lambder 5.0.0 → 5.1.3
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/README.md +3 -2
- package/dist/core/Lambder.d.ts +2 -2
- package/dist/core/LambderFiles.d.ts +10 -3
- package/dist/core/LambderFiles.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/policies/LambderApiGuards.d.ts +8 -8
- package/dist/policies/LambderApiRateLimits.d.ts +3 -3
- package/dist/stores/LambderHttpFileSource.d.ts +31 -0
- package/dist/stores/LambderHttpFileSource.js +46 -0
- package/dist/stores/LambderS3FileSource.d.ts +1 -1
- package/dist/stores/LambderS3FileSource.js +2 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -53,8 +53,9 @@ const company = await caller.api("getCompany", { slug: "acme" });
|
|
|
53
53
|
cookies, and a guard against Lambda's response size cap.
|
|
54
54
|
- **Hooks and actions.** Lifecycle hooks, plus `addAction()` for the non-HTTP
|
|
55
55
|
invocations (EventBridge, SQS, custom events) the same function receives.
|
|
56
|
-
- **Frontend hosting.** Serve a build from a folder, S3
|
|
57
|
-
shell rendered through a build-pipeline-safe template
|
|
56
|
+
- **Frontend hosting.** Serve a build from a folder, S3, R2 or any HTTP
|
|
57
|
+
origin, with an app shell rendered through a build-pipeline-safe template
|
|
58
|
+
engine.
|
|
58
59
|
- **Runs anywhere Lambda does.** API Gateway REST APIs (payload v1), HTTP APIs
|
|
59
60
|
(payload v2) and Lambda Function URLs; the payload format is detected per
|
|
60
61
|
event.
|
package/dist/core/Lambder.d.ts
CHANGED
|
@@ -297,7 +297,7 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
297
297
|
addSessionRoute<TPath extends Path>(condition: TPath, actionFn: (ctx: LambderSessionRenderContext<any, TSessionData, PathParamsOf<TPath>>, resolver: LambderResolver) => MaybePromise<LambderResponse>): this;
|
|
298
298
|
addSessionRoute(condition: RegExp | ConditionFunction | LambderRouteMatcher, actionFn: SessionActionFunction<TSessionData>): this;
|
|
299
299
|
use<_TNewContract extends Record<string, any>>(plugin: (lambder: Lambder<TSessionData, _TContract, any, any, any, any, any>) => Lambder<TSessionData, _TNewContract, any, any, any, any, any>): Lambder<TSessionData, _TNewContract extends _TContract ? _TNewContract : (_TContract & _TNewContract), _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired>;
|
|
300
|
-
addApi<TName extends string, TInput extends z.
|
|
300
|
+
addApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TRateOpt extends LambderRateLimitOption<_TRateLimitPolicies, z.infer<TInput>, false> = never, const TGuardsOpt extends LambderGuardsOption<_TGuards, z.infer<TInput>, false> = never>(name: TName, schema: {
|
|
301
301
|
input: TInput;
|
|
302
302
|
output: TOutput;
|
|
303
303
|
} & {
|
|
@@ -308,7 +308,7 @@ export default class Lambder<TSessionData = any, _TContract extends Record<strin
|
|
|
308
308
|
ttlSeconds?: number;
|
|
309
309
|
}) : never;
|
|
310
310
|
} & LambderRequirableGuardsField<_TPublicGuardsRequired, TGuardsOpt>, handler: (ctx: LambderRenderContext<z.infer<TInput>, Record<string, string>, LambderGuardDataOf<_TGuards, TGuardsOpt>>, resolver: LambderResolver<z.infer<TOutput>>) => MaybePromise<LambderResponse>): Lambder<TSessionData, MergeContract<_TContract, TName, z.infer<TInput>, z.infer<TOutput>, LambderGuardInputsOf<_TGuards, TGuardsOpt>, TGuardsOpt>, _TRateLimitPolicies, _TGuards, _TIdempotencyEnabled, _TSessionGuardsRequired, _TPublicGuardsRequired>;
|
|
311
|
-
addSessionApi<TName extends string, TInput extends z.
|
|
311
|
+
addSessionApi<TName extends string, TInput extends z.ZodType, TOutput extends z.ZodType, const TRateOpt extends LambderRateLimitOption<_TRateLimitPolicies, z.infer<TInput>, true> = never, const TGuardsOpt extends LambderGuardsOption<_TGuards, z.infer<TInput>, true> = never>(name: TName, schema: {
|
|
312
312
|
input: TInput;
|
|
313
313
|
output: TOutput;
|
|
314
314
|
} & {
|
|
@@ -9,9 +9,10 @@ export type LambderFile = {
|
|
|
9
9
|
* servePublicFiles, serveIndexHtml, res.file and res.templateFile alike,
|
|
10
10
|
* through the instance's one reader (LambderFiles). Implement `read` over
|
|
11
11
|
* any backing store: LambderLocalFileSource (a folder), LambderS3FileSource
|
|
12
|
-
* (S3, or R2 and other S3-compatible stores),
|
|
13
|
-
*
|
|
14
|
-
* from the
|
|
12
|
+
* (S3, or R2 and other S3-compatible stores), LambderHttpFileSource (any
|
|
13
|
+
* origin serving files by path), or your own. The reader does the rest for
|
|
14
|
+
* every source: traversal check, memory cache, mime fallback from the
|
|
15
|
+
* extension.
|
|
15
16
|
*/
|
|
16
17
|
export interface LambderFileSource {
|
|
17
18
|
/**
|
|
@@ -48,6 +49,12 @@ export declare class LambderLocalFileSource implements LambderFileSource {
|
|
|
48
49
|
});
|
|
49
50
|
read(relativePath: string): Promise<LambderFile | null>;
|
|
50
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* A file a remote store returned: the store's Content-Type unless it is a
|
|
54
|
+
* generic octet-stream, in which case the extension decides, as for local
|
|
55
|
+
* files.
|
|
56
|
+
*/
|
|
57
|
+
export declare const remoteStoreFile: (body: Buffer, contentType: string | null | undefined) => LambderFile;
|
|
51
58
|
/**
|
|
52
59
|
* The path a source is asked for: leading slash stripped, traversal
|
|
53
60
|
* rejected; null for a path that names no file (empty, or a directory).
|
|
@@ -27,6 +27,12 @@ export class LambderLocalFileSource {
|
|
|
27
27
|
return { body: await fs.promises.readFile(absolute) };
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* A file a remote store returned: the store's Content-Type unless it is a
|
|
32
|
+
* generic octet-stream, in which case the extension decides, as for local
|
|
33
|
+
* files.
|
|
34
|
+
*/
|
|
35
|
+
export const remoteStoreFile = (body, contentType) => contentType && !contentType.endsWith("octet-stream") ? { body, mimeType: contentType } : { body };
|
|
30
36
|
/**
|
|
31
37
|
* The path a source is asked for: leading slash stripped, traversal
|
|
32
38
|
* rejected; null for a path that names no file (empty, or a directory).
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export { LambderFiles, LambderLocalFileSource } from "./core/LambderFiles.js";
|
|
|
21
21
|
export type { LambderFileSource, LambderFile, LambderFilesOption, LambderFileMemoryCacheOption, LambderReadFile } from "./core/LambderFiles.js";
|
|
22
22
|
export { LambderS3FileSource } from "./stores/LambderS3FileSource.js";
|
|
23
23
|
export type { LambderS3FileSourceOptions } from "./stores/LambderS3FileSource.js";
|
|
24
|
+
export { LambderHttpFileSource } from "./stores/LambderHttpFileSource.js";
|
|
25
|
+
export type { LambderHttpFileSourceOptions } from "./stores/LambderHttpFileSource.js";
|
|
24
26
|
export type { LambderSessionCookieOptions } from "./session/LambderSessionController.js";
|
|
25
27
|
export type { LambderSessionContext, LambderCreatedSession, LambderSessionDataRefreshConfig } from "./session/LambderSessionManager.js";
|
|
26
28
|
export { resolveCompressionOption, LAMBDER_ENCODINGS } from "./shared/LambderCompressionOption.js";
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export { LambderTemplatingEngine } from "./core/LambderTemplatingEngine.js";
|
|
|
18
18
|
export { LambderPublicFilesHandler } from "./core/LambderPublicFiles.js";
|
|
19
19
|
export { LambderFiles, LambderLocalFileSource } from "./core/LambderFiles.js";
|
|
20
20
|
export { LambderS3FileSource } from "./stores/LambderS3FileSource.js";
|
|
21
|
+
export { LambderHttpFileSource } from "./stores/LambderHttpFileSource.js";
|
|
21
22
|
// Compression: the option every site shares, and the one codec behind them all.
|
|
22
23
|
export { resolveCompressionOption, LAMBDER_ENCODINGS } from "./shared/LambderCompressionOption.js";
|
|
23
24
|
// Brotli/gzip plus the bounded, length-verified restore every compressed
|
|
@@ -36,7 +36,7 @@ import type { LambderResponse } from "../core/LambderResponse.js";
|
|
|
36
36
|
* and the handler refuses by throwing (typically refuse()/LambderApiError).
|
|
37
37
|
* Build with lambderGuard() so the handler's payload/ctx/param types line up.
|
|
38
38
|
*/
|
|
39
|
-
export type LambderApiGuard<TInput extends z.
|
|
39
|
+
export type LambderApiGuard<TInput extends z.ZodType = z.ZodType, TParam = any, TOutput = any> = {
|
|
40
40
|
apiInput: TInput;
|
|
41
41
|
guardInput?: undefined;
|
|
42
42
|
session?: boolean;
|
|
@@ -61,7 +61,7 @@ type GuardSessionCtx = LambderSessionRenderContext<any, any>;
|
|
|
61
61
|
* inferred from the handler's 4th argument annotation; the output from its
|
|
62
62
|
* return type.
|
|
63
63
|
*/
|
|
64
|
-
export declare function lambderGuard<TInput extends z.
|
|
64
|
+
export declare function lambderGuard<TInput extends z.ZodType, TParam = undefined, TOutput = void>(guard: {
|
|
65
65
|
apiInput: TInput;
|
|
66
66
|
session: true;
|
|
67
67
|
handler: (ctx: GuardSessionCtx, payload: z.output<TInput>, res: LambderResolver, param: TParam) => TOutput | Promise<TOutput>;
|
|
@@ -71,7 +71,7 @@ export declare function lambderGuard<TInput extends z.ZodTypeAny, TParam = undef
|
|
|
71
71
|
session: true;
|
|
72
72
|
handler: (ctx: GuardSessionCtx, payload: z.output<TInput>, res: LambderResolver, param: TParam) => TOutput | Promise<TOutput>;
|
|
73
73
|
};
|
|
74
|
-
export declare function lambderGuard<TInput extends z.
|
|
74
|
+
export declare function lambderGuard<TInput extends z.ZodType, TParam = undefined, TOutput = void>(guard: {
|
|
75
75
|
apiInput: TInput;
|
|
76
76
|
handler: (ctx: GuardCtx, payload: z.output<TInput>, res: LambderResolver, param: TParam) => TOutput | Promise<TOutput>;
|
|
77
77
|
}): {
|
|
@@ -80,7 +80,7 @@ export declare function lambderGuard<TInput extends z.ZodTypeAny, TParam = undef
|
|
|
80
80
|
session?: undefined;
|
|
81
81
|
handler: (ctx: GuardCtx, payload: z.output<TInput>, res: LambderResolver, param: TParam) => TOutput | Promise<TOutput>;
|
|
82
82
|
};
|
|
83
|
-
export declare function lambderGuard<TInput extends z.
|
|
83
|
+
export declare function lambderGuard<TInput extends z.ZodType, TParam = undefined, TOutput = void>(guard: {
|
|
84
84
|
guardInput: TInput;
|
|
85
85
|
session: true;
|
|
86
86
|
handler: (ctx: GuardSessionCtx, payload: z.output<TInput>, res: LambderResolver, param: TParam) => TOutput | Promise<TOutput>;
|
|
@@ -90,7 +90,7 @@ export declare function lambderGuard<TInput extends z.ZodTypeAny, TParam = undef
|
|
|
90
90
|
session: true;
|
|
91
91
|
handler: (ctx: GuardSessionCtx, payload: z.output<TInput>, res: LambderResolver, param: TParam) => TOutput | Promise<TOutput>;
|
|
92
92
|
};
|
|
93
|
-
export declare function lambderGuard<TInput extends z.
|
|
93
|
+
export declare function lambderGuard<TInput extends z.ZodType, TParam = undefined, TOutput = void>(guard: {
|
|
94
94
|
guardInput: TInput;
|
|
95
95
|
handler: (ctx: GuardCtx, payload: z.output<TInput>, res: LambderResolver, param: TParam) => TOutput | Promise<TOutput>;
|
|
96
96
|
}): {
|
|
@@ -126,11 +126,11 @@ type LambderGuardOutputOf<G> = G extends {
|
|
|
126
126
|
} ? Awaited<R> : never;
|
|
127
127
|
/** Per-guard metadata carried on the Lambder instance: input mode, session requirement, param type, output type. */
|
|
128
128
|
export type LambderGuardMeta<G> = (G extends {
|
|
129
|
-
apiInput: infer S extends z.
|
|
129
|
+
apiInput: infer S extends z.ZodType;
|
|
130
130
|
} ? {
|
|
131
131
|
apiInput: z.output<S>;
|
|
132
132
|
} : G extends {
|
|
133
|
-
guardInput: infer S extends z.
|
|
133
|
+
guardInput: infer S extends z.ZodType;
|
|
134
134
|
} ? {
|
|
135
135
|
guardInput: z.output<S>;
|
|
136
136
|
} : {}) & (G extends {
|
|
@@ -237,7 +237,7 @@ export type LambderInputValidationRefusal = (ctx: LambderRenderContext, resolver
|
|
|
237
237
|
* same one regular input validation answers. Shared with the rate-limit
|
|
238
238
|
* engine's apiInput-keyed policies.
|
|
239
239
|
*/
|
|
240
|
-
export declare const parsePreflightSlice: (input: z.
|
|
240
|
+
export declare const parsePreflightSlice: (input: z.ZodType, value: unknown, ctx: LambderRenderContext, resolver: LambderResolver, onInvalid: LambderInputValidationRefusal) => Promise<unknown>;
|
|
241
241
|
/**
|
|
242
242
|
* Runtime side of the guards subsystem: holds the defined guards, asserts
|
|
243
243
|
* API registrations against them at startup, and executes an API's declared
|
|
@@ -14,7 +14,7 @@ import { type LambderInputValidationRefusal } from "./LambderApiGuards.js";
|
|
|
14
14
|
* stays the single owner of the field. Build with lambderRateLimitKey() so
|
|
15
15
|
* the handler's payload type follows `apiInput`.
|
|
16
16
|
*/
|
|
17
|
-
export type LambderRateLimitKeyFn<TInput extends z.
|
|
17
|
+
export type LambderRateLimitKeyFn<TInput extends z.ZodType = z.ZodType> = {
|
|
18
18
|
apiInput: TInput;
|
|
19
19
|
handler: (ctx: LambderRenderContext, payload: z.output<TInput>) => string | Promise<string>;
|
|
20
20
|
} | {
|
|
@@ -26,7 +26,7 @@ export type LambderRateLimitKeyFn<TInput extends z.ZodTypeAny = z.ZodTypeAny> =
|
|
|
26
26
|
* inside one literal. Returns the exact union member so type extraction can
|
|
27
27
|
* see the schema.
|
|
28
28
|
*/
|
|
29
|
-
export declare function lambderRateLimitKey<TInput extends z.
|
|
29
|
+
export declare function lambderRateLimitKey<TInput extends z.ZodType>(key: {
|
|
30
30
|
apiInput: TInput;
|
|
31
31
|
handler: (ctx: LambderRenderContext, payload: z.output<TInput>) => string | Promise<string>;
|
|
32
32
|
}): {
|
|
@@ -78,7 +78,7 @@ export type LambderAllowedPolicyNames<TPolicies, TPayload, TIncludeSession exten
|
|
|
78
78
|
per: "session";
|
|
79
79
|
} ? (TIncludeSession extends true ? K : never) : TPolicies[K] extends {
|
|
80
80
|
per: {
|
|
81
|
-
apiInput: infer S extends z.
|
|
81
|
+
apiInput: infer S extends z.ZodType;
|
|
82
82
|
};
|
|
83
83
|
} ? (TPayload extends z.output<S> ? K : never) : K;
|
|
84
84
|
}[keyof TPolicies] & string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type LambderFile, type LambderFileSource } from "../core/LambderFiles.js";
|
|
2
|
+
export type LambderHttpFileSourceOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* The folder URL relative paths resolve under: "https://assets.example.com/v42/".
|
|
5
|
+
* It names a folder, so a missing trailing slash is added.
|
|
6
|
+
*/
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
/** Sent with every read, e.g. an Authorization header for a private origin or a User-Agent a firewall allows. */
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
/** How long one read may take before it fails. Default: 10000. */
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Files over HTTP(S) from any origin that serves them by path: a CDN, a
|
|
15
|
+
* public bucket's own domain (a Cloudflare R2 custom domain, an S3 website
|
|
16
|
+
* endpoint) or another server. Reads with the runtime's fetch, so it needs
|
|
17
|
+
* no SDK, and no credentials for a public origin; reads come out of the
|
|
18
|
+
* origin's edge cache. Each path segment is percent-encoded, so a relative
|
|
19
|
+
* path names the same object it would as an S3 key. A 404 or 410 reads as
|
|
20
|
+
* null and the request falls through; any other failed status, a network
|
|
21
|
+
* error or a timeout propagates as an error. The response's Content-Type is
|
|
22
|
+
* used unless it is a generic octet-stream, in which case the extension
|
|
23
|
+
* decides, as for local files.
|
|
24
|
+
*/
|
|
25
|
+
export declare class LambderHttpFileSource implements LambderFileSource {
|
|
26
|
+
private readonly baseUrl;
|
|
27
|
+
private readonly headers;
|
|
28
|
+
private readonly timeoutMs;
|
|
29
|
+
constructor({ baseUrl, headers, timeoutMs }: LambderHttpFileSourceOptions);
|
|
30
|
+
read(relativePath: string): Promise<LambderFile | null>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { remoteStoreFile } from "../core/LambderFiles.js";
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
3
|
+
/**
|
|
4
|
+
* Files over HTTP(S) from any origin that serves them by path: a CDN, a
|
|
5
|
+
* public bucket's own domain (a Cloudflare R2 custom domain, an S3 website
|
|
6
|
+
* endpoint) or another server. Reads with the runtime's fetch, so it needs
|
|
7
|
+
* no SDK, and no credentials for a public origin; reads come out of the
|
|
8
|
+
* origin's edge cache. Each path segment is percent-encoded, so a relative
|
|
9
|
+
* path names the same object it would as an S3 key. A 404 or 410 reads as
|
|
10
|
+
* null and the request falls through; any other failed status, a network
|
|
11
|
+
* error or a timeout propagates as an error. The response's Content-Type is
|
|
12
|
+
* used unless it is a generic octet-stream, in which case the extension
|
|
13
|
+
* decides, as for local files.
|
|
14
|
+
*/
|
|
15
|
+
export class LambderHttpFileSource {
|
|
16
|
+
baseUrl;
|
|
17
|
+
headers;
|
|
18
|
+
timeoutMs;
|
|
19
|
+
constructor({ baseUrl, headers = {}, timeoutMs = DEFAULT_TIMEOUT_MS }) {
|
|
20
|
+
let url;
|
|
21
|
+
try {
|
|
22
|
+
url = new URL(baseUrl);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new Error(`baseUrl must be an absolute http(s) URL: ${baseUrl}`);
|
|
26
|
+
}
|
|
27
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
28
|
+
throw new Error(`baseUrl must be an absolute http(s) URL: ${baseUrl}`);
|
|
29
|
+
if (!url.pathname.endsWith("/"))
|
|
30
|
+
url.pathname += "/";
|
|
31
|
+
this.baseUrl = url;
|
|
32
|
+
this.headers = headers;
|
|
33
|
+
this.timeoutMs = timeoutMs;
|
|
34
|
+
}
|
|
35
|
+
async read(relativePath) {
|
|
36
|
+
const url = new URL(relativePath.split("/").map(encodeURIComponent).join("/"), this.baseUrl);
|
|
37
|
+
const response = await fetch(url, { headers: this.headers, signal: AbortSignal.timeout(this.timeoutMs) });
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
await response.body?.cancel();
|
|
40
|
+
if (response.status === 404 || response.status === 410)
|
|
41
|
+
return null;
|
|
42
|
+
throw new Error(`LambderHttpFileSource: ${response.status} ${response.statusText} reading ${url}`);
|
|
43
|
+
}
|
|
44
|
+
return remoteStoreFile(Buffer.from(await response.arrayBuffer()), response.headers.get("content-type"));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { S3Client, S3ClientConfig } from "@aws-sdk/client-s3";
|
|
2
|
-
import type
|
|
2
|
+
import { type LambderFile, type LambderFileSource } from "../core/LambderFiles.js";
|
|
3
3
|
export type LambderS3FileSourceOptions = {
|
|
4
4
|
bucket: string;
|
|
5
5
|
/** Literal key prefix the relative path is appended to, so include the trailing slash: "web/v42/". Default: none. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { remoteStoreFile } from "../core/LambderFiles.js";
|
|
1
2
|
/**
|
|
2
3
|
* Files from an S3 bucket, or any S3-compatible store such as Cloudflare
|
|
3
4
|
* R2 (pass its endpoint in clientConfig). Needs @aws-sdk/client-s3, an
|
|
@@ -46,8 +47,6 @@ export class LambderS3FileSource {
|
|
|
46
47
|
}
|
|
47
48
|
if (!output.Body)
|
|
48
49
|
return null;
|
|
49
|
-
|
|
50
|
-
const contentType = output.ContentType;
|
|
51
|
-
return contentType && !contentType.endsWith("octet-stream") ? { body, mimeType: contentType } : { body };
|
|
50
|
+
return remoteStoreFile(Buffer.from(await output.Body.transformToByteArray()), output.ContentType);
|
|
52
51
|
}
|
|
53
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lambder",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.3",
|
|
4
4
|
"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.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lambda",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"@aws-sdk/client-s3": "^3.574.0",
|
|
91
91
|
"@aws-sdk/lib-dynamodb": "^3.574.0",
|
|
92
92
|
"msw": "^2.0.0",
|
|
93
|
-
"zod": "^4.
|
|
93
|
+
"zod": "^4.6.2"
|
|
94
94
|
},
|
|
95
95
|
"peerDependenciesMeta": {
|
|
96
96
|
"@aws-sdk/client-dynamodb": {
|
|
@@ -125,6 +125,6 @@
|
|
|
125
125
|
"eslint": "^8.57.0",
|
|
126
126
|
"typescript": "^5.9.3",
|
|
127
127
|
"vitest": "^3.2.4",
|
|
128
|
-
"zod": "^4.
|
|
128
|
+
"zod": "^4.6.2"
|
|
129
129
|
}
|
|
130
130
|
}
|