@bifravst/aws-cdk-lambda-helpers 3.2.0 → 3.3.1

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/README.md CHANGED
@@ -17,6 +17,14 @@ Helper functions which simplify working with TypeScript lambdas for AWS CDK.
17
17
 
18
18
  See [the end-to-end test stack](./cdk/e2e.ts).
19
19
 
20
+ ## `updateLambdaCode()` helper
21
+
22
+ [`updateLambdaCode()`](./src/updateLambdaCode.ts) is a helper that will update
23
+ the function code of a lambda directly without a CloudFormation deployment,
24
+ which is many times faster. This is useful during development.
25
+
26
+ See [this example](./cdk/update-lambdas.ts) on how to use it.
27
+
20
28
  ## Example migrations to `@bifravst/aws-cdk-lambda-helpers`
21
29
 
22
30
  - [world.thingy.rocks backend](https://github.com/NordicPlayground/thingy-rocks-cloud-aws-js/commit/3ca6e267917db4d8cb09ca63ed54384c0e23f163)
@@ -0,0 +1,7 @@
1
+ import { type CloudFormationClient } from '@aws-sdk/client-cloudformation';
2
+ import { type LambdaClient } from '@aws-sdk/client-lambda';
3
+ import type { PackedLambda } from './packLambda.ts';
4
+ export declare const updateLambdaCode: ({ cf, lambda }: {
5
+ cf: CloudFormationClient;
6
+ lambda: LambdaClient;
7
+ }) => (stackName: string, packedLambdas: Record<string, PackedLambda>, debug?: (...args: Array<any>) => void) => Promise<void>;
@@ -0,0 +1,73 @@
1
+ import { paginateListStackResources } from '@aws-sdk/client-cloudformation';
2
+ import { GetFunctionCommand, LastUpdateStatus, TagResourceCommand, UpdateFunctionCodeCommand, UpdateFunctionConfigurationCommand } from '@aws-sdk/client-lambda';
3
+ import assert from 'node:assert';
4
+ import { readFile } from 'node:fs/promises';
5
+ import pRetry from 'p-retry';
6
+ const updateLambda = ({ lambda, packs, debug })=>async (lambdaResource)=>{
7
+ const info = await lambda.send(new GetFunctionCommand({
8
+ FunctionName: lambdaResource.PhysicalResourceId
9
+ }));
10
+ const packed = Object.values(packs).find((p)=>p.id === info.Tags?.['packedLambda:id']);
11
+ if (packed === undefined) {
12
+ debug?.(`[${info.Tags?.['packedLambda:id']}]`, 'No pack found for lambda');
13
+ return;
14
+ }
15
+ debug?.(`[${packed.id}]`, 'found pack');
16
+ if (packed.hash === info.Tags?.['packedLambda:hash']) {
17
+ debug?.(`[${packed.id}]`, 'No update needed');
18
+ return;
19
+ }
20
+ if (packed.hash !== info.Tags?.['packedLambda:hash']) {
21
+ debug?.(`[${packed.id}]`, 'Updating lambda');
22
+ }
23
+ const updateResult = await lambda.send(new UpdateFunctionCodeCommand({
24
+ FunctionName: lambdaResource.PhysicalResourceId,
25
+ ZipFile: new Uint8Array(await readFile(packed.zipFilePath))
26
+ }));
27
+ debug?.(`[${packed.id}]`, 'RevisionId', updateResult.RevisionId);
28
+ debug?.(`[${packed.id}]`, 'CodeSha256', updateResult.CodeSha256);
29
+ await pRetry(async ()=>{
30
+ const updateStatus = (await lambda.send(new GetFunctionCommand({
31
+ FunctionName: lambdaResource.PhysicalResourceId
32
+ }))).Configuration?.LastUpdateStatus;
33
+ assert.equal(updateStatus, LastUpdateStatus.Successful, `Lambda update should have succeeded, got ${updateStatus}`);
34
+ }, {
35
+ minTimeout: 1000,
36
+ maxTimeout: 1000,
37
+ retries: 10
38
+ });
39
+ debug?.(`[${packed.id}]`, `updating config to trigger reload ...`);
40
+ await Promise.all([
41
+ await lambda.send(new UpdateFunctionConfigurationCommand({
42
+ FunctionName: lambdaResource.PhysicalResourceId,
43
+ Environment: {
44
+ Variables: {
45
+ ...info.Configuration?.Environment?.Variables,
46
+ PACKED_LAMBDA_HASH: packed.hash
47
+ }
48
+ }
49
+ })),
50
+ await lambda.send(new TagResourceCommand({
51
+ Resource: info.Configuration.FunctionArn,
52
+ Tags: {
53
+ 'packedLambda:hash': packed.hash
54
+ }
55
+ }))
56
+ ]);
57
+ };
58
+ export const updateLambdaCode = ({ cf, lambda })=>async (stackName, packedLambdas, debug)=>{
59
+ const u = updateLambda({
60
+ lambda,
61
+ packs: packedLambdas,
62
+ debug
63
+ });
64
+ const p = [];
65
+ for await (const page of paginateListStackResources({
66
+ client: cf
67
+ }, {
68
+ StackName: stackName
69
+ })){
70
+ p.push(...(page.StackResourceSummaries ?? []).filter((resource)=>resource.ResourceType === 'AWS::Lambda::Function').map(u) ?? []);
71
+ }
72
+ await Promise.all(p);
73
+ };
@@ -2,3 +2,4 @@ export * from './checksumOfFiles.ts';
2
2
  export * from './commonParent.ts';
3
3
  export * from './findDependencies.ts';
4
4
  export * from './isTest.ts';
5
+ export * from './updateLambdaCode.ts';
package/dist/src/util.js CHANGED
@@ -2,3 +2,4 @@ export * from './checksumOfFiles.js';
2
2
  export * from './commonParent.js';
3
3
  export * from './findDependencies.js';
4
4
  export * from './isTest.js';
5
+ export * from './updateLambdaCode.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bifravst/aws-cdk-lambda-helpers",
3
- "version": "3.2.0",
3
+ "version": "3.3.1",
4
4
  "description": "Helper functions which simplify working with TypeScript lambdas for AWS CDK.",
5
5
  "exports": {
6
6
  ".": {
@@ -32,6 +32,7 @@
32
32
  "scripts": {
33
33
  "test": "node --experimental-strip-types --no-warnings --test ./src/*.spec.ts",
34
34
  "test:e2e": "node --experimental-strip-types --test e2e.spec.ts",
35
+ "test:e2e:updated": "node --experimental-strip-types --test e2e-updated.spec.ts",
35
36
  "prepare": "husky",
36
37
  "prepublishOnly": "node --experimental-strip-types npm-compile.ts && npx tsc -P tsconfig.npm.json --outDir ./dist/src"
37
38
  },
@@ -52,8 +53,8 @@
52
53
  "author": "Nordic Semiconductor ASA | nordicsemi.no",
53
54
  "license": "BSD-3-Clause",
54
55
  "devDependencies": {
55
- "@aws-sdk/client-cloudformation": "3.797.0",
56
- "@aws-sdk/client-dynamodb": "3.797.0",
56
+ "@aws-sdk/client-cloudformation": "3.798.0",
57
+ "@aws-sdk/client-dynamodb": "3.798.0",
57
58
  "@bifravst/cloudformation-helpers": "9.1.1",
58
59
  "@bifravst/eslint-config-typescript": "6.1.22",
59
60
  "@bifravst/from-env": "3.0.2",
@@ -61,7 +62,7 @@
61
62
  "@commitlint/config-conventional": "19.8.0",
62
63
  "@swc/cli": "0.7.3",
63
64
  "@types/aws-lambda": "8.10.149",
64
- "@types/node": "22.15.2",
65
+ "@types/node": "22.15.3",
65
66
  "@types/unzip-stream": "0.3.4",
66
67
  "@types/yazl": "2.4.6",
67
68
  "cdk": "2.1012.0",
@@ -115,10 +116,12 @@
115
116
  "@swc/core": "1.11.22",
116
117
  "fp-ts": "2.16.10",
117
118
  "glob": "11.0.2",
119
+ "p-retry": "6.2.1",
118
120
  "typescript": "5.8.3",
119
121
  "yazl": "3.3.1"
120
122
  },
121
123
  "peerDependencies": {
124
+ "@aws-sdk/client-lambda": "^3.798.0",
122
125
  "@bifravst/aws-ssm-settings-helpers": "^1.2.134",
123
126
  "aws-cdk-lib": "^2.192.0",
124
127
  "constructs": "^10.4.2"