lambder 2.0.16 → 3.0.0

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 (67) hide show
  1. package/Readme.md +162 -41
  2. package/dist/Lambder.d.ts +154 -46
  3. package/dist/Lambder.js +312 -166
  4. package/dist/LambderCaller.js +6 -3
  5. package/dist/LambderContext.d.ts +20 -9
  6. package/dist/LambderContext.js +57 -17
  7. package/dist/LambderCors.d.ts +12 -0
  8. package/dist/LambderCors.js +30 -0
  9. package/dist/LambderHtml.d.ts +33 -0
  10. package/dist/LambderHtml.js +62 -0
  11. package/dist/LambderMSW.d.ts +16 -1
  12. package/dist/LambderMSW.js +5 -9
  13. package/dist/LambderPublicFiles.d.ts +47 -0
  14. package/dist/LambderPublicFiles.js +108 -0
  15. package/dist/LambderResolver.d.ts +30 -31
  16. package/dist/LambderResolver.js +29 -43
  17. package/dist/LambderResponse.d.ts +71 -0
  18. package/dist/LambderResponse.js +196 -0
  19. package/dist/LambderResponseBuilder.d.ts +58 -33
  20. package/dist/LambderResponseBuilder.js +114 -167
  21. package/dist/LambderRouting.d.ts +23 -0
  22. package/dist/LambderRouting.js +67 -0
  23. package/dist/LambderSessionController.d.ts +13 -1
  24. package/dist/LambderSessionController.js +33 -10
  25. package/dist/LambderSessionManager.d.ts +3 -1
  26. package/dist/LambderSessionManager.js +15 -6
  27. package/dist/LambderTemplatingEngine.d.ts +87 -0
  28. package/dist/LambderTemplatingEngine.js +156 -0
  29. package/dist/index.d.ts +14 -2
  30. package/dist/index.js +10 -1
  31. package/dist/node-polyfills.d.ts +4 -2
  32. package/dist/node-polyfills.js +28 -0
  33. package/package.json +7 -5
  34. package/.eslintrc.cjs +0 -26
  35. package/.vscode/settings.json +0 -26
  36. package/deploy +0 -22
  37. package/dist/LambderUtils.d.ts +0 -10
  38. package/dist/LambderUtils.js +0 -70
  39. package/docs/DYNAMODB_SETUP.md +0 -96
  40. package/docs/LAMBDER_MSW.md +0 -409
  41. package/docs/TYPE_SAFE_QUICK_START.md +0 -77
  42. package/examples/msw-testing-example.ts +0 -280
  43. package/examples/secure-session-example.ts +0 -207
  44. package/examples/zod-chained-api-example.ts +0 -63
  45. package/src/Lambder.ts +0 -430
  46. package/src/LambderApiContract.ts +0 -20
  47. package/src/LambderCaller.ts +0 -238
  48. package/src/LambderContext.ts +0 -78
  49. package/src/LambderMSW.ts +0 -180
  50. package/src/LambderResolver.ts +0 -101
  51. package/src/LambderResponseBuilder.ts +0 -332
  52. package/src/LambderSessionController.ts +0 -114
  53. package/src/LambderSessionManager.ts +0 -217
  54. package/src/LambderUtils.ts +0 -75
  55. package/src/index.ts +0 -17
  56. package/src/node-polyfills.ts +0 -27
  57. package/tests/error-handling.test.ts +0 -585
  58. package/tests/file-serving.test.ts +0 -194
  59. package/tests/fixtures/public/index.html +0 -1
  60. package/tests/fixtures/public/main.css +0 -1
  61. package/tests/hooks.test.ts +0 -561
  62. package/tests/output-type-runtime.test.ts +0 -381
  63. package/tests/redirect.test.ts +0 -88
  64. package/tests/routes.test.ts +0 -543
  65. package/tests/session.test.ts +0 -1083
  66. package/tests/use-plugin.test.ts +0 -460
  67. package/tsconfig.json +0 -24
@@ -1,52 +1,38 @@
1
1
  import LambderResponseBuilder from "./LambderResponseBuilder.js";
2
+ /**
3
+ * Response builder passed to route/api handlers and hooks.
4
+ *
5
+ * `res.die.*` builds the response and THROWS it, immediately halting the
6
+ * request at any call depth (handlers, hooks, nested service functions).
7
+ * Lambder's render pipeline catches thrown LambderResponse instances and uses
8
+ * them as the response. Plain `throw res.html(...)` works the same way.
9
+ */
2
10
  export default class LambderResolver extends LambderResponseBuilder {
3
- resolve;
4
- reject;
5
11
  die;
6
- constructor({ isCorsEnabled, publicPath, apiVersion, lambderUtils, ctx, resolve, reject }) {
7
- super({ isCorsEnabled, publicPath, apiVersion, lambderUtils, ctx, });
8
- this.resolve = resolve;
9
- this.reject = reject;
12
+ constructor(...args) {
13
+ super(...args);
10
14
  this.die = {
11
- raw: this.autoResolve(this.raw),
12
- json: this.autoResolve(this.json),
13
- xml: this.autoResolve(this.xml),
14
- html: this.autoResolve(this.html),
15
- redirect: this.autoResolve(this.redirect),
16
- status404: this.autoResolve(this.status404),
17
- cors: this.autoResolve(this.cors),
18
- fileBase64: this.autoResolve(this.fileBase64),
19
- file: this.autoResolvePromise(this.file),
20
- ejsFile: this.autoResolvePromise(this.ejsFile),
21
- ejsTemplate: this.autoResolvePromise(this.ejsTemplate),
22
- api: this.autoResolve(this.api),
15
+ raw: (...a) => { throw this.raw(...a); },
16
+ json: (...a) => { throw this.json(...a); },
17
+ text: (...a) => { throw this.text(...a); },
18
+ xml: (...a) => { throw this.xml(...a); },
19
+ html: (...a) => { throw this.html(...a); },
20
+ status: (...a) => { throw this.status(...a); },
21
+ status404: (...a) => { throw this.status404(...a); },
22
+ redirect: (...a) => { throw this.redirect(...a); },
23
+ versionExpired: (...a) => { throw this.versionExpired(...a); },
24
+ fileBase64: (...a) => { throw this.fileBase64(...a); },
25
+ api: (...a) => { throw this.api(...a); },
26
+ apiBinary: (...a) => { throw this.apiBinary(...a); },
27
+ file: async (...a) => { throw await this.file(...a); },
28
+ templateFile: async (...a) => { throw await this.templateFile(...a); },
23
29
  };
24
30
  }
25
- // Override api method with proper typing
26
- api(payload, config, headers) {
27
- return super.api(payload, config, headers);
31
+ // Override api method with proper output typing
32
+ api(payload, config, options) {
33
+ return super.api(payload, config, options);
28
34
  }
29
- autoResolve(method) {
30
- return (...args) => {
31
- const result = method.apply(this, args);
32
- this.resolve(result);
33
- return result;
34
- };
35
- }
36
- autoResolvePromise(method) {
37
- return (...args) => {
38
- return new Promise((resolve, reject) => {
39
- method.apply(this, args)
40
- .then(result => {
41
- this.resolve(result);
42
- resolve(result);
43
- })
44
- .catch(err => {
45
- this.reject(err);
46
- reject(err);
47
- });
48
- });
49
- };
35
+ apiBinary(payload, config, options) {
36
+ return super.apiBinary(payload, config, options);
50
37
  }
51
38
  }
52
- ;
@@ -0,0 +1,71 @@
1
+ import type { LambderRenderContext } from "./LambderContext.js";
2
+ export type HttpStatusCode = 100 | 101 | 200 | 201 | 202 | 203 | 204 | 206 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 408 | 409 | 410 | 412 | 413 | 415 | 416 | 418 | 422 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504;
3
+ export type LambderHeadersInput = Record<string, string | string[]>;
4
+ /**
5
+ * Final Lambda response: v1 (REST API) uses multiValueHeaders, v2 (HTTP API /
6
+ * Function URLs) uses headers + cookies. Assignable to both official aws-lambda
7
+ * result types (compile-time asserted below), so exporting getHandler() as an
8
+ * APIGatewayProxyHandler / APIGatewayProxyHandlerV2 is type-safe.
9
+ */
10
+ export type LambderHttpResponse = {
11
+ statusCode: number;
12
+ body: string;
13
+ isBase64Encoded: boolean;
14
+ /** API Gateway REST API (payload v1). */
15
+ multiValueHeaders?: Record<string, string[]>;
16
+ /** API Gateway HTTP API / Lambda Function URLs (payload v2). */
17
+ headers?: Record<string, string>;
18
+ cookies?: string[];
19
+ };
20
+ export type LambderHttpEventFormat = "v1" | "v2";
21
+ export declare const normalizeHeaders: (headers?: LambderHeadersInput) => Record<string, string[]>;
22
+ export type LambderResponseInit = {
23
+ statusCode: HttpStatusCode;
24
+ headers?: LambderHeadersInput;
25
+ body?: string | Buffer | null;
26
+ /** True when body is already a base64-encoded string (pre-encoded binary content). */
27
+ isBodyBase64?: boolean;
28
+ /** "auto": gzip when enabled + compressible + large enough. true: force (if client accepts). false: never. */
29
+ compress?: boolean | "auto";
30
+ /** "auto": ETag on GET/HEAD 200 when globally enabled. true: force. false: never. */
31
+ etag?: boolean | "auto";
32
+ };
33
+ /**
34
+ * Intermediate response object returned by all response builder methods and by
35
+ * route/api handlers. Bodies stay uncompressed and un-encoded so hooks can
36
+ * still transform them; a single finalize step at the end of render() applies
37
+ * compression, ETag/304 handling and base64 encoding.
38
+ *
39
+ * Throwing a LambderResponse anywhere inside a handler or hook short-circuits
40
+ * the request: the thrown response becomes the response.
41
+ */
42
+ export declare class LambderResponse {
43
+ statusCode: HttpStatusCode;
44
+ headers: Record<string, string[]>;
45
+ body: string | Buffer | null;
46
+ isBodyBase64: boolean;
47
+ compress: boolean | "auto";
48
+ etag: boolean | "auto";
49
+ constructor(init: LambderResponseInit);
50
+ getHeader(key: string): string[] | undefined;
51
+ setHeader(key: string, value: string | string[]): this;
52
+ addHeader(key: string, value: string): this;
53
+ }
54
+ export declare const isCompressibleContentType: (contentType: string | undefined) => boolean;
55
+ export declare const acceptsEncoding: (acceptEncoding: string | undefined | null, encoding: string) => boolean;
56
+ export type LambderFinalizeOptions = {
57
+ compression: false | {
58
+ minBytes: number;
59
+ };
60
+ etag: boolean;
61
+ /** Guard against Lambda's ~6MB response cap with a clear error. */
62
+ maxResponseBytes: number;
63
+ };
64
+ export declare const DEFAULT_FINALIZE_OPTIONS: LambderFinalizeOptions;
65
+ /**
66
+ * Convert an intermediate LambderResponse into the final Lambda response:
67
+ * gzip negotiation (Accept-Encoding), ETag + If-None-Match 304, base64
68
+ * encoding, HEAD body stripping, and Lambda payload size guard. Emits the v1
69
+ * (REST API) or v2 (HTTP API / Function URL) response shape.
70
+ */
71
+ export declare const finalizeResponse: (ctx: Pick<LambderRenderContext, "method" | "headers"> | null, response: LambderResponse, options: LambderFinalizeOptions, format?: LambderHttpEventFormat) => Promise<LambderHttpResponse>;
@@ -0,0 +1,196 @@
1
+ import { getZlib, getCrypto } from "./node-polyfills.js";
2
+ export const normalizeHeaders = (headers) => Object.fromEntries(Object.entries(headers ?? {}).map(([k, v]) => [k, Array.isArray(v) ? [...v] : [v]]));
3
+ /**
4
+ * Intermediate response object returned by all response builder methods and by
5
+ * route/api handlers. Bodies stay uncompressed and un-encoded so hooks can
6
+ * still transform them; a single finalize step at the end of render() applies
7
+ * compression, ETag/304 handling and base64 encoding.
8
+ *
9
+ * Throwing a LambderResponse anywhere inside a handler or hook short-circuits
10
+ * the request: the thrown response becomes the response.
11
+ */
12
+ export class LambderResponse {
13
+ statusCode;
14
+ headers;
15
+ body;
16
+ isBodyBase64;
17
+ compress;
18
+ etag;
19
+ constructor(init) {
20
+ this.statusCode = init.statusCode;
21
+ this.headers = normalizeHeaders(init.headers);
22
+ this.body = init.body ?? null;
23
+ this.isBodyBase64 = init.isBodyBase64 ?? false;
24
+ this.compress = init.compress ?? "auto";
25
+ this.etag = init.etag ?? "auto";
26
+ }
27
+ getHeader(key) {
28
+ const lower = key.toLowerCase();
29
+ for (const [k, v] of Object.entries(this.headers)) {
30
+ if (k.toLowerCase() === lower)
31
+ return v;
32
+ }
33
+ return undefined;
34
+ }
35
+ setHeader(key, value) {
36
+ const lower = key.toLowerCase();
37
+ for (const k of Object.keys(this.headers)) {
38
+ if (k.toLowerCase() === lower)
39
+ delete this.headers[k];
40
+ }
41
+ this.headers[key] = Array.isArray(value) ? [...value] : [value];
42
+ return this;
43
+ }
44
+ addHeader(key, value) {
45
+ const lower = key.toLowerCase();
46
+ const existingKey = Object.keys(this.headers).find((k) => k.toLowerCase() === lower);
47
+ if (existingKey) {
48
+ this.headers[existingKey].push(value);
49
+ }
50
+ else {
51
+ this.headers[key] = [value];
52
+ }
53
+ return this;
54
+ }
55
+ }
56
+ export const isCompressibleContentType = (contentType) => {
57
+ if (!contentType)
58
+ return false;
59
+ const mime = (contentType.split(";")[0] ?? "").trim().toLowerCase();
60
+ if (mime.startsWith("text/"))
61
+ return true;
62
+ if (mime.endsWith("+json") || mime.endsWith("+xml"))
63
+ return true;
64
+ return [
65
+ "application/json",
66
+ "application/javascript",
67
+ "application/x-javascript",
68
+ "application/xml",
69
+ "application/wasm",
70
+ "image/svg+xml",
71
+ "application/lambder-json-stream",
72
+ ].includes(mime);
73
+ };
74
+ export const acceptsEncoding = (acceptEncoding, encoding) => {
75
+ if (!acceptEncoding)
76
+ return false;
77
+ return acceptEncoding.split(",").some((part) => {
78
+ const [token, ...params] = part.trim().split(";");
79
+ const name = (token ?? "").trim().toLowerCase();
80
+ if (name !== encoding && name !== "*")
81
+ return false;
82
+ const q = params.map((p) => p.trim()).find((p) => p.startsWith("q="));
83
+ return !q || Number(q.slice(2)) > 0;
84
+ });
85
+ };
86
+ export const DEFAULT_FINALIZE_OPTIONS = {
87
+ compression: { minBytes: 860 },
88
+ etag: true,
89
+ maxResponseBytes: 5_500_000,
90
+ };
91
+ const getRequestHeader = (ctx, name) => {
92
+ if (!ctx?.headers)
93
+ return undefined;
94
+ const lower = name.toLowerCase();
95
+ for (const [k, v] of Object.entries(ctx.headers)) {
96
+ if (k.toLowerCase() === lower)
97
+ return v ?? undefined;
98
+ }
99
+ return undefined;
100
+ };
101
+ /** Emit the format-specific Lambda response shape. */
102
+ const emitResponse = (format, statusCode, headers, body, isBase64Encoded) => {
103
+ if (format === "v2") {
104
+ // Payload v2 has no multiValueHeaders: multi-values are comma-joined,
105
+ // except Set-Cookie which uses the dedicated cookies array.
106
+ const singleHeaders = {};
107
+ const cookies = [];
108
+ for (const [key, values] of Object.entries(headers)) {
109
+ if (key.toLowerCase() === "set-cookie")
110
+ cookies.push(...values);
111
+ else
112
+ singleHeaders[key] = values.join(", ");
113
+ }
114
+ return { statusCode, headers: singleHeaders, cookies, body, isBase64Encoded };
115
+ }
116
+ return { statusCode, multiValueHeaders: headers, body, isBase64Encoded };
117
+ };
118
+ /**
119
+ * Convert an intermediate LambderResponse into the final Lambda response:
120
+ * gzip negotiation (Accept-Encoding), ETag + If-None-Match 304, base64
121
+ * encoding, HEAD body stripping, and Lambda payload size guard. Emits the v1
122
+ * (REST API) or v2 (HTTP API / Function URL) response shape.
123
+ */
124
+ export const finalizeResponse = async (ctx, response, options, format = "v1") => {
125
+ const method = (ctx?.method ?? "GET").toUpperCase();
126
+ if (response.body === null) {
127
+ return emitResponse(format, response.statusCode, response.headers, "", false);
128
+ }
129
+ let outBody;
130
+ let isBase64 = false;
131
+ if (response.isBodyBase64) {
132
+ // Pre-encoded binary content: passes through untouched (no compression).
133
+ outBody = String(response.body);
134
+ isBase64 = true;
135
+ }
136
+ else {
137
+ let bodyBuffer = Buffer.isBuffer(response.body)
138
+ ? response.body
139
+ : Buffer.from(String(response.body), "utf8");
140
+ const contentType = response.getHeader("Content-Type")?.[0];
141
+ const alreadyEncoded = !!response.getHeader("Content-Encoding");
142
+ const eligibleForCompression = !alreadyEncoded && (response.compress === true ||
143
+ (response.compress === "auto" &&
144
+ options.compression !== false &&
145
+ bodyBuffer.length >= options.compression.minBytes &&
146
+ isCompressibleContentType(contentType)));
147
+ if (eligibleForCompression) {
148
+ // Vary even when this client didn't accept an encoding, to keep caches correct.
149
+ response.addHeader("Vary", "Accept-Encoding");
150
+ if (acceptsEncoding(getRequestHeader(ctx, "accept-encoding"), "gzip")) {
151
+ const zlib = await getZlib();
152
+ if (zlib) {
153
+ bodyBuffer = zlib.gzipSync(bodyBuffer);
154
+ response.setHeader("Content-Encoding", "gzip");
155
+ }
156
+ }
157
+ }
158
+ if (Buffer.isBuffer(response.body) || response.getHeader("Content-Encoding")) {
159
+ outBody = bodyBuffer.toString("base64");
160
+ isBase64 = true;
161
+ }
162
+ else {
163
+ outBody = bodyBuffer.toString("utf8");
164
+ }
165
+ }
166
+ const etagEnabled = response.etag === true || (response.etag === "auto" &&
167
+ options.etag &&
168
+ response.statusCode === 200 &&
169
+ (method === "GET" || method === "HEAD"));
170
+ if (etagEnabled) {
171
+ const crypto = await getCrypto();
172
+ if (crypto) {
173
+ const etagValue = `"${crypto.createHash("sha256").update(outBody).digest("hex").slice(0, 32)}"`;
174
+ response.setHeader("ETag", etagValue);
175
+ const ifNoneMatch = getRequestHeader(ctx, "if-none-match");
176
+ if (ifNoneMatch && ifNoneMatch.split(",").map((s) => s.trim()).includes(etagValue)) {
177
+ const preservedHeaders = {};
178
+ for (const key of ["ETag", "Cache-Control", "Vary", "Expires", "Last-Modified"]) {
179
+ const value = response.getHeader(key);
180
+ if (value)
181
+ preservedHeaders[key] = value;
182
+ }
183
+ return emitResponse(format, 304, preservedHeaders, "", false);
184
+ }
185
+ }
186
+ }
187
+ if (method === "HEAD") {
188
+ return emitResponse(format, response.statusCode, response.headers, "", false);
189
+ }
190
+ if (outBody.length > options.maxResponseBytes) {
191
+ throw new Error(`Lambder: final response body is ${outBody.length} bytes which exceeds the configured ` +
192
+ `maxResponseBytes (${options.maxResponseBytes}). Lambda caps proxy responses at ~6MB. ` +
193
+ `Consider pagination or enabling compression.`);
194
+ }
195
+ return emitResponse(format, response.statusCode, response.headers, outBody, isBase64);
196
+ };
@@ -1,11 +1,16 @@
1
- import LambderUtils from "./LambderUtils.js";
2
- import { LambderRenderContext } from "./LambderContext.js";
3
- export type HttpStatusCode = 200 | 201 | 202 | 204 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 400 | 401 | 403 | 404 | 405 | 409 | 410 | 413 | 415 | 422 | 429 | 500 | 501 | 502 | 503 | 504;
4
- export type LambderResolverResponse = {
5
- statusCode: HttpStatusCode;
6
- multiValueHeaders?: Record<string, string[]>;
7
- body: string | null;
8
- isBase64Encoded?: boolean;
1
+ import type { LambderRenderContext } from "./LambderContext.js";
2
+ import { LambderResponse, type HttpStatusCode, type LambderHeadersInput } from "./LambderResponse.js";
3
+ import { LambderSafeHtml } from "./LambderHtml.js";
4
+ import { type LambderTemplateData } from "./LambderTemplatingEngine.js";
5
+ export type LambderResponseOptions = {
6
+ statusCode?: HttpStatusCode;
7
+ headers?: LambderHeadersInput;
8
+ /** Shorthand for the Cache-Control header. */
9
+ cacheControl?: string;
10
+ /** "auto" (default): gzip when compressible/large enough. true: force. false: never. */
11
+ compress?: boolean | "auto";
12
+ /** "auto" (default): ETag on GET/HEAD 200 when globally enabled. true: force. false: never. */
13
+ etag?: boolean | "auto";
9
14
  };
10
15
  export type LambderApiResponseConfig = {
11
16
  versionExpired?: boolean;
@@ -16,38 +21,58 @@ export type LambderApiResponseConfig = {
16
21
  logList?: any[];
17
22
  };
18
23
  export type LambderApiResponse<T> = LambderApiResponseConfig & {
24
+ apiVersion?: string | null;
19
25
  payload?: T | null;
20
26
  };
27
+ export type LambderRawResponseInit = {
28
+ statusCode: HttpStatusCode;
29
+ headers?: LambderHeadersInput;
30
+ /** Legacy alias for headers (API Gateway naming). */
31
+ multiValueHeaders?: Record<string, string[]>;
32
+ body: string | Buffer | null;
33
+ /** True when body is already a base64-encoded string. */
34
+ isBase64Encoded?: boolean;
35
+ compress?: boolean | "auto";
36
+ etag?: boolean | "auto";
37
+ };
21
38
  export default class LambderResponseBuilder<TResponse = any> {
22
- private isCorsEnabled;
23
- private publicPath;
24
- private apiVersion;
25
- private lambderUtils;
26
- private ctx?;
27
- constructor({ isCorsEnabled, publicPath, apiVersion, lambderUtils, ctx }: {
28
- isCorsEnabled: boolean;
39
+ protected publicPath: string;
40
+ protected apiVersion: string | null;
41
+ protected ctx?: LambderRenderContext;
42
+ constructor({ publicPath, apiVersion, ctx }: {
29
43
  publicPath: string;
30
44
  apiVersion?: string | null;
31
- lambderUtils: LambderUtils;
32
- ctx?: LambderRenderContext<any>;
45
+ ctx?: LambderRenderContext;
33
46
  });
34
- private readPublicFileSync;
35
- private checkPublicFileExist;
47
+ private buildResponse;
48
+ private resolvePublicFilePath;
36
49
  addHeader(key: string, value: string): void;
37
50
  setHeader(key: string, value: string | string[]): void;
38
51
  logToApiResponse(input: any): void;
39
- raw(param: LambderResolverResponse): LambderResolverResponse;
40
- json(data: Record<string, any>, headers?: Record<string, string | string[]>): LambderResolverResponse;
41
- xml(data: string): LambderResolverResponse;
42
- html(data: string, headers?: Record<string, string | string[]>): LambderResolverResponse;
43
- redirect(url: string, statusCode?: HttpStatusCode, headers?: Record<string, string | string[]>): LambderResolverResponse;
44
- status404(data: string, headers?: Record<string, string | string[]>): LambderResolverResponse;
45
- versionExpired(headers?: Record<string, string | string[]>): LambderResolverResponse;
46
- cors(): LambderResolverResponse;
47
- fileBase64(fileBase64: string, mimeType: string, headers?: Record<string, string | string[]>): LambderResolverResponse;
48
- file(filePath: string, headers?: Record<string, string | string[]>, fallbackFilePath?: string): Promise<LambderResolverResponse>;
49
- ejsTemplate(template: string, pageData: Record<string, any>, headers?: Record<string, string | string[]>): Promise<LambderResolverResponse>;
50
- ejsFile(filePath: string, pageData: Record<string, any>, headers?: Record<string, string | string[]>): Promise<LambderResolverResponse>;
51
- api(payload: TResponse | null, { versionExpired, sessionExpired, notAuthorized, message, errorMessage, logList, }?: LambderApiResponseConfig, headers?: Record<string, string | string[]>): LambderResolverResponse;
52
- apiBinary<T = any>(payload: T | null, { versionExpired, sessionExpired, notAuthorized, message, errorMessage, logList, }?: LambderApiResponseConfig, headers?: Record<string, string | string[]>): LambderResolverResponse;
52
+ raw(init: LambderRawResponseInit): LambderResponse;
53
+ json(data: Record<string, any>, options?: LambderResponseOptions): LambderResponse;
54
+ text(data: string, options?: LambderResponseOptions): LambderResponse;
55
+ xml(data: string | LambderSafeHtml, options?: LambderResponseOptions): LambderResponse;
56
+ html(data: string | LambderSafeHtml, options?: LambderResponseOptions): LambderResponse;
57
+ status(statusCode: HttpStatusCode, body?: string, options?: LambderResponseOptions): LambderResponse;
58
+ status404(data: string, options?: LambderResponseOptions): LambderResponse;
59
+ redirect(url: string, statusCode?: HttpStatusCode, options?: LambderResponseOptions): LambderResponse;
60
+ versionExpired(options?: LambderResponseOptions): LambderResponse;
61
+ fileBase64(fileBase64: string, mimeType: string, options?: LambderResponseOptions): LambderResponse;
62
+ file(filePath: string, options?: LambderResponseOptions & {
63
+ fallback?: string;
64
+ }): Promise<LambderResponse>;
65
+ /**
66
+ * Render an HTML file under publicPath through LambderTemplatingEngine
67
+ * (comment-based slots/conditionals) and return it as an HTML response.
68
+ * The compiled template is cached across warm invocations; a missing file
69
+ * throws (it is a server-side configuration error, not a client 404).
70
+ * Set htmlVirtualSlots to expose "title"/"head" slots on marker-less files.
71
+ */
72
+ templateFile(filePath: string, data?: LambderTemplateData, options?: LambderResponseOptions & {
73
+ htmlVirtualSlots?: boolean;
74
+ }): Promise<LambderResponse>;
75
+ api(payload: TResponse | null, { versionExpired, sessionExpired, notAuthorized, message, errorMessage, logList, }?: LambderApiResponseConfig, options?: LambderResponseOptions): LambderResponse;
76
+ /** Same as api() but forces gzip compression of the response body. */
77
+ apiBinary(payload: TResponse | null, config?: LambderApiResponseConfig, options?: LambderResponseOptions): LambderResponse;
53
78
  }