typesea 0.1.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 (271) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +320 -0
  4. package/dist/adapters/index.d.ts +152 -0
  5. package/dist/adapters/index.d.ts.map +1 -0
  6. package/dist/adapters/index.js +396 -0
  7. package/dist/aot/index.d.ts +33 -0
  8. package/dist/aot/index.d.ts.map +1 -0
  9. package/dist/aot/index.js +295 -0
  10. package/dist/async/index.d.ts +111 -0
  11. package/dist/async/index.d.ts.map +1 -0
  12. package/dist/async/index.js +221 -0
  13. package/dist/builders/composite.d.ts +31 -0
  14. package/dist/builders/composite.d.ts.map +1 -0
  15. package/dist/builders/composite.js +165 -0
  16. package/dist/builders/index.d.ts +11 -0
  17. package/dist/builders/index.d.ts.map +1 -0
  18. package/dist/builders/index.js +9 -0
  19. package/dist/builders/modifier.d.ts +26 -0
  20. package/dist/builders/modifier.d.ts.map +1 -0
  21. package/dist/builders/modifier.js +67 -0
  22. package/dist/builders/object/guard.d.ts +62 -0
  23. package/dist/builders/object/guard.d.ts.map +1 -0
  24. package/dist/builders/object/guard.js +113 -0
  25. package/dist/builders/object/index.d.ts +7 -0
  26. package/dist/builders/object/index.d.ts.map +1 -0
  27. package/dist/builders/object/index.js +5 -0
  28. package/dist/builders/object/schema.d.ts +44 -0
  29. package/dist/builders/object/schema.d.ts.map +1 -0
  30. package/dist/builders/object/schema.js +257 -0
  31. package/dist/builders/object/types.d.ts +63 -0
  32. package/dist/builders/object/types.d.ts.map +1 -0
  33. package/dist/builders/object/types.js +5 -0
  34. package/dist/builders/scalar.d.ts +39 -0
  35. package/dist/builders/scalar.d.ts.map +1 -0
  36. package/dist/builders/scalar.js +63 -0
  37. package/dist/builders/table.d.ts +53 -0
  38. package/dist/builders/table.d.ts.map +1 -0
  39. package/dist/builders/table.js +48 -0
  40. package/dist/builders/types.d.ts +26 -0
  41. package/dist/builders/types.d.ts.map +1 -0
  42. package/dist/builders/types.js +5 -0
  43. package/dist/compile/check-composite.d.ts +34 -0
  44. package/dist/compile/check-composite.d.ts.map +1 -0
  45. package/dist/compile/check-composite.js +117 -0
  46. package/dist/compile/check-scalar.d.ts +24 -0
  47. package/dist/compile/check-scalar.d.ts.map +1 -0
  48. package/dist/compile/check-scalar.js +73 -0
  49. package/dist/compile/check.d.ts +15 -0
  50. package/dist/compile/check.d.ts.map +1 -0
  51. package/dist/compile/check.js +98 -0
  52. package/dist/compile/context.d.ts +35 -0
  53. package/dist/compile/context.d.ts.map +1 -0
  54. package/dist/compile/context.js +72 -0
  55. package/dist/compile/graph-predicate.d.ts +19 -0
  56. package/dist/compile/graph-predicate.d.ts.map +1 -0
  57. package/dist/compile/graph-predicate.js +460 -0
  58. package/dist/compile/guard.d.ts +41 -0
  59. package/dist/compile/guard.d.ts.map +1 -0
  60. package/dist/compile/guard.js +180 -0
  61. package/dist/compile/index.d.ts +8 -0
  62. package/dist/compile/index.d.ts.map +1 -0
  63. package/dist/compile/index.js +6 -0
  64. package/dist/compile/issue.d.ts +18 -0
  65. package/dist/compile/issue.d.ts.map +1 -0
  66. package/dist/compile/issue.js +28 -0
  67. package/dist/compile/names.d.ts +16 -0
  68. package/dist/compile/names.d.ts.map +1 -0
  69. package/dist/compile/names.js +82 -0
  70. package/dist/compile/predicate.d.ts +23 -0
  71. package/dist/compile/predicate.d.ts.map +1 -0
  72. package/dist/compile/predicate.js +317 -0
  73. package/dist/compile/runtime.d.ts +55 -0
  74. package/dist/compile/runtime.d.ts.map +1 -0
  75. package/dist/compile/runtime.js +63 -0
  76. package/dist/compile/source.d.ts +11 -0
  77. package/dist/compile/source.d.ts.map +1 -0
  78. package/dist/compile/source.js +51 -0
  79. package/dist/compile/types.d.ts +52 -0
  80. package/dist/compile/types.d.ts.map +1 -0
  81. package/dist/compile/types.js +5 -0
  82. package/dist/decoder/index.d.ts +106 -0
  83. package/dist/decoder/index.d.ts.map +1 -0
  84. package/dist/decoder/index.js +262 -0
  85. package/dist/evaluate/check-composite.d.ts +39 -0
  86. package/dist/evaluate/check-composite.d.ts.map +1 -0
  87. package/dist/evaluate/check-composite.js +184 -0
  88. package/dist/evaluate/check-scalar.d.ts +20 -0
  89. package/dist/evaluate/check-scalar.d.ts.map +1 -0
  90. package/dist/evaluate/check-scalar.js +81 -0
  91. package/dist/evaluate/check.d.ts +11 -0
  92. package/dist/evaluate/check.d.ts.map +1 -0
  93. package/dist/evaluate/check.js +126 -0
  94. package/dist/evaluate/index.d.ts +7 -0
  95. package/dist/evaluate/index.d.ts.map +1 -0
  96. package/dist/evaluate/index.js +6 -0
  97. package/dist/evaluate/issue.d.ts +10 -0
  98. package/dist/evaluate/issue.d.ts.map +1 -0
  99. package/dist/evaluate/issue.js +11 -0
  100. package/dist/evaluate/predicate.d.ts +26 -0
  101. package/dist/evaluate/predicate.d.ts.map +1 -0
  102. package/dist/evaluate/predicate.js +37 -0
  103. package/dist/evaluate/shared.d.ts +59 -0
  104. package/dist/evaluate/shared.d.ts.map +1 -0
  105. package/dist/evaluate/shared.js +96 -0
  106. package/dist/evaluate/state.d.ts +65 -0
  107. package/dist/evaluate/state.d.ts.map +1 -0
  108. package/dist/evaluate/state.js +66 -0
  109. package/dist/guard/base.d.ts +72 -0
  110. package/dist/guard/base.d.ts.map +1 -0
  111. package/dist/guard/base.js +136 -0
  112. package/dist/guard/error.d.ts +19 -0
  113. package/dist/guard/error.d.ts.map +1 -0
  114. package/dist/guard/error.js +22 -0
  115. package/dist/guard/index.d.ts +10 -0
  116. package/dist/guard/index.d.ts.map +1 -0
  117. package/dist/guard/index.js +8 -0
  118. package/dist/guard/number.d.ts +32 -0
  119. package/dist/guard/number.d.ts.map +1 -0
  120. package/dist/guard/number.js +71 -0
  121. package/dist/guard/props.d.ts +18 -0
  122. package/dist/guard/props.d.ts.map +1 -0
  123. package/dist/guard/props.js +35 -0
  124. package/dist/guard/read.d.ts +42 -0
  125. package/dist/guard/read.d.ts.map +1 -0
  126. package/dist/guard/read.js +114 -0
  127. package/dist/guard/registry.d.ts +15 -0
  128. package/dist/guard/registry.d.ts.map +1 -0
  129. package/dist/guard/registry.js +21 -0
  130. package/dist/guard/string.d.ts +36 -0
  131. package/dist/guard/string.d.ts.map +1 -0
  132. package/dist/guard/string.js +95 -0
  133. package/dist/guard/types.d.ts +103 -0
  134. package/dist/guard/types.d.ts.map +1 -0
  135. package/dist/guard/types.js +5 -0
  136. package/dist/index.d.ts +14 -0
  137. package/dist/index.d.ts.map +1 -0
  138. package/dist/index.js +10 -0
  139. package/dist/internal/index.d.ts +34 -0
  140. package/dist/internal/index.d.ts.map +1 -0
  141. package/dist/internal/index.js +56 -0
  142. package/dist/ir/builder.d.ts +173 -0
  143. package/dist/ir/builder.d.ts.map +1 -0
  144. package/dist/ir/builder.js +481 -0
  145. package/dist/ir/freeze.d.ts +10 -0
  146. package/dist/ir/freeze.d.ts.map +1 -0
  147. package/dist/ir/freeze.js +102 -0
  148. package/dist/ir/index.d.ts +9 -0
  149. package/dist/ir/index.d.ts.map +1 -0
  150. package/dist/ir/index.js +7 -0
  151. package/dist/ir/regexp.d.ts +6 -0
  152. package/dist/ir/regexp.d.ts.map +1 -0
  153. package/dist/ir/regexp.js +12 -0
  154. package/dist/ir/types.d.ts +215 -0
  155. package/dist/ir/types.d.ts.map +1 -0
  156. package/dist/ir/types.js +5 -0
  157. package/dist/ir/validate.d.ts +10 -0
  158. package/dist/ir/validate.d.ts.map +1 -0
  159. package/dist/ir/validate.js +271 -0
  160. package/dist/issue/index.d.ts +44 -0
  161. package/dist/issue/index.d.ts.map +1 -0
  162. package/dist/issue/index.js +152 -0
  163. package/dist/json-schema/emit-combinator.d.ts +28 -0
  164. package/dist/json-schema/emit-combinator.d.ts.map +1 -0
  165. package/dist/json-schema/emit-combinator.js +96 -0
  166. package/dist/json-schema/emit-composite.d.ts +28 -0
  167. package/dist/json-schema/emit-composite.d.ts.map +1 -0
  168. package/dist/json-schema/emit-composite.js +127 -0
  169. package/dist/json-schema/emit-scalar.d.ts +25 -0
  170. package/dist/json-schema/emit-scalar.d.ts.map +1 -0
  171. package/dist/json-schema/emit-scalar.js +104 -0
  172. package/dist/json-schema/emit-types.d.ts +12 -0
  173. package/dist/json-schema/emit-types.d.ts.map +1 -0
  174. package/dist/json-schema/emit-types.js +5 -0
  175. package/dist/json-schema/emit.d.ts +12 -0
  176. package/dist/json-schema/emit.d.ts.map +1 -0
  177. package/dist/json-schema/emit.js +62 -0
  178. package/dist/json-schema/freeze.d.ts +14 -0
  179. package/dist/json-schema/freeze.d.ts.map +1 -0
  180. package/dist/json-schema/freeze.js +114 -0
  181. package/dist/json-schema/index.d.ts +20 -0
  182. package/dist/json-schema/index.d.ts.map +1 -0
  183. package/dist/json-schema/index.js +76 -0
  184. package/dist/json-schema/issue.d.ts +11 -0
  185. package/dist/json-schema/issue.d.ts.map +1 -0
  186. package/dist/json-schema/issue.js +14 -0
  187. package/dist/json-schema/read.d.ts +29 -0
  188. package/dist/json-schema/read.d.ts.map +1 -0
  189. package/dist/json-schema/read.js +87 -0
  190. package/dist/json-schema/types.d.ts +106 -0
  191. package/dist/json-schema/types.d.ts.map +1 -0
  192. package/dist/json-schema/types.js +5 -0
  193. package/dist/kind/index.d.ts +119 -0
  194. package/dist/kind/index.d.ts.map +1 -0
  195. package/dist/kind/index.js +94 -0
  196. package/dist/lower/index.d.ts +7 -0
  197. package/dist/lower/index.d.ts.map +1 -0
  198. package/dist/lower/index.js +199 -0
  199. package/dist/message/index.d.ts +51 -0
  200. package/dist/message/index.d.ts.map +1 -0
  201. package/dist/message/index.js +269 -0
  202. package/dist/optimize/compact.d.ts +10 -0
  203. package/dist/optimize/compact.d.ts.map +1 -0
  204. package/dist/optimize/compact.js +60 -0
  205. package/dist/optimize/fold-boolean.d.ts +15 -0
  206. package/dist/optimize/fold-boolean.d.ts.map +1 -0
  207. package/dist/optimize/fold-boolean.js +75 -0
  208. package/dist/optimize/fold-common.d.ts +45 -0
  209. package/dist/optimize/fold-common.d.ts.map +1 -0
  210. package/dist/optimize/fold-common.js +71 -0
  211. package/dist/optimize/fold-scalar.d.ts +59 -0
  212. package/dist/optimize/fold-scalar.d.ts.map +1 -0
  213. package/dist/optimize/fold-scalar.js +174 -0
  214. package/dist/optimize/fold.d.ts +10 -0
  215. package/dist/optimize/fold.d.ts.map +1 -0
  216. package/dist/optimize/fold.js +103 -0
  217. package/dist/optimize/index.d.ts +10 -0
  218. package/dist/optimize/index.d.ts.map +1 -0
  219. package/dist/optimize/index.js +23 -0
  220. package/dist/optimize/map-node.d.ts +21 -0
  221. package/dist/optimize/map-node.d.ts.map +1 -0
  222. package/dist/optimize/map-node.js +222 -0
  223. package/dist/optimize/remap.d.ts +30 -0
  224. package/dist/optimize/remap.d.ts.map +1 -0
  225. package/dist/optimize/remap.js +46 -0
  226. package/dist/optimize/rewrite.d.ts +22 -0
  227. package/dist/optimize/rewrite.d.ts.map +1 -0
  228. package/dist/optimize/rewrite.js +34 -0
  229. package/dist/plan/cache.d.ts +20 -0
  230. package/dist/plan/cache.d.ts.map +1 -0
  231. package/dist/plan/cache.js +122 -0
  232. package/dist/plan/index.d.ts +8 -0
  233. package/dist/plan/index.d.ts.map +1 -0
  234. package/dist/plan/index.js +6 -0
  235. package/dist/plan/predicate.d.ts +27 -0
  236. package/dist/plan/predicate.d.ts.map +1 -0
  237. package/dist/plan/predicate.js +415 -0
  238. package/dist/plan/schema-predicate.d.ts +15 -0
  239. package/dist/plan/schema-predicate.d.ts.map +1 -0
  240. package/dist/plan/schema-predicate.js +277 -0
  241. package/dist/plan/types.d.ts +18 -0
  242. package/dist/plan/types.d.ts.map +1 -0
  243. package/dist/plan/types.js +5 -0
  244. package/dist/result/index.d.ts +27 -0
  245. package/dist/result/index.d.ts.map +1 -0
  246. package/dist/result/index.js +20 -0
  247. package/dist/schema/common.d.ts +30 -0
  248. package/dist/schema/common.d.ts.map +1 -0
  249. package/dist/schema/common.js +102 -0
  250. package/dist/schema/freeze.d.ts +10 -0
  251. package/dist/schema/freeze.d.ts.map +1 -0
  252. package/dist/schema/freeze.js +163 -0
  253. package/dist/schema/index.d.ts +11 -0
  254. package/dist/schema/index.d.ts.map +1 -0
  255. package/dist/schema/index.js +9 -0
  256. package/dist/schema/lazy.d.ts +10 -0
  257. package/dist/schema/lazy.d.ts.map +1 -0
  258. package/dist/schema/lazy.js +25 -0
  259. package/dist/schema/literal.d.ts +10 -0
  260. package/dist/schema/literal.d.ts.map +1 -0
  261. package/dist/schema/literal.js +17 -0
  262. package/dist/schema/types.d.ts +243 -0
  263. package/dist/schema/types.d.ts.map +1 -0
  264. package/dist/schema/types.js +9 -0
  265. package/dist/schema/validate.d.ts +10 -0
  266. package/dist/schema/validate.d.ts.map +1 -0
  267. package/dist/schema/validate.js +268 -0
  268. package/docs/api.md +301 -0
  269. package/docs/engine-notes.md +153 -0
  270. package/docs/index.html +1242 -0
  271. package/package.json +68 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Added the initial zero-dependency TypeSea runtime narrowing API.
6
+ - Added interpreted, compiled, and AOT validation paths with parity coverage.
7
+ - Added Sea-of-Nodes graph introspection and optimizer validation.
8
+ - Added JSON Schema export, tRPC, Fastify, and React Hook Form adapters.
9
+ - Added release gates, package surface checks, and benchmark smoke coverage.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Feralthedogg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,320 @@
1
+ # TypeSea
2
+
3
+ [![CI](https://github.com/Feralthedogg/TypeSea/actions/workflows/ci.yml/badge.svg)](https://github.com/Feralthedogg/TypeSea/actions/workflows/ci.yml)
4
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
5
+ ![TypeScript](https://img.shields.io/badge/language-TypeScript-informational)
6
+ ![Dependencies](https://img.shields.io/badge/runtime%20deps-zero-brightgreen)
7
+ ![Module](https://img.shields.io/badge/module-ESM--only-orange)
8
+ ![Node](https://img.shields.io/badge/node-%3E%3D20.19-yellowgreen)
9
+
10
+ **TypeSea** is a **zero-runtime-dependency TypeScript runtime narrowing library**
11
+ built around **immutable guards**, optimized **Sea-of-Nodes validation plans**,
12
+ runtime compilation, and AOT source generation.
13
+
14
+ > Goal: not "probably valid", but **provably parity-tested validation** that
15
+ > never executes user code, never throws on expected failures, and never leaks
16
+ > mutable state across a public boundary.
17
+
18
+ > [!IMPORTANT]
19
+ > TypeSea is designed for **hostile boundary data**: property reads go through
20
+ > descriptors so **user getters never execute**, `__proto__`/`constructor` keys
21
+ > are handled with null-prototype lookups, user regexes are cloned and
22
+ > `lastIndex`-reset, and cyclic inputs validate finitely. Expected failures
23
+ > return frozen `Result` values — `any`, `try`, and `catch` are banned from the
24
+ > entire codebase and enforced by policy gates.
25
+
26
+ ---
27
+
28
+ ## Why
29
+
30
+ Many validation libraries fall short when you care about:
31
+
32
+ - **untrusted input that fights back** (getters with side effects, prototype
33
+ pollution keys, forged schema objects, revoked proxies)
34
+ - **identical verdicts across execution strategies** (runtime plan vs compiled
35
+ vs AOT-generated validators)
36
+ - **diagnostics without exceptions** (`Result` values instead of `throw`)
37
+ - **immutability at every public boundary**
38
+
39
+ TypeSea focuses on:
40
+
41
+ - **no user-code execution during validation**
42
+ - **runtime plan / compiled / AOT parity, enforced by a seeded generative fuzzer**
43
+ - **injection-safe code generation** (side tables, never string interpolation)
44
+ - **explicit presence semantics** (`optional` vs `undefinedable`)
45
+
46
+ ---
47
+
48
+ ## Key Properties
49
+
50
+ - **Zero dependencies**: no runtime, peer, optional, or bundled dependencies —
51
+ mechanically enforced by package policy before every release.
52
+ - **Three engines, one semantics**: `is()`/`check()` execute a cached validation
53
+ plan, `compile()` emits runtime predicates from optimized IR, and
54
+ `emitAotModule()` emits standalone validator source. The runtime plan owns
55
+ both the graph and a schema-specialized kernel, so the graph is the source of
56
+ truth for generated validators without forcing ordinary `is()` through a
57
+ per-node interpreter. Parity is fuzz-tested with sparse arrays, accessor
58
+ properties, symbol keys, and non-enumerable extras included.
59
+ - **Frozen public surface**: guards, schemas, graphs, diagnostics, and JSON
60
+ Schema payloads are frozen before they cross an API boundary.
61
+ - **Lossless-only export**: JSON Schema and AOT export succeed only when no
62
+ semantics would be lost; runtime-only contracts return typed issues instead
63
+ of silently weakening the schema.
64
+
65
+ > [!NOTE]
66
+ > TypeSea is **ESM-only**: the package ships `"type": "module"` with no
67
+ > CommonJS build. Node.js `>= 20.19` can also load it via `require(esm)`
68
+ > through the `default` export condition.
69
+
70
+ ---
71
+
72
+ ## Quick Start
73
+
74
+ ```ts
75
+ import { compile, t, toJsonSchema, type Infer } from "typesea";
76
+
77
+ const User = t.strictObject({
78
+ id: t.string.uuid(),
79
+ age: t.number.int().gte(0),
80
+ role: t.union(t.literal("admin"), t.literal("user"))
81
+ });
82
+
83
+ type User = Infer<typeof User>;
84
+
85
+ // 1) Boolean narrowing — avoids diagnostic allocation on success
86
+ if (User.is(input)) {
87
+ input.id; // narrowed
88
+ }
89
+
90
+ // 2) Immutable diagnostics — frozen Result, never throws on expected failure
91
+ const checked = User.check(input);
92
+ if (!checked.ok) {
93
+ console.log(checked.error); // frozen issue list with paths
94
+ }
95
+
96
+ // 3) Hot path — generated validator code
97
+ const FastUser = compile(User, { name: "isUser" });
98
+
99
+ // 4) Interop — lossless-only JSON Schema export
100
+ const schema = toJsonSchema(User);
101
+ ```
102
+
103
+ Use `is()` for the allocation-light boolean path. Use `check()` when callers
104
+ need immutable diagnostics. Use `compile()` or `emitAotModule()` when a stable
105
+ schema is hot enough to deserve generated validator code.
106
+
107
+ > [!CAUTION]
108
+ > `compile()` builds the validator with `new Function`, which throws under a
109
+ > Content-Security-Policy that forbids `unsafe-eval`. In CSP-restricted
110
+ > environments, generate validator source ahead of time with
111
+ > `emitAotModule()` instead.
112
+
113
+ ---
114
+
115
+ ## Presence Semantics
116
+
117
+ Object presence is explicit — two different wrappers express two different
118
+ contracts:
119
+
120
+ | Wrapper | Key may be absent | Value may be `undefined` | Inferred type |
121
+ | --- | --- | --- | --- |
122
+ | `t.optional(inner)` | yes | no | `key?: T` |
123
+ | `t.undefinedable(inner)` | no | yes | `key: T \| undefined` |
124
+ | `t.nullable(inner)` | — | value may be `null` | `key: T \| null` |
125
+
126
+ > [!NOTE]
127
+ > Presence survives wrapper composition: `t.nullable(t.optional(x))` still
128
+ > means "the key may be absent" — inference and runtime agree on this under
129
+ > `exactOptionalPropertyTypes`.
130
+
131
+ ---
132
+
133
+ ## Execution Model
134
+
135
+ TypeSea keeps the public schema tree for builder validation and diagnostics,
136
+ then lowers each schema identity into a cached validation plan. The plan owns an
137
+ optimized Sea-of-Nodes graph and a schema-specialized predicate kernel.
138
+ `Guard.is()` uses the kernel to avoid per-node interpreter dispatch, while
139
+ `compile()` and `emitAotModule()` emit predicates from the optimized graph.
140
+ `check()` first asks the same plan for the verdict; failed values then replay
141
+ the schema-aware diagnostic collector to produce issue paths and codes.
142
+
143
+ ```text
144
+ builder -> frozen schema -> lower -> Sea-of-Nodes IR -> optimize
145
+ optimize -> ValidationPlan { graph, schema kernel }
146
+ schema kernel -> Guard.is() / check() preflight
147
+ graph -> compile() predicate / emitAotModule() predicate / Guard.graph()
148
+ failed check() -> schema-aware diagnostic collector
149
+ ```
150
+
151
+ > [!IMPORTANT]
152
+ > Generated validators keep **user-controlled values out of source text**:
153
+ > literals, regexps, object keys, keysets, and dynamic schema fallbacks live in
154
+ > **side tables** referenced by numeric index. Hostile property names cannot
155
+ > escape into generated code — this is pinned by dedicated injection-audit
156
+ > tests.
157
+
158
+ ---
159
+
160
+ ## Performance Snapshot
161
+
162
+ Last local release smoke on 2026-07-04 KST, using
163
+ `npm run release:check` on the benchmark strict-object contract. These are
164
+ operations per second on one machine, not release guarantees.
165
+
166
+ | Valid object path | hz |
167
+ | --- | ---: |
168
+ | TypeSea interpreted `is()` | 496,270 |
169
+ | TypeSea compiled `is()` | 4,237,892 |
170
+ | Zod `safeParse` | 1,363,792 |
171
+ | Valibot `safeParse` | 1,384,892 |
172
+ | Ajv compiled | 4,312,174 |
173
+
174
+ | Invalid object path | hz |
175
+ | --- | ---: |
176
+ | TypeSea interpreted `is()` | 3,422,416 |
177
+ | TypeSea compiled `is()` | 27,125,445 |
178
+ | Zod `safeParse` | 83,501 |
179
+ | Valibot `safeParse` | 902,616 |
180
+ | Ajv compiled | 28,953,501 |
181
+
182
+ The compiled path stays close to Ajv while retaining TypeSea semantics:
183
+ descriptor-based property reads, symbol/non-enumerable strict-key rejection,
184
+ presence semantics, immutable diagnostics, and TypeScript guard inference.
185
+
186
+ ---
187
+
188
+ ## API Reference
189
+
190
+ All public entry points are exported from the package root; builders are also
191
+ grouped under the `t` table.
192
+
193
+ ### Builders
194
+
195
+ | Area | Entry points |
196
+ | --- | --- |
197
+ | Scalar guards | `t.unknown`, `t.never`, `t.string`, `t.number`, `t.bigint`, `t.symbol`, `t.boolean` |
198
+ | Literal and containers | `t.literal`, `t.array`, `t.tuple`, `t.record` |
199
+ | Objects | `t.object`, `t.strictObject`, `extend`, `pick`, `omit`, `partial` |
200
+ | Composition | `t.union`, `t.discriminatedUnion`, `t.intersect`, `guard.intersect` |
201
+ | Presence wrappers | `t.optional`, `t.undefinedable`, `t.nullable` |
202
+ | Dynamic contracts | `t.lazy`, `t.refine` |
203
+
204
+ ### Decoders
205
+
206
+ | Area | Entry points |
207
+ | --- | --- |
208
+ | Sync decoders | `t.decoder`, `t.transform`, `t.pipe`, `t.coerce` |
209
+ | Async decoders | `t.asyncDecoder`, `t.asyncRefine`, `t.asyncTransform`, `t.asyncPipe` |
210
+
211
+ ### Execution & Export
212
+
213
+ | Area | Entry points |
214
+ | --- | --- |
215
+ | Guard methods | `guard.is()`, `guard.check()`, `guard.graph()` |
216
+ | Generated validators | `compile`, `emitAotModule` |
217
+ | JSON Schema | `toJsonSchema` |
218
+
219
+ ### Messages & Adapters
220
+
221
+ | Area | Entry points |
222
+ | --- | --- |
223
+ | Messages / i18n | `formatIssue`, `formatIssues`, `withMessages`, `defineMessages` |
224
+ | tRPC | `toTrpcParser`, `toAsyncTrpcParser` |
225
+ | Fastify | `toFastifyRouteSchema`, `toFastifyValidatorCompiler` |
226
+ | React Hook Form | `toReactHookFormResolver` |
227
+
228
+ > [!TIP]
229
+ > Match the inference alias to the source kind: `Infer<>` for guards,
230
+ > `InferDecoder<>` for decoders, `InferAsyncDecoder<>` for async decoders.
231
+ > Applying `Infer<>` to a decoder resolves to `never` — if a downstream type
232
+ > suddenly collapses, this is the first thing to check.
233
+
234
+ ---
235
+
236
+ ## Edge Semantics
237
+
238
+ Deliberate, documented, and pinned by tests:
239
+
240
+ | Input | Behavior |
241
+ | --- | --- |
242
+ | `NaN`, `Infinity` | rejected by `t.number` (finite numbers only); `t.literal(NaN)` matches `NaN` |
243
+ | `-0` vs `0` | literals match via `Object.is`; diagnostics format `-0` distinctly |
244
+ | Getter-backed properties | never executed; treated as missing/invalid data |
245
+ | `__proto__`, `constructor` keys | validated as plain own keys, no pollution |
246
+ | Sparse array holes | read as `undefined` without executing accessors |
247
+ | Strict object extras | rejected via `Reflect.ownKeys` — including symbol keys and non-enumerable properties |
248
+ | Global-flag regexes | cloned at construction; `lastIndex` reset before every test |
249
+ | UUID | accepts RFC 9562 versions 1–8 plus the nil UUID |
250
+ | Cyclic input values | validate finitely via (value × schema) active-pair tracking |
251
+ | Nesting depth | capped at 256 recursive frames; deeper input fails instead of overflowing the stack |
252
+
253
+ ---
254
+
255
+ ## Best Practices & Pitfalls
256
+
257
+ > [!WARNING]
258
+ > **Recursive guards need an explicit type annotation.** TypeScript cannot
259
+ > infer a self-referential initializer (TS7022):
260
+ >
261
+ > ```ts
262
+ > interface ListNode {
263
+ > readonly value: string;
264
+ > readonly next?: ListNode;
265
+ > }
266
+ >
267
+ > const Node: Guard<ListNode> = t.lazy((): Guard<ListNode> =>
268
+ > t.object({ value: t.string, next: t.optional(Node) })
269
+ > );
270
+ > ```
271
+
272
+ - **Boundary data enters as `unknown`.** Do not pre-narrow with `as` — the
273
+ builder API is typed so that narrowing happens through validation.
274
+ - **Recursive contracts go through `t.lazy`.** Direct schema object cycles are
275
+ rejected at construction.
276
+ - **Choose the engine by schema lifetime.** One-off schemas: runtime plan.
277
+ Stable hot schemas: `compile()`. CSP environments or build-time generation:
278
+ `emitAotModule()`.
279
+ - **Decoders do not embed in object shapes.** Compose transformations with
280
+ `t.pipe` around a validated shape instead of mixing decoders into `t.object`
281
+ entries.
282
+
283
+ ---
284
+
285
+ ## Verification
286
+
287
+ Every gate that CI runs is a local npm script:
288
+
289
+ ```sh
290
+ npm run check # policy, docs, typecheck, lint, tests, build, dist, API snapshot, pack
291
+ npm run check:consumer # tarball install + runtime/type smoke in a temp project
292
+ npm run bench -- --run # benchmark smoke
293
+ npm run pack:dry # package contents dry run
294
+ npm run release:check # the full pre-publish gate (everything above)
295
+ ```
296
+
297
+ `npm run release:check` runs the same gate expected before publishing:
298
+ typecheck, lint, tests, build, docs smoke, dist policy, public API snapshot,
299
+ package contents, consumer install, benchmark smoke, and pack dry run.
300
+ CI executes it on Node 20.19, 22, and 24; releases publish with npm provenance.
301
+
302
+ > [!NOTE]
303
+ > Benchmark comparison packages (Zod, Valibot, Ajv) are dev dependencies only —
304
+ > package policy rejects them from every runtime dependency field. The
305
+ > benchmark suite reports both boolean-path and diagnostic-path
306
+ > (`check()` vs `safeParse`) comparisons, so numbers stay apples-to-apples.
307
+
308
+ ---
309
+
310
+ ## Documentation
311
+
312
+ - [Documentation site](https://feralthedogg.github.io/TypeSea/)
313
+ - [API reference](docs/api.md)
314
+ - [Engine notes](docs/engine-notes.md)
315
+
316
+ ---
317
+
318
+ ## License
319
+
320
+ MIT License. See [LICENSE](./LICENSE).
@@ -0,0 +1,152 @@
1
+ import { type AsyncDecodeSource, type InferAsyncDecoder } from "../async/index.js";
2
+ import { type DecodeSource, type InferDecoder } from "../decoder/index.js";
3
+ import { TypeSeaAssertionError, type Guard, type Presence } from "../guard/index.js";
4
+ import { type IssueMessageOptions } from "../message/index.js";
5
+ import type { Result } from "../result/index.js";
6
+ import { type JsonSchema, type JsonSchemaDialect, type JsonSchemaExportIssue } from "../json-schema/index.js";
7
+ /**
8
+ * @brief sync adapter source.
9
+ */
10
+ export type SyncAdapterSource = DecodeSource;
11
+ /**
12
+ * @brief infer sync adapter.
13
+ */
14
+ export type InferSyncAdapter<TSource> = InferDecoder<TSource>;
15
+ /**
16
+ * @brief infer adapter.
17
+ */
18
+ export type InferAdapter<TSource> = InferAsyncDecoder<TSource>;
19
+ /**
20
+ * @brief trpc parser.
21
+ */
22
+ export interface TrpcParser<TValue> {
23
+ readonly parse: (value: unknown) => TValue;
24
+ }
25
+ /**
26
+ * @brief async trpc parser.
27
+ */
28
+ export interface AsyncTrpcParser<TValue> {
29
+ readonly parseAsync: (value: unknown) => Promise<TValue>;
30
+ }
31
+ /**
32
+ * @brief fastify route schema.
33
+ */
34
+ export interface FastifyRouteSchema {
35
+ readonly body?: JsonSchema;
36
+ readonly querystring?: JsonSchema;
37
+ readonly params?: JsonSchema;
38
+ readonly headers?: JsonSchema;
39
+ readonly response?: Readonly<Record<string, JsonSchema>>;
40
+ }
41
+ /**
42
+ * @brief fastify http part.
43
+ */
44
+ export type FastifyHttpPart = "body" | "querystring" | "params" | "headers";
45
+ /**
46
+ * @brief fastify route schema options.
47
+ */
48
+ export interface FastifyRouteSchemaOptions {
49
+ readonly part: FastifyHttpPart;
50
+ /**
51
+ * @brief schema id.
52
+ * @details Forwards a concrete `$schema` marker to the JSON Schema exporter.
53
+ * @invariant When omitted, TypeSea emits its conservative default dialect marker.
54
+ */
55
+ readonly schemaId?: string;
56
+ /**
57
+ * @brief dialect.
58
+ * @details Selects the JSON Schema keyword set used by generated route schemas.
59
+ * @invariant Tuple schemas remain validator-visible for the selected dialect.
60
+ */
61
+ readonly dialect?: JsonSchemaDialect;
62
+ }
63
+ /**
64
+ * @brief fastify validator route.
65
+ */
66
+ export interface FastifyValidatorRoute {
67
+ readonly schema: unknown;
68
+ readonly method: string | undefined;
69
+ readonly url: string | undefined;
70
+ readonly httpPart: string | undefined;
71
+ }
72
+ /**
73
+ * @brief fastify validation result.
74
+ */
75
+ export type FastifyValidationResult = {
76
+ readonly value: unknown;
77
+ } | {
78
+ readonly error: TypeSeaAssertionError;
79
+ };
80
+ /**
81
+ * @brief fastify validator.
82
+ */
83
+ export type FastifyValidator = (value: unknown) => FastifyValidationResult;
84
+ /**
85
+ * @brief fastify validator compiler.
86
+ */
87
+ export type FastifyValidatorCompiler = (route: FastifyValidatorRoute) => FastifyValidator;
88
+ /**
89
+ * @brief fastify validator compiler source map.
90
+ * @details Maps one Fastify payload channel to the TypeSea source that owns that channel.
91
+ * @invariant Only supported Fastify HTTP parts are consulted by the compiler.
92
+ */
93
+ export type FastifyValidatorCompilerSourceMap = Readonly<Partial<Record<FastifyHttpPart, SyncAdapterSource>>>;
94
+ /**
95
+ * @brief fastify validator compiler source.
96
+ * @details Accepts the historical single-source form or an explicit route-part map.
97
+ * @invariant A mapped source is selected by `route.httpPart` before validation.
98
+ */
99
+ export type FastifyValidatorCompilerSource = SyncAdapterSource | FastifyValidatorCompilerSourceMap;
100
+ /**
101
+ * @brief react hook form field error.
102
+ */
103
+ export interface ReactHookFormFieldError {
104
+ readonly type: string;
105
+ readonly message: string;
106
+ }
107
+ /**
108
+ * @brief react hook form errors.
109
+ * @details Defines the nested field-error tree React Hook Form traverses by path segment.
110
+ * @invariant Branches are frozen objects and leaves are frozen `ReactHookFormFieldError` values.
111
+ */
112
+ export interface ReactHookFormErrors {
113
+ readonly [key: string]: ReactHookFormFieldError | ReactHookFormErrors;
114
+ }
115
+ /**
116
+ * @brief react hook form resolver result.
117
+ */
118
+ export interface ReactHookFormResolverResult<TValue> {
119
+ readonly values: TValue | Readonly<Record<string, never>>;
120
+ readonly errors: ReactHookFormErrors;
121
+ }
122
+ /**
123
+ * @brief react hook form resolver.
124
+ */
125
+ export type ReactHookFormResolver<TValue> = (values: unknown, context: unknown, options: unknown) => Promise<ReactHookFormResolverResult<TValue>>;
126
+ /**
127
+ * @brief react hook form resolver options.
128
+ */
129
+ export interface ReactHookFormResolverOptions {
130
+ readonly messages: Partial<IssueMessageOptions> | undefined;
131
+ }
132
+ /**
133
+ * @brief to trpc parser.
134
+ */
135
+ export declare function toTrpcParser<TSource extends SyncAdapterSource>(source: TSource): TrpcParser<InferSyncAdapter<TSource>>;
136
+ /**
137
+ * @brief to async trpc parser.
138
+ */
139
+ export declare function toAsyncTrpcParser<TSource extends AsyncDecodeSource>(source: TSource): AsyncTrpcParser<InferAdapter<TSource>>;
140
+ /**
141
+ * @brief to fastify route schema.
142
+ */
143
+ export declare function toFastifyRouteSchema(guard: Guard<unknown, Presence>, options?: Partial<FastifyRouteSchemaOptions>): Result<FastifyRouteSchema, readonly JsonSchemaExportIssue[]>;
144
+ /**
145
+ * @brief to fastify validator compiler.
146
+ */
147
+ export declare function toFastifyValidatorCompiler(source: FastifyValidatorCompilerSource): FastifyValidatorCompiler;
148
+ /**
149
+ * @brief to react hook form resolver.
150
+ */
151
+ export declare function toReactHookFormResolver<TSource extends AsyncDecodeSource>(source: TSource, options?: Partial<ReactHookFormResolverOptions>): ReactHookFormResolver<InferAdapter<TSource>>;
152
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,iBAAiB,EAEvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EAElB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,qBAAqB,EACrB,KAAK,KAAK,EACV,KAAK,QAAQ,EACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC3B,MAAM,yBAAyB,CAAC;AAGjC;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,OAAO,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,MAAM;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,MAAM;IACrC,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,aAAa,GACb,QAAQ,GACR,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAE/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAC/B;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,uBAAuB,CAAC;AAE3E;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,KAAK,EAAE,qBAAqB,KACzB,gBAAgB,CAAC;AAEtB;;;;GAIG;AACH,MAAM,MAAM,iCAAiC,GAAG,QAAQ,CACtD,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC,CACpD,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,8BAA8B,GACtC,iBAAiB,GACjB,iCAAiC,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,uBAAuB,GAAG,mBAAmB,CAAC;CACvE;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B,CAAC,MAAM;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAAC,MAAM,IAAI,CAC1C,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,SAAS,iBAAiB,EAC5D,MAAM,EAAE,OAAO,GACd,UAAU,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAWvC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,iBAAiB,EACjE,MAAM,EAAE,OAAO,GACd,eAAe,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAWxC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,EAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAC3C,MAAM,CAAC,kBAAkB,EAAE,SAAS,qBAAqB,EAAE,CAAC,CAY9D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,8BAA8B,GACrC,wBAAwB,CAgB1B;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,SAAS,iBAAiB,EACvE,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE,OAAO,CAAC,4BAA4B,CAAC,GAC9C,qBAAqB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAkB9C"}