lambder 9.0.3 → 10.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 +195 -0
- package/README.md +25 -11
- package/dist/api/LambderApiDefinition.d.ts +9 -0
- package/dist/api/LambderApiEnvelope.d.ts +22 -10
- package/dist/api/LambderApiEnvelope.js +57 -22
- package/dist/api/LambderApiGuards.d.ts +77 -22
- package/dist/api/LambderApiGuards.js +13 -1
- package/dist/api/LambderApiIdempotency.js +4 -4
- package/dist/api/LambderApiOutputValidationError.d.ts +10 -4
- package/dist/api/LambderApiOutputValidationError.js +14 -6
- package/dist/api/LambderApiPipeline.d.ts +2 -1
- package/dist/api/LambderApiPipeline.js +10 -2
- package/dist/api/LambderApiRateLimits.d.ts +15 -11
- package/dist/api/LambderApiRateLimits.js +31 -7
- package/dist/api/LambderApiRefusals.d.ts +204 -0
- package/dist/api/LambderApiRefusals.js +223 -0
- package/dist/api/LambderApiSignature.d.ts +13 -4
- package/dist/api/LambderApiSignature.js +21 -4
- package/dist/build/writeApiOptions.js +7 -5
- package/dist/client/LambderCaller.d.ts +28 -17
- package/dist/client/LambderCaller.js +19 -15
- package/dist/client.d.ts +5 -4
- package/dist/client.js +2 -1
- package/dist/core/Lambder.d.ts +121 -23
- package/dist/core/Lambder.js +105 -51
- package/dist/core/LambderContext.d.ts +1 -1
- package/dist/core/LambderContext.js +5 -0
- package/dist/core/LambderCreateOptions.d.ts +58 -15
- package/dist/core/LambderCreateOptions.js +10 -0
- package/dist/core/LambderPolicyBuilders.d.ts +11 -8
- package/dist/core/LambderPolicyBuilders.js +10 -8
- package/dist/core/LambderResolver.d.ts +1 -1
- package/dist/core/LambderResolver.js +1 -1
- package/dist/core/LambderResponseBuilder.d.ts +11 -9
- package/dist/core/LambderResponseBuilder.js +12 -11
- package/dist/index.d.ts +12 -8
- package/dist/index.js +6 -2
- package/dist/invoke/LambderInvokeCaller.d.ts +5 -6
- package/dist/invoke/LambderInvokeCaller.js +13 -12
- package/dist/invoke/LambderInvokeOutcome.d.ts +32 -23
- package/dist/invoke/LambderInvokeOutcome.js +4 -4
- package/dist/mock/LambderMockApp.d.ts +86 -24
- package/dist/mock/LambderMockApp.js +108 -16
- package/dist/mock/LambderMockCallRecorder.js +6 -3
- package/dist/mock/LambderMockCreateOptions.d.ts +4 -5
- package/dist/mock/LambderMockFailureInjector.d.ts +9 -2
- package/dist/mock/LambderMockFailureInjector.js +18 -4
- package/dist/mock/LambderMockTypes.d.ts +34 -11
- package/dist/mock.d.ts +4 -3
- package/dist/mock.js +4 -3
- package/dist/shared/util/LambderTypeUtilities.d.ts +11 -0
- package/dist/shared/wire/LambderApiContract.d.ts +96 -31
- package/dist/shared/wire/LambderApiOptionEntries.d.ts +19 -12
- package/dist/shared/wire/LambderApiOptionValues.d.ts +15 -6
- package/dist/shared/wire/LambderApiOptionValues.js +3 -3
- package/dist/shared/wire/LambderApiOutcome.d.ts +49 -27
- package/dist/shared/wire/LambderApiOutcome.js +28 -11
- package/dist/shared/wire/LambderApiRefusal.d.ts +127 -42
- package/dist/shared/wire/LambderApiRefusal.js +15 -7
- package/dist/shared/wire/LambderCrashDetail.d.ts +1 -1
- package/dist/shared/wire/LambderCrashDetail.js +1 -1
- package/dist/shared/wire/LambderHttpStatus.d.ts +6 -0
- package/dist/shared/wire/LambderIdempotencyKeyScope.d.ts +3 -2
- package/dist/shared/wire/LambderIdempotencyKeyScope.js +5 -5
- package/dist/shared/wire/LambderObjectPayload.d.ts +15 -0
- package/dist/shared/wire/LambderObjectPayload.js +24 -0
- package/dist/shared/wire/LambderOutcomeAssertions.d.ts +52 -7
- package/dist/shared/wire/LambderOutcomeAssertions.js +34 -8
- package/dist/testing/LambderTestApp.d.ts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
|
@@ -33,7 +33,10 @@ export default class LambderCaller {
|
|
|
33
33
|
get isLoading() { return this.fetchTrackerList.length > 0; }
|
|
34
34
|
versionExpiredHandler;
|
|
35
35
|
sessionExpiredHandler;
|
|
36
|
-
|
|
36
|
+
// Hears every endpoint's refusals, so held at the widest message: the
|
|
37
|
+
// constructor option types it to the contract's codes, and dispatch,
|
|
38
|
+
// generic over one endpoint's message, hands it one of those.
|
|
39
|
+
refusalHandler;
|
|
37
40
|
notAuthorizedHandler;
|
|
38
41
|
errorHandler;
|
|
39
42
|
apiInputValidationErrorHandler;
|
|
@@ -49,7 +52,7 @@ export default class LambderCaller {
|
|
|
49
52
|
constructor(options) {
|
|
50
53
|
// The conditional provider option is resolved per instantiation;
|
|
51
54
|
// inside the class it is read through the plain shape.
|
|
52
|
-
const { apiPath, apiVersion, apiSignatures, isCorsEnabled, timeoutMs, versionExpiredHandler, sessionExpiredHandler,
|
|
55
|
+
const { apiPath, apiVersion, apiSignatures, isCorsEnabled, timeoutMs, versionExpiredHandler, sessionExpiredHandler, refusalHandler, notAuthorizedHandler, errorHandler, logListHandler, fetchStartedHandler, fetchEndedHandler, apiInputValidationErrorHandler, sessionCookieDomain, requestCompression, guardInputsProvider, transport, } = options;
|
|
53
56
|
this.apiPath = apiPath;
|
|
54
57
|
this.apiVersion = apiVersion;
|
|
55
58
|
this.apiSignatures = apiSignatures;
|
|
@@ -60,7 +63,7 @@ export default class LambderCaller {
|
|
|
60
63
|
this.transport = transport ?? lambderFetchTransport({ cors: isCorsEnabled });
|
|
61
64
|
this.versionExpiredHandler = versionExpiredHandler;
|
|
62
65
|
this.sessionExpiredHandler = sessionExpiredHandler;
|
|
63
|
-
this.
|
|
66
|
+
this.refusalHandler = refusalHandler;
|
|
64
67
|
this.notAuthorizedHandler = notAuthorizedHandler;
|
|
65
68
|
this.errorHandler = errorHandler;
|
|
66
69
|
this.apiInputValidationErrorHandler = apiInputValidationErrorHandler;
|
|
@@ -98,7 +101,7 @@ export default class LambderCaller {
|
|
|
98
101
|
// Per-call overrides win over the constructor handlers.
|
|
99
102
|
const versionExpiredHandler = options?.versionExpiredHandler ?? this.versionExpiredHandler;
|
|
100
103
|
const sessionExpiredHandler = options?.sessionExpiredHandler ?? this.sessionExpiredHandler;
|
|
101
|
-
const
|
|
104
|
+
const refusalHandler = options?.refusalHandler ?? this.refusalHandler;
|
|
102
105
|
const notAuthorizedHandler = options?.notAuthorizedHandler ?? this.notAuthorizedHandler;
|
|
103
106
|
const errorHandler = options?.errorHandler ?? this.errorHandler;
|
|
104
107
|
const apiInputValidationErrorHandler = options?.apiInputValidationErrorHandler ?? this.apiInputValidationErrorHandler;
|
|
@@ -325,9 +328,9 @@ export default class LambderCaller {
|
|
|
325
328
|
}
|
|
326
329
|
return outcome;
|
|
327
330
|
}
|
|
328
|
-
if (!outcome.ok && outcome.reason === '
|
|
329
|
-
if (
|
|
330
|
-
await
|
|
331
|
+
if (!outcome.ok && outcome.reason === 'refusal') {
|
|
332
|
+
if (refusalHandler && outcome.refusal !== undefined) {
|
|
333
|
+
await refusalHandler(outcome.refusal);
|
|
331
334
|
}
|
|
332
335
|
return outcome;
|
|
333
336
|
}
|
|
@@ -356,7 +359,9 @@ export default class LambderCaller {
|
|
|
356
359
|
;
|
|
357
360
|
/**
|
|
358
361
|
* Full-fidelity call: resolves to a discriminated LambderApiOutcome
|
|
359
|
-
* instead of collapsing every failure to undefined. Never throws.
|
|
362
|
+
* instead of collapsing every failure to undefined. Never throws. A
|
|
363
|
+
* success's payload is the endpoint's output, and a refusal's
|
|
364
|
+
* refusal narrows on the codes the endpoint declares.
|
|
360
365
|
*
|
|
361
366
|
* The output is computed from the contract in the return type rather than
|
|
362
367
|
* taken as a type parameter, so a call site cannot replace it by
|
|
@@ -371,16 +376,15 @@ export default class LambderCaller {
|
|
|
371
376
|
}
|
|
372
377
|
;
|
|
373
378
|
/**
|
|
374
|
-
* The
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
379
|
+
* The endpoint's output on success, `undefined` on every failure. An
|
|
380
|
+
* output is always an object or an array, so the result is truthy exactly
|
|
381
|
+
* when the call succeeded; the handlers configured on the caller have
|
|
382
|
+
* already been told why it did not. Use apiOutcome() to branch on the
|
|
383
|
+
* reason at the call site.
|
|
378
384
|
*/
|
|
379
385
|
async api(apiName, ...rest) {
|
|
380
386
|
const [payload, options] = rest;
|
|
381
387
|
const outcome = await this.dispatch(apiName, payload, options);
|
|
382
|
-
|
|
383
|
-
return outcome.payload;
|
|
384
|
-
return outcome.reason === 'errorMessage' ? outcome.response.payload : undefined;
|
|
388
|
+
return outcome.ok ? outcome.payload : undefined;
|
|
385
389
|
}
|
|
386
390
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -23,9 +23,10 @@ export type { LambderApiAnswerOutcome, LambderApiSuccessOutcome, LambderApiCallF
|
|
|
23
23
|
export type { LambderApiOutcome, LambderApiFailureReason, LambderValidationError, LambderCallOptions, LambderCallerOptions, LambderGuardInputsProvider, LambderProvidedGuardInputs, LambderLogListHandler, } from "./client/LambderCaller.js";
|
|
24
24
|
export { createIdempotencyKey, createIdempotencyKeyScope } from "./shared/wire/LambderIdempotencyKeyScope.js";
|
|
25
25
|
export type { LambderIdempotencyKeyScope } from "./shared/wire/LambderIdempotencyKeyScope.js";
|
|
26
|
-
export { LambderApiRefusal, isLambderApiRefusal, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
27
|
-
export type { LambderApiRefusalOptions, LambderRefusalMessage,
|
|
28
|
-
export
|
|
26
|
+
export { LambderApiRefusal, isLambderApiRefusal, isLambderRefusalCode, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
27
|
+
export type { LambderApiRefusalOptions, LambderRefusalMessage, LambderPlainRefusalMessage, LambderUncheckedRefusalMessage, LambderRefusalCode, LambderRefuseOptions, LambderDeclaredRefuseOptions, LambderDeclaredRefuse, } from "./shared/wire/LambderApiRefusal.js";
|
|
28
|
+
export { isObjectPayload } from "./shared/wire/LambderObjectPayload.js";
|
|
29
|
+
export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiSuccessEnvelope, LambderApiRefusalEnvelope, LambderRefusalEnvelopeFields, LambderApiRefusalConfig, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractKeysWithGuard, LambderJsonOf, LambderContractRefusalsOf, LambderContractRefusalMessage, LambderContractRefusals, LambderContractAnyRefusalMessage, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractRateLimitNames, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
|
|
29
30
|
export { apiGuardParam } from "./shared/wire/LambderApiOptionEntries.js";
|
|
30
31
|
export type { LambderApiOptionEntries, LambderApiOptionEntry, LambderRateLimitPolicyEntry, LambderGuardDeclarationEntry, LambderApisWithGuard, LambderApisGuardedBy, LambderApisWithMode, LambderGuardParamOf, } from "./shared/wire/LambderApiOptionEntries.js";
|
|
31
32
|
export { describeCrash, errorFromCrashDetail } from "./shared/wire/LambderCrashDetail.js";
|
|
@@ -37,7 +38,7 @@ export type { LambderCompressionOption, LambderCompressionSettingsBase } from ".
|
|
|
37
38
|
export { html, xml, raw, jsonScript, escapeHtml, renderHtmlValue, LambderSafeHtml, type LambderHtmlValue } from "./shared/LambderHtml.js";
|
|
38
39
|
export { createLambderI18n } from "./shared/LambderI18n.js";
|
|
39
40
|
export type { LambderLanguageMeta, LambderI18nConfig, LambderI18nInstance, LambderI18nTranslator, LambderI18nExtractParams, LambderI18nDictionaryLoader, LambderI18nCodes, LambderI18nKeys, LambderI18nTranslatorFor, } from "./shared/LambderI18n.js";
|
|
40
|
-
export type { LambderHttpStatusCode } from "./shared/wire/LambderHttpStatus.js";
|
|
41
|
+
export type { LambderHttpStatusCode, LambderRefusalStatusCode } from "./shared/wire/LambderHttpStatus.js";
|
|
41
42
|
export { LambderBackoffTimer } from "./shared/util/LambderBackoffTimer.js";
|
|
42
43
|
export type { LambderBackoffTimerOptions } from "./shared/util/LambderBackoffTimer.js";
|
|
43
44
|
export { LambderSignedClaims, keyedDigest, randomSecret } from "./shared/util/LambderSignedClaims.js";
|
package/dist/client.js
CHANGED
|
@@ -22,7 +22,8 @@ export { compareDottedVersions, isDottedVersion } from "./shared/wire/LambderVer
|
|
|
22
22
|
export { createIdempotencyKey, createIdempotencyKeyScope } from "./shared/wire/LambderIdempotencyKeyScope.js";
|
|
23
23
|
// Typed API refusals (isomorphic: shared code may throw them from anywhere;
|
|
24
24
|
// in the browser they are plain Errors).
|
|
25
|
-
export { LambderApiRefusal, isLambderApiRefusal, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
25
|
+
export { LambderApiRefusal, isLambderApiRefusal, isLambderRefusalCode, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
26
|
+
export { isObjectPayload } from "./shared/wire/LambderObjectPayload.js";
|
|
26
27
|
// The server's declared options as plain data (the generated options module's
|
|
27
28
|
// entry types) and the readers a client derives its own facts from.
|
|
28
29
|
export { apiGuardParam } from "./shared/wire/LambderApiOptionEntries.js";
|
package/dist/core/Lambder.d.ts
CHANGED
|
@@ -12,17 +12,19 @@ import { LambderFiles } from "./LambderFiles.js";
|
|
|
12
12
|
import { type LambderPipelineBackends, type LambderPipelineBackendSwap } from "../api/LambderApiPipeline.js";
|
|
13
13
|
import type { LambderFileSource } from "../shared/contracts/LambderFileSource.js";
|
|
14
14
|
import { LAMBDER_BACKEND_SWAP, LAMBDER_CRASH_WATCH } from "../shared/util/LambderTestingDoors.js";
|
|
15
|
+
import { type LambderWireRefusalsOf, type LambderHandlerRefusalsOf, type LambderRefusalNamesIn, type LambderRefusalsOption, type LambderRefusalVocabulary, type LambderRefusalVocabularyChecks } from "../api/LambderApiRefusals.js";
|
|
16
|
+
import { type LambderDeclaredRefuse } from "../shared/wire/LambderApiRefusal.js";
|
|
15
17
|
import { type LambderApiSignatureEntry } from "../api/LambderApiSignature.js";
|
|
16
18
|
import { type LambderApiSignatureMap } from "../shared/wire/LambderApiSignatureMap.js";
|
|
17
19
|
import type { LambderApiOptionEntries } from "../shared/wire/LambderApiOptionEntries.js";
|
|
18
20
|
import type { LambderApiIdempotencyOption } from "../shared/wire/LambderApiOptionValues.js";
|
|
19
|
-
import type { LambderApiGuard, LambderGuardMetaMap, LambderGuardsOption, LambderGuardDataOf, LambderGuardInputsOf } from "../api/LambderApiGuards.js";
|
|
21
|
+
import type { LambderApiGuard, LambderGuardMetaMap, LambderGuardsOption, LambderGuardDataOf, LambderGuardInputsOf, LambderGuardRefusalNamesOf } from "../api/LambderApiGuards.js";
|
|
20
22
|
import type { LambderApiRateLimitPolicyConfig, LambderRateLimitOption } from "../api/LambderApiRateLimits.js";
|
|
21
23
|
import type { LambderApiIdempotencyConfig } from "../api/LambderApiIdempotency.js";
|
|
22
|
-
import type { LambderContractEntry,
|
|
24
|
+
import type { LambderContractEntry, LambderJsonOf, LambderMergeContract } from "../shared/wire/LambderApiContract.js";
|
|
23
25
|
import { type LambderHttpEvent, type LambderRenderContext, type LambderSessionRenderContext } from "./LambderContext.js";
|
|
24
26
|
import type { LambderReadonlyDeep, MaybePromise } from "../shared/util/LambderTypeUtilities.js";
|
|
25
|
-
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
|
|
27
|
+
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 LambderObjectOutputCheck, type LambderRequirableGuardsField, type LambderSessionEnabledInstance, type LambderSessionRouteHandler } from "./LambderCreateOptions.js";
|
|
26
28
|
/** Everything `lambder/testing` may put under a built instance: the pipeline's stores, and the source its files are read from. */
|
|
27
29
|
export type LambderInstanceBackends = LambderPipelineBackends & {
|
|
28
30
|
fileSource?: LambderFileSource;
|
|
@@ -37,7 +39,9 @@ export type LambderInstanceBackendSwap = LambderPipelineBackendSwap & {
|
|
|
37
39
|
* because its parameter is the class, and an options module that names the
|
|
38
40
|
* class cannot be read without it.
|
|
39
41
|
*/
|
|
40
|
-
export type LambderCreatedHook = (lambderInstance: Lambder<any, any, any, any, any, any, any, any>) => void | Promise<void>;
|
|
42
|
+
export type LambderCreatedHook = (lambderInstance: Lambder<any, any, any, any, any, any, any, any, any, any>) => void | Promise<void>;
|
|
43
|
+
/** The codes one API may refuse with, typed: its own refusals option's and its declared guards', as the vocabulary holds them. */
|
|
44
|
+
type LambderApiRefusalCodes<TVocabulary, TGuards, TRefusalsOpt, TGuardsOpt> = (LambderRefusalNamesIn<TRefusalsOpt> | LambderGuardRefusalNamesOf<TGuards, TGuardsOpt>) & keyof TVocabulary & string;
|
|
41
45
|
/**
|
|
42
46
|
* Main Lambder class for building type-safe serverless APIs. Create
|
|
43
47
|
* instances with initLambder<SessionData>().create({...}) (see below): the
|
|
@@ -52,6 +56,8 @@ export type LambderCreatedHook = (lambderInstance: Lambder<any, any, any, any, a
|
|
|
52
56
|
* @typeParam _TSessionGuardsRequired - @internal True when create() received requireSessionApiGuards (do not pass manually)
|
|
53
57
|
* @typeParam _TPublicGuardsRequired - @internal True when create() received requirePublicApiGuards (do not pass manually)
|
|
54
58
|
* @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.
|
|
59
|
+
* @typeParam _TRefusals - @internal The refusal vocabulary declareRefusals() gave the init (do not pass manually)
|
|
60
|
+
* @typeParam _TRefusalCodesRequired - @internal True when declareRefusals() received requireCodes (do not pass manually)
|
|
55
61
|
*
|
|
56
62
|
* @example
|
|
57
63
|
* ```typescript
|
|
@@ -62,7 +68,7 @@ export type LambderCreatedHook = (lambderInstance: Lambder<any, any, any, any, a
|
|
|
62
68
|
* .addApi('createUser', { input: z.object({...}), output: z.object({...}) }, handler);
|
|
63
69
|
* ```
|
|
64
70
|
*/
|
|
65
|
-
export default class Lambder<TSessionData = any, _TContract extends Record<string, any> = {}, _TRateLimitPolicies extends Record<string, LambderApiRateLimitPolicyConfig> = {}, _TGuards extends Record<string, any> = {}, _TIdempotencyEnabled extends boolean = false, _TSessionGuardsRequired extends boolean = false, _TPublicGuardsRequired extends boolean = false, _TSessionsEnabled extends boolean = true> {
|
|
71
|
+
export default class Lambder<TSessionData = any, _TContract extends Record<string, any> = {}, _TRateLimitPolicies extends Record<string, LambderApiRateLimitPolicyConfig> = {}, _TGuards extends Record<string, any> = {}, _TIdempotencyEnabled extends boolean = false, _TSessionGuardsRequired extends boolean = false, _TPublicGuardsRequired extends boolean = false, _TSessionsEnabled extends boolean = true, _TRefusals extends LambderRefusalVocabulary = {}, _TRefusalCodesRequired extends boolean = false> {
|
|
66
72
|
apiPath: string;
|
|
67
73
|
/** Stamped on every API answer's envelope as apiVersion. Informational: a client's staleness is judged per endpoint by its signature, see apiSignatures(). */
|
|
68
74
|
apiVersion: null | string;
|
|
@@ -94,6 +100,10 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
94
100
|
private readonly guards;
|
|
95
101
|
/** The rate-limit policies given at creation, kept for apiOptionEntries(), which records each one less its key handler. */
|
|
96
102
|
private readonly rateLimitPolicies;
|
|
103
|
+
/** The refusal vocabulary given at creation: what each API's and each guard's refusal codes resolve against. Null without the option. */
|
|
104
|
+
private readonly refusalVocabulary;
|
|
105
|
+
/** Every API's refusals option as written, for apiOptionEntries(); its definition holds the resolved set. */
|
|
106
|
+
private readonly refusalOptions;
|
|
97
107
|
private hookList;
|
|
98
108
|
private createdHooks;
|
|
99
109
|
private initPromise;
|
|
@@ -108,6 +118,8 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
108
118
|
private corsConfig;
|
|
109
119
|
private finalizeOptions;
|
|
110
120
|
private requireSessionApiGuards;
|
|
121
|
+
/** Whether every refusal an API answers with has to name a code (declareRefusals's requireCodes). */
|
|
122
|
+
private readonly requireRefusalCodes;
|
|
111
123
|
/** Told what a request threw, beside whatever answers it; null outside a test. See LAMBDER_CRASH_WATCH. */
|
|
112
124
|
private crashWatcher;
|
|
113
125
|
/** The crashes option applied: reporting, and the framework's own 500. */
|
|
@@ -155,14 +167,20 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
155
167
|
addRoute(condition: RegExp | LambderRouteConditionFn | LambderRouteMatcher, actionFn: LambderRouteHandler): this;
|
|
156
168
|
addSessionRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: ((ctx: LambderSessionRenderContext<any, TSessionData, LambderPathParamsOf<TPath>, {}, _TRateLimitPolicies>, resolver: LambderResolver) => MaybePromise<LambderResponse>) & LambderSessionEnabledInstance<_TSessionsEnabled>): this;
|
|
157
169
|
addSessionRoute(condition: RegExp | LambderRouteConditionFn | LambderRouteMatcher, actionFn: LambderSessionRouteHandler<TSessionData> & LambderSessionEnabledInstance<_TSessionsEnabled>): this;
|
|
158
|
-
addApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TAnswer extends LambderReadonlyDeep<z.input<TOutput>>, 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: {
|
|
170
|
+
addApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TAnswer extends LambderReadonlyDeep<z.input<TOutput>>, 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, const TRefusalsOpt extends LambderRefusalsOption<_TRefusals> = never>(name: TName, schema: {
|
|
159
171
|
input: TInput;
|
|
160
172
|
output: TOutput;
|
|
161
173
|
} & {
|
|
162
|
-
/** 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,
|
|
174
|
+
/** 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, refusal on any). The first exceeded one refuses (429 envelope + Retry-After); attempts count on every counter checked before it. */
|
|
163
175
|
rateLimit?: TRateOpt;
|
|
164
176
|
/** Replay-protect this API per client idempotencyKey. Requires the idempotency option at creation. */
|
|
165
177
|
idempotency?: _TIdempotencyEnabled extends true ? TIdempotencyOpt : never;
|
|
178
|
+
/**
|
|
179
|
+
* The refusal codes this API may refuse with, from the vocabulary given at creation: one code or a
|
|
180
|
+
* non-empty list. Its guards' codes join them. The handler raises one with `ctx.refuse(content, { code, data })`,
|
|
181
|
+
* its callers narrow on them, and a refusal with any other code is a crash rather than an answer.
|
|
182
|
+
*/
|
|
183
|
+
refusals?: TRefusalsOpt;
|
|
166
184
|
/**
|
|
167
185
|
* Whether this API's answers are compressed for a caller that accepts it: "auto" (the default) when the
|
|
168
186
|
* body is large enough to gain, false never, true always. false suits an answer of base64 bytes: once
|
|
@@ -171,17 +189,25 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
171
189
|
* both ends. A transport setting of this server's, not part of the API's contract.
|
|
172
190
|
*/
|
|
173
191
|
compress?: boolean | "auto";
|
|
174
|
-
} & LambderRequirableGuardsField<_TPublicGuardsRequired, TGuardsOpt>,
|
|
175
|
-
/** Answers the call by returning its output (parsed through `output` before it is sent), or refuses it with refuse(). */
|
|
176
|
-
handler: (ctx: LambderRenderContext<z.infer<TInput>, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt>, TSessionData, _TRateLimitPolicies>
|
|
177
|
-
|
|
192
|
+
} & LambderRequirableGuardsField<_TPublicGuardsRequired, TGuardsOpt> & LambderObjectOutputCheck<TOutput>,
|
|
193
|
+
/** Answers the call by returning its output (parsed through `output` before it is sent), or refuses it with ctx.refuse() or refuse(). */
|
|
194
|
+
handler: (ctx: LambderRenderContext<z.infer<TInput>, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt>, TSessionData, _TRateLimitPolicies> & {
|
|
195
|
+
refuse: LambderDeclaredRefuse<LambderHandlerRefusalsOf<_TRefusals, LambderApiRefusalCodes<_TRefusals, _TGuards, TRefusalsOpt, TGuardsOpt>>, _TRefusalCodesRequired>;
|
|
196
|
+
}) => MaybePromise<TAnswer>): Lambder<TSessionData, LambderMergeContract<_TContract, TName, LambderContractEntry<z.input<TInput>, LambderJsonOf<z.output<TOutput>>, "public", LambderGuardInputsOf<_TGuards, TGuardsOpt>, TGuardsOpt, TRateOpt, TIdempotencyOpt, LambderWireRefusalsOf<_TRefusals, LambderApiRefusalCodes<_TRefusals, _TGuards, TRefusalsOpt, TGuardsOpt>>>>, _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired, _TSessionsEnabled, _TRefusals, _TRefusalCodesRequired>;
|
|
197
|
+
addSessionApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TAnswer extends LambderReadonlyDeep<z.input<TOutput>>, 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, const TRefusalsOpt extends LambderRefusalsOption<_TRefusals> = never>(name: TName, schema: {
|
|
178
198
|
input: TInput;
|
|
179
199
|
output: TOutput;
|
|
180
200
|
} & {
|
|
181
|
-
/** 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,
|
|
201
|
+
/** 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, refusal on any). The first exceeded one refuses (429 envelope + Retry-After); attempts count on every counter checked before it. */
|
|
182
202
|
rateLimit?: TRateOpt;
|
|
183
203
|
/** Replay-protect this API per client idempotencyKey. Requires the idempotency option at creation. */
|
|
184
204
|
idempotency?: _TIdempotencyEnabled extends true ? TIdempotencyOpt : never;
|
|
205
|
+
/**
|
|
206
|
+
* The refusal codes this API may refuse with, from the vocabulary given at creation: one code or a
|
|
207
|
+
* non-empty list. Its guards' codes join them. The handler raises one with `ctx.refuse(content, { code, data })`,
|
|
208
|
+
* its callers narrow on them, and a refusal with any other code is a crash rather than an answer.
|
|
209
|
+
*/
|
|
210
|
+
refusals?: TRefusalsOpt;
|
|
185
211
|
/**
|
|
186
212
|
* Whether this API's answers are compressed for a caller that accepts it: "auto" (the default) when the
|
|
187
213
|
* body is large enough to gain, false never, true always. false suits an answer of base64 bytes: once
|
|
@@ -190,9 +216,11 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
190
216
|
* both ends. A transport setting of this server's, not part of the API's contract.
|
|
191
217
|
*/
|
|
192
218
|
compress?: boolean | "auto";
|
|
193
|
-
} & LambderRequirableGuardsField<_TSessionGuardsRequired, TGuardsOpt> & LambderSessionEnabledInstance<_TSessionsEnabled>,
|
|
194
|
-
/** Answers the call by returning its output (parsed through `output` before it is sent), or refuses it with refuse(). */
|
|
195
|
-
handler: (ctx: LambderSessionRenderContext<z.infer<TInput>, TSessionData, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt>, _TRateLimitPolicies>
|
|
219
|
+
} & LambderRequirableGuardsField<_TSessionGuardsRequired, TGuardsOpt> & LambderSessionEnabledInstance<_TSessionsEnabled> & LambderObjectOutputCheck<TOutput>,
|
|
220
|
+
/** Answers the call by returning its output (parsed through `output` before it is sent), or refuses it with ctx.refuse() or refuse(). */
|
|
221
|
+
handler: (ctx: LambderSessionRenderContext<z.infer<TInput>, TSessionData, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt>, _TRateLimitPolicies> & {
|
|
222
|
+
refuse: LambderDeclaredRefuse<LambderHandlerRefusalsOf<_TRefusals, LambderApiRefusalCodes<_TRefusals, _TGuards, TRefusalsOpt, TGuardsOpt>>, _TRefusalCodesRequired>;
|
|
223
|
+
}) => MaybePromise<TAnswer>): Lambder<TSessionData, LambderMergeContract<_TContract, TName, LambderContractEntry<z.input<TInput>, LambderJsonOf<z.output<TOutput>>, "session", LambderGuardInputsOf<_TGuards, TGuardsOpt>, TGuardsOpt, TRateOpt, TIdempotencyOpt, LambderWireRefusalsOf<_TRefusals, LambderApiRefusalCodes<_TRefusals, _TGuards, TRefusalsOpt, TGuardsOpt>>>>, _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired, _TSessionsEnabled, _TRefusals, _TRefusalCodesRequired>;
|
|
196
224
|
/**
|
|
197
225
|
* What registering an API is, for addApi and addSessionApi alike: the
|
|
198
226
|
* checks that can refuse it, then its definition recorded (what
|
|
@@ -223,7 +251,7 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
223
251
|
*/
|
|
224
252
|
addAction<TEvent>(filter: (event: unknown, ctx: LambderRenderContext | null) => event is TEvent, actionFn: (event: TEvent, tools: LambderActionTools) => MaybePromise<unknown>): this;
|
|
225
253
|
addAction(filter: (event: unknown, ctx: LambderRenderContext | null) => boolean, actionFn: (event: unknown, tools: LambderActionTools) => MaybePromise<unknown>): this;
|
|
226
|
-
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>;
|
|
254
|
+
use<_TNewContract extends Record<string, any>>(plugin: (lambder: Lambder<TSessionData, _TContract, any, any, any, any, any, any, any, any>) => Lambder<TSessionData, _TNewContract, any, any, any, any, any, any, any, any>): Lambder<TSessionData, _TNewContract extends _TContract ? _TNewContract : (_TContract & _TNewContract), _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired, _TSessionsEnabled, _TRefusals, _TRefusalCodesRequired>;
|
|
227
255
|
/**
|
|
228
256
|
* A session controller for a context: what creates, rotates, refreshes
|
|
229
257
|
* and ends sessions. An API call presents its posted CSRF token; a route
|
|
@@ -283,8 +311,10 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
283
311
|
* and guard name. A policy's key handler is never written: its `per`
|
|
284
312
|
* says "custom" and no more. A guard's input schema is never written
|
|
285
313
|
* either; its declaration says only which of the three input modes it
|
|
286
|
-
* has.
|
|
287
|
-
* and
|
|
314
|
+
* has. The refusal vocabulary is not written at all: it is shared code
|
|
315
|
+
* (codes, zod schemas, statuses and flags), and the mock declares the
|
|
316
|
+
* same object. Every table is sorted by name, so the module diffs by
|
|
317
|
+
* endpoint and never moves when registrations are reordered.
|
|
288
318
|
*/
|
|
289
319
|
apiOptionEntries(): LambderApiOptionEntries;
|
|
290
320
|
getResponseBuilder(ctx?: LambderRenderContext): LambderResponseBuilder;
|
|
@@ -399,7 +429,9 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
399
429
|
* see the declared shape. The handler returns the schema's input form, so
|
|
400
430
|
* a transform runs exactly once.
|
|
401
431
|
*
|
|
402
|
-
* An output the schema rejects is
|
|
432
|
+
* An output the schema rejects, or one that is not an object or an array
|
|
433
|
+
* (isObjectPayload: what makes a caller's success never falsy), is the
|
|
434
|
+
* handler breaking its contract,
|
|
403
435
|
* answered as a crash rather than sent (LambderApiOutputValidationError,
|
|
404
436
|
* which an idempotency key records as its answer, since the handler has
|
|
405
437
|
* already run). The parse is synchronous, so an output schema cannot be
|
|
@@ -411,7 +443,13 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
411
443
|
* and every retry would run the operation again.
|
|
412
444
|
*/
|
|
413
445
|
private runApi;
|
|
414
|
-
/**
|
|
446
|
+
/**
|
|
447
|
+
* A thrown LambderApiRefusal (from a hook, say) as the structured API
|
|
448
|
+
* envelope: the core's one mapping, after the same check the pipeline
|
|
449
|
+
* applies, against the endpoint the call names. A name no API is
|
|
450
|
+
* registered under declares no code, so only an uncoded or a framework
|
|
451
|
+
* refusal goes out for it.
|
|
452
|
+
*/
|
|
415
453
|
private apiErrorResponse;
|
|
416
454
|
}
|
|
417
455
|
/**
|
|
@@ -446,10 +484,70 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
446
484
|
* session type in the first call lets the second infer everything else.
|
|
447
485
|
* `new Lambder(options)` serves untyped or session-data-free instances.
|
|
448
486
|
*/
|
|
487
|
+
/** The options create() takes: the constructor's, less the two declareRefusals() supplies. */
|
|
488
|
+
export type LambderInitCreateOptions<TSessionData> = Omit<LambderCreateOptions<TSessionData>, "refusals" | "requireRefusalCodes">;
|
|
489
|
+
/**
|
|
490
|
+
* The entry point of an app: binds the session data type, and hands out the
|
|
491
|
+
* builders and create() that share it. `declareRefusals()` binds the app's
|
|
492
|
+
* refusal vocabulary too, so a guard's ctx.refuse and the init's own refuse
|
|
493
|
+
* are typed to it before any instance exists, and create() gives it to the
|
|
494
|
+
* instance for every API's refusals option to name codes from.
|
|
495
|
+
*/
|
|
449
496
|
export declare const initLambder: <TSessionData = any>() => {
|
|
450
|
-
|
|
497
|
+
/**
|
|
498
|
+
* Declares the app's refusal vocabulary: every code once, with the schema
|
|
499
|
+
* of its data (`{ data: schema }`) or none (`{}`), the status every
|
|
500
|
+
* refusal with it leaves with (`status`, 200 by default) and whether it
|
|
501
|
+
* sets the notAuthorized flag (`notAuthorized: true`). Returns the init
|
|
502
|
+
* bound to it: its guard() types ctx.refuse to a guard's refusals and
|
|
503
|
+
* refuses a guard naming a code outside the vocabulary, its refuse is
|
|
504
|
+
* typed to the whole vocabulary, and its create() hands the vocabulary to
|
|
505
|
+
* the instance. With `requireCodes`, an uncoded refusal from an API
|
|
506
|
+
* handler, a guard or a helper is a crash rather than an answer, so every
|
|
507
|
+
* "no" a client reads names a code.
|
|
508
|
+
*/
|
|
509
|
+
declareRefusals<const TRefusals extends LambderRefusalVocabulary, const TRequireCodes extends boolean = false>(refusals: TRefusals & LambderRefusalVocabularyChecks<TRefusals>, options?: {
|
|
510
|
+
requireCodes?: TRequireCodes;
|
|
511
|
+
}): {
|
|
512
|
+
/**
|
|
513
|
+
* refuse() typed to the app's whole vocabulary, for a shared helper or a
|
|
514
|
+
* hook that raises a declared code with no endpoint in hand: `code` is
|
|
515
|
+
* one of the vocabulary's and `data` follows it. Which endpoint may send
|
|
516
|
+
* the code is checked where the refusal is rendered, as for the free
|
|
517
|
+
* refuse(). Inside an API handler ctx.refuse is narrower, that
|
|
518
|
+
* endpoint's codes alone.
|
|
519
|
+
*/
|
|
520
|
+
refuse: LambderDeclaredRefuse<LambderHandlerRefusalsOf<TRefusals, keyof TRefusals & string>, TRequireCodes>;
|
|
521
|
+
create<const TOptions extends LambderInitCreateOptions<TSessionData>>(options: TOptions & Record<Exclude<keyof TOptions, "session" | "guards" | "idempotency" | "apiVersion" | "cors" | "apiPath" | "apiSignatures" | "trustedClientIpHeaders" | "trustedHostHeaders" | "files" | "etag" | "minApiVersion" | "compression" | "maxResponseBytes" | "maxRequestPayloadBytes" | "rateLimits" | "requireSessionApiGuards" | "requirePublicApiGuards" | "crashes">, never> & LambderNestedOptionChecks<TSessionData, TOptions, TRefusals>): Lambder<TSessionData, {}, TOptions["rateLimits"] extends {
|
|
522
|
+
policies: infer TPolicies extends Record<string, LambderApiRateLimitPolicyConfig>;
|
|
523
|
+
} ? 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, TRefusals, TRequireCodes>;
|
|
524
|
+
guard: import("../api/LambderApiGuards.js").LambderGuardBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>, LambderSessionRenderContext<any, TSessionData>, TRefusals, TRequireCodes>;
|
|
525
|
+
rateLimitKey: import("../api/LambderApiRateLimits.js").LambderRateLimitKeyBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>>;
|
|
526
|
+
};
|
|
527
|
+
/**
|
|
528
|
+
* refuse() typed to the app's whole vocabulary, for a shared helper or a
|
|
529
|
+
* hook that raises a declared code with no endpoint in hand: `code` is
|
|
530
|
+
* one of the vocabulary's and `data` follows it. Which endpoint may send
|
|
531
|
+
* the code is checked where the refusal is rendered, as for the free
|
|
532
|
+
* refuse(). Inside an API handler ctx.refuse is narrower, that
|
|
533
|
+
* endpoint's codes alone.
|
|
534
|
+
*/
|
|
535
|
+
refuse: (content: string, options?: ({
|
|
536
|
+
cause?: unknown;
|
|
537
|
+
type?: import("../shared/wire/LambderApiRefusal.js").LambderRefusalMessage["type"] | undefined;
|
|
538
|
+
title?: string | undefined;
|
|
539
|
+
notAuthorized?: boolean | undefined;
|
|
540
|
+
sessionExpired?: boolean | undefined;
|
|
541
|
+
statusCode?: import("../client.js").LambderHttpStatusCode | undefined;
|
|
542
|
+
headers?: Record<string, string> | undefined;
|
|
543
|
+
} & {
|
|
544
|
+
code?: undefined;
|
|
545
|
+
data?: undefined;
|
|
546
|
+
}) | undefined) => never;
|
|
547
|
+
create<const TOptions extends LambderInitCreateOptions<TSessionData>>(options: TOptions & Record<Exclude<keyof TOptions, "session" | "guards" | "idempotency" | "apiVersion" | "cors" | "apiPath" | "apiSignatures" | "trustedClientIpHeaders" | "trustedHostHeaders" | "files" | "etag" | "minApiVersion" | "compression" | "maxResponseBytes" | "maxRequestPayloadBytes" | "rateLimits" | "requireSessionApiGuards" | "requirePublicApiGuards" | "crashes">, never> & LambderNestedOptionChecks<TSessionData, TOptions, {}>): Lambder<TSessionData, {}, TOptions["rateLimits"] extends {
|
|
451
548
|
policies: infer TPolicies extends Record<string, LambderApiRateLimitPolicyConfig>;
|
|
452
|
-
} ? 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>;
|
|
453
|
-
guard: import("../api/LambderApiGuards.js").LambderGuardBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>, LambderSessionRenderContext<any, TSessionData
|
|
549
|
+
} ? 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, {}, false>;
|
|
550
|
+
guard: import("../api/LambderApiGuards.js").LambderGuardBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>, LambderSessionRenderContext<any, TSessionData>, {}, false>;
|
|
454
551
|
rateLimitKey: import("../api/LambderApiRateLimits.js").LambderRateLimitKeyBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>>;
|
|
455
552
|
};
|
|
553
|
+
export {};
|