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
@@ -0,0 +1,74 @@
1
+ import { assertPositiveInteger } from "../shared/util/LambderOptionChecks.js";
2
+ /*
3
+ * What a cache value has to be, and how a cache call's options are read, for
4
+ * every cache here.
5
+ *
6
+ * LambderDdbCache and LambderMemoryCache refuse the same values and the same
7
+ * options for the reason they refuse the same keys (see LambderCacheKeys): a
8
+ * test that runs over the memory cache must not accept what production then
9
+ * throws on. So the rules are written once, here, and both caches call them.
10
+ */
11
+ /** How long an entry lives when neither the call nor the cache names a TTL: one year. */
12
+ export const DEFAULT_TTL_SECONDS = 365 * 24 * 60 * 60;
13
+ /** Largest value a cache accepts unless told otherwise, in UTF-8 bytes of its JSON: 32 MiB. */
14
+ export const DEFAULT_MAX_VALUE_BYTES = 32 * 1024 * 1024;
15
+ /** How long LambderDdbCache's fill lease holds when getOrSet names none. */
16
+ const DEFAULT_LEASE_SECONDS = 15;
17
+ /**
18
+ * The value as a cache stores it, or a throw when no cache here can hold it:
19
+ * a value JSON cannot represent (undefined, a function) or one whose JSON is
20
+ * past `maxValueBytes`.
21
+ */
22
+ export const serializeCacheValue = (value, maxValueBytes) => {
23
+ const json = JSON.stringify(value);
24
+ if (json === undefined)
25
+ throw new Error("Cache value must be JSON-serializable");
26
+ const utf8 = new TextEncoder().encode(json);
27
+ if (utf8.length > maxValueBytes) {
28
+ throw new Error(`Cache value exceeds maxValueBytes (${utf8.length} > ${maxValueBytes})`);
29
+ }
30
+ return { json, utf8 };
31
+ };
32
+ /**
33
+ * The value as a cache hands a stored one back, a JSON round trip, so a value
34
+ * handed back uncached (a fail-open, a fill a write overtook) has the shape a
35
+ * hit has (a Date as its string). A value JSON cannot hold (undefined, a
36
+ * bigint) is handed back as it is.
37
+ */
38
+ export const asStoredJson = (value) => {
39
+ let json;
40
+ try {
41
+ json = JSON.stringify(value);
42
+ }
43
+ catch {
44
+ return value;
45
+ }
46
+ return json === undefined ? value : JSON.parse(json);
47
+ };
48
+ /** A write's TTL: the call's own or the cache's default, checked either way. */
49
+ export const resolveCacheTtlSeconds = (ttlSeconds, defaultTtlSeconds) => assertPositiveInteger(ttlSeconds ?? defaultTtlSeconds, "ttlSeconds");
50
+ /**
51
+ * getOrSet's options, checked before the call reaches the fail-open (see
52
+ * LambderCacheFiller). Checked inside it, a bad option would read as the
53
+ * cache failing: every call would log, hand the loader's value back
54
+ * uncached, and caching would be off without the caller ever seeing why.
55
+ *
56
+ * The lease options are LambderDdbCache's. The memory cache holds no lease
57
+ * but checks them all the same, so an options object that the table refuses
58
+ * is refused by its twin too.
59
+ */
60
+ export const resolveGetOrSetOptions = (options, defaultTtlSeconds) => {
61
+ const leaseSeconds = assertPositiveInteger(options.leaseSeconds ?? DEFAULT_LEASE_SECONDS, "leaseSeconds");
62
+ return {
63
+ ttlSeconds: resolveCacheTtlSeconds(options.ttlSeconds, defaultTtlSeconds),
64
+ leaseSeconds,
65
+ // As long as the holder's lease lasts, and a second more, by default:
66
+ // a waiter that gives up sooner runs the loader itself while the
67
+ // holder is still loading, so ten containers asking for one slow key
68
+ // would load it ten times. The extra second is the lease's own
69
+ // rounding: it expires in whole seconds, so a crashed holder's lease
70
+ // becomes free up to a second after it runs out, and a waiter should
71
+ // still be there to take it.
72
+ waitForFillMs: assertPositiveInteger(options.waitForFillMs ?? (leaseSeconds + 1) * 1000, "waitForFillMs"),
73
+ };
74
+ };
@@ -1,5 +1,6 @@
1
1
  import type { DynamoDBClient } from "@aws-sdk/client-dynamodb";
2
2
  import { type LambderCompressionOption } from "../shared/wire/LambderCompressionOption.js";
3
+ import type { LambderCache, LambderCacheKey, LambderCacheListOptions, LambderCacheSetOptions } from "../shared/contracts/LambderCache.js";
3
4
  export interface LambderDdbCacheOptions {
4
5
  tableName: string;
5
6
  /** Region the client is created for on first use; the SDK's default chain otherwise. */
@@ -26,42 +27,23 @@ export interface LambderDdbCacheOptions {
26
27
  */
27
28
  now?: () => number;
28
29
  }
29
- /**
30
- * Where a value lives. A plain string addresses one entry, as it always has.
31
- * `{ pk, sk }` puts the entry in a partition it can share with others, so a
32
- * group can be listed or dropped in one call: `{ pk: "division:ist-34", sk:
33
- * "1700:1800" }` keeps every cached window of one division together.
34
- * Only the `pk` part is hashed into the DynamoDB partition key; the sort key
35
- * is stored readable, which is what makes prefix queries possible.
36
- */
37
- export type LambderCacheKey = string | {
38
- pk: string;
39
- sk: string;
40
- };
41
- export interface LambderDdbCacheSetOptions {
42
- ttlSeconds?: number;
43
- }
44
- export interface LambderDdbCacheGetOrSetOptions extends LambderDdbCacheSetOptions {
30
+ export interface LambderDdbCacheGetOrSetOptions extends LambderCacheSetOptions {
31
+ /** How long one container's fill lease on a missing entry holds the others off. Default: 15. */
45
32
  leaseSeconds?: number;
33
+ /** How long a container waits for another's fill before loading itself. Default: (leaseSeconds + 1) * 1000. */
46
34
  waitForFillMs?: number;
47
35
  }
48
- export interface LambderDdbCacheListOptions {
49
- /** Only sort keys starting with this raw (unescaped) prefix. */
50
- prefix?: string;
51
- /** Cap on RESULTS, not on items read: the partition (or prefix range) is read either way. */
52
- limit?: number;
53
- }
54
36
  /**
55
37
  * Persistent JSON cache backed by DynamoDB.
56
38
  *
57
39
  * Values are Brotli-compressed by default (`compression` option; the manifest
58
40
  * records each value's encoding, so the option can be switched on a live
59
41
  * table). Values within the safe DynamoDB item budget are stored directly in
60
- * the manifest for a single-request read; larger values are
61
- * split into versioned binary chunks. A manifest is written only after every
62
- * chunk succeeds, so readers see either the previous complete version or the
63
- * new complete version. DynamoDB TTL is cleanup only; every read also checks
64
- * expiresAt because TTL deletion can lag.
42
+ * the manifest for a single-request read; larger values are split into
43
+ * versioned binary chunks. A manifest is written only after every chunk
44
+ * succeeds, so readers see either the previous complete version or the new
45
+ * one. DynamoDB TTL is cleanup only; every read also checks expiresAt because
46
+ * TTL deletion can lag.
65
47
  *
66
48
  * Table shape: string hash key `pk`, string range key `sk`, TTL on
67
49
  * `expiresAt`. Items are prefixed `CACHE#<namespace>#` by default, so the
@@ -70,12 +52,24 @@ export interface LambderDdbCacheListOptions {
70
52
  *
71
53
  * A key may also be a `{ pk, sk }` pair, which groups entries under one
72
54
  * partition so `deletePartition` and `listSortKeys` can work on the group
73
- * without knowing its members. Plain-string keys keep the exact item layout
74
- * they have always had (`meta`, `lock`, `chunk#...`), and grouped entries
75
- * live beside them under `sk#<encoded sort key>#...`, so both forms can
76
- * share a partition and a live table needs no migration.
55
+ * without knowing its members. Only the `pk` part is hashed into the
56
+ * DynamoDB partition key; the sort key is stored readable, which makes
57
+ * prefix queries possible. Plain-string keys use the bare item keys (`meta`,
58
+ * `chunk#...`) and grouped entries live beside them under
59
+ * `sk#<encoded sort key>#...`, so both forms can share a partition.
60
+ *
61
+ * getOrSet's fill lease lives on the entry's manifest item (see takeLease),
62
+ * and a fill publishes only while its lease is still there. `set` replaces
63
+ * the manifest, and `delete` and `deletePartition` remove it, lease and all,
64
+ * so a fill that started before any of them never stores over it. Both find
65
+ * what to remove on the leader (`delete` by the manifest's own key,
66
+ * `deletePartition` with a consistent Query), since a replica may not have
67
+ * seen a value or a lease the table accepted a moment before.
68
+ *
69
+ * Implements LambderCache, so code typed against the interface runs over
70
+ * LambderMemoryCache in a test.
77
71
  */
78
- export declare class LambderDdbCache {
72
+ export declare class LambderDdbCache implements LambderCache {
79
73
  readonly tableName: string;
80
74
  readonly keyPrefix: string;
81
75
  readonly namespace: string;
@@ -86,41 +80,118 @@ export declare class LambderDdbCache {
86
80
  private readonly compression;
87
81
  private readonly maxValueBytes;
88
82
  private readonly memory;
89
- private readonly inFlight;
83
+ /** getOrSet's single-flight and fail-open, shared with LambderMemoryCache (see LambderCacheFiller). */
84
+ private readonly filler;
90
85
  private readonly now;
86
+ /** This instance's own writes, as its reads and its memory layer need to know them (see LocalWriteLedger). */
87
+ private readonly localWrites;
91
88
  constructor(options: LambderDdbCacheOptions);
92
89
  get<T>(key: LambderCacheKey): Promise<T | undefined>;
93
90
  private getByAddress;
91
+ /**
92
+ * The value a manifest the leader answered describes, its chunks read
93
+ * consistently, or undefined when it fails that read: then it is corrupt,
94
+ * and its manifest is dropped. `overtaken` comes from the read's watch
95
+ * (see LocalWriteLedger).
96
+ */
97
+ private readLeaderEntry;
98
+ /**
99
+ * The value a manifest describes, checked against it and kept in the
100
+ * memory layer unless a write of the key finished while it was read
101
+ * (`overtaken`, see LocalWriteLedger).
102
+ */
103
+ private readEntry;
94
104
  has(key: LambderCacheKey): Promise<boolean>;
95
- set<T>(key: LambderCacheKey, value: T, options?: LambderDdbCacheSetOptions): Promise<void>;
105
+ set<T>(key: LambderCacheKey, value: T, options?: LambderCacheSetOptions): Promise<void>;
106
+ /**
107
+ * Stores the value and hands back what was stored, the parse of its
108
+ * JSON: what every later read answers too.
109
+ *
110
+ * With `leaseOwner` it is a fill publishing under its lease, and the
111
+ * manifest is written only while that lease is still on it. A set,
112
+ * delete or deletePartition since the lease was taken replaced or
113
+ * removed it, and so did a waiter that took it over once it lapsed; the
114
+ * loader may have read its source before any of those, so its value must
115
+ * not land over them. A refused fill deletes the chunks it wrote, which
116
+ * belong to no manifest, and hands its value back uncached. A write
117
+ * winning is the design and is not logged; a takeover is logged, since it
118
+ * means the loader ran past `leaseSeconds`, and while every fill does,
119
+ * each is refused by the next takeover and the entry never fills. The
120
+ * cure is a lease longer than the loader's worst case, which only the
121
+ * caller can give.
122
+ */
96
123
  private setByAddress;
124
+ /**
125
+ * The chunks of the version a manifest write just replaced, which nothing
126
+ * reads any more and which would otherwise sit in the table until their
127
+ * TTL: a large value refreshed hourly leaves a copy an hour. `ownVersion`
128
+ * is the writer's own, which an SDK retry of a write that had already
129
+ * landed reports as the replaced one.
130
+ */
131
+ private deleteReplacedChunks;
132
+ /**
133
+ * One version's chunk items, deleted. The write they belonged to is
134
+ * settled whether or not this succeeds, and the chunks carry their own
135
+ * TTL, so a failure here is logged, not the caller's.
136
+ */
137
+ private deleteChunks;
138
+ /**
139
+ * Removes the entry's manifest item, whatever it holds (a value, or a
140
+ * fill's lease, whose publish is then refused), and its chunks. True when
141
+ * the manifest held a live value: a lease or an expired value the table's
142
+ * TTL has not removed yet is no entry.
143
+ */
97
144
  delete(key: LambderCacheKey): Promise<boolean>;
98
145
  /**
99
146
  * Drop every entry stored under one `pk`, without knowing which sort keys
100
147
  * exist: the invalidation a group of related entries is worth grouping
101
- * for. Returns the number of entries removed. In-memory copies held by
102
- * OTHER Lambda containers still serve until their own TTL, as they do
148
+ * for. Returns the number of live values removed. In-memory copies held
149
+ * by OTHER Lambda containers still serve until their own TTL, as they do
103
150
  * after a single-entry delete.
104
151
  */
105
152
  deletePartition(partition: string): Promise<number>;
106
153
  /**
107
154
  * The live (unexpired) sort keys stored under one `pk`, in table order.
108
155
  * Plain-string entries have no sort key, so they never appear here.
109
- * Reading a partition whose values are chunked also reads those chunk
110
- * items, so grouping very large values makes listing more expensive.
156
+ * The partition (or prefix range) is read whatever the limit, and reading
157
+ * a partition whose values are chunked also reads those chunk items, so
158
+ * grouping very large values makes listing more expensive.
111
159
  */
112
- listSortKeys(partition: string, options?: LambderDdbCacheListOptions): Promise<string[]>;
113
- getOrSet<T>(key: LambderCacheKey, factory: () => Promise<T>, options?: LambderDdbCacheGetOrSetOptions): Promise<T>;
160
+ listSortKeys(partition: string, options?: LambderCacheListOptions): Promise<string[]>;
161
+ getOrSet<T>(key: LambderCacheKey, loader: () => Promise<T>, options?: LambderDdbCacheGetOrSetOptions): Promise<T>;
162
+ /** The fill once a read found nothing: one container loads under the lease while the others wait for its value. */
163
+ private fill;
114
164
  /**
115
- * Cache infrastructure is best-effort for getOrSet: read, lease, or write
116
- * failures return the loader value. Loader failures still propagate and the
117
- * loader is never repeated after it has completed successfully.
165
+ * Takes the fill lease on one entry by writing it onto the entry's
166
+ * manifest item, a manifest with no value that the fill's publish then
167
+ * replaces. Readers find no value on it, so to them it is a miss.
168
+ *
169
+ * The write is conditional on the item holding nothing live: none at
170
+ * all, or one whose expiresAt has passed, whether an expired value or a
171
+ * lapsed lease. So a lease never hides a live value, and a waiter taking
172
+ * over a lapsed lease replaces the first holder's, whose publish is then
173
+ * refused. An expired value the lease replaces goes at once, its chunks
174
+ * with it, and readers see a miss until the fill publishes, as they did
175
+ * from the moment it expired. DynamoDB's TTL removes a lease its holder
176
+ * abandoned.
177
+ *
178
+ * A refusal hands back the item that refused it: "held" for another
179
+ * fill's lease, and for a live value its manifest, which the caller
180
+ * serves the value from. A manifest this instance cannot read (written
181
+ * under another chunkBytes or maxValueBytes) is a miss to every read here
182
+ * and would otherwise block fills until its TTL, so the lease is taken
183
+ * over it, conditioned on it being the same manifest still.
118
184
  */
119
- private getOrSetFailOpen;
120
- private fill;
121
- private acquireLease;
185
+ private takeLease;
186
+ /** Clears this fill's lease off the manifest item, conditional on it still being this fill's, so it never touches what replaced it. */
122
187
  private releaseLease;
123
188
  private readManifest;
189
+ /**
190
+ * The value a manifest item describes, or undefined when it describes
191
+ * none this instance can read: a fill's lease with no value under it
192
+ * yet, or a manifest that does not add up. Expiry is the caller's check.
193
+ */
194
+ private parseManifest;
124
195
  private readChunks;
125
196
  /** Every item matching a partition (optionally a sort-key prefix), following pagination. */
126
197
  private queryItems;
@@ -130,20 +201,14 @@ export declare class LambderDdbCache {
130
201
  /** The JSON text of a stored payload. */
131
202
  private decode;
132
203
  private remember;
133
- private normalizeKey;
134
- private normalizePartition;
135
- /** Length-prefixed so a partition ending in the separator cannot collide with a sort key. */
136
- private memoryKeyOf;
137
204
  private partitionKey;
138
205
  /**
139
- * One of an entry's item keys. A plain-string entry keeps the bare
140
- * suffix it has always used; a grouped one nests under its escaped sort
141
- * key, whose trailing `#` is an unambiguous boundary because an escaped
142
- * sort key never contains a bare `#`.
206
+ * One of an entry's item keys. A plain-string entry uses the bare
207
+ * suffix; a grouped one nests under its escaped sort key, whose trailing
208
+ * `#` is an unambiguous boundary because an escaped sort key never
209
+ * contains a bare `#`.
143
210
  */
144
211
  private itemSortKey;
145
- /** The prefix covering every item of a grouped entry; null for a plain-string entry, which owns the bare item keys instead. */
146
- private entryItemPrefix;
147
212
  private isManifestSortKey;
148
213
  private chunkSortKey;
149
214
  /** Drop every in-memory copy belonging to one partition. */