lambder 8.1.2 → 9.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 +208 -0
- package/README.md +23 -31
- package/dist/api/LambderApiCallContext.d.ts +31 -1
- package/dist/api/LambderApiCallContext.js +8 -0
- package/dist/api/LambderApiDefinition.d.ts +2 -2
- package/dist/api/LambderApiEnvelope.d.ts +1 -1
- package/dist/api/LambderApiEnvelope.js +3 -4
- package/dist/api/LambderApiGuards.d.ts +2 -17
- package/dist/api/LambderApiIdempotency.js +5 -7
- package/dist/api/LambderApiRateLimits.d.ts +2 -29
- package/dist/build/generatedTables.d.ts +72 -0
- package/dist/build/generatedTables.js +99 -0
- package/dist/build/writeApiGuardParams.d.ts +60 -0
- package/dist/build/writeApiGuardParams.js +85 -0
- package/dist/build/writeApiOptions.d.ts +68 -0
- package/dist/build/writeApiOptions.js +102 -0
- package/dist/build.d.ts +10 -4
- package/dist/build.js +7 -4
- package/dist/client/LambderCaller.d.ts +0 -4
- package/dist/client/LambderCaller.js +1 -9
- package/dist/client/LambderUploadRunner.d.ts +7 -7
- package/dist/client/LambderUploadRunner.js +12 -21
- package/dist/client.d.ts +7 -0
- package/dist/client.js +11 -0
- package/dist/core/Lambder.d.ts +71 -12
- package/dist/core/Lambder.js +116 -38
- package/dist/core/LambderContext.d.ts +9 -6
- package/dist/core/LambderContext.js +2 -1
- package/dist/core/LambderResolver.d.ts +6 -12
- package/dist/core/LambderResolver.js +2 -14
- package/dist/core/LambderResponseBuilder.d.ts +15 -70
- package/dist/core/LambderResponseBuilder.js +15 -99
- package/dist/index.d.ts +16 -3
- package/dist/index.js +14 -1
- package/dist/invoke/LambderInvokeCaller.js +3 -4
- package/dist/mock/LambderMockApp.d.ts +34 -17
- package/dist/mock/LambderMockApp.js +69 -24
- package/dist/mock/LambderMockCreateOptions.d.ts +70 -7
- package/dist/mock/LambderMockTypes.d.ts +31 -21
- package/dist/mock/lambderMockPoliciesFrom.d.ts +51 -0
- package/dist/mock/lambderMockPoliciesFrom.js +46 -0
- package/dist/mock.d.ts +3 -0
- package/dist/mock.js +3 -0
- package/dist/secrets/LambderOneShotSecrets.d.ts +166 -0
- package/dist/secrets/LambderOneShotSecrets.js +217 -0
- package/dist/session/LambderSessionCrypto.js +6 -16
- package/dist/shared/contracts/LambderIdempotencyStore.d.ts +3 -2
- package/dist/shared/contracts/LambderOneShotSecretStore.d.ts +122 -0
- package/dist/shared/contracts/LambderOneShotSecretStore.js +38 -0
- package/dist/shared/util/LambderBackoffTimer.d.ts +82 -0
- package/dist/shared/util/LambderBackoffTimer.js +86 -0
- package/dist/shared/util/LambderBase64.d.ts +14 -0
- package/dist/shared/util/LambderBase64.js +17 -0
- package/dist/shared/util/LambderSignedClaims.d.ts +78 -0
- package/dist/shared/util/LambderSignedClaims.js +109 -0
- package/dist/shared/util/LambderTextDigest.d.ts +19 -5
- package/dist/shared/util/LambderTextDigest.js +30 -5
- package/dist/shared/util/LambderTypeUtilities.d.ts +18 -0
- package/dist/shared/util/assertPlainData.d.ts +9 -0
- package/dist/shared/util/assertPlainData.js +41 -0
- package/dist/shared/wire/LambderAnswerHeaders.d.ts +3 -2
- package/dist/shared/wire/LambderAnswerHeaders.js +3 -2
- package/dist/shared/wire/LambderApiContract.d.ts +9 -14
- package/dist/shared/wire/LambderApiOptionEntries.d.ts +148 -0
- package/dist/shared/wire/LambderApiOptionEntries.js +35 -0
- package/dist/shared/wire/LambderApiRefusal.d.ts +3 -4
- package/dist/shared/wire/LambderApiRefusal.js +3 -4
- package/dist/stores/LambderDdbOneShotSecretStore.d.ts +64 -0
- package/dist/stores/LambderDdbOneShotSecretStore.js +266 -0
- package/dist/stores/LambderMemoryIdempotencyStore.d.ts +3 -2
- package/dist/stores/LambderMemoryIdempotencyStore.js +3 -2
- package/dist/stores/LambderMemoryOneShotSecretStore.d.ts +36 -0
- package/dist/stores/LambderMemoryOneShotSecretStore.js +93 -0
- package/dist/testing/LambderConformanceRunner.d.ts +46 -0
- package/dist/testing/LambderConformanceRunner.js +21 -0
- package/dist/testing/lambderIdempotencyStoreConformance.d.ts +33 -0
- package/dist/testing/lambderIdempotencyStoreConformance.js +237 -0
- package/dist/testing/lambderOneShotSecretStoreConformance.d.ts +43 -0
- package/dist/testing/lambderOneShotSecretStoreConformance.js +224 -0
- package/dist/testing/lambderRateLimiterConformance.d.ts +20 -0
- package/dist/testing/lambderRateLimiterConformance.js +72 -0
- package/dist/testing/lambderSessionStoreConformance.d.ts +27 -0
- package/dist/testing/lambderSessionStoreConformance.js +165 -0
- package/dist/testing.d.ts +14 -0
- package/dist/testing.js +12 -0
- package/package.json +1 -1
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import type { z } from "zod";
|
|
2
1
|
import type { LambderRenderContext } from "./LambderContext.js";
|
|
3
|
-
import { type LambderCookieOptions, type LambderClearCookieOptions } from "../shared/wire/LambderCookie.js";
|
|
4
2
|
import type { LambderFiles } from "./LambderFiles.js";
|
|
5
3
|
import { LambderResponse, type LambderHeadersInput } from "./LambderResponse.js";
|
|
6
4
|
import type { LambderHttpStatusCode } from "../shared/wire/LambderHttpStatus.js";
|
|
7
5
|
import { LambderSafeHtml } from "../shared/LambderHtml.js";
|
|
8
6
|
import type { LambderTemplateData } from "./LambderTemplatingEngine.js";
|
|
9
|
-
import type { LambderApiResponseConfig
|
|
7
|
+
import type { LambderApiResponseConfig } from "../shared/wire/LambderApiContract.js";
|
|
10
8
|
export type { LambderApiEnvelopeBody, LambderApiResponseConfig } from "../shared/wire/LambderApiContract.js";
|
|
11
9
|
export type LambderResponseOptions = {
|
|
12
10
|
statusCode?: LambderHttpStatusCode;
|
|
@@ -18,19 +16,6 @@ export type LambderResponseOptions = {
|
|
|
18
16
|
/** "auto" (default): ETag on GET/HEAD 200 when globally enabled. true: force. false: never. */
|
|
19
17
|
etag?: boolean | "auto";
|
|
20
18
|
};
|
|
21
|
-
/**
|
|
22
|
-
* The two shapes of an API answer: the output the contract declares, or
|
|
23
|
-
* `null` beside a config that says why (a refusal flag, an `errorMessage`, a
|
|
24
|
-
* `message`). A bare `res.api(null)` compiles only when the output type
|
|
25
|
-
* itself allows null, so a success payload is always the declared output,
|
|
26
|
-
* which lets a typed caller (LambderInvokeCaller.api) promise it. Untyped
|
|
27
|
-
* resolvers (`TOutput = any`) accept anything. This is the resolver's method
|
|
28
|
-
* type; the core's answer type is LambderApiAnswer.
|
|
29
|
-
*/
|
|
30
|
-
export type LambderResolverApiMethod<TOutput, TResult> = {
|
|
31
|
-
(payload: TOutput, config?: LambderApiResponseConfig, options?: LambderResponseOptions): TResult;
|
|
32
|
-
(payload: null, config: LambderApiNullAnswerConfig, options?: LambderResponseOptions): TResult;
|
|
33
|
-
};
|
|
34
19
|
export type LambderRawResponseInit = {
|
|
35
20
|
statusCode: LambderHttpStatusCode;
|
|
36
21
|
headers?: LambderHeadersInput;
|
|
@@ -40,39 +25,23 @@ export type LambderRawResponseInit = {
|
|
|
40
25
|
compress?: boolean | "auto";
|
|
41
26
|
etag?: boolean | "auto";
|
|
42
27
|
};
|
|
43
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Builds the responses of routes, hooks and error handlers. An API handler
|
|
30
|
+
* never holds one: it returns its output or refuses, and writes headers and
|
|
31
|
+
* cookies through its context (LambderResponseTools).
|
|
32
|
+
*/
|
|
33
|
+
export default class LambderResponseBuilder {
|
|
44
34
|
protected files: LambderFiles | null;
|
|
45
35
|
protected apiVersion: string | null;
|
|
46
36
|
protected ctx?: LambderRenderContext;
|
|
47
|
-
|
|
48
|
-
protected apiOutput: z.ZodType | null;
|
|
49
|
-
constructor({ files, apiVersion, ctx, apiOutput }: {
|
|
37
|
+
constructor({ files, apiVersion, ctx }: {
|
|
50
38
|
files?: LambderFiles | null;
|
|
51
39
|
apiVersion?: string | null;
|
|
52
40
|
ctx?: LambderRenderContext;
|
|
53
|
-
apiOutput?: z.ZodType;
|
|
54
41
|
});
|
|
55
42
|
private buildResponse;
|
|
56
43
|
/** The instance's file reader, which res.file and res.templateFile need. */
|
|
57
44
|
private requireFiles;
|
|
58
|
-
/** Appends a response header; applied onto the response once the handler has one, in call order. */
|
|
59
|
-
addHeader(key: string, value: string): void;
|
|
60
|
-
/** Replaces a response header; applied onto the response once the handler has one, in call order. */
|
|
61
|
-
setHeader(key: string, value: string | string[]): void;
|
|
62
|
-
/**
|
|
63
|
-
* Adds a Set-Cookie header. A function-form `domain` is resolved against
|
|
64
|
-
* the request hostname. Defaults: Path=/, SameSite=Lax, Secure, not
|
|
65
|
-
* HttpOnly, browser-session lifetime.
|
|
66
|
-
*/
|
|
67
|
-
setCookie(name: string, value: string, options?: LambderCookieOptions): void;
|
|
68
|
-
/**
|
|
69
|
-
* Adds a Set-Cookie header that deletes the cookie. Pass the same
|
|
70
|
-
* `domain` and `path` the cookie was set with: a cookie's identity is
|
|
71
|
-
* (name, domain, path), and a deletion under a different scope targets a
|
|
72
|
-
* different cookie and deletes nothing.
|
|
73
|
-
*/
|
|
74
|
-
clearCookie(name: string, options?: LambderClearCookieOptions): void;
|
|
75
|
-
logToApiResponse(input: unknown): void;
|
|
76
45
|
raw(init: LambderRawResponseInit): LambderResponse;
|
|
77
46
|
json(data: Record<string, any>, options?: LambderResponseOptions): LambderResponse;
|
|
78
47
|
text(data: string, options?: LambderResponseOptions): LambderResponse;
|
|
@@ -109,37 +78,13 @@ export default class LambderResponseBuilder<TResponse = any> {
|
|
|
109
78
|
templateFile(filePath: string, data?: LambderTemplateData, options?: LambderResponseOptions & {
|
|
110
79
|
htmlVirtualSlots?: boolean;
|
|
111
80
|
}): Promise<LambderResponse>;
|
|
112
|
-
api(payload: TResponse, config?: LambderApiResponseConfig, options?: LambderResponseOptions): LambderResponse;
|
|
113
|
-
api(payload: null, config: LambderApiNullAnswerConfig, options?: LambderResponseOptions): LambderResponse;
|
|
114
81
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* the declared shape. A refusal's payload beside an errorMessage or a
|
|
122
|
-
* flag is parsed the same way; only null passes as it is. Only an API
|
|
123
|
-
* handler's own resolver holds the schema: a hook, a validation handler
|
|
124
|
-
* or an error handler answers in shapes of its own, a cached answer in
|
|
125
|
-
* its wire form, and is sent as given.
|
|
126
|
-
*
|
|
127
|
-
* The payload is the schema's input form (what a handler writes before
|
|
128
|
-
* the transforms), so a transform runs exactly once. A payload the schema
|
|
129
|
-
* rejects is a handler breaking its contract, answered as a crash rather
|
|
130
|
-
* than sent (LambderApiOutputValidationError, which an idempotency key
|
|
131
|
-
* records as its answer, since the handler has already run).
|
|
132
|
-
*
|
|
133
|
-
* The parse is synchronous, so an output schema cannot be async: zod
|
|
134
|
-
* throws from a synchronous parse that meets an async refinement or
|
|
135
|
-
* transform, and a transform may throw of its own accord. Either throw
|
|
136
|
-
* becomes the same LambderApiOutputValidationError, carrying what was
|
|
137
|
-
* thrown as its cause. Left to escape as it is, it would read as the
|
|
138
|
-
* handler crashing before its answer: the idempotency engine would
|
|
139
|
-
* release the key's claim and every retry would run the operation again.
|
|
82
|
+
* An API envelope written by hand: what a hook, an input validation
|
|
83
|
+
* handler or a global error handler answers an API call with (a refusal
|
|
84
|
+
* flag, an errorMessage, a crash). The payload goes out as given; an API
|
|
85
|
+
* handler's own output is parsed through its schema by the instance
|
|
86
|
+
* instead. The logList channel is what the request accumulated unless the
|
|
87
|
+
* config names its own.
|
|
140
88
|
*/
|
|
141
|
-
|
|
142
|
-
/** Same as api() but forces compression of the response body. */
|
|
143
|
-
apiBinary(payload: TResponse, config?: LambderApiResponseConfig, options?: LambderResponseOptions): LambderResponse;
|
|
144
|
-
apiBinary(payload: null, config: LambderApiNullAnswerConfig, options?: LambderResponseOptions): LambderResponse;
|
|
89
|
+
api(payload: unknown, config?: LambderApiResponseConfig, options?: LambderResponseOptions): LambderResponse;
|
|
145
90
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { serializeCookie, serializeClearCookie } from "../shared/wire/LambderCookie.js";
|
|
2
1
|
import { LambderResponse } from "./LambderResponse.js";
|
|
3
2
|
import { buildApiEnvelope } from "../api/LambderApiEnvelope.js";
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Builds the responses of routes, hooks and error handlers. An API handler
|
|
5
|
+
* never holds one: it returns its output or refuses, and writes headers and
|
|
6
|
+
* cookies through its context (LambderResponseTools).
|
|
7
|
+
*/
|
|
5
8
|
export default class LambderResponseBuilder {
|
|
6
9
|
files;
|
|
7
10
|
apiVersion;
|
|
8
11
|
ctx;
|
|
9
|
-
|
|
10
|
-
apiOutput;
|
|
11
|
-
constructor({ files, apiVersion, ctx, apiOutput }) {
|
|
12
|
+
constructor({ files, apiVersion, ctx }) {
|
|
12
13
|
this.files = files ?? null;
|
|
13
14
|
this.apiVersion = apiVersion ?? null;
|
|
14
15
|
this.ctx = ctx;
|
|
15
|
-
this.apiOutput = apiOutput ?? null;
|
|
16
16
|
}
|
|
17
17
|
;
|
|
18
18
|
buildResponse(statusCode, contentType, body, options, defaults) {
|
|
@@ -37,49 +37,6 @@ export default class LambderResponseBuilder {
|
|
|
37
37
|
throw new Error(`Lambder: ${method} requires the files option at creation (e.g. files: new LambderLocalFileSource({ root }))`);
|
|
38
38
|
return this.files;
|
|
39
39
|
}
|
|
40
|
-
/** Appends a response header; applied onto the response once the handler has one, in call order. */
|
|
41
|
-
addHeader(key, value) {
|
|
42
|
-
if (!this.ctx)
|
|
43
|
-
throw new Error("Lambder: res.addHeader needs the request context, and this response builder was created without one.");
|
|
44
|
-
this.ctx.responseHeaders.add(key, value);
|
|
45
|
-
}
|
|
46
|
-
;
|
|
47
|
-
/** Replaces a response header; applied onto the response once the handler has one, in call order. */
|
|
48
|
-
setHeader(key, value) {
|
|
49
|
-
if (!this.ctx)
|
|
50
|
-
throw new Error("Lambder: res.setHeader needs the request context, and this response builder was created without one.");
|
|
51
|
-
this.ctx.responseHeaders.set(key, value);
|
|
52
|
-
}
|
|
53
|
-
;
|
|
54
|
-
/**
|
|
55
|
-
* Adds a Set-Cookie header. A function-form `domain` is resolved against
|
|
56
|
-
* the request hostname. Defaults: Path=/, SameSite=Lax, Secure, not
|
|
57
|
-
* HttpOnly, browser-session lifetime.
|
|
58
|
-
*/
|
|
59
|
-
setCookie(name, value, options) {
|
|
60
|
-
if (!this.ctx)
|
|
61
|
-
throw new Error("Lambder: res.setCookie needs the request context, and this response builder was created without one.");
|
|
62
|
-
this.addHeader("Set-Cookie", serializeCookie(name, value, options, this.ctx.host));
|
|
63
|
-
}
|
|
64
|
-
;
|
|
65
|
-
/**
|
|
66
|
-
* Adds a Set-Cookie header that deletes the cookie. Pass the same
|
|
67
|
-
* `domain` and `path` the cookie was set with: a cookie's identity is
|
|
68
|
-
* (name, domain, path), and a deletion under a different scope targets a
|
|
69
|
-
* different cookie and deletes nothing.
|
|
70
|
-
*/
|
|
71
|
-
clearCookie(name, options) {
|
|
72
|
-
if (!this.ctx)
|
|
73
|
-
throw new Error("Lambder: res.clearCookie needs the request context, and this response builder was created without one.");
|
|
74
|
-
this.addHeader("Set-Cookie", serializeClearCookie(name, options, this.ctx.host));
|
|
75
|
-
}
|
|
76
|
-
;
|
|
77
|
-
logToApiResponse(input) {
|
|
78
|
-
if (!this.ctx)
|
|
79
|
-
throw new Error("Lambder: res.logToApiResponse needs the request context, and this response builder was created without one.");
|
|
80
|
-
this.ctx.logList.push(input);
|
|
81
|
-
}
|
|
82
|
-
;
|
|
83
40
|
raw(init) {
|
|
84
41
|
return new LambderResponse({
|
|
85
42
|
statusCode: init.statusCode,
|
|
@@ -177,58 +134,17 @@ export default class LambderResponseBuilder {
|
|
|
177
134
|
return this.buildResponse(200, "text/html; charset=utf-8", template.render(data), options);
|
|
178
135
|
}
|
|
179
136
|
;
|
|
180
|
-
api(payload, config = {}, options) {
|
|
181
|
-
// The envelope is the core's (one writer for both the server and the
|
|
182
|
-
// mock runtime); the logList channel is what this request accumulated
|
|
183
|
-
// unless the config names its own.
|
|
184
|
-
const envelope = buildApiEnvelope(this.apiVersion, this.declaredPayload(payload), { ...config, logList: config.logList || this.ctx?.logList });
|
|
185
|
-
return this.json(envelope, options);
|
|
186
|
-
}
|
|
187
|
-
;
|
|
188
137
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
* the declared shape. A refusal's payload beside an errorMessage or a
|
|
196
|
-
* flag is parsed the same way; only null passes as it is. Only an API
|
|
197
|
-
* handler's own resolver holds the schema: a hook, a validation handler
|
|
198
|
-
* or an error handler answers in shapes of its own, a cached answer in
|
|
199
|
-
* its wire form, and is sent as given.
|
|
200
|
-
*
|
|
201
|
-
* The payload is the schema's input form (what a handler writes before
|
|
202
|
-
* the transforms), so a transform runs exactly once. A payload the schema
|
|
203
|
-
* rejects is a handler breaking its contract, answered as a crash rather
|
|
204
|
-
* than sent (LambderApiOutputValidationError, which an idempotency key
|
|
205
|
-
* records as its answer, since the handler has already run).
|
|
206
|
-
*
|
|
207
|
-
* The parse is synchronous, so an output schema cannot be async: zod
|
|
208
|
-
* throws from a synchronous parse that meets an async refinement or
|
|
209
|
-
* transform, and a transform may throw of its own accord. Either throw
|
|
210
|
-
* becomes the same LambderApiOutputValidationError, carrying what was
|
|
211
|
-
* thrown as its cause. Left to escape as it is, it would read as the
|
|
212
|
-
* handler crashing before its answer: the idempotency engine would
|
|
213
|
-
* release the key's claim and every retry would run the operation again.
|
|
138
|
+
* An API envelope written by hand: what a hook, an input validation
|
|
139
|
+
* handler or a global error handler answers an API call with (a refusal
|
|
140
|
+
* flag, an errorMessage, a crash). The payload goes out as given; an API
|
|
141
|
+
* handler's own output is parsed through its schema by the instance
|
|
142
|
+
* instead. The logList channel is what the request accumulated unless the
|
|
143
|
+
* config names its own.
|
|
214
144
|
*/
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const apiName = this.ctx?.apiName ?? "?";
|
|
219
|
-
let parsed;
|
|
220
|
-
try {
|
|
221
|
-
parsed = this.apiOutput.safeParse(payload);
|
|
222
|
-
}
|
|
223
|
-
catch (thrown) {
|
|
224
|
-
throw new LambderApiOutputValidationError(apiName, { thrown });
|
|
225
|
-
}
|
|
226
|
-
if (parsed.success)
|
|
227
|
-
return parsed.data;
|
|
228
|
-
throw new LambderApiOutputValidationError(apiName, { zodError: parsed.error });
|
|
229
|
-
}
|
|
230
|
-
apiBinary(payload, config = {}, options) {
|
|
231
|
-
return this.api(payload, config, { ...options, compress: true });
|
|
145
|
+
api(payload, config = {}, options) {
|
|
146
|
+
const envelope = buildApiEnvelope(this.apiVersion, payload, { ...config, logList: config.logList || this.ctx?.logList });
|
|
147
|
+
return this.json(envelope, options);
|
|
232
148
|
}
|
|
233
149
|
;
|
|
234
150
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,11 @@ export { lambderCookieJarTransport } from "./shared/transport/lambderCookieJarTr
|
|
|
12
12
|
export type { LambderApiTransport, LambderApiTransportRequest, LambderTransportFailureReason } from "./shared/transport/LambderApiTransport.js";
|
|
13
13
|
export { LambderCookieJar, parseSetCookie } from "./shared/transport/LambderCookieJar.js";
|
|
14
14
|
export { LambderExpiringMap, LambderExpiringMapFullError } from "./shared/util/LambderExpiringMap.js";
|
|
15
|
+
export { LambderBackoffTimer } from "./shared/util/LambderBackoffTimer.js";
|
|
16
|
+
export type { LambderBackoffTimerOptions } from "./shared/util/LambderBackoffTimer.js";
|
|
17
|
+
export { LambderSignedClaims, keyedDigest, randomSecret } from "./shared/util/LambderSignedClaims.js";
|
|
18
|
+
export type { LambderSignedClaimsOptions } from "./shared/util/LambderSignedClaims.js";
|
|
19
|
+
export { constantTimeEquals } from "./shared/util/LambderTextDigest.js";
|
|
15
20
|
export type { LambderStoredCookie } from "./shared/transport/LambderCookieJar.js";
|
|
16
21
|
export { lambderHandlerTransport } from "./invoke/lambderHandlerTransport.js";
|
|
17
22
|
export type { LambderHandlerTransportOptions } from "./invoke/lambderHandlerTransport.js";
|
|
@@ -25,7 +30,7 @@ export { toHttpAnswer } from "./api/LambderApiAnswer.js";
|
|
|
25
30
|
export type { LambderApiAnswer } from "./api/LambderApiAnswer.js";
|
|
26
31
|
export { LambderAnswerHeaders, getAnswerHeader, setAnswerHeader, addAnswerHeader } from "./shared/wire/LambderAnswerHeaders.js";
|
|
27
32
|
export { createApiCallContext } from "./api/LambderApiCallContext.js";
|
|
28
|
-
export type { LambderApiCallContext, LambderApiCallTrace } from "./api/LambderApiCallContext.js";
|
|
33
|
+
export type { LambderApiCallContext, LambderApiCallTrace, LambderResponseTools } from "./api/LambderApiCallContext.js";
|
|
29
34
|
export type { LambderApiDefinition } from "./api/LambderApiDefinition.js";
|
|
30
35
|
export { apiSignatureOf } from "./api/LambderApiSignature.js";
|
|
31
36
|
export type { LambderApiSignatureEntry } from "./api/LambderApiSignature.js";
|
|
@@ -63,7 +68,7 @@ export type { LambderHttpStatusCode } from "./shared/wire/LambderHttpStatus.js";
|
|
|
63
68
|
export { html, xml, raw, jsonScript, escapeHtml, renderHtmlValue, LambderSafeHtml, type LambderHtmlValue } from "./shared/LambderHtml.js";
|
|
64
69
|
export { LambderTemplatingEngine } from "./core/LambderTemplatingEngine.js";
|
|
65
70
|
export type { LambderTemplateData, LambderTemplatingEngineOptions } from "./core/LambderTemplatingEngine.js";
|
|
66
|
-
export type { LambderResponseOptions, LambderRawResponseInit,
|
|
71
|
+
export type { LambderResponseOptions, LambderRawResponseInit, } from "./core/LambderResponseBuilder.js";
|
|
67
72
|
export type { LambderRouteMatcher, LambderRouteConditionFn, LambderRouteCondition, LambderPathParamsOf, LambderRoutePath } from "./core/LambderRouting.js";
|
|
68
73
|
export type { LambderCorsConfig } from "./core/LambderCors.js";
|
|
69
74
|
export type { LambderCreateOptions, LambderSessionOptions, LambderActionTools, LambderHandler, } from "./core/LambderCreateOptions.js";
|
|
@@ -106,6 +111,12 @@ export type { LambderRateLimiter, LambderRateLimitWindow, LambderRateLimitPolicy
|
|
|
106
111
|
export { LambderDdbRateLimiter } from "./stores/LambderDdbRateLimiter.js";
|
|
107
112
|
export type { LambderDdbRateLimiterOptions } from "./stores/LambderDdbRateLimiter.js";
|
|
108
113
|
export { LambderMemoryRateLimiter } from "./stores/LambderMemoryRateLimiter.js";
|
|
114
|
+
export { LambderOneShotSecrets } from "./secrets/LambderOneShotSecrets.js";
|
|
115
|
+
export type { LambderOneShotSecretKind, LambderOneShotSecretsOptions, LambderOneShotIssueResult, LambderOneShotRedeemResult, LambderOneShotCodeKindNames, LambderOneShotTokenKindNames, } from "./secrets/LambderOneShotSecrets.js";
|
|
116
|
+
export type { LambderOneShotSecretStore, LambderOneShotSecretRecord, LambderOneShotSecretDraft, LambderOneShotSecretShape, LambderOneShotIssueOutcome, } from "./shared/contracts/LambderOneShotSecretStore.js";
|
|
117
|
+
export { LambderDdbOneShotSecretStore } from "./stores/LambderDdbOneShotSecretStore.js";
|
|
118
|
+
export type { LambderDdbOneShotSecretStoreOptions } from "./stores/LambderDdbOneShotSecretStore.js";
|
|
119
|
+
export { LambderMemoryOneShotSecretStore } from "./stores/LambderMemoryOneShotSecretStore.js";
|
|
109
120
|
export type { LambderIdempotencyStore, LambderIdempotencyBeginResult, LambderIdempotencyDoneRecord, } from "./shared/contracts/LambderIdempotencyStore.js";
|
|
110
121
|
export { LambderDdbIdempotencyStore } from "./stores/LambderDdbIdempotencyStore.js";
|
|
111
122
|
export type { LambderDdbIdempotencyStoreOptions } from "./stores/LambderDdbIdempotencyStore.js";
|
|
@@ -118,9 +129,11 @@ export type { LambderRateLimitKeyBuilder } from "./api/LambderApiRateLimits.js";
|
|
|
118
129
|
export type { LambderContextRateLimit, LambderContextRateLimitCheck, LambderRateLimitCheckResult, LambderChargeablePolicyNames, LambderChargeKeyArgs, LambderRateLimitKeyFn, LambderRateLimitPer, LambderRateLimitBudget, LambderRateLimitChargeAt, LambderApiRateLimitPolicyConfig, LambderApiRateLimitsConfig, LambderAllowedPolicyNames, LambderRateLimitOption, } from "./api/LambderApiRateLimits.js";
|
|
119
130
|
export type { LambderApiIdempotencyConfig } from "./api/LambderApiIdempotency.js";
|
|
120
131
|
export type { LambderGuardsOptionValue, LambderRateLimitOverride, LambderRateLimitOptionValue, LambderApiIdempotencyOption, } from "./shared/wire/LambderApiOptionValues.js";
|
|
132
|
+
export { apiGuardParam } from "./shared/wire/LambderApiOptionEntries.js";
|
|
133
|
+
export type { LambderApiOptionEntries, LambderApiOptionEntry, LambderRateLimitPolicyEntry, LambderGuardDeclarationEntry, LambderApisWithGuard, LambderApisGuardedBy, LambderApisWithMode, LambderGuardParamOf, } from "./shared/wire/LambderApiOptionEntries.js";
|
|
121
134
|
export { createLambderI18n } from "./shared/LambderI18n.js";
|
|
122
135
|
export type { LambderLanguageMeta, LambderI18nConfig, LambderI18nInstance, LambderI18nTranslator, LambderI18nExtractParams, LambderI18nDictionaryLoader, LambderI18nCodes, LambderI18nKeys, LambderI18nTranslatorFor, } from "./shared/LambderI18n.js";
|
|
123
|
-
export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiResponseConfig,
|
|
136
|
+
export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiResponseConfig, LambderContractEntry, LambderMergeContract, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractKeysWithGuard, LambderJsonOf, LambderJsonOutputOf, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractRateLimitNames, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
|
|
124
137
|
export type { LambderRenderContext, LambderSessionRenderContext, LambderHttpEvent, LambderHttpEventFormat } from "./core/LambderContext.js";
|
|
125
138
|
export type { LambderApiAnswerOutcome, LambderApiSuccessOutcome, LambderApiCallFailure, LambderApiValidationFailure, LambderApiEnvelopeFailure, LambderApiHttpAnswer, } from "./shared/wire/LambderApiOutcome.js";
|
|
126
139
|
export { resolveApiOutcome } from "./shared/wire/LambderApiOutcome.js";
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,11 @@ export { buildTransportEnvelope, LambderTransportFailure, isLambderTransportFail
|
|
|
9
9
|
export { lambderCookieJarTransport } from "./shared/transport/lambderCookieJarTransport.js";
|
|
10
10
|
export { LambderCookieJar, parseSetCookie } from "./shared/transport/LambderCookieJar.js";
|
|
11
11
|
export { LambderExpiringMap, LambderExpiringMapFullError } from "./shared/util/LambderExpiringMap.js";
|
|
12
|
+
// Waiting longer after each failure, once: what the upload runner and an app's own retrying code climb.
|
|
13
|
+
export { LambderBackoffTimer } from "./shared/util/LambderBackoffTimer.js";
|
|
14
|
+
// Signed claims tokens, and the keyed digest and random secret for the secrets an app stores.
|
|
15
|
+
export { LambderSignedClaims, keyedDigest, randomSecret } from "./shared/util/LambderSignedClaims.js";
|
|
16
|
+
export { constantTimeEquals } from "./shared/util/LambderTextDigest.js";
|
|
12
17
|
export { lambderHandlerTransport } from "./invoke/lambderHandlerTransport.js";
|
|
13
18
|
export { synthesizeLambdaHttpEvent, decodeLambdaHttpResult, localLambdaContext, LAMBDER_INVOKE_HEADER, LAMBDER_INVOKED_BY_HEADER, LAMBDER_INVOKE_PROTOCOL, } from "./invoke/LambderLambdaEvent.js";
|
|
14
19
|
// The API core: the request, answer, envelope and pipeline both the server and the mock runtime run
|
|
@@ -71,6 +76,11 @@ export { LambderMemoryCache } from "./stores/LambderMemoryCache.js";
|
|
|
71
76
|
export { RATE_LIMIT_WINDOWS } from "./shared/contracts/LambderRateLimiter.js";
|
|
72
77
|
export { LambderDdbRateLimiter } from "./stores/LambderDdbRateLimiter.js";
|
|
73
78
|
export { LambderMemoryRateLimiter } from "./stores/LambderMemoryRateLimiter.js";
|
|
79
|
+
// One-shot secrets: codes and tokens handed out once and taken back once, the
|
|
80
|
+
// store interface they live in, and the DynamoDB and in-memory stores
|
|
81
|
+
export { LambderOneShotSecrets } from "./secrets/LambderOneShotSecrets.js";
|
|
82
|
+
export { LambderDdbOneShotSecretStore } from "./stores/LambderDdbOneShotSecretStore.js";
|
|
83
|
+
export { LambderMemoryOneShotSecretStore } from "./stores/LambderMemoryOneShotSecretStore.js";
|
|
74
84
|
export { LambderDdbIdempotencyStore } from "./stores/LambderDdbIdempotencyStore.js";
|
|
75
85
|
export { LambderMemoryIdempotencyStore } from "./stores/LambderMemoryIdempotencyStore.js";
|
|
76
86
|
// Declarative per-API policies: guards
|
|
@@ -78,6 +88,9 @@ export { lambderGuard, lambderRateLimitKey } from "./core/LambderPolicyBuilders.
|
|
|
78
88
|
export { lambderGuardBuilder } from "./api/LambderApiGuards.js";
|
|
79
89
|
// Declarative per-API policies: rate limits
|
|
80
90
|
export { lambderRateLimitKeyBuilder, rateLimitRefusal, DEFAULT_RATE_LIMIT_REFUSAL } from "./api/LambderApiRateLimits.js";
|
|
91
|
+
// The declared options as plain data: what apiOptionEntries() reports and
|
|
92
|
+
// writeApiOptions writes, and the readers over the generated tables.
|
|
93
|
+
export { apiGuardParam } from "./shared/wire/LambderApiOptionEntries.js";
|
|
81
94
|
// Typed translations (standalone, isomorphic)
|
|
82
95
|
export { createLambderI18n } from "./shared/LambderI18n.js";
|
|
83
96
|
export { resolveApiOutcome } from "./shared/wire/LambderApiOutcome.js";
|
|
@@ -86,5 +99,5 @@ export { createContext, isV2HttpEvent } from "./core/LambderContext.js";
|
|
|
86
99
|
export { COMPRESSED_PAYLOAD_GZ_FIELD, COMPRESSED_PAYLOAD_BR_FIELD, COMPRESSED_PAYLOAD_BYTES_FIELD, DEFAULT_REQUEST_COMPRESSION_SETTINGS, DEFAULT_MAX_RESTORED_PAYLOAD_BYTES,
|
|
87
100
|
// The Brotli twin of the browser's compressPayloadGzip, and its defaults.
|
|
88
101
|
DEFAULT_INVOKE_REQUEST_COMPRESSION_SETTINGS, compressPayloadBrotli, } from "./shared/wire/LambderRequestPayload.js";
|
|
89
|
-
// Cookies (
|
|
102
|
+
// Cookies (ctx.setCookie / ctx.clearCookie build on these; exported for code holding a LambderResponse)
|
|
90
103
|
export { serializeCookie, serializeClearCookie, resolveCookieDomain } from "./shared/wire/LambderCookie.js";
|
|
@@ -378,10 +378,9 @@ export default class LambderInvokeCaller {
|
|
|
378
378
|
// The answer's Set-Cookie values, so a session the callee rotated or
|
|
379
379
|
// cleared is visible to whoever is carrying it.
|
|
380
380
|
const cookies = http.cookies;
|
|
381
|
-
// The declared output, by the callee's own typing:
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
// callee's contract to keep).
|
|
381
|
+
// The declared output, by the callee's own typing: a handler returns
|
|
382
|
+
// its output, so a success payload is null only where the output
|
|
383
|
+
// allows null.
|
|
385
384
|
if (outcome.ok)
|
|
386
385
|
return { ok: true, payload: (outcome.payload ?? null), response: outcome.response, logList, cookies };
|
|
387
386
|
const shared = { status: outcome.status, retryAfterSeconds: outcome.retryAfterSeconds, logList, cookies };
|
|
@@ -10,6 +10,7 @@ import { LambderMemoryIdempotencyStore } from "../stores/LambderMemoryIdempotenc
|
|
|
10
10
|
import { LambderMemorySessionStore } from "../stores/LambderMemorySessionStore.js";
|
|
11
11
|
import LambderSessionManager, { type LambderCreatedSession } from "../session/LambderSessionManager.js";
|
|
12
12
|
import type { LambderMockAppOptions, LambderMockIdempotencyOptions, LambderMockTransport, LambderMockTransportOptions } from "./LambderMockCreateOptions.js";
|
|
13
|
+
import type { LambderApiOptionEntry, LambderGuardDeclarationEntry } from "../shared/wire/LambderApiOptionEntries.js";
|
|
13
14
|
import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, LambderMockEntryInput, LambderMockFailure, LambderMockFailureReason, LambderMockHandler, LambderMockLatency, LambderMockListener, LambderMockPublicNames, LambderMockRateLimitPolicies, LambderMockRegistryCheck, LambderMockRestEntry, LambderMockSessionCallContext, LambderMockSessionNames, LambderMockSlice, LambderMockOverride } from "./LambderMockTypes.js";
|
|
14
15
|
/**
|
|
15
16
|
* The mock runtime: the API core (LambderApiPipeline, the same class the
|
|
@@ -23,9 +24,10 @@ import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, L
|
|
|
23
24
|
*
|
|
24
25
|
* Create one with initLambderMock<Contract, SessionData>().create(...),
|
|
25
26
|
* which fixes the contract and session types first so everything else is
|
|
26
|
-
* inferred from the options.
|
|
27
|
+
* inferred from the options. `TDerived` is true for a mock created with the
|
|
28
|
+
* generated `apiOptions` table, whose entries are their handlers alone.
|
|
27
29
|
*/
|
|
28
|
-
export declare class LambderMockApp<C extends LambderApiContractShape, S = any, G extends Record<string, LambderApiGuard<any, any, any>> = {}> {
|
|
30
|
+
export declare class LambderMockApp<C extends LambderApiContractShape, S = any, G extends Record<string, LambderApiGuard<any, any, any>> = {}, TDerived extends boolean = false> {
|
|
29
31
|
readonly apiVersion: string | null;
|
|
30
32
|
/** The memory stores, for assertions and reset; null for a subsystem that is off or backed by a store of yours. */
|
|
31
33
|
readonly sessionStore: LambderMemorySessionStore<S> | null;
|
|
@@ -61,9 +63,11 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
61
63
|
private readonly recorder;
|
|
62
64
|
/** Registered entries and the overrides over them (see LambderMockEntryRegistry). */
|
|
63
65
|
private readonly registry;
|
|
66
|
+
/** The server's declared options per API, when create() was given the generated table; the entries' declarations come from here. */
|
|
67
|
+
private readonly apiOptions;
|
|
64
68
|
/** The jars the runtime owns and what it planted in document.cookie (see LambderMockBrowserCookies). */
|
|
65
69
|
private readonly browserCookies;
|
|
66
|
-
constructor(options: LambderMockAppOptions<C, S, G>);
|
|
70
|
+
constructor(options: LambderMockAppOptions<C, S, G, LambderMockRateLimitPolicies<S>, boolean | LambderMockIdempotencyOptions<S>, {}, Record<string, LambderApiOptionEntry> | undefined>);
|
|
67
71
|
/**
|
|
68
72
|
* The registration-time checks every entry goes through, mocked or not:
|
|
69
73
|
* the ones the server runs on a definition, and the mock's own "a session
|
|
@@ -75,11 +79,21 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
75
79
|
* option, for a mistake fixed by one option at create().
|
|
76
80
|
*/
|
|
77
81
|
private assertEntryRegistration;
|
|
82
|
+
/**
|
|
83
|
+
* The table's entry for an endpoint, when create() was given one: null
|
|
84
|
+
* without a table, and a throw for a name the table does not hold or an
|
|
85
|
+
* entry registered under the other mode. The compiler already refuses
|
|
86
|
+
* both against the contract; this is where a stale table meets a caller
|
|
87
|
+
* the compiler did not see.
|
|
88
|
+
*/
|
|
89
|
+
private declaredOptionsOf;
|
|
90
|
+
/** The mode the apiOptions table gives a name, or null without a table or for a name it does not hold. */
|
|
91
|
+
private declaredModeOf;
|
|
78
92
|
private buildEntry;
|
|
79
93
|
/** A mock for a public endpoint: a handler, or the handler with the endpoint's declarations restated. */
|
|
80
|
-
publicApi<K extends LambderMockPublicNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema>): LambderMockEntry<C, K>;
|
|
94
|
+
publicApi<K extends LambderMockPublicNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived>): LambderMockEntry<C, K>;
|
|
81
95
|
/** A mock for a session endpoint: the pipeline fetches the session before the handler runs, and refuses without one. */
|
|
82
|
-
sessionApi<K extends LambderMockSessionNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema>): LambderMockEntry<C, K>;
|
|
96
|
+
sessionApi<K extends LambderMockSessionNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived>): LambderMockEntry<C, K>;
|
|
83
97
|
/**
|
|
84
98
|
* A public endpoint deliberately left without a mock; a call answers the
|
|
85
99
|
* notMocked refusal carrying the reason.
|
|
@@ -111,13 +125,15 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
111
125
|
* still refused, and an entry registered later (registerPartial, or a
|
|
112
126
|
* second register) takes its endpoint back from the rest.
|
|
113
127
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
128
|
+
* The mode of an unregistered name comes from the apiOptions table, when
|
|
129
|
+
* create() was given one, so an unmocked session endpoint still reads the
|
|
130
|
+
* session and a signed-out call answers sessionExpired as on the server.
|
|
131
|
+
* Without the table the mode is not knowable at runtime (the contract is
|
|
132
|
+
* a type), and a call it answers is processed as public: the protocol's
|
|
133
|
+
* pre-pass still runs, so a stale client still hears versionExpired, but
|
|
134
|
+
* a signed-out call to an unmocked session endpoint answers "not mocked"
|
|
135
|
+
* where the server answers sessionExpired. Declare an endpoint whose
|
|
136
|
+
* signed-out path a test cares about with sessionNotMocked there.
|
|
121
137
|
*/
|
|
122
138
|
restNotMocked(reason: string): LambderMockRestEntry;
|
|
123
139
|
private buildNotMockedEntry;
|
|
@@ -165,10 +181,11 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
165
181
|
/**
|
|
166
182
|
* The entry that answers a name nothing registered, when register() was
|
|
167
183
|
* given a rest entry: the notMocked refusal carrying its reason, run
|
|
168
|
-
* through the pipeline
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
184
|
+
* through the pipeline under the mode the apiOptions table gives the
|
|
185
|
+
* name, and as a public endpoint where there is no table to say (the
|
|
186
|
+
* mode of an unregistered name cannot otherwise be recovered at runtime).
|
|
187
|
+
* Everything before dispatch still runs (the signature gate, the payload
|
|
188
|
+
* restore, and for a session endpoint the session read).
|
|
172
189
|
*/
|
|
173
190
|
private restNotMockedEntry;
|
|
174
191
|
/** The next call to the endpoint fails this way; several calls queue in order. */
|
|
@@ -332,5 +349,5 @@ export declare const initLambderMock: <C extends LambderApiContractShape, S = an
|
|
|
332
349
|
* dropped. `I` exists for the same reason `P` does, and
|
|
333
350
|
* LambderMockSurplusKeys puts the error back on the key.
|
|
334
351
|
*/
|
|
335
|
-
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S
|
|
352
|
+
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true>;
|
|
336
353
|
};
|