serverless-offline 9.1.2 → 9.1.5
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/package.json +5 -5
- package/src/ServerlessOffline.js +2 -6
- package/src/config/defaultOptions.js +1 -1
- package/src/events/http/Http.js +4 -4
- package/src/events/http/HttpServer.js +181 -153
- package/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +11 -15
- package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +9 -4
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.
|
|
4
|
+
"version": "9.1.5",
|
|
5
5
|
"description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "./src/index.js",
|
|
@@ -194,7 +194,8 @@
|
|
|
194
194
|
"@hapi/boom": "^10.0.0",
|
|
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
199
|
"boxen": "^7.0.0",
|
|
199
200
|
"chalk": "^5.0.1",
|
|
200
201
|
"execa": "^6.1.0",
|
|
@@ -204,7 +205,7 @@
|
|
|
204
205
|
"jsonpath-plus": "^7.0.0",
|
|
205
206
|
"jsonschema": "^1.4.1",
|
|
206
207
|
"jsonwebtoken": "^8.5.1",
|
|
207
|
-
"jszip": "^3.10.
|
|
208
|
+
"jszip": "^3.10.1",
|
|
208
209
|
"luxon": "^3.0.1",
|
|
209
210
|
"node-fetch": "^3.2.10",
|
|
210
211
|
"node-schedule": "^2.1.0",
|
|
@@ -216,7 +217,7 @@
|
|
|
216
217
|
},
|
|
217
218
|
"devDependencies": {
|
|
218
219
|
"archiver": "^5.3.1",
|
|
219
|
-
"eslint": "^8.
|
|
220
|
+
"eslint": "^8.21.0",
|
|
220
221
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
221
222
|
"eslint-config-prettier": "^8.5.0",
|
|
222
223
|
"eslint-plugin-import": "^2.25.4",
|
|
@@ -230,7 +231,6 @@
|
|
|
230
231
|
"standard-version": "^9.5.0"
|
|
231
232
|
},
|
|
232
233
|
"peerDependencies": {
|
|
233
|
-
"@serverless/utils": "^6.7.0",
|
|
234
234
|
"serverless": "^3.2.0"
|
|
235
235
|
}
|
|
236
236
|
}
|
package/src/ServerlessOffline.js
CHANGED
|
@@ -168,7 +168,7 @@ export default class ServerlessOffline {
|
|
|
168
168
|
|
|
169
169
|
this.#http = new Http(this.#serverless, this.#options, this.#lambda)
|
|
170
170
|
|
|
171
|
-
await this.#http.
|
|
171
|
+
await this.#http.createServer()
|
|
172
172
|
|
|
173
173
|
this.#http.create(events)
|
|
174
174
|
|
|
@@ -236,12 +236,8 @@ export default class ServerlessOffline {
|
|
|
236
236
|
.replace(/\s/g, '')
|
|
237
237
|
.split(',')
|
|
238
238
|
|
|
239
|
-
if (this.#options.corsDisallowCredentials) {
|
|
240
|
-
this.#options.corsAllowCredentials = false
|
|
241
|
-
}
|
|
242
|
-
|
|
243
239
|
this.#options.corsConfig = {
|
|
244
|
-
credentials: this.#options.
|
|
240
|
+
credentials: !this.#options.corsDisallowCredentials,
|
|
245
241
|
exposedHeaders: this.#options.corsExposedHeaders,
|
|
246
242
|
headers: this.#options.corsAllowHeaders,
|
|
247
243
|
origin: this.#options.corsAllowOrigin,
|
|
@@ -2,9 +2,9 @@ import { createApiKey } from '../utils/index.js'
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
apiKey: createApiKey(),
|
|
5
|
-
corsAllowCredentials: true, // TODO no CLI option
|
|
6
5
|
corsAllowHeaders: 'accept,content-type,x-api-key,authorization',
|
|
7
6
|
corsAllowOrigin: '*',
|
|
7
|
+
corsDisallowCredentials: true,
|
|
8
8
|
corsExposedHeaders: 'WWW-Authenticate,Server-Authorization',
|
|
9
9
|
disableCookieValidation: false,
|
|
10
10
|
disableScheduledEvents: false,
|
package/src/events/http/Http.js
CHANGED
|
@@ -17,6 +17,10 @@ export default class Http {
|
|
|
17
17
|
return this.#httpServer.stop(timeout)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
async createServer() {
|
|
21
|
+
await this.#httpServer.createServer()
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
#createEvent(functionKey, rawHttpEventDefinition, handler) {
|
|
21
25
|
const httpEvent = new HttpEventDefinition(rawHttpEventDefinition)
|
|
22
26
|
|
|
@@ -39,10 +43,6 @@ export default class Http {
|
|
|
39
43
|
this.#httpServer.create404Route()
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
registerPlugins() {
|
|
43
|
-
return this.#httpServer.registerPlugins()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
46
|
// TEMP FIXME quick fix to expose gateway server for testing, look for better solution
|
|
47
47
|
getServer() {
|
|
48
48
|
return this.#httpServer.getServer()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer'
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
3
|
import { createRequire } from 'node:module'
|
|
4
4
|
import { join, resolve } from 'node:path'
|
|
5
5
|
import { exit } from 'node:process'
|
|
@@ -47,7 +47,9 @@ export default class HttpServer {
|
|
|
47
47
|
this.#lambda = lambda
|
|
48
48
|
this.#options = options
|
|
49
49
|
this.#serverless = serverless
|
|
50
|
+
}
|
|
50
51
|
|
|
52
|
+
async createServer() {
|
|
51
53
|
const {
|
|
52
54
|
enforceSecureCookies,
|
|
53
55
|
host,
|
|
@@ -80,14 +82,20 @@ export default class HttpServer {
|
|
|
80
82
|
// HTTPS support
|
|
81
83
|
if (typeof httpsProtocol === 'string' && httpsProtocol.length > 0) {
|
|
82
84
|
serverOptions.tls = {
|
|
83
|
-
cert:
|
|
84
|
-
key:
|
|
85
|
+
cert: readFile(resolve(httpsProtocol, 'cert.pem'), 'ascii'),
|
|
86
|
+
key: readFile(resolve(httpsProtocol, 'key.pem'), 'ascii'),
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
// Hapijs server creation
|
|
89
91
|
this.#server = new Server(serverOptions)
|
|
90
92
|
|
|
93
|
+
try {
|
|
94
|
+
await this.#server.register([h2o2])
|
|
95
|
+
} catch (err) {
|
|
96
|
+
log.error(err)
|
|
97
|
+
}
|
|
98
|
+
|
|
91
99
|
// Enable CORS preflight response
|
|
92
100
|
this.#server.ext('onPreResponse', (request, h) => {
|
|
93
101
|
if (request.headers.origin) {
|
|
@@ -205,14 +213,6 @@ export default class HttpServer {
|
|
|
205
213
|
})
|
|
206
214
|
}
|
|
207
215
|
|
|
208
|
-
async registerPlugins() {
|
|
209
|
-
try {
|
|
210
|
-
await this.#server.register([h2o2])
|
|
211
|
-
} catch (err) {
|
|
212
|
-
log.error(err)
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
216
|
#logPluginIssue() {
|
|
217
217
|
log.notice(
|
|
218
218
|
'If you think this is an issue with the plugin please submit it, thanks!\nhttps://github.com/dherault/serverless-offline/issues',
|
|
@@ -260,7 +260,7 @@ export default class HttpServer {
|
|
|
260
260
|
log.debug(`Creating Authorization scheme for ${authKey}`)
|
|
261
261
|
|
|
262
262
|
// Create the Auth Scheme for the endpoint
|
|
263
|
-
const scheme = createJWTAuthScheme(jwtSettings
|
|
263
|
+
const scheme = createJWTAuthScheme(jwtSettings)
|
|
264
264
|
|
|
265
265
|
// Set the auth scheme and strategy on the server
|
|
266
266
|
this.#server.auth.scheme(authSchemeName, scheme)
|
|
@@ -338,6 +338,7 @@ export default class HttpServer {
|
|
|
338
338
|
* /tests/integration/custom-authentication
|
|
339
339
|
*/
|
|
340
340
|
const customizations = this.#serverless.service.custom
|
|
341
|
+
|
|
341
342
|
if (
|
|
342
343
|
customizations &&
|
|
343
344
|
customizations.offline?.customAuthenticationProvider
|
|
@@ -350,11 +351,13 @@ export default class HttpServer {
|
|
|
350
351
|
)
|
|
351
352
|
|
|
352
353
|
const strategy = provider(endpoint, functionKey, method, path)
|
|
354
|
+
|
|
353
355
|
this.#server.auth.scheme(
|
|
354
356
|
strategy.scheme,
|
|
355
357
|
strategy.getAuthenticateFunction,
|
|
356
358
|
)
|
|
357
359
|
this.#server.auth.strategy(strategy.name, strategy.scheme)
|
|
360
|
+
|
|
358
361
|
return strategy.name
|
|
359
362
|
}
|
|
360
363
|
|
|
@@ -363,164 +366,44 @@ export default class HttpServer {
|
|
|
363
366
|
? null
|
|
364
367
|
: this.#configureJWTAuthorization(endpoint, functionKey, method, path) ||
|
|
365
368
|
this.#configureAuthorization(endpoint, functionKey, method, path)
|
|
369
|
+
|
|
366
370
|
return authStrategyName
|
|
367
371
|
}
|
|
368
372
|
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
let method
|
|
373
|
-
let path
|
|
374
|
-
let hapiPath
|
|
375
|
-
|
|
376
|
-
if (httpEvent.isHttpApi) {
|
|
377
|
-
if (httpEvent.routeKey === '$default') {
|
|
378
|
-
method = 'ANY'
|
|
379
|
-
path = httpEvent.routeKey
|
|
380
|
-
hapiPath = '/{default*}'
|
|
381
|
-
} else {
|
|
382
|
-
;[method, path] = httpEvent.routeKey.split(' ')
|
|
383
|
-
hapiPath = generateHapiPath(
|
|
384
|
-
path,
|
|
385
|
-
{
|
|
386
|
-
...this.#options,
|
|
387
|
-
noPrependStageInUrl: true, // Serverless always uses the $default stage
|
|
388
|
-
},
|
|
389
|
-
this.#serverless,
|
|
390
|
-
)
|
|
391
|
-
}
|
|
392
|
-
} else {
|
|
393
|
-
method = httpEvent.method.toUpperCase()
|
|
394
|
-
;({ path } = httpEvent)
|
|
395
|
-
hapiPath = generateHapiPath(path, this.#options, this.#serverless)
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const endpoint = new Endpoint(
|
|
399
|
-
join(this.#serverless.config.servicePath, handlerPath),
|
|
400
|
-
httpEvent,
|
|
401
|
-
).generate()
|
|
402
|
-
|
|
403
|
-
const stage = endpoint.isHttpApi
|
|
404
|
-
? '$default'
|
|
405
|
-
: this.#options.stage || this.#serverless.service.provider.stage
|
|
406
|
-
const protectedRoutes = []
|
|
407
|
-
|
|
408
|
-
if (httpEvent.private) {
|
|
409
|
-
protectedRoutes.push(`${method}#${hapiPath}`)
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
const { host, httpPort, httpsProtocol } = this.#options
|
|
413
|
-
const server = `${httpsProtocol ? 'https' : 'http'}://${host}:${httpPort}`
|
|
414
|
-
|
|
415
|
-
this.#terminalInfo.push({
|
|
416
|
-
invokePath: `/2015-03-31/functions/${functionKey}/invocations`,
|
|
417
|
-
method,
|
|
418
|
-
path: hapiPath,
|
|
419
|
-
server,
|
|
420
|
-
stage:
|
|
421
|
-
endpoint.isHttpApi || this.#options.noPrependStageInUrl ? null : stage,
|
|
422
|
-
})
|
|
423
|
-
|
|
424
|
-
const authStrategyName = this.#setAuthorizationStrategy(
|
|
373
|
+
#createHapiHandler(params) {
|
|
374
|
+
const {
|
|
375
|
+
additionalRequestContext,
|
|
425
376
|
endpoint,
|
|
426
377
|
functionKey,
|
|
378
|
+
hapiMethod,
|
|
379
|
+
hapiPath,
|
|
427
380
|
method,
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
let cors = null
|
|
432
|
-
if (endpoint.cors) {
|
|
433
|
-
cors = {
|
|
434
|
-
credentials:
|
|
435
|
-
endpoint.cors.credentials || this.#options.corsConfig.credentials,
|
|
436
|
-
exposedHeaders: this.#options.corsConfig.exposedHeaders,
|
|
437
|
-
headers: endpoint.cors.headers || this.#options.corsConfig.headers,
|
|
438
|
-
origin: endpoint.cors.origins || this.#options.corsConfig.origin,
|
|
439
|
-
}
|
|
440
|
-
} else if (
|
|
441
|
-
this.#serverless.service.provider.httpApi &&
|
|
442
|
-
this.#serverless.service.provider.httpApi.cors
|
|
443
|
-
) {
|
|
444
|
-
const httpApiCors = getHttpApiCorsConfig(
|
|
445
|
-
this.#serverless.service.provider.httpApi.cors,
|
|
446
|
-
this,
|
|
447
|
-
)
|
|
448
|
-
cors = {
|
|
449
|
-
credentials: httpApiCors.allowCredentials,
|
|
450
|
-
exposedHeaders: httpApiCors.exposedResponseHeaders || [],
|
|
451
|
-
headers: httpApiCors.allowedHeaders || [],
|
|
452
|
-
maxAge: httpApiCors.maxAge,
|
|
453
|
-
origin: httpApiCors.allowedOrigins || [],
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const hapiMethod = method === 'ANY' ? '*' : method
|
|
458
|
-
|
|
459
|
-
const state = this.#options.disableCookieValidation
|
|
460
|
-
? {
|
|
461
|
-
failAction: 'ignore',
|
|
462
|
-
parse: false,
|
|
463
|
-
}
|
|
464
|
-
: {
|
|
465
|
-
failAction: 'error',
|
|
466
|
-
parse: true,
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const hapiOptions = {
|
|
470
|
-
auth: authStrategyName,
|
|
471
|
-
cors,
|
|
472
|
-
state,
|
|
473
|
-
timeout: { socket: false },
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// skip HEAD routes as hapi will fail with 'Method name not allowed: HEAD ...'
|
|
477
|
-
// for more details, check https://github.com/dherault/serverless-offline/issues/204
|
|
478
|
-
if (hapiMethod === 'HEAD') {
|
|
479
|
-
log.notice(
|
|
480
|
-
'HEAD method event detected. Skipping HAPI server route mapping',
|
|
481
|
-
)
|
|
482
|
-
|
|
483
|
-
return
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
if (hapiMethod !== 'HEAD' && hapiMethod !== 'GET') {
|
|
487
|
-
// maxBytes: Increase request size from 1MB default limit to 10MB.
|
|
488
|
-
// Cf AWS API GW payload limits.
|
|
489
|
-
hapiOptions.payload = {
|
|
490
|
-
maxBytes: 1024 * 1024 * 10,
|
|
491
|
-
parse: false,
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
const additionalRequestContext = {}
|
|
496
|
-
if (httpEvent.operationId) {
|
|
497
|
-
additionalRequestContext.operationName = httpEvent.operationId
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
hapiOptions.tags = ['api']
|
|
381
|
+
protectedRoute,
|
|
382
|
+
stage,
|
|
383
|
+
} = params
|
|
501
384
|
|
|
502
|
-
|
|
385
|
+
return async (request, h) => {
|
|
503
386
|
const requestPath =
|
|
504
387
|
endpoint.isHttpApi || this.#options.noPrependStageInUrl
|
|
505
388
|
? request.path
|
|
506
389
|
: request.path.substr(`/${stage}`.length)
|
|
507
390
|
|
|
508
|
-
//
|
|
391
|
+
// payload processing
|
|
509
392
|
const encoding = detectEncoding(request)
|
|
510
393
|
|
|
511
394
|
request.payload = request.payload && request.payload.toString(encoding)
|
|
512
395
|
request.rawPayload = request.payload
|
|
513
396
|
|
|
514
|
-
//
|
|
397
|
+
// incomming request message
|
|
515
398
|
log.notice()
|
|
516
399
|
|
|
517
400
|
log.notice()
|
|
518
401
|
log.notice(`${method} ${request.path} (λ: ${functionKey})`)
|
|
519
402
|
|
|
520
|
-
//
|
|
403
|
+
// check for APIKey
|
|
521
404
|
if (
|
|
522
|
-
(
|
|
523
|
-
|
|
405
|
+
(protectedRoute === `${hapiMethod}#${hapiPath}` ||
|
|
406
|
+
protectedRoute === `ANY#${hapiPath}`) &&
|
|
524
407
|
!this.#options.noAuth
|
|
525
408
|
) {
|
|
526
409
|
const errorResponse = () =>
|
|
@@ -704,8 +587,7 @@ export default class HttpServer {
|
|
|
704
587
|
|
|
705
588
|
const errorMessage = (err.message || err).toString()
|
|
706
589
|
|
|
707
|
-
const
|
|
708
|
-
const found = errorMessage.match(re)
|
|
590
|
+
const found = errorMessage.match(/\[(\d{3})]/)
|
|
709
591
|
|
|
710
592
|
if (found && found.length > 1) {
|
|
711
593
|
;[, errorStatusCode] = found
|
|
@@ -856,7 +738,9 @@ export default class HttpServer {
|
|
|
856
738
|
).getContext()
|
|
857
739
|
|
|
858
740
|
result = renderVelocityTemplateObject(
|
|
859
|
-
{
|
|
741
|
+
{
|
|
742
|
+
root: responseTemplate,
|
|
743
|
+
},
|
|
860
744
|
reponseContext,
|
|
861
745
|
).root
|
|
862
746
|
} catch (error) {
|
|
@@ -965,7 +849,9 @@ export default class HttpServer {
|
|
|
965
849
|
headerValue.forEach((value) => {
|
|
966
850
|
// it looks like Hapi doesn't support multiple headers with the same name,
|
|
967
851
|
// appending values is the closest we can come to the AWS behavior.
|
|
968
|
-
response.header(headerKey, value, {
|
|
852
|
+
response.header(headerKey, value, {
|
|
853
|
+
append: true,
|
|
854
|
+
})
|
|
969
855
|
})
|
|
970
856
|
}
|
|
971
857
|
})
|
|
@@ -1003,7 +889,6 @@ export default class HttpServer {
|
|
|
1003
889
|
}
|
|
1004
890
|
}
|
|
1005
891
|
|
|
1006
|
-
// Log response
|
|
1007
892
|
let whatToLog = result
|
|
1008
893
|
|
|
1009
894
|
try {
|
|
@@ -1018,9 +903,152 @@ export default class HttpServer {
|
|
|
1018
903
|
}
|
|
1019
904
|
}
|
|
1020
905
|
|
|
1021
|
-
// Bon voyage!
|
|
1022
906
|
return response
|
|
1023
907
|
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
createRoutes(functionKey, httpEvent, handler) {
|
|
911
|
+
const [handlerPath] = splitHandlerPathAndName(handler)
|
|
912
|
+
|
|
913
|
+
let method
|
|
914
|
+
let path
|
|
915
|
+
let hapiPath
|
|
916
|
+
|
|
917
|
+
if (httpEvent.isHttpApi) {
|
|
918
|
+
if (httpEvent.routeKey === '$default') {
|
|
919
|
+
method = 'ANY'
|
|
920
|
+
path = httpEvent.routeKey
|
|
921
|
+
hapiPath = '/{default*}'
|
|
922
|
+
} else {
|
|
923
|
+
;[method, path] = httpEvent.routeKey.split(' ')
|
|
924
|
+
hapiPath = generateHapiPath(
|
|
925
|
+
path,
|
|
926
|
+
{
|
|
927
|
+
...this.#options,
|
|
928
|
+
noPrependStageInUrl: true, // Serverless always uses the $default stage
|
|
929
|
+
},
|
|
930
|
+
this.#serverless,
|
|
931
|
+
)
|
|
932
|
+
}
|
|
933
|
+
} else {
|
|
934
|
+
method = httpEvent.method.toUpperCase()
|
|
935
|
+
;({ path } = httpEvent)
|
|
936
|
+
hapiPath = generateHapiPath(path, this.#options, this.#serverless)
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const endpoint = new Endpoint(
|
|
940
|
+
join(this.#serverless.config.servicePath, handlerPath),
|
|
941
|
+
httpEvent,
|
|
942
|
+
).generate()
|
|
943
|
+
|
|
944
|
+
const stage = endpoint.isHttpApi
|
|
945
|
+
? '$default'
|
|
946
|
+
: this.#options.stage || this.#serverless.service.provider.stage
|
|
947
|
+
|
|
948
|
+
const protectedRoute = httpEvent.private
|
|
949
|
+
? `${method}#${hapiPath}`
|
|
950
|
+
: undefined
|
|
951
|
+
|
|
952
|
+
const { host, httpPort, httpsProtocol } = this.#options
|
|
953
|
+
const server = `${httpsProtocol ? 'https' : 'http'}://${host}:${httpPort}`
|
|
954
|
+
|
|
955
|
+
this.#terminalInfo.push({
|
|
956
|
+
invokePath: `/2015-03-31/functions/${functionKey}/invocations`,
|
|
957
|
+
method,
|
|
958
|
+
path: hapiPath,
|
|
959
|
+
server,
|
|
960
|
+
stage:
|
|
961
|
+
endpoint.isHttpApi || this.#options.noPrependStageInUrl ? null : stage,
|
|
962
|
+
})
|
|
963
|
+
|
|
964
|
+
const authStrategyName = this.#setAuthorizationStrategy(
|
|
965
|
+
endpoint,
|
|
966
|
+
functionKey,
|
|
967
|
+
method,
|
|
968
|
+
path,
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
let cors = null
|
|
972
|
+
if (endpoint.cors) {
|
|
973
|
+
cors = {
|
|
974
|
+
credentials:
|
|
975
|
+
endpoint.cors.credentials || this.#options.corsConfig.credentials,
|
|
976
|
+
exposedHeaders: this.#options.corsConfig.exposedHeaders,
|
|
977
|
+
headers: endpoint.cors.headers || this.#options.corsConfig.headers,
|
|
978
|
+
origin: endpoint.cors.origins || this.#options.corsConfig.origin,
|
|
979
|
+
}
|
|
980
|
+
} else if (
|
|
981
|
+
this.#serverless.service.provider.httpApi &&
|
|
982
|
+
this.#serverless.service.provider.httpApi.cors
|
|
983
|
+
) {
|
|
984
|
+
const httpApiCors = getHttpApiCorsConfig(
|
|
985
|
+
this.#serverless.service.provider.httpApi.cors,
|
|
986
|
+
this,
|
|
987
|
+
)
|
|
988
|
+
cors = {
|
|
989
|
+
credentials: httpApiCors.allowCredentials,
|
|
990
|
+
exposedHeaders: httpApiCors.exposedResponseHeaders || [],
|
|
991
|
+
headers: httpApiCors.allowedHeaders || [],
|
|
992
|
+
maxAge: httpApiCors.maxAge,
|
|
993
|
+
origin: httpApiCors.allowedOrigins || [],
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
const hapiMethod = method === 'ANY' ? '*' : method
|
|
998
|
+
|
|
999
|
+
const state = this.#options.disableCookieValidation
|
|
1000
|
+
? {
|
|
1001
|
+
failAction: 'ignore',
|
|
1002
|
+
parse: false,
|
|
1003
|
+
}
|
|
1004
|
+
: {
|
|
1005
|
+
failAction: 'error',
|
|
1006
|
+
parse: true,
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
const hapiOptions = {
|
|
1010
|
+
auth: authStrategyName,
|
|
1011
|
+
cors,
|
|
1012
|
+
state,
|
|
1013
|
+
timeout: { socket: false },
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// skip HEAD routes as hapi will fail with 'Method name not allowed: HEAD ...'
|
|
1017
|
+
// for more details, check https://github.com/dherault/serverless-offline/issues/204
|
|
1018
|
+
if (hapiMethod === 'HEAD') {
|
|
1019
|
+
log.notice(
|
|
1020
|
+
'HEAD method event detected. Skipping HAPI server route mapping',
|
|
1021
|
+
)
|
|
1022
|
+
|
|
1023
|
+
return
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
if (hapiMethod !== 'HEAD' && hapiMethod !== 'GET') {
|
|
1027
|
+
// maxBytes: Increase request size from 1MB default limit to 10MB.
|
|
1028
|
+
// Cf AWS API GW payload limits.
|
|
1029
|
+
hapiOptions.payload = {
|
|
1030
|
+
maxBytes: 1024 * 1024 * 10,
|
|
1031
|
+
parse: false,
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
const additionalRequestContext = {}
|
|
1036
|
+
if (httpEvent.operationId) {
|
|
1037
|
+
additionalRequestContext.operationName = httpEvent.operationId
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
hapiOptions.tags = ['api']
|
|
1041
|
+
|
|
1042
|
+
const hapiHandler = this.#createHapiHandler({
|
|
1043
|
+
additionalRequestContext,
|
|
1044
|
+
endpoint,
|
|
1045
|
+
functionKey,
|
|
1046
|
+
hapiMethod,
|
|
1047
|
+
hapiPath,
|
|
1048
|
+
method,
|
|
1049
|
+
protectedRoute,
|
|
1050
|
+
stage,
|
|
1051
|
+
})
|
|
1024
1052
|
|
|
1025
1053
|
this.#server.route({
|
|
1026
1054
|
handler: hapiHandler,
|
|
@@ -41,19 +41,6 @@ export default class ChildProcessRunner {
|
|
|
41
41
|
},
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
-
let message
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
message = new Promise((res, rej) => {
|
|
48
|
-
childProcess.on('message', (data) => {
|
|
49
|
-
if (data.error) rej(data.error)
|
|
50
|
-
else res(data)
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
} finally {
|
|
54
|
-
childProcess.kill()
|
|
55
|
-
}
|
|
56
|
-
|
|
57
44
|
childProcess.send({
|
|
58
45
|
context,
|
|
59
46
|
event,
|
|
@@ -63,12 +50,21 @@ export default class ChildProcessRunner {
|
|
|
63
50
|
let result
|
|
64
51
|
|
|
65
52
|
try {
|
|
66
|
-
result = await
|
|
53
|
+
result = await new Promise((res, rej) => {
|
|
54
|
+
childProcess.on('message', (data) => {
|
|
55
|
+
if (data.error) {
|
|
56
|
+
rej(data.error)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
res(data)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
67
62
|
} catch (err) {
|
|
68
63
|
// TODO
|
|
69
64
|
log.error(err)
|
|
70
|
-
|
|
71
65
|
throw err
|
|
66
|
+
} finally {
|
|
67
|
+
childProcess.kill()
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
return result
|
|
@@ -50,7 +50,6 @@ export default class InProcessRunner {
|
|
|
50
50
|
let handler
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
|
-
// const { [this.#handlerName]: handler } = await import(this.#handlerPath)
|
|
54
53
|
// eslint-disable-next-line import/no-dynamic-require
|
|
55
54
|
;({ [this.#handlerName]: handler } = require(this.#handlerPath))
|
|
56
55
|
} catch (err) {
|
|
@@ -87,15 +86,21 @@ export default class InProcessRunner {
|
|
|
87
86
|
// create new immutable object
|
|
88
87
|
const lambdaContext = {
|
|
89
88
|
...context,
|
|
90
|
-
done
|
|
91
|
-
|
|
89
|
+
done(err, data) {
|
|
90
|
+
callback(err, data)
|
|
91
|
+
},
|
|
92
|
+
fail(err) {
|
|
93
|
+
callback(err)
|
|
94
|
+
},
|
|
92
95
|
getRemainingTimeInMillis() {
|
|
93
96
|
const timeLeft = executionTimeout - performance.now()
|
|
94
97
|
|
|
95
98
|
// just return 0 for now if we are beyond alotted time (timeout)
|
|
96
99
|
return timeLeft > 0 ? floor(timeLeft) : 0
|
|
97
100
|
},
|
|
98
|
-
succeed
|
|
101
|
+
succeed(res) {
|
|
102
|
+
callback(null, res)
|
|
103
|
+
},
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
let result
|