Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sudo: required
language: node_js

node_js:
- "20"
- "20.18.1"
- "18"

services:
Expand Down
35,435 changes: 21,305 additions & 14,130 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions packages/serverless-offline-s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ plugins:

[See example](../../tests/serverless-plugins-integration/README.md#s3)

## Migrating from v7 to v8

This version requires Serverless Framework v4 and serverless-offline v14.4.0+.

### Breaking Changes

- Requires `serverless-offline: "^14.4.0 || >=14"`
- Uses new Serverless v4 plugin API for logging
- Node.js 18+ required

### Upgrade Steps

1. Update serverless to v4: `npm install serverless@^4.0.0`
2. Update serverless-offline to v14.4.0+: `npm install serverless-offline@^14.4.0`
3. Update this plugin: `npm install serverless-offline-s3@^8.0.0`

## How it works?

To be able to emulate AWS S3 Bucket on local machine there should be some bucket system actually running. One of the existing implementations suitable for the task is [Minio](https://github.com/minio/minio).
Expand Down
6 changes: 3 additions & 3 deletions packages/serverless-offline-s3/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "serverless-offline-s3",
"version": "7.0.0",
"version": "8.0.0",
"description": "Emulate AWS λ and s3 locally when developing your Serverless project",
"main": "src",
"repository": {
Expand All @@ -27,7 +27,7 @@
"node": ">=18"
},
"peerDependencies": {
"serverless-offline": "^10.0.2 || >=11"
"serverless-offline": "^14.4.0 || >=14"
},
"dependencies": {
"aws-sdk": "^2.1234.0",
Expand All @@ -36,7 +36,7 @@
"minio": "^7.0.32"
},
"devDependencies": {
"serverless-offline": "^13"
"serverless-offline": "^14.4.0"
},
"keywords": [
"s3",
Expand Down
20 changes: 12 additions & 8 deletions packages/serverless-offline-s3/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
const {get, isUndefined, omitBy, pick} = require('lodash/fp');

const log = require('@serverless/utils/log').log;

const S3 = require('./s3');

const OFFLINE_OPTION = 'serverless-offline';
Expand All @@ -17,15 +15,21 @@ const defaultOptions = {
const omitUndefined = omitBy(isUndefined);

class ServerlessOfflineS3 {
constructor(serverless, cliOptions) {
constructor(serverless, cliOptions, {log} = {}) {
this.cliOptions = null;
this.options = null;
this.s3 = null;
this.lambda = null;
this.serverless = null;
this.log = null;

this.cliOptions = cliOptions;
this.serverless = serverless;
this.log = log || {
debug: console.debug.bind(console),
notice: console.log.bind(console),
warning: console.warn.bind(console)
};

this.hooks = {
'offline:start:init': this.start.bind(this),
Expand All @@ -52,7 +56,7 @@ class ServerlessOfflineS3 {

await Promise.all(eventModules);

this.serverless.cli.log(
this.log.notice(
`Starting Offline S3 at stage ${this.options.stage} (${this.options.endPoint}/${this.options.region})`
);
}
Expand All @@ -68,7 +72,7 @@ class ServerlessOfflineS3 {

signals.map(signal =>
process.on(signal, async () => {
this.serverless.cli.log(`Got ${signal} signal. Offline Halting...`);
this.log.notice(`Got ${signal} signal. Offline Halting...`);

await this.end();
})
Expand All @@ -85,7 +89,7 @@ class ServerlessOfflineS3 {
return;
}

this.serverless.cli.log('Halting offline server');
this.log.notice('Halting offline server');

const eventModules = [];

Expand Down Expand Up @@ -114,7 +118,7 @@ class ServerlessOfflineS3 {
async _createS3(events, skipStart) {
const resources = this._getResources();

this.s3 = new S3(this.lambda, resources, this.options);
this.s3 = new S3(this.lambda, resources, this.options, this.log);

await this.s3.create(events);

Expand All @@ -140,7 +144,7 @@ class ServerlessOfflineS3 {
omitUndefined(this.cliOptions)
);

log.debug('options:', this.options);
this.log.debug('s3 options:', this.options);
}

_getEvents() {
Expand Down
40 changes: 32 additions & 8 deletions packages/serverless-offline-s3/src/s3.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
const Minio = require('minio');
const {assign, toNumber} = require('lodash/fp');

const log = require('@serverless/utils/log').log;

const S3EventDefinition = require('./s3-event-definition');
const S3Event = require('./s3-event');

Expand All @@ -11,15 +9,23 @@ const delay = timeout =>
setTimeout(resolve, timeout);
});

const defaultLog = {
debug: console.debug.bind(console),
notice: console.log.bind(console),
warning: console.warn.bind(console)
};

class S3 {
constructor(lambda, resources, options) {
constructor(lambda, resources, options, log = defaultLog) {
this.lambda = null;
this.resources = null;
this.options = null;
this.log = null;

this.lambda = lambda;
this.resources = resources;
this.options = options;
this.log = log || defaultLog;

const s3Endpoint = this.options.endpoint ? new URL(this.options.endpoint) : {};
this.client = new Minio.Client(
Expand All @@ -34,6 +40,14 @@ class S3 {
this.listeners = [];
}

_safeLog(level, message) {
if (this.log && typeof this.log[level] === 'function') {
this.log[level](message);
} else if (console[level]) {
console[level](message);
}
}

create(events) {
this.events = events;
return Promise.all(
Expand All @@ -48,35 +62,45 @@ class S3 {
return Promise.all(
this.events.map(async ({functionKey, s3}) => {
const {event, bucket, rules} = s3;
await this._waitFor(bucket);
this.log.debug(`Setting up listener for bucket: ${bucket}, event: ${event}`);

await this._waitFor(bucket);
const eventRules = rules || [];
const prefix = (eventRules.find(rule => rule.prefix) || {prefix: '*'}).prefix;
const suffix = (eventRules.find(rule => rule.suffix) || {suffix: '*'}).suffix;

const listener = this.client.listenBucketNotification(bucket, prefix, suffix, [event]);

listener.on('notification', async record => {
if (record) {
try {
this.log.debug(
`Received S3 notification for bucket ${bucket}: ${JSON.stringify(record)}`
);
const lambdaFunction = this.lambda.get(functionKey);

const s3Notification = new S3Event(record);
lambdaFunction.setEvent(s3Notification);

await lambdaFunction.runHandler();
} catch (err) {
log.warn(err.stack);
this.log.warning(
`Error processing S3 notification for bucket ${bucket}: ${err.stack}`
);
}
}
});

listener.on('error', err => {
this.log.warning(`Error in S3 listener for bucket ${bucket}: ${err.message}`);
});

this.listeners = [...this.listeners, listener];
this.log.debug(`Listener set up successfully for bucket: ${bucket}`);
})
);
}

stop(timeout) {
stop(_timeout) {
this.listeners.forEach(listener => listener.stop());
this.listeners = [];
}
Expand Down Expand Up @@ -114,7 +138,7 @@ class S3 {

await lambdaFunction.runHandler();
} catch (err) {
log.warn(err.stack);
this._safeLog('warning', err.stack);
}
}
});
Expand Down
16 changes: 16 additions & 0 deletions packages/serverless-offline-sqs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ plugins:

[See example](../../tests/serverless-plugins-integration/README.md#sqs)

## Migrating from v8 to v9

This version requires Serverless Framework v4 and serverless-offline v14.4.0+.

### Breaking Changes

- Requires `serverless-offline: "^14.4.0 || >=14"`
- Uses new Serverless v4 plugin API for logging
- Node.js 18+ required

### Upgrade Steps

1. Update serverless to v4: `npm install serverless@^4.0.0`
2. Update serverless-offline to v14.4.0+: `npm install serverless-offline@^14.4.0`
3. Update this plugin: `npm install serverless-offline-sqs@^9.0.0`

## How it works?

To be able to emulate AWS SQS queue on local machine there should be some queue system actually running. One of the existing implementations suitable for the task is [ElasticMQ](https://github.com/adamw/elasticmq).
Expand Down
6 changes: 3 additions & 3 deletions packages/serverless-offline-sqs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "serverless-offline-sqs",
"version": "8.0.0",
"version": "9.0.0",
"description": "Emulate AWS λ and SQS locally when developing your Serverless project",
"main": "src",
"repository": {
Expand All @@ -27,15 +27,15 @@
"node": ">=18"
},
"peerDependencies": {
"serverless-offline": "^10.0.2 || >=11"
"serverless-offline": "^14.4.0 || >=14"
},
"dependencies": {
"aws-sdk": "^2.1234.0",
"lodash": "^4.17.21",
"p-queue": "^6.6.2"
},
"devDependencies": {
"serverless-offline": "^13"
"serverless-offline": "^14.4.0"
},
"keywords": [
"sqs",
Expand Down
22 changes: 12 additions & 10 deletions packages/serverless-offline-sqs/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ const {
toPairs
} = require('lodash/fp');

const log = require('@serverless/utils/log').log;

const SQS = require('./sqs');

const OFFLINE_OPTION = 'serverless-offline';
Expand All @@ -32,15 +30,21 @@ const defaultOptions = {
const omitUndefined = omitBy(isUndefined);

class ServerlessOfflineSQS {
constructor(serverless, cliOptions) {
constructor(serverless, cliOptions, {log} = {}) {
this.cliOptions = null;
this.options = null;
this.log = null;
this.sqs = null;
this.lambda = null;
this.serverless = null;

this.cliOptions = cliOptions;
this.serverless = serverless;
this.log = log || {
debug: console.debug.bind(console),
notice: console.log.bind(console),
warning: console.warn.bind(console)
};

this.hooks = {
'offline:start:init': this.start.bind(this),
Expand All @@ -67,9 +71,7 @@ class ServerlessOfflineSQS {

await Promise.all(eventModules);

this.serverless.cli.log(
`Starting Offline SQS at stage ${this.options.stage} (${this.options.region})`
);
this.log.notice(`Starting Offline SQS at stage ${this.options.stage} (${this.options.region})`);
}

ready() {
Expand All @@ -83,7 +85,7 @@ class ServerlessOfflineSQS {

signals.map(signal =>
process.on(signal, async () => {
this.serverless.cli.log(`Got ${signal} signal. Offline Halting...`);
this.log.notice(`Got ${signal} signal. Offline Halting...`);

await this.end();
})
Expand All @@ -100,7 +102,7 @@ class ServerlessOfflineSQS {
return;
}

this.serverless.cli.log('Halting offline server');
this.log.notice('Halting offline server');

const eventModules = [];

Expand Down Expand Up @@ -129,7 +131,7 @@ class ServerlessOfflineSQS {
async _createSqs(events, skipStart) {
const resources = this._getResources();

this.sqs = new SQS(this.lambda, resources, this.options);
this.sqs = new SQS(this.lambda, resources, this.options, this.log);

await this.sqs.create(events);

Expand All @@ -155,7 +157,7 @@ class ServerlessOfflineSQS {
omitUndefined(this.cliOptions)
);

log.debug('options:', this.options);
this.log.debug('sqs options:', this.options);
}

_getEvents() {
Expand Down
Loading