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.
Files changed (207) hide show
  1. package/CHANGELOG.md +933 -3
  2. package/README.md +41 -21
  3. package/dist/api/LambderApiAnswer.d.ts +18 -22
  4. package/dist/api/LambderApiAnswer.js +6 -7
  5. package/dist/api/LambderApiCallContext.d.ts +21 -8
  6. package/dist/api/LambderApiCallContext.js +22 -4
  7. package/dist/api/LambderApiDefinition.d.ts +4 -3
  8. package/dist/api/LambderApiEnvelope.d.ts +14 -9
  9. package/dist/api/LambderApiEnvelope.js +33 -34
  10. package/dist/api/LambderApiGuards.d.ts +78 -51
  11. package/dist/api/LambderApiGuards.js +34 -36
  12. package/dist/api/LambderApiIdempotency.d.ts +68 -62
  13. package/dist/api/LambderApiIdempotency.js +214 -151
  14. package/dist/api/LambderApiOutputValidationError.d.ts +32 -0
  15. package/dist/api/LambderApiOutputValidationError.js +50 -0
  16. package/dist/api/LambderApiPipeline.d.ts +47 -38
  17. package/dist/api/LambderApiPipeline.js +122 -63
  18. package/dist/api/LambderApiRateLimits.d.ts +201 -54
  19. package/dist/api/LambderApiRateLimits.js +185 -108
  20. package/dist/api/LambderApiRequest.d.ts +27 -21
  21. package/dist/api/LambderApiRequest.js +26 -19
  22. package/dist/api/LambderApiSignature.d.ts +12 -15
  23. package/dist/api/LambderApiSignature.js +28 -51
  24. package/dist/api/LambderApiValidationRefusal.d.ts +9 -9
  25. package/dist/api/LambderApiValidationRefusal.js +10 -10
  26. package/dist/build/freshProcessVerifier.d.ts +13 -0
  27. package/dist/build/freshProcessVerifier.js +19 -0
  28. package/dist/build/writeApiSignatures.d.ts +109 -0
  29. package/dist/build/writeApiSignatures.js +222 -0
  30. package/dist/build.d.ts +9 -0
  31. package/dist/build.js +8 -0
  32. package/dist/client/LambderCaller.d.ts +13 -44
  33. package/dist/client/LambderCaller.js +77 -84
  34. package/dist/client/LambderReloadLoopBreaker.d.ts +56 -26
  35. package/dist/client/LambderReloadLoopBreaker.js +90 -46
  36. package/dist/client/lambderFetchTransport.d.ts +4 -1
  37. package/dist/client/lambderFetchTransport.js +52 -28
  38. package/dist/client.d.ts +5 -3
  39. package/dist/client.js +2 -1
  40. package/dist/core/Lambder.d.ts +140 -75
  41. package/dist/core/Lambder.js +347 -227
  42. package/dist/core/LambderContext.d.ts +82 -15
  43. package/dist/core/LambderContext.js +107 -20
  44. package/dist/core/LambderCors.d.ts +21 -3
  45. package/dist/core/LambderCors.js +35 -16
  46. package/dist/core/LambderCrashHandling.d.ts +40 -0
  47. package/dist/core/LambderCrashHandling.js +97 -0
  48. package/dist/core/LambderCreateOptions.d.ts +151 -75
  49. package/dist/core/LambderCreateOptions.js +16 -23
  50. package/dist/core/LambderFiles.d.ts +21 -7
  51. package/dist/core/LambderFiles.js +62 -34
  52. package/dist/core/LambderIndexHtml.js +12 -11
  53. package/dist/core/LambderPolicyBuilders.d.ts +17 -5
  54. package/dist/core/LambderPolicyBuilders.js +17 -5
  55. package/dist/core/LambderPublicFiles.d.ts +11 -5
  56. package/dist/core/LambderPublicFiles.js +32 -4
  57. package/dist/core/LambderRequestPath.d.ts +43 -0
  58. package/dist/core/LambderRequestPath.js +63 -0
  59. package/dist/core/LambderResponse.d.ts +26 -5
  60. package/dist/core/LambderResponse.js +157 -70
  61. package/dist/core/LambderResponseBuilder.d.ts +49 -4
  62. package/dist/core/LambderResponseBuilder.js +64 -3
  63. package/dist/core/LambderRouting.d.ts +2 -3
  64. package/dist/core/LambderRouting.js +22 -7
  65. package/dist/core/LambderTemplatingEngine.js +211 -32
  66. package/dist/index.d.ts +15 -8
  67. package/dist/index.js +5 -4
  68. package/dist/invoke/LambderInvokeCaller.d.ts +37 -42
  69. package/dist/invoke/LambderInvokeCaller.js +76 -66
  70. package/dist/invoke/LambderInvokeOutcome.d.ts +27 -26
  71. package/dist/invoke/LambderInvokeOutcome.js +9 -22
  72. package/dist/invoke/LambderLambdaEvent.d.ts +29 -9
  73. package/dist/invoke/LambderLambdaEvent.js +40 -22
  74. package/dist/invoke/lambderHandlerTransport.d.ts +9 -10
  75. package/dist/invoke/lambderHandlerTransport.js +15 -18
  76. package/dist/mock/LambderMockApp.d.ts +67 -83
  77. package/dist/mock/LambderMockApp.js +167 -153
  78. package/dist/mock/LambderMockBrowserCookies.d.ts +24 -28
  79. package/dist/mock/LambderMockBrowserCookies.js +24 -28
  80. package/dist/mock/LambderMockCallRecorder.d.ts +15 -22
  81. package/dist/mock/LambderMockCallRecorder.js +19 -28
  82. package/dist/mock/LambderMockCreateOptions.d.ts +42 -24
  83. package/dist/mock/LambderMockEntryRegistry.d.ts +11 -12
  84. package/dist/mock/LambderMockEntryRegistry.js +24 -29
  85. package/dist/mock/LambderMockFailureInjector.d.ts +3 -6
  86. package/dist/mock/LambderMockFailureInjector.js +3 -6
  87. package/dist/mock/LambderMockTypes.d.ts +78 -108
  88. package/dist/mock/lambderMockInvokeTransport.d.ts +11 -13
  89. package/dist/mock/lambderMockInvokeTransport.js +11 -10
  90. package/dist/mock/lambderMockMswHandler.d.ts +33 -29
  91. package/dist/mock/lambderMockMswHandler.js +50 -39
  92. package/dist/mock.d.ts +1 -1
  93. package/dist/mock.js +2 -3
  94. package/dist/session/LambderSessionController.d.ts +108 -89
  95. package/dist/session/LambderSessionController.js +187 -168
  96. package/dist/session/LambderSessionCrypto.d.ts +16 -7
  97. package/dist/session/LambderSessionCrypto.js +26 -12
  98. package/dist/session/LambderSessionManager.d.ts +124 -46
  99. package/dist/session/LambderSessionManager.js +262 -137
  100. package/dist/shared/LambderHtml.d.ts +42 -3
  101. package/dist/shared/LambderHtml.js +127 -7
  102. package/dist/shared/LambderHtmlPositions.d.ts +173 -0
  103. package/dist/shared/LambderHtmlPositions.js +652 -0
  104. package/dist/shared/LambderI18n.d.ts +10 -11
  105. package/dist/shared/LambderI18n.js +33 -21
  106. package/dist/shared/contracts/LambderCache.d.ts +66 -0
  107. package/dist/shared/contracts/LambderCache.js +11 -0
  108. package/dist/shared/contracts/LambderFileSource.d.ts +6 -6
  109. package/dist/shared/contracts/LambderFileSource.js +5 -8
  110. package/dist/shared/contracts/LambderIdempotencyStore.d.ts +51 -22
  111. package/dist/shared/contracts/LambderIdempotencyStore.js +4 -5
  112. package/dist/shared/contracts/LambderRateLimiter.d.ts +27 -15
  113. package/dist/shared/contracts/LambderRateLimiter.js +4 -5
  114. package/dist/shared/contracts/LambderSessionStore.d.ts +65 -26
  115. package/dist/shared/contracts/LambderSessionStore.js +5 -6
  116. package/dist/shared/transport/LambderApiTransport.d.ts +27 -27
  117. package/dist/shared/transport/LambderApiTransport.js +7 -7
  118. package/dist/shared/transport/LambderCookieJar.d.ts +28 -35
  119. package/dist/shared/transport/LambderCookieJar.js +54 -66
  120. package/dist/shared/transport/lambderCookieJarTransport.d.ts +11 -13
  121. package/dist/shared/transport/lambderCookieJarTransport.js +24 -23
  122. package/dist/shared/util/LambderCallAbort.d.ts +5 -5
  123. package/dist/shared/util/LambderCallAbort.js +5 -5
  124. package/dist/shared/util/LambderClientIp.d.ts +27 -11
  125. package/dist/shared/util/LambderClientIp.js +96 -13
  126. package/dist/shared/util/LambderExpiringMap.d.ts +35 -49
  127. package/dist/shared/util/LambderExpiringMap.js +41 -57
  128. package/dist/shared/util/LambderNodeModules.js +6 -7
  129. package/dist/shared/util/LambderOptionChecks.d.ts +4 -4
  130. package/dist/shared/util/LambderOptionChecks.js +4 -4
  131. package/dist/shared/util/LambderResponseBrand.d.ts +5 -5
  132. package/dist/shared/util/LambderResponseBrand.js +5 -5
  133. package/dist/shared/util/LambderTypeUtilities.d.ts +7 -8
  134. package/dist/shared/util/LambderTypeUtilities.js +3 -3
  135. package/dist/shared/util/boundKeyField.d.ts +20 -0
  136. package/dist/shared/util/boundKeyField.js +34 -0
  137. package/dist/shared/util/canonicalJson.d.ts +11 -0
  138. package/dist/shared/util/canonicalJson.js +28 -0
  139. package/dist/shared/util/joinKeyFields.d.ts +20 -0
  140. package/dist/shared/util/joinKeyFields.js +22 -0
  141. package/dist/shared/wire/LambderAnswerHeaders.d.ts +12 -16
  142. package/dist/shared/wire/LambderAnswerHeaders.js +12 -16
  143. package/dist/shared/wire/LambderApiContract.d.ts +107 -32
  144. package/dist/shared/wire/LambderApiOutcome.d.ts +43 -31
  145. package/dist/shared/wire/LambderApiOutcome.js +48 -23
  146. package/dist/shared/wire/LambderApiRefusal.d.ts +39 -27
  147. package/dist/shared/wire/LambderApiRefusal.js +36 -7
  148. package/dist/shared/wire/LambderApiSignature.d.ts +18 -22
  149. package/dist/shared/wire/LambderApiSignature.js +16 -19
  150. package/dist/shared/wire/LambderCallOptions.d.ts +38 -47
  151. package/dist/shared/wire/LambderCallOptions.js +9 -11
  152. package/dist/shared/wire/LambderCompressionCodec.d.ts +29 -34
  153. package/dist/shared/wire/LambderCompressionCodec.js +31 -36
  154. package/dist/shared/wire/LambderCompressionOption.d.ts +9 -9
  155. package/dist/shared/wire/LambderCompressionOption.js +9 -9
  156. package/dist/shared/wire/LambderCrashDetail.d.ts +12 -15
  157. package/dist/shared/wire/LambderCrashDetail.js +12 -15
  158. package/dist/shared/wire/LambderDefaultApiPath.d.ts +6 -0
  159. package/dist/shared/wire/LambderDefaultApiPath.js +6 -0
  160. package/dist/shared/wire/LambderHttpStatus.d.ts +6 -7
  161. package/dist/shared/wire/LambderIdempotencyKeyScope.d.ts +89 -0
  162. package/dist/shared/wire/LambderIdempotencyKeyScope.js +146 -0
  163. package/dist/shared/wire/LambderInvokeApiId.d.ts +27 -0
  164. package/dist/shared/wire/LambderInvokeApiId.js +27 -0
  165. package/dist/shared/wire/LambderOutcomeAssertions.d.ts +6 -7
  166. package/dist/shared/wire/LambderOutcomeAssertions.js +6 -7
  167. package/dist/shared/wire/LambderRequestPayload.d.ts +18 -20
  168. package/dist/shared/wire/LambderRequestPayload.js +4 -6
  169. package/dist/stores/LambderCacheFiller.d.ts +48 -0
  170. package/dist/stores/LambderCacheFiller.js +119 -0
  171. package/dist/stores/LambderCacheKeys.d.ts +26 -0
  172. package/dist/stores/LambderCacheKeys.js +54 -0
  173. package/dist/stores/LambderCacheValues.d.ts +45 -0
  174. package/dist/stores/LambderCacheValues.js +74 -0
  175. package/dist/stores/LambderDdbCache.d.ts +121 -56
  176. package/dist/stores/LambderDdbCache.js +528 -225
  177. package/dist/stores/LambderDdbIdempotencyStore.d.ts +33 -22
  178. package/dist/stores/LambderDdbIdempotencyStore.js +75 -50
  179. package/dist/stores/LambderDdbRateLimiter.d.ts +76 -20
  180. package/dist/stores/LambderDdbRateLimiter.js +151 -39
  181. package/dist/stores/LambderDdbSdk.d.ts +43 -31
  182. package/dist/stores/LambderDdbSdk.js +79 -33
  183. package/dist/stores/LambderDdbSessionStore.d.ts +27 -14
  184. package/dist/stores/LambderDdbSessionStore.js +119 -47
  185. package/dist/stores/LambderHttpFileSource.d.ts +15 -6
  186. package/dist/stores/LambderHttpFileSource.js +15 -13
  187. package/dist/stores/LambderMemoryCache.d.ts +49 -0
  188. package/dist/stores/LambderMemoryCache.js +113 -0
  189. package/dist/stores/LambderMemoryIdempotencyStore.d.ts +13 -12
  190. package/dist/stores/LambderMemoryIdempotencyStore.js +31 -30
  191. package/dist/stores/LambderMemoryRateLimiter.d.ts +8 -9
  192. package/dist/stores/LambderMemoryRateLimiter.js +14 -13
  193. package/dist/stores/LambderMemorySessionStore.d.ts +14 -11
  194. package/dist/stores/LambderMemorySessionStore.js +38 -19
  195. package/dist/stores/LambderS3FileSource.d.ts +21 -6
  196. package/dist/stores/LambderS3FileSource.js +12 -7
  197. package/dist/testing/LambderTestApp.d.ts +21 -23
  198. package/dist/testing/LambderTestApp.js +22 -24
  199. package/dist/testing/LambderTestVisitor.d.ts +10 -12
  200. package/dist/testing/LambderTestVisitor.js +15 -15
  201. package/dist/testing.d.ts +1 -0
  202. package/dist/testing.js +1 -0
  203. package/package.json +12 -3
  204. package/dist/api/LambderApiPolicyEngine.d.ts +0 -47
  205. package/dist/api/LambderApiPolicyEngine.js +0 -85
  206. package/dist/shared/util/LambderKeyFields.d.ts +0 -32
  207. package/dist/shared/util/LambderKeyFields.js +0 -34
@@ -1,17 +1,15 @@
1
1
  /**
2
- * The per-call options both callers take, the contract-driven typing of a
3
- * call's arguments, and the runtime merge of guard inputs, shared by the
4
- * browser caller (LambderCaller) and the server-side invoke caller
5
- * (LambderInvokeCaller). Both speak the same envelope to the same kind of
6
- * contract, so what an API demands of its caller (a guardInput-mode guard's
7
- * value, say) is decided here once and the two callers cannot drift on it.
8
- * Pure types and one dependency-free function, so the browser entry resolves
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 on purpose: a caller awaits its provider
14
- * only when it has one, so a call without a provider still issues its
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). They all compress text, so TEXT
8
- * mode throughout, and they all restore it the same way: the compressed
9
- * bytes beside the text's original UTF-8 byte length. The one restore
10
- * without a declared length is a compressed HTTP answer read by
11
- * LambderInvokeCaller, which passes a ceiling instead; both restores take
12
- * either bound. That answer is also the one restore whose bytes may not be
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. Every caller gets that guarantee from this one
21
- * implementation: a bug fixed here is fixed for records at rest and for
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 where it exists and through the web DecompressionStream
28
- * otherwise, so the API core can restore a gzipped request payload in a
29
- * browser (the mock runtime) under the same bound. The option that decides
30
- * WHETHER to compress, and the encoding vocabulary, live in
31
- * LambderCompressionOption, which stays free of zlib entirely so the browser
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 bounds
74
- * the decompression and verifies it, so a body that would expand without
75
- * limit is cut off rather than allocated, and a truncated or tampered input
76
- * fails instead of decoding to something merely plausible. With `maxBytes`
77
- * only the ceiling holds; truncation and corruption are what zlib's
78
- * stream-end check and gzip's CRC catch. Throws LambderCompressionError on
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, which is this plus the
85
- * UTF-8 decode; going through a string would replace every byte that is not
86
- * valid UTF-8 and hand back a body that is silently not what was sent.
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. What every text caller
91
- * uses (sessions, the DynamoDB stores, request payloads). The declared byte
92
- * length a `declaredBytes` bound carries is the text's UTF-8 byte length,
93
- * which is the restored buffer's length, so the verification is the same one
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). They all compress text, so TEXT
8
- * mode throughout, and they all restore it the same way: the compressed
9
- * bytes beside the text's original UTF-8 byte length. The one restore
10
- * without a declared length is a compressed HTTP answer read by
11
- * LambderInvokeCaller, which passes a ceiling instead; both restores take
12
- * either bound. That answer is also the one restore whose bytes may not be
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. Every caller gets that guarantee from this one
21
- * implementation: a bug fixed here is fixed for records at rest and for
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 where it exists and through the web DecompressionStream
28
- * otherwise, so the API core can restore a gzipped request payload in a
29
- * browser (the mock runtime) under the same bound. The option that decides
30
- * WHETHER to compress, and the encoding vocabulary, live in
31
- * LambderCompressionOption, which stays free of zlib entirely so the browser
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` to report. Callers that map reasons fall through to
60
- // their generic failure, which is the honest answer here.
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 bounds
94
- * the decompression and verifies it, so a body that would expand without
95
- * limit is cut off rather than allocated, and a truncated or tampered input
96
- * fails instead of decoding to something merely plausible. With `maxBytes`
97
- * only the ceiling holds; truncation and corruption are what zlib's
98
- * stream-end check and gzip's CRC catch. Throws LambderCompressionError on
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, which is this plus the
105
- * UTF-8 decode; going through a string would replace every byte that is not
106
- * valid UTF-8 and hand back a body that is silently not what was sent.
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. What every text caller
138
- * uses (sessions, the DynamoDB stores, request payloads). The declared byte
139
- * length a `declaredBytes` bound carries is the text's UTF-8 byte length,
140
- * which is the restored buffer's length, so the verification is the same one
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 something: sessions, LambderDdbCache and
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). They
8
- * differ in what they can be tuned with, so each declares its own settings
9
- * type, but they share one vocabulary and one resolution: `true` is on with
10
- * that site's defaults, `false` is off, an object overrides individual
11
- * fields, and `minBytes` is always the size from which a value is
12
- * compressed (0: always). Resolved settings are `null` when off, so every
13
- * consumer holds `Settings | null` and reads `minBytes` the same way.
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 themselves live in LambderCompressionCodec, which does load zlib.
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 something: sessions, LambderDdbCache and
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). They
8
- * differ in what they can be tuned with, so each declares its own settings
9
- * type, but they share one vocabulary and one resolution: `true` is on with
10
- * that site's defaults, `false` is off, an object overrides individual
11
- * fields, and `minBytes` is always the size from which a value is
12
- * compressed (0: always). Resolved settings are `null` when off, so every
13
- * consumer holds `Settings | null` and reads `minBytes` the same way.
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 themselves live in LambderCompressionCodec, which does load zlib.
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 about the
5
- * failure. A browser gets a generic message; a trusted caller (another
6
- * lambda invoking this one, a developer holding a debug cookie) can be
7
- * handed the whole thing: the error's name, message and stack, its cause
8
- * chain, and where it happened, so the caller can store it in its own
9
- * error log and point at the right CloudWatch stream. The envelope carries
10
- * it in the `crash` field beside errorMessage; LambderInvokeCaller reads it
11
- * back and rebuilds an Error from it as the `cause` of the error it throws,
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 the way describeCrash does, JSON where String() cannot
53
- * (a null-prototype object or a throwing toString must not make the
54
- * coercion itself throw). One implementation, rather than
55
- * `err instanceof Error ? err : new Error(...)` spelled at every site with a
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 about the
5
- * failure. A browser gets a generic message; a trusted caller (another
6
- * lambda invoking this one, a developer holding a debug cookie) can be
7
- * handed the whole thing: the error's name, message and stack, its cause
8
- * chain, and where it happened, so the caller can store it in its own
9
- * error log and point at the right CloudWatch stream. The envelope carries
10
- * it in the `crash` field beside errorMessage; LambderInvokeCaller reads it
11
- * back and rebuilds an Error from it as the `cause` of the error it throws,
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 the way describeCrash does, JSON where String() cannot
83
- * (a null-prototype object or a throwing toString must not make the
84
- * coercion itself throw). One implementation, rather than
85
- * `err instanceof Error ? err : new Error(...)` spelled at every site with a
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)
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The path a Lambder server takes API calls on unless the app names its own
3
+ * (`apiPath` at create()). One definition, in shared, so every place that
4
+ * defaults it reads the same value.
5
+ */
6
+ export declare const DEFAULT_API_PATH = "/api";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The path a Lambder server takes API calls on unless the app names its own
3
+ * (`apiPath` at create()). One definition, in shared, so every place that
4
+ * defaults it reads the same value.
5
+ */
6
+ export const DEFAULT_API_PATH = "/api";
@@ -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 because it is HTTP
5
- * vocabulary with no relationship to the server's response class, and the
6
- * places that need it include ones a browser bundle reaches
7
- * (LambderApiRefusal, the mock's contract types). Importing it from `core/`
8
- * pulled `core/LambderResponse.ts` into the type graph of `lambder/client`,
9
- * and with it `aws-lambda`, so a browser-only consumer needed
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;