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
package/dist/mock.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  */
9
9
  export { LambderMockApp, initLambderMock } from "./mock/LambderMockApp.js";
10
10
  export { LambderMockTransportError } from "./mock/LambderMockFailureInjector.js";
11
- export type { LambderMockAppOptions, LambderMockSessionsOptions, LambderMockIdempotencyOptions, LambderMockTransport, LambderMockTransportOptions } from "./mock/LambderMockCreateOptions.js";
11
+ export type { LambderMockAppOptions, LambderMockSessionsOptions, LambderMockIdempotencyOptions, LambderMockInvalidInputAnswer, LambderMockTransport, LambderMockTransportOptions } from "./mock/LambderMockCreateOptions.js";
12
12
  export type { LambderMockCallContext, LambderMockSessionCallContext, LambderMockContext, LambderMockGuards, LambderMockHandler, LambderMockEntry, LambderMockEntryOptions, LambderMockEntryInput, LambderMockSlice, LambderMockRestEntry, LambderMockRegistryCheck, LambderMockMissingNames, LambderMockStrayNames, LambderMockDuplicateNames, LambderMockPublicNames, LambderMockSessionNames, LambderMockLatency, LambderMockFailure, LambderMockFailureReason, LambderMockOutcome, LambderMockCallEvent, LambderMockRequestEvent, LambderMockResponseEvent, LambderMockCallRecord, LambderMockListener, LambderMockRateLimitPolicies, LambderMockInputOf, LambderMockOutputOf, LambderMockOverride, } from "./mock/LambderMockTypes.js";
13
13
  export { lambderMockConsoleLogger } from "./mock/lambderMockConsoleLogger.js";
14
14
  export type { LambderMockConsoleLoggerOptions } from "./mock/lambderMockConsoleLogger.js";
package/dist/mock.js CHANGED
@@ -9,9 +9,8 @@
9
9
  export { LambderMockApp, initLambderMock } from "./mock/LambderMockApp.js";
10
10
  // The four collaborators behind LambderMockApp (the entry registry, the call
11
11
  // recorder, the failure injector, the browser cookies) are deliberately not
12
- // exported: the runtime is reached through the app, and its surface did not
13
- // change when they moved out of it. Only the error a transport rejects with is
14
- // public, as before.
12
+ // exported: the runtime is reached through the app. Only the error a
13
+ // transport rejects with is public.
15
14
  export { LambderMockTransportError } from "./mock/LambderMockFailureInjector.js";
16
15
  export { lambderMockConsoleLogger } from "./mock/lambderMockConsoleLogger.js";
17
16
  export { lambderMockMswHandler } from "./mock/lambderMockMswHandler.js";
@@ -5,10 +5,10 @@ import type LambderSessionManager from "./LambderSessionManager.js";
5
5
  import type { LambderCreatedSession } from "./LambderSessionManager.js";
6
6
  /**
7
7
  * The part of a call this controller touches: the session it reads and
8
- * writes, and the headers it puts Set-Cookie on. Declaring it here is what
9
- * keeps the session layer under the API core rather than beside it: the
10
- * pipeline and both adapters pass their own full call context, which is
11
- * structurally this plus the fields the controller never reads.
8
+ * writes, and the headers it puts Set-Cookie on. Declared here so the session
9
+ * layer sits under the API core rather than beside it: the pipeline and both
10
+ * adapters pass their full call context, which is structurally this plus
11
+ * fields the controller never reads.
12
12
  */
13
13
  export type LambderSessionCallSurface<TSessionData = any> = {
14
14
  session: LambderSessionRecord<TSessionData> | null;
@@ -20,10 +20,9 @@ export type LambderSessionCallSurface<TSessionData = any> = {
20
20
  * one deployment serves several apex domains (return undefined for a
21
21
  * host-only cookie). Changing `domain` or `path` on a live deployment is a
22
22
  * migration: browsers keep the cookie under the old scope beside the new
23
- * one, and both arrive on every request. fetchSession tolerates that by
24
- * scanning every copy for the one live session and evicting the stale
25
- * host-only twin; a copy at a parent domain this host cannot name outlives
26
- * its own Expires.
23
+ * one, and both arrive on every request. fetchSession scans every copy for
24
+ * the one live session and evicts the stale host-only twin; a copy at a
25
+ * parent domain this host cannot name lives until its own Expires.
27
26
  */
28
27
  export type LambderSessionCookieOptions = Pick<LambderCookieOptions, "domain" | "path" | "sameSite" | "secure">;
29
28
  /**
@@ -41,10 +40,9 @@ export type LambderSessionControllerOptions<TSessionData> = {
41
40
  manager: LambderSessionManager<TSessionData>;
42
41
  /**
43
42
  * Name of the session cookie. Required rather than defaulted here: the
44
- * defaults live in shared/wire/LambderSessionCookieNames.ts and are applied
45
- * once, where the app's session options are read, so a second copy of
46
- * them in this constructor would be a second place for them to drift and
47
- * would let a controller read a cookie name the app never writes.
43
+ * defaults (shared/wire/LambderSessionCookieNames.ts) are applied once,
44
+ * where the app's session options are read. A second copy here could
45
+ * drift and have a controller read a cookie name the app never writes.
48
46
  */
49
47
  tokenCookieKey: string;
50
48
  /** Name of the CSRF cookie, required on the same terms as tokenCookieKey. */
@@ -55,40 +53,46 @@ export type LambderSessionControllerOptions<TSessionData> = {
55
53
  request: LambderSessionRequestInfo;
56
54
  };
57
55
  /**
58
- * No session for this request: the cookies named none, or the single session
59
- * they named did not pair with the posted CSRF token.
56
+ * No session for this request: the cookies named none, the single session
57
+ * they named did not pair with the posted CSRF token, they cannot be
58
+ * resolved to one session (LambderSessionAmbiguousError, the one case with a
59
+ * type of its own), or the session was ended while the request held it (a
60
+ * logout or a password change elsewhere, or the dataRefresh callback).
60
61
  *
61
- * Typed rather than a bare Error because fetchSessionIfExists has to tell
62
- * "there is no session here" apart from "something broke". Everything else,
63
- * a TypeError from a custom store, a bug in an app's dataRefresh callback,
64
- * propagates and becomes a crash: answering sessionExpired for a defect makes
65
- * the client clear its cookies and turns somebody's bug into a logout.
62
+ * Typed so fetchSessionIfExists can tell "no session here" from "something
63
+ * broke", and so can every place that answers a request which needed a
64
+ * session and has none (the API pipeline, a route or a hook on the server):
65
+ * each tests for this class, and the ambiguous case with it. Everything else
66
+ * (a TypeError from a custom store, a bug in a dataRefresh callback)
67
+ * propagates as a crash: answering sessionExpired for a defect makes the
68
+ * client clear its cookies and turns a bug into a logout.
66
69
  */
67
70
  export declare class LambderSessionNotFoundError extends Error {
68
71
  constructor(message?: string);
69
72
  }
70
73
  /**
71
74
  * The request's session cookies cannot be resolved to one session, so none of
72
- * them is used and every scope this host can write is cleared. Also a "no
73
- * session" answer to the caller, and deliberately a different type: this one
74
- * carries the clearing Set-Cookie headers that heal the state, and it is the
75
- * one worth finding in a log.
75
+ * them is used and every scope this host can write is cleared. A request with
76
+ * no usable session, so it is a LambderSessionNotFoundError and is answered
77
+ * as one wherever that is (a 401 or the session-expired route answer, the
78
+ * sessionExpired envelope on an API call). The subclass keeps it apart for
79
+ * whoever wants to tell: this case carries the clearing Set-Cookie headers
80
+ * that heal the state, and it is the one worth finding in a log.
76
81
  */
77
- export declare class LambderSessionAmbiguousError extends Error {
82
+ export declare class LambderSessionAmbiguousError extends LambderSessionNotFoundError {
78
83
  constructor(message?: string);
79
84
  }
80
85
  /**
81
86
  * A `__Host-` cookie is the browser's own answer to a sibling subdomain
82
87
  * planting a session cookie at a parent domain: it refuses one that carries a
83
88
  * Domain, so no other host can write it. `__Secure-` is the weaker sibling,
84
- * accepted only on a Secure cookie. Both protections fail silently, though: a
85
- * browser handed a prefixed name with an attribute the prefix forbids simply
86
- * discards the cookie, and the app looks like it has no sessions at all
87
- * rather than like it is misconfigured. So the combinations are rejected at
88
- * creation instead.
89
+ * accepted only on a Secure cookie. Both fail silently: a browser discards a
90
+ * prefixed cookie with an attribute the prefix forbids, and the app looks
91
+ * like it has no sessions rather than like it is misconfigured. So the
92
+ * combinations are rejected at creation.
89
93
  *
90
94
  * Session policy, so it lives beside the controller that writes the cookies
91
- * rather than in the pipeline that happens to call it.
95
+ * rather than in the pipeline that calls it.
92
96
  */
93
97
  export declare const assertSessionCookiePrefixes: (sessions: {
94
98
  tokenCookieKey: string;
@@ -97,11 +101,11 @@ export declare const assertSessionCookiePrefixes: (sessions: {
97
101
  }) => void;
98
102
  /**
99
103
  * Sessions as one request sees them: reads the session the request's
100
- * cookies name onto the context, and writes the cookies a created,
101
- * rotated or ended session needs into the context's response headers.
102
- * Server handlers reach it through lambder.getSessionController(ctx); mock
103
- * handlers through ctx.sessions. It works on the call context and the
104
- * request info alone, so it is one class for both.
104
+ * cookies name onto the context, and writes the cookies a created, rotated
105
+ * or ended session needs into the context's response headers. Server and
106
+ * mock handlers reach it as ctx.sessionController (the server's also through
107
+ * lambder.getSessionController(ctx)); it needs only the call context and
108
+ * request info, so one class serves both.
105
109
  */
106
110
  export default class LambderSessionController<TSessionData = any> {
107
111
  readonly manager: LambderSessionManager<TSessionData>;
@@ -114,48 +118,44 @@ export default class LambderSessionController<TSessionData = any> {
114
118
  /** The configured scope with the domain resolved for this request, or the host-only scope. */
115
119
  private cookieScope;
116
120
  /**
117
- * Both cookies at one expiry, with the raw secrets. They exist only on the
118
- * LambderCreatedSession result, in these cookies and in the request that
119
- * carried them back; the record stores hashes. `csrfToken` is null where
120
- * the raw CSRF value is not known to this request, in which case only the
121
- * session cookie is written: writing a CSRF cookie whose value does not
122
- * pair with the session would break the very session it is refreshing.
121
+ * Both cookies at one expiry, with the raw secrets, which exist only on
122
+ * the LambderCreatedSession result, in these cookies and in requests that
123
+ * carry them back; the record stores hashes. `csrfToken` is null when this
124
+ * request does not know the raw CSRF value, and then only the session
125
+ * cookie is written: a CSRF cookie that does not pair with the session
126
+ * would break the session it is refreshing.
123
127
  */
124
128
  private writeSessionCookies;
125
129
  private setSessionCookies;
126
130
  /**
127
- * The deleting pair for one scope. Written once because a deletion only
128
- * reaches a cookie carrying the same Domain and Path, so the pair is
129
- * emitted per scope and the two callers differ in nothing but which
130
- * scopes they walk.
131
+ * The deleting pair for one scope. A deletion only reaches a cookie with
132
+ * the same Domain and Path, so the pair is emitted per scope; the two
133
+ * callers differ only in which scopes they walk.
131
134
  */
132
135
  private addClearCookiePair;
133
136
  private clearSessionCookies;
134
137
  /**
135
138
  * Every Domain this host is allowed to write the session cookies at: the
136
139
  * host-only scope, the configured one, and each parent domain of the
137
- * request host. A deletion matches only a cookie carrying the same
138
- * Domain, so evicting a copy the app itself never set needs all of them.
139
- * A browser ignores a Domain it will not accept, which is why a suffix
140
- * the registry owns can be offered without checking a public-suffix list.
140
+ * request host. A deletion matches only a cookie with the same Domain, so
141
+ * evicting a copy the app never set needs all of them. A browser ignores
142
+ * a Domain it will not accept, so a registry-owned suffix can be offered
143
+ * without checking a public-suffix list.
141
144
  */
142
145
  private cookieClearDomains;
143
146
  /**
144
- * Clears the session cookies at every scope this host can reach, rather
145
- * than at the one the app configured. Used when a request carries more
146
- * than one live session: the copy that has to go may sit at a parent
147
- * domain a sibling host planted it at, and clearing the configured scope
148
- * alone would evict this visitor's own cookie and leave the planted one
149
- * as the only survivor, which completes the takeover instead of stopping
150
- * it.
147
+ * Clears the session cookies at every scope this host can reach, not just
148
+ * the configured one. Used when a request carries more than one live
149
+ * session: the copy that has to go may sit at a parent domain where a
150
+ * sibling host planted it, and clearing only the configured scope would
151
+ * evict the visitor's own cookie and leave the planted one as the sole
152
+ * survivor, completing the takeover instead of stopping it.
151
153
  */
152
154
  private clearSessionCookiesEverywhere;
153
155
  /**
154
156
  * Refuses a request whose session cookies cannot be resolved to one
155
- * session, clearing every scope this host can write. Clearing only the
156
- * configured scope would be worse than picking one: a deletion matches
157
- * only a cookie carrying the same Domain, so it would evict the visitor's
158
- * own copy and leave a planted one as the sole survivor.
157
+ * session, clearing every scope this host can write (see
158
+ * clearSessionCookiesEverywhere for why not just the configured one).
159
159
  *
160
160
  * Path is the one dimension this cannot sweep: the request info carries
161
161
  * no path, and a deletion matches only a cookie at the same Path, so a
@@ -168,12 +168,11 @@ export default class LambderSessionController<TSessionData = any> {
168
168
  * Both session cookie names read in one pass: every well-formed value
169
169
  * under the token name, and every value under the CSRF name.
170
170
  *
171
- * The CSRF cookie is counted here rather than looked at only when a token
172
- * is checked against it, because it is plantable exactly like the session
173
- * cookie and the browser picks between copies without telling anyone: the
174
- * client reads its CSRF token with js-cookie's Cookies.get, which returns
175
- * the FIRST copy in document.cookie, and a browser orders a longer Path
176
- * first. So a sibling host that plants one CSRF cookie at a parent domain
171
+ * The CSRF cookie is counted, not just checked against a token, because
172
+ * it is plantable like the session cookie and the browser picks between
173
+ * copies silently: the client reads it with js-cookie's Cookies.get, which
174
+ * returns the FIRST copy in document.cookie, and browsers order a longer
175
+ * Path first. A sibling host that plants a CSRF cookie at a parent domain
177
176
  * with a deeper Path decides which token every call posts, and the count
178
177
  * is the only thing that shows it.
179
178
  */
@@ -182,45 +181,65 @@ export default class LambderSessionController<TSessionData = any> {
182
181
  private areRequestSessionTokensValid;
183
182
  createSession(sessionKey: string, data?: TSessionData, ttlInSeconds?: number): Promise<LambderSessionRecord<TSessionData>>;
184
183
  /**
185
- * createSession, handing back the raw tokens beside the session: what a
186
- * test or a mock runtime needs to plant the cookies somewhere else (a
187
- * cookie jar) than this call's response.
184
+ * createSession, handing back the raw tokens beside the session, for a
185
+ * test or mock runtime that plants the cookies somewhere other than this
186
+ * call's response (a cookie jar).
188
187
  */
189
188
  issueSession(sessionKey: string, data?: TSessionData, ttlInSeconds?: number): Promise<LambderCreatedSession<TSessionData>>;
190
189
  regenerateSession(): Promise<LambderSessionRecord<TSessionData>>;
191
190
  /**
192
- * regenerateSession, handing back the raw tokens beside the session, the
193
- * way issueSession does for a new one. Rotating the session mints a new
194
- * CSRF token, and a client that holds its token rather than reading
195
- * document.cookie (a native app, an invoke caller) needs the new one to
196
- * keep calling.
191
+ * regenerateSession, handing back the raw tokens beside the session as
192
+ * issueSession does. Rotation mints a new CSRF token, and a client that
193
+ * holds its token rather than reading document.cookie (a native app, an
194
+ * invoke caller) needs the new one to keep calling.
197
195
  */
198
196
  reissueSession(): Promise<LambderCreatedSession<TSessionData>>;
199
197
  fetchSession(): Promise<LambderSessionRecord<TSessionData>>;
200
198
  /**
201
199
  * Re-issues both cookies at this session's expiry: after a sliding write
202
- * moved it, and beside the host-only eviction above, which would
203
- * otherwise delete a cookie without replacing it.
200
+ * moved it, and beside the host-only eviction, which would otherwise
201
+ * delete a cookie without replacing it.
204
202
  *
205
- * The raw CSRF value is the posted one on an API call, which the pairing
206
- * check above has just matched against this session. A route posts none,
207
- * so the single arriving CSRF cookie stands in, and only once it is known
208
- * to pair: re-issuing an unpaired value would overwrite this visitor's
209
- * real CSRF cookie with a planted one, at the app's own scope, which is
210
- * the takeover the scan exists to prevent. Where neither is available the
211
- * session cookie slides alone, which is the half that decides whether the
212
- * session survives.
203
+ * On an API call the raw CSRF value is the posted one, which the pairing
204
+ * check just matched. A route posts none, so the single arriving CSRF
205
+ * cookie stands in, but only once it is known to pair: re-issuing an
206
+ * unpaired value would overwrite the visitor's real CSRF cookie with a
207
+ * planted one at the app's own scope, the takeover the scan exists to
208
+ * prevent. Where neither is available the session cookie slides alone;
209
+ * it is the half that decides whether the session survives.
213
210
  */
214
211
  private slideSessionCookies;
212
+ /**
213
+ * "No session" for a request whose session cookie names none, or whose
214
+ * session ended while it held it: the context holds none.
215
+ *
216
+ * The cookies are left alone. A deletion matches a cookie by name, not by
217
+ * value, so clearing here would also delete a session another response
218
+ * has just set: a poll sent with the old cookie, answering after a login,
219
+ * a rotation or a password change, would sign the person straight out of
220
+ * the new session. It also keeps the client's own check working, which
221
+ * clears the CSRF cookie only while it still holds the token the call
222
+ * sent. A dead cookie costs a store read per request until it expires.
223
+ */
224
+ private endWithNoSession;
215
225
  fetchSessionIfExists(): Promise<LambderSessionRecord<TSessionData> | null>;
226
+ /**
227
+ * Writes new data onto the current session. Throws
228
+ * LambderSessionNotFoundError when the session was ended while this
229
+ * request held it: the write does not bring it back, and an API call
230
+ * answers sessionExpired.
231
+ */
216
232
  updateSessionData(newData: TSessionData): Promise<LambderSessionRecord<TSessionData>>;
217
233
  /**
218
- * Force-runs the dataRefresh callback now (see the session option of create) and
219
- * persists the result onto the current session. Returns the updated
220
- * session, or null when the callback ended it: the record is deleted and
221
- * the session cookies are cleared.
234
+ * Force-runs the dataRefresh callback now (see the session option of
235
+ * create) and persists the result onto the current session. Throws
236
+ * LambderSessionNotFoundError when the session is over, because the
237
+ * callback ended it (the record is deleted) or because it was ended while
238
+ * this request held it: the same "no session" a read gives for either,
239
+ * with the cookies left alone (see endWithNoSession), and what an API
240
+ * call answers as sessionExpired.
222
241
  */
223
- refreshSessionData(): Promise<LambderSessionRecord<TSessionData> | null>;
242
+ refreshSessionData(): Promise<LambderSessionRecord<TSessionData>>;
224
243
  /**
225
244
  * Deletes every session of the given sessionKey (e.g. a user id): "log
226
245
  * this subject out everywhere". Unlike endSessionAll it needs no fetched