lambder 5.1.2 → 6.0.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 +8 -3
- package/dist/client/LambderCaller.d.ts +8 -83
- package/dist/client/LambderCaller.js +32 -64
- package/dist/client/LambderMSW.js +4 -4
- package/dist/client.d.ts +5 -3
- package/dist/client.js +3 -1
- package/dist/core/Lambder.d.ts +2 -2
- package/dist/core/Lambder.js +10 -3
- package/dist/core/LambderContext.d.ts +6 -5
- package/dist/core/LambderContext.js +20 -12
- package/dist/core/LambderResolver.d.ts +7 -5
- package/dist/core/LambderResolver.js +7 -3
- package/dist/core/LambderResponseBuilder.d.ts +17 -3
- package/dist/core/LambderResponseBuilder.js +2 -2
- package/dist/index.d.ts +10 -6
- package/dist/index.js +6 -2
- package/dist/invoke/LambderInvokeCaller.d.ts +322 -0
- package/dist/invoke/LambderInvokeCaller.js +654 -0
- package/dist/policies/LambderApiGuards.d.ts +8 -8
- package/dist/policies/LambderApiRateLimits.d.ts +3 -3
- package/dist/session/LambderSessionManager.d.ts +5 -1
- package/dist/session/LambderSessionManager.js +26 -13
- package/dist/shared/LambderApiContract.d.ts +9 -0
- package/dist/shared/LambderApiOutcome.d.ts +69 -0
- package/dist/shared/LambderApiOutcome.js +79 -0
- package/dist/shared/LambderCallOptions.d.ts +71 -0
- package/dist/shared/LambderCallOptions.js +16 -0
- package/dist/shared/LambderCompressionCodec.d.ts +45 -8
- package/dist/shared/LambderCompressionCodec.js +44 -14
- package/dist/shared/LambderCrashDetail.d.ts +48 -0
- package/dist/shared/LambderCrashDetail.js +78 -0
- package/dist/shared/LambderRequestPayload.d.ts +46 -23
- package/dist/shared/LambderRequestPayload.js +47 -31
- package/dist/stores/LambderDdbCache.d.ts +7 -2
- package/dist/stores/LambderDdbCache.js +30 -12
- package/dist/stores/LambderDdbIdempotency.d.ts +7 -2
- package/dist/stores/LambderDdbIdempotency.js +26 -10
- package/dist/stores/LambderDdbRateLimiter.d.ts +7 -2
- package/dist/stores/LambderDdbRateLimiter.js +16 -4
- package/dist/stores/LambderDdbSdk.d.ts +20 -0
- package/dist/stores/LambderDdbSdk.js +31 -0
- package/package.json +8 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadDynamoClientSdk } from "./LambderDdbSdk.js";
|
|
2
2
|
/**
|
|
3
3
|
* The fixed windows a policy may cap, smallest first (the evaluation order),
|
|
4
4
|
* with their length. The policy type derives from this table, so the two can
|
|
@@ -32,7 +32,10 @@ export const RATE_LIMIT_WINDOWS = [
|
|
|
32
32
|
export class LambderDdbRateLimiter {
|
|
33
33
|
tableName;
|
|
34
34
|
keyPrefix;
|
|
35
|
-
client;
|
|
35
|
+
/** The client given at creation, or one created from `region` on first use; the SDK arrives with it. */
|
|
36
|
+
providedClient;
|
|
37
|
+
region;
|
|
38
|
+
readyPromise;
|
|
36
39
|
ttlWindowMultiplier;
|
|
37
40
|
failOpen;
|
|
38
41
|
constructor(options) {
|
|
@@ -45,7 +48,15 @@ export class LambderDdbRateLimiter {
|
|
|
45
48
|
throw new Error("ttlWindowMultiplier must be a number greater than or equal to 1");
|
|
46
49
|
}
|
|
47
50
|
this.failOpen = options.failOpen ?? false;
|
|
48
|
-
this.
|
|
51
|
+
this.providedClient = options.client;
|
|
52
|
+
this.region = options.region;
|
|
53
|
+
}
|
|
54
|
+
/** The SDK and the client, loaded and created the first time the table is touched (see LambderDdbSdk). */
|
|
55
|
+
ready() {
|
|
56
|
+
this.readyPromise ??= loadDynamoClientSdk("LambderDdbRateLimiter")
|
|
57
|
+
.then((sdk) => ({ sdk, client: this.providedClient ?? new sdk.DynamoDBClient(this.region ? { region: this.region } : {}) }))
|
|
58
|
+
.catch((error) => { this.readyPromise = undefined; throw error; });
|
|
59
|
+
return this.readyPromise;
|
|
49
60
|
}
|
|
50
61
|
/**
|
|
51
62
|
* Increment every configured window for `trackerKey` (IP, session, user id, ...)
|
|
@@ -84,7 +95,8 @@ export class LambderDdbRateLimiter {
|
|
|
84
95
|
},
|
|
85
96
|
};
|
|
86
97
|
try {
|
|
87
|
-
await this.
|
|
98
|
+
const { client, sdk } = await this.ready();
|
|
99
|
+
await client.send(new sdk.UpdateItemCommand(input));
|
|
88
100
|
return false;
|
|
89
101
|
}
|
|
90
102
|
catch (error) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DynamoDB SDK, loaded on first use.
|
|
3
|
+
*
|
|
4
|
+
* `@aws-sdk/client-dynamodb` and `@aws-sdk/lib-dynamodb` are optional peer
|
|
5
|
+
* dependencies, and an app that keeps no sessions and uses none of the
|
|
6
|
+
* DynamoDB stores should neither install them nor pay for loading them: a
|
|
7
|
+
* module-level import costs every cold start something and, bundled, makes
|
|
8
|
+
* every Lambder app reference both packages. So the session manager and the
|
|
9
|
+
* three stores import their types only and take the classes from here the
|
|
10
|
+
* first time they touch the table, the way LambderS3FileSource and
|
|
11
|
+
* LambderInvokeCaller load theirs. One loader per package, memoized for the
|
|
12
|
+
* container's life; a missing package fails that first call with the
|
|
13
|
+
* install hint rather than failing the import of lambder itself.
|
|
14
|
+
*/
|
|
15
|
+
export type LambderDynamoClientSdk = typeof import("@aws-sdk/client-dynamodb");
|
|
16
|
+
export type LambderDynamoDocumentSdk = typeof import("@aws-sdk/lib-dynamodb");
|
|
17
|
+
/** `@aws-sdk/client-dynamodb`, for the item-level API the stores speak and the client the session manager wraps. */
|
|
18
|
+
export declare const loadDynamoClientSdk: (user: string) => Promise<LambderDynamoClientSdk>;
|
|
19
|
+
/** `@aws-sdk/lib-dynamodb`, the document client the session manager reads and writes through. */
|
|
20
|
+
export declare const loadDynamoDocumentSdk: (user: string) => Promise<LambderDynamoDocumentSdk>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DynamoDB SDK, loaded on first use.
|
|
3
|
+
*
|
|
4
|
+
* `@aws-sdk/client-dynamodb` and `@aws-sdk/lib-dynamodb` are optional peer
|
|
5
|
+
* dependencies, and an app that keeps no sessions and uses none of the
|
|
6
|
+
* DynamoDB stores should neither install them nor pay for loading them: a
|
|
7
|
+
* module-level import costs every cold start something and, bundled, makes
|
|
8
|
+
* every Lambder app reference both packages. So the session manager and the
|
|
9
|
+
* three stores import their types only and take the classes from here the
|
|
10
|
+
* first time they touch the table, the way LambderS3FileSource and
|
|
11
|
+
* LambderInvokeCaller load theirs. One loader per package, memoized for the
|
|
12
|
+
* container's life; a missing package fails that first call with the
|
|
13
|
+
* install hint rather than failing the import of lambder itself.
|
|
14
|
+
*/
|
|
15
|
+
let clientSdk;
|
|
16
|
+
let documentSdk;
|
|
17
|
+
const withInstallHint = (loading, packageName, user, reset) => loading.catch((cause) => {
|
|
18
|
+
// Not memoized: the package may be installed later in the same process (tests), and the next caller names itself.
|
|
19
|
+
reset();
|
|
20
|
+
throw new Error(`${user} requires ${packageName}: npm install ${packageName}`, { cause });
|
|
21
|
+
});
|
|
22
|
+
/** `@aws-sdk/client-dynamodb`, for the item-level API the stores speak and the client the session manager wraps. */
|
|
23
|
+
export const loadDynamoClientSdk = (user) => {
|
|
24
|
+
clientSdk ??= withInstallHint(import("@aws-sdk/client-dynamodb"), "@aws-sdk/client-dynamodb", user, () => { clientSdk = undefined; });
|
|
25
|
+
return clientSdk;
|
|
26
|
+
};
|
|
27
|
+
/** `@aws-sdk/lib-dynamodb`, the document client the session manager reads and writes through. */
|
|
28
|
+
export const loadDynamoDocumentSdk = (user) => {
|
|
29
|
+
documentSdk ??= withInstallHint(import("@aws-sdk/lib-dynamodb"), "@aws-sdk/lib-dynamodb", user, () => { documentSdk = undefined; });
|
|
30
|
+
return documentSdk;
|
|
31
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lambder",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "Opinionated serverless web framework for TypeScript on AWS Lambda: type-safe APIs from Zod schemas, DynamoDB sessions, and declarative rate limits, authorization guards and idempotency.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lambda",
|
|
@@ -87,15 +87,19 @@
|
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"@aws-sdk/client-dynamodb": "^3.574.0",
|
|
90
|
+
"@aws-sdk/client-lambda": "^3.574.0",
|
|
90
91
|
"@aws-sdk/client-s3": "^3.574.0",
|
|
91
92
|
"@aws-sdk/lib-dynamodb": "^3.574.0",
|
|
92
93
|
"msw": "^2.0.0",
|
|
93
|
-
"zod": "^4.
|
|
94
|
+
"zod": "^4.6.2"
|
|
94
95
|
},
|
|
95
96
|
"peerDependenciesMeta": {
|
|
96
97
|
"@aws-sdk/client-dynamodb": {
|
|
97
98
|
"optional": true
|
|
98
99
|
},
|
|
100
|
+
"@aws-sdk/client-lambda": {
|
|
101
|
+
"optional": true
|
|
102
|
+
},
|
|
99
103
|
"@aws-sdk/client-s3": {
|
|
100
104
|
"optional": true
|
|
101
105
|
},
|
|
@@ -111,6 +115,7 @@
|
|
|
111
115
|
},
|
|
112
116
|
"devDependencies": {
|
|
113
117
|
"@aws-sdk/client-dynamodb": "^3.913.0",
|
|
118
|
+
"@aws-sdk/client-lambda": "^3.1131.0",
|
|
114
119
|
"@aws-sdk/client-s3": "^3.1127.0",
|
|
115
120
|
"@aws-sdk/lib-dynamodb": "^3.913.0",
|
|
116
121
|
"@types/aws-lambda": "^8.10.136",
|
|
@@ -125,6 +130,6 @@
|
|
|
125
130
|
"eslint": "^8.57.0",
|
|
126
131
|
"typescript": "^5.9.3",
|
|
127
132
|
"vitest": "^3.2.4",
|
|
128
|
-
"zod": "^4.
|
|
133
|
+
"zod": "^4.6.2"
|
|
129
134
|
}
|
|
130
135
|
}
|