lambder 11.1.1 → 13.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +217 -0
  2. package/README.md +25 -15
  3. package/dist/api/LambderApiAnswer.d.ts +7 -0
  4. package/dist/api/LambderApiDeclarations.d.ts +194 -0
  5. package/dist/api/LambderApiDeclarations.js +52 -0
  6. package/dist/api/LambderApiDefinition.d.ts +1 -1
  7. package/dist/api/LambderApiEnvelope.js +4 -1
  8. package/dist/api/LambderApiGuards.d.ts +21 -22
  9. package/dist/api/LambderApiGuards.js +1 -1
  10. package/dist/api/LambderApiRateLimits.d.ts +19 -19
  11. package/dist/api/LambderApiRateLimits.js +1 -1
  12. package/dist/api/LambderApiRefusals.d.ts +22 -0
  13. package/dist/api/LambderApiRefusals.js +13 -0
  14. package/dist/api/LambderApiRequest.d.ts +15 -6
  15. package/dist/api/LambderApiRequest.js +8 -9
  16. package/dist/build/generateApiFiles.d.ts +60 -0
  17. package/dist/build/generateApiFiles.js +85 -0
  18. package/dist/build/generatedTables.d.ts +2 -1
  19. package/dist/build/generatedTables.js +1 -1
  20. package/dist/build.d.ts +4 -1
  21. package/dist/build.js +3 -1
  22. package/dist/client/LambderCaller.d.ts +36 -23
  23. package/dist/client/LambderCaller.js +88 -67
  24. package/dist/client/lambderFetchTransport.js +2 -1
  25. package/dist/client.d.ts +3 -1
  26. package/dist/client.js +2 -0
  27. package/dist/core/Lambder.d.ts +232 -92
  28. package/dist/core/Lambder.js +400 -103
  29. package/dist/core/LambderCallSummary.d.ts +43 -0
  30. package/dist/core/LambderCallSummary.js +10 -0
  31. package/dist/core/LambderContext.d.ts +15 -2
  32. package/dist/core/LambderContext.js +32 -9
  33. package/dist/core/LambderCreateOptions.d.ts +78 -64
  34. package/dist/core/LambderCreateOptions.js +39 -21
  35. package/dist/core/LambderInvocationScope.d.ts +25 -0
  36. package/dist/core/LambderInvocationScope.js +21 -0
  37. package/dist/core/LambderResponse.d.ts +11 -0
  38. package/dist/core/LambderResponse.js +12 -0
  39. package/dist/core/LambderResponseBuilder.js +5 -1
  40. package/dist/index.d.ts +13 -7
  41. package/dist/index.js +3 -1
  42. package/dist/invoke/LambderInvokeCaller.d.ts +48 -31
  43. package/dist/invoke/LambderInvokeCaller.js +110 -94
  44. package/dist/invoke/LambderLambdaEvent.d.ts +2 -1
  45. package/dist/invoke/LambderLambdaEvent.js +8 -3
  46. package/dist/invoke/lambderHandlerTransport.js +2 -1
  47. package/dist/mock/LambderMockApp.d.ts +39 -33
  48. package/dist/mock/LambderMockApp.js +66 -55
  49. package/dist/mock/LambderMockCreateOptions.d.ts +8 -10
  50. package/dist/mock/LambderMockTypes.d.ts +44 -7
  51. package/dist/mock/lambderMockInvokeTransport.d.ts +9 -1
  52. package/dist/mock/lambderMockInvokeTransport.js +15 -7
  53. package/dist/mock/lambderMockMswHandler.js +8 -4
  54. package/dist/mock.d.ts +2 -2
  55. package/dist/session/LambderSessionManager.d.ts +46 -3
  56. package/dist/session/LambderSessionManager.js +62 -11
  57. package/dist/shared/LambderI18n.js +49 -4
  58. package/dist/shared/contracts/LambderRateLimiter.d.ts +2 -2
  59. package/dist/shared/contracts/LambderRateLimiter.js +2 -2
  60. package/dist/shared/transport/LambderApiTransport.d.ts +3 -2
  61. package/dist/shared/transport/LambderApiTransport.js +2 -3
  62. package/dist/shared/transport/lambderCookieJarTransport.js +2 -1
  63. package/dist/shared/util/LambderInvocationScope.d.ts +10 -0
  64. package/dist/shared/util/LambderInvocationScope.js +5 -0
  65. package/dist/shared/util/LambderNamedMaps.d.ts +22 -0
  66. package/dist/shared/util/LambderNamedMaps.js +19 -0
  67. package/dist/shared/util/LambderTypeUtilities.d.ts +1 -1
  68. package/dist/shared/wire/LambderApiContract.d.ts +4 -18
  69. package/dist/shared/wire/LambderApiContract.js +1 -1
  70. package/dist/shared/wire/LambderApiGroupCalls.d.ts +31 -0
  71. package/dist/shared/wire/LambderApiGroupCalls.js +68 -0
  72. package/dist/shared/wire/LambderApiNames.d.ts +55 -0
  73. package/dist/shared/wire/LambderApiNames.js +81 -0
  74. package/dist/shared/wire/LambderCallOutcome.d.ts +27 -0
  75. package/dist/shared/wire/LambderCallOutcome.js +47 -0
  76. package/dist/shared/wire/LambderInvokeApiId.d.ts +10 -0
  77. package/dist/shared/wire/LambderInvokeApiId.js +10 -0
  78. package/dist/shared/wire/LambderUploadSchemas.js +2 -1
  79. package/dist/stores/LambderDdbRateLimiter.d.ts +24 -16
  80. package/dist/stores/LambderDdbRateLimiter.js +64 -45
  81. package/dist/stores/LambderMemoryRateLimiter.d.ts +9 -4
  82. package/dist/stores/LambderMemoryRateLimiter.js +20 -15
  83. package/dist/testing/LambderTestApp.d.ts +18 -5
  84. package/dist/testing/LambderTestApp.js +21 -5
  85. package/dist/testing/LambderTestVisitor.d.ts +16 -8
  86. package/dist/testing/LambderTestVisitor.js +33 -25
  87. package/package.json +1 -1
@@ -12,7 +12,7 @@ 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";
15
+ import { type LambderWireRefusalsOf, type LambderHandlerRefusalsOf, type LambderRefusalNamesIn, type LambderRefusalsOption, type LambderRefusalVocabularyOption, type LambderRefusalVocabularyOptionChecks, type LambderMergedRefusalVocabulary } from "../api/LambderApiRefusals.js";
16
16
  import { type LambderDeclaredRefuse } from "../shared/wire/LambderApiRefusal.js";
17
17
  import { type LambderApiSignatureEntry } from "../api/LambderApiSignature.js";
18
18
  import { type LambderApiSignatureMap } from "../shared/wire/LambderApiSignatureMap.js";
@@ -21,13 +21,17 @@ import type { LambderApiIdempotencyOption } from "../shared/wire/LambderApiOptio
21
21
  import type { LambderApiGuard, LambderGuardMetaMap, LambderGuardsOption, LambderGuardDataOf, LambderGuardInputsOf, LambderGuardRefusalNamesOf } from "../api/LambderApiGuards.js";
22
22
  import type { LambderApiRateLimitPolicyConfig, LambderRateLimitOption } from "../api/LambderApiRateLimits.js";
23
23
  import type { LambderApiIdempotencyConfig } from "../api/LambderApiIdempotency.js";
24
- import type { LambderContractEntry, LambderJsonOf, LambderMergeContract } from "../shared/wire/LambderApiContract.js";
24
+ import type { LambderContractEntry, LambderJsonOf } from "../shared/wire/LambderApiContract.js";
25
+ import { type LambderActionNamesCheck, type LambderApiDeclaration, type LambderApiDeclarations, type LambderApiGroup, type LambderApiModeOf, type LambderAppTypes, type LambderContractOfGroups, type LambderGroupNameCheck, type LambderGroupPartsCheck, type LambderMergedParts, type LambderLazyApiGroup, type LambderPlainAppTypes, type LambderPublicSessionPolicyCheck, type LambderRegisteredGroupsCheck, type LambderRegistrableApiGroup, type LambderSessionModeCheck } from "../api/LambderApiDeclarations.js";
25
26
  import { type LambderHttpEvent, type LambderRenderContext, type LambderSessionRenderContext } from "./LambderContext.js";
26
27
  import type { LambderReadonlyDeep, MaybePromise } from "../shared/util/LambderTypeUtilities.js";
28
+ import { type LambderCallSummary } from "./LambderCallSummary.js";
27
29
  import { type LambderMergedNamedMaps, type LambderNamedMapsOption, 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 LambderPayloadSliceCheck, type LambderRequirableGuardsField, type LambderSessionEnabledInstance, type LambderSessionRouteHandler } from "./LambderCreateOptions.js";
28
30
  /** Everything `lambder/testing` may put under a built instance: the pipeline's stores, and the source its files are read from. */
29
31
  export type LambderInstanceBackends = LambderPipelineBackends & {
30
32
  fileSource?: LambderFileSource;
33
+ /** Where call summaries go instead of the app's own callSummary; null writes none. */
34
+ callSummary?: ((summary: LambderCallSummary) => void) | null;
31
35
  };
32
36
  /** What the instance had a place for; see LambderPipelineBackendSwap. `files` is false on an instance created without the files option. */
33
37
  export type LambderInstanceBackendSwap = LambderPipelineBackendSwap & {
@@ -39,36 +43,41 @@ export type LambderInstanceBackendSwap = LambderPipelineBackendSwap & {
39
43
  * because its parameter is the class, and an options module that names the
40
44
  * class cannot be read without it.
41
45
  */
42
- export type LambderCreatedHook = (lambderInstance: Lambder<any, any, any, any, any, any, any, any, any, any>) => void | Promise<void>;
46
+ export type LambderCreatedHook = (lambderInstance: Lambder<any, any>) => void | Promise<void>;
43
47
  /** The codes one API may refuse with, typed: its own refusals option's and its declared guards', as the vocabulary holds them. */
44
48
  type LambderApiRefusalCodes<TVocabulary, TGuards, TRefusalsOpt, TGuardsOpt> = (LambderRefusalNamesIn<TRefusalsOpt> | LambderGuardRefusalNamesOf<TGuards, TGuardsOpt>) & keyof TVocabulary & string;
49
+ /**
50
+ * What an endpoint's handler is handed: the session context when one of its
51
+ * guards needs a session (so ctx.session is typed present), the plain one
52
+ * otherwise, with the payload, the guards' data and a refuse() typed to the
53
+ * codes the endpoint may refuse with.
54
+ */
55
+ type LambderApiHandlerContext<TApp extends LambderAppTypes, TPayload, TGuardsOpt, TRefusalsOpt> = (LambderApiModeOf<TApp["guards"], TGuardsOpt> extends "session" ? LambderSessionRenderContext<TPayload, TApp["session"], Record<string, string>, LambderGuardDataOf<TApp["guards"], TGuardsOpt>, TApp["policies"]> : LambderRenderContext<TPayload, Record<string, string>, LambderGuardDataOf<TApp["guards"], TGuardsOpt>, TApp["session"], TApp["policies"]>) & {
56
+ refuse: LambderDeclaredRefuse<LambderHandlerRefusalsOf<TApp["refusals"], LambderApiRefusalCodes<TApp["refusals"], TApp["guards"], TRefusalsOpt, TGuardsOpt>>, TApp["refusalCodesRequired"]>;
57
+ };
45
58
  /**
46
59
  * Main Lambder class for building type-safe serverless APIs. Create
47
60
  * instances with initLambder<SessionData>().create({...}) (see below): the
48
61
  * whole configuration, including the typed policy layer, is given at
49
- * construction, and only registration (routes, apis, hooks, use) chains.
62
+ * construction. Endpoints are declared as values on the instance
63
+ * (defineApi, defineApiGroup) and registered in one registerApiGroups()
64
+ * call; routes, hooks and actions chain.
50
65
  *
51
- * @typeParam TSessionData - Type of session data stored in DynamoDB
52
- * @typeParam _TContract - @internal Accumulates API contract during chaining (do not pass manually)
53
- * @typeParam _TRateLimitPolicies - @internal Inferred from create()'s rateLimits.policies (do not pass manually)
54
- * @typeParam _TGuards - @internal Guard metadata map inferred from create()'s guards (do not pass manually)
55
- * @typeParam _TIdempotencyEnabled - @internal True when create() received idempotency (do not pass manually)
56
- * @typeParam _TSessionGuardsRequired - @internal True when create() received requireSessionApiGuards (do not pass manually)
57
- * @typeParam _TPublicGuardsRequired - @internal True when create() received requirePublicApiGuards (do not pass manually)
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)
66
+ * @typeParam TApp - @internal What create() configured, as LambderAppTypes: the session data, policies, guards, idempotency, the guard requirement, sessions and the refusal vocabulary (do not pass manually)
67
+ * @typeParam _TContract - @internal The contract of the groups registered so far (do not pass manually)
61
68
  *
62
69
  * @example
63
70
  * ```typescript
64
71
  * interface SessionData { userId: string; role: string; }
65
72
  *
66
- * const lambder = initLambder<SessionData>().create({ apiPath: '/api' })
67
- * .addApi('getUser', { input: z.object({...}), output: z.object({...}) }, handler)
68
- * .addApi('createUser', { input: z.object({...}), output: z.object({...}) }, handler);
73
+ * const app = initLambder<SessionData>().create({ apiPath: '/api', session, guards });
74
+ * const userApis = app.defineApiGroup("users", {
75
+ * get: app.defineApi({ input: z.object({...}), output: z.object({...}), guards: "signedIn" }, handler),
76
+ * });
77
+ * const lambder = app.registerApiGroups(userApis);
69
78
  * ```
70
79
  */
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> {
80
+ export default class Lambder<TApp extends LambderAppTypes = LambderPlainAppTypes, _TContract extends Record<string, any> = {}> {
72
81
  apiPath: string;
73
82
  /** Stamped on every API answer's envelope as apiVersion. Informational: a client's staleness is judged per endpoint by its signature, see apiSignatures(). */
74
83
  apiVersion: null | string;
@@ -78,24 +87,35 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
78
87
  * Type property for extracting the API contract: every registered API's
79
88
  * input, output, mode and declared options, as a client calls it.
80
89
  *
81
- * A small app's client imports it as it is. It is an intersection one
82
- * member deep per endpoint, so reading it generically costs a large app's
83
- * client most of its type check; writeApiContract (lambder/build) reads
84
- * this property off the exported instance and writes the contract out as
85
- * plain types for such a client to import instead.
90
+ * A small app's client imports it as it is. A large app's client reads
91
+ * the plain types writeApiContract (lambder/build) prints from this
92
+ * property instead, which cost it nothing to resolve.
86
93
  *
87
94
  * @example
88
95
  * ```typescript
89
- * export const lambder = initLambder().create({ ... }).addApi(...).addApi(...);
96
+ * export const lambder = lambderApp.registerApiGroups(userApis, orderApis);
90
97
  * export type ApiContractType = typeof lambder.ApiContract;
91
98
  * ```
92
99
  */
93
100
  readonly ApiContract: _TContract;
101
+ /**
102
+ * Type property for what create() configured (LambderAppTypes): the
103
+ * session data, policies, guards and the rest, for code that takes any
104
+ * instance and needs one of them (lambderTestApp reads the session data
105
+ * type here). Like ApiContract, it has no value.
106
+ */
107
+ readonly AppTypes: TApp;
94
108
  private actionList;
95
109
  /** The API core: the pipeline every API call runs through, shared in shape with the mock runtime. */
96
110
  private readonly pipeline;
97
- /** Every registered API by name: the duplicate-name check, and what apiSignatures() digests. */
111
+ /** Every registered API by name: what dispatch, apiSignatures() and apiOptionEntries() read. */
98
112
  private readonly apiDefinitions;
113
+ /** What answers each registered API: its output schema, compression setting and handler. */
114
+ private readonly apiHandlers;
115
+ /** Every group name registered, lazy or not: the duplicate-group check. */
116
+ private readonly apiGroupNames;
117
+ /** The lazy groups not loaded yet, each with its load in progress, if one is. */
118
+ private readonly lazyApiGroups;
99
119
  /** The guards given at creation, merged into one map, kept for apiSignatures(): a guard's schema is part of the signature of every endpoint declaring it. */
100
120
  private readonly guards;
101
121
  /** The rate-limit policies given at creation, kept for apiOptionEntries(), which records each one less its key handler. */
@@ -117,7 +137,8 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
117
137
  private eventActionList;
118
138
  private corsConfig;
119
139
  private finalizeOptions;
120
- private requireSessionApiGuards;
140
+ /** Whether every endpoint has to declare guards (create()'s requireApiGuards). */
141
+ private readonly requireApiGuards;
121
142
  /** Whether every refusal an API answers with has to name a code (declareRefusals's requireCodes). */
122
143
  private readonly requireRefusalCodes;
123
144
  /** Told what a request threw, beside whatever answers it; null outside a test. See LAMBDER_CRASH_WATCH. */
@@ -128,8 +149,10 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
128
149
  private readonly contextTools;
129
150
  private readonly trustedClientIpHeaders;
130
151
  private readonly trustedHostHeaders;
131
- private requirePublicApiGuards;
132
- constructor(given?: LambderCreateOptions<TSessionData>);
152
+ private readonly originProof;
153
+ /** Where each API call's summary goes (the callSummary option); null writes none. Replaceable through the backend swap alone. */
154
+ private callSummaryWriter;
155
+ constructor(given?: LambderCreateOptions<TApp["session"]>);
133
156
  setRouteFallbackHandler(routeFallbackHandler: LambderFallbackHandler): this;
134
157
  setApiFallbackHandler(apiFallbackHandler: LambderFallbackHandler): this;
135
158
  setApiInputValidationErrorHandler(apiInputValidationErrorHandler: LambderInputValidationHandler): this;
@@ -163,45 +186,33 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
163
186
  * res.templateFile (markers optional) with no-cache.
164
187
  */
165
188
  serveIndexHtml(handler?: LambderFallbackHandler, options?: LambderIndexHtmlOptions): this;
166
- addRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: (ctx: LambderRenderContext<any, LambderPathParamsOf<TPath>, {}, TSessionData, _TRateLimitPolicies>, resolver: LambderResolver) => MaybePromise<LambderResponse>): this;
189
+ addRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: (ctx: LambderRenderContext<any, LambderPathParamsOf<TPath>, {}, TApp["session"], TApp["policies"]>, resolver: LambderResolver) => MaybePromise<LambderResponse>): this;
167
190
  addRoute(condition: RegExp | LambderRouteConditionFn | LambderRouteMatcher, actionFn: LambderRouteHandler): this;
168
- addSessionRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: ((ctx: LambderSessionRenderContext<any, TSessionData, LambderPathParamsOf<TPath>, {}, _TRateLimitPolicies>, resolver: LambderResolver) => MaybePromise<LambderResponse>) & LambderSessionEnabledInstance<_TSessionsEnabled>): this;
169
- addSessionRoute(condition: RegExp | LambderRouteConditionFn | LambderRouteMatcher, actionFn: LambderSessionRouteHandler<TSessionData> & LambderSessionEnabledInstance<_TSessionsEnabled>): this;
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, false> = never, const TGuardsOpt extends LambderGuardsOption<_TGuards, false> = never, const TIdempotencyOpt extends LambderApiIdempotencyOption = never, const TRefusalsOpt extends LambderRefusalsOption<_TRefusals> = never>(name: TName, schema: {
171
- input: TInput;
172
- output: TOutput;
173
- } & {
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. */
175
- rateLimit?: TRateOpt;
176
- /** Replay-protect this API per client idempotencyKey. Requires the idempotency option at creation. */
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;
184
- /**
185
- * Whether this API's answers are compressed for a caller that accepts it: "auto" (the default) when the
186
- * body is large enough to gain, false never, true always. false suits an answer of base64 bytes: once
187
- * compressed it leaves the function base64-encoded again, so it is no smaller under Lambda's response
188
- * cap or to a lambda caller, and a browser gets it only about a quarter smaller for the time spent at
189
- * both ends. A transport setting of this server's, not part of the API's contract.
190
- */
191
- compress?: boolean | "auto";
192
- } & LambderRequirableGuardsField<_TPublicGuardsRequired, TGuardsOpt> & LambderObjectOutputCheck<TOutput> & LambderPayloadSliceCheck<_TGuards, _TRateLimitPolicies, TGuardsOpt, TRateOpt, z.input<TInput>>,
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, true> = never, const TGuardsOpt extends LambderGuardsOption<_TGuards, true> = never, const TIdempotencyOpt extends LambderApiIdempotencyOption = never, const TRefusalsOpt extends LambderRefusalsOption<_TRefusals> = never>(name: TName, schema: {
191
+ addSessionRoute<TPath extends LambderRoutePath>(condition: TPath, actionFn: ((ctx: LambderSessionRenderContext<any, TApp["session"], LambderPathParamsOf<TPath>, {}, TApp["policies"]>, resolver: LambderResolver) => MaybePromise<LambderResponse>) & LambderSessionEnabledInstance<TApp["sessions"]>): this;
192
+ addSessionRoute(condition: RegExp | LambderRouteConditionFn | LambderRouteMatcher, actionFn: LambderSessionRouteHandler<TApp["session"]> & LambderSessionEnabledInstance<TApp["sessions"]>): this;
193
+ /**
194
+ * Declares one endpoint, typed on this instance's types: its input and
195
+ * output schemas, its guards, rate limits, idempotency and refusals, and
196
+ * its handler. Nothing is registered until the declaration is put in a
197
+ * group (defineApiGroup) and the group is registered (registerApiGroups).
198
+ *
199
+ * The guards say who may call it, and so its mode: an endpoint whose
200
+ * guards include one that needs a session (`session: true`) is a session
201
+ * endpoint, its session read before the guards run and a call without
202
+ * one answered sessionExpired, and its handler's ctx.session is typed
203
+ * present. Any other endpoint is public.
204
+ *
205
+ * An arrow property rather than a method, so an app can hand it out
206
+ * detached: `export const { defineApi, defineApiGroup } = lambderApp;`.
207
+ */
208
+ readonly defineApi: <TInput extends z.ZodType, TOutput extends z.ZodType, const TAnswer extends LambderReadonlyDeep<z.input<TOutput>>, const TRateOpt extends LambderRateLimitOption<TApp["policies"]> = never, const TGuardsOpt extends LambderGuardsOption<TApp["guards"]> = never, const TIdempotencyOpt extends LambderApiIdempotencyOption = never, const TRefusalsOpt extends LambderRefusalsOption<TApp["refusals"]> = never>(options: {
198
209
  input: TInput;
199
210
  output: TOutput;
200
211
  } & {
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. */
212
+ /** 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. A per-session policy needs one of the endpoint's guards to need a session. */
202
213
  rateLimit?: TRateOpt;
203
214
  /** Replay-protect this API per client idempotencyKey. Requires the idempotency option at creation. */
204
- idempotency?: _TIdempotencyEnabled extends true ? TIdempotencyOpt : never;
215
+ idempotency?: TApp["idempotency"] extends true ? TIdempotencyOpt : never;
205
216
  /**
206
217
  * The refusal codes this API may refuse with, from the vocabulary given at creation: one code or a
207
218
  * non-empty list. Its guards' codes join them. The handler raises one with `ctx.refuse(content, { code, data })`,
@@ -216,19 +227,96 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
216
227
  * both ends. A transport setting of this server's, not part of the API's contract.
217
228
  */
218
229
  compress?: boolean | "auto";
219
- } & LambderRequirableGuardsField<_TSessionGuardsRequired, TGuardsOpt> & LambderSessionEnabledInstance<_TSessionsEnabled> & LambderObjectOutputCheck<TOutput> & LambderPayloadSliceCheck<_TGuards, _TRateLimitPolicies, TGuardsOpt, TRateOpt, z.input<TInput>>,
230
+ } & LambderRequirableGuardsField<TApp["guardsRequired"], TGuardsOpt> & LambderObjectOutputCheck<TOutput> & LambderPayloadSliceCheck<TApp["guards"], TApp["policies"], TGuardsOpt, TRateOpt, z.input<TInput>> & LambderPublicSessionPolicyCheck<LambderApiModeOf<TApp["guards"], TGuardsOpt>, TApp["policies"], TRateOpt> & LambderSessionModeCheck<LambderApiModeOf<TApp["guards"], TGuardsOpt>, TApp["sessions"]>,
220
231
  /** 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>;
232
+ handler: (ctx: LambderApiHandlerContext<TApp, z.infer<TInput>, TGuardsOpt, TRefusalsOpt>) => MaybePromise<TAnswer>) => LambderApiDeclaration<LambderContractEntry<z.input<TInput>, LambderJsonOf<z.output<TOutput>>, LambderApiModeOf<TApp["guards"], TGuardsOpt>, LambderGuardInputsOf<TApp["guards"], TGuardsOpt>, TGuardsOpt, TRateOpt, TIdempotencyOpt, LambderWireRefusalsOf<TApp["refusals"], LambderApiRefusalCodes<TApp["refusals"], TApp["guards"], TRefusalsOpt, TGuardsOpt>>>>;
233
+ /**
234
+ * Gathers endpoints into a named group: each is registered as
235
+ * `name.action` and called at `{apiPath}/{name}/{action}`, and every
236
+ * Lambder caller reaches it as `caller.name.action(input)`. A group's
237
+ * name and its actions are identifiers, and a group may not take a name
238
+ * a caller already answers for (see LAMBDER_RESERVED_GROUP_NAMES).
239
+ *
240
+ * A group declared across files takes each file's part:
241
+ * `defineApiGroup("orders", orderReadApis, orderWriteApis)`. An action
242
+ * two parts declare is refused, at compile time and at startup, rather
243
+ * than one silently replacing the other as an object spread would.
244
+ */
245
+ readonly defineApiGroup: <const TName extends string, const TParts extends readonly [LambderApiDeclarations, ...LambderApiDeclarations[]]>(name: TName & LambderGroupNameCheck<TName>, ...parts: TParts & LambderGroupPartsCheck<TParts> & { [TIndex in keyof TParts]: LambderActionNamesCheck<TParts[TIndex]>; }) => LambderApiGroup<TName, LambderMergedParts<TParts>>;
224
246
  /**
225
- * What registering an API is, for addApi and addSessionApi alike: the
226
- * checks that can refuse it, then its definition recorded (what
227
- * apiSignatures() digests) and its action appended to the first-match
228
- * chain. The two public methods differ only in the mode and in the types
229
- * they give the handler.
247
+ * A group loaded on the first call to one of its endpoints:
248
+ * `lazyApiGroup("orders", () => import("./orders.js").then((m) => m.orderApis))`.
249
+ * A cold start then parses none of it, nor anything only it imports,
250
+ * until a request calls it; the contract is the loaded group's, read off
251
+ * its type. The group loaded must carry the same name, which the type
252
+ * checks and loading checks again. `loadApiGroups()` loads every group,
253
+ * for a build step or a boot check that has to see them all.
254
+ */
255
+ readonly lazyApiGroup: <const TName extends string, TGroup extends LambderApiGroup<TName, any>>(name: TName & LambderGroupNameCheck<TName>, load: () => Promise<TGroup>) => LambderLazyApiGroup<TName, NoInfer<TGroup>>;
256
+ /**
257
+ * Registers groups of endpoints, as one contract: `typeof
258
+ * lambder.ApiContract` then maps every `group.action` to its entry, one
259
+ * flat object type the api-contract generator prints as it is. Register
260
+ * every group in one call where you can: the contract of one call is one
261
+ * mapped type, and a second call intersects it with the first.
262
+ *
263
+ * The call's groups take their place in the first-match chain here, as
264
+ * a route does: a route or action registered before them sees their calls
265
+ * first, one registered after them never does. The beforeRender hooks run
266
+ * before a lazy group loads, so a hook that answers a request spares it
267
+ * the import; one that throws a refusal or charges a per-API budget loads
268
+ * it (see registeredDefinitionOf).
269
+ *
270
+ * Refused at compile time: a group typed `any`, or a lazy one loading a
271
+ * group typed `any`, or a group whose endpoints are (its endpoints would
272
+ * be `any` to every client), and a group name given twice. Refused at
273
+ * registration, which is at startup for a group and at its first call for
274
+ * a lazy one: everything registration refuses of one endpoint (an unknown
275
+ * guard or policy, a missing guard where requireApiGuards is on, a
276
+ * refusal code outside the vocabulary).
230
277
  */
231
- private registerApi;
278
+ registerApiGroups<const TGroups extends readonly LambderRegistrableApiGroup[]>(this: LambderRegisteredGroupsCheck<TGroups, Lambder<TApp, _TContract>>, ...groups: TGroups): Lambder<TApp, _TContract & LambderContractOfGroups<TGroups>>;
279
+ /**
280
+ * Loads every lazy group not loaded yet, registering its endpoints: what
281
+ * a build step digesting the signatures, a generator writing the options
282
+ * or a boot check has to do before it sees every endpoint. A group whose
283
+ * registration fails rejects here, which is the point of calling it.
284
+ */
285
+ loadApiGroups(): Promise<void>;
286
+ /**
287
+ * An API call to a registered group, its hooks run: its group loaded
288
+ * first when it is a lazy one no call has reached yet, then its endpoint
289
+ * run. An action the group does not have is answered as any unmatched API
290
+ * call is, fallback hooks first.
291
+ */
292
+ private dispatchApiCall;
293
+ /**
294
+ * The definition of the endpoint a call names, its group loaded first
295
+ * when it is a lazy one no call has reached yet; undefined for a name no
296
+ * registered group declares. Everything that reads an endpoint's
297
+ * declarations for a call asks here (its dispatch, a refusal a hook
298
+ * throws on the way to it, a per-API budget a hook charges), so a lazy
299
+ * group answers each of them as an eager one does.
300
+ */
301
+ private registeredDefinitionOf;
302
+ /** The endpoints of one group, each checked as `group.action`; nothing is registered until they are committed. */
303
+ private prepareApiGroup;
304
+ /**
305
+ * A lazy group, loaded once: its import, checked to be the group it was
306
+ * registered as, then registered. Concurrent first calls share one load;
307
+ * a failed load is forgotten, so the next call tries again rather than
308
+ * answering every later call with the first failure.
309
+ */
310
+ private loadLazyApiGroup;
311
+ /**
312
+ * What registering an endpoint takes: the checks that can refuse it and
313
+ * its mode read off its guards, into the definition apiSignatures()
314
+ * digests, beside its handler. Nothing is recorded here (commitApi does
315
+ * that), so a refusal anywhere in a registration leaves nothing behind.
316
+ */
317
+ private prepareApi;
318
+ /** Records a checked endpoint: its definition, its refusals option as written, and what answers it. */
319
+ private commitApi;
232
320
  addHook(hookEvent: 'created', hookFn: LambderCreatedHook, priority?: number): this;
233
321
  addHook(hookEvent: 'beforeRender', hookFn: LambderBeforeRenderHook, priority?: number): this;
234
322
  addHook(hookEvent: 'afterRender', hookFn: LambderAfterRenderHook, priority?: number): this;
@@ -251,7 +339,13 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
251
339
  */
252
340
  addAction<TEvent>(filter: (event: unknown, ctx: LambderRenderContext | null) => event is TEvent, actionFn: (event: TEvent, tools: LambderActionTools) => MaybePromise<unknown>): this;
253
341
  addAction(filter: (event: unknown, ctx: LambderRenderContext | null) => boolean, actionFn: (event: unknown, tools: LambderActionTools) => MaybePromise<unknown>): this;
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>;
342
+ /**
343
+ * Hands the instance to a function that registers on it (routes, hooks,
344
+ * actions) and continues the chain with what it returns. Endpoints are
345
+ * not registered this way: they are values, registered by
346
+ * registerApiGroups(), so a plugin adds nothing to the contract.
347
+ */
348
+ use(plugin: (lambder: this) => unknown): this;
255
349
  /**
256
350
  * A session controller for a context: what creates, rotates, refreshes
257
351
  * and ends sessions. An API call presents its posted CSRF token; a route
@@ -259,9 +353,9 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
259
353
  * carries one as `ctx.sessionController`; this is for a context it did
260
354
  * not render, such as one createContext() built from an event on its own.
261
355
  */
262
- getSessionController(ctx: LambderRenderContext | LambderSessionRenderContext<any, TSessionData>): LambderSessionController<TSessionData>;
356
+ getSessionController(ctx: LambderRenderContext | LambderSessionRenderContext<any, TApp["session"]>): LambderSessionController<TApp["session"]>;
263
357
  /** The session manager, for code that works on sessions outside a request (maintenance, tests). */
264
- getSessionManager(): LambderSessionManager<TSessionData>;
358
+ getSessionManager(): LambderSessionManager<TApp["session"]>;
265
359
  /**
266
360
  * The backend swap `lambder/testing` performs: the stores given go under
267
361
  * this instance in place, so every handler and guard that closed over it
@@ -316,7 +410,7 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
316
410
  * same object. Every table is sorted by name, so the module diffs by
317
411
  * endpoint and never moves when registrations are reordered.
318
412
  */
319
- apiOptionEntries(): LambderApiOptionEntries;
413
+ apiOptionEntries(): Promise<LambderApiOptionEntries>;
320
414
  getResponseBuilder(ctx?: LambderRenderContext): LambderResponseBuilder;
321
415
  private getResolver;
322
416
  getHandler(): LambderHandler;
@@ -341,6 +435,12 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
341
435
  */
342
436
  private runBeforeRenderHooks;
343
437
  private handleNoMatchedAction;
438
+ /**
439
+ * What answers a request nothing matched, its beforeRender hooks run:
440
+ * the fallback hooks, then the API fallback for an API call, and
441
+ * otherwise the public files, the shell and the route fallback in turn.
442
+ */
443
+ private answerUnmatched;
344
444
  /**
345
445
  * True for the OPTIONS request the CORS layer answers by itself. Asked
346
446
  * twice: once to build the 204, once at the end of render() to pick which
@@ -351,7 +451,15 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
351
451
  */
352
452
  private isCorsPreflight;
353
453
  private resolveRequest;
454
+ /**
455
+ * One HTTP invocation, from the event to the finalized response, under
456
+ * an invocation record of its own (see LambderInvocationScope): what an
457
+ * API call's summary line is written from once the response is final.
458
+ */
354
459
  render(event: LambderHttpEvent, lambdaContext: Context): Promise<LambderHttpResponse>;
460
+ private renderRequest;
461
+ /** What createContext reads this instance's requests with. */
462
+ private contextOptions;
355
463
  /**
356
464
  * A thrown value that is an answer rather than a crash, as the response;
357
465
  * anything else is rethrown to the crash path.
@@ -376,6 +484,12 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
376
484
  * failed too.
377
485
  */
378
486
  private answerCrash;
487
+ /**
488
+ * The summary line of an API call, once its response is final: nothing
489
+ * for an invocation that served no API call. A writer that throws costs
490
+ * the call its line and nothing else.
491
+ */
492
+ private writeCallSummary;
379
493
  /**
380
494
  * An answer to a crash, carrying what the call wrote and its CORS headers.
381
495
  * As on the success path, headers belong to the call: a call that wrote a
@@ -406,6 +520,7 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
406
520
  * so Lambda's retries and dead-letter queues still see the failure.
407
521
  */
408
522
  renderEvent(event: unknown, lambdaContext: Context): Promise<unknown>;
523
+ private renderEventAction;
409
524
  /**
410
525
  * The answer for a rejected input: the app's
411
526
  * setApiInputValidationErrorHandler when set, otherwise the standard 422
@@ -446,7 +561,8 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
446
561
  /**
447
562
  * A thrown LambderApiRefusal (from a hook, say) as the structured API
448
563
  * 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
564
+ * applies, against the endpoint the call names, its lazy group loaded if
565
+ * the refusal came before the call reached it. A name no API is
450
566
  * registered under declares no code, so only an uncoded or a framework
451
567
  * refusal goes out for it.
452
568
  */
@@ -456,11 +572,12 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
456
572
  * The canonical way to create an instance: fix the session data type first,
457
573
  * then create with the full configuration in one declaration. The policy,
458
574
  * guard and idempotency types are inferred from the options, so the instance
459
- * is born fully typed and `typeof lambderApp` is the annotation type for api
460
- * modules. There are no ordering rules, and nothing can be half-configured.
575
+ * is born fully typed, and the endpoints declared with its defineApi are
576
+ * typed against it. There are no ordering rules, and nothing can be
577
+ * half-configured.
461
578
  *
462
579
  * ```typescript
463
- * // app.ts (imports no api modules, so modules can import the type back)
580
+ * // app.ts (imports no api modules, so modules can import from it)
464
581
  * export const lambderApp = initLambder<SessionData>().create({
465
582
  * apiPath: "/api",
466
583
  * session: { store: new LambderDdbSessionStore({ tableName: "app-session", region: "us-east-1" }), sessionSalt: "..." },
@@ -468,13 +585,15 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
468
585
  * guards,
469
586
  * idempotency: { store },
470
587
  * });
471
- * export type AppLambder = typeof lambderApp;
588
+ * export const { defineApi, defineApiGroup, lazyApiGroup } = lambderApp;
472
589
  *
473
590
  * // orders.ts
474
- * export const orderApi = (lambder: AppLambder) => lambder.addSessionApi(...);
591
+ * export const orderApis = defineApiGroup("orders", {
592
+ * place: defineApi({ input, output, guards: "signedIn" }, async (ctx) => ...),
593
+ * });
475
594
  *
476
595
  * // index.ts: registration only
477
- * const lambder = lambderApp.addHook(...).use(orderApi)...;
596
+ * const lambder = lambderApp.registerApiGroups(orderApis).addHook(...);
478
597
  * export const handler = lambder.getHandler();
479
598
  * ```
480
599
  *
@@ -498,7 +617,10 @@ export declare const initLambder: <TSessionData = any>() => {
498
617
  * Declares the app's refusal vocabulary: every code once, with the schema
499
618
  * of its data (`{ data: schema }`) or none (`{}`), the status every
500
619
  * refusal with it leaves with (`status`, 200 by default) and whether it
501
- * sets the notAuthorized flag (`notAuthorized: true`). Returns the init
620
+ * sets the notAuthorized flag (`notAuthorized: true`). One map of codes,
621
+ * or a list of them, as guards and rate-limit policies are declared, so
622
+ * each part of an app declares its own codes; a code two maps declare is
623
+ * refused, at compile time and at the call. Returns the init
502
624
  * bound to it: its guard() types ctx.refuse to a guard's refusals and
503
625
  * refuses a guard naming a code outside the vocabulary, its refuse is
504
626
  * typed to the whole vocabulary, and its create() hands the vocabulary to
@@ -506,7 +628,7 @@ export declare const initLambder: <TSessionData = any>() => {
506
628
  * handler, a guard or a helper is a crash rather than an answer, so every
507
629
  * "no" a client reads names a code.
508
630
  */
509
- declareRefusals<const TRefusals extends LambderRefusalVocabulary, const TRequireCodes extends boolean = false>(refusals: TRefusals & LambderRefusalVocabularyChecks<TRefusals>, options?: {
631
+ declareRefusals<const TRefusals extends LambderRefusalVocabularyOption, const TRequireCodes extends boolean = false>(refusals: TRefusals & LambderRefusalVocabularyOptionChecks<TRefusals>, options?: {
510
632
  requireCodes?: TRequireCodes;
511
633
  }): {
512
634
  /**
@@ -517,11 +639,20 @@ export declare const initLambder: <TSessionData = any>() => {
517
639
  * refuse(). Inside an API handler ctx.refuse is narrower, that
518
640
  * endpoint's codes alone.
519
641
  */
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" | "rateLimits" | "minApiVersion" | "compression" | "maxResponseBytes" | "maxRequestPayloadBytes" | "requireSessionApiGuards" | "requirePublicApiGuards" | "crashes">, never> & LambderNestedOptionChecks<TSessionData, TOptions, TRefusals>): Lambder<TSessionData, {}, TOptions["rateLimits"] extends {
522
- policies: infer TPolicies;
523
- } ? LambderMergedNamedMaps<TPolicies> extends infer TMerged extends Record<string, LambderApiRateLimitPolicyConfig> ? TMerged : {} : {}, TOptions["guards"] extends LambderNamedMapsOption<Record<string, LambderApiGuard<any, any, any>>> ? LambderGuardMetaMap<LambderMergedNamedMaps<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>;
642
+ refuse: LambderDeclaredRefuse<LambderHandlerRefusalsOf<LambderMergedRefusalVocabulary<TRefusals>, keyof LambderMergedRefusalVocabulary<TRefusals> & string>, TRequireCodes>;
643
+ create<const TOptions extends LambderInitCreateOptions<TSessionData>>(options: TOptions & Record<Exclude<keyof TOptions, "session" | "guards" | "idempotency" | "apiVersion" | "cors" | "apiPath" | "apiSignatures" | "trustedClientIpHeaders" | "trustedHostHeaders" | "originProof" | "files" | "etag" | "rateLimits" | "minApiVersion" | "compression" | "maxResponseBytes" | "maxRequestPayloadBytes" | "callSummary" | "requireApiGuards" | "crashes">, never> & LambderNestedOptionChecks<TSessionData, TOptions, LambderMergedRefusalVocabulary<TRefusals>>): Lambder<{
644
+ session: TSessionData;
645
+ policies: TOptions["rateLimits"] extends {
646
+ policies: infer TPolicies;
647
+ } ? LambderMergedNamedMaps<TPolicies> extends infer TMerged extends Record<string, LambderApiRateLimitPolicyConfig> ? TMerged : {} : {};
648
+ guards: TOptions["guards"] extends LambderNamedMapsOption<Record<string, LambderApiGuard<any, any, any>>> ? LambderGuardMetaMap<LambderMergedNamedMaps<TOptions["guards"]>> : {};
649
+ idempotency: TOptions["idempotency"] extends LambderApiIdempotencyConfig ? true : false;
650
+ guardsRequired: [LambderGivenOption<TOptions, "requireApiGuards">] extends [false | undefined] ? false : true;
651
+ sessions: [LambderGivenOption<TOptions, "session">] extends [undefined] ? false : true;
652
+ refusals: LambderMergedRefusalVocabulary<TRefusals>;
653
+ refusalCodesRequired: TRequireCodes;
654
+ }, {}>;
655
+ guard: import("../api/LambderApiGuards.js").LambderGuardBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>, LambderSessionRenderContext<any, TSessionData>, LambderMergedRefusalVocabulary<TRefusals>, TRequireCodes>;
525
656
  rateLimitKey: import("../api/LambderApiRateLimits.js").LambderRateLimitKeyBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>>;
526
657
  };
527
658
  /**
@@ -544,9 +675,18 @@ export declare const initLambder: <TSessionData = any>() => {
544
675
  code?: undefined;
545
676
  data?: undefined;
546
677
  }) | 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" | "rateLimits" | "minApiVersion" | "compression" | "maxResponseBytes" | "maxRequestPayloadBytes" | "requireSessionApiGuards" | "requirePublicApiGuards" | "crashes">, never> & LambderNestedOptionChecks<TSessionData, TOptions, {}>): Lambder<TSessionData, {}, TOptions["rateLimits"] extends {
548
- policies: infer TPolicies;
549
- } ? LambderMergedNamedMaps<TPolicies> extends infer TMerged extends Record<string, LambderApiRateLimitPolicyConfig> ? TMerged : {} : {}, TOptions["guards"] extends LambderNamedMapsOption<Record<string, LambderApiGuard<any, any, any>>> ? LambderGuardMetaMap<LambderMergedNamedMaps<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>;
678
+ create<const TOptions extends LambderInitCreateOptions<TSessionData>>(options: TOptions & Record<Exclude<keyof TOptions, "session" | "guards" | "idempotency" | "apiVersion" | "cors" | "apiPath" | "apiSignatures" | "trustedClientIpHeaders" | "trustedHostHeaders" | "originProof" | "files" | "etag" | "rateLimits" | "minApiVersion" | "compression" | "maxResponseBytes" | "maxRequestPayloadBytes" | "callSummary" | "requireApiGuards" | "crashes">, never> & LambderNestedOptionChecks<TSessionData, TOptions, {}>): Lambder<{
679
+ session: TSessionData;
680
+ policies: TOptions["rateLimits"] extends {
681
+ policies: infer TPolicies;
682
+ } ? LambderMergedNamedMaps<TPolicies> extends infer TMerged extends Record<string, LambderApiRateLimitPolicyConfig> ? TMerged : {} : {};
683
+ guards: TOptions["guards"] extends LambderNamedMapsOption<Record<string, LambderApiGuard<any, any, any>>> ? LambderGuardMetaMap<LambderMergedNamedMaps<TOptions["guards"]>> : {};
684
+ idempotency: TOptions["idempotency"] extends LambderApiIdempotencyConfig ? true : false;
685
+ guardsRequired: [LambderGivenOption<TOptions, "requireApiGuards">] extends [false | undefined] ? false : true;
686
+ sessions: [LambderGivenOption<TOptions, "session">] extends [undefined] ? false : true;
687
+ refusals: {};
688
+ refusalCodesRequired: false;
689
+ }, {}>;
550
690
  guard: import("../api/LambderApiGuards.js").LambderGuardBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>, LambderSessionRenderContext<any, TSessionData>, {}, false>;
551
691
  rateLimitKey: import("../api/LambderApiRateLimits.js").LambderRateLimitKeyBuilder<LambderRenderContext<any, Record<string, string>, {}, TSessionData>>;
552
692
  };