lambder 7.2.5 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1021 -3
- package/README.md +43 -21
- package/dist/api/LambderApiAnswer.d.ts +18 -22
- package/dist/api/LambderApiAnswer.js +6 -7
- package/dist/api/LambderApiCallContext.d.ts +21 -8
- package/dist/api/LambderApiCallContext.js +22 -4
- package/dist/api/LambderApiDefinition.d.ts +4 -3
- package/dist/api/LambderApiEnvelope.d.ts +14 -9
- package/dist/api/LambderApiEnvelope.js +33 -34
- package/dist/api/LambderApiGuards.d.ts +78 -51
- package/dist/api/LambderApiGuards.js +34 -36
- package/dist/api/LambderApiIdempotency.d.ts +74 -61
- package/dist/api/LambderApiIdempotency.js +226 -151
- package/dist/api/LambderApiOutputValidationError.d.ts +32 -0
- package/dist/api/LambderApiOutputValidationError.js +50 -0
- package/dist/api/LambderApiPipeline.d.ts +77 -39
- package/dist/api/LambderApiPipeline.js +135 -62
- package/dist/api/LambderApiRateLimits.d.ts +208 -54
- package/dist/api/LambderApiRateLimits.js +197 -108
- package/dist/api/LambderApiRequest.d.ts +27 -21
- package/dist/api/LambderApiRequest.js +26 -19
- package/dist/api/LambderApiSignature.d.ts +12 -15
- package/dist/api/LambderApiSignature.js +28 -51
- package/dist/api/LambderApiValidationRefusal.d.ts +9 -9
- package/dist/api/LambderApiValidationRefusal.js +10 -10
- package/dist/build/freshProcessVerifier.d.ts +13 -0
- package/dist/build/freshProcessVerifier.js +19 -0
- package/dist/build/writeApiSignatures.d.ts +109 -0
- package/dist/build/writeApiSignatures.js +222 -0
- package/dist/build.d.ts +9 -0
- package/dist/build.js +8 -0
- package/dist/client/LambderCaller.d.ts +13 -44
- package/dist/client/LambderCaller.js +77 -84
- package/dist/client/LambderReloadLoopBreaker.d.ts +56 -26
- package/dist/client/LambderReloadLoopBreaker.js +90 -46
- package/dist/client/lambderFetchTransport.d.ts +4 -1
- package/dist/client/lambderFetchTransport.js +52 -28
- package/dist/client.d.ts +5 -3
- package/dist/client.js +2 -1
- package/dist/core/Lambder.d.ts +161 -69
- package/dist/core/Lambder.js +370 -226
- package/dist/core/LambderContext.d.ts +82 -15
- package/dist/core/LambderContext.js +107 -20
- package/dist/core/LambderCors.d.ts +21 -3
- package/dist/core/LambderCors.js +35 -16
- package/dist/core/LambderCrashHandling.d.ts +40 -0
- package/dist/core/LambderCrashHandling.js +97 -0
- package/dist/core/LambderCreateOptions.d.ts +151 -75
- package/dist/core/LambderCreateOptions.js +16 -23
- package/dist/core/LambderFiles.d.ts +28 -7
- package/dist/core/LambderFiles.js +73 -33
- package/dist/core/LambderIndexHtml.js +12 -11
- package/dist/core/LambderPolicyBuilders.d.ts +17 -5
- package/dist/core/LambderPolicyBuilders.js +17 -5
- package/dist/core/LambderPublicFiles.d.ts +11 -5
- package/dist/core/LambderPublicFiles.js +32 -4
- package/dist/core/LambderRequestPath.d.ts +43 -0
- package/dist/core/LambderRequestPath.js +63 -0
- package/dist/core/LambderResponse.d.ts +26 -5
- package/dist/core/LambderResponse.js +157 -70
- package/dist/core/LambderResponseBuilder.d.ts +49 -4
- package/dist/core/LambderResponseBuilder.js +64 -3
- package/dist/core/LambderRouting.d.ts +2 -3
- package/dist/core/LambderRouting.js +22 -7
- package/dist/core/LambderTemplatingEngine.js +211 -32
- package/dist/index.d.ts +15 -8
- package/dist/index.js +5 -4
- package/dist/invoke/LambderInvokeCaller.d.ts +37 -42
- package/dist/invoke/LambderInvokeCaller.js +76 -66
- package/dist/invoke/LambderInvokeOutcome.d.ts +27 -26
- package/dist/invoke/LambderInvokeOutcome.js +9 -22
- package/dist/invoke/LambderLambdaEvent.d.ts +44 -10
- package/dist/invoke/LambderLambdaEvent.js +80 -37
- package/dist/invoke/lambderHandlerTransport.d.ts +12 -10
- package/dist/invoke/lambderHandlerTransport.js +16 -19
- package/dist/mock/LambderMockApp.d.ts +67 -83
- package/dist/mock/LambderMockApp.js +167 -153
- package/dist/mock/LambderMockBrowserCookies.d.ts +24 -28
- package/dist/mock/LambderMockBrowserCookies.js +24 -28
- package/dist/mock/LambderMockCallRecorder.d.ts +15 -22
- package/dist/mock/LambderMockCallRecorder.js +19 -28
- package/dist/mock/LambderMockCreateOptions.d.ts +42 -24
- package/dist/mock/LambderMockEntryRegistry.d.ts +11 -12
- package/dist/mock/LambderMockEntryRegistry.js +24 -29
- package/dist/mock/LambderMockFailureInjector.d.ts +3 -6
- package/dist/mock/LambderMockFailureInjector.js +3 -6
- package/dist/mock/LambderMockTypes.d.ts +78 -108
- package/dist/mock/lambderMockInvokeTransport.d.ts +11 -13
- package/dist/mock/lambderMockInvokeTransport.js +11 -10
- package/dist/mock/lambderMockMswHandler.d.ts +33 -29
- package/dist/mock/lambderMockMswHandler.js +50 -39
- package/dist/mock.d.ts +3 -1
- package/dist/mock.js +5 -3
- package/dist/session/LambderSessionController.d.ts +108 -89
- package/dist/session/LambderSessionController.js +187 -168
- package/dist/session/LambderSessionCrypto.d.ts +16 -7
- package/dist/session/LambderSessionCrypto.js +26 -12
- package/dist/session/LambderSessionManager.d.ts +136 -47
- package/dist/session/LambderSessionManager.js +280 -139
- package/dist/shared/LambderHtml.d.ts +42 -3
- package/dist/shared/LambderHtml.js +127 -7
- package/dist/shared/LambderHtmlPositions.d.ts +173 -0
- package/dist/shared/LambderHtmlPositions.js +652 -0
- package/dist/shared/LambderI18n.d.ts +10 -11
- package/dist/shared/LambderI18n.js +33 -21
- package/dist/shared/contracts/LambderCache.d.ts +66 -0
- package/dist/shared/contracts/LambderCache.js +11 -0
- package/dist/shared/contracts/LambderFileSource.d.ts +6 -6
- package/dist/shared/contracts/LambderFileSource.js +5 -8
- package/dist/shared/contracts/LambderIdempotencyStore.d.ts +51 -22
- package/dist/shared/contracts/LambderIdempotencyStore.js +4 -5
- package/dist/shared/contracts/LambderRateLimiter.d.ts +27 -15
- package/dist/shared/contracts/LambderRateLimiter.js +4 -5
- package/dist/shared/contracts/LambderSessionStore.d.ts +65 -26
- package/dist/shared/contracts/LambderSessionStore.js +5 -6
- package/dist/shared/transport/LambderApiTransport.d.ts +27 -27
- package/dist/shared/transport/LambderApiTransport.js +7 -7
- package/dist/shared/transport/LambderCookieJar.d.ts +28 -35
- package/dist/shared/transport/LambderCookieJar.js +54 -66
- package/dist/shared/transport/lambderCookieJarTransport.d.ts +11 -13
- package/dist/shared/transport/lambderCookieJarTransport.js +24 -23
- package/dist/shared/util/LambderCallAbort.d.ts +5 -5
- package/dist/shared/util/LambderCallAbort.js +5 -5
- package/dist/shared/util/LambderClientIp.d.ts +27 -11
- package/dist/shared/util/LambderClientIp.js +96 -13
- package/dist/shared/util/LambderExpiringMap.d.ts +35 -49
- package/dist/shared/util/LambderExpiringMap.js +41 -57
- package/dist/shared/util/LambderNodeModules.js +6 -7
- package/dist/shared/util/LambderOptionChecks.d.ts +4 -4
- package/dist/shared/util/LambderOptionChecks.js +4 -4
- package/dist/shared/util/LambderResponseBrand.d.ts +5 -5
- package/dist/shared/util/LambderResponseBrand.js +5 -5
- package/dist/shared/util/LambderTestingDoors.d.ts +29 -0
- package/dist/shared/util/LambderTestingDoors.js +29 -0
- package/dist/shared/util/LambderTypeUtilities.d.ts +7 -8
- package/dist/shared/util/LambderTypeUtilities.js +3 -3
- package/dist/shared/util/boundKeyField.d.ts +20 -0
- package/dist/shared/util/boundKeyField.js +34 -0
- package/dist/shared/util/canonicalJson.d.ts +11 -0
- package/dist/shared/util/canonicalJson.js +28 -0
- package/dist/shared/util/joinKeyFields.d.ts +20 -0
- package/dist/shared/util/joinKeyFields.js +22 -0
- package/dist/shared/wire/LambderAnswerHeaders.d.ts +12 -16
- package/dist/shared/wire/LambderAnswerHeaders.js +12 -16
- package/dist/shared/wire/LambderApiContract.d.ts +107 -32
- package/dist/shared/wire/LambderApiOutcome.d.ts +43 -31
- package/dist/shared/wire/LambderApiOutcome.js +48 -23
- package/dist/shared/wire/LambderApiRefusal.d.ts +39 -27
- package/dist/shared/wire/LambderApiRefusal.js +36 -7
- package/dist/shared/wire/LambderApiSignature.d.ts +18 -22
- package/dist/shared/wire/LambderApiSignature.js +16 -19
- package/dist/shared/wire/LambderCallOptions.d.ts +38 -47
- package/dist/shared/wire/LambderCallOptions.js +9 -11
- package/dist/shared/wire/LambderCompressionCodec.d.ts +29 -34
- package/dist/shared/wire/LambderCompressionCodec.js +31 -36
- package/dist/shared/wire/LambderCompressionOption.d.ts +9 -9
- package/dist/shared/wire/LambderCompressionOption.js +9 -9
- package/dist/shared/wire/LambderCrashDetail.d.ts +12 -15
- package/dist/shared/wire/LambderCrashDetail.js +12 -15
- package/dist/shared/wire/LambderDefaultApiPath.d.ts +6 -0
- package/dist/shared/wire/LambderDefaultApiPath.js +6 -0
- package/dist/shared/wire/LambderHttpStatus.d.ts +6 -7
- package/dist/shared/wire/LambderIdempotencyKeyScope.d.ts +89 -0
- package/dist/shared/wire/LambderIdempotencyKeyScope.js +146 -0
- package/dist/shared/wire/LambderInvokeApiId.d.ts +27 -0
- package/dist/shared/wire/LambderInvokeApiId.js +27 -0
- package/dist/shared/wire/LambderOutcomeAssertions.d.ts +79 -0
- package/dist/shared/wire/LambderOutcomeAssertions.js +112 -0
- package/dist/shared/wire/LambderRequestPayload.d.ts +18 -20
- package/dist/shared/wire/LambderRequestPayload.js +4 -6
- package/dist/stores/LambderCacheFiller.d.ts +48 -0
- package/dist/stores/LambderCacheFiller.js +119 -0
- package/dist/stores/LambderCacheKeys.d.ts +26 -0
- package/dist/stores/LambderCacheKeys.js +54 -0
- package/dist/stores/LambderCacheValues.d.ts +45 -0
- package/dist/stores/LambderCacheValues.js +74 -0
- package/dist/stores/LambderDdbCache.d.ts +121 -56
- package/dist/stores/LambderDdbCache.js +528 -225
- package/dist/stores/LambderDdbIdempotencyStore.d.ts +33 -22
- package/dist/stores/LambderDdbIdempotencyStore.js +75 -50
- package/dist/stores/LambderDdbRateLimiter.d.ts +76 -20
- package/dist/stores/LambderDdbRateLimiter.js +151 -39
- package/dist/stores/LambderDdbSdk.d.ts +43 -31
- package/dist/stores/LambderDdbSdk.js +79 -33
- package/dist/stores/LambderDdbSessionStore.d.ts +27 -14
- package/dist/stores/LambderDdbSessionStore.js +119 -47
- package/dist/stores/LambderHttpFileSource.d.ts +15 -6
- package/dist/stores/LambderHttpFileSource.js +15 -13
- package/dist/stores/LambderMemoryCache.d.ts +49 -0
- package/dist/stores/LambderMemoryCache.js +113 -0
- package/dist/stores/LambderMemoryIdempotencyStore.d.ts +13 -12
- package/dist/stores/LambderMemoryIdempotencyStore.js +31 -30
- package/dist/stores/LambderMemoryRateLimiter.d.ts +8 -9
- package/dist/stores/LambderMemoryRateLimiter.js +14 -13
- package/dist/stores/LambderMemorySessionStore.d.ts +14 -11
- package/dist/stores/LambderMemorySessionStore.js +38 -19
- package/dist/stores/LambderS3FileSource.d.ts +21 -6
- package/dist/stores/LambderS3FileSource.js +12 -7
- package/dist/testing/LambderTestApp.d.ts +176 -0
- package/dist/testing/LambderTestApp.js +204 -0
- package/dist/testing/LambderTestVisitor.d.ts +153 -0
- package/dist/testing/LambderTestVisitor.js +154 -0
- package/dist/testing.d.ts +27 -0
- package/dist/testing.js +24 -0
- package/package.json +20 -3
- package/dist/api/LambderApiPolicyEngine.d.ts +0 -36
- package/dist/api/LambderApiPolicyEngine.js +0 -77
- package/dist/shared/util/LambderKeyFields.d.ts +0 -32
- package/dist/shared/util/LambderKeyFields.js +0 -34
package/dist/core/Lambder.d.ts
CHANGED
|
@@ -9,16 +9,27 @@ import type LambderSessionController from "../session/LambderSessionController.j
|
|
|
9
9
|
import { type LambderPublicFilesOptions } from "./LambderPublicFiles.js";
|
|
10
10
|
import { type LambderIndexHtmlOptions } from "./LambderIndexHtml.js";
|
|
11
11
|
import { LambderFiles } from "./LambderFiles.js";
|
|
12
|
+
import { type LambderPipelineBackends, type LambderPipelineBackendSwap } from "../api/LambderApiPipeline.js";
|
|
13
|
+
import type { LambderFileSource } from "../shared/contracts/LambderFileSource.js";
|
|
14
|
+
import { LAMBDER_BACKEND_SWAP, LAMBDER_CRASH_WATCH } from "../shared/util/LambderTestingDoors.js";
|
|
12
15
|
import { type LambderApiSignatureEntry } from "../api/LambderApiSignature.js";
|
|
13
16
|
import { type LambderApiSignatureMap } from "../shared/wire/LambderApiSignature.js";
|
|
14
17
|
import type { LambderApiIdempotencyOption } from "../shared/wire/LambderApiOptionValues.js";
|
|
15
18
|
import type { LambderApiGuard, LambderGuardMetaMap, LambderGuardsOption, LambderGuardDataOf, LambderGuardInputsOf } from "../api/LambderApiGuards.js";
|
|
16
19
|
import type { LambderApiRateLimitPolicyConfig, LambderRateLimitOption } from "../api/LambderApiRateLimits.js";
|
|
17
20
|
import type { LambderApiIdempotencyConfig } from "../api/LambderApiIdempotency.js";
|
|
18
|
-
import type { LambderContractEntry, LambderMergeContract } from "../shared/wire/LambderApiContract.js";
|
|
21
|
+
import type { LambderContractEntry, LambderJsonOutputOf, LambderMergeContract } from "../shared/wire/LambderApiContract.js";
|
|
19
22
|
import { type LambderHttpEvent, type LambderRenderContext, type LambderSessionRenderContext } from "./LambderContext.js";
|
|
20
23
|
import type { MaybePromise } from "../shared/util/LambderTypeUtilities.js";
|
|
21
24
|
import { type LambderRouteHandler, type LambderInputValidationHandler, type LambderFallbackHandler, type LambderGlobalErrorHandler, type LambderAfterRenderHook, type LambderBeforeRenderHook, type LambderFallbackHook, type LambderActionTools, type LambderCreateOptions, type LambderGivenOption, type LambderHandler, type LambderNestedOptionChecks, type LambderNoExtraKeys, type LambderRequirableGuardsField, type LambderSessionEnabledInstance, type LambderSessionRouteHandler } from "./LambderCreateOptions.js";
|
|
25
|
+
/** Everything `lambder/testing` may put under a built instance: the pipeline's stores, and the source its files are read from. */
|
|
26
|
+
export type LambderInstanceBackends = LambderPipelineBackends & {
|
|
27
|
+
fileSource?: LambderFileSource;
|
|
28
|
+
};
|
|
29
|
+
/** What the instance had a place for; see LambderPipelineBackendSwap. `files` is false on an instance created without the files option. */
|
|
30
|
+
export type LambderInstanceBackendSwap = LambderPipelineBackendSwap & {
|
|
31
|
+
files: boolean;
|
|
32
|
+
};
|
|
22
33
|
/**
|
|
23
34
|
* The "created" hook: run once the instance exists, with the instance. It is
|
|
24
35
|
* declared here rather than beside the other hooks in LambderCreateOptions
|
|
@@ -39,7 +50,7 @@ export type LambderCreatedHook = (lambderInstance: Lambder<any, any, any, any, a
|
|
|
39
50
|
* @typeParam _TIdempotencyEnabled - @internal True when create() received idempotency (do not pass manually)
|
|
40
51
|
* @typeParam _TSessionGuardsRequired - @internal True when create() received requireSessionApiGuards (do not pass manually)
|
|
41
52
|
* @typeParam _TPublicGuardsRequired - @internal True when create() received requirePublicApiGuards (do not pass manually)
|
|
42
|
-
* @typeParam _TSessionsEnabled - @internal True when create() received the session option (do not pass manually).
|
|
53
|
+
* @typeParam _TSessionsEnabled - @internal True when create() received the session option (do not pass manually). Defaults to true, unlike its siblings, so a plugin annotating its parameter as the bare Lambder<SessionData> can still register session APIs. create() knows the option and supplies the false; `new Lambder(...)` relies on the registration-time throw alone.
|
|
43
54
|
*
|
|
44
55
|
* @example
|
|
45
56
|
* ```typescript
|
|
@@ -57,15 +68,15 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
57
68
|
/** The instance's file reader (source + caches), or null without the files option. */
|
|
58
69
|
files: LambderFiles | null;
|
|
59
70
|
/**
|
|
60
|
-
* Type property for extracting the API contract
|
|
61
|
-
*
|
|
71
|
+
* Type property for extracting the API contract, to export your API
|
|
72
|
+
* types to the frontend.
|
|
62
73
|
*
|
|
63
74
|
* Export it as an interface extending LambderFlattenContract, not as a
|
|
64
75
|
* type alias. Chaining builds the contract as an intersection one member
|
|
65
|
-
* deep per endpoint
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
76
|
+
* deep per endpoint; an interface collapses that into one declared set of
|
|
77
|
+
* members, which every generic read of the contract (a mock registry, a
|
|
78
|
+
* needs map, the typed caller) checks far more cheaply. See
|
|
79
|
+
* LambderFlattenContract for the measurements.
|
|
69
80
|
*
|
|
70
81
|
* @example
|
|
71
82
|
* ```typescript
|
|
@@ -95,24 +106,37 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
95
106
|
private corsConfig;
|
|
96
107
|
private finalizeOptions;
|
|
97
108
|
private requireSessionApiGuards;
|
|
109
|
+
/** Told what a request threw, beside whatever answers it; null outside a test. See LAMBDER_CRASH_WATCH. */
|
|
110
|
+
private crashWatcher;
|
|
111
|
+
/** The crashes option applied: reporting, and the framework's own 500. */
|
|
112
|
+
private readonly crashHandling;
|
|
113
|
+
/** What this instance binds onto every context it renders (ctx.sessionController, ctx.rateLimit, ctx.isRateLimited). */
|
|
114
|
+
private readonly contextTools;
|
|
98
115
|
private readonly trustedClientIpHeaders;
|
|
116
|
+
private readonly trustedHostHeaders;
|
|
99
117
|
private requirePublicApiGuards;
|
|
100
118
|
constructor(options?: LambderCreateOptions<TSessionData>);
|
|
101
119
|
setRouteFallbackHandler(routeFallbackHandler: LambderFallbackHandler): this;
|
|
102
120
|
setApiFallbackHandler(apiFallbackHandler: LambderFallbackHandler): this;
|
|
103
121
|
setApiInputValidationErrorHandler(apiInputValidationErrorHandler: LambderInputValidationHandler): this;
|
|
104
122
|
setGlobalErrorHandler(globalErrorHandler: LambderGlobalErrorHandler): this;
|
|
105
|
-
/**
|
|
123
|
+
/**
|
|
124
|
+
* Response for a session route when the session is missing or expired,
|
|
125
|
+
* and for any non-API request whose route or hook meets a
|
|
126
|
+
* LambderSessionNotFoundError (the session ended while the request held
|
|
127
|
+
* it, or a session read found none, or cookies naming several: a
|
|
128
|
+
* LambderSessionAmbiguousError). Default: 401.
|
|
129
|
+
*/
|
|
106
130
|
setSessionExpiredRouteHandler(handler: LambderFallbackHandler): this;
|
|
107
131
|
/**
|
|
108
132
|
* Terminal public-file layer. Runs only when no route matched, so it can
|
|
109
133
|
* never shadow routes registered after it. Serves files from the `files`
|
|
110
134
|
* source configured at creation, under the reader's path rule, mime-typed,
|
|
111
135
|
* memory-cached, with the immutable-cache heuristic for content-hashed
|
|
112
|
-
* assets. Only configured methods reach it
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
136
|
+
* assets. Only configured methods reach it (default GET/HEAD); a
|
|
137
|
+
* gated-out method or a path with no file falls through to
|
|
138
|
+
* setRouteFallbackHandler, where the app decides what remains (e.g.
|
|
139
|
+
* render an app shell with res.templateFile).
|
|
116
140
|
*/
|
|
117
141
|
servePublicFiles(options?: LambderPublicFilesOptions): this;
|
|
118
142
|
/**
|
|
@@ -125,28 +149,36 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
125
149
|
* res.templateFile (markers optional) with no-cache.
|
|
126
150
|
*/
|
|
127
151
|
serveIndexHtml(handler?: LambderFallbackHandler, options?: LambderIndexHtmlOptions): this;
|
|
128
|
-
addRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: (ctx: LambderRenderContext<any, LambderPathParamsOf<TPath
|
|
152
|
+
addRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: (ctx: LambderRenderContext<any, LambderPathParamsOf<TPath>, {}, TSessionData, _TRateLimitPolicies>, resolver: LambderResolver) => MaybePromise<LambderResponse>): this;
|
|
129
153
|
addRoute(condition: RegExp | LambderRouteConditionFn | LambderRouteMatcher, actionFn: LambderRouteHandler): this;
|
|
130
|
-
addSessionRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: ((ctx: LambderSessionRenderContext<any, TSessionData, LambderPathParamsOf<TPath
|
|
154
|
+
addSessionRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: ((ctx: LambderSessionRenderContext<any, TSessionData, LambderPathParamsOf<TPath>, {}, _TRateLimitPolicies>, resolver: LambderResolver) => MaybePromise<LambderResponse>) & LambderSessionEnabledInstance<_TSessionsEnabled>): this;
|
|
131
155
|
addSessionRoute(condition: RegExp | LambderRouteConditionFn | LambderRouteMatcher, actionFn: LambderSessionRouteHandler<TSessionData> & LambderSessionEnabledInstance<_TSessionsEnabled>): this;
|
|
132
|
-
addApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TRateOpt extends LambderRateLimitOption<_TRateLimitPolicies, z.
|
|
156
|
+
addApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TRateOpt extends LambderRateLimitOption<_TRateLimitPolicies, z.input<TInput>, false> = never, const TGuardsOpt extends LambderGuardsOption<_TGuards, z.input<TInput>, false> = never, const TIdempotencyOpt extends LambderApiIdempotencyOption = never>(name: TName, schema: {
|
|
133
157
|
input: TInput;
|
|
134
158
|
output: TOutput;
|
|
135
159
|
} & {
|
|
136
|
-
/** Named rate limits, checked in declared order before guards and validation: a name, a list of names, or a { name: true | override } map (windows overridable on perApi budgets, errorMessage on any). The first exceeded one refuses (429 envelope + Retry-After); attempts count on every counter checked before it. */
|
|
160
|
+
/** Named rate limits, checked in declared order within their phase (per ip before the session read, per session before the guards, a custom key after the guards and input validation): a name, a list of names, or a { name: true | override } map (windows overridable on perApi budgets, errorMessage on any). The first exceeded one refuses (429 envelope + Retry-After); attempts count on every counter checked before it. */
|
|
137
161
|
rateLimit?: TRateOpt;
|
|
138
162
|
/** Replay-protect this API per client idempotencyKey. Requires the idempotency option at creation. */
|
|
139
163
|
idempotency?: _TIdempotencyEnabled extends true ? TIdempotencyOpt : never;
|
|
140
|
-
} & LambderRequirableGuardsField<_TPublicGuardsRequired, TGuardsOpt>, handler: (ctx: LambderRenderContext<z.infer<TInput>, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt
|
|
141
|
-
addSessionApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TRateOpt extends LambderRateLimitOption<_TRateLimitPolicies, z.
|
|
164
|
+
} & LambderRequirableGuardsField<_TPublicGuardsRequired, TGuardsOpt>, handler: (ctx: LambderRenderContext<z.infer<TInput>, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt>, TSessionData, _TRateLimitPolicies>, resolver: LambderResolver<z.input<TOutput>>) => MaybePromise<LambderResponse>): Lambder<TSessionData, LambderMergeContract<_TContract, TName, LambderContractEntry<z.input<TInput>, LambderJsonOutputOf<z.output<TOutput>>, "public", LambderGuardInputsOf<_TGuards, TGuardsOpt>, TGuardsOpt, TRateOpt, TIdempotencyOpt>>, _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired, _TSessionsEnabled>;
|
|
165
|
+
addSessionApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TRateOpt extends LambderRateLimitOption<_TRateLimitPolicies, z.input<TInput>, true> = never, const TGuardsOpt extends LambderGuardsOption<_TGuards, z.input<TInput>, true> = never, const TIdempotencyOpt extends LambderApiIdempotencyOption = never>(name: TName, schema: {
|
|
142
166
|
input: TInput;
|
|
143
167
|
output: TOutput;
|
|
144
168
|
} & {
|
|
145
|
-
/** Named rate limits, checked in declared order before guards and validation: a name, a list of names, or a { name: true | override } map (windows overridable on perApi budgets, errorMessage on any). The first exceeded one refuses (429 envelope + Retry-After); attempts count on every counter checked before it. */
|
|
169
|
+
/** Named rate limits, checked in declared order within their phase (per ip before the session read, per session before the guards, a custom key after the guards and input validation): a name, a list of names, or a { name: true | override } map (windows overridable on perApi budgets, errorMessage on any). The first exceeded one refuses (429 envelope + Retry-After); attempts count on every counter checked before it. */
|
|
146
170
|
rateLimit?: TRateOpt;
|
|
147
171
|
/** Replay-protect this API per client idempotencyKey. Requires the idempotency option at creation. */
|
|
148
172
|
idempotency?: _TIdempotencyEnabled extends true ? TIdempotencyOpt : never;
|
|
149
|
-
} & LambderRequirableGuardsField<_TSessionGuardsRequired, TGuardsOpt> & LambderSessionEnabledInstance<_TSessionsEnabled>, handler: (ctx: LambderSessionRenderContext<z.infer<TInput>, TSessionData, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt
|
|
173
|
+
} & LambderRequirableGuardsField<_TSessionGuardsRequired, TGuardsOpt> & LambderSessionEnabledInstance<_TSessionsEnabled>, handler: (ctx: LambderSessionRenderContext<z.infer<TInput>, TSessionData, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt>, _TRateLimitPolicies>, resolver: LambderResolver<z.input<TOutput>>) => MaybePromise<LambderResponse>): Lambder<TSessionData, LambderMergeContract<_TContract, TName, LambderContractEntry<z.input<TInput>, LambderJsonOutputOf<z.output<TOutput>>, "session", LambderGuardInputsOf<_TGuards, TGuardsOpt>, TGuardsOpt, TRateOpt, TIdempotencyOpt>>, _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired, _TSessionsEnabled>;
|
|
174
|
+
/**
|
|
175
|
+
* What registering an API is, for addApi and addSessionApi alike: the
|
|
176
|
+
* checks that can refuse it, then its definition recorded (what
|
|
177
|
+
* apiSignatures() digests) and its action appended to the first-match
|
|
178
|
+
* chain. The two public methods differ only in the mode and in the types
|
|
179
|
+
* they give the handler.
|
|
180
|
+
*/
|
|
181
|
+
private registerApi;
|
|
150
182
|
addHook(hookEvent: 'created', hookFn: LambderCreatedHook, priority?: number): this;
|
|
151
183
|
addHook(hookEvent: 'beforeRender', hookFn: LambderBeforeRenderHook, priority?: number): this;
|
|
152
184
|
addHook(hookEvent: 'afterRender', hookFn: LambderAfterRenderHook, priority?: number): this;
|
|
@@ -171,34 +203,48 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
171
203
|
addAction(filter: (event: unknown, ctx: LambderRenderContext | null) => boolean, actionFn: (event: unknown, tools: LambderActionTools) => MaybePromise<unknown>): this;
|
|
172
204
|
use<_TNewContract extends Record<string, any>>(plugin: (lambder: Lambder<TSessionData, _TContract, any, any, any, any, any, any>) => Lambder<TSessionData, _TNewContract, any, any, any, any, any, any>): Lambder<TSessionData, _TNewContract extends _TContract ? _TNewContract : (_TContract & _TNewContract), _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired, _TSessionsEnabled>;
|
|
173
205
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* presents cookies alone.
|
|
206
|
+
* A session controller for a context: what creates, rotates, refreshes
|
|
207
|
+
* and ends sessions. An API call presents its posted CSRF token; a route
|
|
208
|
+
* presents cookies alone. A context this instance renders already
|
|
209
|
+
* carries one as `ctx.sessionController`; this is for a context it did
|
|
210
|
+
* not render, such as one createContext() built from an event on its own.
|
|
177
211
|
*/
|
|
178
212
|
getSessionController(ctx: LambderRenderContext | LambderSessionRenderContext<any, TSessionData>): LambderSessionController<TSessionData>;
|
|
179
213
|
/** The session manager, for code that works on sessions outside a request (maintenance, tests). */
|
|
180
214
|
getSessionManager(): LambderSessionManager<TSessionData>;
|
|
215
|
+
/**
|
|
216
|
+
* The backend swap `lambder/testing` performs: the stores given go under
|
|
217
|
+
* this instance in place, so every handler and guard that closed over it
|
|
218
|
+
* reaches them, and the production ones are out of reach from then on.
|
|
219
|
+
* Keyed by a symbol no entry point exports, so it is not part of what an
|
|
220
|
+
* app can call; see LAMBDER_BACKEND_SWAP.
|
|
221
|
+
*/
|
|
222
|
+
[LAMBDER_BACKEND_SWAP](backends: LambderInstanceBackends): LambderInstanceBackendSwap;
|
|
223
|
+
/**
|
|
224
|
+
* The crash watch `lambder/testing` sets: told every error a request
|
|
225
|
+
* throws past the framework's own handling, before the global error
|
|
226
|
+
* handler or the last-resort 500 answers it. The answer is unchanged.
|
|
227
|
+
*/
|
|
228
|
+
[LAMBDER_CRASH_WATCH](watcher: (error: Error) => void): void;
|
|
181
229
|
/**
|
|
182
230
|
* Every registered endpoint's signature, keyed by its hashed name: the
|
|
183
231
|
* LambderApiSignatureMap both sides ship with. A generator imports the
|
|
184
|
-
* finished instance, awaits this, and writes
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* itself. Keys are sorted, so the generated file diffs by endpoint.
|
|
232
|
+
* finished instance, awaits this, and writes a file that LambderCaller
|
|
233
|
+
* and create() both take as apiSignatures; at request time the pipeline
|
|
234
|
+
* compares a call's signature with the server's copy. This is the only
|
|
235
|
+
* place a digest is computed, so there is no second computation to drift
|
|
236
|
+
* from it. Keys are sorted, so the generated file diffs by endpoint.
|
|
190
237
|
*/
|
|
191
238
|
apiSignatures(): Promise<LambderApiSignatureMap>;
|
|
192
239
|
/**
|
|
193
|
-
* The same signatures
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* Reading this instead, it can name them.
|
|
240
|
+
* The same signatures, sorted by key as the map is, with the endpoint
|
|
241
|
+
* name each was digested from. The map a client ships deliberately lists
|
|
242
|
+
* no names, so a generator reading only the map could say how many
|
|
243
|
+
* signatures changed but not which endpoints; this lets it name them.
|
|
198
244
|
*
|
|
199
|
-
* A build-time view
|
|
200
|
-
*
|
|
201
|
-
*
|
|
245
|
+
* A build-time view: it comes off the server instance, which a generator
|
|
246
|
+
* imports and a client never does, so nothing here reaches a bundle
|
|
247
|
+
* unless the generator writes it there.
|
|
202
248
|
*/
|
|
203
249
|
apiSignatureEntries(): Promise<LambderApiSignatureEntry[]>;
|
|
204
250
|
getResponseBuilder(ctx?: LambderRenderContext): LambderResponseBuilder<any>;
|
|
@@ -212,38 +258,84 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
212
258
|
* The beforeRender hooks, in priority order: the replaced context to
|
|
213
259
|
* continue with, or the response one of them answered with.
|
|
214
260
|
*
|
|
215
|
-
* Its own method because
|
|
216
|
-
* match, it
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
261
|
+
* Its own method because both request paths run it. Run only after a
|
|
262
|
+
* match, it would skip every servePublicFiles and serveIndexHtml answer
|
|
263
|
+
* (every asset and app-shell page): a security header written in a hook
|
|
264
|
+
* would miss the HTML it was written for, and a maintenance-mode hook
|
|
265
|
+
* would still serve the whole frontend.
|
|
266
|
+
*
|
|
267
|
+
* Each replacement is also handed to `onContextReplaced` as it is made,
|
|
268
|
+
* rather than only returned: render() answers from it after the handler
|
|
269
|
+
* too (the afterRender hooks, a crash's report, reveal and global error
|
|
270
|
+
* handler), and a handler or a later hook that throws returns nothing.
|
|
222
271
|
*/
|
|
223
272
|
private runBeforeRenderHooks;
|
|
224
273
|
private handleNoMatchedAction;
|
|
225
274
|
/**
|
|
226
275
|
* True for the OPTIONS request the CORS layer answers by itself. Asked
|
|
227
|
-
* twice: once to build the 204, once at the end of render() to
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
276
|
+
* twice: once to build the 204, once at the end of render() to pick which
|
|
277
|
+
* form of the headers goes on. Applying the ordinary headers on top of
|
|
278
|
+
* the 204's would put both forms on a preflight: `Vary: Origin, Origin`
|
|
279
|
+
* and an Access-Control-Expose-Headers that means nothing before a
|
|
280
|
+
* request.
|
|
232
281
|
*/
|
|
233
282
|
private isCorsPreflight;
|
|
234
283
|
private resolveRequest;
|
|
235
284
|
render(event: LambderHttpEvent, lambdaContext: Context): Promise<LambderHttpResponse>;
|
|
285
|
+
/**
|
|
286
|
+
* A thrown value that is an answer rather than a crash, as the response;
|
|
287
|
+
* anything else is rethrown to the crash path.
|
|
288
|
+
*
|
|
289
|
+
* - A LambderResponse IS the response (res.die.*, throw res.html(...)).
|
|
290
|
+
* - A LambderApiRefusal on an API call is its structured refusal
|
|
291
|
+
* (brand-checked, not instanceof, to survive duplicate installs).
|
|
292
|
+
* - A LambderSessionNotFoundError is a missing session: one that ended
|
|
293
|
+
* while the request held it (a logout or a password change landing
|
|
294
|
+
* mid-request), or one a route or hook asked for that the request
|
|
295
|
+
* never had or whose cookies named several (its subclass
|
|
296
|
+
* LambderSessionAmbiguousError). It is answered the way a missing
|
|
297
|
+
* session is answered here, the decision the API pipeline makes for a
|
|
298
|
+
* handler, applied to the routes and hooks it never sees.
|
|
299
|
+
*/
|
|
300
|
+
private answerThrown;
|
|
301
|
+
/**
|
|
302
|
+
* A crash, from the thrown value to the answer. It is told to the test
|
|
303
|
+
* watch and reported before anything answers, so the report depends on
|
|
304
|
+
* nothing the answer might break; then the app's global error handler
|
|
305
|
+
* answers it, or the framework's own 500 does when there is none or it
|
|
306
|
+
* failed too.
|
|
307
|
+
*/
|
|
308
|
+
private answerCrash;
|
|
309
|
+
/**
|
|
310
|
+
* An answer to a crash, carrying what the call wrote and its CORS headers.
|
|
311
|
+
* As on the success path, headers belong to the call: a call that wrote a
|
|
312
|
+
* session cookie and then threw still owes the browser that cookie, and a
|
|
313
|
+
* cross-origin caller cannot read the error at all without CORS headers.
|
|
314
|
+
* The CORS verdict is the one the request settled before it crashed, so
|
|
315
|
+
* answering a crash runs none of the app's code.
|
|
316
|
+
*/
|
|
317
|
+
private withCallHeaders;
|
|
236
318
|
/**
|
|
237
319
|
* Fetch the session for a session route or short-circuit it with the
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
320
|
+
* answer for a missing session. Session APIs never come through here:
|
|
321
|
+
* the pipeline answers them with the protocol's { sessionExpired: true }
|
|
322
|
+
* envelope itself.
|
|
241
323
|
*/
|
|
242
324
|
private requireSession;
|
|
243
|
-
/**
|
|
325
|
+
/**
|
|
326
|
+
* The answer to a request that needed a session and has none, whether it
|
|
327
|
+
* never had one or it ended while the request held it: an API call gets
|
|
328
|
+
* the protocol's sessionExpired envelope, as the pipeline gives a session
|
|
329
|
+
* API, and anything else the setSessionExpiredRouteHandler answer, a 401
|
|
330
|
+
* by default.
|
|
331
|
+
*/
|
|
332
|
+
private sessionMissingResponse;
|
|
333
|
+
/**
|
|
334
|
+
* Dispatch a non-HTTP Lambda event to the registered actions. What an
|
|
335
|
+
* action throws is reported (crashes.report) and then rethrown untouched,
|
|
336
|
+
* so Lambda's retries and dead-letter queues still see the failure.
|
|
337
|
+
*/
|
|
244
338
|
renderEvent(event: unknown, lambdaContext: Context): Promise<unknown>;
|
|
245
|
-
/** Registration-time checks shared by addApi/addSessionApi. */
|
|
246
|
-
private assertApiRegistration;
|
|
247
339
|
/**
|
|
248
340
|
* The answer for a rejected input: the app's
|
|
249
341
|
* setApiInputValidationErrorHandler when set, otherwise the standard 422
|
|
@@ -257,7 +349,8 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
257
349
|
* via res.die.*) becomes the answer the pipeline stores and hands back.
|
|
258
350
|
* The context is the pipeline's context, so a session it fetched is on
|
|
259
351
|
* ctx.session and the validated payload is on ctx.apiPayload when the
|
|
260
|
-
* handler runs.
|
|
352
|
+
* handler runs. The handler's resolver knows the API's output schema, so
|
|
353
|
+
* every success payload is parsed through it before it is sent.
|
|
261
354
|
*/
|
|
262
355
|
private runApi;
|
|
263
356
|
/** A thrown LambderApiRefusal (from a hook, say) as the structured API envelope: the core's one mapping. */
|
|
@@ -265,11 +358,10 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
265
358
|
}
|
|
266
359
|
/**
|
|
267
360
|
* The canonical way to create an instance: fix the session data type first,
|
|
268
|
-
* then create with the full configuration in one declaration
|
|
269
|
-
* guard
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
* ordering rules and nothing can be half-configured.
|
|
361
|
+
* then create with the full configuration in one declaration. The policy,
|
|
362
|
+
* guard and idempotency types are inferred from the options, so the instance
|
|
363
|
+
* is born fully typed and `typeof lambderApp` is the annotation type for api
|
|
364
|
+
* modules. There are no ordering rules, and nothing can be half-configured.
|
|
273
365
|
*
|
|
274
366
|
* ```typescript
|
|
275
367
|
* // app.ts (imports no api modules, so modules can import the type back)
|
|
@@ -290,16 +382,16 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
290
382
|
* export const handler = lambder.getHandler();
|
|
291
383
|
* ```
|
|
292
384
|
*
|
|
293
|
-
*
|
|
294
|
-
* `new Lambder<S>(...)`
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
* infer everything else from the options. `new Lambder(options)` remains
|
|
299
|
-
* for untyped or session-data-free instances.
|
|
385
|
+
* Curried because TypeScript type arguments are all-or-nothing per call:
|
|
386
|
+
* passing the session data type to `new Lambder<S>(...)` would silently
|
|
387
|
+
* widen the inferred policy and guard types to their {} defaults. Fixing the
|
|
388
|
+
* session type in the first call lets the second infer everything else.
|
|
389
|
+
* `new Lambder(options)` serves untyped or session-data-free instances.
|
|
300
390
|
*/
|
|
301
391
|
export declare const initLambder: <TSessionData = any>() => {
|
|
302
392
|
create<const TOptions extends LambderCreateOptions<TSessionData>>(options: LambderNoExtraKeys<TOptions, LambderCreateOptions<TSessionData>> & LambderNestedOptionChecks<TSessionData, TOptions>): Lambder<TSessionData, {}, TOptions["rateLimits"] extends {
|
|
303
393
|
policies: infer TPolicies extends Record<string, LambderApiRateLimitPolicyConfig>;
|
|
304
394
|
} ? TPolicies : {}, TOptions["guards"] extends Record<string, LambderApiGuard<any, any, any>> ? LambderGuardMetaMap<TOptions["guards"]> : {}, TOptions["idempotency"] extends LambderApiIdempotencyConfig ? true : false, [LambderGivenOption<TOptions, "requireSessionApiGuards">] extends [false | undefined] ? false : true, [LambderGivenOption<TOptions, "requirePublicApiGuards">] extends [false | undefined] ? false : true, [LambderGivenOption<TOptions, "session">] extends [undefined] ? false : true>;
|
|
395
|
+
guard: import("../api/LambderApiGuards.js").LambderGuardBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>, LambderSessionRenderContext<any, TSessionData>>;
|
|
396
|
+
rateLimitKey: import("../api/LambderApiRateLimits.js").LambderRateLimitKeyBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>>;
|
|
305
397
|
};
|