typesea 0.1.0 → 0.2.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 (285) hide show
  1. package/CHANGELOG.md +67 -6
  2. package/README.md +98 -17
  3. package/dist/adapters/index.d.ts +50 -8
  4. package/dist/adapters/index.d.ts.map +1 -1
  5. package/dist/adapters/index.js +169 -48
  6. package/dist/aot/index.d.ts +18 -2
  7. package/dist/aot/index.d.ts.map +1 -1
  8. package/dist/aot/index.js +93 -14
  9. package/dist/async/index.d.ts +28 -56
  10. package/dist/async/index.d.ts.map +1 -1
  11. package/dist/async/index.js +94 -37
  12. package/dist/builders/composite.d.ts +37 -6
  13. package/dist/builders/composite.d.ts.map +1 -1
  14. package/dist/builders/composite.js +84 -10
  15. package/dist/builders/index.d.ts +2 -0
  16. package/dist/builders/index.d.ts.map +1 -1
  17. package/dist/builders/index.js +2 -0
  18. package/dist/builders/modifier.d.ts +30 -5
  19. package/dist/builders/modifier.d.ts.map +1 -1
  20. package/dist/builders/modifier.js +38 -5
  21. package/dist/builders/object/guard.d.ts +18 -22
  22. package/dist/builders/object/guard.d.ts.map +1 -1
  23. package/dist/builders/object/guard.js +26 -26
  24. package/dist/builders/object/index.d.ts +2 -0
  25. package/dist/builders/object/index.d.ts.map +1 -1
  26. package/dist/builders/object/index.js +2 -0
  27. package/dist/builders/object/schema.d.ts +55 -9
  28. package/dist/builders/object/schema.d.ts.map +1 -1
  29. package/dist/builders/object/schema.js +92 -15
  30. package/dist/builders/object/types.d.ts +5 -31
  31. package/dist/builders/object/types.d.ts.map +1 -1
  32. package/dist/builders/object/types.js +2 -0
  33. package/dist/builders/scalar.d.ts +29 -8
  34. package/dist/builders/scalar.d.ts.map +1 -1
  35. package/dist/builders/scalar.js +33 -8
  36. package/dist/builders/table.d.ts +4 -0
  37. package/dist/builders/table.d.ts.map +1 -1
  38. package/dist/builders/table.js +4 -0
  39. package/dist/builders/types.d.ts +14 -4
  40. package/dist/builders/types.d.ts.map +1 -1
  41. package/dist/builders/types.js +2 -0
  42. package/dist/compile/check-composite.d.ts +22 -1
  43. package/dist/compile/check-composite.d.ts.map +1 -1
  44. package/dist/compile/check-composite.js +564 -24
  45. package/dist/compile/check-scalar.d.ts +78 -0
  46. package/dist/compile/check-scalar.d.ts.map +1 -1
  47. package/dist/compile/check-scalar.js +432 -1
  48. package/dist/compile/check.d.ts +12 -0
  49. package/dist/compile/check.d.ts.map +1 -1
  50. package/dist/compile/check.js +37 -0
  51. package/dist/compile/context.d.ts +47 -9
  52. package/dist/compile/context.d.ts.map +1 -1
  53. package/dist/compile/context.js +51 -8
  54. package/dist/compile/graph-predicate.d.ts +4 -2
  55. package/dist/compile/graph-predicate.d.ts.map +1 -1
  56. package/dist/compile/graph-predicate.js +1907 -171
  57. package/dist/compile/guard.d.ts +15 -24
  58. package/dist/compile/guard.d.ts.map +1 -1
  59. package/dist/compile/guard.js +158 -74
  60. package/dist/compile/index.d.ts +3 -1
  61. package/dist/compile/index.d.ts.map +1 -1
  62. package/dist/compile/index.js +2 -0
  63. package/dist/compile/issue.d.ts +110 -0
  64. package/dist/compile/issue.d.ts.map +1 -1
  65. package/dist/compile/issue.js +184 -1
  66. package/dist/compile/names.d.ts +12 -2
  67. package/dist/compile/names.d.ts.map +1 -1
  68. package/dist/compile/names.js +19 -3
  69. package/dist/compile/predicate.d.ts +24 -0
  70. package/dist/compile/predicate.d.ts.map +1 -1
  71. package/dist/compile/predicate.js +131 -5
  72. package/dist/compile/runtime.d.ts +80 -12
  73. package/dist/compile/runtime.d.ts.map +1 -1
  74. package/dist/compile/runtime.js +25 -6
  75. package/dist/compile/source.d.ts +10 -2
  76. package/dist/compile/source.d.ts.map +1 -1
  77. package/dist/compile/source.js +361 -26
  78. package/dist/compile/types.d.ts +20 -0
  79. package/dist/compile/types.d.ts.map +1 -1
  80. package/dist/compile/types.js +2 -0
  81. package/dist/decoder/index.d.ts +32 -46
  82. package/dist/decoder/index.d.ts.map +1 -1
  83. package/dist/decoder/index.js +102 -38
  84. package/dist/evaluate/check-composite.d.ts +59 -0
  85. package/dist/evaluate/check-composite.d.ts.map +1 -1
  86. package/dist/evaluate/check-composite.js +151 -3
  87. package/dist/evaluate/check-scalar.d.ts +16 -0
  88. package/dist/evaluate/check-scalar.d.ts.map +1 -1
  89. package/dist/evaluate/check-scalar.js +32 -0
  90. package/dist/evaluate/check.d.ts +7 -0
  91. package/dist/evaluate/check.d.ts.map +1 -1
  92. package/dist/evaluate/check.js +43 -0
  93. package/dist/evaluate/index.d.ts +2 -0
  94. package/dist/evaluate/index.d.ts.map +1 -1
  95. package/dist/evaluate/index.js +2 -0
  96. package/dist/evaluate/issue.d.ts +11 -1
  97. package/dist/evaluate/issue.d.ts.map +1 -1
  98. package/dist/evaluate/issue.js +15 -1
  99. package/dist/evaluate/predicate.d.ts +16 -5
  100. package/dist/evaluate/predicate.d.ts.map +1 -1
  101. package/dist/evaluate/predicate.js +20 -5
  102. package/dist/evaluate/shared.d.ts +59 -13
  103. package/dist/evaluate/shared.d.ts.map +1 -1
  104. package/dist/evaluate/shared.js +66 -8
  105. package/dist/evaluate/state.d.ts +35 -13
  106. package/dist/evaluate/state.d.ts.map +1 -1
  107. package/dist/evaluate/state.js +35 -2
  108. package/dist/guard/base.d.ts +79 -29
  109. package/dist/guard/base.d.ts.map +1 -1
  110. package/dist/guard/base.js +91 -29
  111. package/dist/guard/error.d.ts +10 -5
  112. package/dist/guard/error.d.ts.map +1 -1
  113. package/dist/guard/error.js +10 -5
  114. package/dist/guard/index.d.ts +2 -0
  115. package/dist/guard/index.d.ts.map +1 -1
  116. package/dist/guard/index.js +2 -0
  117. package/dist/guard/number.d.ts +26 -11
  118. package/dist/guard/number.d.ts.map +1 -1
  119. package/dist/guard/number.js +30 -11
  120. package/dist/guard/props.d.ts +27 -3
  121. package/dist/guard/props.d.ts.map +1 -1
  122. package/dist/guard/props.js +27 -3
  123. package/dist/guard/read.d.ts +62 -9
  124. package/dist/guard/read.d.ts.map +1 -1
  125. package/dist/guard/read.js +83 -10
  126. package/dist/guard/registry.d.ts +12 -2
  127. package/dist/guard/registry.d.ts.map +1 -1
  128. package/dist/guard/registry.js +15 -3
  129. package/dist/guard/string.d.ts +33 -13
  130. package/dist/guard/string.d.ts.map +1 -1
  131. package/dist/guard/string.js +37 -13
  132. package/dist/guard/types.d.ts +92 -40
  133. package/dist/guard/types.d.ts.map +1 -1
  134. package/dist/guard/types.js +2 -0
  135. package/dist/index.d.ts +1 -1
  136. package/dist/index.d.ts.map +1 -1
  137. package/dist/internal/index.d.ts +42 -6
  138. package/dist/internal/index.d.ts.map +1 -1
  139. package/dist/internal/index.js +51 -8
  140. package/dist/ir/builder.d.ts +16 -126
  141. package/dist/ir/builder.d.ts.map +1 -1
  142. package/dist/ir/builder.js +77 -137
  143. package/dist/ir/freeze.d.ts +4 -0
  144. package/dist/ir/freeze.d.ts.map +1 -1
  145. package/dist/ir/freeze.js +59 -0
  146. package/dist/ir/index.d.ts +3 -1
  147. package/dist/ir/index.d.ts.map +1 -1
  148. package/dist/ir/index.js +2 -0
  149. package/dist/ir/regexp.d.ts +2 -0
  150. package/dist/ir/regexp.d.ts.map +1 -1
  151. package/dist/ir/regexp.js +2 -0
  152. package/dist/ir/types.d.ts +90 -55
  153. package/dist/ir/types.d.ts.map +1 -1
  154. package/dist/ir/types.js +2 -0
  155. package/dist/ir/validate.d.ts +8 -1
  156. package/dist/ir/validate.d.ts.map +1 -1
  157. package/dist/ir/validate.js +477 -61
  158. package/dist/issue/index.d.ts +41 -9
  159. package/dist/issue/index.d.ts.map +1 -1
  160. package/dist/issue/index.js +61 -11
  161. package/dist/json-schema/emit-combinator.d.ts +44 -4
  162. package/dist/json-schema/emit-combinator.d.ts.map +1 -1
  163. package/dist/json-schema/emit-combinator.js +44 -4
  164. package/dist/json-schema/emit-composite.d.ts +10 -0
  165. package/dist/json-schema/emit-composite.d.ts.map +1 -1
  166. package/dist/json-schema/emit-composite.js +15 -1
  167. package/dist/json-schema/emit-scalar.d.ts +26 -3
  168. package/dist/json-schema/emit-scalar.d.ts.map +1 -1
  169. package/dist/json-schema/emit-scalar.js +70 -9
  170. package/dist/json-schema/emit-types.d.ts +11 -1
  171. package/dist/json-schema/emit-types.d.ts.map +1 -1
  172. package/dist/json-schema/emit-types.js +2 -0
  173. package/dist/json-schema/emit.d.ts +12 -1
  174. package/dist/json-schema/emit.d.ts.map +1 -1
  175. package/dist/json-schema/emit.js +12 -1
  176. package/dist/json-schema/freeze.d.ts +13 -2
  177. package/dist/json-schema/freeze.d.ts.map +1 -1
  178. package/dist/json-schema/freeze.js +41 -8
  179. package/dist/json-schema/index.d.ts +16 -2
  180. package/dist/json-schema/index.d.ts.map +1 -1
  181. package/dist/json-schema/index.js +23 -3
  182. package/dist/json-schema/issue.d.ts +4 -1
  183. package/dist/json-schema/issue.d.ts.map +1 -1
  184. package/dist/json-schema/issue.js +4 -1
  185. package/dist/json-schema/read.d.ts +24 -3
  186. package/dist/json-schema/read.d.ts.map +1 -1
  187. package/dist/json-schema/read.js +59 -12
  188. package/dist/json-schema/types.d.ts +38 -15
  189. package/dist/json-schema/types.d.ts.map +1 -1
  190. package/dist/json-schema/types.js +2 -0
  191. package/dist/kind/index.d.ts +15 -28
  192. package/dist/kind/index.d.ts.map +1 -1
  193. package/dist/kind/index.js +15 -10
  194. package/dist/lower/index.d.ts +6 -1
  195. package/dist/lower/index.d.ts.map +1 -1
  196. package/dist/lower/index.js +411 -44
  197. package/dist/message/index.d.ts +46 -10
  198. package/dist/message/index.d.ts.map +1 -1
  199. package/dist/message/index.js +88 -17
  200. package/dist/optimize/algebraic.d.ts +54 -0
  201. package/dist/optimize/algebraic.d.ts.map +1 -0
  202. package/dist/optimize/algebraic.js +314 -0
  203. package/dist/optimize/compact.d.ts +8 -1
  204. package/dist/optimize/compact.d.ts.map +1 -1
  205. package/dist/optimize/compact.js +13 -2
  206. package/dist/optimize/domain.d.ts +16 -0
  207. package/dist/optimize/domain.d.ts.map +1 -0
  208. package/dist/optimize/domain.js +615 -0
  209. package/dist/optimize/fold-boolean.d.ts +17 -2
  210. package/dist/optimize/fold-boolean.d.ts.map +1 -1
  211. package/dist/optimize/fold-boolean.js +59 -14
  212. package/dist/optimize/fold-common.d.ts +43 -8
  213. package/dist/optimize/fold-common.d.ts.map +1 -1
  214. package/dist/optimize/fold-common.js +37 -6
  215. package/dist/optimize/fold-constraints.d.ts +33 -0
  216. package/dist/optimize/fold-constraints.d.ts.map +1 -0
  217. package/dist/optimize/fold-constraints.js +484 -0
  218. package/dist/optimize/fold-scalar.d.ts +98 -13
  219. package/dist/optimize/fold-scalar.d.ts.map +1 -1
  220. package/dist/optimize/fold-scalar.js +98 -13
  221. package/dist/optimize/fold.d.ts +8 -1
  222. package/dist/optimize/fold.d.ts.map +1 -1
  223. package/dist/optimize/fold.js +22 -2
  224. package/dist/optimize/index.d.ts +9 -1
  225. package/dist/optimize/index.d.ts.map +1 -1
  226. package/dist/optimize/index.js +18 -3
  227. package/dist/optimize/map-node.d.ts +3 -1
  228. package/dist/optimize/map-node.d.ts.map +1 -1
  229. package/dist/optimize/map-node.js +45 -3
  230. package/dist/optimize/peephole.d.ts +16 -0
  231. package/dist/optimize/peephole.d.ts.map +1 -0
  232. package/dist/optimize/peephole.js +254 -0
  233. package/dist/optimize/remap.d.ts +2 -0
  234. package/dist/optimize/remap.d.ts.map +1 -1
  235. package/dist/optimize/remap.js +2 -0
  236. package/dist/optimize/rewrite.d.ts +13 -8
  237. package/dist/optimize/rewrite.d.ts.map +1 -1
  238. package/dist/optimize/rewrite.js +13 -8
  239. package/dist/plan/cache.d.ts +9 -3
  240. package/dist/plan/cache.d.ts.map +1 -1
  241. package/dist/plan/cache.js +21 -5
  242. package/dist/plan/index.d.ts +2 -0
  243. package/dist/plan/index.d.ts.map +1 -1
  244. package/dist/plan/index.js +2 -0
  245. package/dist/plan/predicate.d.ts +2 -0
  246. package/dist/plan/predicate.d.ts.map +1 -1
  247. package/dist/plan/predicate.js +268 -29
  248. package/dist/plan/schema-predicate.d.ts +6 -0
  249. package/dist/plan/schema-predicate.d.ts.map +1 -1
  250. package/dist/plan/schema-predicate.js +117 -13
  251. package/dist/plan/types.d.ts +2 -0
  252. package/dist/plan/types.d.ts.map +1 -1
  253. package/dist/plan/types.js +2 -0
  254. package/dist/result/index.d.ts +19 -5
  255. package/dist/result/index.d.ts.map +1 -1
  256. package/dist/result/index.js +10 -2
  257. package/dist/schema/common.d.ts +69 -6
  258. package/dist/schema/common.d.ts.map +1 -1
  259. package/dist/schema/common.js +104 -10
  260. package/dist/schema/freeze.d.ts +4 -0
  261. package/dist/schema/freeze.d.ts.map +1 -1
  262. package/dist/schema/freeze.js +18 -0
  263. package/dist/schema/index.d.ts +3 -0
  264. package/dist/schema/index.d.ts.map +1 -1
  265. package/dist/schema/index.js +3 -0
  266. package/dist/schema/lazy.d.ts +4 -0
  267. package/dist/schema/lazy.d.ts.map +1 -1
  268. package/dist/schema/lazy.js +4 -0
  269. package/dist/schema/literal.d.ts +7 -1
  270. package/dist/schema/literal.d.ts.map +1 -1
  271. package/dist/schema/literal.js +7 -1
  272. package/dist/schema/types.d.ts +20 -96
  273. package/dist/schema/types.d.ts.map +1 -1
  274. package/dist/schema/types.js +5 -1
  275. package/dist/schema/undefined.d.ts +17 -0
  276. package/dist/schema/undefined.d.ts.map +1 -0
  277. package/dist/schema/undefined.js +72 -0
  278. package/dist/schema/validate.d.ts +8 -1
  279. package/dist/schema/validate.d.ts.map +1 -1
  280. package/dist/schema/validate.js +146 -55
  281. package/docs/api.md +57 -0
  282. package/docs/assets/benchmark-headline.svg +163 -0
  283. package/docs/engine-notes.md +58 -15
  284. package/docs/index.html +130 -110
  285. package/package.json +65 -65
@@ -18,6 +18,9 @@ allocation sites, branch behavior, and validation contracts visible in code.
18
18
  - For all-required strict objects, reject extras by counting own string names
19
19
  and own symbols after field validation. Optional strict objects keep the full
20
20
  key membership scan.
21
+ - Keep `compile()` and `emitAotModule()` safe by default. Unsafe mode is an
22
+ explicit opt-in that may use direct property/index loads and own-enumerable
23
+ strict-key loops after the caller accepts getter/prototype/symbol-extra risk.
21
24
  - Mark constructed guards out-of-band so normal receivers avoid repeated schema
22
25
  validation while forged receivers still fall back to structural checks.
23
26
  - Use `Readonly<Record<string, unknown>>` after object guards.
@@ -91,14 +94,51 @@ descriptor-based element access, and dynamic edges use the same IR-backed
91
94
  runtime fallback as ordinary guard execution, preserving behavior for `lazy` and
92
95
  `refine`.
93
96
 
94
- Strict object IR emits two shapes. When every declared key is required and has
95
- already passed the data-property descriptor check, generated validators compare
96
- `Object.getOwnPropertyNames(value).length` with the declared key count and
97
- require `Object.getOwnPropertySymbols(value).length === 0`. This keeps
98
- non-enumerable and symbol extras rejected without paying a `Reflect.ownKeys`
99
- membership loop on the common all-required path. Optional strict objects still
100
- emit the full own-key membership scan because a missing optional key cannot be
101
- distinguished by the final key count alone.
97
+ Strict object IR emits two shapes. When every declared key is required,
98
+ generated validators run the strict-key count before field descriptor reads:
99
+ they compare `Object.getOwnPropertyNames(value).length` with the declared key
100
+ count and require `Object.getOwnPropertySymbols(value).length === 0`. V8
101
+ optimizes this count-only path better than a generic `Reflect.ownKeys` count,
102
+ and it rejects obvious extra-key objects before touching field descriptors.
103
+ Optional strict objects still emit the full own-key membership scan because a
104
+ missing optional key cannot be distinguished by the final key count alone.
105
+
106
+ `compile(..., { mode: "unsafe" })` and
107
+ `emitAotModule(..., { mode: "unsafe" })` switch generated predicates to a
108
+ trusted-data code shape. Required object fields whose schemas reject
109
+ `undefined` use direct `value[key]` loads without descriptor or own-key checks.
110
+ Required fields that can accept `undefined` retain an own-key presence guard so
111
+ missing required keys do not collapse into valid `undefined` values. Optional
112
+ fields take the direct-load fast path for present non-`undefined` values and
113
+ fall back to an own-key check only for the ambiguous `undefined` case.
114
+
115
+ Unsafe array, tuple, record, and discriminant paths also prefer direct loads.
116
+ Strict objects use a `for...in` own-enumerable key loop instead of allocating
117
+ own-key arrays.
118
+ Object keys that are ASCII identifier names emit as dot-property loads such as
119
+ `value.id`; other keys emit as escaped string-literal bracket loads. That is
120
+ intentionally not hostile-input equivalent: getters can execute,
121
+ prototype-backed values can be accepted, symbol or non-enumerable strict extras
122
+ are not rejected, and static property names may appear in unsafe generated
123
+ predicate source.
124
+
125
+ `mode: "unchecked"` keeps the unsafe direct-read shape and removes strict
126
+ extra-key loops. It is a trusted-shape path for objects already normalized by
127
+ the caller; strict objects no longer reject any extra keys there.
128
+
129
+ Fast modes also remove `Object.freeze()` from successful compiled `check()`
130
+ results. The returned object keeps the same `{ ok: true, value }` shape, but it
131
+ is intentionally not frozen. Failed diagnostics stay frozen because those
132
+ objects are off the success hot path and are often retained for reporting.
133
+ Object diagnostics in fast modes are generated from the same direct-read
134
+ contract as predicates. Required fields load through `value.key`, optional
135
+ fields use direct load plus an own-key fallback for `undefined`, unsafe strict
136
+ objects scan own enumerable string keys, and unchecked strict objects skip the
137
+ strict-key diagnostic scan. Array and tuple diagnostics in fast modes read
138
+ items through direct indexes instead of descriptor probes. Record diagnostics
139
+ read through `record[key]`; unchecked mode intentionally keeps inherited
140
+ enumerable keys visible. Discriminant diagnostics read the tag directly and
141
+ compare literal string cases with strict equality.
102
142
 
103
143
  ## Recursion
104
144
 
@@ -141,13 +181,16 @@ Zod, Valibot, and Ajv are dev dependencies for measurement only. They are not
141
181
  imported by `src`, and package policy rejects runtime, peer, optional, or
142
182
  bundled dependency fields before release.
143
183
 
144
- Last local release smoke on 2026-07-04 KST reported this ecosystem boolean
145
- path over the JSON-compatible strict-object benchmark:
184
+ Last local benchmark on 2026-07-04 KST reported these ecosystem paths over the
185
+ JSON-compatible strict-object benchmark:
146
186
 
147
- | Case | TypeSea runtime plan | TypeSea compiled | Ajv compiled |
148
- | --- | ---: | ---: | ---: |
149
- | Valid object | 496,270 hz | 4,237,892 hz | 4,312,174 hz |
150
- | Invalid object | 3,422,416 hz | 27,125,445 hz | 28,953,501 hz |
187
+ | Case | TypeSea runtime plan | TypeSea compiled safe | TypeSea compiled unsafe | TypeSea compiled unchecked | Ajv compiled |
188
+ | --- | ---: | ---: | ---: | ---: | ---: |
189
+ | Valid `is()` | 513,701 hz | 4,297,306 hz | 36,297,653 hz | 42,581,174 hz | 4,275,389 hz |
190
+ | Valid `check()` | 503,232 hz | 3,903,929 hz | 35,568,425 hz | 40,084,605 hz | 4,278,587 hz |
191
+ | Invalid `is()` | 3,636,369 hz | 42,080,241 hz | 49,654,076 hz | 50,482,732 hz | 27,820,643 hz |
192
+ | Invalid `check()` | 420,446 hz | 2,086,129 hz | 3,077,367 hz | 3,673,508 hz | 28,713,035 hz |
151
193
 
152
194
  Benchmark numbers are machine-local telemetry. They are useful for catching
153
- regressions, not for promising a fixed throughput floor.
195
+ regressions, not for promising a fixed throughput floor. Unsafe and unchecked
196
+ numbers are not hostile-input equivalent to safe mode.
package/docs/index.html CHANGED
@@ -159,31 +159,6 @@
159
159
  line-height: 1.5;
160
160
  }
161
161
 
162
- .search {
163
- padding: 16px 16px 8px;
164
- }
165
-
166
- .search input {
167
- width: 100%;
168
- min-height: 36px;
169
- border: 1px solid var(--sidebar-line);
170
- border-radius: 8px;
171
- padding: 0 12px;
172
- background: rgba(255, 255, 255, 0.06);
173
- color: var(--sidebar-ink);
174
- font: inherit;
175
- font-size: 13px;
176
- outline: none;
177
- }
178
-
179
- .search input:focus {
180
- border-color: #46b48f;
181
- }
182
-
183
- .search input::placeholder {
184
- color: var(--sidebar-muted);
185
- }
186
-
187
162
  .nav {
188
163
  flex: 1;
189
164
  padding: 6px 12px 18px;
@@ -687,15 +662,12 @@
687
662
  <aside class="sidebar" aria-label="Documentation navigation">
688
663
  <div class="brand">
689
664
  <h1>TypeSea</h1>
690
- <span class="version">v0.1.0</span>
665
+ <span class="version">v0.2.0</span>
691
666
  </div>
692
667
  <p class="brand-tagline">
693
668
  Zero-dependency runtime narrowing for TypeScript.
694
669
  ESM-only &middot; Node &ge; 20.19 &middot; MIT
695
670
  </p>
696
- <div class="search">
697
- <input data-search type="search" placeholder="Filter sections&hellip;" aria-label="Filter documentation sections">
698
- </div>
699
671
  <nav class="nav">
700
672
  <p class="nav-group">Guide</p>
701
673
  <a href="#overview">Overview</a>
@@ -813,6 +785,22 @@ const schema = toJsonSchema(User);</code></pre>
813
785
  environments, emit validator source ahead of time with <code>emitAotModule()</code>.
814
786
  </p>
815
787
  </div>
788
+ <div class="callout warn">
789
+ <span class="icon">&#9888;</span>
790
+ <p>
791
+ <strong>Unsafe FastMode:</strong> <code>compile(User, { mode: "unsafe" })</code>
792
+ and <code>emitAotModule(User, { mode: "unsafe" })</code> emit direct
793
+ property and index reads plus an allocation-free strict-key loop for trusted
794
+ normalized data. They may execute getters, may accept prototype-backed values,
795
+ strict objects do not reject symbol or non-enumerable extras, and escaped
796
+ static property keys may appear directly in unsafe predicate source.
797
+ <code>mode: "unchecked"</code> also skips strict extra-key loops for
798
+ already-trusted object shapes. Unsafe and unchecked successful
799
+ <code>check()</code> results are raw <code>{ ok: true, value }</code>
800
+ objects; failed diagnostics remain frozen and use the same direct-read
801
+ FastMode object/array/record/discriminant contract where possible.
802
+ </p>
803
+ </div>
816
804
  </section>
817
805
 
818
806
  <section id="semantics" data-doc-section data-title="semantics presence optional undefinedable nullable edge nan proto uuid strict">
@@ -1068,23 +1056,71 @@ const schema = toJsonSchema(User);</code></pre>
1068
1056
  <tbody>
1069
1057
  <tr>
1070
1058
  <td>TypeSea runtime plan <code>is()</code></td>
1071
- <td class="num">496,270</td>
1059
+ <td class="num">513,701</td>
1060
+ </tr>
1061
+ <tr>
1062
+ <td>TypeSea compiled safe <code>is()</code></td>
1063
+ <td class="num">4,297,306</td>
1064
+ </tr>
1065
+ <tr>
1066
+ <td>TypeSea compiled unsafe <code>is()</code></td>
1067
+ <td class="num">36,297,653</td>
1068
+ </tr>
1069
+ <tr>
1070
+ <td>TypeSea compiled unchecked <code>is()</code></td>
1071
+ <td class="num"><span class="best">42,581,174</span></td>
1072
+ </tr>
1073
+ <tr>
1074
+ <td>Zod <code>safeParse</code></td>
1075
+ <td class="num">1,343,756</td>
1076
+ </tr>
1077
+ <tr>
1078
+ <td>Valibot <code>safeParse</code></td>
1079
+ <td class="num">1,406,528</td>
1080
+ </tr>
1081
+ <tr>
1082
+ <td>Ajv compiled</td>
1083
+ <td class="num">4,275,389</td>
1084
+ </tr>
1085
+ </tbody>
1086
+ </table>
1087
+ </div>
1088
+ <div class="table-wrap">
1089
+ <table>
1090
+ <thead>
1091
+ <tr>
1092
+ <th>Valid diagnostic path</th>
1093
+ <th class="num">ops/sec</th>
1094
+ </tr>
1095
+ </thead>
1096
+ <tbody>
1097
+ <tr>
1098
+ <td>TypeSea runtime plan <code>check()</code></td>
1099
+ <td class="num">503,232</td>
1072
1100
  </tr>
1073
1101
  <tr>
1074
- <td>TypeSea compiled <code>is()</code></td>
1075
- <td class="num"><span class="best">4,237,892</span></td>
1102
+ <td>TypeSea compiled safe <code>check()</code></td>
1103
+ <td class="num">3,903,929</td>
1104
+ </tr>
1105
+ <tr>
1106
+ <td>TypeSea compiled unsafe <code>check()</code></td>
1107
+ <td class="num">35,568,425</td>
1108
+ </tr>
1109
+ <tr>
1110
+ <td>TypeSea compiled unchecked <code>check()</code></td>
1111
+ <td class="num"><span class="best">40,084,605</span></td>
1076
1112
  </tr>
1077
1113
  <tr>
1078
1114
  <td>Zod <code>safeParse</code></td>
1079
- <td class="num">1,363,792</td>
1115
+ <td class="num">1,355,014</td>
1080
1116
  </tr>
1081
1117
  <tr>
1082
1118
  <td>Valibot <code>safeParse</code></td>
1083
- <td class="num">1,384,892</td>
1119
+ <td class="num">1,378,266</td>
1084
1120
  </tr>
1085
1121
  <tr>
1086
1122
  <td>Ajv compiled</td>
1087
- <td class="num">4,312,174</td>
1123
+ <td class="num">4,278,587</td>
1088
1124
  </tr>
1089
1125
  </tbody>
1090
1126
  </table>
@@ -1100,35 +1136,83 @@ const schema = toJsonSchema(User);</code></pre>
1100
1136
  <tbody>
1101
1137
  <tr>
1102
1138
  <td>TypeSea runtime plan <code>is()</code></td>
1103
- <td class="num">3,422,416</td>
1139
+ <td class="num">3,636,369</td>
1140
+ </tr>
1141
+ <tr>
1142
+ <td>TypeSea compiled safe <code>is()</code></td>
1143
+ <td class="num">42,080,241</td>
1104
1144
  </tr>
1105
1145
  <tr>
1106
- <td>TypeSea compiled <code>is()</code></td>
1107
- <td class="num"><span class="best">27,125,445</span></td>
1146
+ <td>TypeSea compiled unsafe <code>is()</code></td>
1147
+ <td class="num">49,654,076</td>
1148
+ </tr>
1149
+ <tr>
1150
+ <td>TypeSea compiled unchecked <code>is()</code></td>
1151
+ <td class="num"><span class="best">50,482,732</span></td>
1108
1152
  </tr>
1109
1153
  <tr>
1110
1154
  <td>Zod <code>safeParse</code></td>
1111
- <td class="num">83,501</td>
1155
+ <td class="num">84,272</td>
1112
1156
  </tr>
1113
1157
  <tr>
1114
1158
  <td>Valibot <code>safeParse</code></td>
1115
- <td class="num">902,616</td>
1159
+ <td class="num">878,521</td>
1116
1160
  </tr>
1117
1161
  <tr>
1118
1162
  <td>Ajv compiled</td>
1119
- <td class="num">28,953,501</td>
1163
+ <td class="num">27,820,643</td>
1164
+ </tr>
1165
+ </tbody>
1166
+ </table>
1167
+ </div>
1168
+ <div class="table-wrap">
1169
+ <table>
1170
+ <thead>
1171
+ <tr>
1172
+ <th>Invalid diagnostic path</th>
1173
+ <th class="num">ops/sec</th>
1174
+ </tr>
1175
+ </thead>
1176
+ <tbody>
1177
+ <tr>
1178
+ <td>TypeSea runtime plan <code>check()</code></td>
1179
+ <td class="num">420,446</td>
1180
+ </tr>
1181
+ <tr>
1182
+ <td>TypeSea compiled safe <code>check()</code></td>
1183
+ <td class="num">2,086,129</td>
1184
+ </tr>
1185
+ <tr>
1186
+ <td>TypeSea compiled unsafe <code>check()</code></td>
1187
+ <td class="num">3,077,367</td>
1188
+ </tr>
1189
+ <tr>
1190
+ <td>TypeSea compiled unchecked <code>check()</code></td>
1191
+ <td class="num">3,673,508</td>
1192
+ </tr>
1193
+ <tr>
1194
+ <td>Zod <code>safeParse</code></td>
1195
+ <td class="num">79,613</td>
1196
+ </tr>
1197
+ <tr>
1198
+ <td>Valibot <code>safeParse</code></td>
1199
+ <td class="num">887,991</td>
1200
+ </tr>
1201
+ <tr>
1202
+ <td>Ajv compiled</td>
1203
+ <td class="num"><span class="best">28,713,035</span></td>
1120
1204
  </tr>
1121
1205
  </tbody>
1122
1206
  </table>
1123
1207
  </div>
1124
1208
  <p class="footnote">
1125
- Local release smoke, 2026-07-04 KST, single machine &mdash; regression telemetry,
1126
- not throughput guarantees. The compiled path stays at Ajv-level speed while keeping
1127
- descriptor-based reads, strict symbol/non-enumerable key rejection, and immutable
1128
- diagnostics.
1209
+ Local benchmark, 2026-07-04 KST, single machine &mdash; regression telemetry,
1210
+ not throughput guarantees. Safe compiled mode keeps descriptor-based reads,
1211
+ strict symbol/non-enumerable key rejection, and immutable diagnostics. Unsafe
1212
+ and unchecked modes are faster because they are only for trusted normalized data.
1129
1213
  </p>
1130
1214
  <div class="code-block">
1131
- <pre><code>npm run bench -- --run</code></pre>
1215
+ <pre><code>npm run bench -- bench/ecosystem.bench.ts --run</code></pre>
1132
1216
  </div>
1133
1217
  </section>
1134
1218
 
@@ -1174,69 +1258,5 @@ const schema = toJsonSchema(User);</code></pre>
1174
1258
  </div>
1175
1259
  </div>
1176
1260
 
1177
- <script>
1178
- const search = document.querySelector("[data-search]");
1179
- const sections = Array.from(document.querySelectorAll("[data-doc-section]"));
1180
- const links = Array.from(document.querySelectorAll(".nav a"));
1181
- const groups = Array.from(document.querySelectorAll(".nav-group"));
1182
-
1183
- if (search instanceof HTMLInputElement) {
1184
- search.addEventListener("input", () => {
1185
- const query = search.value.trim().toLowerCase();
1186
- for (const section of sections) {
1187
- const title = section.getAttribute("data-title") ?? "";
1188
- const text = section.textContent?.toLowerCase() ?? "";
1189
- const visible = query === "" || title.includes(query) || text.includes(query);
1190
- section.classList.toggle("hidden", !visible);
1191
- }
1192
- for (const link of links) {
1193
- const target = link.getAttribute("href") ?? "";
1194
- const section = target.startsWith("#")
1195
- ? document.getElementById(target.slice(1))
1196
- : null;
1197
- const visible = section === null || !section.classList.contains("hidden");
1198
- link.classList.toggle("hidden", !visible);
1199
- }
1200
- for (const group of groups) {
1201
- let sibling = group.nextElementSibling;
1202
- let anyVisible = false;
1203
- while (sibling !== null && !sibling.classList.contains("nav-group")) {
1204
- if (sibling.matches("a") && !sibling.classList.contains("hidden")) {
1205
- anyVisible = true;
1206
- }
1207
- sibling = sibling.nextElementSibling;
1208
- }
1209
- group.classList.toggle("hidden", !anyVisible);
1210
- }
1211
- });
1212
- }
1213
-
1214
- const linkById = new Map(
1215
- links
1216
- .map((link) => [link.getAttribute("href")?.slice(1) ?? "", link])
1217
- .filter(([id]) => id !== "")
1218
- );
1219
-
1220
- if ("IntersectionObserver" in window) {
1221
- const observer = new IntersectionObserver(
1222
- (entries) => {
1223
- for (const entry of entries) {
1224
- if (entry.isIntersecting) {
1225
- for (const link of links) {
1226
- link.classList.toggle(
1227
- "active",
1228
- link === linkById.get(entry.target.id)
1229
- );
1230
- }
1231
- }
1232
- }
1233
- },
1234
- { rootMargin: "-20% 0px -70% 0px" }
1235
- );
1236
- for (const section of sections) {
1237
- observer.observe(section);
1238
- }
1239
- }
1240
- </script>
1241
1261
  </body>
1242
1262
  </html>
package/package.json CHANGED
@@ -1,68 +1,68 @@
1
1
  {
2
- "name": "typesea",
3
- "version": "0.1.0",
4
- "description": "V8-friendly runtime narrowing for TypeScript with Sea-of-Nodes graph introspection.",
5
- "type": "module",
6
- "author": "feral",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/Feralthedogg/TypeSea.git"
10
- },
11
- "sideEffects": false,
12
- "main": "./dist/index.js",
13
- "types": "./dist/index.d.ts",
14
- "exports": {
15
- ".": {
16
- "types": "./dist/index.d.ts",
17
- "import": "./dist/index.js",
18
- "default": "./dist/index.js"
2
+ "name": "typesea",
3
+ "version": "0.2.0",
4
+ "description": "V8-friendly runtime narrowing for TypeScript with Sea-of-Nodes graph introspection.",
5
+ "type": "module",
6
+ "author": "feral",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Feralthedogg/TypeSea.git"
10
+ },
11
+ "sideEffects": false,
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "keywords": [
22
+ "typescript",
23
+ "typeguard",
24
+ "type-guard",
25
+ "runtime-validation",
26
+ "schema",
27
+ "narrowing",
28
+ "v8"
29
+ ],
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "CHANGELOG.md",
34
+ "docs"
35
+ ],
36
+ "scripts": {
37
+ "build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
38
+ "bench": "vitest bench",
39
+ "check": "npm run policy && npm run check:docs && npm run typecheck && npm run lint && npm run test && npm run build && npm run check:dist && npm run check:api && npm run check:pack",
40
+ "check:api": "node scripts/public-api-surface.mjs",
41
+ "check:consumer": "node scripts/consumer-smoke.mjs",
42
+ "check:docs": "node scripts/docs-site-check.mjs",
43
+ "check:dist": "node scripts/dist-policy.mjs",
44
+ "check:pack": "node scripts/package-contents.mjs",
45
+ "lint": "eslint .",
46
+ "pack:dry": "npm pack --dry-run --ignore-scripts",
47
+ "policy": "node scripts/source-policy.mjs",
48
+ "prepack": "npm run check",
49
+ "release:check": "node scripts/release-gate.mjs",
50
+ "test": "vitest run",
51
+ "typecheck": "tsc -p tsconfig.json --noEmit"
52
+ },
53
+ "engines": {
54
+ "node": ">=20.19"
55
+ },
56
+ "license": "MIT",
57
+ "devDependencies": {
58
+ "@eslint/js": "^10.0.1",
59
+ "@types/node": "^26.1.0",
60
+ "ajv": "^8.20.0",
61
+ "eslint": "^10.6.0",
62
+ "typescript": "^6.0.3",
63
+ "typescript-eslint": "^8.62.1",
64
+ "valibot": "^1.4.2",
65
+ "vitest": "^4.1.9",
66
+ "zod": "^4.4.3"
19
67
  }
20
- },
21
- "keywords": [
22
- "typescript",
23
- "typeguard",
24
- "type-guard",
25
- "runtime-validation",
26
- "schema",
27
- "narrowing",
28
- "v8"
29
- ],
30
- "files": [
31
- "dist",
32
- "README.md",
33
- "CHANGELOG.md",
34
- "docs"
35
- ],
36
- "scripts": {
37
- "build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
38
- "bench": "vitest bench",
39
- "check": "npm run policy && npm run check:docs && npm run typecheck && npm run lint && npm run test && npm run build && npm run check:dist && npm run check:api && npm run check:pack",
40
- "check:api": "node scripts/public-api-surface.mjs",
41
- "check:consumer": "node scripts/consumer-smoke.mjs",
42
- "check:docs": "node scripts/docs-site-check.mjs",
43
- "check:dist": "node scripts/dist-policy.mjs",
44
- "check:pack": "node scripts/package-contents.mjs",
45
- "lint": "eslint .",
46
- "pack:dry": "npm pack --dry-run --ignore-scripts",
47
- "policy": "node scripts/source-policy.mjs",
48
- "prepack": "npm run check",
49
- "release:check": "node scripts/release-gate.mjs",
50
- "test": "vitest run",
51
- "typecheck": "tsc -p tsconfig.json --noEmit"
52
- },
53
- "engines": {
54
- "node": ">=20.19"
55
- },
56
- "license": "MIT",
57
- "devDependencies": {
58
- "@eslint/js": "^10.0.1",
59
- "@types/node": "^26.1.0",
60
- "ajv": "^8.20.0",
61
- "eslint": "^10.6.0",
62
- "typescript": "^6.0.3",
63
- "typescript-eslint": "^8.62.1",
64
- "valibot": "^1.4.2",
65
- "vitest": "^4.1.9",
66
- "zod": "^4.4.3"
67
- }
68
68
  }