serverless-offline 12.0.3 → 12.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "dedicatedTo": "Blue, a great migrating bird.",
3
3
  "name": "serverless-offline",
4
- "version": "12.0.3",
4
+ "version": "12.0.4",
5
5
  "description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
6
6
  "license": "MIT",
7
7
  "exports": {
@@ -24,12 +24,8 @@
24
24
  "prettify:updated": "pipe-git-updated --ext=css --ext=html --ext=js --ext=json --ext=md --ext=yaml --ext=yml -- prettier --write",
25
25
  "test": "mocha --require ./tests/mochaHooks.cjs",
26
26
  "test:cov": "NODE_OPTIONS='--experimental-loader @istanbuljs/esm-loader-hook' nyc --reporter=html npm test",
27
- "old-test:jest": "npm run build && jest --verbose --silent --runInBand",
28
- "old-test:cov": "npm run build && jest --coverage --silent --runInBand --collectCoverageFrom=src/**/*.js",
29
- "old-test:log": "npm run build && jest --verbose",
30
- "old-test:noBuild": "jest --verbose --runInBand --bail",
31
- "old-test:unit": "jest --verbose --silent --runInBand --config jest.config.units.js",
32
- "old-test:watch": "SKIP_SETUP=true jest --verbose --watch"
27
+ "test:node": "TEST=unit mocha --require ./tests/mochaHooks.cjs",
28
+ "test:unit": "TEST=unit mocha --require ./tests/mochaHooks.cjs"
33
29
  },
34
30
  "repository": {
35
31
  "type": "git",
@@ -82,24 +78,25 @@
82
78
  ]
83
79
  },
84
80
  "dependencies": {
85
- "@aws-sdk/client-lambda": "^3.231.0",
81
+ "@aws-sdk/client-lambda": "^3.241.0",
86
82
  "@hapi/boom": "^10.0.0",
87
83
  "@hapi/h2o2": "^10.0.0",
88
84
  "@hapi/hapi": "^21.1.0",
89
85
  "@serverless/utils": "^6.8.2",
90
- "array-unflat-js": "^0.1.0",
91
- "boxen": "^7.0.0",
86
+ "array-unflat-js": "^0.1.3",
87
+ "boxen": "^7.0.1",
92
88
  "chalk": "^5.2.0",
89
+ "desm": "^1.3.0",
93
90
  "execa": "^6.1.0",
94
91
  "fs-extra": "^11.1.0",
95
92
  "is-wsl": "^2.2.0",
96
93
  "java-invoke-local": "0.0.6",
97
- "jose": "^4.11.1",
94
+ "jose": "^4.11.2",
98
95
  "js-string-escape": "^1.0.1",
99
96
  "jsonpath-plus": "^7.2.0",
100
97
  "jsonschema": "^1.4.1",
101
98
  "jszip": "^3.10.1",
102
- "luxon": "^3.1.1",
99
+ "luxon": "^3.2.0",
103
100
  "node-fetch": "^3.3.0",
104
101
  "node-schedule": "^2.1.0",
105
102
  "object.hasown": "^1.1.2",
@@ -111,18 +108,19 @@
111
108
  "devDependencies": {
112
109
  "@istanbuljs/esm-loader-hook": "^0.2.0",
113
110
  "archiver": "^5.3.1",
114
- "eslint": "^8.30.0",
111
+ "eslint": "^8.31.0",
115
112
  "eslint-config-airbnb-base": "^15.0.0",
116
- "eslint-config-prettier": "^8.5.0",
113
+ "eslint-config-prettier": "^8.6.0",
117
114
  "eslint-plugin-import": "^2.25.4",
118
115
  "eslint-plugin-prettier": "^4.2.1",
116
+ "eslint-plugin-unicorn": "^45.0.2",
119
117
  "git-list-updated": "^1.2.1",
120
- "husky": "^8.0.2",
118
+ "husky": "^8.0.3",
121
119
  "lint-staged": "^13.1.0",
122
120
  "mocha": "^10.2.0",
123
121
  "nyc": "^15.1.0",
124
122
  "prettier": "^2.8.1",
125
- "serverless": "^3.25.1",
123
+ "serverless": "^3.26.0",
126
124
  "standard-version": "^9.5.0"
127
125
  },
128
126
  "peerDependencies": {
@@ -1,20 +1,17 @@
1
1
  import { existsSync, readFileSync } from 'node:fs'
2
- import { dirname, resolve } from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
2
  import { log } from '@serverless/utils/log.js'
3
+ import { join } from 'desm'
5
4
  import OfflineEndpoint from './OfflineEndpoint.js'
6
5
 
7
6
  const { entries } = Object
8
7
 
9
- const __dirname = dirname(fileURLToPath(import.meta.url))
10
-
11
8
  // velocity template defaults
12
9
  const defaultRequestTemplate = readFileSync(
13
- resolve(__dirname, 'templates/offline-default.req.vm'),
10
+ join(import.meta.url, 'templates/offline-default.req.vm'),
14
11
  'utf8',
15
12
  )
16
13
  const defaultResponseTemplate = readFileSync(
17
- resolve(__dirname, 'templates/offline-default.res.vm'),
14
+ join(import.meta.url, 'templates/offline-default.res.vm'),
18
15
  'utf8',
19
16
  )
20
17
 
@@ -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'), 'utf-8'),
61
- readFile(resolve(httpsProtocol, 'key.pem'), 'utf-8'),
60
+ readFile(resolve(httpsProtocol, 'cert.pem'), 'utf8'),
61
+ readFile(resolve(httpsProtocol, 'key.pem'), 'utf8'),
62
62
  ])
63
63
 
64
64
  return {
@@ -328,9 +328,9 @@ export default class HttpServer {
328
328
  'method.request.header.Authorization',
329
329
  identityValidationExpression:
330
330
  serverlessAuthorizerOptions?.identityValidationExpression || '(.*)',
331
- payloadVersion: !endpoint.isHttpApi
332
- ? '1.0'
333
- : serverlessAuthorizerOptions?.payloadVersion || '2.0',
331
+ payloadVersion: endpoint.isHttpApi
332
+ ? serverlessAuthorizerOptions?.payloadVersion || '2.0'
333
+ : '1.0',
334
334
  resultTtlInSeconds:
335
335
  serverlessAuthorizerOptions?.resultTtlInSeconds || '300',
336
336
  }
@@ -502,9 +502,9 @@ export default class HttpServer {
502
502
  : ''
503
503
 
504
504
  const schemas =
505
- endpoint?.request?.schemas !== undefined
506
- ? endpoint.request.schemas[contentType]
507
- : ''
505
+ endpoint?.request?.schemas === undefined
506
+ ? ''
507
+ : endpoint.request.schemas[contentType]
508
508
 
509
509
  // https://hapijs.com/api#route-configuration doesn't seem to support selectively parsing
510
510
  // so we have to do it ourselves
@@ -519,7 +519,7 @@ export default class HttpServer {
519
519
  request.payload.length > 1
520
520
  ) {
521
521
  try {
522
- if (!request.payload || request.payload.length < 1) {
522
+ if (!request.payload || request.payload.length === 0) {
523
523
  request.payload = '{}'
524
524
  }
525
525
 
@@ -640,7 +640,7 @@ export default class HttpServer {
640
640
  for (const [key, value] of entries(endpoint.responses)) {
641
641
  if (
642
642
  key !== 'default' &&
643
- errorMessage.match(`^${value.selectionPattern || key}$`)
643
+ `^${value.selectionPattern || key}$`.test(errorMessage)
644
644
  ) {
645
645
  responseName = key
646
646
  break
@@ -685,11 +685,8 @@ export default class HttpServer {
685
685
  headerValue = valueArray[3]
686
686
  ? jsonPath(result, valueArray.slice(3).join('.'))
687
687
  : result
688
- if (headerValue === undefined || headerValue === null) {
689
- headerValue = ''
690
- } else {
691
- headerValue = headerValue.toString()
692
- }
688
+
689
+ headerValue = headerValue == null ? '' : String(headerValue)
693
690
  } else {
694
691
  log.notice()
695
692
 
@@ -702,7 +699,7 @@ export default class HttpServer {
702
699
  log.notice()
703
700
  }
704
701
  } else {
705
- headerValue = value.match(/^'.*'$/) ? value.slice(1, -1) : value // See #34
702
+ headerValue = /^'.*'$/.test(value) ? value.slice(1, -1) : value // See #34
706
703
  }
707
704
  // Applies the header;
708
705
  if (headerValue === '') {
@@ -748,7 +745,7 @@ export default class HttpServer {
748
745
  const { responseTemplates } = chosenResponse
749
746
 
750
747
  if (typeof responseTemplates === 'object') {
751
- if (keys(responseTemplates).length) {
748
+ if (keys(responseTemplates).length > 0) {
752
749
  // BAD IMPLEMENTATION: first key in responseTemplates
753
750
  const responseTemplate = responseTemplates[responseContentType]
754
751
 
@@ -1137,7 +1134,7 @@ export default class HttpServer {
1137
1134
 
1138
1135
  const resourceRoutes = parseResources(this.#serverless.service.resources)
1139
1136
 
1140
- if (!resourceRoutes || !keys(resourceRoutes).length) {
1137
+ if (!resourceRoutes || keys(resourceRoutes).length === 0) {
1141
1138
  return
1142
1139
  }
1143
1140
 
@@ -67,7 +67,7 @@ export default function createAuthScheme(jwtOptions) {
67
67
  }
68
68
 
69
69
  let scopes = null
70
- if (jwtOptions.scopes && jwtOptions.scopes.length) {
70
+ if (jwtOptions.scopes && jwtOptions.scopes.length > 0) {
71
71
  if (!scope) {
72
72
  log.notice(`JWT Token missing valid scope`)
73
73
 
@@ -33,20 +33,25 @@ function renderVelocityString(velocityString, context) {
33
33
 
34
34
  // Haaaa Velocity... this language sure loves strings a lot
35
35
  switch (renderResult) {
36
- case 'undefined':
37
- return undefined // But we don't, we want JavaScript types
36
+ case 'undefined': {
37
+ return undefined
38
+ } // But we don't, we want JavaScript types
38
39
 
39
- case 'null':
40
+ case 'null': {
40
41
  return null
42
+ }
41
43
 
42
- case 'true':
44
+ case 'true': {
43
45
  return true
46
+ }
44
47
 
45
- case 'false':
48
+ case 'false': {
46
49
  return false
50
+ }
47
51
 
48
- default:
52
+ default: {
49
53
  return tryToParseJSON(renderResult)
54
+ }
50
55
  }
51
56
  }
52
57
 
@@ -78,21 +78,25 @@ export default class Schedule {
78
78
 
79
79
  switch (unit) {
80
80
  case 'minute':
81
- case 'minutes':
81
+ case 'minutes': {
82
82
  return `*/${number} * * * *`
83
+ }
83
84
 
84
85
  case 'hour':
85
- case 'hours':
86
+ case 'hours': {
86
87
  return `0 */${number} * * *`
88
+ }
87
89
 
88
90
  case 'day':
89
- case 'days':
91
+ case 'days': {
90
92
  return `0 0 */${number} * *`
93
+ }
91
94
 
92
- default:
95
+ default: {
93
96
  log.error(`scheduler: Invalid rate syntax '${rate}', will not schedule`)
94
97
 
95
98
  return null
99
+ }
96
100
  }
97
101
  }
98
102
 
@@ -19,8 +19,8 @@ export default class HttpServer {
19
19
 
20
20
  async #loadCerts(httpsProtocol) {
21
21
  const [cert, key] = await Promise.all([
22
- readFile(resolve(httpsProtocol, 'cert.pem'), 'utf-8'),
23
- readFile(resolve(httpsProtocol, 'key.pem'), 'utf-8'),
22
+ readFile(resolve(httpsProtocol, 'cert.pem'), 'utf8'),
23
+ readFile(resolve(httpsProtocol, 'key.pem'), 'utf8'),
24
24
  ])
25
25
 
26
26
  return {
@@ -14,7 +14,7 @@ export default class ConnectionsController {
14
14
  const clientExisted = this.#webSocketClients.send(
15
15
  connectionId,
16
16
  // payload is a Buffer
17
- payload.toString('utf-8'),
17
+ payload.toString('utf8'),
18
18
  )
19
19
 
20
20
  return clientExisted
@@ -95,13 +95,7 @@ export default class DockerContainer {
95
95
  if (this.#layers.length > 0) {
96
96
  log.verbose(`Found layers, checking provider type`)
97
97
 
98
- if (this.#provider.name.toLowerCase() !== 'aws') {
99
- log.warning(
100
- `Provider ${
101
- this.#provider.name
102
- } is Unsupported. Layers are only supported on aws.`,
103
- )
104
- } else {
98
+ if (this.#provider.name.toLowerCase() === 'aws') {
105
99
  let layerDir = this.#dockerOptions.layersDir
106
100
 
107
101
  if (!layerDir) {
@@ -142,6 +136,12 @@ export default class DockerContainer {
142
136
  )
143
137
  }
144
138
  dockerArgs.push('-v', `${layerDir}:/opt:ro,delegated`)
139
+ } else {
140
+ log.warning(
141
+ `Provider ${
142
+ this.#provider.name
143
+ } is Unsupported. Layers are only supported on aws.`,
144
+ )
145
145
  }
146
146
  }
147
147
 
@@ -106,7 +106,7 @@ export default class GoRunner {
106
106
  // Get go env to run this locally
107
107
  if (!this.#goEnv) {
108
108
  const goEnvResponse = await execa('go', ['env'], {
109
- encoding: 'utf-8',
109
+ encoding: 'utf8',
110
110
  stdio: 'pipe',
111
111
  })
112
112
 
@@ -136,7 +136,7 @@ export default class GoRunner {
136
136
  }
137
137
 
138
138
  const { stdout, stderr } = await execa(`./tmp`, {
139
- encoding: 'utf-8',
139
+ encoding: 'utf8',
140
140
  env: {
141
141
  ...this.#env,
142
142
  ...this.#goEnv,
@@ -1,17 +1,15 @@
1
1
  import { spawn } from 'node:child_process'
2
2
  import { EOL, platform } from 'node:os'
3
- import { delimiter, dirname, join, relative, resolve } from 'node:path'
3
+ import { delimiter, join as pathJoin, relative } from 'node:path'
4
4
  import process, { cwd, nextTick } from 'node:process'
5
5
  import { createInterface } from 'node:readline'
6
- import { fileURLToPath } from 'node:url'
7
6
  import { log } from '@serverless/utils/log.js'
7
+ import { join } from 'desm'
8
8
  import { splitHandlerPathAndName } from '../../../utils/index.js'
9
9
 
10
10
  const { parse, stringify } = JSON
11
11
  const { assign, hasOwn } = Object
12
12
 
13
- const __dirname = dirname(fileURLToPath(import.meta.url))
14
-
15
13
  export default class PythonRunner {
16
14
  static #payloadIdentifier = '__offline_payload__'
17
15
 
@@ -32,7 +30,7 @@ export default class PythonRunner {
32
30
  const runtimeDir = platform() === 'win32' ? 'Scripts' : 'bin'
33
31
 
34
32
  process.env.PATH = [
35
- join(process.env.VIRTUAL_ENV, runtimeDir),
33
+ pathJoin(process.env.VIRTUAL_ENV, runtimeDir),
36
34
  delimiter,
37
35
  process.env.PATH,
38
36
  ].join('')
@@ -44,7 +42,7 @@ export default class PythonRunner {
44
42
  pythonExecutable,
45
43
  [
46
44
  '-u',
47
- resolve(__dirname, 'invoke.py'),
45
+ join(import.meta.url, 'invoke.py'),
48
46
  relative(cwd(), handlerPath),
49
47
  handlerName,
50
48
  ],
@@ -1,16 +1,14 @@
1
1
  import { EOL, platform } from 'node:os'
2
- import { dirname, relative, resolve } from 'node:path'
2
+ import { relative } from 'node:path'
3
3
  import { cwd } from 'node:process'
4
- import { fileURLToPath } from 'node:url'
5
4
  import { log } from '@serverless/utils/log.js'
5
+ import { join } from 'desm'
6
6
  import { execa } from 'execa'
7
7
  import { splitHandlerPathAndName } from '../../../utils/index.js'
8
8
 
9
9
  const { parse, stringify } = JSON
10
10
  const { hasOwn } = Object
11
11
 
12
- const __dirname = dirname(fileURLToPath(import.meta.url))
13
-
14
12
  export default class RubyRunner {
15
13
  static #payloadIdentifier = '__offline_payload__'
16
14
 
@@ -86,7 +84,7 @@ export default class RubyRunner {
86
84
  const { stderr, stdout } = await execa(
87
85
  runtime,
88
86
  [
89
- resolve(__dirname, 'invoke.rb'),
87
+ join(import.meta.url, 'invoke.rb'),
90
88
  relative(cwd(), this.#handlerPath),
91
89
  this.#handlerName,
92
90
  ],
@@ -1,9 +1,5 @@
1
- import { dirname, resolve } from 'node:path'
2
- import { fileURLToPath } from 'node:url'
3
1
  import { MessageChannel, Worker } from 'node:worker_threads'
4
-
5
- const __dirname = dirname(fileURLToPath(import.meta.url))
6
- const workerThreadHelperPath = resolve(__dirname, 'workerThreadHelper.js')
2
+ import { join } from 'desm'
7
3
 
8
4
  export default class WorkerThreadRunner {
9
5
  #workerThread = null
@@ -11,17 +7,20 @@ export default class WorkerThreadRunner {
11
7
  constructor(funOptions, env) {
12
8
  const { codeDir, functionKey, handler, servicePath, timeout } = funOptions
13
9
 
14
- this.#workerThread = new Worker(workerThreadHelperPath, {
15
- // don't pass process.env from the main process!
16
- env,
17
- workerData: {
18
- codeDir,
19
- functionKey,
20
- handler,
21
- servicePath,
22
- timeout,
10
+ this.#workerThread = new Worker(
11
+ join(import.meta.url, 'workerThreadHelper.js'),
12
+ {
13
+ // don't pass process.env from the main process!
14
+ env,
15
+ workerData: {
16
+ codeDir,
17
+ functionKey,
18
+ handler,
19
+ servicePath,
20
+ timeout,
21
+ },
23
22
  },
24
- })
23
+ )
25
24
  }
26
25
 
27
26
  // () => Promise<number>
@@ -25,11 +25,11 @@ export default function invocationsRoute(lambda, options) {
25
25
  // check client context header was set
26
26
  if (clientContextHeader) {
27
27
  const clientContextBuffer = Buffer.from(clientContextHeader, 'base64')
28
- clientContext = parse(clientContextBuffer.toString('utf-8'))
28
+ clientContext = parse(clientContextBuffer.toString('utf8'))
29
29
  }
30
30
 
31
31
  // check if payload was set, if not, default event is an empty object
32
- const event = payload.length > 0 ? parse(payload.toString('utf-8')) : {}
32
+ const event = payload.length > 0 ? parse(payload.toString('utf8')) : {}
33
33
 
34
34
  const invokeResults = await invocationsController.invoke(
35
35
  functionName,
@@ -13,7 +13,7 @@ export default function invokeRoute(lambda, options) {
13
13
  payload,
14
14
  } = request
15
15
 
16
- const event = parse(payload.toString('utf-8'))
16
+ const event = parse(payload.toString('utf8'))
17
17
 
18
18
  return invokeAsyncController.invokeAsync(functionName, event)
19
19
  },
@@ -5,7 +5,7 @@ export default async function checkGoVersion() {
5
5
 
6
6
  try {
7
7
  const { stdout } = await execa('go', ['version'])
8
- if (stdout.match(/go1.\d+/g)) {
8
+ if (/go1.\d+/g.test(stdout)) {
9
9
  goVersion = '1.x'
10
10
  }
11
11
  } catch {
@@ -8,7 +8,7 @@ export default function splitHandlerPathAndName(handler) {
8
8
  // filename: source
9
9
  // path: ./src/somefolder/source
10
10
  // name: LambdaFunctions::Handler.process
11
- if (handler.match(/::/)) {
11
+ if (/::/.test(handler)) {
12
12
  const prepathDelimiter = handler.lastIndexOf('/')
13
13
  const prepath = handler.substr(0, prepathDelimiter + 1) // include '/' for path
14
14
  const postpath = handler.substr(prepathDelimiter + 1)