typesea 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +104 -41
  3. package/SECURITY.md +52 -0
  4. package/dist/aot/index.d.ts +1 -1
  5. package/dist/aot/index.d.ts.map +1 -1
  6. package/dist/aot/index.js +22 -3
  7. package/dist/builders/composite.d.ts +6 -3
  8. package/dist/builders/composite.d.ts.map +1 -1
  9. package/dist/builders/composite.js +22 -13
  10. package/dist/builders/index.d.ts +6 -5
  11. package/dist/builders/index.d.ts.map +1 -1
  12. package/dist/builders/index.js +5 -4
  13. package/dist/builders/modifier.d.ts +6 -0
  14. package/dist/builders/modifier.d.ts.map +1 -1
  15. package/dist/builders/modifier.js +14 -0
  16. package/dist/builders/object/guard.d.ts +54 -2
  17. package/dist/builders/object/guard.d.ts.map +1 -1
  18. package/dist/builders/object/guard.js +117 -7
  19. package/dist/builders/object/index.d.ts +2 -2
  20. package/dist/builders/object/index.d.ts.map +1 -1
  21. package/dist/builders/object/index.js +1 -1
  22. package/dist/builders/object/schema.d.ts +33 -2
  23. package/dist/builders/object/schema.d.ts.map +1 -1
  24. package/dist/builders/object/schema.js +198 -8
  25. package/dist/builders/object/types.d.ts +15 -0
  26. package/dist/builders/object/types.d.ts.map +1 -1
  27. package/dist/builders/runtime.d.ts +40 -0
  28. package/dist/builders/runtime.d.ts.map +1 -0
  29. package/dist/builders/runtime.js +150 -0
  30. package/dist/builders/scalar.d.ts +20 -1
  31. package/dist/builders/scalar.d.ts.map +1 -1
  32. package/dist/builders/scalar.js +54 -1
  33. package/dist/builders/table.d.ts +31 -5
  34. package/dist/builders/table.d.ts.map +1 -1
  35. package/dist/builders/table.js +31 -5
  36. package/dist/builders/types.d.ts +6 -0
  37. package/dist/builders/types.d.ts.map +1 -1
  38. package/dist/compile/check-composite.d.ts +3 -1
  39. package/dist/compile/check-composite.d.ts.map +1 -1
  40. package/dist/compile/check-composite.js +143 -11
  41. package/dist/compile/check-scalar.d.ts +10 -0
  42. package/dist/compile/check-scalar.d.ts.map +1 -1
  43. package/dist/compile/check-scalar.js +138 -2
  44. package/dist/compile/check.d.ts.map +1 -1
  45. package/dist/compile/check.js +25 -3
  46. package/dist/compile/context.d.ts.map +1 -1
  47. package/dist/compile/context.js +2 -0
  48. package/dist/compile/first.d.ts +26 -0
  49. package/dist/compile/first.d.ts.map +1 -0
  50. package/dist/compile/first.js +850 -0
  51. package/dist/compile/graph-predicate.d.ts.map +1 -1
  52. package/dist/compile/graph-predicate.js +389 -18
  53. package/dist/compile/guard.d.ts +2 -1
  54. package/dist/compile/guard.d.ts.map +1 -1
  55. package/dist/compile/guard.js +54 -8
  56. package/dist/compile/predicate.d.ts.map +1 -1
  57. package/dist/compile/predicate.js +156 -5
  58. package/dist/compile/runtime.d.ts +20 -1
  59. package/dist/compile/runtime.d.ts.map +1 -1
  60. package/dist/compile/runtime.js +31 -0
  61. package/dist/compile/source.d.ts.map +1 -1
  62. package/dist/compile/source.js +27 -3
  63. package/dist/compile/types.d.ts +2 -0
  64. package/dist/compile/types.d.ts.map +1 -1
  65. package/dist/decoder/index.d.ts +60 -0
  66. package/dist/decoder/index.d.ts.map +1 -1
  67. package/dist/decoder/index.js +164 -1
  68. package/dist/evaluate/check-composite.d.ts +52 -2
  69. package/dist/evaluate/check-composite.d.ts.map +1 -1
  70. package/dist/evaluate/check-composite.js +193 -6
  71. package/dist/evaluate/check-scalar.d.ts +9 -0
  72. package/dist/evaluate/check-scalar.d.ts.map +1 -1
  73. package/dist/evaluate/check-scalar.js +92 -3
  74. package/dist/evaluate/check.d.ts.map +1 -1
  75. package/dist/evaluate/check.js +19 -4
  76. package/dist/evaluate/shared.d.ts +19 -0
  77. package/dist/evaluate/shared.d.ts.map +1 -1
  78. package/dist/evaluate/shared.js +35 -0
  79. package/dist/guard/array.d.ts +48 -0
  80. package/dist/guard/array.d.ts.map +1 -0
  81. package/dist/guard/array.js +84 -0
  82. package/dist/guard/base.d.ts +32 -2
  83. package/dist/guard/base.d.ts.map +1 -1
  84. package/dist/guard/base.js +74 -3
  85. package/dist/guard/date.d.ts +34 -0
  86. package/dist/guard/date.d.ts.map +1 -0
  87. package/dist/guard/date.js +60 -0
  88. package/dist/guard/index.d.ts +2 -0
  89. package/dist/guard/index.d.ts.map +1 -1
  90. package/dist/guard/index.js +2 -0
  91. package/dist/guard/number.d.ts +60 -0
  92. package/dist/guard/number.d.ts.map +1 -1
  93. package/dist/guard/number.js +129 -0
  94. package/dist/guard/read.d.ts +53 -1
  95. package/dist/guard/read.d.ts.map +1 -1
  96. package/dist/guard/read.js +102 -0
  97. package/dist/guard/string.d.ts +82 -0
  98. package/dist/guard/string.d.ts.map +1 -1
  99. package/dist/guard/string.js +213 -0
  100. package/dist/guard/types.d.ts +18 -0
  101. package/dist/guard/types.d.ts.map +1 -1
  102. package/dist/index.d.ts +4 -4
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +4 -4
  105. package/dist/ir/builder.d.ts +3 -3
  106. package/dist/ir/builder.d.ts.map +1 -1
  107. package/dist/ir/builder.js +5 -2
  108. package/dist/ir/freeze.js +7 -0
  109. package/dist/ir/types.d.ts +4 -1
  110. package/dist/ir/types.d.ts.map +1 -1
  111. package/dist/ir/validate.d.ts.map +1 -1
  112. package/dist/ir/validate.js +35 -1
  113. package/dist/issue/index.d.ts +1 -1
  114. package/dist/issue/index.d.ts.map +1 -1
  115. package/dist/issue/index.js +4 -0
  116. package/dist/json-schema/emit-composite.d.ts +6 -2
  117. package/dist/json-schema/emit-composite.d.ts.map +1 -1
  118. package/dist/json-schema/emit-composite.js +66 -12
  119. package/dist/json-schema/emit-scalar.d.ts.map +1 -1
  120. package/dist/json-schema/emit-scalar.js +54 -1
  121. package/dist/json-schema/emit.d.ts.map +1 -1
  122. package/dist/json-schema/emit.js +11 -2
  123. package/dist/json-schema/types.d.ts +7 -1
  124. package/dist/json-schema/types.d.ts.map +1 -1
  125. package/dist/kind/index.d.ts +25 -0
  126. package/dist/kind/index.d.ts.map +1 -1
  127. package/dist/kind/index.js +26 -3
  128. package/dist/lower/index.d.ts.map +1 -1
  129. package/dist/lower/index.js +52 -3
  130. package/dist/message/index.d.ts +18 -0
  131. package/dist/message/index.d.ts.map +1 -1
  132. package/dist/message/index.js +67 -0
  133. package/dist/optimize/domain.js +6 -2
  134. package/dist/optimize/map-node.d.ts.map +1 -1
  135. package/dist/optimize/map-node.js +3 -0
  136. package/dist/plan/cache.js +13 -1
  137. package/dist/plan/predicate.d.ts.map +1 -1
  138. package/dist/plan/predicate.js +33 -3
  139. package/dist/plan/schema-predicate.d.ts.map +1 -1
  140. package/dist/plan/schema-predicate.js +267 -8
  141. package/dist/schema/freeze.js +22 -0
  142. package/dist/schema/index.d.ts +2 -2
  143. package/dist/schema/index.d.ts.map +1 -1
  144. package/dist/schema/index.js +1 -1
  145. package/dist/schema/types.d.ts +89 -4
  146. package/dist/schema/types.d.ts.map +1 -1
  147. package/dist/schema/types.js +8 -1
  148. package/dist/schema/undefined.d.ts.map +1 -1
  149. package/dist/schema/undefined.js +5 -0
  150. package/dist/schema/validate.d.ts.map +1 -1
  151. package/dist/schema/validate.js +111 -4
  152. package/docs/api.md +79 -10
  153. package/docs/assets/benchmark-headline.svg +33 -33
  154. package/docs/engine-notes.md +9 -5
  155. package/docs/index.html +1366 -722
  156. package/docs/ko/api.md +383 -0
  157. package/docs/ko/engine-notes.md +156 -0
  158. package/docs/ko/readme.md +404 -0
  159. package/package.json +6 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,46 @@
2
2
 
3
3
  All notable changes to TypeSea are recorded here.
4
4
 
5
+ ## 0.3.1 - Unreleased
6
+
7
+ ### Changed
8
+
9
+ - Hardened the manual GitHub Release workflow so `workflow_dispatch` tag input
10
+ is passed through environment variables and validated as a release tag before
11
+ it reaches shell output.
12
+ - Added `SECURITY.md` with supported versions, reporting guidance, and the
13
+ security boundary for safe, unsafe, unchecked, AOT, and dynamic compilation.
14
+ - Added a post-publish npm registry verification step to the GitHub Publish
15
+ workflow.
16
+ - Added `release:publish` so the repository-owned publish command always uses
17
+ `npm publish --provenance --access public --ignore-scripts`.
18
+ - Removed the version-pinned Socket badge URL from the README.
19
+ - Refreshed the benchmark snapshot and docs graph from the 2026-07-05 local
20
+ `bench/ecosystem.bench.ts` run.
21
+ - Clarified the release path: local npm publishing is allowed for emergency
22
+ manual releases, but normal releases should go through GitHub Release so npm
23
+ provenance is attached.
24
+ - Expanded decoder documentation around method chaining with `transform`,
25
+ `default`, `prefault`, and `catch`.
26
+
27
+ ## 0.3.0 - 2026-07-05
28
+
29
+ ### Added
30
+
31
+ - Added Date bounds with `t.date.min()` and `t.date.max()`.
32
+ - Added tuple rest support with `t.tuple([head], rest)`.
33
+ - Added `t.map`, `t.set`, `t.instanceOf`, `t.property`, `guard.property`, and
34
+ `t.json`.
35
+ - Added scalar aliases `t.null`, `t.undefined`, `t.void`, and presence helper
36
+ `t.nullish`.
37
+ - Added string decoder helpers `t.string.trim()`, `t.string.toLowerCase()`,
38
+ and `t.string.toUpperCase()`.
39
+
40
+ ### Changed
41
+
42
+ - Hardened Date validation to use intrinsic Date reads instead of
43
+ user-overridable Date instance methods.
44
+
5
45
  ## 0.2.0 - 2026-07-04
6
46
 
7
47
  Initial public release of TypeSea: a zero-runtime-dependency TypeScript runtime
package/README.md CHANGED
@@ -1,9 +1,13 @@
1
1
  # TypeSea
2
2
 
3
3
  [![CI](https://github.com/Feralthedogg/TypeSea/actions/workflows/ci.yml/badge.svg)](https://github.com/Feralthedogg/TypeSea/actions/workflows/ci.yml)
4
+ [![Socket Badge](https://badge.socket.dev/npm/package/typesea)](https://socket.dev/npm/package/typesea)
4
5
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
5
6
  ![TypeScript](https://img.shields.io/badge/language-TypeScript-informational)
6
7
  ![Dependencies](https://img.shields.io/badge/runtime%20deps-zero-brightgreen)
8
+ ![Tree-shakeable](https://img.shields.io/badge/tree--shakeable-yes-7CFF9B)
9
+ ![Side-effect free](https://img.shields.io/badge/side--effect%20free-yes-7CFF9B)
10
+ ![No dependencies](https://img.shields.io/badge/dependencies-none-7CFF9B)
7
11
  ![Module](https://img.shields.io/badge/module-ESM--only-orange)
8
12
  ![Node](https://img.shields.io/badge/node-%3E%3D20.19-yellowgreen)
9
13
 
@@ -13,7 +17,7 @@ runtime compilation, and AOT source generation.
13
17
 
14
18
  ## Benchmark Headline
15
19
 
16
- Last local benchmark on 2026-07-04 KST:
20
+ Last local benchmark on 2026-07-05 KST:
17
21
  `npm run bench -- bench/ecosystem.bench.ts --run`, strict-object contract,
18
22
  operations per second on one machine.
19
23
 
@@ -36,6 +40,12 @@ loads, allocation-light strict-key loops, and V8-friendly monomorphic codegen.
36
40
  > return frozen `Result` values — `any`, `try`, and `catch` are banned from the
37
41
  > entire codebase and enforced by policy gates.
38
42
 
43
+ > [!WARNING]
44
+ > `unsafe` and `unchecked` are **not public-boundary modes**. They are for
45
+ > trusted, already-normalized data where the caller accepts getter execution,
46
+ > prototype-backed values, and weaker strict-extra-key guarantees. Use the
47
+ > default safe mode for external input.
48
+
39
49
  ---
40
50
 
41
51
  ## Why
@@ -89,8 +99,10 @@ import { compile, t, toJsonSchema, type Infer } from "typesea";
89
99
 
90
100
  const User = t.strictObject({
91
101
  id: t.string.uuid(),
92
- age: t.number.int().gte(0),
93
- role: t.union(t.literal("admin"), t.literal("user"))
102
+ email: t.string.email(),
103
+ age: t.number.int().nonnegative(),
104
+ role: t.enum(["admin", "user"]),
105
+ tags: t.array(t.string.min(1)).max(8)
94
106
  });
95
107
 
96
108
  type User = Infer<typeof User>;
@@ -114,8 +126,11 @@ const schema = toJsonSchema(User);
114
126
  ```
115
127
 
116
128
  Use `is()` for the allocation-light boolean path. Use `check()` when callers
117
- need immutable diagnostics. Use `compile()` or `emitAotModule()` when a stable
118
- schema is hot enough to deserve generated validator code.
129
+ need the full immutable diagnostic list, or `checkFirst()` when a hot rejection
130
+ path only needs one machine-readable issue. Use `compile()` or `emitAotModule()`
131
+ when a stable schema is hot enough to deserve generated validator code.
132
+ Compiled and AOT `checkFirst()` use a dedicated first-fault collector instead
133
+ of building the full issue list and slicing it afterward.
119
134
 
120
135
  > [!CAUTION]
121
136
  > `compile()` builds the validator with `new Function`, which throws under a
@@ -213,50 +228,50 @@ failed check() -> schema-aware diagnostic collector
213
228
 
214
229
  ## Performance Snapshot
215
230
 
216
- Last local benchmark on 2026-07-04 KST, using
231
+ Last local benchmark on 2026-07-05 KST, using
217
232
  `npm run bench -- bench/ecosystem.bench.ts --run` on the benchmark strict-object
218
233
  contract. These are operations per second on one machine, not release
219
234
  guarantees.
220
235
 
221
236
  | Valid object path | hz |
222
237
  | --- | ---: |
223
- | TypeSea interpreted `is()` | 513,701 |
224
- | TypeSea compiled safe `is()` | 4,297,306 |
225
- | TypeSea compiled unsafe `is()` | 36,297,653 |
226
- | TypeSea compiled unchecked `is()` | 42,581,174 |
227
- | Zod `safeParse` | 1,343,756 |
228
- | Valibot `safeParse` | 1,406,528 |
229
- | Ajv compiled | 4,275,389 |
238
+ | TypeSea interpreted `is()` | 478,576 |
239
+ | TypeSea compiled safe `is()` | 5,109,602 |
240
+ | TypeSea compiled unsafe `is()` | 36,777,097 |
241
+ | TypeSea compiled unchecked `is()` | 42,620,570 |
242
+ | Zod `safeParse` | 1,400,045 |
243
+ | Valibot `safeParse` | 1,400,599 |
244
+ | Ajv compiled | 4,238,036 |
230
245
 
231
246
  | Valid diagnostic path | hz |
232
247
  | --- | ---: |
233
- | TypeSea interpreted `check()` | 503,232 |
234
- | TypeSea compiled safe `check()` | 3,903,929 |
235
- | TypeSea compiled unsafe `check()` | 35,568,425 |
236
- | TypeSea compiled unchecked `check()` | 40,084,605 |
237
- | Zod `safeParse` | 1,355,014 |
238
- | Valibot `safeParse` | 1,378,266 |
239
- | Ajv compiled | 4,278,587 |
248
+ | TypeSea interpreted `check()` | 424,989 |
249
+ | TypeSea compiled safe `check()` | 4,642,948 |
250
+ | TypeSea compiled unsafe `check()` | 37,184,199 |
251
+ | TypeSea compiled unchecked `check()` | 42,487,325 |
252
+ | Zod `safeParse` | 1,278,859 |
253
+ | Valibot `safeParse` | 1,391,040 |
254
+ | Ajv compiled | 4,338,063 |
240
255
 
241
256
  | Invalid object path | hz |
242
257
  | --- | ---: |
243
- | TypeSea interpreted `is()` | 3,636,369 |
244
- | TypeSea compiled safe `is()` | 42,080,241 |
245
- | TypeSea compiled unsafe `is()` | 49,654,076 |
246
- | TypeSea compiled unchecked `is()` | 50,482,732 |
247
- | Zod `safeParse` | 84,272 |
248
- | Valibot `safeParse` | 878,521 |
249
- | Ajv compiled | 27,820,643 |
258
+ | TypeSea interpreted `is()` | 3,325,603 |
259
+ | TypeSea compiled safe `is()` | 43,094,061 |
260
+ | TypeSea compiled unsafe `is()` | 50,738,235 |
261
+ | TypeSea compiled unchecked `is()` | 50,898,012 |
262
+ | Zod `safeParse` | 84,647 |
263
+ | Valibot `safeParse` | 866,013 |
264
+ | Ajv compiled | 30,535,761 |
250
265
 
251
266
  | Invalid diagnostic path | hz |
252
267
  | --- | ---: |
253
- | TypeSea interpreted `check()` | 420,446 |
254
- | TypeSea compiled safe `check()` | 2,086,129 |
255
- | TypeSea compiled unsafe `check()` | 3,077,367 |
256
- | TypeSea compiled unchecked `check()` | 3,673,508 |
257
- | Zod `safeParse` | 79,613 |
258
- | Valibot `safeParse` | 887,991 |
259
- | Ajv compiled | 28,713,035 |
268
+ | TypeSea interpreted `check()` | 405,590 |
269
+ | TypeSea compiled safe `check()` | 2,107,460 |
270
+ | TypeSea compiled unsafe `check()` | 3,186,702 |
271
+ | TypeSea compiled unchecked `check()` | 3,509,673 |
272
+ | Zod `safeParse` | 85,355 |
273
+ | Valibot `safeParse` | 788,870 |
274
+ | Ajv compiled | 29,951,403 |
260
275
 
261
276
  The safe compiled path stays close to Ajv while retaining TypeSea hostile-input
262
277
  semantics: descriptor-based property reads, symbol/non-enumerable strict-key
@@ -275,37 +290,57 @@ grouped under the `t` table.
275
290
 
276
291
  | Area | Entry points |
277
292
  | --- | --- |
278
- | Scalar guards | `t.unknown`, `t.never`, `t.string`, `t.number`, `t.bigint`, `t.symbol`, `t.boolean` |
279
- | Literal and containers | `t.literal`, `t.array`, `t.tuple`, `t.record` |
280
- | Objects | `t.object`, `t.strictObject`, `extend`, `pick`, `omit`, `partial` |
293
+ | Scalar guards | `t.unknown`, `t.never`, `t.string`, `t.number`, `t.date`, `t.bigint`, `t.symbol`, `t.boolean`, `t.null`, `t.undefined`, `t.void` |
294
+ | String checks | `.min`, `.max`, `.length`, `.nonempty`, `.regex`, `.startsWith`, `.endsWith`, `.includes`, `.uuid`, `.email`, `.url`, `.isoDate`, `.isoDateTime`, `.ulid`, `.ipv4`, `.ipv6` |
295
+ | Number checks | `.int`, `.finite`, `.safe`, `.gte`, `.lte`, `.min`, `.max`, `.gt`, `.lt`, `.multipleOf`, `.positive`, `.nonnegative`, `.negative`, `.nonpositive` |
296
+ | Date checks | `.min`, `.max` |
297
+ | Literal and containers | `t.literal`, `t.enum`, `t.array`, `t.tuple`, tuple rest, `t.record`, `t.map`, `t.set`, `t.json` |
298
+ | Array checks | `.min`, `.max`, `.length`, `.nonempty` |
299
+ | Objects | `t.object`, `t.strictObject`, `extend`, `safeExtend`, `merge`, `pick`, `omit`, `partial`, `deepPartial`, `required`, `strict`, `passthrough`, `strip`, `catchall` |
300
+ | Runtime object contracts | `t.instanceOf`, `t.property`, `guard.property` |
281
301
  | Composition | `t.union`, `t.discriminatedUnion`, `t.intersect`, `guard.intersect` |
282
- | Presence wrappers | `t.optional`, `t.undefinedable`, `t.nullable` |
302
+ | Presence wrappers | `t.optional`, `t.undefinedable`, `t.nullable`, `t.nullish` |
283
303
  | Dynamic contracts | `t.lazy`, `t.refine` |
284
304
 
285
305
  ### Decoders
286
306
 
287
307
  | Area | Entry points |
288
308
  | --- | --- |
289
- | Sync decoders | `t.decoder`, `t.transform`, `t.pipe`, `t.coerce` |
309
+ | Sync decoders | `t.decoder`, `t.transform`, `t.pipe`, `t.default`, `t.defaultValue`, `t.prefault`, `t.catch`, `t.codec`, `t.coerce`, `t.string.trim()`, `t.string.toLowerCase()`, `t.string.toUpperCase()` |
290
310
  | Async decoders | `t.asyncDecoder`, `t.asyncRefine`, `t.asyncTransform`, `t.asyncPipe` |
291
311
 
292
312
  ### Execution & Export
293
313
 
294
314
  | Area | Entry points |
295
315
  | --- | --- |
296
- | Guard methods | `guard.is()`, `guard.check()`, `guard.graph()` |
316
+ | Guard methods | `guard.is()`, `guard.check()`, `guard.checkFirst()`, `guard.graph()` |
297
317
  | Generated validators | `compile`, `emitAotModule` |
298
318
  | JSON Schema | `toJsonSchema` |
319
+ | Messages | `formatIssue`, `formatIssues`, `flattenIssues`, `withMessages` |
299
320
 
300
321
  ### Messages & Adapters
301
322
 
302
323
  | Area | Entry points |
303
324
  | --- | --- |
304
- | Messages / i18n | `formatIssue`, `formatIssues`, `withMessages`, `defineMessages` |
325
+ | Messages / i18n | `formatIssue`, `formatIssues`, `flattenIssues`, `withMessages`, `defineMessages` |
305
326
  | tRPC | `toTrpcParser`, `toAsyncTrpcParser` |
306
327
  | Fastify | `toFastifyRouteSchema`, `toFastifyValidatorCompiler` |
307
328
  | React Hook Form | `toReactHookFormResolver` |
308
329
 
330
+ Adapters accept compiled guards too. Compile once at startup, then pass the
331
+ compiled guard into parser or validator-compiler adapters so framework hot paths
332
+ reuse the generated predicate.
333
+
334
+ ```ts
335
+ const FastUser = compile(User);
336
+ const trpcParser = toTrpcParser(FastUser);
337
+ const fastifyCompiler = toFastifyValidatorCompiler(FastUser);
338
+
339
+ // Trusted normalized data only: trades hostile-input hardening for direct reads.
340
+ const UnsafeUser = compile(User, { mode: "unsafe" });
341
+ const internalParser = toTrpcParser(UnsafeUser);
342
+ ```
343
+
309
344
  > [!TIP]
310
345
  > Match the inference alias to the source kind: `Infer<>` for guards,
311
346
  > `InferDecoder<>` for decoders, `InferAsyncDecoder<>` for async decoders.
@@ -326,6 +361,11 @@ Deliberate, documented, and pinned by tests:
326
361
  | `__proto__`, `constructor` keys | validated as plain own keys, no pollution |
327
362
  | Sparse array holes | read as `undefined` without executing accessors |
328
363
  | Strict object extras | rejected via `Reflect.ownKeys` — including symbol keys and non-enumerable properties |
364
+ | `catchall` extras | unknown own keys are descriptor-read and validated by the catchall schema |
365
+ | `strip()` | validation-only alias for accepting extras; TypeSea does not clone stripped output |
366
+ | `t.date` | accepts valid JavaScript `Date` objects; `.min` and `.max` compare epoch milliseconds without reading user-overridable Date methods |
367
+ | `t.map`, `t.set`, `t.instanceOf` | runtime-only contracts; JSON Schema and AOT export reject them instead of weakening semantics |
368
+ | `property` | validates own data properties only; getter-backed properties are rejected |
329
369
  | Global-flag regexes | cloned at construction; `lastIndex` reset before every test |
330
370
  | UUID | accepts RFC 9562 versions 1–8 plus the nil UUID |
331
371
  | Cyclic input values | validate finitely via (value × schema) active-pair tracking |
@@ -373,6 +413,7 @@ npm run check:consumer # tarball install + runtime/type smoke in a temp project
373
413
  npm run bench -- --run # benchmark smoke
374
414
  npm run pack:dry # package contents dry run
375
415
  npm run release:check # the full pre-publish gate (everything above)
416
+ npm run release:publish # npm publish with provenance and ignored lifecycle scripts
376
417
  ```
377
418
 
378
419
  `npm run release:check` runs the same gate expected before publishing:
@@ -380,6 +421,16 @@ typecheck, lint, tests, build, docs smoke, dist policy, public API snapshot,
380
421
  package contents, consumer install, benchmark smoke, and pack dry run.
381
422
  CI executes it on Node 20.19, 22, and 24; releases publish with npm provenance.
382
423
 
424
+ Release path:
425
+
426
+ 1. Push a `vX.Y.Z` tag or run the GitHub `Release` workflow with that tag.
427
+ 2. The release workflow verifies that the tag matches `package.json`.
428
+ 3. Publishing happens from the GitHub `Publish` workflow through `npm run release:publish`, which expands to `npm publish --provenance --access public --ignore-scripts`.
429
+
430
+ Local publishing with `NPM_TOKEN` is reserved for manual recovery releases. It
431
+ must still run `npm run release:check` first, and it cannot attach GitHub OIDC
432
+ provenance.
433
+
383
434
  > [!NOTE]
384
435
  > Benchmark comparison packages (Zod, Valibot, Ajv) are dev dependencies only —
385
436
  > package policy rejects them from every runtime dependency field. The
@@ -393,6 +444,18 @@ CI executes it on Node 20.19, 22, and 24; releases publish with npm provenance.
393
444
  - [Documentation site](https://feralthedogg.github.io/TypeSea/)
394
445
  - [API reference](docs/api.md)
395
446
  - [Engine notes](docs/engine-notes.md)
447
+ - [Security policy](https://github.com/Feralthedogg/TypeSea/blob/main/SECURITY.md)
448
+
449
+ ---
450
+
451
+ ## Migration Notes
452
+
453
+ ### 0.3.0 to 0.3.1
454
+
455
+ No application code changes are required. `0.3.1` is a release-hardening patch:
456
+ it tightens manual release tag handling, documents npm provenance expectations,
457
+ adds a security policy, and verifies that npm exposes the published version after
458
+ the GitHub publish workflow completes.
396
459
 
397
460
  ---
398
461
 
package/SECURITY.md ADDED
@@ -0,0 +1,52 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ TypeSea supports the latest published minor line. Security fixes are released as
6
+ patch versions whenever a fix can be shipped without changing the public API.
7
+
8
+ | Version | Supported |
9
+ | --- | --- |
10
+ | 0.3.x | yes |
11
+ | 0.2.x | no |
12
+
13
+ ## Reporting A Vulnerability
14
+
15
+ Please report security issues through GitHub Security Advisories for
16
+ `Feralthedogg/TypeSea`. If that is unavailable, open a GitHub issue with the
17
+ minimum public detail needed to start coordination and mark the title as a
18
+ security report.
19
+
20
+ Useful reports include:
21
+
22
+ - affected TypeSea version
23
+ - minimal schema and input needed to reproduce the issue
24
+ - whether the issue affects `safe`, `unsafe`, `unchecked`, AOT, JSON Schema, or
25
+ an adapter
26
+ - expected verdict and actual verdict
27
+ - generated source or stack output that helps reproduce the issue
28
+
29
+ ## Security Boundary
30
+
31
+ The default validation mode is `safe`. It is the mode intended for hostile
32
+ boundary data. Safe mode avoids user getter execution, treats prototype-backed
33
+ data as untrusted, handles `__proto__` and `constructor` keys with
34
+ null-prototype lookups, checks strict-object symbol and non-enumerable extras,
35
+ and returns explicit `Result` values for expected failures.
36
+
37
+ `unsafe` and `unchecked` are performance escape hatches for trusted,
38
+ already-normalized data. They may execute getters, may accept prototype-backed
39
+ values, and may relax strict-object extra-key guarantees. Do not use these modes
40
+ on public input boundaries unless a separate normalization step has already
41
+ converted the input into plain owned data.
42
+
43
+ `compile()` uses `new Function` by design. If a deployment forbids dynamic code
44
+ generation through Content Security Policy, use normal guards or
45
+ `emitAotModule()` instead.
46
+
47
+ ## Release Integrity
48
+
49
+ The package is expected to have zero runtime, peer, optional, and bundled
50
+ dependencies. Release checks verify package contents, public API drift, docs,
51
+ tests, consumer install smoke, benchmarks, and dist policy before publishing.
52
+ Normal releases should go through GitHub Releases so npm provenance is attached.
@@ -7,7 +7,7 @@ import { type Result } from "../result/index.js";
7
7
  * @details AOT helpers serialize only portable data because standalone modules cannot close
8
8
  * over runtime side tables.
9
9
  */
10
- export type AotIssueCode = "unsupported_aot_lazy" | "unsupported_aot_refine" | "unsupported_aot_symbol_literal";
10
+ export type AotIssueCode = "unsupported_aot_lazy" | "unsupported_aot_refine" | "unsupported_aot_date" | "unsupported_aot_runtime_object" | "unsupported_aot_symbol_literal";
11
11
  /**
12
12
  * @brief aot issue.
13
13
  * @details AOT helpers serialize only portable data because standalone modules cannot close
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/aot/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAQ1D;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAClB,sBAAsB,GACtB,wBAAwB,GACxB,gCAAgC,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;CAC1C;AAYD;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CACzB,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACrC,MAAM,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC,CAsBxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/aot/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAQ1D;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAClB,sBAAsB,GACtB,wBAAwB,GACxB,sBAAsB,GACtB,gCAAgC,GAChC,gCAAgC,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;CAC1C;AAYD;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CACzB,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACrC,MAAM,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC,CAsBxC"}
package/dist/aot/index.js CHANGED
@@ -124,17 +124,32 @@ function scanAotSchema(schema, path, issues, seen) {
124
124
  pushIssue(path, issues, "unsupported_aot_symbol_literal", "AOT modules cannot preserve symbol literal identity");
125
125
  }
126
126
  return;
127
+ case SchemaTag.Date:
128
+ pushIssue(path, issues, "unsupported_aot_date", "AOT modules cannot preserve JavaScript Date object validation yet");
129
+ return;
127
130
  case SchemaTag.Array:
128
131
  scanAotSchema(schema.item, path.concat("items"), issues, seen);
129
132
  return;
130
133
  case SchemaTag.Tuple:
131
134
  scanSchemaArray(schema.items, path, issues, seen);
135
+ if (schema.rest !== undefined) {
136
+ scanAotSchema(schema.rest, path.concat("rest"), issues, seen);
137
+ }
132
138
  return;
133
139
  case SchemaTag.Record:
134
140
  scanAotSchema(schema.value, path.concat("additionalProperties"), issues, seen);
135
141
  return;
142
+ case SchemaTag.Map:
143
+ case SchemaTag.Set:
144
+ case SchemaTag.InstanceOf:
145
+ case SchemaTag.Property:
146
+ pushIssue(path, issues, "unsupported_aot_runtime_object", "AOT modules cannot preserve JavaScript runtime object contracts yet");
147
+ return;
136
148
  case SchemaTag.Object:
137
149
  scanObjectEntries(schema.entries, path, issues, seen);
150
+ if (schema.catchall !== undefined) {
151
+ scanAotSchema(schema.catchall, path.concat("additionalProperties"), issues, seen);
152
+ }
138
153
  return;
139
154
  case SchemaTag.Union:
140
155
  scanSchemaArray(schema.options, path, issues, seen);
@@ -216,14 +231,16 @@ function emitModuleSource(bundle) {
216
231
  JSON.stringify(bundle.strings),
217
232
  ";const d=function(){return false;};",
218
233
  "const m=function(){return;};",
234
+ "const mf=function(){return;};",
219
235
  "const sk=function(v,ks){if(typeof v!==\"object\"||v===null||Array.isArray(v))return false;const ps=Reflect.ownKeys(v);for(let i=0;i<ps.length;i+=1){const key=ps[i];if(typeof key!==\"string\"||!ks.includes(key))return false;}return true;};",
220
- "const __typesea=(function(l,r,k,u,d,m,sk){",
236
+ "const __typesea=(function(l,r,k,u,d,m,mf,sk){",
221
237
  bundle.source,
222
- "})(l,r,k,u,d,m,sk);",
238
+ "})(l,r,k,u,d,m,mf,sk);",
223
239
  "export function is(value){return __typesea.is(value);}",
224
240
  "export function check(value){return __typesea.result(value);}",
241
+ "export function checkFirst(value){return __typesea.first(value);}",
225
242
  "export function assert(value){const result=check(value);if(!result.ok){const error=new Error(\"TypeSea assertion failed\");Object.defineProperty(error,\"issues\",{configurable:false,enumerable:true,value:result.error,writable:false});throw error;}}",
226
- "export default Object.freeze({is,check,assert});",
243
+ "export default Object.freeze({is,check,checkFirst,assert});",
227
244
  ""
228
245
  ].join("");
229
246
  }
@@ -246,10 +263,12 @@ function emitDeclarationSource() {
246
263
  " | { readonly ok: false; readonly error: readonly AotIssue[] };",
247
264
  "export declare function is(value: unknown): boolean;",
248
265
  "export declare function check<TValue = unknown>(value: TValue): AotCheckResult<TValue>;",
266
+ "export declare function checkFirst<TValue = unknown>(value: TValue): AotCheckResult<TValue>;",
249
267
  "export declare function assert(value: unknown): void;",
250
268
  "declare const guard: {",
251
269
  " readonly is: typeof is;",
252
270
  " readonly check: typeof check;",
271
+ " readonly checkFirst: typeof checkFirst;",
253
272
  " readonly assert: typeof assert;",
254
273
  "};",
255
274
  "export default guard;",
@@ -4,8 +4,8 @@
4
4
  * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
5
5
  * with stable metadata.
6
6
  */
7
- import { BaseGuard, type Guard, type Infer, type Presence } from "../guard/index.js";
8
- import type { DiscriminatedUnionCases, InferTuple, TupleShape, UnionInput } from "./types.js";
7
+ import { ArrayGuard, BaseGuard, type Guard, type Infer, type Presence } from "../guard/index.js";
8
+ import type { DiscriminatedUnionCases, InferTuple, InferTupleWithRest, TupleShape, UnionInput } from "./types.js";
9
9
  /**
10
10
  * @brief Build an array guard.
11
11
  * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
@@ -13,7 +13,7 @@ import type { DiscriminatedUnionCases, InferTuple, TupleShape, UnionInput } from
13
13
  * @param item Guard used for each logical array slot.
14
14
  * @returns Fresh array guard.
15
15
  */
16
- export declare function array<TGuard extends Guard<unknown, Presence>>(item: TGuard): BaseGuard<Infer<TGuard>[]>;
16
+ export declare function array<TGuard extends Guard<unknown, Presence>>(item: TGuard): ArrayGuard<Infer<TGuard>>;
17
17
  /**
18
18
  * @brief Build a fixed-length tuple guard.
19
19
  * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
@@ -23,6 +23,7 @@ export declare function array<TGuard extends Guard<unknown, Presence>>(item: TGu
23
23
  * @throws TypeError when shape is not an array-like tuple input.
24
24
  */
25
25
  export declare function tuple<const TShape extends TupleShape>(shape: TShape): BaseGuard<InferTuple<TShape>>;
26
+ export declare function tuple<const TShape extends TupleShape, TRest extends Guard<unknown, Presence>>(shape: TShape, rest: TRest): BaseGuard<InferTupleWithRest<TShape, TRest>>;
26
27
  /**
27
28
  * @brief Build a string-keyed record guard.
28
29
  * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
@@ -31,6 +32,8 @@ export declare function tuple<const TShape extends TupleShape>(shape: TShape): B
31
32
  * @returns Fresh record guard.
32
33
  */
33
34
  export declare function record<TGuard extends Guard<unknown, Presence>>(value: TGuard): BaseGuard<Readonly<Record<string, Infer<TGuard>>>>;
35
+ export declare function map<TKey extends Guard<unknown, Presence>, TValue extends Guard<unknown, Presence>>(key: TKey, value: TValue): BaseGuard<ReadonlyMap<Infer<TKey>, Infer<TValue>>>;
36
+ export declare function set<TItem extends Guard<unknown, Presence>>(item: TItem): BaseGuard<ReadonlySet<Infer<TItem>>>;
34
37
  /**
35
38
  * @brief Build a union guard from one or more guards.
36
39
  * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
@@ -1 +1 @@
1
- {"version":3,"file":"composite.d.ts","sourceRoot":"","sources":["../../src/builders/composite.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACH,SAAS,EACT,KAAK,KAAK,EACV,KAAK,KAAK,EACV,KAAK,QAAQ,EAChB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,KAAK,EACR,uBAAuB,EACvB,UAAU,EACV,UAAU,EACV,UAAU,EACb,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACzD,IAAI,EAAE,MAAM,GACb,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAK5B;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,MAAM,SAAS,UAAU,EACjD,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAkB/B;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC1D,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAKpD;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,OAAO,SAAS,UAAU,EAClD,GAAG,MAAM,EAAE,OAAO,GACnB,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAiBnC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACrB,KAAK,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACtC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAEvC,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAMzC;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,CAAC,IAAI,SAAS,MAAM,EACzB,KAAK,CAAC,MAAM,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAEvE,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,MAAM,GAAG,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,GACtD,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAiCxC"}
1
+ {"version":3,"file":"composite.d.ts","sourceRoot":"","sources":["../../src/builders/composite.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACH,UAAU,EACV,SAAS,EACT,KAAK,KAAK,EACV,KAAK,KAAK,EACV,KAAK,QAAQ,EAChB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,KAAK,EACR,uBAAuB,EACvB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,UAAU,EACb,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACzD,IAAI,EAAE,MAAM,GACb,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAM3B;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,MAAM,SAAS,UAAU,EACjD,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAEjC,wBAAgB,KAAK,CACjB,KAAK,CAAC,MAAM,SAAS,UAAU,EAC/B,KAAK,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAEtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,KAAK,GACZ,SAAS,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AA4BhD;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC1D,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAKpD;AAED,wBAAgB,GAAG,CACf,IAAI,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACrC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAEvC,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAMpD;AAED,wBAAgB,GAAG,CAAC,KAAK,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACtD,IAAI,EAAE,KAAK,GACZ,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAKtC;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,OAAO,SAAS,UAAU,EAClD,GAAG,MAAM,EAAE,OAAO,GACnB,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAiBnC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACrB,KAAK,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACtC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAEvC,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAMzC;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,CAAC,IAAI,SAAS,MAAM,EACzB,KAAK,CAAC,MAAM,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAEvE,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,MAAM,GAAG,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,GACtD,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAiCxC"}
@@ -5,7 +5,7 @@
5
5
  * with stable metadata.
6
6
  */
7
7
  import { PresenceTag, SchemaTag } from "../kind/index.js";
8
- import { BaseGuard } from "../guard/index.js";
8
+ import { ArrayGuard, BaseGuard } from "../guard/index.js";
9
9
  import { isRecord, readGuardSchema } from "../internal/index.js";
10
10
  /**
11
11
  * @brief Build an array guard.
@@ -15,20 +15,13 @@ import { isRecord, readGuardSchema } from "../internal/index.js";
15
15
  * @returns Fresh array guard.
16
16
  */
17
17
  export function array(item) {
18
- return new BaseGuard({
18
+ return new ArrayGuard({
19
19
  tag: SchemaTag.Array,
20
- item: readGuardSchema(item, "array item")
20
+ item: readGuardSchema(item, "array item"),
21
+ checks: []
21
22
  });
22
23
  }
23
- /**
24
- * @brief Build a fixed-length tuple guard.
25
- * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
26
- * with stable metadata.
27
- * @param shape Ordered guard list for tuple indexes.
28
- * @returns Fresh tuple guard preserving item order.
29
- * @throws TypeError when shape is not an array-like tuple input.
30
- */
31
- export function tuple(shape) {
24
+ export function tuple(shape, rest) {
32
25
  const rawShape = shape;
33
26
  if (!Array.isArray(rawShape)) {
34
27
  throw new TypeError("tuple shape must be an array");
@@ -44,7 +37,10 @@ export function tuple(shape) {
44
37
  }
45
38
  return new BaseGuard({
46
39
  tag: SchemaTag.Tuple,
47
- items
40
+ items,
41
+ rest: rest === undefined
42
+ ? undefined
43
+ : readGuardSchema(rest, "tuple rest")
48
44
  });
49
45
  }
50
46
  /**
@@ -60,6 +56,19 @@ export function record(value) {
60
56
  value: readGuardSchema(value, "record value")
61
57
  });
62
58
  }
59
+ export function map(key, value) {
60
+ return new BaseGuard({
61
+ tag: SchemaTag.Map,
62
+ key: readGuardSchema(key, "map key"),
63
+ value: readGuardSchema(value, "map value")
64
+ });
65
+ }
66
+ export function set(item) {
67
+ return new BaseGuard({
68
+ tag: SchemaTag.Set,
69
+ item: readGuardSchema(item, "set item")
70
+ });
71
+ }
63
72
  /**
64
73
  * @brief Build a union guard from one or more guards.
65
74
  * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
@@ -4,10 +4,11 @@
4
4
  * @details This barrel keeps public import paths stable while implementation files remain
5
5
  * split by responsibility.
6
6
  */
7
- export { array, discriminatedUnion, intersect, record, tuple, union } from "./composite.js";
8
- export { lazy, nullable, optional, refine, undefinedable } from "./modifier.js";
9
- export { ObjectGuard, extend, object, omit, partial, pick, strictObject, type InferObject, type MergeObjectShapes, type ObjectGuardMode, type ObjectShape, type OmitObjectShape, type PartialObjectShape, type PickObjectShape } from "./object/index.js";
10
- export { bigintGuard, literal, neverGuard, symbolGuard, unknownGuard } from "./scalar.js";
7
+ export { array, discriminatedUnion, intersect, map, record, set, tuple, union } from "./composite.js";
8
+ export { lazy, nullable, nullish, optional, refine, undefinedable } from "./modifier.js";
9
+ export { ObjectGuard, catchall, deepPartial, extend, merge, object, omit, partial, passthrough, pick, required, safeExtend, strict, strictObject, strip, type DeepPartialObjectShape, type DeepPartialValue, type InferObject, type MaskSelectedKeys, type MergeObjectShapes, type ObjectKeyMask, type ObjectGuardMode, type ObjectShape, type OmitObjectShape, type OmitObjectShapeByMask, type PartialObjectShape, type PickObjectShape, type PickObjectShapeByMask, type RequiredObjectShape } from "./object/index.js";
10
+ export { bigintGuard, booleanGuard, dateGuard, enumValues, enumValues as enum, literal, neverGuard, nullGuard, numberGuard, symbolGuard, stringGuard, unknownGuard, undefinedGuard, voidGuard, type EnumValues } from "./scalar.js";
11
+ export { instanceOf, json, property, type InstanceConstructor, type JsonValue } from "./runtime.js";
11
12
  export { t } from "./table.js";
12
- export type { InferTuple, TupleShape } from "./types.js";
13
+ export type { InferTuple, InferTupleWithRest, TupleShape } from "./types.js";
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builders/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,KAAK,EACL,kBAAkB,EAClB,SAAS,EACT,MAAM,EACN,KAAK,EACL,KAAK,EACR,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACH,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,aAAa,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,WAAW,EACX,MAAM,EACN,MAAM,EACN,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,WAAW,EACX,OAAO,EACP,UAAU,EACV,WAAW,EACX,YAAY,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAC/B,YAAY,EACR,UAAU,EACV,UAAU,EACb,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builders/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,KAAK,EACL,kBAAkB,EAClB,SAAS,EACT,GAAG,EACH,MAAM,EACN,GAAG,EACH,KAAK,EACL,KAAK,EACR,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACH,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,MAAM,EACN,aAAa,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,WAAW,EACX,QAAQ,EACR,WAAW,EACX,MAAM,EACN,KAAK,EACL,MAAM,EACN,IAAI,EACJ,OAAO,EACP,WAAW,EACX,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,MAAM,EACN,YAAY,EACZ,KAAK,EACL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,UAAU,IAAI,IAAI,EAClB,OAAO,EACP,UAAU,EACV,SAAS,EACT,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,cAAc,EACd,SAAS,EACT,KAAK,UAAU,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAC/B,YAAY,EACR,UAAU,EACV,kBAAkB,EAClB,UAAU,EACb,MAAM,YAAY,CAAC"}
@@ -4,8 +4,9 @@
4
4
  * @details This barrel keeps public import paths stable while implementation files remain
5
5
  * split by responsibility.
6
6
  */
7
- export { array, discriminatedUnion, intersect, record, tuple, union } from "./composite.js";
8
- export { lazy, nullable, optional, refine, undefinedable } from "./modifier.js";
9
- export { ObjectGuard, extend, object, omit, partial, pick, strictObject } from "./object/index.js";
10
- export { bigintGuard, literal, neverGuard, symbolGuard, unknownGuard } from "./scalar.js";
7
+ export { array, discriminatedUnion, intersect, map, record, set, tuple, union } from "./composite.js";
8
+ export { lazy, nullable, nullish, optional, refine, undefinedable } from "./modifier.js";
9
+ export { ObjectGuard, catchall, deepPartial, extend, merge, object, omit, partial, passthrough, pick, required, safeExtend, strict, strictObject, strip } from "./object/index.js";
10
+ export { bigintGuard, booleanGuard, dateGuard, enumValues, enumValues as enum, literal, neverGuard, nullGuard, numberGuard, symbolGuard, stringGuard, unknownGuard, undefinedGuard, voidGuard } from "./scalar.js";
11
+ export { instanceOf, json, property } from "./runtime.js";
11
12
  export { t } from "./table.js";
@@ -29,6 +29,12 @@ export declare function undefinedable<TGuard extends Guard<unknown, Presence>>(g
29
29
  * @returns Fresh nullable guard preserving original presence.
30
30
  */
31
31
  export declare function nullable<TGuard extends Guard<unknown, Presence>>(guard: TGuard): BaseGuard<GuardValue<TGuard> | null, GuardPresence<TGuard>>;
32
+ /**
33
+ * @brief Allow null, undefined, and absent object keys.
34
+ * @param guard Guard to wrap.
35
+ * @returns Fresh optional guard whose value domain also includes null.
36
+ */
37
+ export declare function nullish<TGuard extends Guard<unknown, Presence>>(guard: TGuard): BaseGuard<GuardValue<TGuard> | null, "optional">;
32
38
  /**
33
39
  * @brief Resolve recursive schemas once and reuse the frozen schema handle.
34
40
  * @details Builder helpers normalize user-facing fluent calls into immutable schema nodes
@@ -1 +1 @@
1
- {"version":3,"file":"modifier.d.ts","sourceRoot":"","sources":["../../src/builders/modifier.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACH,SAAS,EACT,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,QAAQ,EAChB,MAAM,mBAAmB,CAAC;AAI3B;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC5D,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAK3C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACjE,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAKlE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC5D,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAK7D;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACxD,GAAG,EAAE,MAAM,MAAM,GAClB,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAgB1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC1D,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,EAC5C,IAAI,EAAE,MAAM,GACb,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAkBtD"}
1
+ {"version":3,"file":"modifier.d.ts","sourceRoot":"","sources":["../../src/builders/modifier.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACH,SAAS,EACT,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,QAAQ,EAChB,MAAM,mBAAmB,CAAC;AAI3B;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC5D,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAK3C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACjE,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAKlE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC5D,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAK7D;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC3D,KAAK,EAAE,MAAM,GACd,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAQlD;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EACxD,GAAG,EAAE,MAAM,MAAM,GAClB,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAgB1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,MAAM,SAAS,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC1D,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,EAC5C,IAAI,EAAE,MAAM,GACb,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAkBtD"}