lambder 7.3.1 → 8.0.2
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/CHANGELOG.md +933 -3
- package/README.md +41 -21
- package/dist/api/LambderApiAnswer.d.ts +18 -22
- package/dist/api/LambderApiAnswer.js +6 -7
- package/dist/api/LambderApiCallContext.d.ts +21 -8
- package/dist/api/LambderApiCallContext.js +22 -4
- package/dist/api/LambderApiDefinition.d.ts +4 -3
- package/dist/api/LambderApiEnvelope.d.ts +14 -9
- package/dist/api/LambderApiEnvelope.js +33 -34
- package/dist/api/LambderApiGuards.d.ts +78 -51
- package/dist/api/LambderApiGuards.js +34 -36
- package/dist/api/LambderApiIdempotency.d.ts +68 -62
- package/dist/api/LambderApiIdempotency.js +214 -151
- package/dist/api/LambderApiOutputValidationError.d.ts +32 -0
- package/dist/api/LambderApiOutputValidationError.js +50 -0
- package/dist/api/LambderApiPipeline.d.ts +47 -38
- package/dist/api/LambderApiPipeline.js +122 -63
- package/dist/api/LambderApiRateLimits.d.ts +201 -54
- package/dist/api/LambderApiRateLimits.js +185 -108
- package/dist/api/LambderApiRequest.d.ts +27 -21
- package/dist/api/LambderApiRequest.js +26 -19
- package/dist/api/LambderApiSignature.d.ts +12 -15
- package/dist/api/LambderApiSignature.js +28 -51
- package/dist/api/LambderApiValidationRefusal.d.ts +9 -9
- package/dist/api/LambderApiValidationRefusal.js +10 -10
- package/dist/build/freshProcessVerifier.d.ts +13 -0
- package/dist/build/freshProcessVerifier.js +19 -0
- package/dist/build/writeApiSignatures.d.ts +109 -0
- package/dist/build/writeApiSignatures.js +222 -0
- package/dist/build.d.ts +9 -0
- package/dist/build.js +8 -0
- package/dist/client/LambderCaller.d.ts +13 -44
- package/dist/client/LambderCaller.js +77 -84
- package/dist/client/LambderReloadLoopBreaker.d.ts +56 -26
- package/dist/client/LambderReloadLoopBreaker.js +90 -46
- package/dist/client/lambderFetchTransport.d.ts +4 -1
- package/dist/client/lambderFetchTransport.js +52 -28
- package/dist/client.d.ts +5 -3
- package/dist/client.js +2 -1
- package/dist/core/Lambder.d.ts +140 -75
- package/dist/core/Lambder.js +347 -227
- package/dist/core/LambderContext.d.ts +82 -15
- package/dist/core/LambderContext.js +107 -20
- package/dist/core/LambderCors.d.ts +21 -3
- package/dist/core/LambderCors.js +35 -16
- package/dist/core/LambderCrashHandling.d.ts +40 -0
- package/dist/core/LambderCrashHandling.js +97 -0
- package/dist/core/LambderCreateOptions.d.ts +151 -75
- package/dist/core/LambderCreateOptions.js +16 -23
- package/dist/core/LambderFiles.d.ts +21 -7
- package/dist/core/LambderFiles.js +62 -34
- package/dist/core/LambderIndexHtml.js +12 -11
- package/dist/core/LambderPolicyBuilders.d.ts +17 -5
- package/dist/core/LambderPolicyBuilders.js +17 -5
- package/dist/core/LambderPublicFiles.d.ts +11 -5
- package/dist/core/LambderPublicFiles.js +32 -4
- package/dist/core/LambderRequestPath.d.ts +43 -0
- package/dist/core/LambderRequestPath.js +63 -0
- package/dist/core/LambderResponse.d.ts +26 -5
- package/dist/core/LambderResponse.js +157 -70
- package/dist/core/LambderResponseBuilder.d.ts +49 -4
- package/dist/core/LambderResponseBuilder.js +64 -3
- package/dist/core/LambderRouting.d.ts +2 -3
- package/dist/core/LambderRouting.js +22 -7
- package/dist/core/LambderTemplatingEngine.js +211 -32
- package/dist/index.d.ts +15 -8
- package/dist/index.js +5 -4
- package/dist/invoke/LambderInvokeCaller.d.ts +37 -42
- package/dist/invoke/LambderInvokeCaller.js +76 -66
- package/dist/invoke/LambderInvokeOutcome.d.ts +27 -26
- package/dist/invoke/LambderInvokeOutcome.js +9 -22
- package/dist/invoke/LambderLambdaEvent.d.ts +29 -9
- package/dist/invoke/LambderLambdaEvent.js +40 -22
- package/dist/invoke/lambderHandlerTransport.d.ts +9 -10
- package/dist/invoke/lambderHandlerTransport.js +15 -18
- package/dist/mock/LambderMockApp.d.ts +67 -83
- package/dist/mock/LambderMockApp.js +167 -153
- package/dist/mock/LambderMockBrowserCookies.d.ts +24 -28
- package/dist/mock/LambderMockBrowserCookies.js +24 -28
- package/dist/mock/LambderMockCallRecorder.d.ts +15 -22
- package/dist/mock/LambderMockCallRecorder.js +19 -28
- package/dist/mock/LambderMockCreateOptions.d.ts +42 -24
- package/dist/mock/LambderMockEntryRegistry.d.ts +11 -12
- package/dist/mock/LambderMockEntryRegistry.js +24 -29
- package/dist/mock/LambderMockFailureInjector.d.ts +3 -6
- package/dist/mock/LambderMockFailureInjector.js +3 -6
- package/dist/mock/LambderMockTypes.d.ts +78 -108
- package/dist/mock/lambderMockInvokeTransport.d.ts +11 -13
- package/dist/mock/lambderMockInvokeTransport.js +11 -10
- package/dist/mock/lambderMockMswHandler.d.ts +33 -29
- package/dist/mock/lambderMockMswHandler.js +50 -39
- package/dist/mock.d.ts +1 -1
- package/dist/mock.js +2 -3
- package/dist/session/LambderSessionController.d.ts +108 -89
- package/dist/session/LambderSessionController.js +187 -168
- package/dist/session/LambderSessionCrypto.d.ts +16 -7
- package/dist/session/LambderSessionCrypto.js +26 -12
- package/dist/session/LambderSessionManager.d.ts +124 -46
- package/dist/session/LambderSessionManager.js +262 -137
- package/dist/shared/LambderHtml.d.ts +42 -3
- package/dist/shared/LambderHtml.js +127 -7
- package/dist/shared/LambderHtmlPositions.d.ts +173 -0
- package/dist/shared/LambderHtmlPositions.js +652 -0
- package/dist/shared/LambderI18n.d.ts +10 -11
- package/dist/shared/LambderI18n.js +33 -21
- package/dist/shared/contracts/LambderCache.d.ts +66 -0
- package/dist/shared/contracts/LambderCache.js +11 -0
- package/dist/shared/contracts/LambderFileSource.d.ts +6 -6
- package/dist/shared/contracts/LambderFileSource.js +5 -8
- package/dist/shared/contracts/LambderIdempotencyStore.d.ts +51 -22
- package/dist/shared/contracts/LambderIdempotencyStore.js +4 -5
- package/dist/shared/contracts/LambderRateLimiter.d.ts +27 -15
- package/dist/shared/contracts/LambderRateLimiter.js +4 -5
- package/dist/shared/contracts/LambderSessionStore.d.ts +65 -26
- package/dist/shared/contracts/LambderSessionStore.js +5 -6
- package/dist/shared/transport/LambderApiTransport.d.ts +27 -27
- package/dist/shared/transport/LambderApiTransport.js +7 -7
- package/dist/shared/transport/LambderCookieJar.d.ts +28 -35
- package/dist/shared/transport/LambderCookieJar.js +54 -66
- package/dist/shared/transport/lambderCookieJarTransport.d.ts +11 -13
- package/dist/shared/transport/lambderCookieJarTransport.js +24 -23
- package/dist/shared/util/LambderCallAbort.d.ts +5 -5
- package/dist/shared/util/LambderCallAbort.js +5 -5
- package/dist/shared/util/LambderClientIp.d.ts +27 -11
- package/dist/shared/util/LambderClientIp.js +96 -13
- package/dist/shared/util/LambderExpiringMap.d.ts +35 -49
- package/dist/shared/util/LambderExpiringMap.js +41 -57
- package/dist/shared/util/LambderNodeModules.js +6 -7
- package/dist/shared/util/LambderOptionChecks.d.ts +4 -4
- package/dist/shared/util/LambderOptionChecks.js +4 -4
- package/dist/shared/util/LambderResponseBrand.d.ts +5 -5
- package/dist/shared/util/LambderResponseBrand.js +5 -5
- package/dist/shared/util/LambderTypeUtilities.d.ts +7 -8
- package/dist/shared/util/LambderTypeUtilities.js +3 -3
- package/dist/shared/util/boundKeyField.d.ts +20 -0
- package/dist/shared/util/boundKeyField.js +34 -0
- package/dist/shared/util/canonicalJson.d.ts +11 -0
- package/dist/shared/util/canonicalJson.js +28 -0
- package/dist/shared/util/joinKeyFields.d.ts +20 -0
- package/dist/shared/util/joinKeyFields.js +22 -0
- package/dist/shared/wire/LambderAnswerHeaders.d.ts +12 -16
- package/dist/shared/wire/LambderAnswerHeaders.js +12 -16
- package/dist/shared/wire/LambderApiContract.d.ts +107 -32
- package/dist/shared/wire/LambderApiOutcome.d.ts +43 -31
- package/dist/shared/wire/LambderApiOutcome.js +48 -23
- package/dist/shared/wire/LambderApiRefusal.d.ts +39 -27
- package/dist/shared/wire/LambderApiRefusal.js +36 -7
- package/dist/shared/wire/LambderApiSignature.d.ts +18 -22
- package/dist/shared/wire/LambderApiSignature.js +16 -19
- package/dist/shared/wire/LambderCallOptions.d.ts +38 -47
- package/dist/shared/wire/LambderCallOptions.js +9 -11
- package/dist/shared/wire/LambderCompressionCodec.d.ts +29 -34
- package/dist/shared/wire/LambderCompressionCodec.js +31 -36
- package/dist/shared/wire/LambderCompressionOption.d.ts +9 -9
- package/dist/shared/wire/LambderCompressionOption.js +9 -9
- package/dist/shared/wire/LambderCrashDetail.d.ts +12 -15
- package/dist/shared/wire/LambderCrashDetail.js +12 -15
- package/dist/shared/wire/LambderDefaultApiPath.d.ts +6 -0
- package/dist/shared/wire/LambderDefaultApiPath.js +6 -0
- package/dist/shared/wire/LambderHttpStatus.d.ts +6 -7
- package/dist/shared/wire/LambderIdempotencyKeyScope.d.ts +89 -0
- package/dist/shared/wire/LambderIdempotencyKeyScope.js +146 -0
- package/dist/shared/wire/LambderInvokeApiId.d.ts +27 -0
- package/dist/shared/wire/LambderInvokeApiId.js +27 -0
- package/dist/shared/wire/LambderOutcomeAssertions.d.ts +6 -7
- package/dist/shared/wire/LambderOutcomeAssertions.js +6 -7
- package/dist/shared/wire/LambderRequestPayload.d.ts +18 -20
- package/dist/shared/wire/LambderRequestPayload.js +4 -6
- package/dist/stores/LambderCacheFiller.d.ts +48 -0
- package/dist/stores/LambderCacheFiller.js +119 -0
- package/dist/stores/LambderCacheKeys.d.ts +26 -0
- package/dist/stores/LambderCacheKeys.js +54 -0
- package/dist/stores/LambderCacheValues.d.ts +45 -0
- package/dist/stores/LambderCacheValues.js +74 -0
- package/dist/stores/LambderDdbCache.d.ts +121 -56
- package/dist/stores/LambderDdbCache.js +528 -225
- package/dist/stores/LambderDdbIdempotencyStore.d.ts +33 -22
- package/dist/stores/LambderDdbIdempotencyStore.js +75 -50
- package/dist/stores/LambderDdbRateLimiter.d.ts +76 -20
- package/dist/stores/LambderDdbRateLimiter.js +151 -39
- package/dist/stores/LambderDdbSdk.d.ts +43 -31
- package/dist/stores/LambderDdbSdk.js +79 -33
- package/dist/stores/LambderDdbSessionStore.d.ts +27 -14
- package/dist/stores/LambderDdbSessionStore.js +119 -47
- package/dist/stores/LambderHttpFileSource.d.ts +15 -6
- package/dist/stores/LambderHttpFileSource.js +15 -13
- package/dist/stores/LambderMemoryCache.d.ts +49 -0
- package/dist/stores/LambderMemoryCache.js +113 -0
- package/dist/stores/LambderMemoryIdempotencyStore.d.ts +13 -12
- package/dist/stores/LambderMemoryIdempotencyStore.js +31 -30
- package/dist/stores/LambderMemoryRateLimiter.d.ts +8 -9
- package/dist/stores/LambderMemoryRateLimiter.js +14 -13
- package/dist/stores/LambderMemorySessionStore.d.ts +14 -11
- package/dist/stores/LambderMemorySessionStore.js +38 -19
- package/dist/stores/LambderS3FileSource.d.ts +21 -6
- package/dist/stores/LambderS3FileSource.js +12 -7
- package/dist/testing/LambderTestApp.d.ts +21 -23
- package/dist/testing/LambderTestApp.js +22 -24
- package/dist/testing/LambderTestVisitor.d.ts +10 -12
- package/dist/testing/LambderTestVisitor.js +15 -15
- package/dist/testing.d.ts +1 -0
- package/dist/testing.js +1 -0
- package/package.json +12 -3
- package/dist/api/LambderApiPolicyEngine.d.ts +0 -47
- package/dist/api/LambderApiPolicyEngine.js +0 -85
- package/dist/shared/util/LambderKeyFields.d.ts +0 -32
- package/dist/shared/util/LambderKeyFields.js +0 -34
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The per-call options
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* it.
|
|
2
|
+
* The per-call options, the contract-driven typing of a call's arguments, and
|
|
3
|
+
* the runtime merge of guard inputs, shared by the browser caller
|
|
4
|
+
* (LambderCaller) and the server-side invoke caller (LambderInvokeCaller).
|
|
5
|
+
* Both speak the same envelope to the same kind of contract, so what an API
|
|
6
|
+
* demands of its caller (a guardInput-mode guard's value, say) is decided
|
|
7
|
+
* here once and the two cannot drift. Pure types and one dependency-free
|
|
8
|
+
* function, so the browser entry resolves it.
|
|
10
9
|
*/
|
|
11
10
|
/**
|
|
12
11
|
* Provider values underneath, per-call values on top; undefined when neither
|
|
13
|
-
* side supplied any. Synchronous
|
|
14
|
-
*
|
|
15
|
-
* request in the same tick it was made.
|
|
12
|
+
* side supplied any. Synchronous so a call without a provider still issues
|
|
13
|
+
* its request in the same tick it was made.
|
|
16
14
|
*/
|
|
17
15
|
export const mergeGuardInputs = (provided, perCall) => provided !== undefined || perCall !== undefined ? { ...provided, ...perCall } : undefined;
|
|
@@ -4,32 +4,28 @@
|
|
|
4
4
|
* Five things compress: sessions, LambderDdbCache and LambderDdbIdempotencyStore
|
|
5
5
|
* (Brotli at rest in DynamoDB), HTTP responses (Brotli or gzip, negotiated)
|
|
6
6
|
* and request payloads (gzip from a browser, whose CompressionStream offers
|
|
7
|
-
* nothing else; Brotli from a Node caller).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* text at all, so the restore comes in two: restoreBytes returns the buffer
|
|
14
|
-
* and restoreText decodes it.
|
|
7
|
+
* nothing else; Brotli from a Node caller). All compress text, so TEXT mode
|
|
8
|
+
* throughout, and all restore from the compressed bytes plus the text's
|
|
9
|
+
* original UTF-8 byte length. The exception is a compressed HTTP answer read
|
|
10
|
+
* by LambderInvokeCaller: it has no declared length, so it passes a ceiling
|
|
11
|
+
* instead, and its bytes may not be text, hence restoreBytes beside
|
|
12
|
+
* restoreText. Both restores take either bound.
|
|
15
13
|
*
|
|
16
14
|
* That length is the safety mechanism, not bookkeeping. It bounds the
|
|
17
15
|
* decompression, so a body that would expand without limit is cut off
|
|
18
16
|
* rather than allocated, and the restored length must match it exactly, so
|
|
19
17
|
* a truncated or tampered input fails instead of decoding to something
|
|
20
|
-
* merely plausible.
|
|
21
|
-
* implementation
|
|
22
|
-
* untrusted request bodies alike.
|
|
18
|
+
* merely plausible. Records at rest and untrusted request bodies share this
|
|
19
|
+
* one implementation of it.
|
|
23
20
|
*
|
|
24
21
|
* zlib is loaded lazily through LambderNodeModules, so a module importing this
|
|
25
22
|
* one can still sit in a frontend bundle's import graph via the package
|
|
26
23
|
* root. Compressing needs zlib and is server-side; restoring runs anywhere,
|
|
27
|
-
* through zlib
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* entry can resolve it.
|
|
24
|
+
* through zlib or else the web DecompressionStream, so the mock runtime can
|
|
25
|
+
* restore a gzipped request payload in a browser under the same bound.
|
|
26
|
+
* Whether to compress, and the encoding vocabulary, live in
|
|
27
|
+
* LambderCompressionOption, which stays free of zlib so the browser entry can
|
|
28
|
+
* resolve it.
|
|
33
29
|
*/
|
|
34
30
|
import type { LambderEncoding } from "./LambderCompressionOption.js";
|
|
35
31
|
/** Why a bounded restore failed, for callers that answer rather than throw. */
|
|
@@ -53,7 +49,9 @@ export declare class LambderCompressionError extends Error {
|
|
|
53
49
|
}
|
|
54
50
|
/**
|
|
55
51
|
* Compresses text. `quality` is the Brotli quality (0-11) and is ignored by
|
|
56
|
-
* gzip, which has no comparable knob worth exposing.
|
|
52
|
+
* gzip, which has no comparable knob worth exposing. The result may be a view
|
|
53
|
+
* onto zlib's larger output chunk: a caller that keeps it for long copies it
|
|
54
|
+
* first (the DynamoDB cache's memory layer does).
|
|
57
55
|
*/
|
|
58
56
|
export declare const compressText: (input: Buffer, encoding: LambderEncoding, quality: number) => Promise<Buffer>;
|
|
59
57
|
/**
|
|
@@ -70,27 +68,24 @@ export type LambderRestoreBound = {
|
|
|
70
68
|
};
|
|
71
69
|
/**
|
|
72
70
|
* Restores the original bytes from compressed bytes under a bound. With
|
|
73
|
-
* `declaredBytes` (records at rest, request payloads) the length both
|
|
74
|
-
* the decompression and verifies
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* anything it cannot vouch for. A nonsense ceiling is the caller's
|
|
80
|
-
* configuration error and throws a plain Error.
|
|
71
|
+
* `declaredBytes` (records at rest, request payloads) the length both caps
|
|
72
|
+
* the decompression and verifies its result. With `maxBytes` only the
|
|
73
|
+
* ceiling holds; zlib's stream-end check and gzip's CRC catch truncation and
|
|
74
|
+
* corruption. Throws LambderCompressionError on anything it cannot vouch
|
|
75
|
+
* for; a nonsense ceiling is the caller's configuration error and throws a
|
|
76
|
+
* plain Error.
|
|
81
77
|
*
|
|
82
78
|
* This is the restore for bytes that are not text: a compressed binary
|
|
83
79
|
* answer (a wasm module, an image a route forced compression on) read by
|
|
84
|
-
* LambderInvokeCaller. Text callers use restoreText
|
|
85
|
-
*
|
|
86
|
-
*
|
|
80
|
+
* LambderInvokeCaller. Text callers use restoreText; decoding binary through
|
|
81
|
+
* a string would replace every invalid UTF-8 byte and silently hand back a
|
|
82
|
+
* different body.
|
|
87
83
|
*/
|
|
88
84
|
export declare const restoreBytes: (compressed: Uint8Array, encoding: LambderEncoding, bound: LambderRestoreBound) => Promise<Uint8Array>;
|
|
89
85
|
/**
|
|
90
|
-
* Restores text: restoreBytes plus the UTF-8 decode
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* either way.
|
|
86
|
+
* Restores text: restoreBytes plus the UTF-8 decode, for every text caller
|
|
87
|
+
* (sessions, the DynamoDB stores, request payloads). A `declaredBytes` bound
|
|
88
|
+
* is the text's UTF-8 byte length, which is the restored buffer's length, so
|
|
89
|
+
* the verification is the same.
|
|
95
90
|
*/
|
|
96
91
|
export declare const restoreText: (compressed: Uint8Array, encoding: LambderEncoding, bound: LambderRestoreBound) => Promise<string>;
|
|
@@ -4,32 +4,28 @@
|
|
|
4
4
|
* Five things compress: sessions, LambderDdbCache and LambderDdbIdempotencyStore
|
|
5
5
|
* (Brotli at rest in DynamoDB), HTTP responses (Brotli or gzip, negotiated)
|
|
6
6
|
* and request payloads (gzip from a browser, whose CompressionStream offers
|
|
7
|
-
* nothing else; Brotli from a Node caller).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* text at all, so the restore comes in two: restoreBytes returns the buffer
|
|
14
|
-
* and restoreText decodes it.
|
|
7
|
+
* nothing else; Brotli from a Node caller). All compress text, so TEXT mode
|
|
8
|
+
* throughout, and all restore from the compressed bytes plus the text's
|
|
9
|
+
* original UTF-8 byte length. The exception is a compressed HTTP answer read
|
|
10
|
+
* by LambderInvokeCaller: it has no declared length, so it passes a ceiling
|
|
11
|
+
* instead, and its bytes may not be text, hence restoreBytes beside
|
|
12
|
+
* restoreText. Both restores take either bound.
|
|
15
13
|
*
|
|
16
14
|
* That length is the safety mechanism, not bookkeeping. It bounds the
|
|
17
15
|
* decompression, so a body that would expand without limit is cut off
|
|
18
16
|
* rather than allocated, and the restored length must match it exactly, so
|
|
19
17
|
* a truncated or tampered input fails instead of decoding to something
|
|
20
|
-
* merely plausible.
|
|
21
|
-
* implementation
|
|
22
|
-
* untrusted request bodies alike.
|
|
18
|
+
* merely plausible. Records at rest and untrusted request bodies share this
|
|
19
|
+
* one implementation of it.
|
|
23
20
|
*
|
|
24
21
|
* zlib is loaded lazily through LambderNodeModules, so a module importing this
|
|
25
22
|
* one can still sit in a frontend bundle's import graph via the package
|
|
26
23
|
* root. Compressing needs zlib and is server-side; restoring runs anywhere,
|
|
27
|
-
* through zlib
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* entry can resolve it.
|
|
24
|
+
* through zlib or else the web DecompressionStream, so the mock runtime can
|
|
25
|
+
* restore a gzipped request payload in a browser under the same bound.
|
|
26
|
+
* Whether to compress, and the encoding vocabulary, live in
|
|
27
|
+
* LambderCompressionOption, which stays free of zlib so the browser entry can
|
|
28
|
+
* resolve it.
|
|
33
29
|
*/
|
|
34
30
|
import { getZlib } from "../util/LambderNodeModules.js";
|
|
35
31
|
import { assertPositiveInteger } from "../util/LambderOptionChecks.js";
|
|
@@ -56,8 +52,8 @@ export class LambderCompressionError extends Error {
|
|
|
56
52
|
}
|
|
57
53
|
}
|
|
58
54
|
// Not a LambderCompressionError: nothing was wrong with the bytes, so there
|
|
59
|
-
// is no restore `reason
|
|
60
|
-
//
|
|
55
|
+
// is no restore `reason`. Callers that map reasons fall through to their
|
|
56
|
+
// generic failure, which is the honest answer here.
|
|
61
57
|
const requireZlib = async () => {
|
|
62
58
|
const zlib = await getZlib();
|
|
63
59
|
if (!zlib)
|
|
@@ -66,7 +62,9 @@ const requireZlib = async () => {
|
|
|
66
62
|
};
|
|
67
63
|
/**
|
|
68
64
|
* Compresses text. `quality` is the Brotli quality (0-11) and is ignored by
|
|
69
|
-
* gzip, which has no comparable knob worth exposing.
|
|
65
|
+
* gzip, which has no comparable knob worth exposing. The result may be a view
|
|
66
|
+
* onto zlib's larger output chunk: a caller that keeps it for long copies it
|
|
67
|
+
* first (the DynamoDB cache's memory layer does).
|
|
70
68
|
*/
|
|
71
69
|
export const compressText = async (input, encoding, quality) => {
|
|
72
70
|
const zlib = await requireZlib();
|
|
@@ -90,20 +88,18 @@ export const compressText = async (input, encoding, quality) => {
|
|
|
90
88
|
};
|
|
91
89
|
/**
|
|
92
90
|
* Restores the original bytes from compressed bytes under a bound. With
|
|
93
|
-
* `declaredBytes` (records at rest, request payloads) the length both
|
|
94
|
-
* the decompression and verifies
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* anything it cannot vouch for. A nonsense ceiling is the caller's
|
|
100
|
-
* configuration error and throws a plain Error.
|
|
91
|
+
* `declaredBytes` (records at rest, request payloads) the length both caps
|
|
92
|
+
* the decompression and verifies its result. With `maxBytes` only the
|
|
93
|
+
* ceiling holds; zlib's stream-end check and gzip's CRC catch truncation and
|
|
94
|
+
* corruption. Throws LambderCompressionError on anything it cannot vouch
|
|
95
|
+
* for; a nonsense ceiling is the caller's configuration error and throws a
|
|
96
|
+
* plain Error.
|
|
101
97
|
*
|
|
102
98
|
* This is the restore for bytes that are not text: a compressed binary
|
|
103
99
|
* answer (a wasm module, an image a route forced compression on) read by
|
|
104
|
-
* LambderInvokeCaller. Text callers use restoreText
|
|
105
|
-
*
|
|
106
|
-
*
|
|
100
|
+
* LambderInvokeCaller. Text callers use restoreText; decoding binary through
|
|
101
|
+
* a string would replace every invalid UTF-8 byte and silently hand back a
|
|
102
|
+
* different body.
|
|
107
103
|
*/
|
|
108
104
|
export const restoreBytes = async (compressed, encoding, bound) => {
|
|
109
105
|
const verified = "declaredBytes" in bound;
|
|
@@ -134,11 +130,10 @@ export const restoreBytes = async (compressed, encoding, bound) => {
|
|
|
134
130
|
return output;
|
|
135
131
|
};
|
|
136
132
|
/**
|
|
137
|
-
* Restores text: restoreBytes plus the UTF-8 decode
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* either way.
|
|
133
|
+
* Restores text: restoreBytes plus the UTF-8 decode, for every text caller
|
|
134
|
+
* (sessions, the DynamoDB stores, request payloads). A `declaredBytes` bound
|
|
135
|
+
* is the text's UTF-8 byte length, which is the restored buffer's length, so
|
|
136
|
+
* the verification is the same.
|
|
142
137
|
*/
|
|
143
138
|
export const restoreText = async (compressed, encoding, bound) => new TextDecoder().decode(await restoreBytes(compressed, encoding, bound));
|
|
144
139
|
/** zlib reads any Uint8Array in place; maxOutputLength is the bound, so it stops rather than allocating past it. */
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
* The compression option every part of Lambder speaks, and the one function
|
|
3
3
|
* that resolves it.
|
|
4
4
|
*
|
|
5
|
-
* Five places compress
|
|
5
|
+
* Five places compress: sessions, LambderDdbCache and
|
|
6
6
|
* LambderDdbIdempotencyStore (Brotli at rest in DynamoDB), HTTP responses
|
|
7
|
-
* (Brotli/gzip on the wire) and request payloads (gzip on the wire).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
7
|
+
* (Brotli/gzip on the wire) and request payloads (gzip on the wire). Each
|
|
8
|
+
* declares its own settings type, since they tune differently, but all
|
|
9
|
+
* share one vocabulary and one resolution: `true` is on with that site's
|
|
10
|
+
* defaults, `false` is off, an object overrides individual fields, and
|
|
11
|
+
* `minBytes` is always the size from which a value is compressed (0:
|
|
12
|
+
* always). Resolved settings are `null` when off, so every consumer holds
|
|
13
|
+
* `Settings | null` and reads `minBytes` the same way.
|
|
14
14
|
*
|
|
15
15
|
* Nothing here touches zlib, so the browser entry can resolve the caller's
|
|
16
16
|
* option without pulling Node built-ins into the bundle; the compression
|
|
17
|
-
* primitives
|
|
17
|
+
* primitives live in LambderCompressionCodec, which does load zlib.
|
|
18
18
|
*/
|
|
19
19
|
/** Algorithms Lambder can produce. Brotli at rest and preferred on responses; gzip everywhere a browser has to do the compressing. */
|
|
20
20
|
export declare const LAMBDER_ENCODINGS: readonly ["br", "gzip"];
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
* The compression option every part of Lambder speaks, and the one function
|
|
3
3
|
* that resolves it.
|
|
4
4
|
*
|
|
5
|
-
* Five places compress
|
|
5
|
+
* Five places compress: sessions, LambderDdbCache and
|
|
6
6
|
* LambderDdbIdempotencyStore (Brotli at rest in DynamoDB), HTTP responses
|
|
7
|
-
* (Brotli/gzip on the wire) and request payloads (gzip on the wire).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
7
|
+
* (Brotli/gzip on the wire) and request payloads (gzip on the wire). Each
|
|
8
|
+
* declares its own settings type, since they tune differently, but all
|
|
9
|
+
* share one vocabulary and one resolution: `true` is on with that site's
|
|
10
|
+
* defaults, `false` is off, an object overrides individual fields, and
|
|
11
|
+
* `minBytes` is always the size from which a value is compressed (0:
|
|
12
|
+
* always). Resolved settings are `null` when off, so every consumer holds
|
|
13
|
+
* `Settings | null` and reads `minBytes` the same way.
|
|
14
14
|
*
|
|
15
15
|
* Nothing here touches zlib, so the browser entry can resolve the caller's
|
|
16
16
|
* option without pulling Node built-ins into the bundle; the compression
|
|
17
|
-
* primitives
|
|
17
|
+
* primitives live in LambderCompressionCodec, which does load zlib.
|
|
18
18
|
*/
|
|
19
19
|
import { assertNonNegativeInteger } from "../util/LambderOptionChecks.js";
|
|
20
20
|
/** Algorithms Lambder can produce. Brotli at rest and preferred on responses; gzip everywhere a browser has to do the compressing. */
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A crash, described for a caller that is allowed to see it.
|
|
3
3
|
*
|
|
4
|
-
* A global error handler decides what a failed request learns
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* so an error reporter that walks causes sees the callee's stack without
|
|
13
|
-
* being taught anything.
|
|
4
|
+
* A global error handler decides what a failed request learns. A browser
|
|
5
|
+
* gets a generic message; a trusted caller (another lambda invoking this
|
|
6
|
+
* one, a developer holding a debug cookie) can get the error's name, message,
|
|
7
|
+
* stack, cause chain and where it happened, to store in its own error log
|
|
8
|
+
* and find the right CloudWatch stream. The envelope carries it in `crash`
|
|
9
|
+
* beside errorMessage; LambderInvokeCaller rebuilds an Error from it as the
|
|
10
|
+
* `cause` of the error it throws, so a reporter that walks causes sees the
|
|
11
|
+
* callee's stack unaided.
|
|
14
12
|
*
|
|
15
13
|
* Dependency-free and isomorphic: the type is part of the envelope both
|
|
16
14
|
* entries export, and describeCrash needs nothing from Node.
|
|
@@ -49,10 +47,9 @@ export declare const errorFromCrashDetail: (crash: LambderCrashDetail) => Error;
|
|
|
49
47
|
/**
|
|
50
48
|
* A thrown value as an Error, so a reporter or a `cause` chain always holds
|
|
51
49
|
* one. An Error passes through; anything else becomes an Error whose message
|
|
52
|
-
* describes the value
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* `err instanceof Error ? err : new Error(...)`
|
|
56
|
-
* fallback of its own.
|
|
50
|
+
* describes the value as describeCrash does, JSON before String() (a
|
|
51
|
+
* null-prototype object or a throwing toString must not make the coercion
|
|
52
|
+
* itself throw). Use it instead of spelling
|
|
53
|
+
* `err instanceof Error ? err : new Error(...)` with a fallback per site.
|
|
57
54
|
*/
|
|
58
55
|
export declare const coerceToError: (value: unknown, fallbackMessage?: string) => Error;
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A crash, described for a caller that is allowed to see it.
|
|
3
3
|
*
|
|
4
|
-
* A global error handler decides what a failed request learns
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* so an error reporter that walks causes sees the callee's stack without
|
|
13
|
-
* being taught anything.
|
|
4
|
+
* A global error handler decides what a failed request learns. A browser
|
|
5
|
+
* gets a generic message; a trusted caller (another lambda invoking this
|
|
6
|
+
* one, a developer holding a debug cookie) can get the error's name, message,
|
|
7
|
+
* stack, cause chain and where it happened, to store in its own error log
|
|
8
|
+
* and find the right CloudWatch stream. The envelope carries it in `crash`
|
|
9
|
+
* beside errorMessage; LambderInvokeCaller rebuilds an Error from it as the
|
|
10
|
+
* `cause` of the error it throws, so a reporter that walks causes sees the
|
|
11
|
+
* callee's stack unaided.
|
|
14
12
|
*
|
|
15
13
|
* Dependency-free and isomorphic: the type is part of the envelope both
|
|
16
14
|
* entries export, and describeCrash needs nothing from Node.
|
|
@@ -79,11 +77,10 @@ export const errorFromCrashDetail = (crash) => {
|
|
|
79
77
|
/**
|
|
80
78
|
* A thrown value as an Error, so a reporter or a `cause` chain always holds
|
|
81
79
|
* one. An Error passes through; anything else becomes an Error whose message
|
|
82
|
-
* describes the value
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* `err instanceof Error ? err : new Error(...)`
|
|
86
|
-
* fallback of its own.
|
|
80
|
+
* describes the value as describeCrash does, JSON before String() (a
|
|
81
|
+
* null-prototype object or a throwing toString must not make the coercion
|
|
82
|
+
* itself throw). Use it instead of spelling
|
|
83
|
+
* `err instanceof Error ? err : new Error(...)` with a fallback per site.
|
|
87
84
|
*/
|
|
88
85
|
export const coerceToError = (value, fallbackMessage = "Unknown error") => {
|
|
89
86
|
if (value instanceof Error)
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The HTTP status codes a Lambder response may carry.
|
|
3
3
|
*
|
|
4
|
-
* In `shared/` rather than beside LambderResponse
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `@types/aws-lambda` resolvable to typecheck a status union.
|
|
4
|
+
* In `shared/` rather than beside LambderResponse: it is HTTP vocabulary, and
|
|
5
|
+
* code a browser bundle reaches needs it (LambderApiRefusal, the mock's
|
|
6
|
+
* contract types). Importing it from `core/` would pull
|
|
7
|
+
* `core/LambderResponse.ts`, and with it `aws-lambda`, into the type graph of
|
|
8
|
+
* `lambder/client`, so a browser-only consumer would need `@types/aws-lambda`
|
|
9
|
+
* to typecheck a status union.
|
|
11
10
|
*/
|
|
12
11
|
export type LambderHttpStatusCode = 100 | 101 | 200 | 201 | 202 | 203 | 204 | 206 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 408 | 409 | 410 | 412 | 413 | 415 | 416 | 418 | 422 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a key scope reads from an attempt's outcome. Both callers' outcomes
|
|
3
|
+
* carry these fields, so the one rule below serves the browser caller and
|
|
4
|
+
* the invoke caller alike.
|
|
5
|
+
*/
|
|
6
|
+
export type LambderIdempotentAttemptOutcome = {
|
|
7
|
+
ok: boolean;
|
|
8
|
+
reason?: string;
|
|
9
|
+
status?: number;
|
|
10
|
+
errorMessage?: {
|
|
11
|
+
code?: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
/** One call's key, and what tells its scope how the call ended. */
|
|
15
|
+
export type LambderIdempotentAttempt = {
|
|
16
|
+
/** The key this attempt sends; undefined for a call that sends none. */
|
|
17
|
+
readonly key: string | undefined;
|
|
18
|
+
/** Tells the scope the attempt's outcome, once it is known. Only the first call counts. */
|
|
19
|
+
settle(outcome: LambderIdempotentAttemptOutcome): void;
|
|
20
|
+
};
|
|
21
|
+
/** The outcome of an attempt that ended before anything was sent: it tried nothing. */
|
|
22
|
+
export declare const IDEMPOTENT_ATTEMPT_NOT_SENT: LambderIdempotentAttemptOutcome;
|
|
23
|
+
/**
|
|
24
|
+
* Generate an idempotency key for one logical operation. Create it when the
|
|
25
|
+
* operation begins (a form opens, a draft starts), send the same key on every
|
|
26
|
+
* attempt of that operation, and generate a new one after a confirmed
|
|
27
|
+
* success; createIdempotencyKeyScope() does that bookkeeping itself. Uses
|
|
28
|
+
* crypto.randomUUID when available, else a v4 UUID from getRandomValues,
|
|
29
|
+
* because randomUUID only exists in secure contexts (plain-http LAN device
|
|
30
|
+
* testing lacks it).
|
|
31
|
+
*
|
|
32
|
+
* A runtime with neither throws rather than using Math.random: the key
|
|
33
|
+
* scopes the replay record for a logged-out client, so a guessable one hands
|
|
34
|
+
* that client's stored response to whoever guesses it.
|
|
35
|
+
*/
|
|
36
|
+
export declare const createIdempotencyKey: () => string;
|
|
37
|
+
/**
|
|
38
|
+
* One logical operation's rotating idempotency key, from
|
|
39
|
+
* createIdempotencyKeyScope(). Every attempt of the operation
|
|
40
|
+
* sends the current key, and the scope moves to a new key once an answer
|
|
41
|
+
* settles the operation:
|
|
42
|
+
*
|
|
43
|
+
* - A success settles it, and so does a key refused as reused for another
|
|
44
|
+
* request, since that key can never carry this one.
|
|
45
|
+
* - A refusal of this request (a rejected input, not authorized, an
|
|
46
|
+
* errorMessage) settles it, unless another attempt under the same key is
|
|
47
|
+
* still in flight or went unanswered. That attempt may run or have run the
|
|
48
|
+
* operation, and guards, validation and rate limits refuse before the
|
|
49
|
+
* replay record is claimed, so the refusal of a retry or a double-tap says
|
|
50
|
+
* nothing about it. Keeping the key lets the next attempt replay the
|
|
51
|
+
* original's answer rather than run again.
|
|
52
|
+
* - A rate limit, an expired session, a stale version, and an attempt that
|
|
53
|
+
* ended before anything was sent keep the key.
|
|
54
|
+
* - Anything that is not an answer (a network failure, a timeout, a 5xx, a
|
|
55
|
+
* crash) keeps the key and marks it as possibly used, and so does a
|
|
56
|
+
* duplicate of an original still in flight, unless the scope has another
|
|
57
|
+
* attempt of its own still waiting for its answer (a double-tap): that
|
|
58
|
+
* attempt is the original, and its answer settles the key, a refusal
|
|
59
|
+
* included.
|
|
60
|
+
*
|
|
61
|
+
* An answer to a key the scope has already moved past changes nothing: a
|
|
62
|
+
* slow original answering after the person moved on must not rotate away
|
|
63
|
+
* the key their current attempt is using.
|
|
64
|
+
*/
|
|
65
|
+
export declare class LambderIdempotencyKeyScope {
|
|
66
|
+
#private;
|
|
67
|
+
/** The key for the operation currently in progress. */
|
|
68
|
+
get current(): string;
|
|
69
|
+
/** Moves on to a new operation by hand, for a caller that settles operations itself. Returns the new key. */
|
|
70
|
+
rotate(): string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A self-rotating idempotency key for a component or form that performs the
|
|
74
|
+
* same logical operation repeatedly. Pass the scope itself as the call's
|
|
75
|
+
* `idempotencyKey`, on LambderCaller or LambderInvokeCaller: every attempt of
|
|
76
|
+
* one operation (a retry after a dropped connection, a double-tap) sends its
|
|
77
|
+
* current key, so the server collapses them, and the caller rotates it once
|
|
78
|
+
* an answer settles the operation (a success, or a refusal of this request),
|
|
79
|
+
* so the next attempt, a corrected form included, is a new operation.
|
|
80
|
+
* LambderIdempotencyKeyScope says which answers settle it.
|
|
81
|
+
*
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const submitKey = createIdempotencyKeyScope();
|
|
84
|
+
* await caller.api("order.create", payload, { idempotencyKey: submitKey });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare const createIdempotencyKeyScope: () => LambderIdempotencyKeyScope;
|
|
88
|
+
/** The attempt a call makes with its idempotencyKey option: a scope's current key, or a plain key with nothing to settle. */
|
|
89
|
+
export declare const beginIdempotentAttempt: (option: string | LambderIdempotencyKeyScope | undefined) => LambderIdempotentAttempt;
|