skuba 9.0.0-renovate-eslint-9.x-20240923103202 → 9.0.1-upgrade-cdk-template-20241002233314

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 (68) hide show
  1. package/lib/api/github/issueComment.js.map +2 -2
  2. package/lib/cli/adapter/eslint.js +4 -4
  3. package/lib/cli/adapter/eslint.js.map +2 -2
  4. package/lib/cli/lint/autofix.js +0 -15
  5. package/lib/cli/lint/autofix.js.map +2 -2
  6. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/collapseDuplicateMergeKeys.js +15 -6
  7. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/collapseDuplicateMergeKeys.js.map +2 -2
  8. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/index.js +10 -0
  9. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/index.js.map +2 -2
  10. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/moveNpmrcMounts.d.ts +2 -0
  11. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/moveNpmrcMounts.js +82 -0
  12. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/moveNpmrcMounts.js.map +7 -0
  13. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/patchDockerCompose.js +1 -3
  14. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/patchDockerCompose.js.map +2 -2
  15. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/patchDockerImages.d.ts +2 -0
  16. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/patchDockerImages.js +141 -0
  17. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/patchDockerImages.js.map +7 -0
  18. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js +5 -3
  19. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js.map +2 -2
  20. package/lib/wrapper/requestListener.js.map +2 -2
  21. package/package.json +9 -9
  22. package/template/express-rest-api/.buildkite/pipeline.yml +2 -2
  23. package/template/express-rest-api/Dockerfile +1 -1
  24. package/template/express-rest-api/Dockerfile.dev-deps +1 -1
  25. package/template/express-rest-api/package.json +1 -1
  26. package/template/greeter/.buildkite/pipeline.yml +2 -2
  27. package/template/greeter/Dockerfile +1 -1
  28. package/template/greeter/package.json +1 -1
  29. package/template/koa-rest-api/.buildkite/pipeline.yml +2 -2
  30. package/template/koa-rest-api/Dockerfile +1 -1
  31. package/template/koa-rest-api/Dockerfile.dev-deps +1 -1
  32. package/template/koa-rest-api/package.json +4 -4
  33. package/template/koa-rest-api/src/framework/bodyParser.ts +1 -1
  34. package/template/koa-rest-api/src/framework/server.test.ts +0 -1
  35. package/template/lambda-sqs-worker/.buildkite/pipeline.yml +2 -2
  36. package/template/lambda-sqs-worker/Dockerfile +1 -1
  37. package/template/lambda-sqs-worker/package.json +2 -2
  38. package/template/lambda-sqs-worker/serverless.yml +1 -1
  39. package/template/lambda-sqs-worker-cdk/.buildkite/pipeline.yml +2 -2
  40. package/template/lambda-sqs-worker-cdk/.env +1 -0
  41. package/template/lambda-sqs-worker-cdk/Dockerfile +1 -1
  42. package/template/lambda-sqs-worker-cdk/README.md +145 -0
  43. package/template/lambda-sqs-worker-cdk/infra/__snapshots__/appStack.test.ts.snap +102 -134
  44. package/template/lambda-sqs-worker-cdk/infra/appStack.test.ts +13 -2
  45. package/template/lambda-sqs-worker-cdk/infra/appStack.ts +52 -6
  46. package/template/lambda-sqs-worker-cdk/infra/config.ts +3 -0
  47. package/template/lambda-sqs-worker-cdk/package.json +9 -2
  48. package/template/lambda-sqs-worker-cdk/src/app.test.ts +116 -0
  49. package/template/lambda-sqs-worker-cdk/src/app.ts +43 -21
  50. package/template/lambda-sqs-worker-cdk/src/config.ts +15 -0
  51. package/template/lambda-sqs-worker-cdk/src/framework/handler.test.ts +61 -0
  52. package/template/lambda-sqs-worker-cdk/src/framework/handler.ts +43 -0
  53. package/template/lambda-sqs-worker-cdk/src/framework/logging.ts +27 -0
  54. package/template/lambda-sqs-worker-cdk/src/framework/metrics.ts +14 -0
  55. package/template/lambda-sqs-worker-cdk/src/framework/validation.test.ts +84 -0
  56. package/template/lambda-sqs-worker-cdk/src/framework/validation.ts +10 -0
  57. package/template/lambda-sqs-worker-cdk/src/mapping/jobScorer.ts +22 -0
  58. package/template/lambda-sqs-worker-cdk/src/services/aws.ts +5 -0
  59. package/template/lambda-sqs-worker-cdk/src/services/jobScorer.test.ts +44 -0
  60. package/template/lambda-sqs-worker-cdk/src/services/jobScorer.ts +59 -0
  61. package/template/lambda-sqs-worker-cdk/src/services/pipelineEventSender.test.ts +40 -0
  62. package/template/lambda-sqs-worker-cdk/src/services/pipelineEventSender.ts +33 -0
  63. package/template/lambda-sqs-worker-cdk/src/testing/handler.ts +13 -0
  64. package/template/lambda-sqs-worker-cdk/src/testing/logging.ts +19 -0
  65. package/template/lambda-sqs-worker-cdk/src/testing/services.ts +28 -0
  66. package/template/lambda-sqs-worker-cdk/src/testing/types.ts +33 -0
  67. package/template/lambda-sqs-worker-cdk/src/types/jobScorer.ts +15 -0
  68. package/template/lambda-sqs-worker-cdk/src/types/pipelineEvents.ts +21 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.ts"],
4
- "sourcesContent": ["// eslint-disable-next-line no-restricted-imports -- fs-extra is mocked\nimport * as fsp from 'fs/promises';\nimport path from 'path';\nimport { inspect } from 'util';\n\nimport { promises as fsExtra } from 'fs-extra';\n\nimport type { PatchFunction, PatchReturnType } from '../..';\nimport { createExec } from '../../../../../../utils/exec';\nimport { log } from '../../../../../../utils/logging';\nimport { createDestinationFileReader } from '../../../../../configure/analysis/project';\nimport { mergeWithConfigFile } from '../../../../../configure/processing/configFile';\nimport { formatPrettier } from '../../../../../configure/processing/prettier';\n\nconst IGNORE_FILE = '.eslintignore';\nconst OLD_CONFIG_FILE = '.eslintrc.js';\nconst NEW_CONFIG_FILE_CJS = 'eslint.config.cjs';\nconst NEW_CONFIG_FILE_JS = 'eslint.config.js';\n\nconst upgradeESLint: PatchFunction = async ({\n mode,\n dir: cwd = process.cwd(),\n}): Promise<PatchReturnType> => {\n const readFile = createDestinationFileReader(cwd);\n const [ignoreFileContents, oldConfig] = await Promise.all([\n readFile(IGNORE_FILE),\n readFile(OLD_CONFIG_FILE),\n ]);\n\n if (oldConfig === undefined) {\n return {\n result: 'skip',\n reason: `no ${OLD_CONFIG_FILE} - have you already migrated?`,\n };\n }\n\n if (mode === 'lint') {\n return { result: 'apply' };\n }\n\n const ignoreContentsWithoutSkubaManaged = mergeWithConfigFile(\n '',\n 'ignore',\n )(ignoreFileContents);\n\n const exec = createExec({\n cwd: process.cwd(),\n stdio: 'ignore',\n });\n\n // eslint-migrate-config require()s the file, so for testability, put it in a temporary location\n const dir = await writeTemporaryFiles({\n [OLD_CONFIG_FILE]: oldConfig,\n ...(ignoreContentsWithoutSkubaManaged.trim().length > 0\n ? { [IGNORE_FILE]: ignoreContentsWithoutSkubaManaged }\n : {}),\n });\n try {\n await exec(\n 'eslint-migrate-config',\n path.join(dir, OLD_CONFIG_FILE),\n '--commonjs',\n );\n\n const output = fiddleWithOutput(\n await fsp.readFile(path.join(dir, NEW_CONFIG_FILE_CJS), 'utf-8'),\n );\n await fsExtra.writeFile(\n NEW_CONFIG_FILE_JS,\n await formatPrettier(output, { filepath: NEW_CONFIG_FILE_JS }),\n );\n\n await Promise.all([\n ignoreFileContents === undefined\n ? Promise.resolve()\n : fsExtra.rm(IGNORE_FILE),\n fsExtra.rm(OLD_CONFIG_FILE),\n ]);\n\n return { result: 'apply' };\n } finally {\n await fsp.rm(dir, { recursive: true });\n }\n};\n\nconst writeTemporaryFiles = async (contents: Record<string, string>) => {\n const dir = await fsp.mkdtemp('eslint-migrate-config');\n\n for (const [file, content] of Object.entries(contents)) {\n await fsp.writeFile(path.join(dir, file), content);\n }\n\n return dir;\n};\n\nconst fiddleWithOutput = (input: string) => {\n let output = input.replace(/compat.extends\\([\"']skuba[\"']\\)/, 'skuba');\n\n if (!output.includes('eslint-config-skuba')) {\n output = `const skuba = require('eslint-config-skuba');\\n\\n${output}`;\n }\n\n if (!output.includes('compat.')) {\n output = output.replace(/const compat = new FlatCompat\\(\\{[^}]+\\}\\);/m, '');\n output = output.replace(\n /const \\{\\s*FlatCompat,?\\s*\\}\\s*=\\s*require\\([\"']@eslint\\/eslintrc[\"']\\);/m,\n '',\n );\n }\n\n if (!output.includes('js.')) {\n output = output.replace(/const js = require\\(['\"]@eslint\\/js['\"]\\);/, '');\n }\n\n output = output.replace(\n /^const skuba = require\\('eslint-config-skuba'\\);\\s*module.exports = \\[...skuba\\];$/m,\n \"module.exports = require('eslint-config-skuba');\",\n );\n\n return output;\n};\n\nexport const tryUpgradeESLint: PatchFunction = async (config) => {\n try {\n return await upgradeESLint(config);\n } catch (err) {\n log.warn('Failed to upgrade ESLint to flat config.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// eslint-disable-next-line no-restricted-imports -- fs-extra is mocked\nimport * as fsp from 'fs/promises';\nimport path from 'path';\nimport { inspect } from 'util';\n\nimport { promises as fsExtra } from 'fs-extra';\n\nimport type { PatchFunction, PatchReturnType } from '../..';\nimport { createExec } from '../../../../../../utils/exec';\nimport { log } from '../../../../../../utils/logging';\nimport { createDestinationFileReader } from '../../../../../configure/analysis/project';\nimport { mergeWithConfigFile } from '../../../../../configure/processing/configFile';\nimport { formatPrettier } from '../../../../../configure/processing/prettier';\n\nconst IGNORE_FILE = '.eslintignore';\nconst OLD_CONFIG_FILE = '.eslintrc.js';\nconst NEW_CONFIG_FILE_CJS = 'eslint.config.cjs';\nconst NEW_CONFIG_FILE_JS = 'eslint.config.js';\n\nconst upgradeESLint: PatchFunction = async ({\n mode,\n dir: cwd = process.cwd(),\n}): Promise<PatchReturnType> => {\n const readFile = createDestinationFileReader(cwd);\n const [ignoreFileContents, oldConfig] = await Promise.all([\n readFile(IGNORE_FILE),\n readFile(OLD_CONFIG_FILE),\n ]);\n\n if (oldConfig === undefined) {\n return {\n result: 'skip',\n reason: `no ${OLD_CONFIG_FILE} - have you already migrated?`,\n };\n }\n\n if (mode === 'lint') {\n return { result: 'apply' };\n }\n\n const ignoreContentsWithoutSkubaManaged = mergeWithConfigFile(\n '',\n 'ignore',\n )(ignoreFileContents);\n\n const exec = createExec({\n cwd: process.cwd(),\n stdio: 'ignore',\n });\n\n // eslint-migrate-config require()s the file, so for testability, put it in a temporary location\n const dir = await writeTemporaryFiles({\n [OLD_CONFIG_FILE]: oldConfig,\n ...(ignoreContentsWithoutSkubaManaged.trim().length > 0\n ? { [IGNORE_FILE]: ignoreContentsWithoutSkubaManaged }\n : {}),\n });\n try {\n await exec(\n 'eslint-migrate-config',\n path.join(dir, OLD_CONFIG_FILE),\n '--commonjs',\n );\n\n const output = fiddleWithOutput(\n await fsp.readFile(path.join(dir, NEW_CONFIG_FILE_CJS), 'utf-8'),\n );\n await fsExtra.writeFile(\n NEW_CONFIG_FILE_JS,\n await formatPrettier(output, { filepath: NEW_CONFIG_FILE_JS }),\n );\n\n await Promise.all([\n ignoreFileContents === undefined\n ? Promise.resolve()\n : fsExtra.rm(IGNORE_FILE),\n fsExtra.rm(OLD_CONFIG_FILE),\n ]);\n\n return { result: 'apply' };\n } finally {\n await fsp.rm(dir, { recursive: true });\n }\n};\n\nconst writeTemporaryFiles = async (contents: Record<string, string>) => {\n const dir = await fsp.mkdtemp('eslint-migrate-config');\n\n await Promise.all(\n Object.entries(contents).map(([file, content]) =>\n fsp.writeFile(path.join(dir, file), content),\n ),\n );\n\n return dir;\n};\n\nconst fiddleWithOutput = (input: string) => {\n let output = input.replace(/compat.extends\\([\"']skuba[\"']\\)/, 'skuba');\n\n if (!output.includes('eslint-config-skuba')) {\n output = `const skuba = require('eslint-config-skuba');\\n\\n${output}`;\n }\n\n if (!output.includes('compat.')) {\n output = output.replace(/const compat = new FlatCompat\\(\\{[^}]+\\}\\);/m, '');\n output = output.replace(\n /const \\{\\s*FlatCompat,?\\s*\\}\\s*=\\s*require\\([\"']@eslint\\/eslintrc[\"']\\);/m,\n '',\n );\n }\n\n if (!output.includes('js.')) {\n output = output.replace(/const js = require\\(['\"]@eslint\\/js['\"]\\);/, '');\n }\n\n output = output.replace(\n /^const skuba = require\\('eslint-config-skuba'\\);\\s*module.exports = \\[...skuba\\];$/m,\n \"module.exports = require('eslint-config-skuba');\",\n );\n\n return output;\n};\n\nexport const tryUpgradeESLint: PatchFunction = async (config) => {\n try {\n return await upgradeESLint(config);\n } catch (err) {\n log.warn('Failed to upgrade ESLint to flat config.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["path", "fsExtra"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/wrapper/requestListener.ts"],
4
- "sourcesContent": ["import http from 'http';\n\nimport { isFunction, isIpPort, isObject } from '../utils/validation';\n\nimport { serveRequestListener, startServer } from './http';\n\n// Express compatibility\ninterface FunctionConfig extends http.RequestListener {\n port?: number;\n}\n\ninterface ObjectConfig {\n // Koa compatibility\n callback?: () => http.RequestListener;\n\n requestListener?: http.RequestListener;\n\n // Fastify compatibility\n server?: http.Server;\n\n default?: Promise<unknown>;\n port?: unknown;\n}\n\nconst isConfig = (\n data: unknown,\n): data is Promise<FunctionConfig> | Promise<ObjectConfig> =>\n isFunction(data) || isObject(data);\n\ninterface Args {\n availablePort?: number;\n entryPoint: unknown;\n}\n\n/**\n * Create an HTTP server that calls into an exported `http.RequestListener`.\n *\n * This supports Express and Koa applications out of the box.\n */\nexport const runRequestListener = async ({\n availablePort,\n entryPoint,\n}: Args): Promise<void> => {\n if (!isConfig(entryPoint)) {\n // Assume an executable script with weird exports\n return;\n }\n\n let config: FunctionConfig | ObjectConfig = await entryPoint;\n\n if (typeof config === 'object' && isConfig(config.default)) {\n // Prefer `export default` over `export =`\n config = await config.default;\n }\n\n if (Object.keys(config).length === 0) {\n // Assume an executable script with no exports\n return;\n }\n\n const port = isIpPort(config.port) ? config.port : availablePort;\n\n // http.Server support\n if (typeof config !== 'function' && config instanceof http.Server) {\n return startServer(config, port);\n }\n\n // Fastify workaround\n if (\n typeof config !== 'function' &&\n config.server &&\n config.server instanceof http.Server\n ) {\n return startServer(config.server, port);\n }\n\n const requestListener =\n typeof config === 'function'\n ? config\n : config.requestListener ?? config.callback?.();\n\n if (typeof requestListener !== 'function') {\n // Assume an executable script with non-request listener exports\n return;\n }\n\n return serveRequestListener(requestListener, port);\n};\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AAEjB,wBAA+C;AAE/C,IAAAA,eAAkD;AAoBlD,MAAM,WAAW,CACf,aAEA,8BAAW,IAAI,SAAK,4BAAS,IAAI;AAY5B,MAAM,qBAAqB,OAAO;AAAA,EACvC;AAAA,EACA;AACF,MAA2B;AACzB,MAAI,CAAC,SAAS,UAAU,GAAG;AAEzB;AAAA,EACF;AAEA,MAAI,SAAwC,MAAM;AAElD,MAAI,OAAO,WAAW,YAAY,SAAS,OAAO,OAAO,GAAG;AAE1D,aAAS,MAAM,OAAO;AAAA,EACxB;AAEA,MAAI,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG;AAEpC;AAAA,EACF;AAEA,QAAM,WAAO,4BAAS,OAAO,IAAI,IAAI,OAAO,OAAO;AAGnD,MAAI,OAAO,WAAW,cAAc,kBAAkB,YAAAC,QAAK,QAAQ;AACjE,eAAO,0BAAY,QAAQ,IAAI;AAAA,EACjC;AAGA,MACE,OAAO,WAAW,cAClB,OAAO,UACP,OAAO,kBAAkB,YAAAA,QAAK,QAC9B;AACA,eAAO,0BAAY,OAAO,QAAQ,IAAI;AAAA,EACxC;AAEA,QAAM,kBACJ,OAAO,WAAW,aACd,SACA,OAAO,mBAAmB,OAAO,WAAW;AAElD,MAAI,OAAO,oBAAoB,YAAY;AAEzC;AAAA,EACF;AAEA,aAAO,mCAAqB,iBAAiB,IAAI;AACnD;",
4
+ "sourcesContent": ["import http from 'http';\n\nimport { isFunction, isIpPort, isObject } from '../utils/validation';\n\nimport { serveRequestListener, startServer } from './http';\n\n// Express compatibility\ninterface FunctionConfig extends http.RequestListener {\n port?: number;\n}\n\ninterface ObjectConfig {\n // Koa compatibility\n callback?: () => http.RequestListener;\n\n requestListener?: http.RequestListener;\n\n // Fastify compatibility\n server?: http.Server;\n\n default?: Promise<unknown>;\n port?: unknown;\n}\n\nconst isConfig = (\n data: unknown,\n): data is Promise<FunctionConfig> | Promise<ObjectConfig> =>\n isFunction(data) || isObject(data);\n\ninterface Args {\n availablePort?: number;\n entryPoint: unknown;\n}\n\n/**\n * Create an HTTP server that calls into an exported `http.RequestListener`.\n *\n * This supports Express and Koa applications out of the box.\n */\nexport const runRequestListener = async ({\n availablePort,\n entryPoint,\n}: Args): Promise<void> => {\n if (!isConfig(entryPoint)) {\n // Assume an executable script with weird exports\n return;\n }\n\n let config: FunctionConfig | ObjectConfig = await entryPoint;\n\n if (typeof config === 'object' && isConfig(config.default)) {\n // Prefer `export default` over `export =`\n config = await config.default;\n }\n\n if (Object.keys(config).length === 0) {\n // Assume an executable script with no exports\n return;\n }\n\n const port = isIpPort(config.port) ? config.port : availablePort;\n\n // http.Server support\n if (typeof config !== 'function' && config instanceof http.Server) {\n return startServer(config, port);\n }\n\n // Fastify workaround\n if (\n typeof config !== 'function' &&\n config.server &&\n config.server instanceof http.Server\n ) {\n return startServer(config.server, port);\n }\n\n const requestListener =\n typeof config === 'function'\n ? config\n : (config.requestListener ?? config.callback?.());\n\n if (typeof requestListener !== 'function') {\n // Assume an executable script with non-request listener exports\n return;\n }\n\n return serveRequestListener(requestListener, port);\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AAEjB,wBAA+C;AAE/C,IAAAA,eAAkD;AAoBlD,MAAM,WAAW,CACf,aAEA,8BAAW,IAAI,SAAK,4BAAS,IAAI;AAY5B,MAAM,qBAAqB,OAAO;AAAA,EACvC;AAAA,EACA;AACF,MAA2B;AACzB,MAAI,CAAC,SAAS,UAAU,GAAG;AAEzB;AAAA,EACF;AAEA,MAAI,SAAwC,MAAM;AAElD,MAAI,OAAO,WAAW,YAAY,SAAS,OAAO,OAAO,GAAG;AAE1D,aAAS,MAAM,OAAO;AAAA,EACxB;AAEA,MAAI,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG;AAEpC;AAAA,EACF;AAEA,QAAM,WAAO,4BAAS,OAAO,IAAI,IAAI,OAAO,OAAO;AAGnD,MAAI,OAAO,WAAW,cAAc,kBAAkB,YAAAC,QAAK,QAAQ;AACjE,eAAO,0BAAY,QAAQ,IAAI;AAAA,EACjC;AAGA,MACE,OAAO,WAAW,cAClB,OAAO,UACP,OAAO,kBAAkB,YAAAA,QAAK,QAC9B;AACA,eAAO,0BAAY,OAAO,QAAQ,IAAI;AAAA,EACxC;AAEA,QAAM,kBACJ,OAAO,WAAW,aACd,SACC,OAAO,mBAAmB,OAAO,WAAW;AAEnD,MAAI,OAAO,oBAAoB,YAAY;AAEzC;AAAA,EACF;AAEA,aAAO,mCAAqB,iBAAiB,IAAI;AACnD;",
6
6
  "names": ["import_http", "http"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skuba",
3
- "version": "9.0.0-renovate-eslint-9.x-20240923103202",
3
+ "version": "9.0.1-upgrade-cdk-template-20241002233314",
4
4
  "private": false,
5
5
  "description": "SEEK development toolkit for backend applications and packages",
6
6
  "homepage": "https://github.com/seek-oss/skuba#readme",
@@ -65,7 +65,7 @@
65
65
  "ejs": "^3.1.6",
66
66
  "enquirer": "^2.3.6",
67
67
  "esbuild": "~0.24.0",
68
- "eslint": "^9.0.0",
68
+ "eslint": "^9.11.1",
69
69
  "execa": "^5.0.0",
70
70
  "fast-glob": "^3.3.2",
71
71
  "find-up": "^5.0.0",
@@ -81,7 +81,7 @@
81
81
  "libnpmsearch": "^7.0.0",
82
82
  "lodash.mergewith": "^4.6.2",
83
83
  "minimist": "^1.2.6",
84
- "normalize-package-data": "^6.0.0",
84
+ "normalize-package-data": "^7.0.0",
85
85
  "npm-run-path": "^4.0.1",
86
86
  "npm-which": "^3.0.1",
87
87
  "picomatch": "^4.0.0",
@@ -99,9 +99,9 @@
99
99
  "tsconfig-seek": "2.0.0",
100
100
  "tsx": "^4.16.2",
101
101
  "typescript": "~5.6.0",
102
- "validate-npm-package-name": "^5.0.0",
102
+ "validate-npm-package-name": "^6.0.0",
103
103
  "zod": "^3.22.4",
104
- "eslint-config-skuba": "5.0.0-renovate-eslint-9.x-20240923103202"
104
+ "eslint-config-skuba": "5.0.0"
105
105
  },
106
106
  "devDependencies": {
107
107
  "@changesets/cli": "2.27.8",
@@ -121,12 +121,12 @@
121
121
  "@types/supertest": "6.0.2",
122
122
  "@types/validate-npm-package-name": "4.0.2",
123
123
  "enhanced-resolve": "5.17.1",
124
- "express": "4.20.0",
125
- "fastify": "4.28.1",
124
+ "express": "4.21.0",
125
+ "fastify": "5.0.0",
126
126
  "jest-diff": "29.7.0",
127
127
  "jsonfile": "6.1.0",
128
128
  "koa": "2.15.3",
129
- "memfs": "4.11.1",
129
+ "memfs": "4.12.0",
130
130
  "remark-cli": "12.0.1",
131
131
  "remark-preset-lint-recommended": "7.0.0",
132
132
  "semver": "7.6.3",
@@ -152,7 +152,7 @@
152
152
  "entryPoint": "src/index.ts",
153
153
  "template": null,
154
154
  "type": "package",
155
- "version": "8.2.1"
155
+ "version": "9.0.0"
156
156
  },
157
157
  "scripts": {
158
158
  "build": "scripts/build.sh",
@@ -15,12 +15,12 @@ configs:
15
15
  - package.json#.packageManager
16
16
  - pnpm-lock.yaml
17
17
  dockerfile: Dockerfile.dev-deps
18
- secrets: id=npm,src=tmp/.npmrc
18
+ secrets: id=npm,src=/tmp/.npmrc
19
19
 
20
20
  - &private-npm
21
21
  seek-oss/private-npm#v1.2.0:
22
22
  env: NPM_READ_TOKEN
23
- output-path: tmp/
23
+ output-path: /tmp/
24
24
 
25
25
  base-steps:
26
26
  - &deploy
@@ -12,7 +12,7 @@ RUN pnpm install --offline --prod
12
12
 
13
13
  ###
14
14
 
15
- FROM --platform=<%- platformName %> gcr.io/distroless/nodejs20-debian12 AS runtime
15
+ FROM gcr.io/distroless/nodejs20-debian12 AS runtime
16
16
 
17
17
  WORKDIR /workdir
18
18
 
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.10
2
2
 
3
- FROM --platform=<%- platformName %> node:20-alpine AS dev-deps
3
+ FROM public.ecr.aws/docker/library/node:20-alpine AS dev-deps
4
4
 
5
5
  RUN --mount=type=bind,source=package.json,target=package.json \
6
6
  corepack enable pnpm && corepack install
@@ -13,7 +13,7 @@
13
13
  "test:watch": "skuba test --watch"
14
14
  },
15
15
  "dependencies": {
16
- "@seek/logger": "^6.0.0",
16
+ "@seek/logger": "^9.0.0",
17
17
  "express": "^4.17.1",
18
18
  "hot-shots": "^10.0.0",
19
19
  "seek-datadog-custom-metrics": "^4.6.3",
@@ -16,12 +16,12 @@ configs:
16
16
  - .npmrc
17
17
  - package.json#.packageManager
18
18
  - pnpm-lock.yaml
19
- secrets: id=npm,src=tmp/.npmrc
19
+ secrets: id=npm,src=/tmp/.npmrc
20
20
 
21
21
  - &private-npm
22
22
  seek-oss/private-npm#v1.2.0:
23
23
  env: NPM_READ_TOKEN
24
- output-path: tmp/
24
+ output-path: /tmp/
25
25
 
26
26
  steps:
27
27
  - label: 🧪 Test & Lint
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.10
2
2
 
3
- FROM --platform=<%- platformName %> node:20-alpine AS dev-deps
3
+ FROM public.ecr.aws/docker/library/node:20-alpine AS dev-deps
4
4
 
5
5
  RUN --mount=type=bind,source=package.json,target=package.json \
6
6
  corepack enable pnpm && corepack install
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/node": "^20.9.0",
20
- "skuba": "9.0.0-renovate-eslint-9.x-20240923103202"
20
+ "skuba": "9.0.1-upgrade-cdk-template-20241002233314"
21
21
  },
22
22
  "packageManager": "pnpm@9.11.0",
23
23
  "engines": {
@@ -15,12 +15,12 @@ configs:
15
15
  - package.json#.packageManager
16
16
  - pnpm-lock.yaml
17
17
  dockerfile: Dockerfile.dev-deps
18
- secrets: id=npm,src=tmp/.npmrc
18
+ secrets: id=npm,src=/tmp/.npmrc
19
19
 
20
20
  - &private-npm
21
21
  seek-oss/private-npm#v1.2.0:
22
22
  env: NPM_READ_TOKEN
23
- output-path: tmp/
23
+ output-path: /tmp/
24
24
 
25
25
  base-steps:
26
26
  - &deploy
@@ -12,7 +12,7 @@ RUN pnpm install --offline --prod
12
12
 
13
13
  ###
14
14
 
15
- FROM --platform=<%- platformName %> gcr.io/distroless/nodejs20-debian12 AS runtime
15
+ FROM gcr.io/distroless/nodejs20-debian12 AS runtime
16
16
 
17
17
  WORKDIR /workdir
18
18
 
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.10
2
2
 
3
- FROM --platform=<%- platformName %> node:20-alpine AS dev-deps
3
+ FROM public.ecr.aws/docker/library/node:20-alpine AS dev-deps
4
4
 
5
5
  RUN --mount=type=bind,source=package.json,target=package.json \
6
6
  corepack enable pnpm && corepack install
@@ -13,7 +13,8 @@
13
13
  "test:watch": "skuba test --watch"
14
14
  },
15
15
  "dependencies": {
16
- "@koa/router": "^12.0.0",
16
+ "@koa/bodyparser": "^5.1.1",
17
+ "@koa/router": "^13.0.0",
17
18
  "@opentelemetry/api": "^1.9.0",
18
19
  "@opentelemetry/core": "^1.25.0",
19
20
  "@opentelemetry/exporter-trace-otlp-grpc": "^0.53.0",
@@ -21,10 +22,9 @@
21
22
  "@opentelemetry/instrumentation-http": "^0.53.0",
22
23
  "@opentelemetry/propagator-b3": "^1.25.0",
23
24
  "@opentelemetry/sdk-node": "^0.53.0",
24
- "@seek/logger": "^6.0.0",
25
+ "@seek/logger": "^9.0.0",
25
26
  "hot-shots": "^10.0.0",
26
27
  "koa": "^2.13.4",
27
- "koa-bodyparser": "^4.3.0",
28
28
  "koa-compose": "^4.1.0",
29
29
  "seek-datadog-custom-metrics": "^4.6.3",
30
30
  "seek-koala": "^7.0.0",
@@ -33,8 +33,8 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/chance": "^1.1.3",
36
+ "@types/co-body": "^6.1.3",
36
37
  "@types/koa": "^2.13.4",
37
- "@types/koa-bodyparser": "^5.0.2",
38
38
  "@types/koa__router": "^12.0.0",
39
39
  "@types/node": "^20.16.5",
40
40
  "@types/supertest": "^6.0.0",
@@ -1,3 +1,3 @@
1
- import bodyParser from 'koa-bodyparser';
1
+ import { bodyParser } from '@koa/bodyparser';
2
2
 
3
3
  export const jsonBodyParser = bodyParser({ enableTypes: ['json'] });
@@ -203,7 +203,6 @@ describe('createApp', () => {
203
203
 
204
204
  it('handles null error', async () => {
205
205
  middleware.mockImplementation(() => {
206
- /* eslint-disable-next-line @typescript-eslint/only-throw-error */
207
206
  throw null;
208
207
  });
209
208
 
@@ -14,12 +14,12 @@ configs:
14
14
  - .npmrc
15
15
  - package.json#.packageManager
16
16
  - pnpm-lock.yaml
17
- secrets: id=npm,src=tmp/.npmrc
17
+ secrets: id=npm,src=/tmp/.npmrc
18
18
 
19
19
  - &private-npm
20
20
  seek-oss/private-npm#v1.2.0:
21
21
  env: NPM_READ_TOKEN
22
- output-path: tmp/
22
+ output-path: /tmp/
23
23
 
24
24
  base-steps:
25
25
  - &deploy
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.10
2
2
 
3
- FROM --platform=<%- platformName %> node:20-alpine AS dev-deps
3
+ FROM public.ecr.aws/docker/library/node:20-alpine AS dev-deps
4
4
 
5
5
  RUN --mount=type=bind,source=package.json,target=package.json \
6
6
  corepack enable pnpm && corepack install
@@ -18,8 +18,8 @@
18
18
  "@aws-sdk/client-codedeploy": "^3.363.0",
19
19
  "@aws-sdk/client-lambda": "^3.363.0",
20
20
  "@aws-sdk/client-sns": "^3.363.0",
21
- "@seek/logger": "^6.0.0",
22
- "datadog-lambda-js": "^8.0.0",
21
+ "@seek/logger": "^9.0.0",
22
+ "datadog-lambda-js": "^9.0.0",
23
23
  "dd-trace": "^5.0.0",
24
24
  "skuba-dive": "^2.0.0",
25
25
  "zod": "^3.19.1"
@@ -173,7 +173,7 @@ resources:
173
173
  # Properties:
174
174
  # Endpoint: !GetAtt MessageQueue.Arn
175
175
  # Protocol: sqs
176
- # RawMessageDelivery: true
176
+ # RawMessageDelivery: true # Remove this property if you require end to end datadog tracing
177
177
  # TopicArn: 'TODO: sourceSnsTopicArn'
178
178
 
179
179
  DestinationTopic:
@@ -14,12 +14,12 @@ configs:
14
14
  - .npmrc
15
15
  - package.json#.packageManager
16
16
  - pnpm-lock.yaml
17
- secrets: id=npm,src=tmp/.npmrc
17
+ secrets: id=npm,src=/tmp/.npmrc
18
18
 
19
19
  - &private-npm
20
20
  seek-oss/private-npm#v1.2.0:
21
21
  env: NPM_READ_TOKEN
22
- output-path: tmp/
22
+ output-path: /tmp/
23
23
 
24
24
  base-steps:
25
25
  - &deploy
@@ -0,0 +1 @@
1
+ ENVIRONMENT=local
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.10
2
2
 
3
- FROM --platform=<%- platformName %> node:20-alpine AS dev-deps
3
+ FROM public.ecr.aws/docker/library/node:20-alpine AS dev-deps
4
4
 
5
5
  # Needed for cdk
6
6
  RUN apk add --no-cache bash
@@ -0,0 +1,145 @@
1
+ # <%- repoName %>
2
+
3
+ [![Powered by skuba](https://img.shields.io/badge/🤿%20skuba-powered-009DC4)](https://github.com/seek-oss/skuba)
4
+
5
+ Next steps:
6
+
7
+ 1. [ ] Finish templating if this was skipped earlier:
8
+
9
+ ```shell
10
+ pnpm exec skuba configure
11
+ ```
12
+
13
+ 2. [ ] Create a new repository in the appropriate GitHub organisation.
14
+ 3. [ ] Add the repository to BuildAgency;
15
+ see our internal [Buildkite Docs] for more information.
16
+ 4. [ ] Add Datadog extension, deployment bucket configuration and data classification tags to [infra/config.ts](infra/config.ts).
17
+ 5. [ ] Push local commits to the upstream GitHub branch.
18
+ 6. [ ] Configure [GitHub repository settings].
19
+ 7. [ ] Delete this checklist 😌.
20
+
21
+ [Buildkite Docs]: https://backstage.myseek.xyz/docs/default/component/buildkite-docs
22
+ [GitHub repository settings]: https://github.com/<%-orgName%>/<%-repoName%>/settings
23
+
24
+ ## Design
25
+
26
+ <%-repoName %> is a Node.js [Lambda] application built in line with our [Technical Guidelines].
27
+ It is backed by a typical SQS message + dead letter queue configuration and uses common SEEK packages.
28
+ Workers enable fault-tolerant asynchronous processing of events.
29
+
30
+ The `lambda-sqs-worker-cdk` template is modelled after a hypothetical enricher that scores job advertisements.
31
+ It's stubbed out with in-memory [scoring service](src/services/jobScorer.ts).
32
+ This would be replaced with internal logic or an external service in production.
33
+
34
+ This project is deployed with [AWS CDK].
35
+ The Lambda runtime provisions a single Node.js process per container.
36
+ The supplied [infra/appStack.ts](infra/appStack.ts) starts out with a minimal `memorySize` which may require tuning based on workload.
37
+ Under load, we autoscale horizontally in terms of container count up to `reservedConcurrency`.
38
+
39
+ [@seek/aws-codedeploy-hooks] configures [CodeDeploy] for a blue-green deployment approach.
40
+ A smoke test is run against the new version before traffic is switched over,
41
+ providing an opportunity to test access and connectivity to online dependencies.
42
+ This defaults to an invocation with an empty object `{}`.
43
+
44
+ ## Development
45
+
46
+ ### Test
47
+
48
+ ```shell
49
+ # Run Jest tests locally
50
+ pnpm test
51
+
52
+ # Authenticate to dev account
53
+ awsauth
54
+
55
+ # Run smoke test against deployed application
56
+ ENVIRONMENT=dev pnpm smoke
57
+ ```
58
+
59
+ ### Lint
60
+
61
+ ```shell
62
+ # Fix issues
63
+ pnpm format
64
+
65
+ # Check for issues
66
+ pnpm lint
67
+ ```
68
+
69
+ ### Start
70
+
71
+ ```shell
72
+ # Start a local HTTP server
73
+ pnpm start
74
+
75
+ # Start with Node.js Inspector enabled
76
+ pnpm start:debug
77
+ ```
78
+
79
+ This serves the Lambda application over HTTP.
80
+ For example, to invoke the handler with an empty object `{}` for smoke testing:
81
+
82
+ ```shell
83
+ curl --data '[{}, {"awsRequestId": "local"}]' --include localhost:<%- port %>
84
+ ```
85
+
86
+ ### Deploy
87
+
88
+ This project is deployed through a [Buildkite pipeline](.buildkite/pipeline.yml).
89
+
90
+ - Commits to a feature branch can be deployed to the dev environment by unblocking a step in the Buildkite UI
91
+ - Commits to the default branch are automatically deployed to the dev and prod environments in sequence
92
+
93
+ To deploy locally:
94
+
95
+ ```shell
96
+ # Authenticate to dev account
97
+ awsauth
98
+
99
+ ENVIRONMENT=dev pnpm run deploy
100
+ ```
101
+
102
+ A hotswap deploy enables faster deployment but come with caveats such as requiring a Lambda to be rebuilt with every build.
103
+
104
+ To deploy a [hotswap]:
105
+
106
+ ```shell
107
+ # Authenticate to dev account
108
+ awsauth
109
+
110
+ ENVIRONMENT=dev pnpm run deploy:hotswap
111
+ ```
112
+
113
+ To rapidly roll back a change,
114
+ retry an individual deployment step from the previous build in Buildkite.
115
+ Note that this will introduce drift between the head of the default Git branch and the live environment;
116
+ use with caution and always follow up with a proper revert or fix in Git history.
117
+
118
+ ## Support
119
+
120
+ ### Dev
121
+
122
+ TODO: add support links for the dev environment.
123
+
124
+ <!--
125
+ - CloudWatch dashboard
126
+ - Datadog dashboard
127
+ - Splunk logs
128
+ -->
129
+
130
+ ### Prod
131
+
132
+ TODO: add support links for the prod environment.
133
+
134
+ <!--
135
+ - CloudWatch dashboard
136
+ - Datadog dashboard
137
+ - Splunk logs
138
+ -->
139
+
140
+ [@seek/aws-codedeploy-hooks]: https://github.com/seek-oss/aws-codedeploy-hooks
141
+ [AWS CDK]: https://docs.aws.amazon.com/cdk/v2/guide/home.html
142
+ [CodeDeploy]: https://docs.aws.amazon.com/codedeploy
143
+ [Hotswap]: https://docs.aws.amazon.com/cdk/v2/guide/ref-cli-cmd-deploy.html#ref-cli-cmd-deploy-options
144
+ [Lambda]: https://docs.aws.amazon.com/lambda
145
+ [Technical Guidelines]: https://myseek.atlassian.net/wiki/spaces/AA/pages/2358346017/