lambder 15.0.2 → 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 +118 -0
- package/README.md +4 -4
- 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 +68 -93
- package/dist/core/Lambder.js +147 -71
- 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/LambderCallSummary.d.ts +11 -9
- package/dist/core/LambderCreateOptions.d.ts +29 -24
- package/dist/core/LambderInvocationScope.d.ts +9 -3
- package/dist/core/LambderRouting.d.ts +9 -0
- package/dist/core/LambderRouting.js +20 -0
- 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/dist/testing/LambderTestApp.d.ts +4 -3
- package/dist/testing/LambderTestApp.js +4 -3
- package/package.json +1 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { LambderAppTypes, LambderPlainAppTypes } from "../api/LambderApiDeclarations.js";
|
|
2
|
+
import type { LambderApiModuleDeclarations } from "../api/LambderApiModules.js";
|
|
3
|
+
import type { LambderGuardMetaMap } from "../api/LambderApiGuards.js";
|
|
4
|
+
import type { LambderApiRateLimitPolicyConfig } from "../api/LambderApiRateLimits.js";
|
|
5
|
+
import type { LambderMergedNamedMaps, LambderNamedMapsOption } from "../shared/util/LambderNamedMaps.js";
|
|
6
|
+
import { type LambderDefineApi, type LambderDefineApiGroup, type LambderDefineLazyApiGroup } from "./LambderApiBuilders.js";
|
|
7
|
+
import type { LambderGivenOption, LambderGuardChecks, LambderGuardsMap, LambderRateLimitPoliciesMap, LambderRateLimitPolicyChecks } from "./LambderCreateOptions.js";
|
|
8
|
+
/**
|
|
9
|
+
* What defineApiModule() takes: the guards and the rate-limit policies a
|
|
10
|
+
* module declares for its own endpoints, each one map or a list of maps, as
|
|
11
|
+
* create() takes its own. The guards are pinned to the app's session type,
|
|
12
|
+
* as create()'s are.
|
|
13
|
+
*/
|
|
14
|
+
export type LambderApiModuleOptions<TSessionData = any> = {
|
|
15
|
+
/** The module's guards, which its endpoints name beside the instance's: one map, or a list of maps merged in order. */
|
|
16
|
+
guards?: LambderNamedMapsOption<LambderGuardsMap<TSessionData>>;
|
|
17
|
+
/** The module's rate-limit policies, counted on the instance's limiter, which its endpoints name beside the instance's: one map, or a list of maps merged in order. */
|
|
18
|
+
rateLimitPolicies?: LambderNamedMapsOption<LambderRateLimitPoliciesMap>;
|
|
19
|
+
};
|
|
20
|
+
/** Every name a map, or each map of a list, declares. */
|
|
21
|
+
type LambderNamesDeclaredBy<TMaps> = TMaps extends readonly unknown[] ? {
|
|
22
|
+
[TIndex in keyof TMaps]: keyof TMaps[TIndex];
|
|
23
|
+
}[number] : keyof TMaps;
|
|
24
|
+
/** A module's map held to declaring names of its own: one the instance declares is a compile error, and the property name is the message. */
|
|
25
|
+
type LambderModuleNamesCheck<TMaps, TInstanceNames> = [
|
|
26
|
+
Extract<LambderNamesDeclaredBy<TMaps>, TInstanceNames>
|
|
27
|
+
] extends [never] ? unknown : {
|
|
28
|
+
readonly "lambder: the instance declares these names already; a module declares names of its own": Extract<LambderNamesDeclaredBy<TMaps>, TInstanceNames>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* defineApiModule()'s options held to what create() holds its own to, one
|
|
32
|
+
* level down (each guard and each policy checked for surplus keys, a guard's
|
|
33
|
+
* refusal codes held to the vocabulary, a name two maps of a list declare
|
|
34
|
+
* refused), and to declaring no name the instance declares.
|
|
35
|
+
*/
|
|
36
|
+
export type LambderApiModuleOptionChecks<TApp extends LambderAppTypes, TOptions extends LambderApiModuleOptions<TApp["session"]>> = {
|
|
37
|
+
guards?: LambderGuardChecks<TApp["session"], NonNullable<LambderGivenOption<TOptions, "guards">>, TApp["refusals"]> & LambderModuleNamesCheck<NonNullable<LambderGivenOption<TOptions, "guards">>, keyof TApp["guards"]>;
|
|
38
|
+
rateLimitPolicies?: LambderRateLimitPolicyChecks<NonNullable<LambderGivenOption<TOptions, "rateLimitPolicies">>> & LambderModuleNamesCheck<NonNullable<LambderGivenOption<TOptions, "rateLimitPolicies">>, keyof TApp["policies"]>;
|
|
39
|
+
} & LambderModuleDeclaresSomething<TOptions>;
|
|
40
|
+
/**
|
|
41
|
+
* A module declaring neither guards nor policies, refused as an empty guards
|
|
42
|
+
* option is: its builders would be the instance's own. The property name is
|
|
43
|
+
* the message.
|
|
44
|
+
*/
|
|
45
|
+
type LambderModuleDeclaresSomething<TOptions> = [
|
|
46
|
+
LambderGivenOption<TOptions, "guards"> | LambderGivenOption<TOptions, "rateLimitPolicies">
|
|
47
|
+
] extends [undefined] ? {
|
|
48
|
+
readonly "lambder: a module declares guards or rate-limit policies of its own; one with neither declares its endpoints with the instance's builders": never;
|
|
49
|
+
} : unknown;
|
|
50
|
+
/** One map from what a module option was given: a list merged, a lone map as it is, nothing for an option left out. */
|
|
51
|
+
type LambderModuleMap<TOption> = [TOption] extends [undefined] ? {} : LambderMergedNamedMaps<TOption>;
|
|
52
|
+
/**
|
|
53
|
+
* The app types a module's builders are typed on: the instance's, with the
|
|
54
|
+
* module's guards and rate-limit policies beside the instance's own. Its
|
|
55
|
+
* endpoints name either, and nothing else.
|
|
56
|
+
*/
|
|
57
|
+
export type LambderModuleAppTypes<TApp extends LambderAppTypes, TGuards, TPolicies> = {
|
|
58
|
+
session: TApp["session"];
|
|
59
|
+
policies: TApp["policies"] & (LambderModuleMap<TPolicies> extends infer TMerged extends Record<string, LambderApiRateLimitPolicyConfig> ? TMerged : {});
|
|
60
|
+
guards: TApp["guards"] & LambderGuardMetaMap<LambderModuleMap<TGuards>>;
|
|
61
|
+
idempotency: TApp["idempotency"];
|
|
62
|
+
guardsRequired: TApp["guardsRequired"];
|
|
63
|
+
sessions: TApp["sessions"];
|
|
64
|
+
refusals: TApp["refusals"];
|
|
65
|
+
refusalCodesRequired: TApp["refusalCodesRequired"];
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* A part of an app with guards and rate-limit policies of its own, for its
|
|
69
|
+
* own endpoints: the declaration builders typed on its instance's types with
|
|
70
|
+
* the module's guards and policies beside the instance's. Made by an
|
|
71
|
+
* instance's defineApiModule(); its endpoints are registered on the instance
|
|
72
|
+
* as any are (registerApiGroups), and their registration adds the module's
|
|
73
|
+
* guards and policies to the instance, refusing a name the instance or
|
|
74
|
+
* another module declares.
|
|
75
|
+
*
|
|
76
|
+
* So an app's core creates its instance knowing only its own policies, and
|
|
77
|
+
* each module brings its own: nothing has to import every module's guards
|
|
78
|
+
* before the instance can exist. Hand the builders out under the module's
|
|
79
|
+
* name, as an instance's are:
|
|
80
|
+
*
|
|
81
|
+
* ```typescript
|
|
82
|
+
* export const giftCardModule = storeApp.defineApiModule({ guards: { cardHolder }, rateLimitPolicies: { redeemPerCard } });
|
|
83
|
+
* export type GiftCardModule = typeof giftCardModule;
|
|
84
|
+
* export const defineApi: GiftCardModule["defineApi"] = giftCardModule.defineApi;
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @typeParam TApp - @internal The module's app types (LambderModuleAppTypes): the instance's, widened by the module's guards and policies (do not pass manually)
|
|
88
|
+
*/
|
|
89
|
+
export declare class LambderApiModule<TApp extends LambderAppTypes = LambderPlainAppTypes> {
|
|
90
|
+
/**
|
|
91
|
+
* Type property for the module's app types, as an instance's AppTypes
|
|
92
|
+
* is: what LambderRenderContextOf<typeof module> reads, for a helper
|
|
93
|
+
* handed one of the module's handler contexts, its policies typed. It
|
|
94
|
+
* has no value.
|
|
95
|
+
*/
|
|
96
|
+
readonly AppTypes: TApp;
|
|
97
|
+
/** Declares one of the module's endpoints: its guards and rate limits may name the instance's and the module's own. */
|
|
98
|
+
readonly defineApi: LambderDefineApi<TApp>;
|
|
99
|
+
/** Gathers endpoints into a named group, as the instance's does. */
|
|
100
|
+
readonly defineApiGroup: LambderDefineApiGroup;
|
|
101
|
+
/** A group of the module's loaded on the first call to it, carrying the module, so its guards and policies are added when the group is registered. */
|
|
102
|
+
readonly lazyApiGroup: LambderDefineLazyApiGroup;
|
|
103
|
+
/** Called by an instance's defineApiModule(), with the declarations it checked; an app does not construct one. */
|
|
104
|
+
constructor(declarations: LambderApiModuleDeclarations);
|
|
105
|
+
}
|
|
106
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { apiBuildersFor, } from "./LambderApiBuilders.js";
|
|
2
|
+
/**
|
|
3
|
+
* A part of an app with guards and rate-limit policies of its own, for its
|
|
4
|
+
* own endpoints: the declaration builders typed on its instance's types with
|
|
5
|
+
* the module's guards and policies beside the instance's. Made by an
|
|
6
|
+
* instance's defineApiModule(); its endpoints are registered on the instance
|
|
7
|
+
* as any are (registerApiGroups), and their registration adds the module's
|
|
8
|
+
* guards and policies to the instance, refusing a name the instance or
|
|
9
|
+
* another module declares.
|
|
10
|
+
*
|
|
11
|
+
* So an app's core creates its instance knowing only its own policies, and
|
|
12
|
+
* each module brings its own: nothing has to import every module's guards
|
|
13
|
+
* before the instance can exist. Hand the builders out under the module's
|
|
14
|
+
* name, as an instance's are:
|
|
15
|
+
*
|
|
16
|
+
* ```typescript
|
|
17
|
+
* export const giftCardModule = storeApp.defineApiModule({ guards: { cardHolder }, rateLimitPolicies: { redeemPerCard } });
|
|
18
|
+
* export type GiftCardModule = typeof giftCardModule;
|
|
19
|
+
* export const defineApi: GiftCardModule["defineApi"] = giftCardModule.defineApi;
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @typeParam TApp - @internal The module's app types (LambderModuleAppTypes): the instance's, widened by the module's guards and policies (do not pass manually)
|
|
23
|
+
*/
|
|
24
|
+
export class LambderApiModule {
|
|
25
|
+
/**
|
|
26
|
+
* Type property for the module's app types, as an instance's AppTypes
|
|
27
|
+
* is: what LambderRenderContextOf<typeof module> reads, for a helper
|
|
28
|
+
* handed one of the module's handler contexts, its policies typed. It
|
|
29
|
+
* has no value.
|
|
30
|
+
*/
|
|
31
|
+
AppTypes;
|
|
32
|
+
/** Declares one of the module's endpoints: its guards and rate limits may name the instance's and the module's own. */
|
|
33
|
+
defineApi;
|
|
34
|
+
/** Gathers endpoints into a named group, as the instance's does. */
|
|
35
|
+
defineApiGroup;
|
|
36
|
+
/** A group of the module's loaded on the first call to it, carrying the module, so its guards and policies are added when the group is registered. */
|
|
37
|
+
lazyApiGroup;
|
|
38
|
+
/** Called by an instance's defineApiModule(), with the declarations it checked; an app does not construct one. */
|
|
39
|
+
constructor(declarations) {
|
|
40
|
+
const builders = apiBuildersFor(declarations);
|
|
41
|
+
this.defineApi = builders.defineApi;
|
|
42
|
+
this.defineApiGroup = builders.defineApiGroup;
|
|
43
|
+
this.lazyApiGroup = builders.lazyApiGroup;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import type { LambderCallOutcome } from "../shared/wire/LambderCallOutcome.js";
|
|
2
2
|
/**
|
|
3
|
-
* One API call
|
|
4
|
-
* ended, how long it took, and the ids that join
|
|
5
|
-
* logs. Nothing from the call's input, its
|
|
6
|
-
* caller's address is in it, so the line can be
|
|
7
|
-
* the app likes.
|
|
3
|
+
* One API call, or one request a route answered, as its summary line records
|
|
4
|
+
* it: what was called, how it ended, how long it took, and the ids that join
|
|
5
|
+
* it to the rest of the logs. Nothing from the call's input, its path, its
|
|
6
|
+
* session, its cookies or its caller's address is in it, so the line can be
|
|
7
|
+
* kept and queried as long as the app likes.
|
|
8
8
|
*/
|
|
9
9
|
export type LambderCallSummary = {
|
|
10
10
|
/** Always "lambder.call": what a log query picks the lines out by. */
|
|
11
11
|
kind: "lambder.call";
|
|
12
|
-
/** The endpoint
|
|
13
|
-
api: string;
|
|
14
|
-
/**
|
|
12
|
+
/** The endpoint an API call's path named (`group.action`), whether or not one is registered under it; null for a route. */
|
|
13
|
+
api: string | null;
|
|
14
|
+
/** The route that answered, as it was registered: its matcher's name, or its method and path pattern; null for an API call, for a predicate route given no name, and for an addAction that answered an HTTP request. */
|
|
15
|
+
route: string | null;
|
|
16
|
+
/** How the call ended; see LambderCallOutcome. A route's is read from its status: success below 400, crash from 500, other between. */
|
|
15
17
|
outcome: LambderCallOutcome;
|
|
16
18
|
/** The refusal's code, the framework's (`lambder/rate-limited`) or the app's; null when the answer carries none. */
|
|
17
19
|
code: string | null;
|
|
@@ -19,7 +21,7 @@ export type LambderCallSummary = {
|
|
|
19
21
|
status: number;
|
|
20
22
|
/** From the invocation's start to the answer, in milliseconds. */
|
|
21
23
|
durationMs: number;
|
|
22
|
-
/** How long the API handler itself ran, in milliseconds; null when it did not run (refused before it, or
|
|
24
|
+
/** How long the API handler, or the route's handler, itself ran, in milliseconds; null when it did not run (refused before it, replayed, or answered by a hook). */
|
|
23
25
|
handlerMs: number | null;
|
|
24
26
|
/** True when a stored idempotent answer was replayed and no handler ran. */
|
|
25
27
|
replayed: boolean;
|
|
@@ -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"> & {
|
|
@@ -292,14 +296,15 @@ export type LambderCreateOptions<TSessionData = any> = {
|
|
|
292
296
|
*/
|
|
293
297
|
originProof?: LambderOriginProof;
|
|
294
298
|
/**
|
|
295
|
-
* One summary per API call,
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* the
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
299
|
+
* One summary per API call, and per request a route answered, written
|
|
300
|
+
* when it is answered: the endpoint or the route as registered, how it
|
|
301
|
+
* ended (success, a refusal and its code, a flag, a validation refusal, a
|
|
302
|
+
* crash; a route's read from its status), the status, the duration and
|
|
303
|
+
* the handler's own time, whether an idempotent answer was replayed,
|
|
304
|
+
* whether the invocation was the process's first, and its request id
|
|
305
|
+
* with the id of the invocation that called it over invoke. Nothing from
|
|
306
|
+
* the input, the path, the session, the cookies or the caller's address.
|
|
307
|
+
* See LambderCallSummary.
|
|
303
308
|
*
|
|
304
309
|
* Default: each summary as one JSON line on stdout, which a Lambda
|
|
305
310
|
* function's log group keeps and CloudWatch Logs Insights reads field by
|
|
@@ -474,7 +479,7 @@ type LambderGuardRefusalsKnown<TGuard, TRefusals> = TGuard extends {
|
|
|
474
479
|
refusals: readonly (keyof NonNullable<TRefusals> & string)[];
|
|
475
480
|
} : unknown : unknown;
|
|
476
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. */
|
|
477
|
-
type LambderRateLimitPolicyChecks<TPolicies> = TPolicies extends readonly unknown[] ? {
|
|
482
|
+
export type LambderRateLimitPolicyChecks<TPolicies> = TPolicies extends readonly unknown[] ? {
|
|
478
483
|
[TIndex in keyof TPolicies]: LambderRateLimitPolicyChecks<TPolicies[TIndex]>;
|
|
479
484
|
} & LambderNoRepeatedNames<TPolicies> : {
|
|
480
485
|
[TPolicy in keyof TPolicies]: LambderNoExtraKeys<TPolicies[TPolicy], LambderApiRateLimitPolicyConfig<LambderRenderContext>> & (TPolicies[TPolicy] extends {
|
|
@@ -484,7 +489,7 @@ type LambderRateLimitPolicyChecks<TPolicies> = TPolicies extends readonly unknow
|
|
|
484
489
|
} : unknown);
|
|
485
490
|
};
|
|
486
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. */
|
|
487
|
-
type LambderGuardChecks<TSessionData, TGuards, TRefusals> = TGuards extends readonly unknown[] ? {
|
|
492
|
+
export type LambderGuardChecks<TSessionData, TGuards, TRefusals> = TGuards extends readonly unknown[] ? {
|
|
488
493
|
[TIndex in keyof TGuards]: LambderGuardChecks<TSessionData, TGuards[TIndex], TRefusals>;
|
|
489
494
|
} & LambderNoRepeatedNames<TGuards> : {
|
|
490
495
|
[TGuard in keyof TGuards]: LambderNoExtraKeys<TGuards[TGuard], LambderGuardsMap<TSessionData>[string]> & LambderGuardRefusalsKnown<TGuards[TGuard], TRefusals>;
|
|
@@ -509,7 +514,7 @@ export type LambderNestedOptionChecks<TSessionData, TOptions extends LambderCrea
|
|
|
509
514
|
crashes?: LambderNoExtraKeys<NonNullable<TOptions["crashes"]>, LambderOptionShape<TSessionData, "crashes">>;
|
|
510
515
|
originProof?: LambderNoExtraKeys<NonNullable<TOptions["originProof"]>, LambderOptionShape<TSessionData, "originProof">>;
|
|
511
516
|
rateLimits?: LambderNoExtraKeys<NonNullable<TOptions["rateLimits"]>, LambderOptionShape<TSessionData, "rateLimits">> & {
|
|
512
|
-
policies?: LambderRateLimitPolicyChecks<NonNullable<TOptions["rateLimits"]>["policies"]
|
|
517
|
+
policies?: LambderRateLimitPolicyChecks<NonNullable<NonNullable<TOptions["rateLimits"]>["policies"]>>;
|
|
513
518
|
};
|
|
514
519
|
guards?: LambderGuardChecks<TSessionData, NonNullable<TOptions["guards"]>, TRefusals>;
|
|
515
520
|
files?: TOptions["files"] extends {
|
|
@@ -7,13 +7,19 @@ export type LambderInvocationRecord = LambderInvocation & {
|
|
|
7
7
|
readonly startedAt: number;
|
|
8
8
|
/** Whether this is the first invocation this process has run. */
|
|
9
9
|
readonly coldStart: boolean;
|
|
10
|
-
/** How long the API handler itself ran, in milliseconds; null until it has. */
|
|
10
|
+
/** How long the API handler, or the route's handler, itself ran, in milliseconds; null until it has. */
|
|
11
11
|
handlerMs: number | null;
|
|
12
12
|
/** Whether an idempotent answer was replayed, so no handler ran. */
|
|
13
13
|
replayed: boolean;
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* What the invocation serves, named: an API call by the endpoint its path
|
|
16
|
+
* named, or a request a route answered by the route as registered (null
|
|
17
|
+
* for a route with no name), with the invocation that invoked it, when
|
|
18
|
+
* one did. Null for anything else: a file, the index page, an event.
|
|
19
|
+
*/
|
|
15
20
|
call: {
|
|
16
|
-
api: string;
|
|
21
|
+
api: string | null;
|
|
22
|
+
route: string | null;
|
|
17
23
|
parentRequestId: string | null;
|
|
18
24
|
} | null;
|
|
19
25
|
/** What the answer is, once the call has one. */
|
|
@@ -15,6 +15,8 @@ export type LambderRouteMatcher = {
|
|
|
15
15
|
/** One or more HTTP methods; HEAD requests also match GET routes. */
|
|
16
16
|
method?: string | string[];
|
|
17
17
|
condition?: LambderRouteConditionFn;
|
|
18
|
+
/** What the route's call summary line names it by; by default its method and path pattern, which a route with neither has none of. */
|
|
19
|
+
name?: string;
|
|
18
20
|
};
|
|
19
21
|
export type LambderRouteCondition = LambderRoutePath | RegExp | LambderRouteConditionFn | LambderRouteMatcher;
|
|
20
22
|
/** Returns matched path params, or false when the route doesn't match. */
|
|
@@ -28,6 +30,13 @@ export type CompiledMatcher = (ctx: LambderRenderContext) => false | Record<stri
|
|
|
28
30
|
* this rule, so neighbouring slots cannot disagree about what a method means.
|
|
29
31
|
*/
|
|
30
32
|
export declare const allowsRequestMethod: (methods: ReadonlySet<string>, requestMethod: string) => boolean;
|
|
33
|
+
/**
|
|
34
|
+
* What a route's call summary line names it by: the name its matcher gives,
|
|
35
|
+
* or its method and path pattern, both fixed at registration, so the line
|
|
36
|
+
* carries nothing of the request's own path. Null for a route with neither,
|
|
37
|
+
* a bare predicate, which the line still counts.
|
|
38
|
+
*/
|
|
39
|
+
export declare const routeNameOf: (condition: LambderRouteCondition) => string | null;
|
|
31
40
|
/** Compile a route condition once at registration time. */
|
|
32
41
|
export declare const compileRouteMatcher: (condition: LambderRouteCondition) => CompiledMatcher;
|
|
33
42
|
export {};
|
|
@@ -57,6 +57,26 @@ export const allowsRequestMethod = (methods, requestMethod) => {
|
|
|
57
57
|
return true;
|
|
58
58
|
return method === "HEAD" && methods.has("GET");
|
|
59
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* What a route's call summary line names it by: the name its matcher gives,
|
|
62
|
+
* or its method and path pattern, both fixed at registration, so the line
|
|
63
|
+
* carries nothing of the request's own path. Null for a route with neither,
|
|
64
|
+
* a bare predicate, which the line still counts.
|
|
65
|
+
*/
|
|
66
|
+
export const routeNameOf = (condition) => {
|
|
67
|
+
if (typeof condition === "string")
|
|
68
|
+
return condition;
|
|
69
|
+
if (condition instanceof RegExp)
|
|
70
|
+
return condition.toString();
|
|
71
|
+
if (typeof condition === "function")
|
|
72
|
+
return null;
|
|
73
|
+
if (condition.name !== undefined)
|
|
74
|
+
return condition.name;
|
|
75
|
+
const methods = condition.method === undefined ? [] : (Array.isArray(condition.method) ? condition.method : [condition.method]).map((m) => m.toUpperCase());
|
|
76
|
+
const path = condition.path === undefined ? null : typeof condition.path === "string" ? condition.path : condition.path.toString();
|
|
77
|
+
const name = [methods.join(","), path].filter((part) => part).join(" ");
|
|
78
|
+
return name || null;
|
|
79
|
+
};
|
|
60
80
|
/** Compile a route condition once at registration time. */
|
|
61
81
|
export const compileRouteMatcher = (condition) => {
|
|
62
82
|
if (typeof condition === "string" || condition instanceof RegExp) {
|
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
|
+
}
|