serverless-offline 9.1.6 → 9.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/package.json +3 -3
  2. package/src/ServerlessOffline.js +32 -32
  3. package/src/config/defaultOptions.js +1 -1
  4. package/src/events/http/HttpServer.js +19 -14
  5. package/src/events/schedule/ScheduleEvent.js +19 -11
  6. package/src/events/websocket/HttpServer.js +2 -2
  7. package/src/events/websocket/WebSocketServer.js +2 -2
  8. package/src/events/websocket/lambda-events/WebSocketConnectEvent.js +1 -1
  9. package/src/lambda/HttpServer.js +5 -3
  10. package/src/lambda/LambdaFunction.js +1 -4
  11. package/src/lambda/__tests__/LambdaFunction.test.js +17 -17
  12. package/src/lambda/__tests__/fixtures/Lambda/{LambdaFunctionThatReturnsJSONObject.fixture.js → LambdaFunctionThatReturnsJSONObject-fixture.js} +2 -3
  13. package/src/lambda/__tests__/fixtures/Lambda/{LambdaFunctionThatReturnsNativeString.fixture.js → LambdaFunctionThatReturnsNativeString-fixture.js} +2 -2
  14. package/src/lambda/__tests__/fixtures/{lambdaFunction.fixture.js → lambdaFunction-fixture.js} +0 -0
  15. package/src/lambda/__tests__/routes/invocations/InvocationsController.test.js +2 -2
  16. package/src/lambda/handler-runner/HandlerRunner.js +3 -11
  17. package/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +9 -6
  18. package/src/lambda/handler-runner/child-process-runner/childProcessHelper.js +8 -5
  19. package/src/lambda/handler-runner/go-runner/GoRunner.js +3 -1
  20. package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +16 -34
  21. package/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js +359 -0
  22. package/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/package.json +3 -0
  23. package/src/lambda/handler-runner/python-runner/PythonRunner.js +17 -19
  24. package/src/lambda/handler-runner/ruby-runner/RubyRunner.js +4 -1
  25. package/src/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +5 -6
  26. package/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +8 -5
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "dedicatedTo": "Blue, a great migrating bird.",
3
3
  "name": "serverless-offline",
4
- "version": "9.1.6",
4
+ "version": "9.2.1",
5
5
  "description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
6
6
  "license": "MIT",
7
7
  "main": "./src/index.js",
@@ -195,7 +195,7 @@
195
195
  "@hapi/h2o2": "^9.1.0",
196
196
  "@hapi/hapi": "^20.2.2",
197
197
  "@serverless/utils": "^6.7.0",
198
- "aws-sdk": "^2.1187.0",
198
+ "aws-sdk": "^2.1194.0",
199
199
  "boxen": "^7.0.0",
200
200
  "chalk": "^5.0.1",
201
201
  "execa": "^6.1.0",
@@ -217,7 +217,7 @@
217
217
  },
218
218
  "devDependencies": {
219
219
  "archiver": "^5.3.1",
220
- "eslint": "^8.21.0",
220
+ "eslint": "^8.22.0",
221
221
  "eslint-config-airbnb-base": "^15.0.0",
222
222
  "eslint-config-prettier": "^8.5.0",
223
223
  "eslint-plugin-import": "^2.25.4",
@@ -23,38 +23,38 @@ export default class ServerlessOffline {
23
23
 
24
24
  #webSocket = null
25
25
 
26
- constructor(serverless, cliOptions) {
27
- this.#cliOptions = cliOptions
28
- this.#serverless = serverless
29
-
30
- this.commands = {
31
- offline: {
32
- // add start nested options
33
- commands: {
34
- functionsUpdated: {
35
- lifecycleEvents: ['cleanup'],
36
- type: 'entrypoint',
37
- },
38
- start: {
39
- lifecycleEvents: ['init', 'ready', 'end'],
40
- options: commandOptions,
41
- usage:
42
- 'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.',
43
- },
26
+ commands = {
27
+ offline: {
28
+ // add start nested options
29
+ commands: {
30
+ functionsUpdated: {
31
+ lifecycleEvents: ['cleanup'],
32
+ type: 'entrypoint',
33
+ },
34
+ start: {
35
+ lifecycleEvents: ['init', 'ready', 'end'],
36
+ options: commandOptions,
37
+ usage:
38
+ 'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.',
44
39
  },
45
- lifecycleEvents: ['start'],
46
- options: commandOptions,
47
- usage: 'Simulates API Gateway to call your lambda functions offline.',
48
40
  },
49
- }
41
+ lifecycleEvents: ['start'],
42
+ options: commandOptions,
43
+ usage: 'Simulates API Gateway to call your lambda functions offline.',
44
+ },
45
+ }
50
46
 
51
- this.hooks = {
52
- 'offline:functionsUpdated:cleanup': this.#cleanupFunctions.bind(this),
53
- 'offline:start': this.#startWithExplicitEnd.bind(this),
54
- 'offline:start:end': this.end.bind(this),
55
- 'offline:start:init': this.start.bind(this),
56
- 'offline:start:ready': this.#ready.bind(this),
57
- }
47
+ hooks = {
48
+ 'offline:functionsUpdated:cleanup': this.#cleanupFunctions.bind(this),
49
+ 'offline:start': this.#startWithExplicitEnd.bind(this),
50
+ 'offline:start:end': this.end.bind(this),
51
+ 'offline:start:init': this.start.bind(this),
52
+ 'offline:start:ready': this.#ready.bind(this),
53
+ }
54
+
55
+ constructor(serverless, cliOptions) {
56
+ this.#cliOptions = cliOptions
57
+ this.#serverless = serverless
58
58
  }
59
59
 
60
60
  // Entry point for the plugin (sls offline) when running 'sls offline start'
@@ -245,9 +245,9 @@ export default class ServerlessOffline {
245
245
 
246
246
  log.notice()
247
247
  log.notice(
248
- `Starting Offline at stage ${provider.stage} ${chalk.gray(
249
- `(${provider.region})`,
250
- )}`,
248
+ `Starting Offline at stage ${
249
+ this.#options.stage || provider.stage
250
+ } ${chalk.gray(`(${this.#options.region || provider.region})`)}`,
251
251
  )
252
252
  log.notice()
253
253
  log.debug('options:', this.#options)
@@ -17,7 +17,7 @@ export default {
17
17
  hideStackTraces: false,
18
18
  host: 'localhost',
19
19
  httpPort: 3000,
20
- httpsProtocol: '',
20
+ httpsProtocol: null,
21
21
  lambdaPort: 3002,
22
22
  layersDir: null,
23
23
  localEnvironment: false,
@@ -49,6 +49,18 @@ export default class HttpServer {
49
49
  this.#serverless = serverless
50
50
  }
51
51
 
52
+ async #loadCerts(httpsProtocol) {
53
+ const [cert, key] = await Promise.all([
54
+ readFile(resolve(httpsProtocol, 'cert.pem'), 'utf-8'),
55
+ readFile(resolve(httpsProtocol, 'key.pem'), 'utf-8'),
56
+ ])
57
+
58
+ return {
59
+ cert,
60
+ key,
61
+ }
62
+ }
63
+
52
64
  async createServer() {
53
65
  const {
54
66
  enforceSecureCookies,
@@ -77,19 +89,10 @@ export default class HttpServer {
77
89
  isSameSite: false,
78
90
  isSecure: false,
79
91
  },
80
- }
81
-
82
- // https support
83
- if (typeof httpsProtocol === 'string' && httpsProtocol.length > 0) {
84
- const [cert, key] = await Promise.all([
85
- readFile(resolve(httpsProtocol, 'cert.pem'), 'utf-8'),
86
- readFile(resolve(httpsProtocol, 'key.pem'), 'utf-8'),
87
- ])
88
-
89
- serverOptions.tls = {
90
- cert,
91
- key,
92
- }
92
+ // https support
93
+ ...(httpsProtocol != null && {
94
+ tls: await this.#loadCerts(httpsProtocol),
95
+ }),
93
96
  }
94
97
 
95
98
  // Hapijs server creation
@@ -1017,7 +1020,9 @@ export default class HttpServer {
1017
1020
  auth: authStrategyName,
1018
1021
  cors,
1019
1022
  state,
1020
- timeout: { socket: false },
1023
+ timeout: {
1024
+ socket: false,
1025
+ },
1021
1026
  }
1022
1027
 
1023
1028
  // skip HEAD routes as hapi will fail with 'Method name not allowed: HEAD ...'
@@ -1,18 +1,26 @@
1
1
  import { createUniqueId } from '../../utils/index.js'
2
2
 
3
3
  export default class ScheduleEvent {
4
- constructor(region) {
5
- // format of aws displaying the time, e.g.: 2020-02-09T14:13:57Z
6
- const time = new Date().toISOString().replace(/\.(.*)(?=Z)/g, '')
4
+ account = createUniqueId()
5
+
6
+ detail = {};
7
+
8
+ ['detail-type'] = 'Scheduled Event'
9
+
10
+ id = createUniqueId()
11
+
12
+ region = null
7
13
 
8
- this.account = createUniqueId()
9
- this.detail = {}
10
- this['detail-type'] = 'Scheduled Event'
11
- this.id = createUniqueId()
14
+ resources = []
15
+
16
+ source = 'aws.events'
17
+
18
+ // format of aws displaying the time, e.g.: 2020-02-09T14:13:57Z
19
+ time = new Date().toISOString().replace(/\.(.*)(?=Z)/g, '')
20
+
21
+ version = '0'
22
+
23
+ constructor(region) {
12
24
  this.region = region
13
- this.resources = []
14
- this.source = 'aws.events'
15
- this.time = time
16
- this.version = '0'
17
25
  }
18
26
  }
@@ -50,8 +50,8 @@ export default class HttpServer {
50
50
  }
51
51
 
52
52
  log.notice(
53
- `Offline [http for websocket] listening on http${
54
- httpsProtocol ? 's' : ''
53
+ `Offline [http for websocket] listening on ${
54
+ httpsProtocol ? 'https' : 'http'
55
55
  }://${host}:${websocketPort}`,
56
56
  )
57
57
  }
@@ -58,8 +58,8 @@ export default class WebSocketServer {
58
58
  const { host, httpsProtocol, websocketPort } = this.#options
59
59
 
60
60
  log.notice(
61
- `Offline [websocket] listening on ws${
62
- httpsProtocol ? 's' : ''
61
+ `Offline [websocket] listening on ${
62
+ httpsProtocol ? 'wss' : 'ws'
63
63
  }://${host}:${websocketPort}`,
64
64
  )
65
65
  }
@@ -37,7 +37,7 @@ export default class WebSocketConnectEvent {
37
37
  // 'X-Amzn-Trace-Id': `Root=${createUniqueId()}`,
38
38
  // 'X-Forwarded-For': '127.0.0.1',
39
39
  // 'X-Forwarded-Port': String(this.#websocketPort),
40
- // 'X-Forwarded-Proto': `http${this.#httpsProtocol ? 's' : ''}`,
40
+ // 'X-Forwarded-Proto': ${httpsProtocol ? 'https' : 'http'},
41
41
  // }
42
42
 
43
43
  const headers = parseHeaders(this.#rawHeaders)
@@ -44,13 +44,15 @@ export default class HttpServer {
44
44
  }
45
45
 
46
46
  log.notice(
47
- `Offline [http for lambda] listening on http${
48
- httpsProtocol ? 's' : ''
47
+ `Offline [http for lambda] listening on ${
48
+ httpsProtocol ? 'https' : 'http'
49
49
  }://${host}:${lambdaPort}`,
50
50
  )
51
51
 
52
52
  // Print all the invocation routes to debug
53
- const basePath = `http${httpsProtocol ? 's' : ''}://${host}:${lambdaPort}`
53
+ const basePath = `${
54
+ httpsProtocol ? 'https' : 'http'
55
+ }://${host}:${lambdaPort}`
54
56
  const funcNamePairs = this.#lambda.listFunctionNamePairs()
55
57
 
56
58
  log.notice(
@@ -13,7 +13,7 @@ import {
13
13
  DEFAULT_LAMBDA_TIMEOUT,
14
14
  supportedRuntimes,
15
15
  } from '../config/index.js'
16
- import { createUniqueId, splitHandlerPathAndName } from '../utils/index.js'
16
+ import { createUniqueId } from '../utils/index.js'
17
17
 
18
18
  const { ceil } = Math
19
19
  const { entries, fromEntries } = Object
@@ -70,7 +70,6 @@ export default class LambdaFunction {
70
70
  const servicepath = resolve(servicePath, options.location || '')
71
71
 
72
72
  const { handler, name, package: functionPackage = {} } = functionDefinition
73
- const [handlerPath, handlerName] = splitHandlerPathAndName(handler)
74
73
 
75
74
  const memorySize =
76
75
  functionDefinition.memorySize ||
@@ -140,8 +139,6 @@ export default class LambdaFunction {
140
139
  ? resolve(servicepath, functionPackage.artifact)
141
140
  : undefined,
142
141
  handler,
143
- handlerName,
144
- handlerPath: resolve(this.#codeDir, handlerPath),
145
142
  layers: functionDefinition.layers || [],
146
143
  provider,
147
144
  runtime,
@@ -27,52 +27,52 @@ describe('LambdaFunction', () => {
27
27
  {
28
28
  description: 'should return result when handler is context.done',
29
29
  expected: 'foo',
30
- handler: 'fixtures/lambdaFunction.fixture.contextDoneHandler',
30
+ handler: 'fixtures/lambdaFunction-fixture.contextDoneHandler',
31
31
  },
32
32
  {
33
33
  description:
34
34
  'should return result when handler is context.done which is deferred',
35
35
  expected: 'foo',
36
- handler: 'fixtures/lambdaFunction.fixture.contextDoneHandlerDeferred',
36
+ handler: 'fixtures/lambdaFunction-fixture.contextDoneHandlerDeferred',
37
37
  },
38
38
  {
39
39
  description: 'should return result when handler is context.succeed',
40
40
  expected: 'foo',
41
- handler: 'fixtures/lambdaFunction.fixture.contextSucceedHandler',
41
+ handler: 'fixtures/lambdaFunction-fixture.contextSucceedHandler',
42
42
  },
43
43
  {
44
44
  description:
45
45
  'should return result when handler is context.succeed which is deferred',
46
46
  expected: 'foo',
47
47
  handler:
48
- 'fixtures/lambdaFunction.fixture.contextSucceedHandlerDeferred',
48
+ 'fixtures/lambdaFunction-fixture.contextSucceedHandlerDeferred',
49
49
  },
50
50
  {
51
51
  description: 'should return result when handler is a callback',
52
52
  expected: 'foo',
53
- handler: 'fixtures/lambdaFunction.fixture.callbackHandler',
53
+ handler: 'fixtures/lambdaFunction-fixture.callbackHandler',
54
54
  },
55
55
  {
56
56
  description:
57
57
  'should return result when handler is a callback which is deferred',
58
58
  expected: 'foo',
59
- handler: 'fixtures/lambdaFunction.fixture.callbackHandlerDeferred',
59
+ handler: 'fixtures/lambdaFunction-fixture.callbackHandlerDeferred',
60
60
  },
61
61
  {
62
62
  description: 'should return result when handler returns a promise',
63
63
  expected: 'foo',
64
- handler: 'fixtures/lambdaFunction.fixture.promiseHandler',
64
+ handler: 'fixtures/lambdaFunction-fixture.promiseHandler',
65
65
  },
66
66
  {
67
67
  description:
68
68
  'should return result when handler returns a promise which is deferred',
69
69
  expected: 'foo',
70
- handler: 'fixtures/lambdaFunction.fixture.promiseHandlerDeferred',
70
+ handler: 'fixtures/lambdaFunction-fixture.promiseHandlerDeferred',
71
71
  },
72
72
  {
73
73
  description: 'should return result when handler is an async function',
74
74
  expected: 'foo',
75
- handler: 'fixtures/lambdaFunction.fixture.asyncFunctionHandler',
75
+ handler: 'fixtures/lambdaFunction-fixture.asyncFunctionHandler',
76
76
  },
77
77
  // NOTE: mix and matching of callbacks and promises is not recommended,
78
78
  // nonetheless, we test some of the behaviour to match AWS execution precedence
@@ -81,33 +81,33 @@ describe('LambdaFunction', () => {
81
81
  'should return result when handler returns a callback but defines a callback parameter',
82
82
  expected: 'Hello Promise!',
83
83
  handler:
84
- 'fixtures/lambdaFunction.fixture.promiseWithDefinedCallbackHandler',
84
+ 'fixtures/lambdaFunction-fixture.promiseWithDefinedCallbackHandler',
85
85
  },
86
86
  {
87
87
  description:
88
88
  'should return result when handler calls context.succeed and context.done',
89
89
  expected: 'Hello Context.succeed!',
90
90
  handler:
91
- 'fixtures/lambdaFunction.fixture.contextSucceedWithContextDoneHandler',
91
+ 'fixtures/lambdaFunction-fixture.contextSucceedWithContextDoneHandler',
92
92
  },
93
93
  {
94
94
  description:
95
95
  'should return result when handler calls callback and context.done',
96
96
  expected: 'Hello Callback!',
97
97
  handler:
98
- 'fixtures/lambdaFunction.fixture.callbackWithContextDoneHandler',
98
+ 'fixtures/lambdaFunction-fixture.callbackWithContextDoneHandler',
99
99
  },
100
100
  {
101
101
  description:
102
102
  'should return result when handler calls callback and returns Promise',
103
103
  expected: 'Hello Callback!',
104
- handler: 'fixtures/lambdaFunction.fixture.callbackWithPromiseHandler',
104
+ handler: 'fixtures/lambdaFunction-fixture.callbackWithPromiseHandler',
105
105
  },
106
106
  {
107
107
  description:
108
108
  'should return result when handler calls callback inside returned Promise',
109
109
  expected: 'Hello Callback!',
110
- handler: 'fixtures/lambdaFunction.fixture.callbackInsidePromiseHandler',
110
+ handler: 'fixtures/lambdaFunction-fixture.callbackInsidePromiseHandler',
111
111
  },
112
112
  ].forEach(({ description, expected, handler }) => {
113
113
  it(description, async () => {
@@ -132,7 +132,7 @@ describe('LambdaFunction', () => {
132
132
 
133
133
  it('should pass remaining time to LambdaContext', async () => {
134
134
  const functionDefinition = {
135
- handler: 'fixtures/lambdaFunction.fixture.remainingExecutionTimeHandler',
135
+ handler: 'fixtures/lambdaFunction-fixture.remainingExecutionTimeHandler',
136
136
  }
137
137
  const options = {}
138
138
  const lambdaFunction = new LambdaFunction(
@@ -152,7 +152,7 @@ describe('LambdaFunction', () => {
152
152
 
153
153
  it.skip('should use default lambda timeout when timeout is not provided', async () => {
154
154
  const functionDefinition = {
155
- handler: 'fixtures/lambdaFunction.fixture.defaultTimeoutHandler',
155
+ handler: 'fixtures/lambdaFunction-fixture.defaultTimeoutHandler',
156
156
  }
157
157
  const options = {}
158
158
  const lambdaFunction = new LambdaFunction(
@@ -175,7 +175,7 @@ describe('LambdaFunction', () => {
175
175
  // // might run flaky (unreliable)
176
176
  // test('executionTimeInMillis should return execution time', async () => {
177
177
  // const functionDefinition = {
178
- // handler: 'fixtures/lambdaFunction.fixture.executionTimeInMillisHandler',
178
+ // handler: 'fixtures/lambdaFunction-fixture.executionTimeInMillisHandler',
179
179
  // }
180
180
  // const options = {}
181
181
  // const lambdaFunction = new LambdaFunction(
@@ -12,7 +12,7 @@ export default class LambdaFunctionThatReturnsJSONObject {
12
12
  serverless = {
13
13
  config: {
14
14
  serverlessPath: '',
15
- servicePath: resolve(__dirname),
15
+ servicePath: resolve(__dirname, '../..'),
16
16
  },
17
17
  service: {
18
18
  provider: {
@@ -27,8 +27,7 @@ export default class LambdaFunctionThatReturnsJSONObject {
27
27
 
28
28
  getByFunctionName(functionName) {
29
29
  const functionDefinition = {
30
- handler:
31
- '../../fixtures/lambdaFunction.fixture.asyncFunctionHandlerObject',
30
+ handler: 'fixtures/lambdaFunction-fixture.asyncFunctionHandlerObject',
32
31
  }
33
32
 
34
33
  this.#lambdaFunction = new LambdaFunction(
@@ -12,7 +12,7 @@ export default class LambdaFunctionThatReturnsNativeString {
12
12
  serverless = {
13
13
  config: {
14
14
  serverlessPath: '',
15
- servicePath: resolve(__dirname),
15
+ servicePath: resolve(__dirname, '../..'),
16
16
  },
17
17
  service: {
18
18
  provider: {
@@ -27,7 +27,7 @@ export default class LambdaFunctionThatReturnsNativeString {
27
27
 
28
28
  getByFunctionName(functionName) {
29
29
  const functionDefinition = {
30
- handler: '../../fixtures/lambdaFunction.fixture.asyncFunctionHandler',
30
+ handler: 'fixtures/lambdaFunction-fixture.asyncFunctionHandler',
31
31
  }
32
32
 
33
33
  this.#lambdaFunction = new LambdaFunction(
@@ -1,7 +1,7 @@
1
1
  import assert from 'node:assert'
2
2
  import InvocationsController from '../../../routes/invocations/InvocationsController.js'
3
- import LambdaFunctionThatReturnsJSONObject from '../../fixtures/Lambda/LambdaFunctionThatReturnsJSONObject.fixture.js'
4
- import LambdaFunctionThatReturnsNativeString from '../../fixtures/Lambda/LambdaFunctionThatReturnsNativeString.fixture.js'
3
+ import LambdaFunctionThatReturnsJSONObject from '../../fixtures/Lambda/LambdaFunctionThatReturnsJSONObject-fixture.js'
4
+ import LambdaFunctionThatReturnsNativeString from '../../fixtures/Lambda/LambdaFunctionThatReturnsNativeString-fixture.js'
5
5
 
6
6
  describe('InvocationController', () => {
7
7
  const functionName = 'foo'
@@ -24,11 +24,9 @@ export default class HandlerRunner {
24
24
 
25
25
  async #loadRunner() {
26
26
  const { useChildProcesses, useDocker, useInProcess } = this.#options
27
+ const { handler, runtime } = this.#funOptions
27
28
 
28
- const { functionKey, handlerName, handlerPath, runtime, timeout } =
29
- this.#funOptions
30
-
31
- log.debug(`Loading handler... (${handlerPath})`)
29
+ log.debug(`Loading handler... (${handler})`)
32
30
 
33
31
  if (useDocker) {
34
32
  // https://github.com/lambci/docker-lambda/issues/329
@@ -71,13 +69,7 @@ export default class HandlerRunner {
71
69
  './in-process-runner/index.js'
72
70
  )
73
71
 
74
- return new InProcessRunner(
75
- functionKey,
76
- handlerPath,
77
- handlerName,
78
- this.#env,
79
- timeout,
80
- )
72
+ return new InProcessRunner(this.#funOptions, this.#env)
81
73
  }
82
74
 
83
75
  const { default: WorkerThreadRunner } = await import(
@@ -7,23 +7,26 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
7
7
  const childProcessHelperPath = resolve(__dirname, 'childProcessHelper.js')
8
8
 
9
9
  export default class ChildProcessRunner {
10
+ #codeDir = null
11
+
10
12
  #env = null
11
13
 
12
14
  #functionKey = null
13
15
 
14
- #handlerName = null
16
+ #handler = null
15
17
 
16
- #handlerPath = null
18
+ #servicePath = null
17
19
 
18
20
  #timeout = null
19
21
 
20
22
  constructor(funOptions, env) {
21
- const { functionKey, handlerName, handlerPath, timeout } = funOptions
23
+ const { codeDir, functionKey, handler, servicePath, timeout } = funOptions
22
24
 
25
+ this.#codeDir = codeDir
23
26
  this.#env = env
24
27
  this.#functionKey = functionKey
25
- this.#handlerName = handlerName
26
- this.#handlerPath = handlerPath
28
+ this.#handler = handler
29
+ this.#servicePath = servicePath
27
30
  this.#timeout = timeout
28
31
  }
29
32
 
@@ -34,7 +37,7 @@ export default class ChildProcessRunner {
34
37
  async run(event, context) {
35
38
  const childProcess = execaNode(
36
39
  childProcessHelperPath,
37
- [this.#functionKey, this.#handlerName, this.#handlerPath],
40
+ [this.#functionKey, this.#handler, this.#servicePath, this.#codeDir],
38
41
  {
39
42
  env: this.#env,
40
43
  stdio: 'inherit',
@@ -21,18 +21,21 @@ process.on('uncaughtException', (err) => {
21
21
  })
22
22
  })
23
23
 
24
- const [, , functionKey, handlerName, handlerPath] = argv
24
+ const [, , functionKey, handler, servicePath, codeDir] = argv
25
25
 
26
26
  process.on('message', async (messageData) => {
27
27
  const { context, event, timeout } = messageData
28
28
 
29
29
  // TODO we could probably cache this in the module scope?
30
30
  const inProcessRunner = new InProcessRunner(
31
- functionKey,
32
- handlerPath,
33
- handlerName,
31
+ {
32
+ codeDir,
33
+ functionKey,
34
+ handler,
35
+ servicePath,
36
+ timeout,
37
+ },
34
38
  process.env,
35
- timeout,
36
39
  )
37
40
 
38
41
  const result = await inProcessRunner.run(event, context)
@@ -4,6 +4,7 @@ import process, { chdir, cwd } from 'node:process'
4
4
  import { parse as pathParse, resolve, sep } from 'node:path'
5
5
  import { log } from '@serverless/utils/log.js'
6
6
  import { execa } from 'execa'
7
+ import { splitHandlerPathAndName } from '../../../utils/index.js'
7
8
 
8
9
  const { parse, stringify } = JSON
9
10
 
@@ -23,7 +24,8 @@ export default class GoRunner {
23
24
  #tmpPath = null
24
25
 
25
26
  constructor(funOptions, env) {
26
- const { handlerPath, codeDir } = funOptions
27
+ const { handler, codeDir } = funOptions
28
+ const [handlerPath] = splitHandlerPathAndName(handler)
27
29
 
28
30
  this.#codeDir = codeDir
29
31
  this.#env = env
@@ -1,29 +1,32 @@
1
- import { createRequire } from 'node:module'
1
+ import { join } from 'node:path'
2
2
  import { performance } from 'node:perf_hooks'
3
3
  import process from 'node:process'
4
- import { log } from '@serverless/utils/log.js'
4
+ import { load } from './aws-lambda-ric/UserFunction.js'
5
5
 
6
6
  const { floor } = Math
7
7
  const { assign } = Object
8
8
 
9
- const require = createRequire(import.meta.url)
10
-
11
9
  export default class InProcessRunner {
10
+ #codeDir = null
11
+
12
12
  #env = null
13
13
 
14
14
  #functionKey = null
15
15
 
16
- #handlerName = null
16
+ #handler = null
17
17
 
18
- #handlerPath = null
18
+ #servicePath = null
19
19
 
20
20
  #timeout = null
21
21
 
22
- constructor(functionKey, handlerPath, handlerName, env, timeout) {
22
+ constructor(funOptions, env) {
23
+ const { codeDir, functionKey, handler, servicePath, timeout } = funOptions
24
+
25
+ this.#codeDir = codeDir
23
26
  this.#env = env
24
27
  this.#functionKey = functionKey
25
- this.#handlerName = handlerName
26
- this.#handlerPath = handlerPath
28
+ this.#handler = handler
29
+ this.#servicePath = servicePath
27
30
  this.#timeout = timeout
28
31
  }
29
32
 
@@ -32,37 +35,16 @@ export default class InProcessRunner {
32
35
  cleanup() {}
33
36
 
34
37
  async run(event, context) {
35
- // check if the handler module path exists
36
- if (!require.resolve(this.#handlerPath)) {
37
- throw new Error(
38
- `Could not find handler module '${this.#handlerPath}' for function '${
39
- this.#functionKey
40
- }'.`,
41
- )
42
- }
43
-
44
38
  // process.env should be available in the handler module scope as well as in the handler function scope
45
39
  // NOTE: Don't use Object spread (...) here!
46
40
  // otherwise the values of the attached props are not coerced to a string
47
41
  // e.g. process.env.foo = 1 should be coerced to '1' (string)
48
42
  assign(process.env, this.#env)
49
43
 
50
- let handler
51
-
52
- try {
53
- // eslint-disable-next-line import/no-dynamic-require
54
- ;({ [this.#handlerName]: handler } = require(this.#handlerPath))
55
- } catch (err) {
56
- log.error(err)
57
- }
58
-
59
- if (typeof handler !== 'function') {
60
- throw new Error(
61
- `offline: handler '${this.#handlerName}' in ${
62
- this.#handlerPath
63
- } is not a function`,
64
- )
65
- }
44
+ const handler = await load(
45
+ this.#servicePath,
46
+ join(this.#codeDir, this.#handler),
47
+ )
66
48
 
67
49
  let callback
68
50
 
@@ -0,0 +1,359 @@
1
+ 'use strict'
2
+
3
+ const { pathToFileURL } = require('node:url')
4
+
5
+ // node_modules/lambda-runtime/dist/node16/UserFunction.js
6
+ ;(function () {
7
+ const __getOwnPropNames = Object.getOwnPropertyNames
8
+ const __commonJS = (cb, mod) =>
9
+ function __require() {
10
+ return (
11
+ mod ||
12
+ (0, cb[__getOwnPropNames(cb)[0]])(
13
+ (mod = { exports: {} }).exports,
14
+ mod,
15
+ ),
16
+ mod.exports
17
+ )
18
+ }
19
+ const require_Errors = __commonJS({
20
+ 'Errors.js': function (exports2, module2) {
21
+ 'use strict'
22
+
23
+ const util = require('util')
24
+ function _isError(obj) {
25
+ return (
26
+ obj &&
27
+ obj.name &&
28
+ obj.message &&
29
+ obj.stack &&
30
+ typeof obj.name === 'string' &&
31
+ typeof obj.message === 'string' &&
32
+ typeof obj.stack === 'string'
33
+ )
34
+ }
35
+ function intoError(err) {
36
+ if (err instanceof Error) {
37
+ return err
38
+ }
39
+ return new Error(err)
40
+ }
41
+ module2.exports.intoError = intoError
42
+ function toRapidResponse(error) {
43
+ try {
44
+ if (util.types.isNativeError(error) || _isError(error)) {
45
+ return {
46
+ errorType: error.name,
47
+ errorMessage: error.message,
48
+ trace: error.stack.split('\n'),
49
+ }
50
+ }
51
+ return {
52
+ errorType: typeof error,
53
+ errorMessage: error.toString(),
54
+ trace: [],
55
+ }
56
+ } catch (_err) {
57
+ return {
58
+ errorType: 'handled',
59
+ errorMessage:
60
+ 'callback called with Error argument, but there was a problem while retrieving one or more of its message, name, and stack',
61
+ }
62
+ }
63
+ }
64
+ module2.exports.toRapidResponse = toRapidResponse
65
+ module2.exports.toFormatted = (error) => {
66
+ try {
67
+ return ` ${JSON.stringify(error, (_k, v) =>
68
+ _withEnumerableProperties(v),
69
+ )}`
70
+ } catch (err) {
71
+ return ` ${JSON.stringify(toRapidResponse(error))}`
72
+ }
73
+ }
74
+ function _withEnumerableProperties(error) {
75
+ if (error instanceof Error) {
76
+ const ret = {
77
+ errorType: error.name,
78
+ errorMessage: error.message,
79
+ code: error.code,
80
+ ...error,
81
+ }
82
+ if (typeof error.stack === 'string') {
83
+ ret.stack = error.stack.split('\n')
84
+ }
85
+ return ret
86
+ }
87
+ return error
88
+ }
89
+ const errorClasses = [
90
+ class ImportModuleError extends Error {},
91
+ class HandlerNotFound extends Error {},
92
+ class MalformedHandlerName extends Error {},
93
+ class UserCodeSyntaxError extends Error {},
94
+ class MalformedStreamingHandler extends Error {},
95
+ class InvalidStreamingOperation extends Error {},
96
+ class UnhandledPromiseRejection extends Error {
97
+ constructor(reason, promise) {
98
+ super(reason)
99
+ this.reason = reason
100
+ this.promise = promise
101
+ }
102
+ },
103
+ ]
104
+ errorClasses.forEach((e) => {
105
+ module2.exports[e.name] = e
106
+ e.prototype.name = `Runtime.${e.name}`
107
+ })
108
+ },
109
+ })
110
+ const require_VerboseLog = __commonJS({
111
+ 'VerboseLog.js': function (exports2) {
112
+ 'use strict'
113
+
114
+ const EnvVarName = 'AWS_LAMBDA_RUNTIME_VERBOSE'
115
+ const Tag = 'RUNTIME'
116
+ const Verbosity = (() => {
117
+ if (!process.env[EnvVarName]) {
118
+ return 0
119
+ }
120
+ try {
121
+ const verbosity = parseInt(process.env[EnvVarName])
122
+ return verbosity < 0 ? 0 : verbosity > 3 ? 3 : verbosity
123
+ } catch (_) {
124
+ return 0
125
+ }
126
+ })()
127
+ exports2.logger = function (category) {
128
+ return {
129
+ verbose() {
130
+ if (Verbosity >= 1) {
131
+ console.log.apply(null, [Tag, category, ...arguments])
132
+ }
133
+ },
134
+ vverbose() {
135
+ if (Verbosity >= 2) {
136
+ console.log.apply(null, [Tag, category, ...arguments])
137
+ }
138
+ },
139
+ vvverbose() {
140
+ if (Verbosity >= 3) {
141
+ console.log.apply(null, [Tag, category, ...arguments])
142
+ }
143
+ },
144
+ }
145
+ }
146
+ },
147
+ })
148
+ const require_HttpResponseStream = __commonJS({
149
+ 'HttpResponseStream.js': function (exports2, module2) {
150
+ 'use strict'
151
+
152
+ const METADATA_PRELUDE_CONTENT_TYPE =
153
+ 'application/vnd.awslambda.http-integration-response'
154
+ const DELIMITER_LEN = 8
155
+ const HttpResponseStream2 = class {
156
+ static from(underlyingStream, prelude) {
157
+ underlyingStream.setContentType(METADATA_PRELUDE_CONTENT_TYPE)
158
+ const metadataPrelude = JSON.stringify(prelude)
159
+ underlyingStream._onBeforeFirstWrite = (write) => {
160
+ write(metadataPrelude)
161
+ write(new Uint8Array(DELIMITER_LEN))
162
+ }
163
+ return underlyingStream
164
+ }
165
+ }
166
+ module2.exports.HttpResponseStream = HttpResponseStream2
167
+ },
168
+ })
169
+ const path = require('path')
170
+ const fs = require('fs')
171
+ const {
172
+ HandlerNotFound,
173
+ MalformedHandlerName,
174
+ ImportModuleError,
175
+ UserCodeSyntaxError,
176
+ } = require_Errors()
177
+ const { verbose } = require_VerboseLog().logger('LOADER')
178
+ const { HttpResponseStream } = require_HttpResponseStream()
179
+ const FUNCTION_EXPR = /^([^.]*)\.(.*)$/
180
+ const RELATIVE_PATH_SUBSTRING = '..'
181
+ const HANDLER_STREAMING = Symbol.for('aws.lambda.runtime.handler.streaming')
182
+ const STREAM_RESPONSE = 'response'
183
+ const NoGlobalAwsLambda =
184
+ process.env.AWS_LAMBDA_NODEJS_NO_GLOBAL_AWSLAMBDA === '1' ||
185
+ process.env.AWS_LAMBDA_NODEJS_NO_GLOBAL_AWSLAMBDA === 'true'
186
+ function _moduleRootAndHandler(fullHandlerString) {
187
+ const handlerString = path.basename(fullHandlerString)
188
+ const moduleRoot = fullHandlerString.substring(
189
+ 0,
190
+ fullHandlerString.indexOf(handlerString),
191
+ )
192
+ return [moduleRoot, handlerString]
193
+ }
194
+ function _splitHandlerString(handler) {
195
+ const match = handler.match(FUNCTION_EXPR)
196
+ if (!match || match.length != 3) {
197
+ throw new MalformedHandlerName('Bad handler')
198
+ }
199
+ return [match[1], match[2]]
200
+ }
201
+ function _resolveHandler(object, nestedProperty) {
202
+ return nestedProperty.split('.').reduce((nested, key) => {
203
+ return nested && nested[key]
204
+ }, object)
205
+ }
206
+ function _tryRequireFile(file, extension) {
207
+ const path2 = file + (extension || '')
208
+ verbose('Try loading as commonjs:', path2)
209
+ return fs.existsSync(path2) ? require(path2) : void 0
210
+ }
211
+ async function _tryAwaitImport(file, extension) {
212
+ const path2 = file + (extension || '')
213
+ verbose('Try loading as esmodule:', path2)
214
+ if (fs.existsSync(path2)) {
215
+ return await import(pathToFileURL(path2).href)
216
+ }
217
+ return void 0
218
+ }
219
+ function _hasFolderPackageJsonTypeModule(folder) {
220
+ if (folder.endsWith('/node_modules')) {
221
+ return false
222
+ }
223
+ const pj = path.join(folder, '/package.json')
224
+ if (fs.existsSync(pj)) {
225
+ try {
226
+ const pkg = JSON.parse(fs.readFileSync(pj))
227
+ if (pkg) {
228
+ if (pkg.type === 'module') {
229
+ verbose(`'type: module' detected in ${pj}`)
230
+ return true
231
+ }
232
+ verbose(`'type: module' not detected in ${pj}`)
233
+ return false
234
+ }
235
+ } catch (e) {
236
+ console.warn(
237
+ `${pj} cannot be read, it will be ignored for ES module detection purposes.`,
238
+ e,
239
+ )
240
+ return false
241
+ }
242
+ }
243
+ if (folder === '/') {
244
+ return false
245
+ }
246
+ return _hasFolderPackageJsonTypeModule(path.resolve(folder, '..'))
247
+ }
248
+ function _hasPackageJsonTypeModule(file) {
249
+ const jsPath = `${file}.js`
250
+ return fs.existsSync(jsPath)
251
+ ? _hasFolderPackageJsonTypeModule(path.resolve(path.dirname(jsPath)))
252
+ : false
253
+ }
254
+ async function _tryRequire(appRoot, moduleRoot, module2) {
255
+ verbose(
256
+ 'Try loading as commonjs: ',
257
+ module2,
258
+ ' with paths: ,',
259
+ appRoot,
260
+ moduleRoot,
261
+ )
262
+ const lambdaStylePath = path.resolve(appRoot, moduleRoot, module2)
263
+ const extensionless = _tryRequireFile(lambdaStylePath)
264
+ if (extensionless) {
265
+ return extensionless
266
+ }
267
+ const pjHasModule = _hasPackageJsonTypeModule(lambdaStylePath)
268
+ if (!pjHasModule) {
269
+ const loaded2 = _tryRequireFile(lambdaStylePath, '.js')
270
+ if (loaded2) {
271
+ return loaded2
272
+ }
273
+ }
274
+ const loaded =
275
+ (pjHasModule && (await _tryAwaitImport(lambdaStylePath, '.js'))) ||
276
+ (await _tryAwaitImport(lambdaStylePath, '.mjs')) ||
277
+ _tryRequireFile(lambdaStylePath, '.cjs')
278
+ if (loaded) {
279
+ return loaded
280
+ }
281
+ verbose(
282
+ 'Try loading as commonjs: ',
283
+ module2,
284
+ ' with path(s): ',
285
+ appRoot,
286
+ moduleRoot,
287
+ )
288
+ const nodeStylePath = require.resolve(module2, {
289
+ paths: [appRoot, moduleRoot],
290
+ })
291
+ return require(nodeStylePath)
292
+ }
293
+ async function _loadUserApp(appRoot, moduleRoot, module2) {
294
+ if (!NoGlobalAwsLambda) {
295
+ globalThis.awslambda = {
296
+ streamifyResponse: (handler) => {
297
+ handler[HANDLER_STREAMING] = STREAM_RESPONSE
298
+ return handler
299
+ },
300
+ HttpResponseStream,
301
+ }
302
+ }
303
+ try {
304
+ return await _tryRequire(appRoot, moduleRoot, module2)
305
+ } catch (e) {
306
+ if (e instanceof SyntaxError) {
307
+ throw new UserCodeSyntaxError(e)
308
+ } else if (e.code !== void 0 && e.code === 'MODULE_NOT_FOUND') {
309
+ verbose('globalPaths', JSON.stringify(require('module').globalPaths))
310
+ throw new ImportModuleError(e)
311
+ } else {
312
+ throw e
313
+ }
314
+ }
315
+ }
316
+ function _throwIfInvalidHandler(fullHandlerString) {
317
+ if (fullHandlerString.includes(RELATIVE_PATH_SUBSTRING)) {
318
+ throw new MalformedHandlerName(
319
+ `'${fullHandlerString}' is not a valid handler name. Use absolute paths when specifying root directories in handler names.`,
320
+ )
321
+ }
322
+ }
323
+ function _isHandlerStreaming(handler) {
324
+ if (
325
+ typeof handler[HANDLER_STREAMING] === 'undefined' ||
326
+ handler[HANDLER_STREAMING] === null ||
327
+ handler[HANDLER_STREAMING] === false
328
+ ) {
329
+ return false
330
+ }
331
+ if (handler[HANDLER_STREAMING] === STREAM_RESPONSE) {
332
+ return STREAM_RESPONSE
333
+ }
334
+ throw new MalformedStreamingHandler('Only response streaming is supported.')
335
+ }
336
+ module.exports.load = async function (appRoot, fullHandlerString) {
337
+ _throwIfInvalidHandler(fullHandlerString)
338
+ const [moduleRoot, moduleAndHandler] =
339
+ _moduleRootAndHandler(fullHandlerString)
340
+ const [module2, handlerPath] = _splitHandlerString(moduleAndHandler)
341
+ const userApp = await _loadUserApp(appRoot, moduleRoot, module2)
342
+ const handlerFunc = _resolveHandler(userApp, handlerPath)
343
+ if (!handlerFunc) {
344
+ throw new HandlerNotFound(
345
+ `${fullHandlerString} is undefined or not exported`,
346
+ )
347
+ }
348
+ if (typeof handlerFunc !== 'function') {
349
+ throw new HandlerNotFound(`${fullHandlerString} is not a function`)
350
+ }
351
+ return handlerFunc
352
+ }
353
+ module.exports.getHandlerMetadata = function (handlerFunc) {
354
+ return {
355
+ streaming: _isHandlerStreaming(handlerFunc),
356
+ }
357
+ }
358
+ module.exports.STREAM_RESPONSE = STREAM_RESPONSE
359
+ })()
@@ -2,9 +2,10 @@ import { spawn } from 'node:child_process'
2
2
  import { EOL, platform } from 'node:os'
3
3
  import { delimiter, dirname, join, relative, resolve } from 'node:path'
4
4
  import process, { cwd } from 'node:process'
5
- import readline from 'node:readline'
5
+ import { createInterface } from 'node:readline'
6
6
  import { fileURLToPath } from 'node:url'
7
7
  import { log } from '@serverless/utils/log.js'
8
+ import { splitHandlerPathAndName } from '../../../utils/index.js'
8
9
 
9
10
  const { parse, stringify } = JSON
10
11
  const { assign, hasOwn } = Object
@@ -16,18 +17,15 @@ export default class PythonRunner {
16
17
 
17
18
  #env = null
18
19
 
19
- #handlerName = null
20
-
21
- #handlerPath = null
20
+ #handlerProcess = null
22
21
 
23
22
  #runtime = null
24
23
 
25
24
  constructor(funOptions, env) {
26
- const { handlerName, handlerPath, runtime } = funOptions
25
+ const { handler, runtime } = funOptions
26
+ const [handlerPath, handlerName] = splitHandlerPathAndName(handler)
27
27
 
28
28
  this.#env = env
29
- this.#handlerName = handlerName
30
- this.#handlerPath = handlerPath
31
29
  this.#runtime = platform() === 'win32' ? 'python.exe' : runtime
32
30
 
33
31
  if (process.env.VIRTUAL_ENV) {
@@ -42,13 +40,13 @@ export default class PythonRunner {
42
40
 
43
41
  const [pythonExecutable] = this.#runtime.split('.')
44
42
 
45
- this.handlerProcess = spawn(
43
+ this.#handlerProcess = spawn(
46
44
  pythonExecutable,
47
45
  [
48
46
  '-u',
49
47
  resolve(__dirname, 'invoke.py'),
50
- relative(cwd(), this.#handlerPath),
51
- this.#handlerName,
48
+ relative(cwd(), handlerPath),
49
+ handlerName,
52
50
  ],
53
51
  {
54
52
  env: assign(process.env, this.#env),
@@ -56,14 +54,14 @@ export default class PythonRunner {
56
54
  },
57
55
  )
58
56
 
59
- this.handlerProcess.stdout.readline = readline.createInterface({
60
- input: this.handlerProcess.stdout,
57
+ this.#handlerProcess.stdout.readline = createInterface({
58
+ input: this.#handlerProcess.stdout,
61
59
  })
62
60
  }
63
61
 
64
62
  // () => void
65
63
  cleanup() {
66
- this.handlerProcess.kill()
64
+ this.#handlerProcess.kill()
67
65
  }
68
66
 
69
67
  #parsePayload(value) {
@@ -117,8 +115,8 @@ export default class PythonRunner {
117
115
  try {
118
116
  const parsed = this.#parsePayload(line.toString())
119
117
  if (parsed) {
120
- this.handlerProcess.stdout.readline.removeListener('line', onLine)
121
- this.handlerProcess.stderr.removeListener('data', onErr)
118
+ this.#handlerProcess.stdout.readline.removeListener('line', onLine)
119
+ this.#handlerProcess.stderr.removeListener('data', onErr)
122
120
  return accept(parsed)
123
121
  }
124
122
  return null
@@ -127,12 +125,12 @@ export default class PythonRunner {
127
125
  }
128
126
  }
129
127
 
130
- this.handlerProcess.stdout.readline.on('line', onLine)
131
- this.handlerProcess.stderr.on('data', onErr)
128
+ this.#handlerProcess.stdout.readline.on('line', onLine)
129
+ this.#handlerProcess.stderr.on('data', onErr)
132
130
 
133
131
  process.nextTick(() => {
134
- this.handlerProcess.stdin.write(input)
135
- this.handlerProcess.stdin.write('\n')
132
+ this.#handlerProcess.stdin.write(input)
133
+ this.#handlerProcess.stdin.write('\n')
136
134
  })
137
135
  })
138
136
  }
@@ -4,6 +4,7 @@ import { cwd } from 'node:process'
4
4
  import { fileURLToPath } from 'node:url'
5
5
  import { log } from '@serverless/utils/log.js'
6
6
  import { execa } from 'execa'
7
+ import { splitHandlerPathAndName } from '../../../utils/index.js'
7
8
 
8
9
  const { parse, stringify } = JSON
9
10
  const { hasOwn } = Object
@@ -20,7 +21,9 @@ export default class RubyRunner {
20
21
  #handlerPath = null
21
22
 
22
23
  constructor(funOptions, env) {
23
- const { handlerName, handlerPath } = funOptions
24
+ const [handlerPath, handlerName] = splitHandlerPathAndName(
25
+ funOptions.handler,
26
+ )
24
27
 
25
28
  this.#env = env
26
29
  this.#handlerName = handlerName
@@ -8,18 +8,17 @@ const workerThreadHelperPath = resolve(__dirname, './workerThreadHelper.js')
8
8
  export default class WorkerThreadRunner {
9
9
  #workerThread = null
10
10
 
11
- constructor(funOptions /* options */, env) {
12
- // this._options = options
13
-
14
- const { functionKey, handlerName, handlerPath, timeout } = funOptions
11
+ constructor(funOptions, env) {
12
+ const { codeDir, functionKey, handler, servicePath, timeout } = funOptions
15
13
 
16
14
  this.#workerThread = new Worker(workerThreadHelperPath, {
17
15
  // don't pass process.env from the main process!
18
16
  env,
19
17
  workerData: {
18
+ codeDir,
20
19
  functionKey,
21
- handlerName,
22
- handlerPath,
20
+ handler,
21
+ servicePath,
23
22
  timeout,
24
23
  },
25
24
  })
@@ -2,18 +2,21 @@ import { env } from 'node:process'
2
2
  import { parentPort, workerData } from 'node:worker_threads'
3
3
  import InProcessRunner from '../in-process-runner/index.js'
4
4
 
5
- const { functionKey, handlerName, handlerPath, timeout } = workerData
5
+ const { functionKey, handler, servicePath, timeout, codeDir } = workerData
6
6
 
7
7
  parentPort.on('message', async (messageData) => {
8
8
  const { context, event, port } = messageData
9
9
 
10
10
  // TODO we could probably cache this in the module scope?
11
11
  const inProcessRunner = new InProcessRunner(
12
- functionKey,
13
- handlerPath,
14
- handlerName,
12
+ {
13
+ codeDir,
14
+ functionKey,
15
+ handler,
16
+ servicePath,
17
+ timeout,
18
+ },
15
19
  env,
16
- timeout,
17
20
  )
18
21
 
19
22
  let result