serverless-offline 9.2.6 → 10.0.0

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.
package/README.md CHANGED
@@ -121,7 +121,6 @@ All CLI options are optional:
121
121
  --dockerNetwork The network that the Docker container will connect to
122
122
  --dockerReadOnly Marks if the docker code layer should be read only. Default: true
123
123
  --enforceSecureCookies Enforce secure cookies
124
- --hideStackTraces Hide the stack trace on lambda failure. Default: false
125
124
  --host -o Host name to listen on. Default: localhost
126
125
  --httpPort Http port to listen on. Default: 3000
127
126
  --httpsProtocol -H To enable HTTPS, specify directory (relative to your cwd, typically your project dir) for both cert.pem and key.pem files
@@ -134,10 +133,9 @@ All CLI options are optional:
134
133
  --noStripTrailingSlashInUrl Don't strip trailing slash from http routes.
135
134
  --noTimeout -t Disables the timeout feature.
136
135
  --prefix -p Adds a prefix to every path, to send your requests to http://localhost:3000/[prefix]/[your_path] instead. Default: ''
137
- --printOutput Turns on logging of your lambda outputs in the terminal.
138
136
  --reloadHandler Reloads handler with each request.
139
137
  --resourceRoutes Turns on loading of your HTTP proxy settings from serverless.yml
140
- --useChildProcesses [This option is deprecated] Run handlers in a child process.
138
+ --terminateIdleLambdaTime Number of seconds until an idle function is eligible for termination.
141
139
  --useDocker Run handlers in a docker container.
142
140
  --useInProcess Run handlers in the same process as 'serverless-offline'.
143
141
  --webSocketHardTimeout Set WebSocket hard timeout in seconds to reproduce AWS limits (https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html#apigateway-execution-service-websocket-limits-table). Default: 7200 (2 hours)
@@ -188,15 +186,6 @@ Lambda handlers for the `node.js` runtime can run in different execution modes w
188
186
  - global state is being shared across lambda handlers as well as with `serverless` and `serverless-offline`
189
187
  - easy debugging
190
188
 
191
- #### child-processes (this option is deprecated, please use the default worker-threads instead)
192
-
193
- - handlers run in a separate node.js instance
194
- - memory is not being shared between handlers, memory consumption is therefore higher
195
- - memory is being released when handlers reload or after usage
196
- - environment (process.env) is not being shared across handlers
197
- - global state is not being shared across handlers
198
- - debugging more complicated
199
-
200
189
  #### docker
201
190
 
202
191
  - handlers run in a docker container
@@ -215,10 +204,10 @@ the Lambda handler process is running in a child process.
215
204
  To use `Lambda.invoke` you need to set the lambda endpoint to the `serverless-offline` endpoint:
216
205
 
217
206
  ```js
218
- const { env } = require('node:process')
219
- const { Lambda } = require('aws-sdk')
207
+ import { env } from 'node:process'
208
+ import aws from 'aws-sdk'
220
209
 
221
- const lambda = new Lambda({
210
+ const lambda = new aws.Lambda({
222
211
  apiVersion: '2015-03-31',
223
212
  // endpoint needs to be set only if it deviates from the default
224
213
  endpoint: env.IS_OFFLINE
@@ -230,17 +219,17 @@ const lambda = new Lambda({
230
219
  All your lambdas can then be invoked in a handler using
231
220
 
232
221
  ```js
233
- const { Buffer } = require('node:buffer')
234
- const { Lambda } = require('aws-sdk')
222
+ import { Buffer } from 'node:buffer'
223
+ import aws from 'aws-sdk'
235
224
 
236
225
  const { stringify } = JSON
237
226
 
238
- const lambda = new Lambda({
227
+ const lambda = new aws.Lambda({
239
228
  apiVersion: '2015-03-31',
240
229
  endpoint: 'http://localhost:3002',
241
230
  })
242
231
 
243
- exports.handler = async function () {
232
+ export async function handler() {
244
233
  const clientContextData = stringify({ foo: 'foo' })
245
234
 
246
235
  const params = {
@@ -623,9 +612,9 @@ Usage in order to send messages back to clients:
623
612
  Or,
624
613
 
625
614
  ```js
626
- const { ApiGatewayManagementApi } = require('aws-sdk')
615
+ import aws from 'aws-sdk'
627
616
 
628
- const apiGatewayManagementApi = new ApiGatewayManagementApi({
617
+ const apiGatewayManagementApi = new aws.ApiGatewayManagementApi({
629
618
  apiVersion: '2018-11-29',
630
619
  endpoint: 'http://localhost:3001',
631
620
  });
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "dedicatedTo": "Blue, a great migrating bird.",
3
3
  "name": "serverless-offline",
4
- "version": "9.2.6",
4
+ "version": "10.0.0",
5
5
  "description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
6
6
  "license": "MIT",
7
- "main": "./src/index.js",
8
- "exports": "./src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./lambda": "./src/lambda/index.js"
10
+ },
9
11
  "type": "module",
10
12
  "scripts": {
11
13
  "format": "eslint . --fix",
@@ -189,18 +191,18 @@
189
191
  "@hapi/h2o2": "^9.1.0",
190
192
  "@hapi/hapi": "^20.2.2",
191
193
  "@serverless/utils": "^6.7.0",
192
- "aws-sdk": "^2.1195.0",
194
+ "aws-sdk": "^2.1209.0",
193
195
  "boxen": "^7.0.0",
194
196
  "chalk": "^5.0.1",
195
197
  "execa": "^6.1.0",
196
198
  "fs-extra": "^10.1.0",
197
199
  "java-invoke-local": "0.0.6",
198
200
  "js-string-escape": "^1.0.1",
199
- "jsonpath-plus": "^7.0.0",
201
+ "jsonpath-plus": "^7.2.0",
200
202
  "jsonschema": "^1.4.1",
201
203
  "jsonwebtoken": "^8.5.1",
202
204
  "jszip": "^3.10.1",
203
- "luxon": "^3.0.1",
205
+ "luxon": "^3.0.3",
204
206
  "node-fetch": "^3.2.10",
205
207
  "node-schedule": "^2.1.0",
206
208
  "object.hasown": "^1.1.1",
@@ -211,7 +213,7 @@
211
213
  },
212
214
  "devDependencies": {
213
215
  "archiver": "^5.3.1",
214
- "eslint": "^8.22.0",
216
+ "eslint": "^8.23.0",
215
217
  "eslint-config-airbnb-base": "^15.0.0",
216
218
  "eslint-config-prettier": "^8.5.0",
217
219
  "eslint-plugin-import": "^2.25.4",
@@ -6,7 +6,7 @@ import {
6
6
  defaultOptions,
7
7
  SERVER_SHUTDOWN_TIMEOUT,
8
8
  } from './config/index.js'
9
- import { gray, orange } from './config/colors.js'
9
+ import { gray } from './config/colors.js'
10
10
 
11
11
  export default class ServerlessOffline {
12
12
  #cliOptions = null
@@ -83,15 +83,6 @@ export default class ServerlessOffline {
83
83
  }
84
84
 
85
85
  await Promise.all(eventModules)
86
-
87
- if (this.#options.useChildProcesses) {
88
- log.notice()
89
- log.warning(
90
- orange(`'--useChildProcesses' is deprecated and will be removed in the next major version. Worker threads, the current default, should provide the same if not an even better developer experience.
91
- If you are experiencing any issues please let us know: https://github.com/dherault/serverless-offline/issues`),
92
- )
93
- log.notice()
94
- }
95
86
  }
96
87
 
97
88
  async #ready() {
@@ -54,14 +54,6 @@ export default {
54
54
  type: 'boolean',
55
55
  usage: 'Enforce secure cookies',
56
56
  },
57
- functionCleanupIdleTimeSeconds: {
58
- type: 'string',
59
- usage: 'Number of seconds until an idle function is eligible for cleanup',
60
- },
61
- hideStackTraces: {
62
- type: 'boolean',
63
- usage: 'Hide the stack trace on lambda failure. Default: false',
64
- },
65
57
  host: {
66
58
  shortcut: 'o',
67
59
  type: 'string',
@@ -118,10 +110,6 @@ export default {
118
110
  usage:
119
111
  'Adds a prefix to every path, to send your requests to http://localhost:3000/prefix/[your_path] instead.',
120
112
  },
121
- printOutput: {
122
- type: 'boolean',
123
- usage: 'Outputs your lambda response to the terminal.',
124
- },
125
113
  reloadHandler: {
126
114
  type: 'boolean',
127
115
  usage: 'Reloads handler with each request.',
@@ -130,10 +118,10 @@ export default {
130
118
  type: 'boolean',
131
119
  usage: 'Turns on loading of your HTTP proxy settings from serverless.yml.',
132
120
  },
133
- useChildProcesses: {
134
- type: 'boolean',
121
+ terminateIdleLambdaTime: {
122
+ type: 'string',
135
123
  usage:
136
- '[This option is deprecated] Use separate node process to run handlers.',
124
+ 'Number of seconds until an idle function is eligible for termination.',
137
125
  },
138
126
  useDocker: {
139
127
  type: 'boolean',
@@ -13,8 +13,6 @@ export default {
13
13
  dockerNetwork: null,
14
14
  dockerReadOnly: true,
15
15
  enforceSecureCookies: false,
16
- functionCleanupIdleTimeSeconds: 60,
17
- hideStackTraces: false,
18
16
  host: 'localhost',
19
17
  httpPort: 3000,
20
18
  httpsProtocol: null,
@@ -26,10 +24,9 @@ export default {
26
24
  noStripTrailingSlashInUrl: false,
27
25
  noTimeout: false,
28
26
  prefix: '',
29
- printOutput: false,
30
27
  reloadHandler: false,
31
28
  resourceRoutes: false,
32
- useChildProcesses: false,
29
+ terminateIdleLambdaTime: 60,
33
30
  useDocker: false,
34
31
  useInProcess: false,
35
32
  webSocketHardTimeout: 7200,
@@ -2,10 +2,10 @@
2
2
  // https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
3
3
 
4
4
  // .NET CORE
5
- export const supportedDotnetcore = new Set([
6
- // 'dotnet6',
7
- // 'dotnetcore3.1',
8
- ])
5
+ // export const supportedDotnetcore = new Set([
6
+ // 'dotnet6',
7
+ // 'dotnetcore3.1',
8
+ // ])
9
9
 
10
10
  // GO
11
11
  export const supportedGo = new Set(['go1.x'])
@@ -37,7 +37,7 @@ export const supportedRuby = new Set(['ruby2.7'])
37
37
  // deprecated runtimes
38
38
  // https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html
39
39
  export const supportedRuntimes = new Set([
40
- ...supportedDotnetcore,
40
+ // ...supportedDotnetcore,
41
41
  ...supportedGo,
42
42
  ...supportedJava,
43
43
  ...supportedNodejs,
@@ -45,3 +45,9 @@ export const supportedRuntimes = new Set([
45
45
  ...supportedPython,
46
46
  ...supportedRuby,
47
47
  ])
48
+
49
+ export const unsupportedDockerRuntimes = new Set([
50
+ 'nodejs14.x',
51
+ 'nodejs16.x',
52
+ 'python3.9',
53
+ ])
@@ -580,21 +580,8 @@ export default class HttpServer {
580
580
 
581
581
  // Failure handling
582
582
  let errorStatusCode = '502'
583
- if (err) {
584
- // Since the --useChildProcesses option loads the handler in
585
- // a separate process and serverless-offline communicates with it
586
- // over IPC, we are unable to catch JavaScript unhandledException errors
587
- // when the handler code contains bad JavaScript. Instead, we "catch"
588
- // it here and reply in the same way that we would have above when
589
- // we lazy-load the non-IPC handler function.
590
- if (this.#options.useChildProcesses && err.ipcException) {
591
- return this.#reply502(
592
- response,
593
- `Error while loading ${functionKey}`,
594
- err,
595
- )
596
- }
597
583
 
584
+ if (err) {
598
585
  const errorMessage = (err.message || err).toString()
599
586
 
600
587
  const found = errorMessage.match(/\[(\d{3})]/)
@@ -614,10 +601,6 @@ export default class HttpServer {
614
601
 
615
602
  log.error(errorMessage)
616
603
 
617
- if (!this.#options.hideStackTraces) {
618
- log.error(err.stack)
619
- }
620
-
621
604
  for (const [key, value] of entries(endpoint.responses)) {
622
605
  if (
623
606
  key !== 'default' &&
@@ -894,20 +877,6 @@ export default class HttpServer {
894
877
  }
895
878
  }
896
879
 
897
- let whatToLog = result
898
-
899
- try {
900
- whatToLog = stringify(result)
901
- } catch {
902
- // nothing
903
- } finally {
904
- if (this.#options.printOutput) {
905
- log.notice(
906
- err ? `Replying ${statusCode}` : `[${statusCode}] ${whatToLog}`,
907
- )
908
- }
909
- }
910
-
911
880
  return response
912
881
  }
913
882
  }
@@ -2,6 +2,7 @@ import { readFile, writeFile } from 'node:fs/promises'
2
2
  import { dirname, join, resolve } from 'node:path'
3
3
  import process from 'node:process'
4
4
  import { performance } from 'node:perf_hooks'
5
+ import { promisify } from 'node:util'
5
6
  import { log } from '@serverless/utils/log.js'
6
7
  import { emptyDir, ensureDir, remove } from 'fs-extra'
7
8
  import jszip from 'jszip'
@@ -18,6 +19,8 @@ import { createUniqueId } from '../utils/index.js'
18
19
  const { ceil } = Math
19
20
  const { entries, fromEntries } = Object
20
21
 
22
+ const setTimeoutPromise = promisify(setTimeout)
23
+
21
24
  export default class LambdaFunction {
22
25
  #artifact = null
23
26
 
@@ -37,6 +40,8 @@ export default class LambdaFunction {
37
40
 
38
41
  #handler = null
39
42
 
43
+ #handlerRunDone = false
44
+
40
45
  #handlerRunner = null
41
46
 
42
47
  #idleTimeStarted = null
@@ -49,13 +54,15 @@ export default class LambdaFunction {
49
54
 
50
55
  #memorySize = null
51
56
 
57
+ #noTimeout = null
58
+
52
59
  #region = null
53
60
 
54
61
  #runtime = null
55
62
 
56
- #timeout = null
63
+ #status = 'IDLE' // can be 'BUSY' or 'IDLE'
57
64
 
58
- status = 'IDLE' // can be 'BUSY' or 'IDLE'
65
+ #timeout = null
59
66
 
60
67
  constructor(functionKey, functionDefinition, serverless, options) {
61
68
  const {
@@ -71,28 +78,28 @@ export default class LambdaFunction {
71
78
 
72
79
  const { handler, name, package: functionPackage = {} } = functionDefinition
73
80
 
74
- const memorySize =
81
+ // this._executionTimeout = null
82
+ this.#functionKey = functionKey
83
+ this.#functionName = name
84
+ this.#handler = handler
85
+
86
+ this.#memorySize =
75
87
  functionDefinition.memorySize ||
76
88
  provider.memorySize ||
77
89
  DEFAULT_LAMBDA_MEMORY_SIZE
78
90
 
79
- const runtime =
91
+ this.#noTimeout = options.noTimeout
92
+
93
+ this.#region = provider.region
94
+
95
+ this.#runtime =
80
96
  functionDefinition.runtime || provider.runtime || DEFAULT_LAMBDA_RUNTIME
81
97
 
82
- const timeout =
98
+ this.#timeout =
83
99
  (functionDefinition.timeout ||
84
100
  provider.timeout ||
85
101
  DEFAULT_LAMBDA_TIMEOUT) * 1000
86
102
 
87
- // this._executionTimeout = null
88
- this.#functionKey = functionKey
89
- this.#functionName = name
90
- this.#handler = handler
91
- this.#memorySize = memorySize
92
- this.#region = provider.region
93
- this.#runtime = runtime
94
- this.#timeout = timeout
95
-
96
103
  this.#verifySupportedRuntime()
97
104
 
98
105
  const env = {
@@ -141,17 +148,17 @@ export default class LambdaFunction {
141
148
  handler,
142
149
  layers: functionDefinition.layers || [],
143
150
  provider,
144
- runtime,
151
+ runtime: this.#runtime,
145
152
  serverlessPath,
146
153
  servicePackage: servicePackage.artifact
147
154
  ? resolve(servicepath, servicePackage.artifact)
148
155
  : undefined,
149
156
  servicePath: servicepath,
150
- timeout,
157
+ timeout: this.#timeout,
151
158
  }
152
159
 
153
160
  this.#handlerRunner = new HandlerRunner(funOptions, options, env)
154
- this.#lambdaContext = new LambdaContext(name, memorySize)
161
+ this.#lambdaContext = new LambdaContext(name, this.#memorySize)
155
162
  }
156
163
 
157
164
  #startExecutionTimer() {
@@ -259,16 +266,33 @@ export default class LambdaFunction {
259
266
  this.#initialized = true
260
267
  }
261
268
 
262
- get idleTimeInMinutes() {
263
- return (performance.now() - this.#idleTimeStarted) / 1000 / 60
269
+ get idleTimeInMillis() {
270
+ return performance.now() - this.#idleTimeStarted
264
271
  }
265
272
 
266
273
  get functionName() {
267
274
  return this.#functionName
268
275
  }
269
276
 
277
+ get status() {
278
+ return this.#status
279
+ }
280
+
281
+ async #timeoutAndTerminate() {
282
+ await setTimeoutPromise(this.#timeout)
283
+
284
+ // if the handler has finished before the timeout don't terminate
285
+ if (this.#handlerRunDone) {
286
+ return
287
+ }
288
+
289
+ await this.#handlerRunner.cleanup()
290
+
291
+ throw new Error('Lambda timeout.')
292
+ }
293
+
270
294
  async runHandler() {
271
- this.status = 'BUSY'
295
+ this.#status = 'BUSY'
272
296
 
273
297
  if (!this.#initialized) {
274
298
  await this.#initialize()
@@ -283,7 +307,14 @@ export default class LambdaFunction {
283
307
 
284
308
  this.#startExecutionTimer()
285
309
 
286
- const result = await this.#handlerRunner.run(this.#event, context)
310
+ this.#handlerRunDone = false
311
+
312
+ const result = await Promise.race([
313
+ this.#handlerRunner.run(this.#event, context),
314
+ ...(this.#noTimeout ? [] : [this.#timeoutAndTerminate()]),
315
+ ])
316
+
317
+ this.#handlerRunDone = true
287
318
 
288
319
  this.#stopExecutionTimer()
289
320
 
@@ -298,7 +329,7 @@ export default class LambdaFunction {
298
329
  )
299
330
  }
300
331
 
301
- this.status = 'IDLE'
332
+ this.#status = 'IDLE'
302
333
  this.#startIdleTimer()
303
334
 
304
335
  return result
@@ -20,19 +20,20 @@ export default class LambdaFunctionPool {
20
20
  }
21
21
 
22
22
  #startCleanTimer() {
23
+ const functionCleanupIdleTimeInMillis =
24
+ this.#options.terminateIdleLambdaTime * 1000
25
+
23
26
  // NOTE: don't use setInterval, as it would schedule always a new run,
24
27
  // regardless of function processing time and e.g. user action (debugging)
25
28
  this.#timerRef = setTimeout(() => {
26
29
  // console.log('run cleanup')
27
30
  this.#pool.forEach((lambdaFunctions) => {
28
31
  lambdaFunctions.forEach((lambdaFunction) => {
29
- const { idleTimeInMinutes, status } = lambdaFunction
30
- // console.log(idleTimeInMinutes, status)
32
+ const { idleTimeInMillis, status } = lambdaFunction
31
33
 
32
34
  if (
33
35
  status === 'IDLE' &&
34
- idleTimeInMinutes >=
35
- this.#options.functionCleanupIdleTimeSeconds / 60
36
+ idleTimeInMillis >= functionCleanupIdleTimeInMillis
36
37
  ) {
37
38
  // console.log(`removed Lambda Function ${lambdaFunction.functionName}`)
38
39
  lambdaFunction.cleanup()
@@ -43,7 +44,7 @@ export default class LambdaFunctionPool {
43
44
 
44
45
  // schedule new timer
45
46
  this.#startCleanTimer()
46
- }, (this.#options.functionCleanupIdleTimeSeconds * 1000) / 2)
47
+ }, functionCleanupIdleTimeInMillis)
47
48
  }
48
49
 
49
50
  #cleanupPool() {
@@ -5,6 +5,7 @@ import {
5
5
  supportedNodejs,
6
6
  supportedPython,
7
7
  supportedRuby,
8
+ unsupportedDockerRuntimes,
8
9
  } from '../../config/index.js'
9
10
 
10
11
  export default class HandlerRunner {
@@ -23,25 +24,19 @@ export default class HandlerRunner {
23
24
  }
24
25
 
25
26
  async #loadRunner() {
26
- const { useChildProcesses, useDocker, useInProcess } = this.#options
27
+ const { useDocker, useInProcess } = this.#options
27
28
  const { handler, runtime } = this.#funOptions
28
29
 
29
30
  log.debug(`Loading handler... (${handler})`)
30
31
 
31
32
  if (useDocker) {
32
- // https://github.com/lambci/docker-lambda/issues/329
33
- if (runtime === 'nodejs14.x') {
33
+ if (unsupportedDockerRuntimes.has(runtime)) {
34
34
  log.warning(
35
- '"nodejs14.x" runtime is not supported with docker. See https://github.com/lambci/docker-lambda/issues/329',
35
+ `"${runtime}" runtime is not supported with docker. See https://github.com/lambci/docker-lambda`,
36
36
  )
37
37
  throw new Error('Unsupported runtime')
38
38
  }
39
39
 
40
- if (runtime === 'python3.9') {
41
- log.warning('"python3.9" runtime is not supported with docker.')
42
- throw new Error('Unsupported runtime')
43
- }
44
-
45
40
  const dockerOptions = {
46
41
  host: this.#options.dockerHost,
47
42
  hostServicePath: this.#options.dockerHostServicePath,
@@ -56,14 +51,6 @@ export default class HandlerRunner {
56
51
  }
57
52
 
58
53
  if (supportedNodejs.has(runtime)) {
59
- if (useChildProcesses) {
60
- const { default: ChildProcessRunner } = await import(
61
- './child-process-runner/index.js'
62
- )
63
-
64
- return new ChildProcessRunner(this.#funOptions, this.#env)
65
- }
66
-
67
54
  if (useInProcess) {
68
55
  const { default: InProcessRunner } = await import(
69
56
  './in-process-runner/index.js'
@@ -86,11 +86,6 @@ export default class InProcessRunner {
86
86
  // no try/catch so that errors bubble up and are logged with root stack traces
87
87
  const result = handler(event, lambdaContext, callback)
88
88
 
89
- // // not a Promise, which is not supported by aws
90
- // if (result == null || typeof result.then !== 'function') {
91
- // throw new Error(`Synchronous function execution is not supported.`)
92
- // }
93
-
94
89
  const responses = [callbackWrapper]
95
90
 
96
91
  // Promise was returned
@@ -83,7 +83,7 @@ export default class RubyRunner {
83
83
 
84
84
  // console.log(input)
85
85
 
86
- const ruby = execa(
86
+ const { stderr, stdout } = await execa(
87
87
  runtime,
88
88
  [
89
89
  resolve(__dirname, 'invoke.rb'),
@@ -97,10 +97,6 @@ export default class RubyRunner {
97
97
  },
98
98
  )
99
99
 
100
- const result = await ruby
101
-
102
- const { stderr, stdout } = result
103
-
104
100
  if (stderr) {
105
101
  // TODO
106
102
 
@@ -1,7 +1,10 @@
1
+ export { default as checkDockerDaemon } from './checkDockerDaemon.js'
2
+ export { default as checkGoVersion } from './checkGoVersion.js'
1
3
  export { default as createApiKey } from './createApiKey.js'
2
4
  export { default as createUniqueId } from './createUniqueId.js'
3
5
  export { default as detectExecutable } from './detectExecutable.js'
4
6
  export { default as formatToClfTime } from './formatToClfTime.js'
7
+ export { default as generateHapiPath } from './generateHapiPath.js'
5
8
  export { default as getHttpApiCorsConfig } from './getHttpApiCorsConfig.js'
6
9
  export { default as jsonPath } from './jsonPath.js'
7
10
  export { default as lowerCaseKeys } from './lowerCaseKeys.js'
@@ -10,9 +13,7 @@ export { default as parseMultiValueHeaders } from './parseMultiValueHeaders.js'
10
13
  export { default as parseMultiValueQueryStringParameters } from './parseMultiValueQueryStringParameters.js'
11
14
  export { default as parseQueryStringParameters } from './parseQueryStringParameters.js'
12
15
  export { default as splitHandlerPathAndName } from './splitHandlerPathAndName.js'
13
- export { default as checkDockerDaemon } from './checkDockerDaemon.js'
14
- export { default as checkGoVersion } from './checkGoVersion.js'
15
- export { default as generateHapiPath } from './generateHapiPath.js'
16
+
16
17
  // export { default as baseImage } from './baseImage.js'
17
18
 
18
19
  const { isArray } = Array
@@ -1,75 +0,0 @@
1
- import { dirname, resolve } from 'node:path'
2
- import { fileURLToPath } from 'node:url'
3
- import { log } from '@serverless/utils/log.js'
4
- import { execaNode } from 'execa'
5
-
6
- const __dirname = dirname(fileURLToPath(import.meta.url))
7
- const childProcessHelperPath = resolve(__dirname, 'childProcessHelper.js')
8
-
9
- export default class ChildProcessRunner {
10
- #codeDir = null
11
-
12
- #env = null
13
-
14
- #functionKey = null
15
-
16
- #handler = null
17
-
18
- #servicePath = null
19
-
20
- #timeout = null
21
-
22
- constructor(funOptions, env) {
23
- const { codeDir, functionKey, handler, servicePath, timeout } = funOptions
24
-
25
- this.#codeDir = codeDir
26
- this.#env = env
27
- this.#functionKey = functionKey
28
- this.#handler = handler
29
- this.#servicePath = servicePath
30
- this.#timeout = timeout
31
- }
32
-
33
- // no-op
34
- // () => void
35
- cleanup() {}
36
-
37
- async run(event, context) {
38
- const childProcess = execaNode(
39
- childProcessHelperPath,
40
- [this.#functionKey, this.#handler, this.#servicePath, this.#codeDir],
41
- {
42
- env: this.#env,
43
- stdio: 'inherit',
44
- },
45
- )
46
-
47
- childProcess.send({
48
- context,
49
- event,
50
- timeout: this.#timeout,
51
- })
52
-
53
- let result
54
-
55
- try {
56
- result = await new Promise((res, rej) => {
57
- childProcess.on('message', (data) => {
58
- if (data.error) {
59
- rej(data.error)
60
- return
61
- }
62
- res(data.result)
63
- })
64
- })
65
- } catch (err) {
66
- // TODO
67
- log.error(err)
68
- throw err
69
- } finally {
70
- childProcess.kill()
71
- }
72
-
73
- return result
74
- }
75
- }
@@ -1,45 +0,0 @@
1
- import process, { argv } from 'node:process'
2
- import InProcessRunner from '../in-process-runner/index.js'
3
-
4
- // TODO handle this:
5
- process.on('uncaughtException', (err) => {
6
- const {
7
- constructor: { name },
8
- message,
9
- stack,
10
- } = err
11
-
12
- process.send({
13
- // process.send() can't serialize an Error object, so we help it out a bit
14
- error: {
15
- constructor: {
16
- name,
17
- },
18
- message,
19
- stack,
20
- },
21
- })
22
- })
23
-
24
- const [, , functionKey, handler, servicePath, codeDir] = argv
25
-
26
- process.on('message', async (messageData) => {
27
- const { context, event, timeout } = messageData
28
-
29
- // TODO we could probably cache this in the module scope?
30
- const inProcessRunner = new InProcessRunner(
31
- {
32
- codeDir,
33
- functionKey,
34
- handler,
35
- servicePath,
36
- timeout,
37
- },
38
- process.env,
39
- )
40
-
41
- const result = await inProcessRunner.run(event, context)
42
-
43
- // TODO check serializeability (contains function, symbol etc)
44
- process.send({ result })
45
- })
@@ -1 +0,0 @@
1
- export { default } from './ChildProcessRunner.js'