skuba 13.0.0-custom-conditions-exports-20250730235248 → 13.0.0-custom-conditions-exports-20250923005538

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 (136) hide show
  1. package/README.md +1 -2
  2. package/config/tsconfig.json +2 -1
  3. package/jest/moduleNameMapper.js +3 -0
  4. package/lib/cli/build/assets.js +1 -1
  5. package/lib/cli/build/assets.js.map +2 -2
  6. package/lib/cli/build/esbuild.js +1 -1
  7. package/lib/cli/build/esbuild.js.map +2 -2
  8. package/lib/cli/build/index.js +1 -1
  9. package/lib/cli/build/index.js.map +2 -2
  10. package/lib/cli/build/tsc.d.ts +9 -2
  11. package/lib/cli/build/tsc.js +76 -40
  12. package/lib/cli/build/tsc.js.map +3 -3
  13. package/lib/cli/configure/analyseDependencies.d.ts +2 -2
  14. package/lib/cli/configure/analyseDependencies.js.map +1 -1
  15. package/lib/cli/configure/analysis/package.d.ts +1 -1
  16. package/lib/cli/configure/analysis/package.js +1 -1
  17. package/lib/cli/configure/analysis/package.js.map +2 -2
  18. package/lib/cli/configure/ensureTemplateCompletion.d.ts +2 -2
  19. package/lib/cli/configure/ensureTemplateCompletion.js.map +1 -1
  20. package/lib/cli/configure/getEntryPoint.d.ts +2 -2
  21. package/lib/cli/configure/getEntryPoint.js.map +1 -1
  22. package/lib/cli/configure/getProjectType.d.ts +2 -2
  23. package/lib/cli/configure/getProjectType.js.map +1 -1
  24. package/lib/cli/configure/processing/package.js +8 -2
  25. package/lib/cli/configure/processing/package.js.map +2 -2
  26. package/lib/cli/init/getConfig.js +1 -1
  27. package/lib/cli/init/getConfig.js.map +2 -2
  28. package/lib/cli/lint/internal.js +1 -1
  29. package/lib/cli/lint/internal.js.map +2 -2
  30. package/lib/cli/lint/internalLints/patchRenovateConfig.js +2 -2
  31. package/lib/cli/lint/internalLints/patchRenovateConfig.js.map +1 -1
  32. package/lib/cli/lint/internalLints/upgrade/index.d.ts +2 -2
  33. package/lib/cli/lint/internalLints/upgrade/index.js.map +1 -1
  34. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/index.js +3 -8
  35. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/index.js.map +2 -2
  36. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/unhandledRejections.d.ts +4 -0
  37. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/unhandledRejections.js +162 -0
  38. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/unhandledRejections.js.map +7 -0
  39. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/index.d.ts +2 -0
  40. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/index.js +35 -0
  41. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/index.js.map +7 -0
  42. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/patchJestSnapshots.d.ts +3 -0
  43. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/patchJestSnapshots.js +105 -0
  44. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/patchJestSnapshots.js.map +7 -0
  45. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/configureTsConfigForESM.d.ts +23 -0
  46. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/configureTsConfigForESM.js +321 -0
  47. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/configureTsConfigForESM.js.map +7 -0
  48. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/index.d.ts +2 -0
  49. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/index.js +40 -0
  50. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/index.js.map +7 -0
  51. package/lib/cli/lint/internalLints/upgrade/patches/{12.0.2 → 12.2.0}/rewriteSrcImports.js +7 -4
  52. package/lib/cli/lint/internalLints/upgrade/patches/{12.0.2 → 12.2.0}/rewriteSrcImports.js.map +3 -3
  53. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js +1 -1
  54. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js.map +2 -2
  55. package/lib/cli/node/index.js +6 -0
  56. package/lib/cli/node/index.js.map +2 -2
  57. package/lib/cli/start/index.js +6 -0
  58. package/lib/cli/start/index.js.map +2 -2
  59. package/lib/cli/test/index.d.ts +1 -1
  60. package/lib/cli/test/index.js +18 -4
  61. package/lib/cli/test/index.js.map +2 -2
  62. package/lib/utils/args.d.ts +2 -0
  63. package/lib/utils/args.js +5 -0
  64. package/lib/utils/args.js.map +2 -2
  65. package/lib/utils/manifest.d.ts +1 -1
  66. package/lib/utils/manifest.js +1 -1
  67. package/lib/utils/manifest.js.map +2 -2
  68. package/lib/utils/template.d.ts +1 -1
  69. package/package.json +17 -20
  70. package/template/base/_.prettierrc.js +1 -1
  71. package/template/base/_eslint.config.js +1 -1
  72. package/template/base/_pnpm-workspace.yaml +1 -0
  73. package/template/base/jest.setup.ts +1 -1
  74. package/template/base/tsconfig.build.json +3 -0
  75. package/template/base/tsconfig.json +0 -1
  76. package/template/express-rest-api/.buildkite/pipeline.yml +6 -0
  77. package/template/express-rest-api/.env +1 -1
  78. package/template/express-rest-api/.gantry/dev.yml +5 -1
  79. package/template/express-rest-api/.gantry/prod.yml +5 -1
  80. package/template/express-rest-api/Dockerfile +1 -1
  81. package/template/express-rest-api/Dockerfile.dev-deps +1 -1
  82. package/template/express-rest-api/README.md +5 -5
  83. package/template/express-rest-api/gantry.apply.yml +17 -1
  84. package/template/express-rest-api/package.json +11 -5
  85. package/template/express-rest-api/src/api/healthCheck.ts +2 -2
  86. package/template/express-rest-api/src/config.ts +7 -7
  87. package/template/express-rest-api/src/framework/logging.ts +11 -7
  88. package/template/express-rest-api/src/framework/metrics.ts +1 -1
  89. package/template/express-rest-api/src/listen.ts +6 -0
  90. package/template/express-rest-api/src/tracing.ts +56 -0
  91. package/template/greeter/Dockerfile +1 -1
  92. package/template/greeter/README.md +2 -2
  93. package/template/greeter/package.json +2 -2
  94. package/template/koa-rest-api/.buildkite/pipeline.yml +6 -0
  95. package/template/koa-rest-api/.env +1 -1
  96. package/template/koa-rest-api/.gantry/dev.yml +3 -3
  97. package/template/koa-rest-api/.gantry/prod.yml +3 -3
  98. package/template/koa-rest-api/Dockerfile.dev-deps +1 -1
  99. package/template/koa-rest-api/README.md +6 -6
  100. package/template/koa-rest-api/gantry.apply.yml +15 -3
  101. package/template/koa-rest-api/package.json +10 -11
  102. package/template/koa-rest-api/skuba.template.js +1 -1
  103. package/template/koa-rest-api/src/api/healthCheck.ts +2 -2
  104. package/template/koa-rest-api/src/config.ts +7 -7
  105. package/template/koa-rest-api/src/framework/logging.ts +12 -8
  106. package/template/koa-rest-api/src/framework/metrics.ts +1 -1
  107. package/template/koa-rest-api/src/framework/server.test.ts +7 -8
  108. package/template/koa-rest-api/src/framework/server.ts +1 -4
  109. package/template/koa-rest-api/src/listen.ts +6 -0
  110. package/template/lambda-sqs-worker-cdk/.buildkite/pipeline.yml +6 -2
  111. package/template/lambda-sqs-worker-cdk/.env +1 -1
  112. package/template/lambda-sqs-worker-cdk/Dockerfile +1 -1
  113. package/template/lambda-sqs-worker-cdk/README.md +8 -8
  114. package/template/lambda-sqs-worker-cdk/infra/__snapshots__/appStack.test.ts.snap +54 -26
  115. package/template/lambda-sqs-worker-cdk/infra/appStack.test.ts +5 -22
  116. package/template/lambda-sqs-worker-cdk/infra/appStack.ts +16 -9
  117. package/template/lambda-sqs-worker-cdk/infra/config.ts +34 -20
  118. package/template/lambda-sqs-worker-cdk/infra/index.ts +1 -1
  119. package/template/lambda-sqs-worker-cdk/package.json +7 -9
  120. package/template/lambda-sqs-worker-cdk/src/app.test.ts +91 -51
  121. package/template/lambda-sqs-worker-cdk/src/app.ts +10 -9
  122. package/template/lambda-sqs-worker-cdk/src/config.ts +11 -16
  123. package/template/lambda-sqs-worker-cdk/src/framework/handler.test.ts +10 -5
  124. package/template/lambda-sqs-worker-cdk/src/framework/handler.ts +48 -24
  125. package/template/lambda-sqs-worker-cdk/src/framework/logging.ts +23 -11
  126. package/template/lambda-sqs-worker-cdk/src/framework/metrics.ts +1 -4
  127. package/template/lambda-sqs-worker-cdk/src/testing/handler.ts +4 -1
  128. package/template/lambda-sqs-worker-cdk/tsconfig.json +1 -2
  129. package/template/oss-npm-package/.github/workflows/release.yml +5 -6
  130. package/template/oss-npm-package/.github/workflows/validate.yml +5 -5
  131. package/template/oss-npm-package/_package.json +0 -3
  132. package/template/oss-npm-package/skuba.template.js +1 -1
  133. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/configureTsConfigForESM.d.ts +0 -6
  134. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/configureTsConfigForESM.js +0 -248
  135. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/configureTsConfigForESM.js.map +0 -7
  136. /package/lib/cli/lint/internalLints/upgrade/patches/{12.0.2 → 12.2.0}/rewriteSrcImports.d.ts +0 -0
@@ -1,4 +1,4 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
2
 
3
3
  exports[`returns expected CloudFormation stack for dev 1`] = `
4
4
  {
@@ -173,35 +173,35 @@ exports[`returns expected CloudFormation stack for dev 1`] = `
173
173
  },
174
174
  "S3Key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.zip",
175
175
  },
176
- "Description": "Updated at 1212-12-12T12:12:12.121Z",
177
176
  "Environment": {
178
177
  "Variables": {
179
178
  "DD_API_KEY_SECRET_ARN": {
180
179
  "Ref": "datadogapikeysecret046FEF06",
181
180
  },
182
181
  "DD_CAPTURE_LAMBDA_PAYLOAD": "false",
182
+ "DD_ENV": "development",
183
183
  "DD_FLUSH_TO_LOG": "false",
184
184
  "DD_LAMBDA_HANDLER": "index.handler",
185
185
  "DD_LOGS_INJECTION": "false",
186
186
  "DD_MERGE_XRAY_TRACES": "false",
187
187
  "DD_SERVERLESS_APPSEC_ENABLED": "false",
188
188
  "DD_SERVERLESS_LOGS_ENABLED": "false",
189
+ "DD_SERVICE": "serviceName",
189
190
  "DD_SITE": "datadoghq.com",
190
191
  "DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING": "$.*",
191
192
  "DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING": "$.*",
192
193
  "DD_TRACE_ENABLED": "true",
194
+ "DD_VERSION": "local",
195
+ "DEPLOYMENT": "dev",
193
196
  "DESTINATION_SNS_TOPIC_ARN": {
194
197
  "Ref": "destinationtopicDCE2E0B8",
195
198
  },
196
- "ENVIRONMENT": "dev",
197
199
  "NODE_ENV": "production",
198
200
  "NODE_OPTIONS": "--enable-source-maps",
199
- "SERVICE": "serviceName",
200
- "VERSION": "local",
201
201
  },
202
202
  },
203
203
  "FunctionName": "serviceName",
204
- "Handler": "node_modules/datadog-lambda-js/dist/handler.handler",
204
+ "Handler": "/opt/nodejs/node_modules/datadog-lambda-js/handler.handler",
205
205
  "KmsKeyArn": {
206
206
  "Fn::GetAtt": [
207
207
  "kmskey49FBC3B3",
@@ -209,6 +209,18 @@ exports[`returns expected CloudFormation stack for dev 1`] = `
209
209
  ],
210
210
  },
211
211
  "Layers": [
212
+ {
213
+ "Fn::Join": [
214
+ "",
215
+ [
216
+ "arn:aws:lambda:",
217
+ {
218
+ "Ref": "AWS::Region",
219
+ },
220
+ ":464622532012:layer:Datadog-Node22-x:x",
221
+ ],
222
+ ],
223
+ },
212
224
  {
213
225
  "Fn::Join": [
214
226
  "",
@@ -222,7 +234,8 @@ exports[`returns expected CloudFormation stack for dev 1`] = `
222
234
  ],
223
235
  },
224
236
  ],
225
- "ReservedConcurrentExecutions": 2,
237
+ "MemorySize": 512,
238
+ "ReservedConcurrentExecutions": 3,
226
239
  "Role": {
227
240
  "Fn::GetAtt": [
228
241
  "workerServiceRole2130CC7F",
@@ -332,6 +345,7 @@ exports[`returns expected CloudFormation stack for dev 1`] = `
332
345
  },
333
346
  "workerAliasLiveSqsEventSourceappStackworkerqueue8281B9F443B0CF93": {
334
347
  "Properties": {
348
+ "BatchSize": 10,
335
349
  "EventSourceArn": {
336
350
  "Fn::GetAtt": [
337
351
  "workerqueueA05CE5C6",
@@ -359,6 +373,12 @@ exports[`returns expected CloudFormation stack for dev 1`] = `
359
373
  ],
360
374
  ],
361
375
  },
376
+ "FunctionResponseTypes": [
377
+ "ReportBatchItemFailures",
378
+ ],
379
+ "ScalingConfig": {
380
+ "MaximumConcurrency": 2,
381
+ },
362
382
  "Tags": [
363
383
  {
364
384
  "Key": "aws-codedeploy-hooks",
@@ -743,14 +763,6 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
743
763
  },
744
764
  },
745
765
  "Resources": {
746
- "datadogapikeysecret046FEF06": {
747
- "DeletionPolicy": "Delete",
748
- "Properties": {
749
- "GenerateSecretString": {},
750
- },
751
- "Type": "AWS::SecretsManager::Secret",
752
- "UpdateReplacePolicy": "Delete",
753
- },
754
766
  "destinationtopicDCE2E0B8": {
755
767
  "Properties": {
756
768
  "KmsMasterKeyId": {
@@ -906,35 +918,33 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
906
918
  },
907
919
  "S3Key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.zip",
908
920
  },
909
- "Description": "Updated at 1212-12-12T12:12:12.121Z",
910
921
  "Environment": {
911
922
  "Variables": {
912
- "DD_API_KEY_SECRET_ARN": {
913
- "Ref": "datadogapikeysecret046FEF06",
914
- },
923
+ "DD_API_KEY_SECRET_ARN": "arn:aws:secretsmanager:<Region>:<AccountId>:secret:TODO_SECRET_NAME",
915
924
  "DD_CAPTURE_LAMBDA_PAYLOAD": "false",
925
+ "DD_ENV": "production",
916
926
  "DD_FLUSH_TO_LOG": "false",
917
927
  "DD_LAMBDA_HANDLER": "index.handler",
918
928
  "DD_LOGS_INJECTION": "false",
919
929
  "DD_MERGE_XRAY_TRACES": "false",
920
930
  "DD_SERVERLESS_APPSEC_ENABLED": "false",
921
931
  "DD_SERVERLESS_LOGS_ENABLED": "false",
932
+ "DD_SERVICE": "serviceName",
922
933
  "DD_SITE": "datadoghq.com",
923
934
  "DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING": "$.*",
924
935
  "DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING": "$.*",
925
936
  "DD_TRACE_ENABLED": "true",
937
+ "DD_VERSION": "local",
938
+ "DEPLOYMENT": "prod",
926
939
  "DESTINATION_SNS_TOPIC_ARN": {
927
940
  "Ref": "destinationtopicDCE2E0B8",
928
941
  },
929
- "ENVIRONMENT": "prod",
930
942
  "NODE_ENV": "production",
931
943
  "NODE_OPTIONS": "--enable-source-maps",
932
- "SERVICE": "serviceName",
933
- "VERSION": "local",
934
944
  },
935
945
  },
936
946
  "FunctionName": "serviceName",
937
- "Handler": "node_modules/datadog-lambda-js/dist/handler.handler",
947
+ "Handler": "/opt/nodejs/node_modules/datadog-lambda-js/handler.handler",
938
948
  "KmsKeyArn": {
939
949
  "Fn::GetAtt": [
940
950
  "kmskey49FBC3B3",
@@ -942,6 +952,18 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
942
952
  ],
943
953
  },
944
954
  "Layers": [
955
+ {
956
+ "Fn::Join": [
957
+ "",
958
+ [
959
+ "arn:aws:lambda:",
960
+ {
961
+ "Ref": "AWS::Region",
962
+ },
963
+ ":464622532012:layer:Datadog-Node22-x:x",
964
+ ],
965
+ ],
966
+ },
945
967
  {
946
968
  "Fn::Join": [
947
969
  "",
@@ -955,6 +977,7 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
955
977
  ],
956
978
  },
957
979
  ],
980
+ "MemorySize": 512,
958
981
  "ReservedConcurrentExecutions": 20,
959
982
  "Role": {
960
983
  "Fn::GetAtt": [
@@ -1065,6 +1088,7 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
1065
1088
  },
1066
1089
  "workerAliasLiveSqsEventSourceappStackworkerqueue8281B9F443B0CF93": {
1067
1090
  "Properties": {
1091
+ "BatchSize": 10,
1068
1092
  "EventSourceArn": {
1069
1093
  "Fn::GetAtt": [
1070
1094
  "workerqueueA05CE5C6",
@@ -1092,6 +1116,12 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
1092
1116
  ],
1093
1117
  ],
1094
1118
  },
1119
+ "FunctionResponseTypes": [
1120
+ "ReportBatchItemFailures",
1121
+ ],
1122
+ "ScalingConfig": {
1123
+ "MaximumConcurrency": 19,
1124
+ },
1095
1125
  "Tags": [
1096
1126
  {
1097
1127
  "Key": "aws-codedeploy-hooks",
@@ -1354,9 +1384,7 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
1354
1384
  "secretsmanager:DescribeSecret",
1355
1385
  ],
1356
1386
  "Effect": "Allow",
1357
- "Resource": {
1358
- "Ref": "datadogapikeysecret046FEF06",
1359
- },
1387
+ "Resource": "arn:aws:secretsmanager:<Region>:<AccountId>:secret:TODO_SECRET_NAME-??????",
1360
1388
  },
1361
1389
  {
1362
1390
  "Action": [
@@ -1,25 +1,11 @@
1
1
  import { App, aws_secretsmanager, aws_sns } from 'aws-cdk-lib';
2
2
  import { Template } from 'aws-cdk-lib/assertions';
3
3
 
4
- const currentDate = '1212-12-12T12:12:12.121Z';
5
-
6
- jest.useFakeTimers({
7
- legacyFakeTimers: false,
8
- doNotFake: [
9
- 'nextTick',
10
- 'setInterval',
11
- 'clearInterval',
12
- 'setTimeout',
13
- 'clearTimeout',
14
- ],
15
- now: new Date(currentDate),
16
- });
17
-
18
- const originalEnv = process.env.ENVIRONMENT;
4
+ const originalDeployment = process.env.DEPLOYMENT;
19
5
  const originalVersion = process.env.VERSION;
20
6
 
21
7
  afterAll(() => {
22
- process.env.ENVIRONMENT = originalEnv;
8
+ process.env.DEPLOYMENT = originalDeployment;
23
9
  process.env.VERSION = originalVersion;
24
10
  });
25
11
 
@@ -29,8 +15,8 @@ afterEach(() => {
29
15
 
30
16
  it.each(['dev', 'prod'])(
31
17
  'returns expected CloudFormation stack for %s',
32
- async (env) => {
33
- process.env.ENVIRONMENT = env;
18
+ async (deployment) => {
19
+ process.env.DEPLOYMENT = deployment;
34
20
  process.env.VERSION = 'local';
35
21
 
36
22
  const { AppStack } = await import('./appStack.js');
@@ -69,10 +55,7 @@ it.each(['dev', 'prod'])(
69
55
  /"DD_TAGS":"git.commit.sha:([0-9a-f]+),git.repository_url:([^\"]+)",/g,
70
56
  '',
71
57
  )
72
- .replaceAll(
73
- /(layer:Datadog-Extension-.+?:)\d+/g,
74
- (_, layer) => `${layer}x`,
75
- );
58
+ .replaceAll(/(layer:Datadog-[^-]+-.+?:)\d+/g, (_, layer) => `${layer}x`);
76
59
  expect(JSON.parse(json)).toMatchSnapshot();
77
60
  },
78
61
  );
@@ -19,7 +19,10 @@ import { DatadogLambda } from 'datadog-cdk-constructs-v2';
19
19
  import { config } from './config.js';
20
20
 
21
21
  // Updated by https://github.com/seek-oss/rynovate
22
- const DATADOG_EXTENSION_LAYER_VERSION = 64;
22
+ const DATADOG_EXTENSION_LAYER_VERSION = 86;
23
+
24
+ // Updated by https://github.com/seek-oss/rynovate
25
+ const DATADOG_NODE_LAYER_VERSION = 126;
23
26
 
24
27
  export class AppStack extends Stack {
25
28
  constructor(scope: Construct, id: string, props?: StackProps) {
@@ -84,6 +87,7 @@ export class AppStack extends Stack {
84
87
  const worker = new aws_lambda_nodejs.NodejsFunction(this, 'worker', {
85
88
  architecture: aws_lambda.Architecture[architecture],
86
89
  runtime: aws_lambda.Runtime.NODEJS_22_X,
90
+ memorySize: 512,
87
91
  environmentEncryption: kmsKey,
88
92
  // aws-sdk-v3 sets this to true by default, so it is not necessary to set the environment variable
89
93
  // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html
@@ -95,7 +99,6 @@ export class AppStack extends Stack {
95
99
  target: 'node22',
96
100
  // aws-sdk-v3 is set as an external module by default, but we want it to be bundled with the function
97
101
  externalModules: [],
98
- nodeModules: ['datadog-lambda-js', 'dd-trace'],
99
102
  },
100
103
  functionName: '<%- serviceName %>',
101
104
  environment: {
@@ -111,10 +114,6 @@ export class AppStack extends Stack {
111
114
  }
112
115
  : {}),
113
116
  },
114
- // https://github.com/aws/aws-cdk/issues/28237
115
- // This forces the lambda to be updated on every deployment
116
- // If you do not wish to use hotswap, you can remove the new Date().toISOString() from the description
117
- description: `Updated at ${new Date().toISOString()}`,
118
117
  reservedConcurrentExecutions: config.workerLambda.reservedConcurrency,
119
118
  });
120
119
 
@@ -127,11 +126,15 @@ export class AppStack extends Stack {
127
126
  );
128
127
 
129
128
  const datadog = new DatadogLambda(this, 'datadog', {
129
+ env: config.env,
130
+ service: config.service,
131
+ version: config.version,
132
+
130
133
  apiKeySecret: datadogSecret,
131
- addLayers: false,
132
134
  enableDatadogLogs: false,
133
- flushMetricsToLogs: false,
134
135
  extensionLayerVersion: DATADOG_EXTENSION_LAYER_VERSION,
136
+ flushMetricsToLogs: false,
137
+ nodeLayerVersion: DATADOG_NODE_LAYER_VERSION,
135
138
  });
136
139
 
137
140
  datadog.addLambdaFunctions([worker]);
@@ -141,7 +144,11 @@ export class AppStack extends Stack {
141
144
  });
142
145
 
143
146
  workerDeployment.alias.addEventSource(
144
- new aws_lambda_event_sources.SqsEventSource(queue),
147
+ new aws_lambda_event_sources.SqsEventSource(queue, {
148
+ batchSize: config.workerLambda.batchSize,
149
+ maxConcurrency: config.workerLambda.reservedConcurrency - 1, // Ensure we have capacity reserved for our blue/green deployment
150
+ reportBatchItemFailures: true,
151
+ }),
145
152
  );
146
153
  }
147
154
  }
@@ -1,52 +1,66 @@
1
1
  import { Env } from 'skuba-dive';
2
2
 
3
- const ENVIRONMENTS = ['dev', 'prod'] as const;
3
+ type Deployment = (typeof deployments)[number];
4
4
 
5
- type Environment = (typeof ENVIRONMENTS)[number];
5
+ const deployments = ['dev', 'prod'] as const;
6
6
 
7
- const environment = Env.oneOf(ENVIRONMENTS)('ENVIRONMENT');
7
+ const deployment = Env.oneOf(deployments)('DEPLOYMENT');
8
8
 
9
9
  interface Config {
10
- appName: string;
10
+ env: 'development' | 'production';
11
+ service: string;
12
+ version: string;
13
+
11
14
  workerLambda: {
15
+ batchSize: number;
12
16
  reservedConcurrency: number;
13
17
  environment: {
14
- ENVIRONMENT: Environment;
15
- SERVICE: string;
16
- VERSION: string;
18
+ DEPLOYMENT: Deployment;
17
19
  };
18
20
  };
21
+
19
22
  datadogApiKeySecretArn: string;
20
23
  sourceSnsTopicArn: string;
21
24
  }
22
25
 
23
- const configs: Record<Environment, Config> = {
26
+ const service = '<%- serviceName %>';
27
+ const version = Env.string('VERSION');
28
+
29
+ const configs: Record<Deployment, Config> = {
24
30
  dev: {
25
- appName: '<%- serviceName %>',
31
+ env: 'development',
32
+ service,
33
+ version,
34
+
26
35
  workerLambda: {
27
- reservedConcurrency: 2,
36
+ batchSize: 10,
37
+ reservedConcurrency: 3,
28
38
  environment: {
29
- ENVIRONMENT: 'dev',
30
- SERVICE: '<%- serviceName %>',
31
- VERSION: Env.string('VERSION', { default: 'local' }),
39
+ DEPLOYMENT: 'dev',
32
40
  },
33
41
  },
34
- datadogApiKeySecretArn: 'TODO: datadogApiKeySecretArn',
42
+
43
+ datadogApiKeySecretArn:
44
+ 'arn:aws:secretsmanager:<Region>:<AccountId>:secret:TODO_SECRET_NAME',
35
45
  sourceSnsTopicArn: 'TODO: sourceSnsTopicArn',
36
46
  },
37
47
  prod: {
38
- appName: '<%- serviceName %>',
48
+ env: 'production',
49
+ service,
50
+ version,
51
+
39
52
  workerLambda: {
53
+ batchSize: 10,
40
54
  reservedConcurrency: 20,
41
55
  environment: {
42
- ENVIRONMENT: 'prod',
43
- SERVICE: '<%- serviceName %>',
44
- VERSION: Env.string('VERSION', { default: 'local' }),
56
+ DEPLOYMENT: 'prod',
45
57
  },
46
58
  },
47
- datadogApiKeySecretArn: 'TODO: datadogApiKeySecretArn',
59
+
60
+ datadogApiKeySecretArn:
61
+ 'arn:aws:secretsmanager:<Region>:<AccountId>:secret:TODO_SECRET_NAME',
48
62
  sourceSnsTopicArn: 'TODO: sourceSnsTopicArn',
49
63
  },
50
64
  };
51
65
 
52
- export const config: Config = configs[environment];
66
+ export const config: Config = configs[deployment];
@@ -7,7 +7,7 @@ import { config } from './config.js';
7
7
  const app = new App();
8
8
 
9
9
  const appStack = new AppStack(app, 'appStack', {
10
- stackName: config.appName,
10
+ stackName: config.service,
11
11
  tags: {
12
12
  'seek:source:url': 'https://github.com/SEEK-Jobs/<%- repoName %>',
13
13
  // 'seek:system:name': 'TODO: https://rfc.skinfra.xyz/RFC051-AWS-Tagging-Standard.html#tagging-schema',
@@ -10,8 +10,6 @@
10
10
  },
11
11
  "scripts": {
12
12
  "deploy": "cdk deploy appStack --require-approval never",
13
- "deploy:hotswap": "pnpm --silent run deploy --hotswap",
14
- "deploy:watch": "pnpm --silent deploy:hotswap --watch",
15
13
  "format": "skuba format",
16
14
  "lint": "skuba lint",
17
15
  "start": "skuba start --port <%- port %>",
@@ -24,11 +22,9 @@
24
22
  "@aws-sdk/client-lambda": "^3.363.0",
25
23
  "@aws-sdk/client-sns": "^3.363.0",
26
24
  "@seek/aws-codedeploy-hooks": "^2.0.0",
27
- "@seek/logger": "^10.0.0",
28
- "datadog-lambda-js": "^10.0.0",
29
- "dd-trace": "^5.0.0",
25
+ "@seek/logger": "^11.1.0",
30
26
  "skuba-dive": "^2.0.0",
31
- "zod": "^3.25.67"
27
+ "zod": "^4.0.0"
32
28
  },
33
29
  "devDependencies": {
34
30
  "@seek/aws-codedeploy-infra": "^3.0.0",
@@ -41,11 +37,13 @@
41
37
  "aws-sdk-client-mock-jest": "^4.0.0",
42
38
  "chance": "^1.1.8",
43
39
  "constructs": "^10.0.17",
44
- "datadog-cdk-constructs-v2": "^2.0.0",
40
+ "datadog-cdk-constructs-v2": "^3.0.0",
41
+ "datadog-lambda-js": "^12.0.0",
42
+ "dd-trace": "^5.0.0",
45
43
  "pino-pretty": "^13.0.0",
46
- "skuba": "13.0.0-custom-conditions-exports-20250730235248"
44
+ "skuba": "13.0.0-custom-conditions-exports-20250923005538"
47
45
  },
48
- "packageManager": "pnpm@10.12.4",
46
+ "packageManager": "pnpm@10.15.1",
49
47
  "engines": {
50
48
  "node": ">=22"
51
49
  }
@@ -1,4 +1,5 @@
1
1
  import { PublishCommand } from '@aws-sdk/client-sns';
2
+ import type { SQSBatchResponse } from 'aws-lambda';
2
3
 
3
4
  import * as app from './app.js';
4
5
  import { stdoutMock } from './framework/logging.js';
@@ -40,42 +41,100 @@ describe('handler', () => {
40
41
  it('handles one record', async () => {
41
42
  const event = createSqsEvent([JSON.stringify(jobPublished)]);
42
43
 
43
- await expect(app.handler(event, ctx)).resolves.toBeUndefined();
44
+ await expect(app.handler(event, ctx)).resolves.toEqual<SQSBatchResponse>({
45
+ batchItemFailures: [],
46
+ });
44
47
 
45
48
  expect(scoringService.request).toHaveBeenCalledTimes(1);
46
49
 
47
50
  expect(stdoutMock.calls).toMatchObject([
51
+ { count: 1, level: 20, msg: 'Received jobs' },
48
52
  {
49
- awsRequestId: '-',
50
- count: 1,
51
53
  level: 20,
52
- msg: 'Received jobs',
54
+ msg: 'Scored job',
55
+ snsMessageId: expect.any(String),
56
+ sqsMessageId: event.Records[0]!.messageId,
53
57
  },
58
+ { level: 20, msg: 'Function completed' },
59
+ ]);
60
+
61
+ expect(distribution.mock.calls).toEqual([
62
+ ['job.received', 1],
63
+ ['job.scored', 1],
64
+ ]);
65
+
66
+ expect(sns.client).toReceiveCommandTimes(PublishCommand, 1);
67
+ });
68
+
69
+ it('handles multiple records', async () => {
70
+ const event = createSqsEvent([
71
+ JSON.stringify(jobPublished),
72
+ JSON.stringify(jobPublished),
73
+ ]);
74
+
75
+ await expect(app.handler(event, ctx)).resolves.toEqual<SQSBatchResponse>({
76
+ batchItemFailures: [],
77
+ });
78
+
79
+ expect(stdoutMock.calls).toMatchObject([
80
+ { count: 2, level: 20, msg: 'Received jobs' },
54
81
  {
55
- awsRequestId: '-',
56
82
  level: 20,
57
83
  msg: 'Scored job',
58
84
  snsMessageId: expect.any(String),
85
+ sqsMessageId: event.Records[0]!.messageId,
59
86
  },
60
87
  {
61
- awsRequestId: '-',
62
88
  level: 20,
63
- msg: 'Function succeeded',
89
+ msg: 'Scored job',
90
+ snsMessageId: expect.any(String),
91
+ sqsMessageId: event.Records[1]!.messageId,
64
92
  },
93
+ { level: 20, msg: 'Function completed' },
65
94
  ]);
95
+ });
66
96
 
67
- expect(distribution.mock.calls).toEqual([
68
- ['job.received', 1],
69
- ['job.scored', 1],
97
+ it('handles partial batch failure', async () => {
98
+ const event = createSqsEvent([
99
+ JSON.stringify('}'),
100
+ JSON.stringify(jobPublished),
70
101
  ]);
71
102
 
72
- expect(sns.client).toReceiveCommandTimes(PublishCommand, 1);
103
+ await expect(app.handler(event, ctx)).resolves.toEqual<SQSBatchResponse>({
104
+ batchItemFailures: [{ itemIdentifier: event.Records[0]!.messageId }],
105
+ });
106
+
107
+ expect(stdoutMock.calls).toMatchObject([
108
+ { count: 2, level: 20, msg: 'Received jobs' },
109
+ {
110
+ error: {
111
+ name: 'ZodError',
112
+ type: 'ZodError',
113
+ },
114
+ level: 50,
115
+ msg: 'Processing record failed',
116
+ sqsMessageId: event.Records[0]!.messageId,
117
+ },
118
+ {
119
+ level: 20,
120
+ msg: 'Scored job',
121
+ snsMessageId: expect.any(String),
122
+ sqsMessageId: event.Records[1]!.messageId,
123
+ },
124
+ { level: 20, msg: 'Function completed' },
125
+ ]);
73
126
  });
74
127
 
75
- it('throws on invalid input', () => {
128
+ it('returns a batchItemFailure on invalid input', () => {
76
129
  const event = createSqsEvent(['}']);
77
130
 
78
- return expect(app.handler(event, ctx)).rejects.toThrow('Function failed');
131
+ return expect(app.handler(event, ctx)).resolves.toEqual<SQSBatchResponse>({
132
+ batchItemFailures: [
133
+ {
134
+ itemIdentifier: event.Records[0]!.messageId,
135
+ },
136
+ ],
137
+ });
79
138
  });
80
139
 
81
140
  it('bubbles up scoring service error', async () => {
@@ -85,24 +144,22 @@ describe('handler', () => {
85
144
 
86
145
  const event = createSqsEvent([JSON.stringify(jobPublished)]);
87
146
 
88
- await expect(app.handler(event, ctx)).rejects.toThrow('Function failed');
147
+ await expect(app.handler(event, ctx)).resolves.toEqual<SQSBatchResponse>({
148
+ batchItemFailures: [{ itemIdentifier: event.Records[0]!.messageId }],
149
+ });
89
150
 
90
151
  expect(stdoutMock.calls).toMatchObject([
152
+ { count: 1, level: 20, msg: 'Received jobs' },
91
153
  {
92
- awsRequestId: '-',
93
- count: 1,
94
- level: 20,
95
- msg: 'Received jobs',
96
- },
97
- {
98
- awsRequestId: '-',
99
- err: {
154
+ error: {
100
155
  message: err.message,
101
156
  type: 'Error',
102
157
  },
103
158
  level: 50,
104
- msg: 'Function failed',
159
+ msg: 'Processing record failed',
160
+ sqsMessageId: event.Records[0]!.messageId,
105
161
  },
162
+ { level: 20, msg: 'Function completed' },
106
163
  ]);
107
164
  });
108
165
 
@@ -113,23 +170,28 @@ describe('handler', () => {
113
170
 
114
171
  const event = createSqsEvent([JSON.stringify(jobPublished)]);
115
172
 
116
- await expect(app.handler(event, ctx)).rejects.toThrow('Function failed');
173
+ await expect(app.handler(event, ctx)).resolves.toEqual<SQSBatchResponse>({
174
+ batchItemFailures: [{ itemIdentifier: event.Records[0]!.messageId }],
175
+ });
117
176
 
118
177
  expect(stdoutMock.calls).toMatchObject([
119
178
  {
120
- awsRequestId: '-',
121
179
  count: 1,
122
180
  level: 20,
123
181
  msg: 'Received jobs',
124
182
  },
125
183
  {
126
- awsRequestId: '-',
127
- err: {
184
+ error: {
128
185
  message: err.message,
129
186
  type: 'Error',
130
187
  },
131
188
  level: 50,
132
- msg: 'Function failed',
189
+ msg: 'Processing record failed',
190
+ sqsMessageId: event.Records[0]!.messageId,
191
+ },
192
+ {
193
+ level: 20,
194
+ msg: 'Function completed',
133
195
  },
134
196
  ]);
135
197
  });
@@ -141,8 +203,7 @@ describe('handler', () => {
141
203
 
142
204
  expect(stdoutMock.calls).toMatchObject([
143
205
  {
144
- awsRequestId: '-',
145
- err: {
206
+ error: {
146
207
  message: 'Received 0 records',
147
208
  type: 'Error',
148
209
  },
@@ -151,25 +212,4 @@ describe('handler', () => {
151
212
  },
152
213
  ]);
153
214
  });
154
-
155
- it('throws on multiple records', async () => {
156
- const event = createSqsEvent([
157
- JSON.stringify(jobPublished),
158
- JSON.stringify(jobPublished),
159
- ]);
160
-
161
- await expect(app.handler(event, ctx)).rejects.toThrow('Function failed');
162
-
163
- expect(stdoutMock.calls).toMatchObject([
164
- {
165
- awsRequestId: '-',
166
- err: {
167
- message: 'Received 2 records',
168
- type: 'Error',
169
- },
170
- level: 50,
171
- msg: 'Function failed',
172
- },
173
- ]);
174
- });
175
215
  });