serverless-offline 13.3.2 → 13.3.3

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 (112) hide show
  1. package/README.md +17 -17
  2. package/package.json +14 -13
  3. package/src/ServerlessOffline.js +42 -42
  4. package/src/config/colors.js +9 -9
  5. package/src/config/commandOptions.js +61 -61
  6. package/src/config/constants.js +5 -5
  7. package/src/config/defaultOptions.js +6 -6
  8. package/src/config/index.js +4 -4
  9. package/src/config/supportedRuntimes.js +18 -18
  10. package/src/errors/index.js +1 -1
  11. package/src/events/alb/Alb.js +2 -2
  12. package/src/events/alb/AlbEventDefinition.js +2 -2
  13. package/src/events/alb/HttpServer.js +54 -54
  14. package/src/events/alb/index.js +1 -1
  15. package/src/events/alb/lambda-events/LambdaAlbRequestEvent.js +2 -2
  16. package/src/events/alb/lambda-events/index.js +1 -1
  17. package/src/events/authCanExecuteResource.js +3 -3
  18. package/src/events/authFunctionNameExtractor.js +9 -9
  19. package/src/events/authMatchPolicyResource.js +8 -8
  20. package/src/events/authValidateContext.js +11 -11
  21. package/src/events/http/Endpoint.js +26 -26
  22. package/src/events/http/Http.js +2 -2
  23. package/src/events/http/HttpEventDefinition.js +2 -2
  24. package/src/events/http/HttpServer.js +156 -156
  25. package/src/events/http/OfflineEndpoint.js +7 -7
  26. package/src/events/http/authJWTSettingsExtractor.js +2 -2
  27. package/src/events/http/createAuthScheme.js +29 -27
  28. package/src/events/http/createJWTAuthScheme.js +12 -12
  29. package/src/events/http/index.js +1 -1
  30. package/src/events/http/javaHelpers.js +2 -2
  31. package/src/events/http/lambda-events/LambdaIntegrationEvent.js +5 -5
  32. package/src/events/http/lambda-events/LambdaProxyIntegrationEvent.js +47 -47
  33. package/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +27 -27
  34. package/src/events/http/lambda-events/VelocityContext.js +28 -32
  35. package/src/events/http/lambda-events/index.js +4 -4
  36. package/src/events/http/lambda-events/renderVelocityTemplateObject.js +13 -13
  37. package/src/events/http/parseResources.js +6 -6
  38. package/src/events/http/payloadSchemaValidator.js +2 -2
  39. package/src/events/schedule/Schedule.js +21 -21
  40. package/src/events/schedule/ScheduleEvent.js +7 -7
  41. package/src/events/schedule/ScheduleEventDefinition.js +1 -1
  42. package/src/events/schedule/index.js +1 -1
  43. package/src/events/websocket/HttpServer.js +9 -9
  44. package/src/events/websocket/WebSocket.js +4 -4
  45. package/src/events/websocket/WebSocketClients.js +29 -29
  46. package/src/events/websocket/WebSocketEventDefinition.js +1 -1
  47. package/src/events/websocket/WebSocketServer.js +9 -9
  48. package/src/events/websocket/http-routes/_catchAll/catchAllRoute.js +3 -3
  49. package/src/events/websocket/http-routes/_catchAll/index.js +1 -1
  50. package/src/events/websocket/http-routes/connections/ConnectionsController.js +1 -1
  51. package/src/events/websocket/http-routes/connections/connectionsRoutes.js +6 -6
  52. package/src/events/websocket/http-routes/connections/index.js +1 -1
  53. package/src/events/websocket/http-routes/index.js +2 -2
  54. package/src/events/websocket/index.js +1 -1
  55. package/src/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +5 -5
  56. package/src/events/websocket/lambda-events/WebSocketConnectEvent.js +7 -6
  57. package/src/events/websocket/lambda-events/WebSocketDisconnectEvent.js +5 -5
  58. package/src/events/websocket/lambda-events/WebSocketEvent.js +2 -2
  59. package/src/events/websocket/lambda-events/WebSocketRequestContext.js +12 -11
  60. package/src/events/websocket/lambda-events/index.js +4 -4
  61. package/src/index.js +1 -1
  62. package/src/lambda/HttpServer.js +11 -11
  63. package/src/lambda/Lambda.js +2 -2
  64. package/src/lambda/LambdaContext.js +1 -1
  65. package/src/lambda/LambdaFunction.js +34 -34
  66. package/src/lambda/LambdaFunctionPool.js +3 -3
  67. package/src/lambda/handler-runner/HandlerRunner.js +12 -12
  68. package/src/lambda/handler-runner/docker-runner/DockerContainer.js +59 -59
  69. package/src/lambda/handler-runner/docker-runner/DockerImage.js +6 -6
  70. package/src/lambda/handler-runner/docker-runner/DockerRunner.js +2 -2
  71. package/src/lambda/handler-runner/docker-runner/index.js +1 -1
  72. package/src/lambda/handler-runner/go-runner/GoRunner.js +34 -34
  73. package/src/lambda/handler-runner/go-runner/index.js +1 -1
  74. package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +7 -7
  75. package/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js +52 -52
  76. package/src/lambda/handler-runner/in-process-runner/index.js +1 -1
  77. package/src/lambda/handler-runner/index.js +1 -1
  78. package/src/lambda/handler-runner/java-runner/JavaRunner.js +13 -13
  79. package/src/lambda/handler-runner/java-runner/index.js +1 -1
  80. package/src/lambda/handler-runner/python-runner/PythonRunner.js +21 -21
  81. package/src/lambda/handler-runner/python-runner/index.js +1 -1
  82. package/src/lambda/handler-runner/ruby-runner/RubyRunner.js +11 -11
  83. package/src/lambda/handler-runner/ruby-runner/index.js +1 -1
  84. package/src/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +6 -6
  85. package/src/lambda/handler-runner/worker-thread-runner/index.js +1 -1
  86. package/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +4 -4
  87. package/src/lambda/index.js +1 -1
  88. package/src/lambda/routes/index.js +2 -2
  89. package/src/lambda/routes/invocations/InvocationsController.js +11 -11
  90. package/src/lambda/routes/invocations/index.js +1 -1
  91. package/src/lambda/routes/invocations/invocationsRoute.js +15 -15
  92. package/src/lambda/routes/invoke-async/index.js +1 -1
  93. package/src/lambda/routes/invoke-async/invokeAsyncRoute.js +6 -6
  94. package/src/utils/checkDockerDaemon.js +8 -8
  95. package/src/utils/checkGoVersion.js +3 -3
  96. package/src/utils/createApiKey.js +2 -2
  97. package/src/utils/detectExecutable.js +2 -2
  98. package/src/utils/formatToClfTime.js +2 -2
  99. package/src/utils/generateHapiPath.js +8 -8
  100. package/src/utils/getApiKeysValues.js +2 -2
  101. package/src/utils/getHttpApiCorsConfig.js +11 -11
  102. package/src/utils/getRawQueryParams.js +2 -2
  103. package/src/utils/index.js +25 -26
  104. package/src/utils/jsonPath.js +1 -1
  105. package/src/utils/logRoutes.js +13 -13
  106. package/src/utils/parseHeaders.js +1 -1
  107. package/src/utils/parseMultiValueHeaders.js +1 -1
  108. package/src/utils/parseMultiValueQueryStringParameters.js +1 -1
  109. package/src/utils/parseQueryStringParameters.js +1 -1
  110. package/src/utils/parseQueryStringParametersForPayloadV2.js +1 -1
  111. package/src/utils/splitHandlerPathAndName.js +3 -3
  112. package/src/utils/createUniqueId.js +0 -5
@@ -1,26 +1,26 @@
1
- import { Buffer } from 'node:buffer'
2
- import { readFile } from 'node:fs/promises'
3
- import { createRequire } from 'node:module'
4
- import { join, resolve } from 'node:path'
5
- import { exit } from 'node:process'
6
- import h2o2 from '@hapi/h2o2'
7
- import { Server } from '@hapi/hapi'
8
- import { log } from '@serverless/utils/log.js'
9
- import authFunctionNameExtractor from '../authFunctionNameExtractor.js'
10
- import authJWTSettingsExtractor from './authJWTSettingsExtractor.js'
11
- import createAuthScheme from './createAuthScheme.js'
12
- import createJWTAuthScheme from './createJWTAuthScheme.js'
13
- import Endpoint from './Endpoint.js'
1
+ import { Buffer } from "node:buffer"
2
+ import { readFile } from "node:fs/promises"
3
+ import { createRequire } from "node:module"
4
+ import { join, resolve } from "node:path"
5
+ import { exit } from "node:process"
6
+ import h2o2 from "@hapi/h2o2"
7
+ import { Server } from "@hapi/hapi"
8
+ import { log } from "@serverless/utils/log.js"
9
+ import authFunctionNameExtractor from "../authFunctionNameExtractor.js"
10
+ import authJWTSettingsExtractor from "./authJWTSettingsExtractor.js"
11
+ import createAuthScheme from "./createAuthScheme.js"
12
+ import createJWTAuthScheme from "./createJWTAuthScheme.js"
13
+ import Endpoint from "./Endpoint.js"
14
14
  import {
15
15
  LambdaIntegrationEvent,
16
16
  LambdaProxyIntegrationEvent,
17
17
  renderVelocityTemplateObject,
18
18
  VelocityContext,
19
- } from './lambda-events/index.js'
20
- import LambdaProxyIntegrationEventV2 from './lambda-events/LambdaProxyIntegrationEventV2.js'
21
- import parseResources from './parseResources.js'
22
- import payloadSchemaValidator from './payloadSchemaValidator.js'
23
- import logRoutes from '../../utils/logRoutes.js'
19
+ } from "./lambda-events/index.js"
20
+ import LambdaProxyIntegrationEventV2 from "./lambda-events/LambdaProxyIntegrationEventV2.js"
21
+ import parseResources from "./parseResources.js"
22
+ import payloadSchemaValidator from "./payloadSchemaValidator.js"
23
+ import logRoutes from "../../utils/logRoutes.js"
24
24
  import {
25
25
  createApiKey,
26
26
  detectEncoding,
@@ -29,7 +29,7 @@ import {
29
29
  getHttpApiCorsConfig,
30
30
  jsonPath,
31
31
  splitHandlerPathAndName,
32
- } from '../../utils/index.js'
32
+ } from "../../utils/index.js"
33
33
 
34
34
  const { parse, stringify } = JSON
35
35
  const { assign, entries, keys } = Object
@@ -57,8 +57,8 @@ export default class HttpServer {
57
57
 
58
58
  async #loadCerts(httpsProtocol) {
59
59
  const [cert, key] = await Promise.all([
60
- readFile(resolve(httpsProtocol, 'cert.pem'), 'utf8'),
61
- readFile(resolve(httpsProtocol, 'key.pem'), 'utf8'),
60
+ readFile(resolve(httpsProtocol, "cert.pem"), "utf8"),
61
+ readFile(resolve(httpsProtocol, "key.pem"), "utf8"),
62
62
  ])
63
63
 
64
64
  return {
@@ -104,7 +104,7 @@ export default class HttpServer {
104
104
  }
105
105
 
106
106
  // Enable CORS preflight response
107
- this.#server.ext('onPreResponse', (request, h) => {
107
+ this.#server.ext("onPreResponse", (request, h) => {
108
108
  if (request.headers.origin) {
109
109
  const response = request.response.isBoom
110
110
  ? request.response.output
@@ -123,11 +123,11 @@ export default class HttpServer {
123
123
  this,
124
124
  )
125
125
 
126
- if (request.method === 'options') {
126
+ if (request.method === "options") {
127
127
  response.statusCode = 204
128
128
  const allowAllOrigins =
129
129
  httpApiCors.allowedOrigins.length === 1 &&
130
- httpApiCors.allowedOrigins[0] === '*'
130
+ httpApiCors.allowedOrigins[0] === "*"
131
131
  if (
132
132
  !allowAllOrigins &&
133
133
  !httpApiCors.allowedOrigins.includes(request.headers.origin)
@@ -136,47 +136,47 @@ export default class HttpServer {
136
136
  }
137
137
  }
138
138
 
139
- response.headers['access-control-allow-origin'] =
139
+ response.headers["access-control-allow-origin"] =
140
140
  request.headers.origin
141
141
  if (httpApiCors.allowCredentials) {
142
- response.headers['access-control-allow-credentials'] = 'true'
142
+ response.headers["access-control-allow-credentials"] = "true"
143
143
  }
144
144
  if (httpApiCors.maxAge) {
145
- response.headers['access-control-max-age'] = httpApiCors.maxAge
145
+ response.headers["access-control-max-age"] = httpApiCors.maxAge
146
146
  }
147
147
  if (httpApiCors.exposedResponseHeaders) {
148
- response.headers['access-control-expose-headers'] =
149
- httpApiCors.exposedResponseHeaders.join(',')
148
+ response.headers["access-control-expose-headers"] =
149
+ httpApiCors.exposedResponseHeaders.join(",")
150
150
  }
151
151
  if (httpApiCors.allowedMethods) {
152
- response.headers['access-control-allow-methods'] =
153
- httpApiCors.allowedMethods.join(',')
152
+ response.headers["access-control-allow-methods"] =
153
+ httpApiCors.allowedMethods.join(",")
154
154
  }
155
155
  if (httpApiCors.allowedHeaders) {
156
- response.headers['access-control-allow-headers'] =
157
- httpApiCors.allowedHeaders.join(',')
156
+ response.headers["access-control-allow-headers"] =
157
+ httpApiCors.allowedHeaders.join(",")
158
158
  }
159
159
  } else {
160
- response.headers['access-control-allow-origin'] =
160
+ response.headers["access-control-allow-origin"] =
161
161
  request.headers.origin
162
- response.headers['access-control-allow-credentials'] = 'true'
162
+ response.headers["access-control-allow-credentials"] = "true"
163
163
 
164
- if (request.method === 'options') {
164
+ if (request.method === "options") {
165
165
  response.statusCode = 200
166
166
 
167
- response.headers['access-control-expose-headers'] =
168
- request.headers['access-control-expose-headers'] ||
169
- 'content-type, content-length, etag'
170
- response.headers['access-control-max-age'] = 60 * 10
167
+ response.headers["access-control-expose-headers"] =
168
+ request.headers["access-control-expose-headers"] ||
169
+ "content-type, content-length, etag"
170
+ response.headers["access-control-max-age"] = 60 * 10
171
171
 
172
- if (request.headers['access-control-request-headers']) {
173
- response.headers['access-control-allow-headers'] =
174
- request.headers['access-control-request-headers']
172
+ if (request.headers["access-control-request-headers"]) {
173
+ response.headers["access-control-allow-headers"] =
174
+ request.headers["access-control-request-headers"]
175
175
  }
176
176
 
177
- if (request.headers['access-control-request-method']) {
178
- response.headers['access-control-allow-methods'] =
179
- request.headers['access-control-request-method']
177
+ if (request.headers["access-control-request-method"]) {
178
+ response.headers["access-control-allow-methods"] =
179
+ request.headers["access-control-request-method"]
180
180
  }
181
181
  }
182
182
 
@@ -206,7 +206,7 @@ export default class HttpServer {
206
206
  }
207
207
 
208
208
  // TODO move the following block
209
- const server = `${httpsProtocol ? 'https' : 'http'}://${host}:${httpPort}`
209
+ const server = `${httpsProtocol ? "https" : "http"}://${host}:${httpPort}`
210
210
 
211
211
  log.notice(`Server ready: ${server} 🚀`)
212
212
  }
@@ -220,7 +220,7 @@ export default class HttpServer {
220
220
 
221
221
  #logPluginIssue() {
222
222
  log.notice(
223
- 'If you think this is an issue with the plugin please submit it, thanks!\nhttps://github.com/dherault/serverless-offline/issues',
223
+ "If you think this is an issue with the plugin please submit it, thanks!\nhttps://github.com/dherault/serverless-offline/issues",
224
224
  )
225
225
  log.notice()
226
226
  }
@@ -243,7 +243,7 @@ export default class HttpServer {
243
243
  // right now _configureJWTAuthorization only handles AWS HttpAPI Gateway JWT
244
244
  // authorizers that are defined in the serverless file
245
245
  if (
246
- this.#serverless.service.provider.name !== 'aws' ||
246
+ this.#serverless.service.provider.name !== "aws" ||
247
247
  !endpoint.isHttpApi
248
248
  ) {
249
249
  return null
@@ -253,8 +253,8 @@ export default class HttpServer {
253
253
  (endpoint.authorizer.name &&
254
254
  this.#serverless.service.provider?.httpApi?.authorizers?.[
255
255
  endpoint.authorizer.name
256
- ]?.type === 'request') ||
257
- endpoint.authorizer.type === 'request'
256
+ ]?.type === "request") ||
257
+ endpoint.authorizer.type === "request"
258
258
  ) {
259
259
  return null
260
260
  }
@@ -321,17 +321,17 @@ export default class HttpServer {
321
321
  false,
322
322
  identitySource: serverlessAuthorizerOptions?.identitySource,
323
323
  identityValidationExpression:
324
- serverlessAuthorizerOptions?.identityValidationExpression || '(.*)',
324
+ serverlessAuthorizerOptions?.identityValidationExpression || "(.*)",
325
325
  payloadVersion: endpoint.isHttpApi
326
- ? serverlessAuthorizerOptions?.payloadVersion || '2.0'
327
- : '1.0',
326
+ ? serverlessAuthorizerOptions?.payloadVersion || "2.0"
327
+ : "1.0",
328
328
  resultTtlInSeconds:
329
- serverlessAuthorizerOptions?.resultTtlInSeconds || '300',
329
+ serverlessAuthorizerOptions?.resultTtlInSeconds || "300",
330
330
  }
331
331
 
332
332
  if (
333
333
  authorizerOptions.enableSimpleResponses &&
334
- authorizerOptions.payloadVersion === '1.0'
334
+ authorizerOptions.payloadVersion === "1.0"
335
335
  ) {
336
336
  log.error(
337
337
  `Cannot create Authorization function '${authFunctionName}' if payloadVersion is '1.0' and enableSimpleResponses is true`,
@@ -339,7 +339,7 @@ export default class HttpServer {
339
339
  return null
340
340
  }
341
341
 
342
- if (typeof endpoint.authorizer === 'string') {
342
+ if (typeof endpoint.authorizer === "string") {
343
343
  authorizerOptions.name = authFunctionName
344
344
  } else {
345
345
  assign(authorizerOptions, endpoint.authorizer)
@@ -348,11 +348,11 @@ export default class HttpServer {
348
348
  if (
349
349
  !authorizerOptions.identitySource &&
350
350
  !(
351
- authorizerOptions.type === 'request' &&
351
+ authorizerOptions.type === "request" &&
352
352
  authorizerOptions.resultTtlInSeconds === 0
353
353
  )
354
354
  ) {
355
- authorizerOptions.identitySource = 'method.request.header.Authorization'
355
+ authorizerOptions.identitySource = "method.request.header.Authorization"
356
356
  }
357
357
 
358
358
  // Create a unique scheme per endpoint
@@ -391,7 +391,7 @@ export default class HttpServer {
391
391
  customizations &&
392
392
  customizations.offline?.customAuthenticationProvider
393
393
  ) {
394
- const root = resolve(this.#serverless.serviceDir, 'require-resolver')
394
+ const root = resolve(this.#serverless.serviceDir, "require-resolver")
395
395
  const customRequire = createRequire(root)
396
396
 
397
397
  const provider = customRequire(
@@ -457,13 +457,13 @@ export default class HttpServer {
457
457
  const errorResponse = () =>
458
458
  h
459
459
  .response({
460
- message: 'Forbidden',
460
+ message: "Forbidden",
461
461
  })
462
462
  .code(403)
463
- .header('x-amzn-ErrorType', 'ForbiddenException')
464
- .type('application/json')
463
+ .header("x-amzn-ErrorType", "ForbiddenException")
464
+ .type("application/json")
465
465
 
466
- const apiKey = request.headers['x-api-key']
466
+ const apiKey = request.headers["x-api-key"]
467
467
 
468
468
  if (apiKey) {
469
469
  if (!this.#apiKeysValues.has(apiKey)) {
@@ -495,26 +495,26 @@ export default class HttpServer {
495
495
  }
496
496
 
497
497
  const response = h.response()
498
- const contentType = request.mime || 'application/json' // default content type
498
+ const contentType = request.mime || "application/json" // default content type
499
499
 
500
500
  const { integration, requestTemplates } = endpoint
501
501
 
502
502
  // default request template to '' if we don't have a definition pushed in from serverless or endpoint
503
503
  const requestTemplate =
504
- requestTemplates !== undefined && integration === 'AWS'
504
+ requestTemplates !== undefined && integration === "AWS"
505
505
  ? requestTemplates[contentType]
506
- : ''
506
+ : ""
507
507
 
508
508
  const schemas =
509
509
  endpoint?.request?.schemas === undefined
510
- ? ''
510
+ ? ""
511
511
  : endpoint.request.schemas[contentType]
512
512
 
513
513
  // https://hapijs.com/api#route-configuration doesn't seem to support selectively parsing
514
514
  // so we have to do it ourselves
515
515
  const contentTypesThatRequirePayloadParsing = [
516
- 'application/json',
517
- 'application/vnd.api+json',
516
+ "application/json",
517
+ "application/vnd.api+json",
518
518
  ]
519
519
 
520
520
  if (
@@ -524,22 +524,22 @@ export default class HttpServer {
524
524
  ) {
525
525
  try {
526
526
  if (!request.payload || request.payload.length === 0) {
527
- request.payload = '{}'
527
+ request.payload = "{}"
528
528
  }
529
529
 
530
530
  request.payload = parse(request.payload)
531
531
  } catch (err) {
532
- log.debug('error in converting request.payload to JSON:', err)
532
+ log.debug("error in converting request.payload to JSON:", err)
533
533
  }
534
534
  }
535
535
 
536
- log.debug('contentType:', contentType)
537
- log.debug('requestTemplate:', requestTemplate)
538
- log.debug('payload:', request.payload)
536
+ log.debug("contentType:", contentType)
537
+ log.debug("requestTemplate:", requestTemplate)
538
+ log.debug("payload:", request.payload)
539
539
 
540
540
  /* REQUEST PAYLOAD SCHEMA VALIDATION */
541
541
  if (schemas) {
542
- log.debug('schemas:', schemas)
542
+ log.debug("schemas:", schemas)
543
543
 
544
544
  try {
545
545
  payloadSchemaValidator(schemas, request.payload)
@@ -552,10 +552,10 @@ export default class HttpServer {
552
552
 
553
553
  let event = {}
554
554
 
555
- if (integration === 'AWS') {
555
+ if (integration === "AWS") {
556
556
  if (requestTemplate) {
557
557
  try {
558
- log.debug('_____ REQUEST TEMPLATE PROCESSING _____')
558
+ log.debug("_____ REQUEST TEMPLATE PROCESSING _____")
559
559
 
560
560
  event = new LambdaIntegrationEvent(
561
561
  request,
@@ -570,12 +570,12 @@ export default class HttpServer {
570
570
  err,
571
571
  )
572
572
  }
573
- } else if (typeof request.payload === 'object') {
573
+ } else if (typeof request.payload === "object") {
574
574
  event = request.payload || {}
575
575
  }
576
- } else if (integration === 'AWS_PROXY') {
576
+ } else if (integration === "AWS_PROXY") {
577
577
  const lambdaProxyIntegrationEvent =
578
- endpoint.isHttpApi && endpoint.payload === '2.0'
578
+ endpoint.isHttpApi && endpoint.payload === "2.0"
579
579
  ? new LambdaProxyIntegrationEventV2(
580
580
  request,
581
581
  stage,
@@ -593,7 +593,7 @@ export default class HttpServer {
593
593
  event = lambdaProxyIntegrationEvent.create()
594
594
  }
595
595
 
596
- log.debug('event:', event)
596
+ log.debug("event:", event)
597
597
 
598
598
  const lambdaFunction = this.#lambda.get(functionKey)
599
599
 
@@ -611,15 +611,15 @@ export default class HttpServer {
611
611
  // const processResponse = (err, data) => {
612
612
  // Everything in this block happens once the lambda function has resolved
613
613
 
614
- log.debug('_____ HANDLER RESOLVED _____')
614
+ log.debug("_____ HANDLER RESOLVED _____")
615
615
 
616
- let responseName = 'default'
616
+ let responseName = "default"
617
617
  const { contentHandling, responseContentType } = endpoint
618
618
 
619
619
  /* RESPONSE SELECTION (among endpoint's possible responses) */
620
620
 
621
621
  // Failure handling
622
- let errorStatusCode = '502'
622
+ let errorStatusCode = "502"
623
623
 
624
624
  if (err) {
625
625
  const errorMessage = (err.message || err).toString()
@@ -629,7 +629,7 @@ export default class HttpServer {
629
629
  if (found && found.length > 1) {
630
630
  ;[, errorStatusCode] = found
631
631
  } else {
632
- errorStatusCode = '502'
632
+ errorStatusCode = "502"
633
633
  }
634
634
 
635
635
  // Mocks Lambda errors
@@ -643,7 +643,7 @@ export default class HttpServer {
643
643
 
644
644
  for (const [key, value] of entries(endpoint.responses)) {
645
645
  if (
646
- key !== 'default' &&
646
+ key !== "default" &&
647
647
  `^${value.selectionPattern || key}$`.test(errorMessage)
648
648
  ) {
649
649
  responseName = key
@@ -661,7 +661,7 @@ export default class HttpServer {
661
661
  const { responseParameters } = chosenResponse
662
662
 
663
663
  if (responseParameters) {
664
- log.debug('_____ RESPONSE PARAMETERS PROCCESSING _____')
664
+ log.debug("_____ RESPONSE PARAMETERS PROCCESSING _____")
665
665
  log.debug(
666
666
  `Found ${
667
667
  keys(responseParameters).length
@@ -670,27 +670,27 @@ export default class HttpServer {
670
670
 
671
671
  // responseParameters use the following shape: "key": "value"
672
672
  entries(responseParameters).forEach(([key, value]) => {
673
- const keyArray = key.split('.') // eg: "method.response.header.location"
674
- const valueArray = value.split('.') // eg: "integration.response.body.redirect.url"
673
+ const keyArray = key.split(".") // eg: "method.response.header.location"
674
+ const valueArray = value.split(".") // eg: "integration.response.body.redirect.url"
675
675
 
676
676
  log.debug(`Processing responseParameter "${key}": "${value}"`)
677
677
 
678
678
  // For now the plugin only supports modifying headers
679
- if (key.startsWith('method.response.header') && keyArray[3]) {
680
- const headerName = keyArray.slice(3).join('.')
679
+ if (key.startsWith("method.response.header") && keyArray[3]) {
680
+ const headerName = keyArray.slice(3).join(".")
681
681
  let headerValue
682
682
 
683
- log.debug('Found header in left-hand:', headerName)
683
+ log.debug("Found header in left-hand:", headerName)
684
684
 
685
- if (value.startsWith('integration.response')) {
686
- if (valueArray[2] === 'body') {
687
- log.debug('Found body in right-hand')
685
+ if (value.startsWith("integration.response")) {
686
+ if (valueArray[2] === "body") {
687
+ log.debug("Found body in right-hand")
688
688
 
689
689
  headerValue = valueArray[3]
690
- ? jsonPath(result, valueArray.slice(3).join('.'))
690
+ ? jsonPath(result, valueArray.slice(3).join("."))
691
691
  : result
692
692
 
693
- headerValue = headerValue == null ? '' : String(headerValue)
693
+ headerValue = headerValue == null ? "" : String(headerValue)
694
694
  } else {
695
695
  log.notice()
696
696
 
@@ -706,7 +706,7 @@ export default class HttpServer {
706
706
  headerValue = /^'.*'$/.test(value) ? value.slice(1, -1) : value // See #34
707
707
  }
708
708
  // Applies the header;
709
- if (headerValue === '') {
709
+ if (headerValue === "") {
710
710
  log.warning(
711
711
  `Empty value for responseParameter "${key}": "${value}", it won't be set`,
712
712
  )
@@ -733,13 +733,13 @@ export default class HttpServer {
733
733
 
734
734
  let statusCode = 200
735
735
 
736
- if (integration === 'AWS') {
736
+ if (integration === "AWS") {
737
737
  const endpointResponseHeaders =
738
738
  (endpoint.response && endpoint.response.headers) || {}
739
739
 
740
740
  entries(endpointResponseHeaders)
741
741
  .filter(
742
- ([, value]) => typeof value === 'string' && /^'.*?'$/.test(value),
742
+ ([, value]) => typeof value === "string" && /^'.*?'$/.test(value),
743
743
  )
744
744
  .forEach(([key, value]) => response.header(key, value.slice(1, -1)))
745
745
 
@@ -749,14 +749,14 @@ export default class HttpServer {
749
749
  const { responseTemplates } = chosenResponse
750
750
 
751
751
  if (
752
- typeof responseTemplates === 'object' &&
752
+ typeof responseTemplates === "object" &&
753
753
  keys(responseTemplates).length > 0
754
754
  ) {
755
755
  // BAD IMPLEMENTATION: first key in responseTemplates
756
756
  const responseTemplate = responseTemplates[responseContentType]
757
757
 
758
- if (responseTemplate && responseTemplate !== '\n') {
759
- log.debug('_____ RESPONSE TEMPLATE PROCCESSING _____')
758
+ if (responseTemplate && responseTemplate !== "\n") {
759
+ log.debug("_____ RESPONSE TEMPLATE PROCCESSING _____")
760
760
  log.debug(`Using responseTemplate '${responseContentType}'`)
761
761
 
762
762
  try {
@@ -794,34 +794,34 @@ export default class HttpServer {
794
794
  log.warning(`No statusCode found for response "${responseName}".`)
795
795
  }
796
796
 
797
- response.header('Content-Type', responseContentType, {
797
+ response.header("Content-Type", responseContentType, {
798
798
  override: false, // Maybe a responseParameter set it already. See #34
799
799
  })
800
800
 
801
801
  response.statusCode = statusCode
802
802
 
803
- if (contentHandling === 'CONVERT_TO_BINARY') {
804
- response.encoding = 'binary'
805
- response.source = Buffer.from(result, 'base64')
806
- response.variety = 'buffer'
807
- } else if (typeof result === 'string') {
803
+ if (contentHandling === "CONVERT_TO_BINARY") {
804
+ response.encoding = "binary"
805
+ response.source = Buffer.from(result, "base64")
806
+ response.variety = "buffer"
807
+ } else if (typeof result === "string") {
808
808
  response.source = stringify(result)
809
809
  } else {
810
810
  response.source = result
811
811
  }
812
- } else if (integration === 'AWS_PROXY') {
812
+ } else if (integration === "AWS_PROXY") {
813
813
  /* LAMBDA PROXY INTEGRATION HAPIJS RESPONSE CONFIGURATION */
814
814
 
815
815
  if (
816
816
  endpoint.isHttpApi &&
817
- endpoint.payload === '2.0' &&
818
- (typeof result === 'string' || !result.statusCode)
817
+ endpoint.payload === "2.0" &&
818
+ (typeof result === "string" || !result.statusCode)
819
819
  ) {
820
- const body = typeof result === 'string' ? result : stringify(result)
820
+ const body = typeof result === "string" ? result : stringify(result)
821
821
  result = {
822
822
  body,
823
823
  headers: {
824
- 'Content-Type': 'application/json',
824
+ "Content-Type": "application/json",
825
825
  },
826
826
  isBase64Encoded: false,
827
827
  statusCode: 200,
@@ -855,20 +855,20 @@ export default class HttpServer {
855
855
  )
856
856
  }
857
857
 
858
- log.debug('headers', headers)
858
+ log.debug("headers", headers)
859
859
 
860
860
  const parseCookies = (headerValue) => {
861
- const cookieName = headerValue.slice(0, headerValue.indexOf('='))
862
- const cookieValue = headerValue.slice(headerValue.indexOf('=') + 1)
861
+ const cookieName = headerValue.slice(0, headerValue.indexOf("="))
862
+ const cookieValue = headerValue.slice(headerValue.indexOf("=") + 1)
863
863
 
864
864
  h.state(cookieName, cookieValue, {
865
- encoding: 'none',
865
+ encoding: "none",
866
866
  strictHeader: false,
867
867
  })
868
868
  }
869
869
 
870
870
  entries(headers).forEach(([headerKey, headerValue]) => {
871
- if (headerKey.toLowerCase() === 'set-cookie') {
871
+ if (headerKey.toLowerCase() === "set-cookie") {
872
872
  headerValue.forEach(parseCookies)
873
873
  } else {
874
874
  headerValue.forEach((value) => {
@@ -883,30 +883,30 @@ export default class HttpServer {
883
883
 
884
884
  if (
885
885
  endpoint.isHttpApi &&
886
- endpoint.payload === '2.0' &&
886
+ endpoint.payload === "2.0" &&
887
887
  result.cookies
888
888
  ) {
889
889
  result.cookies.forEach(parseCookies)
890
890
  }
891
891
 
892
- response.header('Content-Type', 'application/json', {
892
+ response.header("Content-Type", "application/json", {
893
893
  duplicate: false,
894
894
  override: false,
895
895
  })
896
896
 
897
- if (typeof result === 'string') {
897
+ if (typeof result === "string") {
898
898
  response.source = stringify(result)
899
899
  } else if (result && result.body !== undefined) {
900
900
  if (result.isBase64Encoded) {
901
- response.encoding = 'binary'
902
- response.source = Buffer.from(result.body, 'base64')
903
- response.variety = 'buffer'
901
+ response.encoding = "binary"
902
+ response.source = Buffer.from(result.body, "base64")
903
+ response.variety = "buffer"
904
904
  } else {
905
- if (result && result.body && typeof result.body !== 'string') {
905
+ if (result && result.body && typeof result.body !== "string") {
906
906
  // FIXME TODO we should probably just write to console instead of returning a payload
907
907
  return this.#reply502(
908
908
  response,
909
- 'According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object',
909
+ "According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object",
910
910
  {},
911
911
  )
912
912
  }
@@ -951,12 +951,12 @@ export default class HttpServer {
951
951
  let hapiPath
952
952
 
953
953
  if (httpEvent.isHttpApi) {
954
- if (httpEvent.routeKey === '$default') {
955
- method = 'ANY'
954
+ if (httpEvent.routeKey === "$default") {
955
+ method = "ANY"
956
956
  path = httpEvent.routeKey
957
- hapiPath = '/{default*}'
957
+ hapiPath = "/{default*}"
958
958
  } else {
959
- ;[method, path] = httpEvent.routeKey.split(' ')
959
+ ;[method, path] = httpEvent.routeKey.split(" ")
960
960
  hapiPath = generateHapiPath(
961
961
  path,
962
962
  {
@@ -980,7 +980,7 @@ export default class HttpServer {
980
980
  ).generate()
981
981
 
982
982
  const stage = endpoint.isHttpApi
983
- ? '$default'
983
+ ? "$default"
984
984
  : this.#options.stage || this.#serverless.service.provider.stage
985
985
 
986
986
  const protectedRoute = httpEvent.private
@@ -988,7 +988,7 @@ export default class HttpServer {
988
988
  : undefined
989
989
 
990
990
  const { host, httpPort, httpsProtocol } = this.#options
991
- const server = `${httpsProtocol ? 'https' : 'http'}://${host}:${httpPort}`
991
+ const server = `${httpsProtocol ? "https" : "http"}://${host}:${httpPort}`
992
992
 
993
993
  this.#terminalInfo.push({
994
994
  invokePath: `/2015-03-31/functions/${functionKey}/invocations`,
@@ -1032,15 +1032,15 @@ export default class HttpServer {
1032
1032
  }
1033
1033
  }
1034
1034
 
1035
- const hapiMethod = method === 'ANY' ? '*' : method
1035
+ const hapiMethod = method === "ANY" ? "*" : method
1036
1036
 
1037
1037
  const state = this.#options.disableCookieValidation
1038
1038
  ? {
1039
- failAction: 'ignore',
1039
+ failAction: "ignore",
1040
1040
  parse: false,
1041
1041
  }
1042
1042
  : {
1043
- failAction: 'error',
1043
+ failAction: "error",
1044
1044
  parse: true,
1045
1045
  }
1046
1046
 
@@ -1058,15 +1058,15 @@ export default class HttpServer {
1058
1058
 
1059
1059
  // skip HEAD routes as hapi will fail with 'Method name not allowed: HEAD ...'
1060
1060
  // for more details, check https://github.com/dherault/serverless-offline/issues/204
1061
- if (hapiMethod === 'HEAD') {
1061
+ if (hapiMethod === "HEAD") {
1062
1062
  log.notice(
1063
- 'HEAD method event detected. Skipping HAPI server route mapping',
1063
+ "HEAD method event detected. Skipping HAPI server route mapping",
1064
1064
  )
1065
1065
 
1066
1066
  return
1067
1067
  }
1068
1068
 
1069
- if (hapiMethod !== 'HEAD' && hapiMethod !== 'GET') {
1069
+ if (hapiMethod !== "HEAD" && hapiMethod !== "GET") {
1070
1070
  // maxBytes: Increase request size from 1MB default limit to 10MB.
1071
1071
  // Cf AWS API GW payload limits.
1072
1072
  hapiOptions.payload = {
@@ -1080,7 +1080,7 @@ export default class HttpServer {
1080
1080
  additionalRequestContext.operationName = httpEvent.operationId
1081
1081
  }
1082
1082
 
1083
- hapiOptions.tags = ['api']
1083
+ hapiOptions.tags = ["api"]
1084
1084
 
1085
1085
  const hapiHandler = this.#createHapiHandler({
1086
1086
  additionalRequestContext,
@@ -1106,14 +1106,14 @@ export default class HttpServer {
1106
1106
 
1107
1107
  log.error(error)
1108
1108
 
1109
- response.header('Content-Type', 'application/json')
1109
+ response.header("Content-Type", "application/json")
1110
1110
 
1111
1111
  response.statusCode = statusCode
1112
1112
  response.source = {
1113
1113
  errorMessage: message,
1114
1114
  errorType: error.constructor.name,
1115
1115
  offlineInfo:
1116
- 'If you believe this is an issue with serverless-offline please submit it, thanks. https://github.com/dherault/serverless-offline/issues',
1116
+ "If you believe this is an issue with serverless-offline please submit it, thanks. https://github.com/dherault/serverless-offline/issues",
1117
1117
  stackTrace: this.#getArrayStackTrace(error.stack),
1118
1118
  }
1119
1119
 
@@ -1146,7 +1146,7 @@ export default class HttpServer {
1146
1146
  log.notice()
1147
1147
 
1148
1148
  log.notice()
1149
- log.notice('Routes defined in resources:')
1149
+ log.notice("Routes defined in resources:")
1150
1150
 
1151
1151
  entries(resourceRoutes).forEach(([methodId, resourceRoutesObj]) => {
1152
1152
  const { isProxy, method, pathResource, proxyUri } = resourceRoutesObj
@@ -1178,15 +1178,15 @@ export default class HttpServer {
1178
1178
  return
1179
1179
  }
1180
1180
 
1181
- const hapiMethod = method === 'ANY' ? '*' : method
1181
+ const hapiMethod = method === "ANY" ? "*" : method
1182
1182
 
1183
1183
  const state = this.#options.disableCookieValidation
1184
1184
  ? {
1185
- failAction: 'ignore',
1185
+ failAction: "ignore",
1186
1186
  parse: false,
1187
1187
  }
1188
1188
  : {
1189
- failAction: 'error',
1189
+ failAction: "error",
1190
1190
  parse: true,
1191
1191
  }
1192
1192
 
@@ -1197,15 +1197,15 @@ export default class HttpServer {
1197
1197
 
1198
1198
  // skip HEAD routes as hapi will fail with 'Method name not allowed: HEAD ...'
1199
1199
  // for more details, check https://github.com/dherault/serverless-offline/issues/204
1200
- if (hapiMethod === 'HEAD') {
1200
+ if (hapiMethod === "HEAD") {
1201
1201
  log.notice(
1202
- 'HEAD method event detected. Skipping HAPI server route mapping',
1202
+ "HEAD method event detected. Skipping HAPI server route mapping",
1203
1203
  )
1204
1204
 
1205
1205
  return
1206
1206
  }
1207
1207
 
1208
- if (hapiMethod !== 'GET' && hapiMethod !== 'HEAD') {
1208
+ if (hapiMethod !== "GET" && hapiMethod !== "HEAD") {
1209
1209
  hapiOptions.payload = {
1210
1210
  parse: false,
1211
1211
  }
@@ -1248,14 +1248,14 @@ export default class HttpServer {
1248
1248
 
1249
1249
  create404Route() {
1250
1250
  // If a {proxy+} or $default route exists, don't conflict with it
1251
- if (this.#server.match('*', '/{p*}')) {
1251
+ if (this.#server.match("*", "/{p*}")) {
1252
1252
  return
1253
1253
  }
1254
1254
 
1255
1255
  const existingRoutes = this.#server
1256
1256
  .table()
1257
1257
  // Exclude this (404) route
1258
- .filter((route) => route.path !== '/{p*}')
1258
+ .filter((route) => route.path !== "/{p*}")
1259
1259
  // Sort by path
1260
1260
  .sort((a, b) => (a.path <= b.path ? -1 : 1))
1261
1261
  // Human-friendly result
@@ -1265,7 +1265,7 @@ export default class HttpServer {
1265
1265
  handler(request, h) {
1266
1266
  const response = h.response({
1267
1267
  currentRoute: `${request.method} - ${request.path}`,
1268
- error: 'Serverless-offline: route not found.',
1268
+ error: "Serverless-offline: route not found.",
1269
1269
  existingRoutes,
1270
1270
  statusCode: 404,
1271
1271
  })
@@ -1273,11 +1273,11 @@ export default class HttpServer {
1273
1273
 
1274
1274
  return response
1275
1275
  },
1276
- method: '*',
1276
+ method: "*",
1277
1277
  options: {
1278
1278
  cors: this.#options.corsConfig,
1279
1279
  },
1280
- path: '/{p*}',
1280
+ path: "/{p*}",
1281
1281
  }
1282
1282
 
1283
1283
  this.#server.route(route)
@@ -1286,7 +1286,7 @@ export default class HttpServer {
1286
1286
  #getArrayStackTrace(stack) {
1287
1287
  if (!stack) return null
1288
1288
 
1289
- const splittedStack = stack.split('\n')
1289
+ const splittedStack = stack.split("\n")
1290
1290
 
1291
1291
  return splittedStack
1292
1292
  .slice(