lambder 7.2.3 → 7.2.5

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 CHANGED
@@ -9,6 +9,35 @@ sit on its first published patch, and later patches list only what they changed.
9
9
  Releases up to 3.2.6 carry git tags; the ones after it were published without
10
10
  one, so versions are not cross-linked to tag comparisons here.
11
11
 
12
+ ## [7.2.4] - 2026-09-19
13
+
14
+ ### Changed
15
+
16
+ - **The mock's options are checked against the contract at compile time.**
17
+ Only the guard map was before, so a mock whose other options no longer fit
18
+ the contract compiled and then threw when its registry loaded, which in a
19
+ dev server is a blank page and an error in the browser console. Now each of
20
+ these is a type error at `create()`:
21
+ - `rateLimits.policies` leaving out a policy an endpoint references (a
22
+ policy added on the server and not to the mock);
23
+ - `sessions`, `idempotency` or `rateLimits` left out (or switched off)
24
+ while the contract has an endpoint that needs it, the way `guards`
25
+ already was;
26
+ - a guard with `session: true`, or a policy keyed `per: "session"`, where a
27
+ public endpoint names it;
28
+ - a `perPolicy` budget on a policy whose windows an endpoint overrides.
29
+
30
+ Each of these was already refused at registration, so a mock that compiles
31
+ now behaves as it did. The runtime checks stay for callers the types do not
32
+ reach.
33
+
34
+ ### Added
35
+
36
+ - **`LambderContractRateLimitNames<C, M?>`**, from both entries: every
37
+ rate-limit policy name the contract references, the twin of
38
+ `LambderContractGuardNames`. Both now take an optional mode to read only the
39
+ public or only the session endpoints.
40
+
12
41
  ## [7.2.3] - 2026-09-19
13
42
 
14
43
  ### Added
package/dist/client.d.ts CHANGED
@@ -23,7 +23,7 @@ export type { LambderApiAnswerOutcome, LambderApiSuccessOutcome, LambderApiCallF
23
23
  export type { LambderApiOutcome, LambderApiFailureReason, LambderValidationError, LambderCallOptions, LambderCallerOptions, LambderGuardInputsProvider, LambderProvidedGuardInputs, LambderIdempotencyKeyScope, LambderLogListHandler, } from "./client/LambderCaller.js";
24
24
  export { LambderApiRefusal, isLambderApiRefusal, refuse, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
25
25
  export type { LambderApiRefusalOptions, LambderRefusalMessage, LambderAppRefusalMessage, LambderRefusalCode, LambderRefuseOptions } from "./shared/wire/LambderApiRefusal.js";
26
- export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiResponseConfig, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
26
+ export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiResponseConfig, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractRateLimitNames, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
27
27
  export { describeCrash, errorFromCrashDetail } from "./shared/wire/LambderCrashDetail.js";
28
28
  export type { LambderCrashDetail, LambderCrashCause } from "./shared/wire/LambderCrashDetail.js";
29
29
  export { compressPayloadGzip, isRequestCompressionAvailable, COMPRESSED_PAYLOAD_GZ_FIELD, COMPRESSED_PAYLOAD_BR_FIELD, COMPRESSED_PAYLOAD_BYTES_FIELD, DEFAULT_REQUEST_COMPRESSION_SETTINGS, } from "./shared/wire/LambderRequestPayload.js";
@@ -60,10 +60,17 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
60
60
  * Type property for extracting the API contract
61
61
  * Use this to export your API types to the frontend
62
62
  *
63
+ * Export it as an interface extending LambderFlattenContract, not as a
64
+ * type alias. Chaining builds the contract as an intersection one member
65
+ * deep per endpoint, and an interface collapses that into one declared
66
+ * set of members, which every generic read of the contract (a mock
67
+ * registry, a needs map, the typed caller) is then far cheaper against.
68
+ * See LambderFlattenContract for the measurements.
69
+ *
63
70
  * @example
64
71
  * ```typescript
65
72
  * const lambder = new Lambder().addApi(...).addApi(...);
66
- * export type ApiContractType = typeof lambder.ApiContract;
73
+ * export interface ApiContractType extends LambderFlattenContract<typeof lambder.ApiContract> {}
67
74
  * ```
68
75
  */
69
76
  readonly ApiContract: _TContract;
@@ -55,10 +55,17 @@ export default class Lambder {
55
55
  * Type property for extracting the API contract
56
56
  * Use this to export your API types to the frontend
57
57
  *
58
+ * Export it as an interface extending LambderFlattenContract, not as a
59
+ * type alias. Chaining builds the contract as an intersection one member
60
+ * deep per endpoint, and an interface collapses that into one declared
61
+ * set of members, which every generic read of the contract (a mock
62
+ * registry, a needs map, the typed caller) is then far cheaper against.
63
+ * See LambderFlattenContract for the measurements.
64
+ *
58
65
  * @example
59
66
  * ```typescript
60
67
  * const lambder = new Lambder().addApi(...).addApi(...);
61
- * export type ApiContractType = typeof lambder.ApiContract;
68
+ * export interface ApiContractType extends LambderFlattenContract<typeof lambder.ApiContract> {}
62
69
  * ```
63
70
  */
64
71
  ApiContract;
package/dist/index.d.ts CHANGED
@@ -104,7 +104,7 @@ export type { LambderApiIdempotencyConfig } from "./api/LambderApiIdempotency.js
104
104
  export type { LambderGuardsOptionValue, LambderRateLimitOverride, LambderRateLimitOptionValue, LambderApiIdempotencyOption, } from "./shared/wire/LambderApiOptionValues.js";
105
105
  export { createLambderI18n } from "./shared/LambderI18n.js";
106
106
  export type { LambderLanguageMeta, LambderI18nConfig, LambderI18nInstance, LambderI18nTranslator, LambderI18nExtractParams, LambderI18nDictionaryLoader, LambderI18nCodes, LambderI18nKeys, LambderI18nTranslatorFor, } from "./shared/LambderI18n.js";
107
- export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiResponseConfig, LambderApiNullAnswerConfig, LambderContractEntry, LambderMergeContract, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
107
+ export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiResponseConfig, LambderApiNullAnswerConfig, LambderContractEntry, LambderMergeContract, LambderFlattenContract, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractRateLimitNames, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
108
108
  export type { LambderRenderContext, LambderSessionRenderContext, LambderHttpEvent, LambderHttpEventFormat } from "./core/LambderContext.js";
109
109
  export type { LambderApiAnswerOutcome, LambderApiSuccessOutcome, LambderApiCallFailure, LambderApiValidationFailure, LambderApiEnvelopeFailure, LambderApiHttpAnswer, } from "./shared/wire/LambderApiOutcome.js";
110
110
  export { resolveApiOutcome } from "./shared/wire/LambderApiOutcome.js";
@@ -1,12 +1,12 @@
1
1
  import type { LambderApiSignatureMap } from "../shared/wire/LambderApiSignature.js";
2
- import type { LambderContractGuardNames } from "../shared/wire/LambderApiContract.js";
2
+ import type { LambderContractGuardNames, LambderContractIdempotencyOf, LambderContractKeysWithMode, LambderContractRateLimitNames, LambderContractRateLimitOf } from "../shared/wire/LambderApiContract.js";
3
3
  import type { LambderApiGuard } from "../api/LambderApiGuards.js";
4
4
  import type { LambderApiRateLimitPolicyConfig } from "../api/LambderApiRateLimits.js";
5
5
  import type { LambderApiRequest } from "../api/LambderApiRequest.js";
6
6
  import type { LambderApiTransport } from "../shared/transport/LambderApiTransport.js";
7
7
  import type { LambderCookieJar } from "../shared/transport/LambderCookieJar.js";
8
8
  import type { LambderIdempotencyStore } from "../shared/contracts/LambderIdempotencyStore.js";
9
- import type { LambderRateLimiter } from "../shared/contracts/LambderRateLimiter.js";
9
+ import type { LambderRateLimiter, LambderRateLimitWindow } from "../shared/contracts/LambderRateLimiter.js";
10
10
  import type { LambderSessionStore } from "../shared/contracts/LambderSessionStore.js";
11
11
  import type { LambderSessionDataRefreshConfig } from "../session/LambderSessionManager.js";
12
12
  import type { LambderSessionCookieOptions } from "../session/LambderSessionController.js";
@@ -60,19 +60,52 @@ export type LambderMockIdempotencyOptions<S = any> = {
60
60
  */
61
61
  callerIdentity?: (ctx: Omit<LambderMockCallContext<S>, "session">, request: LambderApiRequest) => string | null | Promise<string | null>;
62
62
  };
63
+ /** Policy names whose windows some endpoint of the contract overrides, in the map form of its rateLimit option. */
64
+ type LambderContractWindowOverrideNames<C> = {
65
+ [K in keyof C]: LambderWindowOverrideNamesIn<LambderContractRateLimitOf<C, K>>;
66
+ }[keyof C] & string;
67
+ type LambderWindowOverrideNamesIn<R> = R extends string | readonly string[] ? never : {
68
+ [N in keyof R]: R[N] extends object ? ([Extract<keyof R[N], LambderRateLimitWindow>] extends [never] ? never : N) : never;
69
+ }[keyof R];
70
+ /** Endpoint names whose idempotency option asks for a store (`false` is an opt-out and asks for none). */
71
+ type LambderContractIdempotentKeys<C> = {
72
+ [K in keyof C]: [LambderContractIdempotencyOf<C, K>] extends [never] ? never : LambderContractIdempotencyOf<C, K> extends false ? never : K;
73
+ }[keyof C];
63
74
  /**
64
75
  * The rate limits option: the policies endpoints may restate, the limiter
65
76
  * they are counted on, and what happens when that limiter throws.
66
77
  *
78
+ * The policies are held to what the server's own policies were held to when
79
+ * it registered the same endpoints, because an entry the mock's copy does not
80
+ * fit cannot be registered, and this makes that an error at the option rather
81
+ * than a throw when the registry loads. So the map names every policy the
82
+ * contract references, a policy a public endpoint names is not keyed per
83
+ * session, and a policy whose windows an endpoint overrides keeps a per-API
84
+ * budget. Policies the contract does not reference may be added freely.
85
+ *
67
86
  * `failOpen` is the server's own option (see LambderApiRateLimitsConfig) and
68
87
  * is here for the reason the idempotency option's twin is: with a limiter of
69
88
  * the app's own that fails, a mock that cannot express it always lets the
70
89
  * call through, so it answers 200 where a server configured to refuse answers
71
90
  * 429.
72
91
  */
73
- type LambderMockRateLimitsOptions<S, P extends LambderMockRateLimitPolicies<S>> = {
92
+ type LambderMockRateLimitsOptions<C, S, P extends LambderMockRateLimitPolicies<S>> = {
74
93
  policies: P & {
75
94
  [N in keyof P]: LambderMockSurplusKeys<P[N], LambderApiRateLimitPolicyConfig<LambderMockCallContext<S>>>;
95
+ } & {
96
+ [N in LambderContractRateLimitNames<C>]: LambderApiRateLimitPolicyConfig<LambderMockCallContext<S>>;
97
+ } & {
98
+ [N in keyof P & LambderContractRateLimitNames<C, "public">]: P[N] extends {
99
+ per: "session";
100
+ } ? {
101
+ per: never;
102
+ } : unknown;
103
+ } & {
104
+ [N in keyof P & LambderContractWindowOverrideNames<C>]: P[N] extends {
105
+ budget: "perPolicy";
106
+ } ? {
107
+ budget: never;
108
+ } : unknown;
76
109
  };
77
110
  /** Where attempts are counted. Default: a fresh LambderMemoryRateLimiter. */
78
111
  limiter?: LambderRateLimiter;
@@ -95,11 +128,45 @@ type LambderMockGuardsOption<C, S, G> = [
95
128
  } : {
96
129
  guards: G & LambderMockGuards<C, S> & LambderMockGuardShapes<S, G>;
97
130
  };
131
+ /**
132
+ * The sessions, idempotency and rateLimits options: each required whenever
133
+ * the contract has an endpoint that needs it, for the guards option's reason.
134
+ * An entry that needs one the mock was created without cannot be registered,
135
+ * so leaving it out is an error here rather than a throw when the registry
136
+ * loads.
137
+ */
138
+ type LambderMockSessionsOption<C, S> = [
139
+ LambderContractKeysWithMode<C, "session">
140
+ ] extends [never] ? {
141
+ /** Sessions over the memory store: `true` for the defaults, or the options. Off by default. */
142
+ sessions?: boolean | LambderMockSessionsOptions<S>;
143
+ } : {
144
+ /** Sessions over the memory store: `true` for the defaults, or the options. Required: the contract has session endpoints. */
145
+ sessions: true | LambderMockSessionsOptions<S>;
146
+ };
147
+ type LambderMockIdempotencyOption<C, S, I> = [
148
+ LambderContractIdempotentKeys<C>
149
+ ] extends [never] ? {
150
+ /** Idempotency over a memory store: `true` for the defaults, or the options. Off by default. */
151
+ idempotency?: I & LambderMockSurplusKeys<I, LambderMockIdempotencyOptions<S>>;
152
+ } : {
153
+ /** Idempotency over a memory store: `true` for the defaults, or the options. Required: the contract has idempotent endpoints. */
154
+ idempotency: I & ([I] extends [false] ? never : unknown) & LambderMockSurplusKeys<I, LambderMockIdempotencyOptions<S>>;
155
+ };
156
+ type LambderMockRateLimitsOption<C, S, P extends LambderMockRateLimitPolicies<S>> = [
157
+ LambderContractRateLimitNames<C>
158
+ ] extends [never] ? {
159
+ /** The rate-limit policies endpoints may restate, over a memory limiter unless one is given. Off by default. */
160
+ rateLimits?: LambderMockRateLimitsOptions<C, S, P>;
161
+ } : {
162
+ /** The rate-limit policies endpoints may restate, over a memory limiter unless one is given. Required: the contract references policies. */
163
+ rateLimits: LambderMockRateLimitsOptions<C, S, P>;
164
+ };
98
165
  /** Each guard checked for surplus keys, so `sesion: true` on an inline guard is an error at the key rather than a guard that silently runs as public. */
99
166
  type LambderMockGuardShapes<S, G> = {
100
167
  [N in keyof G]: LambderMockSurplusKeys<G[N], LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>>;
101
168
  };
102
- export type LambderMockAppOptions<C, S, G, P extends LambderMockRateLimitPolicies<S> = LambderMockRateLimitPolicies<S>, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>> = LambderMockGuardsOption<C, S, G> & {
169
+ export type LambderMockAppOptions<C, S, G, P extends LambderMockRateLimitPolicies<S> = LambderMockRateLimitPolicies<S>, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>> = LambderMockGuardsOption<C, S, G> & LambderMockSessionsOption<C, S> & LambderMockIdempotencyOption<C, S, I> & LambderMockRateLimitsOption<C, S, P> & {
103
170
  /** Stamped on every answer's envelope as apiVersion, as the server's option is. */
104
171
  apiVersion?: string;
105
172
  /** The version floor, as on the server: a call naming a lower `version` answers versionExpired whatever its signature says. */
@@ -108,12 +175,6 @@ export type LambderMockAppOptions<C, S, G, P extends LambderMockRateLimitPolicie
108
175
  apiSignatures?: LambderApiSignatureMap;
109
176
  /** Artificial latency per call; off by default. */
110
177
  latency?: LambderMockLatency;
111
- /** Sessions over the memory store: `true` for the defaults, or the options. Off by default: session endpoints then fail at registration. */
112
- sessions?: boolean | LambderMockSessionsOptions<S>;
113
- /** The rate-limit policies endpoints may restate, over a memory limiter unless one is given. Off by default. */
114
- rateLimits?: LambderMockRateLimitsOptions<S, P>;
115
- /** Idempotency over a memory store: `true` for the defaults, or the options. Off by default. */
116
- idempotency?: I & LambderMockSurplusKeys<I, LambderMockIdempotencyOptions<S>>;
117
178
  /**
118
179
  * The host the runtime's cookies belong to: what signIn plants them
119
180
  * under, what the direct transport's jar scopes them by, what the MSW
@@ -90,8 +90,10 @@ export type LambderMockContext<C, K extends keyof C, S, G> = Omit<LambderMockCal
90
90
  * The guard map a mock app must declare: one guard per name any endpoint of
91
91
  * the contract declares, and for every guard the contract knows in
92
92
  * guardInput mode, a `guardInput` schema whose output is what the server
93
- * inferred. A missing name or a schema that parses to something else fails
94
- * at the `guards` option.
93
+ * inferred. A guard a public endpoint names may not require a session, since
94
+ * an entry naming one cannot be registered. A missing name, a schema that
95
+ * parses to something else, or a session guard where the contract has a
96
+ * public endpoint fails at the `guards` option.
95
97
  */
96
98
  export type LambderMockGuards<C, S = any> = {
97
99
  [N in LambderContractGuardNames<C>]: LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>;
@@ -99,6 +101,10 @@ export type LambderMockGuards<C, S = any> = {
99
101
  [N in LambderContractGuardInputNames<C>]: {
100
102
  guardInput: z.ZodType<LambderContractGuardInput<C, N>, any>;
101
103
  };
104
+ } & {
105
+ [N in LambderContractGuardNames<C, "public">]: {
106
+ session?: false;
107
+ };
102
108
  };
103
109
  export type LambderMockHandler<C, K extends keyof C, S, G> = (ctx: LambderMockContext<C, K, S, G>) => LambderMockOutputOf<C, K> | Promise<LambderMockOutputOf<C, K>>;
104
110
  /**
@@ -85,6 +85,56 @@ export type LambderContractEntry<In, Out, Mode extends LambderApiMode, GuardInpu
85
85
  export type LambderMergeContract<Old, Name extends string, Entry> = Old & {
86
86
  [K in Name]: Entry;
87
87
  };
88
+ /**
89
+ * The contract as one object type, for the `export interface` a consuming
90
+ * app declares its contract through:
91
+ *
92
+ * ```ts
93
+ * export interface ApiContractType extends LambderFlattenContract<typeof lambder.ApiContract> {}
94
+ * ```
95
+ *
96
+ * Chaining leaves the contract an intersection one member deep per endpoint
97
+ * (LambderMergeContract above), and every `C[K]` written against a type
98
+ * parameter then resolves the property across all of them. That lookup is
99
+ * the atom the reading helpers below are built from, so its cost is paid
100
+ * again by each of them, per endpoint, in every app that registers a mock,
101
+ * declares a needs map, or otherwise reads the contract generically: in a
102
+ * 182-endpoint app one indexed access measured ~3,000 type instantiations
103
+ * and one mock registration ~18,000.
104
+ *
105
+ * Extending an interface is what collapses it. An interface's members are
106
+ * declared, so they are resolved once for the whole declaration rather than
107
+ * per lookup, and the same access measured ~6 instantiations after the
108
+ * change: a 182-endpoint app's frontend type check went from 27.8M
109
+ * instantiations to 7.0M and from 20.2s to 10.6s of check time. The alias
110
+ * form (`type C = LambderFlattenContract<...>`) does NOT do this: a mapped
111
+ * type stays deferred and each lookup pays the full cost again, so the
112
+ * `interface ... extends` spelling is the point.
113
+ *
114
+ * Diagnostics are the same ones, and they read better: a message naming the
115
+ * contract prints the interface by name, where the intersection is printed
116
+ * as a truncated spill of entries.
117
+ *
118
+ * Every endpoint name must be a string literal for an interface to extend
119
+ * the result, which registration through addApi/addSessionApi guarantees.
120
+ *
121
+ * Two things quietly undo it, both of which look like tidying:
122
+ *
123
+ * - `@typescript-eslint/no-empty-object-type` reports the empty body as
124
+ * "equivalent to its supertype" and its fix is a type alias, which is the
125
+ * one spelling that does not collapse anything. Disable the rule on the
126
+ * line rather than taking the fix.
127
+ * - Extending anything but a mapped type loses the inferable index signature.
128
+ * An interface has none of its own, so a hand-written `interface C { ... }`
129
+ * is not assignable to LambderApiContractShape and is rejected by
130
+ * initLambderMock<C>, LambderCaller<C> and LambderInvokeCaller<C>;
131
+ * extending this mapped type is what keeps it. api-contract.test.ts pins
132
+ * that, along with the flattened contract being the same type member for
133
+ * member.
134
+ */
135
+ export type LambderFlattenContract<C> = {
136
+ [K in keyof C]: C[K];
137
+ };
88
138
  /** Guard names referenced by a guards option, whichever of its three forms is used. */
89
139
  export type LambderGuardNamesIn<TOpt> = TOpt extends string ? TOpt : TOpt extends readonly (infer N extends string)[] ? N : TOpt extends object ? keyof TOpt & string : never;
90
140
  /** The endpoint's mode; a contract written without one admits either. */
@@ -99,10 +149,10 @@ export type LambderContractKeysWithMode<C, M extends LambderApiMode> = {
99
149
  export type LambderContractGuardsOf<C, K extends keyof C> = C[K] extends {
100
150
  guards: infer G;
101
151
  } ? G : never;
102
- /** Every guard name any endpoint of the contract declares. */
103
- export type LambderContractGuardNames<C> = {
104
- [K in keyof C]: LambderGuardNamesIn<LambderContractGuardsOf<C, K>>;
105
- }[keyof C] & string;
152
+ /** Every guard name any endpoint of the contract declares, or only the endpoints of mode M. */
153
+ export type LambderContractGuardNames<C, M extends LambderApiMode = LambderApiMode> = {
154
+ [K in LambderContractKeysWithMode<C, M>]: LambderGuardNamesIn<LambderContractGuardsOf<C, K>>;
155
+ }[LambderContractKeysWithMode<C, M>] & string;
106
156
  /** The endpoint's guardInputs requirement, or never when its guards take no client input. */
107
157
  export type LambderContractGuardInputsOf<C, K extends keyof C> = C[K] extends {
108
158
  guardInputs: infer G;
@@ -123,6 +173,10 @@ export type LambderContractGuardInputNames<C> = {
123
173
  export type LambderContractRateLimitOf<C, K extends keyof C> = C[K] extends {
124
174
  rateLimit: infer R;
125
175
  } ? R : never;
176
+ /** Every rate-limit policy name any endpoint of the contract references, or only the endpoints of mode M. The rateLimit option takes the guards option's three forms, so the names come out the same way. */
177
+ export type LambderContractRateLimitNames<C, M extends LambderApiMode = LambderApiMode> = {
178
+ [K in LambderContractKeysWithMode<C, M>]: LambderGuardNamesIn<LambderContractRateLimitOf<C, K>>;
179
+ }[LambderContractKeysWithMode<C, M>] & string;
126
180
  /** The endpoint's idempotency option as written, or never. */
127
181
  export type LambderContractIdempotencyOf<C, K extends keyof C> = C[K] extends {
128
182
  idempotency: infer I;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambder",
3
- "version": "7.2.3",
3
+ "version": "7.2.5",
4
4
  "sideEffects": false,
5
5
  "description": "Opinionated serverless web framework for TypeScript on AWS Lambda: type-safe APIs from Zod schemas, DynamoDB sessions, and declarative rate limits, authorization guards and idempotency.",
6
6
  "keywords": [