lambder 15.1.1 → 16.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 +92 -0
- package/dist/api/LambderApiDeclarations.d.ts +21 -5
- package/dist/api/LambderApiDeclarations.js +21 -3
- package/dist/api/LambderApiGuards.d.ts +23 -3
- package/dist/api/LambderApiGuards.js +50 -25
- package/dist/api/LambderApiModules.d.ts +50 -0
- package/dist/api/LambderApiModules.js +36 -0
- package/dist/api/LambderApiPipeline.d.ts +27 -4
- package/dist/api/LambderApiPipeline.js +71 -5
- package/dist/api/LambderApiRateLimits.d.ts +35 -4
- package/dist/api/LambderApiRateLimits.js +74 -35
- package/dist/core/Lambder.d.ts +62 -87
- package/dist/core/Lambder.js +105 -57
- package/dist/core/LambderApiBuilders.d.ts +105 -0
- package/dist/core/LambderApiBuilders.js +12 -0
- package/dist/core/LambderApiModule.d.ts +106 -0
- package/dist/core/LambderApiModule.js +45 -0
- package/dist/core/LambderCreateOptions.d.ts +20 -16
- package/dist/index.d.ts +10 -5
- package/dist/index.js +2 -0
- package/dist/mock/LambderMockApiModule.d.ts +70 -0
- package/dist/mock/LambderMockApiModule.js +34 -0
- package/dist/mock/LambderMockApp.d.ts +53 -8
- package/dist/mock/LambderMockApp.js +104 -28
- package/dist/mock/LambderMockCreateOptions.d.ts +18 -18
- package/dist/mock/LambderMockTypes.d.ts +46 -26
- package/dist/mock.d.ts +4 -1
- package/dist/mock.js +2 -0
- package/dist/shared/util/LambderTypeUtilities.d.ts +1 -1
- package/package.json +1 -1
|
@@ -19,15 +19,15 @@ import { type LambderRefusalVocabulary } from "../api/LambderApiRefusals.js";
|
|
|
19
19
|
import type { LambderNoExtraKeys } from "../shared/util/LambderTypeUtilities.js";
|
|
20
20
|
import type { LambderGuardNamesIn, LambderJsonOf } from "../shared/wire/LambderApiContract.js";
|
|
21
21
|
import type { LambderRateLimitMessage } from "../shared/wire/LambderApiOptionValues.js";
|
|
22
|
-
import type {
|
|
23
|
-
export type LambderRouteHandler = (ctx: LambderRenderContext, resolver: LambderResolver) =>
|
|
24
|
-
export type LambderSessionRouteHandler<SessionData = any> = (ctx: LambderSessionRenderContext<any, SessionData>, resolver: LambderResolver) =>
|
|
22
|
+
import type { LambderMaybePromise } from "../shared/util/LambderTypeUtilities.js";
|
|
23
|
+
export type LambderRouteHandler = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderMaybePromise<LambderResponse>;
|
|
24
|
+
export type LambderSessionRouteHandler<SessionData = any> = (ctx: LambderSessionRenderContext<any, SessionData>, resolver: LambderResolver) => LambderMaybePromise<LambderResponse>;
|
|
25
25
|
export type LambderHookEvent = "created" | "beforeRender" | "afterRender" | "fallback";
|
|
26
26
|
/** Return the (possibly replaced) ctx to continue, a LambderResponse to short-circuit, or an Error to fail. */
|
|
27
|
-
export type LambderBeforeRenderHook = (ctx: LambderRenderContext, resolver: LambderResolver) =>
|
|
28
|
-
export type LambderAfterRenderHook = (ctx: LambderRenderContext, resolver: LambderResolver, response: LambderResponse) =>
|
|
27
|
+
export type LambderBeforeRenderHook = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderMaybePromise<LambderRenderContext | LambderResponse | Error>;
|
|
28
|
+
export type LambderAfterRenderHook = (ctx: LambderRenderContext, resolver: LambderResolver, response: LambderResponse) => LambderMaybePromise<LambderResponse | Error>;
|
|
29
29
|
export type LambderFallbackHook = (ctx: LambderRenderContext, resolver: LambderResolver) => void | Promise<void>;
|
|
30
|
-
export type LambderGlobalErrorHandler = (err: Error, ctx: LambderRenderContext | null, response: LambderResponseBuilder) =>
|
|
30
|
+
export type LambderGlobalErrorHandler = (err: Error, ctx: LambderRenderContext | null, response: LambderResponseBuilder) => LambderMaybePromise<LambderResponse>;
|
|
31
31
|
/**
|
|
32
32
|
* Where a crash happened.
|
|
33
33
|
*
|
|
@@ -68,7 +68,7 @@ export type LambderCrashSite = {
|
|
|
68
68
|
* password in the body, the session record): forward the fields a crash
|
|
69
69
|
* needs rather than the whole context to an error tracker.
|
|
70
70
|
*/
|
|
71
|
-
export type LambderCrashReporter = (error: Error, site: LambderCrashSite) =>
|
|
71
|
+
export type LambderCrashReporter = (error: Error, site: LambderCrashSite) => LambderMaybePromise<void>;
|
|
72
72
|
/** The `crashes` option of create(). */
|
|
73
73
|
export type LambderCrashOptions = {
|
|
74
74
|
/** Told every crash on every path; see LambderCrashReporter. Default: none, and the framework's own 500 logs the crash to the console instead. */
|
|
@@ -88,10 +88,10 @@ export type LambderCrashOptions = {
|
|
|
88
88
|
* writes its own answer, and describeCrash is there for it. A reveal
|
|
89
89
|
* that throws counts as no. Default: nobody.
|
|
90
90
|
*/
|
|
91
|
-
reveal?: (ctx: LambderRenderContext) =>
|
|
91
|
+
reveal?: (ctx: LambderRenderContext) => LambderMaybePromise<boolean>;
|
|
92
92
|
};
|
|
93
|
-
export type LambderFallbackHandler = (ctx: LambderRenderContext, resolver: LambderResolver) =>
|
|
94
|
-
export type LambderInputValidationHandler = (ctx: LambderRenderContext, resolver: LambderResolver, zodError: z.ZodError) =>
|
|
93
|
+
export type LambderFallbackHandler = (ctx: LambderRenderContext, resolver: LambderResolver) => LambderMaybePromise<LambderResponse>;
|
|
94
|
+
export type LambderInputValidationHandler = (ctx: LambderRenderContext, resolver: LambderResolver, zodError: z.ZodError) => LambderMaybePromise<LambderResponse>;
|
|
95
95
|
/**
|
|
96
96
|
* Second argument of an addAction handler. Discriminated on `ctx`: HTTP
|
|
97
97
|
* invocations get the full context and a resolver, non-HTTP invocations get
|
|
@@ -107,7 +107,7 @@ export type LambderActionTools = {
|
|
|
107
107
|
lambdaContext: Context;
|
|
108
108
|
};
|
|
109
109
|
export type LambderActionFilter = (event: unknown, ctx: LambderRenderContext | null) => boolean;
|
|
110
|
-
export type LambderActionHandler<TEvent = unknown> = (event: TEvent, tools: LambderActionTools) =>
|
|
110
|
+
export type LambderActionHandler<TEvent = unknown> = (event: TEvent, tools: LambderActionTools) => LambderMaybePromise<unknown>;
|
|
111
111
|
/** Overloaded handler type returned by getHandler(): HTTP events get a typed response, others dispatch to actions. */
|
|
112
112
|
export type LambderHandler = {
|
|
113
113
|
(event: LambderHttpEvent, context: Context): Promise<LambderHttpResponse>;
|
|
@@ -170,8 +170,12 @@ export type LambderGuardsMap<TSessionData = any> = Record<string, LambderApiGuar
|
|
|
170
170
|
export type LambderRateLimitPoliciesMap = Record<string, LambderApiRateLimitPolicyConfig<LambderRenderContext>>;
|
|
171
171
|
/** The `rateLimits` option of create(): the engine's config, with `policies` as one map or a list of maps. */
|
|
172
172
|
export type LambderCreateRateLimitsOption = Omit<LambderApiRateLimitsConfig<LambderRateLimitPoliciesMap>, "policies"> & {
|
|
173
|
-
/**
|
|
174
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Named policies referenced (typed) from defineApi: one map, or a list of
|
|
175
|
+
* maps merged in order. Left out where every policy is declared by the
|
|
176
|
+
* app's modules (defineApiModule), which count on this limiter.
|
|
177
|
+
*/
|
|
178
|
+
policies?: LambderNamedMapsOption<LambderRateLimitPoliciesMap>;
|
|
175
179
|
};
|
|
176
180
|
/** The options as the instance holds them: the guards and the rate-limit policies merged into one map each. */
|
|
177
181
|
export type LambderMergedCreateOptions<TSessionData = any> = Omit<LambderCreateOptions<TSessionData>, "guards" | "rateLimits"> & {
|
|
@@ -475,7 +479,7 @@ type LambderGuardRefusalsKnown<TGuard, TRefusals> = TGuard extends {
|
|
|
475
479
|
refusals: readonly (keyof NonNullable<TRefusals> & string)[];
|
|
476
480
|
} : unknown : unknown;
|
|
477
481
|
/** Every policy in a map, or in each map of a list, held to the policy shape, its message included; a list also declares no name twice. */
|
|
478
|
-
type LambderRateLimitPolicyChecks<TPolicies> = TPolicies extends readonly unknown[] ? {
|
|
482
|
+
export type LambderRateLimitPolicyChecks<TPolicies> = TPolicies extends readonly unknown[] ? {
|
|
479
483
|
[TIndex in keyof TPolicies]: LambderRateLimitPolicyChecks<TPolicies[TIndex]>;
|
|
480
484
|
} & LambderNoRepeatedNames<TPolicies> : {
|
|
481
485
|
[TPolicy in keyof TPolicies]: LambderNoExtraKeys<TPolicies[TPolicy], LambderApiRateLimitPolicyConfig<LambderRenderContext>> & (TPolicies[TPolicy] extends {
|
|
@@ -485,7 +489,7 @@ type LambderRateLimitPolicyChecks<TPolicies> = TPolicies extends readonly unknow
|
|
|
485
489
|
} : unknown);
|
|
486
490
|
};
|
|
487
491
|
/** Every guard in a map, or in each map of a list, held to the guard shape and its refusals to the vocabulary; a list also declares no name twice. */
|
|
488
|
-
type LambderGuardChecks<TSessionData, TGuards, TRefusals> = TGuards extends readonly unknown[] ? {
|
|
492
|
+
export type LambderGuardChecks<TSessionData, TGuards, TRefusals> = TGuards extends readonly unknown[] ? {
|
|
489
493
|
[TIndex in keyof TGuards]: LambderGuardChecks<TSessionData, TGuards[TIndex], TRefusals>;
|
|
490
494
|
} & LambderNoRepeatedNames<TGuards> : {
|
|
491
495
|
[TGuard in keyof TGuards]: LambderNoExtraKeys<TGuards[TGuard], LambderGuardsMap<TSessionData>[string]> & LambderGuardRefusalsKnown<TGuards[TGuard], TRefusals>;
|
|
@@ -510,7 +514,7 @@ export type LambderNestedOptionChecks<TSessionData, TOptions extends LambderCrea
|
|
|
510
514
|
crashes?: LambderNoExtraKeys<NonNullable<TOptions["crashes"]>, LambderOptionShape<TSessionData, "crashes">>;
|
|
511
515
|
originProof?: LambderNoExtraKeys<NonNullable<TOptions["originProof"]>, LambderOptionShape<TSessionData, "originProof">>;
|
|
512
516
|
rateLimits?: LambderNoExtraKeys<NonNullable<TOptions["rateLimits"]>, LambderOptionShape<TSessionData, "rateLimits">> & {
|
|
513
|
-
policies?: LambderRateLimitPolicyChecks<NonNullable<TOptions["rateLimits"]>["policies"]
|
|
517
|
+
policies?: LambderRateLimitPolicyChecks<NonNullable<NonNullable<TOptions["rateLimits"]>["policies"]>>;
|
|
514
518
|
};
|
|
515
519
|
guards?: LambderGuardChecks<TSessionData, NonNullable<TOptions["guards"]>, TRefusals>;
|
|
516
520
|
files?: TOptions["files"] extends {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import Lambder from './core/Lambder.js';
|
|
2
2
|
export default Lambder;
|
|
3
3
|
export { initLambder } from './core/Lambder.js';
|
|
4
|
-
export type { LambderCreatedHook } from './core/Lambder.js';
|
|
5
|
-
export type {
|
|
4
|
+
export type { LambderCreatedHook, LambderInitCreateOptions } from './core/Lambder.js';
|
|
5
|
+
export type { LambderDefineApi, LambderDefineApiGroup, LambderDefineLazyApiGroup, LambderApiHandlerContext, } from './core/LambderApiBuilders.js';
|
|
6
|
+
export { LambderApiModule } from './core/LambderApiModule.js';
|
|
7
|
+
export type { LambderApiModuleOptions, LambderApiModuleOptionChecks, LambderModuleAppTypes } from './core/LambderApiModule.js';
|
|
8
|
+
export type { LambderApiModuleDeclarations } from './api/LambderApiModules.js';
|
|
9
|
+
export type { LambderAppTypes, LambderPlainAppTypes, LambderApiDeclaration, LambderApiDeclarations, LambderApiGroup, LambderLazyApiGroup, LambderRegistrableApiGroup, LambderApiModeOf, LambderEntryOf, LambderContractOfGroups, LambderRegisteredGroupsCheck, LambderActionNamesCheck, LambderGroupNameCheck, LambderGroupPartsCheck, LambderMergedParts, LambderPublicSessionPolicyCheck, LambderSessionModeCheck, } from './api/LambderApiDeclarations.js';
|
|
6
10
|
export { apiCallPath, apiNameOfCallPath, splitApiName, isGroupName, isActionName, LAMBDER_API_NAME_SEGMENT, LAMBDER_CALLER_MEMBER_NAMES, LAMBDER_RESERVED_GROUP_NAMES, LAMBDER_RESERVED_ACTION_NAMES, } from './shared/wire/LambderApiNames.js';
|
|
7
11
|
export type { LambderReservedGroupName, LambderReservedActionName } from './shared/wire/LambderApiNames.js';
|
|
8
12
|
export type { LambderContractGroupsOf, LambderContractNamesInGroup, LambderContractActionOf } from './shared/wire/LambderApiGroupCalls.js';
|
|
@@ -77,7 +81,7 @@ export type { LambderTemplateData, LambderTemplatingEngineOptions } from "./core
|
|
|
77
81
|
export type { LambderResponseOptions, LambderRawResponseInit, LambderTemplateFileOptions, } from "./core/LambderResponseBuilder.js";
|
|
78
82
|
export type { LambderRouteMatcher, LambderRouteConditionFn, LambderRouteCondition, LambderPathParamsOf, LambderRoutePath } from "./core/LambderRouting.js";
|
|
79
83
|
export type { LambderCorsConfig } from "./core/LambderCors.js";
|
|
80
|
-
export type { LambderCreateOptions, LambderSessionOptions, LambderActionTools, LambderHandler, } from "./core/LambderCreateOptions.js";
|
|
84
|
+
export type { LambderCreateOptions, LambderSessionOptions, LambderActionTools, LambderHandler, LambderGivenOption, LambderNamedMapsOption, LambderMergedNamedMaps, LambderNestedOptionChecks, LambderObjectOutputCheck, LambderPayloadSliceCheck, LambderRequirableGuardsField, LambderSessionEnabledInstance, } from "./core/LambderCreateOptions.js";
|
|
81
85
|
export type { LambderIndexHtmlOptions } from "./core/LambderIndexHtml.js";
|
|
82
86
|
export type { LambderRouteHandler, LambderSessionRouteHandler, LambderActionHandler, LambderActionFilter, LambderHookEvent, LambderBeforeRenderHook, LambderAfterRenderHook, LambderFallbackHook, LambderGlobalErrorHandler, LambderFallbackHandler, LambderInputValidationHandler, LambderCrashOptions, LambderCrashReporter, LambderCrashSite, } from "./core/LambderCreateOptions.js";
|
|
83
87
|
export type { LambderPublicFilesOptions } from "./core/LambderPublicFiles.js";
|
|
@@ -136,10 +140,11 @@ export { lambderGuard, lambderRateLimitKey } from "./core/LambderPolicyBuilders.
|
|
|
136
140
|
export { lambderGuardBuilder } from "./api/LambderApiGuards.js";
|
|
137
141
|
export type { LambderGuardBuilder, LambderApiGuard, LambderGuardMeta, LambderGuardMetaMap, LambderGuardRunAt, LambderAllowedGuardNames, LambderGuardNamesInputLacks, LambderParamlessGuardNames, LambderGuardsOption, LambderGuardDataOf, LambderGuardInputsOf, LambderGuardRefusals, LambderGuardRefusalNamesOf, } from "./api/LambderApiGuards.js";
|
|
138
142
|
export { LambderApiRefusalValidationError } from "./api/LambderApiRefusals.js";
|
|
139
|
-
export type { LambderRefusalDeclaration, LambderRefusalVocabulary, LambderRefusalVocabularyOption, LambderMergedRefusalVocabulary, LambderApiAllowedRefusal, LambderApiAllowedRefusals, LambderEndpointRefusals, LambderRefusalsOption, LambderRefusalNamesIn, LambderHandlerRefusalsOf, LambderWireRefusalsOf, } from "./api/LambderApiRefusals.js";
|
|
143
|
+
export type { LambderRefusalDeclaration, LambderRefusalVocabulary, LambderRefusalVocabularyOption, LambderRefusalVocabularyOptionChecks, LambderMergedRefusalVocabulary, LambderApiAllowedRefusal, LambderApiAllowedRefusals, LambderEndpointRefusals, LambderRefusalsOption, LambderRefusalNamesIn, LambderHandlerRefusalsOf, LambderWireRefusalsOf, } from "./api/LambderApiRefusals.js";
|
|
140
144
|
export { lambderRateLimitKeyBuilder, rateLimitRefusal, DEFAULT_RATE_LIMIT_REFUSAL } from "./api/LambderApiRateLimits.js";
|
|
141
145
|
export type { LambderRateLimitKeyBuilder } from "./api/LambderApiRateLimits.js";
|
|
142
|
-
export type { LambderContextRateLimit, LambderContextRateLimitCheck, LambderRateLimitCheckResult, LambderChargeablePolicyNames, LambderChargeKeyArgs, LambderRateLimitKeyFn, LambderRateLimitPer, LambderRateLimitBudget, LambderRateLimitChargeAt, LambderApiRateLimitPolicyConfig, LambderApiRateLimitsConfig, LambderAllowedPolicyNames, LambderPolicyNamesInputLacks, LambderRateLimitOption, } from "./api/LambderApiRateLimits.js";
|
|
146
|
+
export type { LambderContextRateLimit, LambderContextRateLimitCheck, LambderRateLimitCheckResult, LambderChargeablePolicyNames, LambderChargeKeyArgs, LambderRateLimitKeyFn, LambderRateLimitPer, LambderRateLimitBudget, LambderRateLimitChargeAt, LambderApiRateLimitPolicyConfig, LambderApiRateLimitsConfig, LambderAllowedPolicyNames, LambderPolicyNamesInputLacks, LambderRateLimitOption, LambderPolicyPerOf, } from "./api/LambderApiRateLimits.js";
|
|
147
|
+
export type { LambderMaybePromise, LambderNoExtraKeys } from "./shared/util/LambderTypeUtilities.js";
|
|
143
148
|
export type { LambderApiIdempotencyConfig } from "./api/LambderApiIdempotency.js";
|
|
144
149
|
export type { LambderGuardsOptionValue, LambderRateLimitMessage, LambderRateLimitOverride, LambderRateLimitOptionValue, LambderRefusalsOptionValue, LambderApiIdempotencyOption, } from "./shared/wire/LambderApiOptionValues.js";
|
|
145
150
|
export { apiGuardParam, apiGuardParamExportName, apisWithGuard } from "./shared/wire/LambderApiOptionEntries.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import Lambder from './core/Lambder.js';
|
|
2
2
|
export default Lambder;
|
|
3
3
|
export { initLambder } from './core/Lambder.js';
|
|
4
|
+
// Modules: guards and rate-limit policies a part of an app declares for its own endpoints.
|
|
5
|
+
export { LambderApiModule } from './core/LambderApiModule.js';
|
|
4
6
|
// How an endpoint is named, and where a call to it goes.
|
|
5
7
|
export { apiCallPath, apiNameOfCallPath, splitApiName, isGroupName, isActionName, LAMBDER_API_NAME_SEGMENT, LAMBDER_CALLER_MEMBER_NAMES, LAMBDER_RESERVED_GROUP_NAMES, LAMBDER_RESERVED_ACTION_NAMES, } from './shared/wire/LambderApiNames.js';
|
|
6
8
|
export { default as LambderCaller } from "./client/LambderCaller.js";
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { LambderApiContractShape } from "../shared/wire/LambderApiContract.js";
|
|
3
|
+
import type { LambderApiGuard } from "../api/LambderApiGuards.js";
|
|
4
|
+
import type { LambderRefusalVocabulary } from "../api/LambderApiRefusals.js";
|
|
5
|
+
import type { LambderMockGuardsAgree, LambderMockGuardShapes } from "./LambderMockCreateOptions.js";
|
|
6
|
+
import type { LambderMockCallContext, LambderMockEntry, LambderMockEntryGuardsCheck, LambderMockEntryInput, LambderMockGuardMapChecks, LambderMockHandler, LambderMockNotMockedGuardsCheck, LambderMockNotMockedInput, LambderMockOverride, LambderMockSessionCallContext, LambderMockSlice } from "./LambderMockTypes.js";
|
|
7
|
+
/**
|
|
8
|
+
* What a mock app's defineApiModule() takes: the mock guards a part of the
|
|
9
|
+
* app declares for its own endpoints, standing in for the guards the
|
|
10
|
+
* server's module declares (its defineApiModule), as create()'s guards stand
|
|
11
|
+
* in for the server instance's. One map.
|
|
12
|
+
*
|
|
13
|
+
* No rate-limit policies: a mock takes every policy at create(), from the
|
|
14
|
+
* generated table the server writes (lambderMockPoliciesFrom), the module's
|
|
15
|
+
* among them, so none is restated by hand here.
|
|
16
|
+
*/
|
|
17
|
+
export type LambderMockApiModuleOptions<S = any> = {
|
|
18
|
+
/** The module's mock guards, one per guard the server's module declares, built with the mock init's guard(). */
|
|
19
|
+
guards: Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>>;
|
|
20
|
+
};
|
|
21
|
+
/** A module's map held to declaring names of its own: one the mock app's create() declares is a compile error, and the property name is the message. */
|
|
22
|
+
type LambderMockModuleNamesCheck<MG, TAppNames> = [
|
|
23
|
+
Extract<keyof MG, TAppNames>
|
|
24
|
+
] extends [never] ? unknown : {
|
|
25
|
+
readonly "lambder: the mock app declares these guards already; a module declares guards of its own": Extract<keyof MG, TAppNames>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A module's mock guards held to what create()'s are held to: the contract,
|
|
29
|
+
* the generated guard declarations when the app was given them, surplus
|
|
30
|
+
* keys, and names of their own.
|
|
31
|
+
*/
|
|
32
|
+
export type LambderMockApiModuleChecks<C, S, G, D, TOptions extends LambderMockApiModuleOptions<S>> = {
|
|
33
|
+
guards: LambderMockGuardMapChecks<C, S, TOptions["guards"]> & LambderMockGuardShapes<S, TOptions["guards"]> & LambderMockGuardsAgree<TOptions["guards"], D> & LambderMockModuleNamesCheck<TOptions["guards"], keyof G>;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* What a mock module asks of the app that made it: the app's own entry
|
|
37
|
+
* builders, given the module's declarations. The constructor's parameter,
|
|
38
|
+
* which the app's defineApiModule() passes; an app does not build one.
|
|
39
|
+
*/
|
|
40
|
+
export type LambderMockApiModuleDoor = {
|
|
41
|
+
api: (name: string, entry: unknown) => LambderMockEntry<any, any>;
|
|
42
|
+
notMocked: (name: string, input: unknown) => LambderMockEntry<any, any>;
|
|
43
|
+
apiSlice: (...entries: readonly LambderMockEntry<any, any>[]) => unknown;
|
|
44
|
+
override: (name: string, handler: unknown) => LambderMockOverride;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* A part of a mock app with mock guards of its own: the app's entry builders,
|
|
48
|
+
* typed with the module's guards beside the app's. Made by the mock app's
|
|
49
|
+
* defineApiModule(); its entries are registered as any are (register,
|
|
50
|
+
* registerPartial), and registering them adds the module's guards to the
|
|
51
|
+
* app, refusing a name the app or another module declares. The mock twin of
|
|
52
|
+
* the server's LambderApiModule, so a module's mock guards are declared with
|
|
53
|
+
* the module's mocks, and the app's own setup imports none of them.
|
|
54
|
+
*
|
|
55
|
+
* `G` is the app's guards and the module's together, which is what the
|
|
56
|
+
* entries' handlers read guardData by.
|
|
57
|
+
*/
|
|
58
|
+
export declare class LambderMockApiModule<C extends LambderApiContractShape, S = any, G extends Record<string, LambderApiGuard<any, any, any>> = {}, TDerived extends boolean = false, TVocabulary extends LambderRefusalVocabulary = never, TCodesRequired extends boolean = false> {
|
|
59
|
+
private readonly door;
|
|
60
|
+
constructor(door: LambderMockApiModuleDoor);
|
|
61
|
+
/** A mock for one of the module's endpoints, as the app's api() builds one: its guards may be the app's and the module's own. */
|
|
62
|
+
api<K extends keyof C & string, TInputSchema extends z.ZodType = z.ZodType>(name: K & LambderMockEntryGuardsCheck<C, K, G, TDerived>, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived, TVocabulary, TCodesRequired>): LambderMockEntry<C, K>;
|
|
63
|
+
/** One of the module's endpoints deliberately left without a mock, as the app's notMocked() builds one; its restated guards may name the module's. */
|
|
64
|
+
notMocked<K extends keyof C & string>(name: K & LambderMockNotMockedGuardsCheck<C, K, G, TDerived>, input: LambderMockNotMockedInput<C, K, TDerived>): LambderMockEntry<C, K>;
|
|
65
|
+
/** The entries of one slice, keyed by name, as the app's apiSlice() gathers them. */
|
|
66
|
+
apiSlice<const E extends readonly LambderMockEntry<C, keyof C & string>[]>(...entries: E): LambderMockSlice<C, E[number]["name"]>;
|
|
67
|
+
/** Replaces one of the module's registered handlers until restored, as the app's override() does, its guardData typed with the module's guards. */
|
|
68
|
+
override<K extends keyof C & string>(name: K, handler: LambderMockHandler<C, K, S, G, TVocabulary, TCodesRequired>): LambderMockOverride;
|
|
69
|
+
}
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A part of a mock app with mock guards of its own: the app's entry builders,
|
|
3
|
+
* typed with the module's guards beside the app's. Made by the mock app's
|
|
4
|
+
* defineApiModule(); its entries are registered as any are (register,
|
|
5
|
+
* registerPartial), and registering them adds the module's guards to the
|
|
6
|
+
* app, refusing a name the app or another module declares. The mock twin of
|
|
7
|
+
* the server's LambderApiModule, so a module's mock guards are declared with
|
|
8
|
+
* the module's mocks, and the app's own setup imports none of them.
|
|
9
|
+
*
|
|
10
|
+
* `G` is the app's guards and the module's together, which is what the
|
|
11
|
+
* entries' handlers read guardData by.
|
|
12
|
+
*/
|
|
13
|
+
export class LambderMockApiModule {
|
|
14
|
+
door;
|
|
15
|
+
constructor(door) {
|
|
16
|
+
this.door = door;
|
|
17
|
+
}
|
|
18
|
+
/** A mock for one of the module's endpoints, as the app's api() builds one: its guards may be the app's and the module's own. */
|
|
19
|
+
api(name, entry) {
|
|
20
|
+
return this.door.api(name, entry);
|
|
21
|
+
}
|
|
22
|
+
/** One of the module's endpoints deliberately left without a mock, as the app's notMocked() builds one; its restated guards may name the module's. */
|
|
23
|
+
notMocked(name, input) {
|
|
24
|
+
return this.door.notMocked(name, input);
|
|
25
|
+
}
|
|
26
|
+
/** The entries of one slice, keyed by name, as the app's apiSlice() gathers them. */
|
|
27
|
+
apiSlice(...entries) {
|
|
28
|
+
return this.door.apiSlice(...entries);
|
|
29
|
+
}
|
|
30
|
+
/** Replaces one of the module's registered handlers until restored, as the app's override() does, its guardData typed with the module's guards. */
|
|
31
|
+
override(name, handler) {
|
|
32
|
+
return this.door.override(name, handler);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -7,6 +7,8 @@ import { type LambderDeclaredVocabulary, type LambderHandlerRefusalsOf, type Lam
|
|
|
7
7
|
import { type LambderApiTransport, type LambderApiTransportRequest } from "../shared/transport/LambderApiTransport.js";
|
|
8
8
|
import { LambderCookieJar } from "../shared/transport/LambderCookieJar.js";
|
|
9
9
|
import { type LambderApiGuard } from "../api/LambderApiGuards.js";
|
|
10
|
+
import type { LambderNoExtraKeys } from "../shared/util/LambderTypeUtilities.js";
|
|
11
|
+
import { LambderMockApiModule, type LambderMockApiModuleChecks, type LambderMockApiModuleOptions } from "./LambderMockApiModule.js";
|
|
10
12
|
import { LAMBDER_MOCK_ADAPTER_DOOR, type LambderMockAdapterDoor } from "./LambderMockAdapterDoor.js";
|
|
11
13
|
import { LambderMemoryRateLimiter } from "../stores/LambderMemoryRateLimiter.js";
|
|
12
14
|
import { LambderMemoryIdempotencyStore } from "../stores/LambderMemoryIdempotencyStore.js";
|
|
@@ -14,7 +16,7 @@ import { LambderMemorySessionStore } from "../stores/LambderMemorySessionStore.j
|
|
|
14
16
|
import LambderSessionManager, { type LambderCreatedSession } from "../session/LambderSessionManager.js";
|
|
15
17
|
import type { LambderMockAppOptions, LambderMockIdempotencyOptions, LambderMockTransport, LambderMockTransportOptions } from "./LambderMockCreateOptions.js";
|
|
16
18
|
import type { LambderApiOptionEntry, LambderGuardDeclarationEntry } from "../shared/wire/LambderApiOptionEntries.js";
|
|
17
|
-
import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, LambderMockEntryInput, LambderMockFailure, LambderMockFailureReason, LambderMockHandler, LambderMockLatency, LambderMockListener, LambderMockNotMockedInput, LambderMockRateLimitPolicies, LambderMockRegistryCheck, LambderMockRestEntry, LambderMockSessionCallContext, LambderMockSlice, LambderMockOverride, LambderMockRefusalsOf } from "./LambderMockTypes.js";
|
|
19
|
+
import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, LambderMockEntryGuardsCheck, LambderMockEntryInput, LambderMockFailure, LambderMockFailureReason, LambderMockHandler, LambderMockLatency, LambderMockListener, LambderMockNotMockedGuardsCheck, LambderMockNotMockedInput, LambderMockRateLimitPolicies, LambderMockRegistryCheck, LambderMockRestEntry, LambderMockSessionCallContext, LambderMockSlice, LambderMockOverride, LambderMockRefusalsOf } from "./LambderMockTypes.js";
|
|
18
20
|
/**
|
|
19
21
|
* The mock runtime: the API core (LambderApiPipeline, the same class the
|
|
20
22
|
* Lambda server runs) over memory stores, with typed mock handlers and mock
|
|
@@ -31,8 +33,10 @@ import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, L
|
|
|
31
33
|
* generated `apiOptions` table, whose entries are their handlers alone.
|
|
32
34
|
* `TVocabulary` and `TCodesRequired` are the refusal vocabulary the init
|
|
33
35
|
* declared (declareRefusals), which types every handler's ctx.refuse.
|
|
36
|
+
* `D` is the generated guard declarations create() was given, which a
|
|
37
|
+
* module's mock guards are held to as create()'s are.
|
|
34
38
|
*/
|
|
35
|
-
export declare class LambderMockApp<C extends LambderApiContractShape, S = any, G extends Record<string, LambderApiGuard<any, any, any>> = {}, TDerived extends boolean = false, TVocabulary extends LambderRefusalVocabulary = never, TCodesRequired extends boolean = false> {
|
|
39
|
+
export declare class LambderMockApp<C extends LambderApiContractShape, S = any, G extends Record<string, LambderApiGuard<any, any, any>> = {}, TDerived extends boolean = false, TVocabulary extends LambderRefusalVocabulary = never, TCodesRequired extends boolean = false, D extends Record<string, LambderGuardDeclarationEntry> = {}> {
|
|
36
40
|
readonly apiVersion: string | null;
|
|
37
41
|
/** The memory stores, for assertions and reset; null for a subsystem that is off or backed by a store of yours. */
|
|
38
42
|
readonly sessionStore: LambderMemorySessionStore<S> | null;
|
|
@@ -87,8 +91,8 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
87
91
|
private readonly apiOptions;
|
|
88
92
|
/** The server's schemas, when create() was given the generated table: every entry's input is validated, and every answer parsed, through them. */
|
|
89
93
|
private readonly apiSchemas;
|
|
90
|
-
/** The mock's own guards as create() was given them: which of them need a session, for an entry's mode without the apiOptions table. */
|
|
91
|
-
private
|
|
94
|
+
/** The mock's own guards as create() was given them, and every registered module's beside them: which of them need a session, for an entry's mode without the apiOptions table. */
|
|
95
|
+
private mockGuards;
|
|
92
96
|
/** The server's guard declarations, when create() was given the generated table: the refusal codes a declared guard adds to an entry. */
|
|
93
97
|
private readonly guardDeclarations;
|
|
94
98
|
/** The server's refusal vocabulary, when create() was given the generated table: whether each code an entry may refuse with carries data. */
|
|
@@ -100,6 +104,15 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
100
104
|
constructor(options: LambderMockAppOptions<C, S, G, LambderMockRateLimitPolicies<S>, boolean | LambderMockIdempotencyOptions<S>, {}, Record<string, LambderApiOptionEntry> | undefined>,
|
|
101
105
|
/** The vocabulary the init declared, or null: what initLambderMock().declareRefusals() passes on. */
|
|
102
106
|
declared?: LambderDeclaredVocabulary<TVocabulary, TCodesRequired> | null);
|
|
107
|
+
/**
|
|
108
|
+
* A mock guard stands in for the server's guard of its name, so it
|
|
109
|
+
* declares the codes that guard declares: its own refusals type its
|
|
110
|
+
* ctx.refuse and are what checkApiRefusals holds it to. The compiler
|
|
111
|
+
* compares literal lists at the guards option and at a module's; this
|
|
112
|
+
* catches a list typed as any string and a caller the compiler did not
|
|
113
|
+
* see.
|
|
114
|
+
*/
|
|
115
|
+
private assertGuardRefusalsAgree;
|
|
103
116
|
/**
|
|
104
117
|
* The registration-time checks every entry goes through, mocked or not:
|
|
105
118
|
* the ones the server runs on a definition, and the mock's own "a session
|
|
@@ -145,6 +158,11 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
145
158
|
* and defaulted as on the server). Either alone where only one is given.
|
|
146
159
|
*/
|
|
147
160
|
private entryInputOf;
|
|
161
|
+
/**
|
|
162
|
+
* An entry built and checked, by the app's api() or by a module's, whose
|
|
163
|
+
* declarations (`module`) its guards may name beside the app's own; the
|
|
164
|
+
* entry carries the module, which registering it adds.
|
|
165
|
+
*/
|
|
148
166
|
private buildEntry;
|
|
149
167
|
/**
|
|
150
168
|
* A mock for an endpoint: a handler, or the handler with the endpoint's
|
|
@@ -152,7 +170,7 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
152
170
|
* session endpoint's session is fetched before the handler runs, and a
|
|
153
171
|
* call without one is refused as on the server.
|
|
154
172
|
*/
|
|
155
|
-
api<K extends keyof C & string, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived, TVocabulary, TCodesRequired>): LambderMockEntry<C, K>;
|
|
173
|
+
api<K extends keyof C & string, TInputSchema extends z.ZodType = z.ZodType>(name: K & LambderMockEntryGuardsCheck<C, K, G, TDerived>, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived, TVocabulary, TCodesRequired>): LambderMockEntry<C, K>;
|
|
156
174
|
/**
|
|
157
175
|
* An endpoint deliberately left without a mock; a call answers the
|
|
158
176
|
* notMocked refusal carrying the reason. The refusal runs through the
|
|
@@ -162,7 +180,9 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
162
180
|
* apiOptions table a session endpoint restates its guards to say so,
|
|
163
181
|
* `notMocked(name, { reason, guards })`; no guard runs.
|
|
164
182
|
*/
|
|
165
|
-
notMocked<K extends keyof C & string>(name: K, input: LambderMockNotMockedInput<C, K, TDerived>): LambderMockEntry<C, K>;
|
|
183
|
+
notMocked<K extends keyof C & string>(name: K & LambderMockNotMockedGuardsCheck<C, K, G, TDerived>, input: LambderMockNotMockedInput<C, K, TDerived>): LambderMockEntry<C, K>;
|
|
184
|
+
/** A notMocked entry, by the app's notMocked() or by a module's, whose guards give its mode beside the app's own. */
|
|
185
|
+
private buildNotMockedEntry;
|
|
166
186
|
/**
|
|
167
187
|
* "Everything I did not register is not mocked, for this reason", as an
|
|
168
188
|
* argument to the same register() call:
|
|
@@ -190,8 +210,33 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
190
210
|
* a test cares about that path.
|
|
191
211
|
*/
|
|
192
212
|
restNotMocked(reason: string): LambderMockRestEntry;
|
|
213
|
+
/**
|
|
214
|
+
* Defines a module: the mock guards a part of the app declares with its
|
|
215
|
+
* own entries, standing in for the guards the server's module declares
|
|
216
|
+
* (its defineApiModule). Returns the module's entry builders, whose
|
|
217
|
+
* entries may name the app's guards and the module's own; registering
|
|
218
|
+
* them adds the module's guards to the app. So the app's create() need
|
|
219
|
+
* not import every module's mock guards.
|
|
220
|
+
*
|
|
221
|
+
* ```ts
|
|
222
|
+
* export const giftCardMocks = mockApp.defineApiModule({ guards: { cardHolder: mock.guard({ ... }) } });
|
|
223
|
+
* giftCardMocks.apiSlice(giftCardMocks.api("giftCards.redeem", async () => ({ redeemed: true })));
|
|
224
|
+
* ```
|
|
225
|
+
*
|
|
226
|
+
* Each guard is held to what create()'s are held to (the contract, the
|
|
227
|
+
* generated guardDeclarations, surplus keys); a name the app's create()
|
|
228
|
+
* declares is refused here, at compile time and at the call, and a name
|
|
229
|
+
* two modules declare when the second is registered.
|
|
230
|
+
*/
|
|
231
|
+
defineApiModule<const TOptions extends LambderMockApiModuleOptions<S>>(options: LambderNoExtraKeys<TOptions, LambderMockApiModuleOptions<S>> & LambderMockApiModuleChecks<C, S, G, D, TOptions>): LambderMockApiModule<C, S, G & TOptions["guards"], TDerived, TVocabulary, TCodesRequired>;
|
|
193
232
|
/** The entries of one module as a slice, keyed by name. Two entries for one endpoint is an error here. */
|
|
194
233
|
apiSlice<const E extends readonly LambderMockEntry<C, keyof C & string>[]>(...entries: E): LambderMockSlice<C, E[number]["name"]>;
|
|
234
|
+
/**
|
|
235
|
+
* Registers slices, adding the modules their entries were built with: a
|
|
236
|
+
* module's mock guards are checked against the app's and every other
|
|
237
|
+
* module's first, and taken only once the registry took the slices, so a
|
|
238
|
+
* refused registration leaves the app as it was.
|
|
239
|
+
*/
|
|
195
240
|
private addSlices;
|
|
196
241
|
/**
|
|
197
242
|
* Registers the whole contract: every endpoint in exactly one slice, or
|
|
@@ -389,7 +434,7 @@ export declare const initLambderMock: <C extends LambderApiContractShape, S = an
|
|
|
389
434
|
* dropped. `I` exists for the same reason `P` does, and
|
|
390
435
|
* LambderMockSurplusKeys puts the error back on the key.
|
|
391
436
|
*/
|
|
392
|
-
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true, LambderMergedRefusalVocabulary<TVocabulary>, TRequireCodes>;
|
|
437
|
+
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true, LambderMergedRefusalVocabulary<TVocabulary>, TRequireCodes, D>;
|
|
393
438
|
};
|
|
394
439
|
/**
|
|
395
440
|
* Builds a mock guard: the server guard's shape, the handler seeing the
|
|
@@ -425,5 +470,5 @@ export declare const initLambderMock: <C extends LambderApiContractShape, S = an
|
|
|
425
470
|
* dropped. `I` exists for the same reason `P` does, and
|
|
426
471
|
* LambderMockSurplusKeys puts the error back on the key.
|
|
427
472
|
*/
|
|
428
|
-
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true, never, false>;
|
|
473
|
+
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true, never, false, D>;
|
|
429
474
|
};
|