lambder 6.0.1 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2316 -0
- package/README.md +60 -33
- package/dist/api/LambderApiAnswer.d.ts +40 -0
- package/dist/api/LambderApiAnswer.js +19 -0
- package/dist/api/LambderApiCallContext.d.ts +38 -0
- package/dist/api/LambderApiCallContext.js +13 -0
- package/dist/api/LambderApiDefinition.d.ts +18 -0
- package/dist/api/LambderApiDefinition.js +1 -0
- package/dist/api/LambderApiEnvelope.d.ts +67 -0
- package/dist/api/LambderApiEnvelope.js +180 -0
- package/dist/api/LambderApiGuards.d.ts +302 -0
- package/dist/api/LambderApiGuards.js +134 -0
- package/dist/api/LambderApiIdempotency.d.ts +122 -0
- package/dist/api/LambderApiIdempotency.js +330 -0
- package/dist/api/LambderApiPipeline.d.ts +134 -0
- package/dist/api/LambderApiPipeline.js +221 -0
- package/dist/api/LambderApiPolicyEngine.d.ts +36 -0
- package/dist/api/LambderApiPolicyEngine.js +77 -0
- package/dist/api/LambderApiRateLimits.d.ts +206 -0
- package/dist/api/LambderApiRateLimits.js +239 -0
- package/dist/api/LambderApiRequest.d.ts +101 -0
- package/dist/api/LambderApiRequest.js +129 -0
- package/dist/api/LambderApiValidationRefusal.d.ts +32 -0
- package/dist/api/LambderApiValidationRefusal.js +40 -0
- package/dist/client/LambderCaller.d.ts +62 -55
- package/dist/client/LambderCaller.js +147 -90
- package/dist/client/lambderFetchTransport.d.ts +9 -0
- package/dist/client/lambderFetchTransport.js +71 -0
- package/dist/client.d.ts +20 -10
- package/dist/client.js +11 -5
- package/dist/core/Lambder.d.ts +117 -253
- package/dist/core/Lambder.js +374 -341
- package/dist/core/LambderContext.d.ts +54 -44
- package/dist/core/LambderContext.js +41 -110
- package/dist/core/LambderCreateOptions.d.ts +285 -0
- package/dist/core/LambderCreateOptions.js +44 -0
- package/dist/core/LambderFiles.d.ts +1 -45
- package/dist/core/LambderFiles.js +18 -38
- package/dist/core/LambderIndexHtml.d.ts +37 -0
- package/dist/core/LambderIndexHtml.js +87 -0
- package/dist/core/LambderPolicyBuilders.d.ts +17 -0
- package/dist/core/LambderPolicyBuilders.js +16 -0
- package/dist/core/LambderPublicFiles.d.ts +5 -2
- package/dist/core/LambderPublicFiles.js +7 -2
- package/dist/core/LambderResolver.d.ts +8 -6
- package/dist/core/LambderResponse.d.ts +29 -11
- package/dist/core/LambderResponse.js +96 -49
- package/dist/core/LambderResponseBuilder.d.ts +18 -14
- package/dist/core/LambderResponseBuilder.js +19 -25
- package/dist/core/LambderRouting.d.ts +18 -7
- package/dist/core/LambderRouting.js +17 -7
- package/dist/core/LambderTemplatingEngine.d.ts +0 -62
- package/dist/core/LambderTemplatingEngine.js +7 -3
- package/dist/index.d.ts +85 -32
- package/dist/index.js +44 -16
- package/dist/invoke/LambderInvokeCaller.d.ts +46 -139
- package/dist/invoke/LambderInvokeCaller.js +140 -335
- package/dist/invoke/LambderInvokeOutcome.d.ts +165 -0
- package/dist/invoke/LambderInvokeOutcome.js +129 -0
- package/dist/invoke/LambderLambdaEvent.d.ts +81 -0
- package/dist/invoke/LambderLambdaEvent.js +187 -0
- package/dist/invoke/lambderHandlerTransport.d.ts +36 -0
- package/dist/invoke/lambderHandlerTransport.js +89 -0
- package/dist/mock/LambderMockApp.d.ts +352 -0
- package/dist/mock/LambderMockApp.js +815 -0
- package/dist/mock/LambderMockBrowserCookies.d.ts +55 -0
- package/dist/mock/LambderMockBrowserCookies.js +76 -0
- package/dist/mock/LambderMockCallRecorder.d.ts +85 -0
- package/dist/mock/LambderMockCallRecorder.js +183 -0
- package/dist/mock/LambderMockCreateOptions.d.ts +161 -0
- package/dist/mock/LambderMockCreateOptions.js +9 -0
- package/dist/mock/LambderMockEntryRegistry.d.ts +52 -0
- package/dist/mock/LambderMockEntryRegistry.js +126 -0
- package/dist/mock/LambderMockFailureInjector.d.ts +60 -0
- package/dist/mock/LambderMockFailureInjector.js +138 -0
- package/dist/mock/LambderMockTypes.d.ts +421 -0
- package/dist/mock/LambderMockTypes.js +8 -0
- package/dist/mock/lambderMockConsoleLogger.d.ts +16 -0
- package/dist/mock/lambderMockConsoleLogger.js +35 -0
- package/dist/mock/lambderMockInvokeTransport.d.ts +50 -0
- package/dist/mock/lambderMockInvokeTransport.js +52 -0
- package/dist/mock/lambderMockMswHandler.d.ts +99 -0
- package/dist/mock/lambderMockMswHandler.js +126 -0
- package/dist/mock.d.ts +34 -0
- package/dist/mock.js +27 -0
- package/dist/session/LambderSessionController.d.ts +199 -30
- package/dist/session/LambderSessionController.js +396 -82
- package/dist/session/LambderSessionCrypto.d.ts +66 -0
- package/dist/session/LambderSessionCrypto.js +101 -0
- package/dist/session/LambderSessionManager.d.ts +118 -80
- package/dist/session/LambderSessionManager.js +212 -184
- package/dist/shared/LambderI18n.d.ts +6 -6
- package/dist/shared/LambderI18n.js +1 -1
- package/dist/shared/contracts/LambderFileSource.d.ts +33 -0
- package/dist/shared/contracts/LambderFileSource.js +19 -0
- package/dist/shared/contracts/LambderIdempotencyStore.d.ts +66 -0
- package/dist/shared/contracts/LambderIdempotencyStore.js +12 -0
- package/dist/shared/contracts/LambderRateLimiter.d.ts +71 -0
- package/dist/shared/contracts/LambderRateLimiter.js +24 -0
- package/dist/shared/contracts/LambderSessionStore.d.ts +72 -0
- package/dist/shared/contracts/LambderSessionStore.js +13 -0
- package/dist/shared/transport/LambderApiTransport.d.ts +139 -0
- package/dist/shared/transport/LambderApiTransport.js +65 -0
- package/dist/shared/transport/LambderCookieJar.d.ts +121 -0
- package/dist/shared/transport/LambderCookieJar.js +246 -0
- package/dist/shared/transport/lambderCookieJarTransport.d.ts +30 -0
- package/dist/shared/transport/lambderCookieJarTransport.js +60 -0
- package/dist/shared/util/LambderBase64.d.ts +10 -0
- package/dist/shared/util/LambderBase64.js +27 -0
- package/dist/shared/util/LambderCallAbort.d.ts +62 -0
- package/dist/shared/util/LambderCallAbort.js +80 -0
- package/dist/shared/util/LambderClientIp.d.ts +32 -0
- package/dist/shared/util/LambderClientIp.js +56 -0
- package/dist/shared/util/LambderExpiringMap.d.ts +119 -0
- package/dist/shared/util/LambderExpiringMap.js +217 -0
- package/dist/shared/util/LambderKeyFields.d.ts +32 -0
- package/dist/shared/util/LambderKeyFields.js +34 -0
- package/dist/shared/util/LambderNodeModules.d.ts +9 -0
- package/dist/shared/util/LambderNodeModules.js +39 -0
- package/dist/shared/util/LambderOptionChecks.d.ts +17 -0
- package/dist/shared/util/LambderOptionChecks.js +33 -0
- package/dist/shared/util/LambderResponseBrand.d.ts +20 -0
- package/dist/shared/util/LambderResponseBrand.js +18 -0
- package/dist/shared/util/LambderTextDigest.d.ts +17 -0
- package/dist/shared/util/LambderTextDigest.js +34 -0
- package/dist/shared/util/LambderTypeUtilities.d.ts +33 -0
- package/dist/shared/util/LambderTypeUtilities.js +8 -0
- package/dist/shared/wire/LambderAnswerHeaders.d.ts +60 -0
- package/dist/shared/wire/LambderAnswerHeaders.js +94 -0
- package/dist/shared/wire/LambderApiContract.d.ts +129 -0
- package/dist/shared/wire/LambderApiOptionValues.d.ts +39 -0
- package/dist/shared/wire/LambderApiOptionValues.js +11 -0
- package/dist/shared/wire/LambderApiOutcome.d.ts +128 -0
- package/dist/shared/{LambderApiOutcome.js → wire/LambderApiOutcome.js} +16 -9
- package/dist/shared/{LambderApiError.d.ts → wire/LambderApiRefusal.d.ts} +48 -26
- package/dist/shared/{LambderApiError.js → wire/LambderApiRefusal.js} +13 -11
- package/dist/shared/wire/LambderCallOptions.d.ts +171 -0
- package/dist/shared/wire/LambderCallOptions.js +17 -0
- package/dist/shared/{LambderCompressionCodec.d.ts → wire/LambderCompressionCodec.d.ts} +10 -6
- package/dist/shared/{LambderCompressionCodec.js → wire/LambderCompressionCodec.js} +67 -23
- package/dist/shared/{LambderCompressionOption.d.ts → wire/LambderCompressionOption.d.ts} +1 -1
- package/dist/shared/{LambderCompressionOption.js → wire/LambderCompressionOption.js} +3 -4
- package/dist/shared/{LambderCrashDetail.d.ts → wire/LambderCrashDetail.d.ts} +10 -0
- package/dist/shared/{LambderCrashDetail.js → wire/LambderCrashDetail.js} +30 -0
- package/dist/shared/wire/LambderHttpStatus.d.ts +12 -0
- package/dist/shared/wire/LambderHttpStatus.js +1 -0
- package/dist/shared/{LambderRequestPayload.d.ts → wire/LambderRequestPayload.d.ts} +25 -17
- package/dist/shared/{LambderRequestPayload.js → wire/LambderRequestPayload.js} +29 -52
- package/dist/shared/wire/LambderSessionCookieNames.d.ts +9 -0
- package/dist/shared/wire/LambderSessionCookieNames.js +9 -0
- package/dist/stores/LambderDdbCache.d.ts +12 -9
- package/dist/stores/LambderDdbCache.js +56 -47
- package/dist/stores/{LambderDdbIdempotency.d.ts → LambderDdbIdempotencyStore.d.ts} +41 -31
- package/dist/stores/LambderDdbIdempotencyStore.js +319 -0
- package/dist/stores/LambderDdbRateLimiter.d.ts +30 -49
- package/dist/stores/LambderDdbRateLimiter.js +47 -45
- package/dist/stores/LambderDdbSdk.d.ts +83 -6
- package/dist/stores/LambderDdbSdk.js +83 -2
- package/dist/stores/LambderDdbSessionStore.d.ts +65 -0
- package/dist/stores/LambderDdbSessionStore.js +161 -0
- package/dist/stores/LambderHttpFileSource.d.ts +1 -1
- package/dist/stores/LambderHttpFileSource.js +10 -1
- package/dist/stores/LambderLocalFileSource.d.ts +15 -0
- package/dist/stores/LambderLocalFileSource.js +28 -0
- package/dist/stores/LambderMemoryIdempotencyStore.d.ts +63 -0
- package/dist/stores/LambderMemoryIdempotencyStore.js +113 -0
- package/dist/stores/LambderMemoryRateLimiter.d.ts +34 -0
- package/dist/stores/LambderMemoryRateLimiter.js +64 -0
- package/dist/stores/LambderMemorySessionStore.d.ts +48 -0
- package/dist/stores/LambderMemorySessionStore.js +74 -0
- package/dist/stores/LambderS3FileSource.d.ts +1 -1
- package/dist/stores/LambderS3FileSource.js +1 -1
- package/package.json +26 -24
- package/dist/client/LambderMSW.d.ts +0 -69
- package/dist/client/LambderMSW.js +0 -121
- package/dist/policies/LambderApiGuards.d.ts +0 -256
- package/dist/policies/LambderApiGuards.js +0 -94
- package/dist/policies/LambderApiIdempotency.d.ts +0 -58
- package/dist/policies/LambderApiIdempotency.js +0 -219
- package/dist/policies/LambderApiPolicies.d.ts +0 -42
- package/dist/policies/LambderApiPolicies.js +0 -52
- package/dist/policies/LambderApiRateLimits.d.ts +0 -132
- package/dist/policies/LambderApiRateLimits.js +0 -119
- package/dist/shared/LambderApiContract.d.ts +0 -57
- package/dist/shared/LambderApiOutcome.d.ts +0 -69
- package/dist/shared/LambderCallOptions.d.ts +0 -71
- package/dist/shared/LambderCallOptions.js +0 -16
- package/dist/shared/node-polyfills.d.ts +0 -4
- package/dist/shared/node-polyfills.js +0 -58
- package/dist/stores/LambderDdbIdempotency.js +0 -229
- package/dist/testing.d.ts +0 -9
- package/dist/testing.js +0 -8
- /package/dist/shared/{LambderApiContract.js → wire/LambderApiContract.js} +0 -0
- /package/dist/{core → shared/wire}/LambderCookie.d.ts +0 -0
- /package/dist/{core → shared/wire}/LambderCookie.js +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type LambderApiRequest } from "../api/LambderApiRequest.js";
|
|
2
|
+
import type { LambderApiAnswer } from "../api/LambderApiAnswer.js";
|
|
3
|
+
import { LambderCookieJar } from "../shared/transport/LambderCookieJar.js";
|
|
4
|
+
/**
|
|
5
|
+
* The parts of the msw module the adapter uses: `import * as msw from "msw"`.
|
|
6
|
+
*
|
|
7
|
+
* Written so the real package satisfies it, which is the whole point of a
|
|
8
|
+
* structural declaration and was not true of the previous one. msw's resolver
|
|
9
|
+
* answers a Response, or `undefined` to hand the request back (its
|
|
10
|
+
* AsyncResponseResolverReturnType), and a resolver declared to return
|
|
11
|
+
* `Promise<unknown>` is not assignable to that, so `http.post` did not fit
|
|
12
|
+
* here and the handler this returned did not fit `setupWorker`. Both errors
|
|
13
|
+
* landed on the documented five-line wiring.
|
|
14
|
+
*/
|
|
15
|
+
export type LambderMswModule = {
|
|
16
|
+
http: {
|
|
17
|
+
post: (path: string, resolver: (info: {
|
|
18
|
+
request: Request;
|
|
19
|
+
}) => Promise<Response | undefined>) => unknown;
|
|
20
|
+
};
|
|
21
|
+
HttpResponse: {
|
|
22
|
+
new (body?: BodyInit | null, init?: ResponseInit): Response;
|
|
23
|
+
error(): Response;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/** What the adapter needs from the mock app: a parsed request in, an answer out, and the runtime's own bookkeeping. */
|
|
27
|
+
export type LambderMockMswTarget = {
|
|
28
|
+
handleRequest(request: LambderApiRequest): Promise<LambderApiAnswer>;
|
|
29
|
+
/**
|
|
30
|
+
* Whether this name would be answered from the registry, overrides and a
|
|
31
|
+
* registered rest entry included; asked once per request, so not a list to
|
|
32
|
+
* scan.
|
|
33
|
+
*/
|
|
34
|
+
hasRegisteredEntry(apiName: string): boolean;
|
|
35
|
+
/** Records a request this adapter handed on rather than answering. */
|
|
36
|
+
notePassthrough(request: LambderApiRequest): void;
|
|
37
|
+
/** Mirrors an answer's readable cookies into document.cookie, and remembers them for reset(). */
|
|
38
|
+
mirrorCookiesIntoDocument(setCookies: readonly string[]): void;
|
|
39
|
+
/** Takes the jar this adapter built as the runtime's own, so reset() empties it too. */
|
|
40
|
+
adoptCookieJar(jar: LambderCookieJar): void;
|
|
41
|
+
/** The IP a call carrying none is read as arriving from, so this adapter and the direct transport report one address. */
|
|
42
|
+
readonly defaultClientIp: string;
|
|
43
|
+
/**
|
|
44
|
+
* The host the runtime's cookies belong to, which this adapter's jar is
|
|
45
|
+
* scoped by. The runtime's value, not the request URL's: signIn plants at
|
|
46
|
+
* the app's cookieHost and the direct transport's jar sends from there, so
|
|
47
|
+
* an adapter scoping by whatever host the page is served from held the
|
|
48
|
+
* session cookies at a host it never sent them to, and every session call
|
|
49
|
+
* behind the worker answered sessionExpired with a full jar.
|
|
50
|
+
*/
|
|
51
|
+
readonly cookieHost: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* ONE MSW request handler for the whole API path, over the mock app: the
|
|
55
|
+
* opt-in that makes mocked calls appear in the browser's network panel as
|
|
56
|
+
* genuine requests, with real method, status, timing and bodies. The request
|
|
57
|
+
* is read the way the server reads it, its headers and Cookie header
|
|
58
|
+
* included.
|
|
59
|
+
*
|
|
60
|
+
* Session cookies are held in a jar here rather than by the browser, because
|
|
61
|
+
* the browser will not hold them: a response a service worker synthesizes
|
|
62
|
+
* never reaches the cookie store, and MSW's own jar comma-joins the
|
|
63
|
+
* Set-Cookie headers before parsing them, which loses every cookie after the
|
|
64
|
+
* first. So the answer's cookies go into the jar, the next request carries
|
|
65
|
+
* them back, and the ones a page's scripts may see are mirrored into
|
|
66
|
+
* document.cookie. The Set-Cookie headers still travel on the response, where
|
|
67
|
+
* the network panel shows them.
|
|
68
|
+
*
|
|
69
|
+
* Lambder never depends on msw: the app installs it and passes the module
|
|
70
|
+
* in. An injected network failure answers MSW's network error. A POST whose
|
|
71
|
+
* body is not an API envelope is left to other handlers.
|
|
72
|
+
*
|
|
73
|
+
* Generic over the module so the handler keeps msw's own handler type, which
|
|
74
|
+
* is what `setupWorker(...)` and `setupServer(...)` take. Returning `unknown`
|
|
75
|
+
* made the documented wiring an error at the consumer.
|
|
76
|
+
*/
|
|
77
|
+
export declare const lambderMockMswHandler: <M extends LambderMswModule>(mockApp: LambderMockMswTarget, options: {
|
|
78
|
+
msw: M;
|
|
79
|
+
apiPath: string;
|
|
80
|
+
cookieJar?: LambderCookieJar;
|
|
81
|
+
/**
|
|
82
|
+
* What happens to a call the runtime has no entry for. "refuse"
|
|
83
|
+
* (the default) answers the apiNotFound refusal, which is what an
|
|
84
|
+
* exhaustive `register` is for. "passthrough" leaves the request to
|
|
85
|
+
* MSW's other handlers and, failing those, to the network: the shape
|
|
86
|
+
* a partially mocked app runs in while its remaining endpoints still
|
|
87
|
+
* come from a real backend.
|
|
88
|
+
*
|
|
89
|
+
* This and `mockApp.restNotMocked(reason)` are the two answers to the
|
|
90
|
+
* same question, and the rest entry wins: it leaves the runtime with
|
|
91
|
+
* an entry for every name, so nothing is ever unmocked here and a call
|
|
92
|
+
* that would have gone to the network is answered notMocked instead.
|
|
93
|
+
* Pick the rest entry for an app with no backend to reach, and this
|
|
94
|
+
* for one whose remaining endpoints are served by a real one.
|
|
95
|
+
*/
|
|
96
|
+
onUnmocked?: "refuse" | "passthrough";
|
|
97
|
+
/** The client IP its calls are read as arriving from. Default: the runtime's own defaultClientIp. */
|
|
98
|
+
clientIp?: string;
|
|
99
|
+
}) => ReturnType<M["http"]["post"]>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { LambderMockTransportError } from "./LambderMockFailureInjector.js";
|
|
2
|
+
import { readApiEnvelope, cookieValuesByName, lowercaseHeaderNames } from "../api/LambderApiRequest.js";
|
|
3
|
+
import { getAnswerHeader } from "../shared/wire/LambderAnswerHeaders.js";
|
|
4
|
+
import { LambderCookieJar } from "../shared/transport/LambderCookieJar.js";
|
|
5
|
+
import { normalizeClientIp } from "../shared/util/LambderClientIp.js";
|
|
6
|
+
/**
|
|
7
|
+
* ONE MSW request handler for the whole API path, over the mock app: the
|
|
8
|
+
* opt-in that makes mocked calls appear in the browser's network panel as
|
|
9
|
+
* genuine requests, with real method, status, timing and bodies. The request
|
|
10
|
+
* is read the way the server reads it, its headers and Cookie header
|
|
11
|
+
* included.
|
|
12
|
+
*
|
|
13
|
+
* Session cookies are held in a jar here rather than by the browser, because
|
|
14
|
+
* the browser will not hold them: a response a service worker synthesizes
|
|
15
|
+
* never reaches the cookie store, and MSW's own jar comma-joins the
|
|
16
|
+
* Set-Cookie headers before parsing them, which loses every cookie after the
|
|
17
|
+
* first. So the answer's cookies go into the jar, the next request carries
|
|
18
|
+
* them back, and the ones a page's scripts may see are mirrored into
|
|
19
|
+
* document.cookie. The Set-Cookie headers still travel on the response, where
|
|
20
|
+
* the network panel shows them.
|
|
21
|
+
*
|
|
22
|
+
* Lambder never depends on msw: the app installs it and passes the module
|
|
23
|
+
* in. An injected network failure answers MSW's network error. A POST whose
|
|
24
|
+
* body is not an API envelope is left to other handlers.
|
|
25
|
+
*
|
|
26
|
+
* Generic over the module so the handler keeps msw's own handler type, which
|
|
27
|
+
* is what `setupWorker(...)` and `setupServer(...)` take. Returning `unknown`
|
|
28
|
+
* made the documented wiring an error at the consumer.
|
|
29
|
+
*/
|
|
30
|
+
export const lambderMockMswHandler = (mockApp, options) => {
|
|
31
|
+
const { msw, apiPath } = options;
|
|
32
|
+
if (!msw?.http || !msw?.HttpResponse) {
|
|
33
|
+
throw new Error('lambderMockMswHandler requires the msw module: lambderMockMswHandler(mockApp, { apiPath, msw: await import("msw") }). Install it with: npm install msw --save-dev');
|
|
34
|
+
}
|
|
35
|
+
const jar = options.cookieJar ?? new LambderCookieJar();
|
|
36
|
+
// A jar the app passed stays the app's; the one built here is the
|
|
37
|
+
// runtime's, so its reset() empties it along with the sessions those
|
|
38
|
+
// cookies name.
|
|
39
|
+
if (!options.cookieJar)
|
|
40
|
+
mockApp.adoptCookieJar(jar);
|
|
41
|
+
// The runtime's default, not a second one of this adapter's own: an app
|
|
42
|
+
// that set defaultClientIp saw its address through the direct transport
|
|
43
|
+
// and 127.0.0.1 through the service worker, so a per-IP rate limit counted
|
|
44
|
+
// two clients where there was one and the two adapters disagreed about
|
|
45
|
+
// what ctx.request.ip is.
|
|
46
|
+
// Normalized the way every other adapter's is, so one address is one
|
|
47
|
+
// counter under a `per: "ip"` limit however it was spelled.
|
|
48
|
+
const clientIp = normalizeClientIp(options.clientIp ?? mockApp.defaultClientIp);
|
|
49
|
+
const handler = msw.http.post(apiPath, async ({ request }) => {
|
|
50
|
+
let post;
|
|
51
|
+
try {
|
|
52
|
+
post = await request.clone().json();
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
// Through the one header map every adapter builds, which is built on
|
|
58
|
+
// Object.create(null): a header literally named __proto__ was dropped
|
|
59
|
+
// here and landed as an own key on the server, and headers["toString"]
|
|
60
|
+
// handed a guard an inherited function where every other adapter gives
|
|
61
|
+
// undefined.
|
|
62
|
+
const headers = lowercaseHeaderNames(Object.fromEntries(request.headers));
|
|
63
|
+
const url = new URL(request.url);
|
|
64
|
+
// Only the cookies whose scope covers this call, as a browser would
|
|
65
|
+
// send: reading the whole jar sent one host's session to another as
|
|
66
|
+
// soon as a jar was shared across hosts, and read cookies the request
|
|
67
|
+
// path was never in scope for. The host is the runtime's own, the path
|
|
68
|
+
// the one this call is going to. The jar's copies come first: where a
|
|
69
|
+
// name is in both, the jar holds what this runtime last set and the
|
|
70
|
+
// document's copy is the mirror of it, so the jar is the one to
|
|
71
|
+
// believe.
|
|
72
|
+
const cookieScope = { host: mockApp.cookieHost, path: url.pathname };
|
|
73
|
+
const cookies = cookieValuesByName(jar.cookiePairs(cookieScope));
|
|
74
|
+
// Pair by pair, so a name the document holds at two scopes keeps both
|
|
75
|
+
// values and the session controller can weigh them, as it does on
|
|
76
|
+
// the server.
|
|
77
|
+
for (const [name, values] of Object.entries(cookieValuesByName((request.headers.get("cookie") ?? "").split(";")))) {
|
|
78
|
+
for (const value of values) {
|
|
79
|
+
if (!cookies[name]?.includes(value))
|
|
80
|
+
(cookies[name] ??= []).push(value);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const parsed = readApiEnvelope(post, {
|
|
84
|
+
headers, cookies, ip: clientIp, host: url.host, signal: request.signal,
|
|
85
|
+
});
|
|
86
|
+
if (!parsed)
|
|
87
|
+
return undefined;
|
|
88
|
+
// Returning undefined hands the request back to MSW, which tries its
|
|
89
|
+
// other handlers and then the network. Noted on the runtime first:
|
|
90
|
+
// a passthrough that leaves no event and no call-log row is a
|
|
91
|
+
// mistyped endpoint name reaching the real backend in silence.
|
|
92
|
+
if (options.onUnmocked === "passthrough" && !mockApp.hasRegisteredEntry(parsed.apiName)) {
|
|
93
|
+
mockApp.notePassthrough(parsed);
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
let answer;
|
|
97
|
+
try {
|
|
98
|
+
answer = await mockApp.handleRequest(parsed);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
if (err instanceof LambderMockTransportError)
|
|
102
|
+
return msw.HttpResponse.error();
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
105
|
+
const setCookies = getAnswerHeader(answer.headers, "Set-Cookie") ?? [];
|
|
106
|
+
jar.storeSetCookies(setCookies, cookieScope);
|
|
107
|
+
// The cookies a page's own scripts may see are mirrored into
|
|
108
|
+
// document.cookie, so it reads the same in mocked development as it
|
|
109
|
+
// does against the real backend. Not decoration: the browser caller
|
|
110
|
+
// reads the CSRF token from there and posts it on the envelope, so
|
|
111
|
+
// without this every session call fails its CSRF check. Through the
|
|
112
|
+
// runtime, which is where the one mirror implementation lives and
|
|
113
|
+
// where what was planted is remembered for reset().
|
|
114
|
+
mockApp.mirrorCookiesIntoDocument(setCookies);
|
|
115
|
+
const responseHeaders = new Headers();
|
|
116
|
+
for (const [key, values] of Object.entries(answer.headers)) {
|
|
117
|
+
for (const value of values)
|
|
118
|
+
responseHeaders.append(key, value);
|
|
119
|
+
}
|
|
120
|
+
return new msw.HttpResponse(answer.body, { status: answer.statusCode, headers: responseHeaders });
|
|
121
|
+
});
|
|
122
|
+
// The call above is resolved against the constraint, which says `unknown`;
|
|
123
|
+
// what the module actually hands back is its own handler type, and naming
|
|
124
|
+
// it is the whole reason this function is generic.
|
|
125
|
+
return handler;
|
|
126
|
+
};
|
package/dist/mock.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock entry point (`import ... from "lambder/mock"`).
|
|
3
|
+
*
|
|
4
|
+
* The mock runtime: the API core over memory stores, serving a typed
|
|
5
|
+
* contract from mock handlers in development and in tests, in a browser or
|
|
6
|
+
* in Node. Browser-safe like `lambder/client`, and never part of a
|
|
7
|
+
* production bundle by construction: nothing else imports it.
|
|
8
|
+
*/
|
|
9
|
+
export { LambderMockApp, initLambderMock } from "./mock/LambderMockApp.js";
|
|
10
|
+
export { LambderMockTransportError } from "./mock/LambderMockFailureInjector.js";
|
|
11
|
+
export type { LambderMockAppOptions, LambderMockSessionsOptions, LambderMockIdempotencyOptions, LambderMockTransport, LambderMockTransportOptions } from "./mock/LambderMockCreateOptions.js";
|
|
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
|
+
export { lambderMockConsoleLogger } from "./mock/lambderMockConsoleLogger.js";
|
|
14
|
+
export type { LambderMockConsoleLoggerOptions } from "./mock/lambderMockConsoleLogger.js";
|
|
15
|
+
export { lambderMockMswHandler } from "./mock/lambderMockMswHandler.js";
|
|
16
|
+
export type { LambderMswModule, LambderMockMswTarget } from "./mock/lambderMockMswHandler.js";
|
|
17
|
+
export { lambderMockInvokeTransport } from "./mock/lambderMockInvokeTransport.js";
|
|
18
|
+
export type { LambderMockInvokeEvent, LambderMockInvokeResult } from "./mock/lambderMockInvokeTransport.js";
|
|
19
|
+
export { LambderCookieJar } from "./shared/transport/LambderCookieJar.js";
|
|
20
|
+
export { lambderCookieJarTransport } from "./shared/transport/lambderCookieJarTransport.js";
|
|
21
|
+
export type { LambderApiTransport, LambderApiTransportRequest } from "./shared/transport/LambderApiTransport.js";
|
|
22
|
+
export { LambderMemorySessionStore } from "./stores/LambderMemorySessionStore.js";
|
|
23
|
+
export { LambderMemoryRateLimiter } from "./stores/LambderMemoryRateLimiter.js";
|
|
24
|
+
export { LambderMemoryIdempotencyStore } from "./stores/LambderMemoryIdempotencyStore.js";
|
|
25
|
+
export { LambderWebCrypto, LambderPlainSessionCrypto } from "./session/LambderSessionCrypto.js";
|
|
26
|
+
export type { LambderSessionCrypto } from "./session/LambderSessionCrypto.js";
|
|
27
|
+
export { LambderApiRefusal, refuse, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
28
|
+
export type { LambderRefusalMessage } from "./shared/wire/LambderApiRefusal.js";
|
|
29
|
+
export type { LambderApiRequest } from "./api/LambderApiRequest.js";
|
|
30
|
+
export type { LambderApiAnswer } from "./api/LambderApiAnswer.js";
|
|
31
|
+
export type { LambderSessionRecord } from "./shared/contracts/LambderSessionStore.js";
|
|
32
|
+
export type { LambderCreatedSession } from "./session/LambderSessionManager.js";
|
|
33
|
+
export type { default as LambderSessionManager } from "./session/LambderSessionManager.js";
|
|
34
|
+
export type { LambderHttpStatusCode } from "./shared/wire/LambderHttpStatus.js";
|
package/dist/mock.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock entry point (`import ... from "lambder/mock"`).
|
|
3
|
+
*
|
|
4
|
+
* The mock runtime: the API core over memory stores, serving a typed
|
|
5
|
+
* contract from mock handlers in development and in tests, in a browser or
|
|
6
|
+
* in Node. Browser-safe like `lambder/client`, and never part of a
|
|
7
|
+
* production bundle by construction: nothing else imports it.
|
|
8
|
+
*/
|
|
9
|
+
export { LambderMockApp, initLambderMock } from "./mock/LambderMockApp.js";
|
|
10
|
+
// The four collaborators behind LambderMockApp (the entry registry, the call
|
|
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.
|
|
15
|
+
export { LambderMockTransportError } from "./mock/LambderMockFailureInjector.js";
|
|
16
|
+
export { lambderMockConsoleLogger } from "./mock/lambderMockConsoleLogger.js";
|
|
17
|
+
export { lambderMockMswHandler } from "./mock/lambderMockMswHandler.js";
|
|
18
|
+
export { lambderMockInvokeTransport } from "./mock/lambderMockInvokeTransport.js";
|
|
19
|
+
// What a mock setup reaches for beside the app: the stores it runs on, the
|
|
20
|
+
// jar its transport carries, and the refusal a handler says no with.
|
|
21
|
+
export { LambderCookieJar } from "./shared/transport/LambderCookieJar.js";
|
|
22
|
+
export { lambderCookieJarTransport } from "./shared/transport/lambderCookieJarTransport.js";
|
|
23
|
+
export { LambderMemorySessionStore } from "./stores/LambderMemorySessionStore.js";
|
|
24
|
+
export { LambderMemoryRateLimiter } from "./stores/LambderMemoryRateLimiter.js";
|
|
25
|
+
export { LambderMemoryIdempotencyStore } from "./stores/LambderMemoryIdempotencyStore.js";
|
|
26
|
+
export { LambderWebCrypto, LambderPlainSessionCrypto } from "./session/LambderSessionCrypto.js";
|
|
27
|
+
export { LambderApiRefusal, refuse, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { type LambderCookieOptions } from "../shared/wire/LambderCookie.js";
|
|
2
|
+
import type { LambderAnswerHeaders } from "../shared/wire/LambderAnswerHeaders.js";
|
|
3
|
+
import type { LambderSessionRecord } from "../shared/contracts/LambderSessionStore.js";
|
|
3
4
|
import type LambderSessionManager from "./LambderSessionManager.js";
|
|
4
|
-
import {
|
|
5
|
+
import type { LambderCreatedSession } from "./LambderSessionManager.js";
|
|
6
|
+
/**
|
|
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.
|
|
12
|
+
*/
|
|
13
|
+
export type LambderSessionCallSurface<TSessionData = any> = {
|
|
14
|
+
session: LambderSessionRecord<TSessionData> | null;
|
|
15
|
+
responseHeaders: LambderAnswerHeaders;
|
|
16
|
+
};
|
|
5
17
|
/**
|
|
6
18
|
* Scope of the session cookies. `domain` is e.g. ".example.com" to share
|
|
7
19
|
* sessions across subdomains, or a function of the request hostname when
|
|
@@ -9,49 +21,206 @@ import { type LambderSessionContext } from "./LambderSessionManager.js";
|
|
|
9
21
|
* host-only cookie). Changing `domain` or `path` on a live deployment is a
|
|
10
22
|
* migration: browsers keep the cookie under the old scope beside the new
|
|
11
23
|
* one, and both arrive on every request. fetchSession tolerates that by
|
|
12
|
-
*
|
|
13
|
-
* parent domain this host cannot name outlives
|
|
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.
|
|
14
27
|
*/
|
|
15
28
|
export type LambderSessionCookieOptions = Pick<LambderCookieOptions, "domain" | "path" | "sameSite" | "secure">;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
/**
|
|
30
|
+
* What the controller reads off the request: the host (cookie domain
|
|
31
|
+
* resolution), every value of every cookie, and the CSRF token the caller
|
|
32
|
+
* posted, or null when the request is not an API call (a route), in which
|
|
33
|
+
* case no CSRF check applies.
|
|
34
|
+
*/
|
|
35
|
+
export type LambderSessionRequestInfo = {
|
|
36
|
+
host: string;
|
|
37
|
+
cookies: Record<string, string[]>;
|
|
38
|
+
csrfToken: string | null;
|
|
39
|
+
};
|
|
40
|
+
export type LambderSessionControllerOptions<TSessionData> = {
|
|
41
|
+
manager: LambderSessionManager<TSessionData>;
|
|
42
|
+
/**
|
|
43
|
+
* 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.
|
|
48
|
+
*/
|
|
49
|
+
tokenCookieKey: string;
|
|
50
|
+
/** Name of the CSRF cookie, required on the same terms as tokenCookieKey. */
|
|
51
|
+
csrfCookieKey: string;
|
|
52
|
+
cookieOptions?: LambderSessionCookieOptions;
|
|
53
|
+
/** The call context the session is read onto and whose responseHeaders receive the cookies. */
|
|
54
|
+
ctx: LambderSessionCallSurface<TSessionData>;
|
|
55
|
+
request: LambderSessionRequestInfo;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
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.
|
|
60
|
+
*
|
|
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.
|
|
66
|
+
*/
|
|
67
|
+
export declare class LambderSessionNotFoundError extends Error {
|
|
68
|
+
constructor(message?: string);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 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.
|
|
76
|
+
*/
|
|
77
|
+
export declare class LambderSessionAmbiguousError extends Error {
|
|
78
|
+
constructor(message?: string);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A `__Host-` cookie is the browser's own answer to a sibling subdomain
|
|
82
|
+
* planting a session cookie at a parent domain: it refuses one that carries a
|
|
83
|
+
* 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
|
+
*
|
|
90
|
+
* Session policy, so it lives beside the controller that writes the cookies
|
|
91
|
+
* rather than in the pipeline that happens to call it.
|
|
92
|
+
*/
|
|
93
|
+
export declare const assertSessionCookiePrefixes: (sessions: {
|
|
94
|
+
tokenCookieKey: string;
|
|
95
|
+
csrfCookieKey: string;
|
|
20
96
|
cookieOptions: LambderSessionCookieOptions;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
97
|
+
}) => void;
|
|
98
|
+
/**
|
|
99
|
+
* 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.
|
|
105
|
+
*/
|
|
106
|
+
export default class LambderSessionController<TSessionData = any> {
|
|
107
|
+
readonly manager: LambderSessionManager<TSessionData>;
|
|
108
|
+
readonly tokenCookieKey: string;
|
|
109
|
+
readonly csrfCookieKey: string;
|
|
110
|
+
readonly cookieOptions: LambderSessionCookieOptions;
|
|
111
|
+
private readonly ctx;
|
|
112
|
+
private readonly request;
|
|
113
|
+
constructor({ manager, tokenCookieKey, csrfCookieKey, cookieOptions, ctx, request }: LambderSessionControllerOptions<TSessionData>);
|
|
29
114
|
/** The configured scope with the domain resolved for this request, or the host-only scope. */
|
|
30
115
|
private cookieScope;
|
|
31
|
-
/**
|
|
116
|
+
/**
|
|
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.
|
|
123
|
+
*/
|
|
124
|
+
private writeSessionCookies;
|
|
32
125
|
private setSessionCookies;
|
|
126
|
+
/**
|
|
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
|
+
*/
|
|
132
|
+
private addClearCookiePair;
|
|
33
133
|
private clearSessionCookies;
|
|
34
134
|
/**
|
|
35
|
-
* Every
|
|
36
|
-
*
|
|
37
|
-
*
|
|
135
|
+
* Every Domain this host is allowed to write the session cookies at: the
|
|
136
|
+
* 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.
|
|
141
|
+
*/
|
|
142
|
+
private cookieClearDomains;
|
|
143
|
+
/**
|
|
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.
|
|
151
|
+
*/
|
|
152
|
+
private clearSessionCookiesEverywhere;
|
|
153
|
+
/**
|
|
154
|
+
* 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.
|
|
159
|
+
*
|
|
160
|
+
* Path is the one dimension this cannot sweep: the request info carries
|
|
161
|
+
* no path, and a deletion matches only a cookie at the same Path, so a
|
|
162
|
+
* copy planted at a deeper path stays out of reach. A `__Host-` cookie
|
|
163
|
+
* name is the structural answer, since the prefix forbids Domain and
|
|
164
|
+
* pins Path to "/"; see docs/sessions.md.
|
|
38
165
|
*/
|
|
39
|
-
private
|
|
166
|
+
private refuseAmbiguousSession;
|
|
167
|
+
/**
|
|
168
|
+
* Both session cookie names read in one pass: every well-formed value
|
|
169
|
+
* under the token name, and every value under the CSRF name.
|
|
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
|
|
177
|
+
* with a deeper Path decides which token every call posts, and the count
|
|
178
|
+
* is the only thing that shows it.
|
|
179
|
+
*/
|
|
180
|
+
private scanSessionCookies;
|
|
181
|
+
/** An API call must also carry a CSRF token; a route only needs the cookie. */
|
|
40
182
|
private areRequestSessionTokensValid;
|
|
41
|
-
createSession(sessionKey: string, data?: TSessionData, ttlInSeconds?: number): Promise<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
183
|
+
createSession(sessionKey: string, data?: TSessionData, ttlInSeconds?: number): Promise<LambderSessionRecord<TSessionData>>;
|
|
184
|
+
/**
|
|
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.
|
|
188
|
+
*/
|
|
189
|
+
issueSession(sessionKey: string, data?: TSessionData, ttlInSeconds?: number): Promise<LambderCreatedSession<TSessionData>>;
|
|
190
|
+
regenerateSession(): Promise<LambderSessionRecord<TSessionData>>;
|
|
191
|
+
/**
|
|
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.
|
|
197
|
+
*/
|
|
198
|
+
reissueSession(): Promise<LambderCreatedSession<TSessionData>>;
|
|
199
|
+
fetchSession(): Promise<LambderSessionRecord<TSessionData>>;
|
|
200
|
+
/**
|
|
201
|
+
* 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.
|
|
204
|
+
*
|
|
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.
|
|
213
|
+
*/
|
|
214
|
+
private slideSessionCookies;
|
|
215
|
+
fetchSessionIfExists(): Promise<LambderSessionRecord<TSessionData> | null>;
|
|
216
|
+
updateSessionData(newData: TSessionData): Promise<LambderSessionRecord<TSessionData>>;
|
|
48
217
|
/**
|
|
49
218
|
* Force-runs the dataRefresh callback now (see the session option of create) and
|
|
50
219
|
* persists the result onto the current session. Returns the updated
|
|
51
220
|
* session, or null when the callback ended it: the record is deleted and
|
|
52
221
|
* the session cookies are cleared.
|
|
53
222
|
*/
|
|
54
|
-
refreshSessionData(): Promise<
|
|
223
|
+
refreshSessionData(): Promise<LambderSessionRecord<TSessionData> | null>;
|
|
55
224
|
/**
|
|
56
225
|
* Deletes every session of the given sessionKey (e.g. a user id): "log
|
|
57
226
|
* this subject out everywhere". Unlike endSessionAll it needs no fetched
|