typesea 0.1.0 → 0.3.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.
- package/CHANGELOG.md +85 -6
- package/README.md +143 -28
- package/dist/adapters/index.d.ts +50 -8
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +169 -48
- package/dist/aot/index.d.ts +19 -3
- package/dist/aot/index.d.ts.map +1 -1
- package/dist/aot/index.js +115 -17
- package/dist/async/index.d.ts +28 -56
- package/dist/async/index.d.ts.map +1 -1
- package/dist/async/index.js +94 -37
- package/dist/builders/composite.d.ts +43 -9
- package/dist/builders/composite.d.ts.map +1 -1
- package/dist/builders/composite.js +100 -17
- package/dist/builders/index.d.ts +8 -5
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +7 -4
- package/dist/builders/modifier.d.ts +36 -5
- package/dist/builders/modifier.d.ts.map +1 -1
- package/dist/builders/modifier.js +52 -5
- package/dist/builders/object/guard.d.ts +72 -24
- package/dist/builders/object/guard.d.ts.map +1 -1
- package/dist/builders/object/guard.js +139 -29
- package/dist/builders/object/index.d.ts +4 -2
- package/dist/builders/object/index.d.ts.map +1 -1
- package/dist/builders/object/index.js +3 -1
- package/dist/builders/object/schema.d.ts +88 -11
- package/dist/builders/object/schema.d.ts.map +1 -1
- package/dist/builders/object/schema.js +290 -23
- package/dist/builders/object/types.d.ts +20 -31
- package/dist/builders/object/types.d.ts.map +1 -1
- package/dist/builders/object/types.js +2 -0
- package/dist/builders/runtime.d.ts +40 -0
- package/dist/builders/runtime.d.ts.map +1 -0
- package/dist/builders/runtime.js +150 -0
- package/dist/builders/scalar.d.ts +49 -9
- package/dist/builders/scalar.d.ts.map +1 -1
- package/dist/builders/scalar.js +87 -9
- package/dist/builders/table.d.ts +35 -5
- package/dist/builders/table.d.ts.map +1 -1
- package/dist/builders/table.js +35 -5
- package/dist/builders/types.d.ts +20 -4
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/builders/types.js +2 -0
- package/dist/compile/check-composite.d.ts +25 -2
- package/dist/compile/check-composite.d.ts.map +1 -1
- package/dist/compile/check-composite.js +699 -27
- package/dist/compile/check-scalar.d.ts +88 -0
- package/dist/compile/check-scalar.d.ts.map +1 -1
- package/dist/compile/check-scalar.js +570 -3
- package/dist/compile/check.d.ts +12 -0
- package/dist/compile/check.d.ts.map +1 -1
- package/dist/compile/check.js +62 -3
- package/dist/compile/context.d.ts +47 -9
- package/dist/compile/context.d.ts.map +1 -1
- package/dist/compile/context.js +53 -8
- package/dist/compile/first.d.ts +26 -0
- package/dist/compile/first.d.ts.map +1 -0
- package/dist/compile/first.js +850 -0
- package/dist/compile/graph-predicate.d.ts +4 -2
- package/dist/compile/graph-predicate.d.ts.map +1 -1
- package/dist/compile/graph-predicate.js +2272 -165
- package/dist/compile/guard.d.ts +16 -24
- package/dist/compile/guard.d.ts.map +1 -1
- package/dist/compile/guard.js +202 -72
- package/dist/compile/index.d.ts +3 -1
- package/dist/compile/index.d.ts.map +1 -1
- package/dist/compile/index.js +2 -0
- package/dist/compile/issue.d.ts +110 -0
- package/dist/compile/issue.d.ts.map +1 -1
- package/dist/compile/issue.js +184 -1
- package/dist/compile/names.d.ts +12 -2
- package/dist/compile/names.d.ts.map +1 -1
- package/dist/compile/names.js +19 -3
- package/dist/compile/predicate.d.ts +24 -0
- package/dist/compile/predicate.d.ts.map +1 -1
- package/dist/compile/predicate.js +287 -10
- package/dist/compile/runtime.d.ts +100 -13
- package/dist/compile/runtime.d.ts.map +1 -1
- package/dist/compile/runtime.js +56 -6
- package/dist/compile/source.d.ts +10 -2
- package/dist/compile/source.d.ts.map +1 -1
- package/dist/compile/source.js +385 -26
- package/dist/compile/types.d.ts +22 -0
- package/dist/compile/types.d.ts.map +1 -1
- package/dist/compile/types.js +2 -0
- package/dist/decoder/index.d.ts +92 -46
- package/dist/decoder/index.d.ts.map +1 -1
- package/dist/decoder/index.js +266 -39
- package/dist/evaluate/check-composite.d.ts +111 -2
- package/dist/evaluate/check-composite.d.ts.map +1 -1
- package/dist/evaluate/check-composite.js +343 -8
- package/dist/evaluate/check-scalar.d.ts +25 -0
- package/dist/evaluate/check-scalar.d.ts.map +1 -1
- package/dist/evaluate/check-scalar.js +124 -3
- package/dist/evaluate/check.d.ts +7 -0
- package/dist/evaluate/check.d.ts.map +1 -1
- package/dist/evaluate/check.js +62 -4
- package/dist/evaluate/index.d.ts +2 -0
- package/dist/evaluate/index.d.ts.map +1 -1
- package/dist/evaluate/index.js +2 -0
- package/dist/evaluate/issue.d.ts +11 -1
- package/dist/evaluate/issue.d.ts.map +1 -1
- package/dist/evaluate/issue.js +15 -1
- package/dist/evaluate/predicate.d.ts +16 -5
- package/dist/evaluate/predicate.d.ts.map +1 -1
- package/dist/evaluate/predicate.js +20 -5
- package/dist/evaluate/shared.d.ts +78 -13
- package/dist/evaluate/shared.d.ts.map +1 -1
- package/dist/evaluate/shared.js +101 -8
- package/dist/evaluate/state.d.ts +35 -13
- package/dist/evaluate/state.d.ts.map +1 -1
- package/dist/evaluate/state.js +35 -2
- package/dist/guard/array.d.ts +48 -0
- package/dist/guard/array.d.ts.map +1 -0
- package/dist/guard/array.js +84 -0
- package/dist/guard/base.d.ts +111 -31
- package/dist/guard/base.d.ts.map +1 -1
- package/dist/guard/base.js +165 -32
- package/dist/guard/date.d.ts +34 -0
- package/dist/guard/date.d.ts.map +1 -0
- package/dist/guard/date.js +60 -0
- package/dist/guard/error.d.ts +10 -5
- package/dist/guard/error.d.ts.map +1 -1
- package/dist/guard/error.js +10 -5
- package/dist/guard/index.d.ts +4 -0
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +4 -0
- package/dist/guard/number.d.ts +86 -11
- package/dist/guard/number.d.ts.map +1 -1
- package/dist/guard/number.js +159 -11
- package/dist/guard/props.d.ts +27 -3
- package/dist/guard/props.d.ts.map +1 -1
- package/dist/guard/props.js +27 -3
- package/dist/guard/read.d.ts +115 -10
- package/dist/guard/read.d.ts.map +1 -1
- package/dist/guard/read.js +185 -10
- package/dist/guard/registry.d.ts +12 -2
- package/dist/guard/registry.d.ts.map +1 -1
- package/dist/guard/registry.js +15 -3
- package/dist/guard/string.d.ts +115 -13
- package/dist/guard/string.d.ts.map +1 -1
- package/dist/guard/string.js +250 -13
- package/dist/guard/types.d.ts +110 -40
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/guard/types.js +2 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/internal/index.d.ts +42 -6
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +51 -8
- package/dist/ir/builder.d.ts +17 -127
- package/dist/ir/builder.d.ts.map +1 -1
- package/dist/ir/builder.js +80 -137
- package/dist/ir/freeze.d.ts +4 -0
- package/dist/ir/freeze.d.ts.map +1 -1
- package/dist/ir/freeze.js +66 -0
- package/dist/ir/index.d.ts +3 -1
- package/dist/ir/index.d.ts.map +1 -1
- package/dist/ir/index.js +2 -0
- package/dist/ir/regexp.d.ts +2 -0
- package/dist/ir/regexp.d.ts.map +1 -1
- package/dist/ir/regexp.js +2 -0
- package/dist/ir/types.d.ts +94 -56
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/ir/types.js +2 -0
- package/dist/ir/validate.d.ts +8 -1
- package/dist/ir/validate.d.ts.map +1 -1
- package/dist/ir/validate.js +511 -61
- package/dist/issue/index.d.ts +42 -10
- package/dist/issue/index.d.ts.map +1 -1
- package/dist/issue/index.js +65 -11
- package/dist/json-schema/emit-combinator.d.ts +44 -4
- package/dist/json-schema/emit-combinator.d.ts.map +1 -1
- package/dist/json-schema/emit-combinator.js +44 -4
- package/dist/json-schema/emit-composite.d.ts +16 -2
- package/dist/json-schema/emit-composite.d.ts.map +1 -1
- package/dist/json-schema/emit-composite.js +81 -13
- package/dist/json-schema/emit-scalar.d.ts +26 -3
- package/dist/json-schema/emit-scalar.d.ts.map +1 -1
- package/dist/json-schema/emit-scalar.js +124 -10
- package/dist/json-schema/emit-types.d.ts +11 -1
- package/dist/json-schema/emit-types.d.ts.map +1 -1
- package/dist/json-schema/emit-types.js +2 -0
- package/dist/json-schema/emit.d.ts +12 -1
- package/dist/json-schema/emit.d.ts.map +1 -1
- package/dist/json-schema/emit.js +23 -3
- package/dist/json-schema/freeze.d.ts +13 -2
- package/dist/json-schema/freeze.d.ts.map +1 -1
- package/dist/json-schema/freeze.js +41 -8
- package/dist/json-schema/index.d.ts +16 -2
- package/dist/json-schema/index.d.ts.map +1 -1
- package/dist/json-schema/index.js +23 -3
- package/dist/json-schema/issue.d.ts +4 -1
- package/dist/json-schema/issue.d.ts.map +1 -1
- package/dist/json-schema/issue.js +4 -1
- package/dist/json-schema/read.d.ts +24 -3
- package/dist/json-schema/read.d.ts.map +1 -1
- package/dist/json-schema/read.js +59 -12
- package/dist/json-schema/types.d.ts +45 -16
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/json-schema/types.js +2 -0
- package/dist/kind/index.d.ts +40 -28
- package/dist/kind/index.d.ts.map +1 -1
- package/dist/kind/index.js +41 -13
- package/dist/lower/index.d.ts +6 -1
- package/dist/lower/index.d.ts.map +1 -1
- package/dist/lower/index.js +462 -46
- package/dist/message/index.d.ts +64 -10
- package/dist/message/index.d.ts.map +1 -1
- package/dist/message/index.js +155 -17
- package/dist/optimize/algebraic.d.ts +54 -0
- package/dist/optimize/algebraic.d.ts.map +1 -0
- package/dist/optimize/algebraic.js +314 -0
- package/dist/optimize/compact.d.ts +8 -1
- package/dist/optimize/compact.d.ts.map +1 -1
- package/dist/optimize/compact.js +13 -2
- package/dist/optimize/domain.d.ts +16 -0
- package/dist/optimize/domain.d.ts.map +1 -0
- package/dist/optimize/domain.js +619 -0
- package/dist/optimize/fold-boolean.d.ts +17 -2
- package/dist/optimize/fold-boolean.d.ts.map +1 -1
- package/dist/optimize/fold-boolean.js +59 -14
- package/dist/optimize/fold-common.d.ts +43 -8
- package/dist/optimize/fold-common.d.ts.map +1 -1
- package/dist/optimize/fold-common.js +37 -6
- package/dist/optimize/fold-constraints.d.ts +33 -0
- package/dist/optimize/fold-constraints.d.ts.map +1 -0
- package/dist/optimize/fold-constraints.js +484 -0
- package/dist/optimize/fold-scalar.d.ts +98 -13
- package/dist/optimize/fold-scalar.d.ts.map +1 -1
- package/dist/optimize/fold-scalar.js +98 -13
- package/dist/optimize/fold.d.ts +8 -1
- package/dist/optimize/fold.d.ts.map +1 -1
- package/dist/optimize/fold.js +22 -2
- package/dist/optimize/index.d.ts +9 -1
- package/dist/optimize/index.d.ts.map +1 -1
- package/dist/optimize/index.js +18 -3
- package/dist/optimize/map-node.d.ts +3 -1
- package/dist/optimize/map-node.d.ts.map +1 -1
- package/dist/optimize/map-node.js +48 -3
- package/dist/optimize/peephole.d.ts +16 -0
- package/dist/optimize/peephole.d.ts.map +1 -0
- package/dist/optimize/peephole.js +254 -0
- package/dist/optimize/remap.d.ts +2 -0
- package/dist/optimize/remap.d.ts.map +1 -1
- package/dist/optimize/remap.js +2 -0
- package/dist/optimize/rewrite.d.ts +13 -8
- package/dist/optimize/rewrite.d.ts.map +1 -1
- package/dist/optimize/rewrite.js +13 -8
- package/dist/plan/cache.d.ts +9 -3
- package/dist/plan/cache.d.ts.map +1 -1
- package/dist/plan/cache.js +34 -6
- package/dist/plan/index.d.ts +2 -0
- package/dist/plan/index.d.ts.map +1 -1
- package/dist/plan/index.js +2 -0
- package/dist/plan/predicate.d.ts +2 -0
- package/dist/plan/predicate.d.ts.map +1 -1
- package/dist/plan/predicate.js +298 -29
- package/dist/plan/schema-predicate.d.ts +6 -0
- package/dist/plan/schema-predicate.d.ts.map +1 -1
- package/dist/plan/schema-predicate.js +382 -19
- package/dist/plan/types.d.ts +2 -0
- package/dist/plan/types.d.ts.map +1 -1
- package/dist/plan/types.js +2 -0
- package/dist/result/index.d.ts +19 -5
- package/dist/result/index.d.ts.map +1 -1
- package/dist/result/index.js +10 -2
- package/dist/schema/common.d.ts +69 -6
- package/dist/schema/common.d.ts.map +1 -1
- package/dist/schema/common.js +104 -10
- package/dist/schema/freeze.d.ts +4 -0
- package/dist/schema/freeze.d.ts.map +1 -1
- package/dist/schema/freeze.js +40 -0
- package/dist/schema/index.d.ts +5 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +4 -1
- package/dist/schema/lazy.d.ts +4 -0
- package/dist/schema/lazy.d.ts.map +1 -1
- package/dist/schema/lazy.js +4 -0
- package/dist/schema/literal.d.ts +7 -1
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +7 -1
- package/dist/schema/types.d.ts +109 -100
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +13 -2
- package/dist/schema/undefined.d.ts +17 -0
- package/dist/schema/undefined.d.ts.map +1 -0
- package/dist/schema/undefined.js +77 -0
- package/dist/schema/validate.d.ts +8 -1
- package/dist/schema/validate.d.ts.map +1 -1
- package/dist/schema/validate.js +255 -57
- package/docs/api.md +128 -8
- package/docs/assets/benchmark-headline.svg +163 -0
- package/docs/engine-notes.md +62 -15
- package/docs/index.html +1340 -702
- package/docs/ko/api.md +375 -0
- package/docs/ko/engine-notes.md +156 -0
- package/docs/ko/readme.md +378 -0
- package/package.json +66 -65
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# TypeSea
|
|
2
|
+
|
|
3
|
+
**TypeSea**는 런타임 의존성 없이 TypeScript 값을 검증하고 타입을 좁히는 라이브러리입니다.
|
|
4
|
+
불변 스키마, Sea-of-Nodes에서 영향을 받은 검증 IR, 런타임 컴파일, AOT 소스 생성을 한 흐름으로 묶는 것을 목표로 합니다.
|
|
5
|
+
|
|
6
|
+
## 벤치마크 요약
|
|
7
|
+
|
|
8
|
+
마지막 로컬 벤치마크는 2026-07-04 KST에 실행했습니다.
|
|
9
|
+
명령은 `npm run bench -- bench/ecosystem.bench.ts --run`이며, strict object 계약을 대상으로 한 단일 머신의 초당 실행 횟수입니다.
|
|
10
|
+
아래 수치는 회귀를 잡기 위한 로컬 측정값이지, 릴리스 성능 보증값은 아닙니다.
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
TypeSea의 안전 모드 컴파일 검증기는 getter 실행 방지와 strict extra key 검사 같은 적대적 입력 방어를 유지하면서도 Ajv의 boolean hot path에 가까운 성능을 냅니다.
|
|
15
|
+
`unsafe`와 `unchecked` FastMode는 호출자가 이미 입력을 정규화했고 객체 그래프를 신뢰할 수 있을 때 쓰는 성능 우선 경로입니다.
|
|
16
|
+
이 모드에서는 직접 필드 로드, 할당을 줄인 strict-key loop, V8이 inline cache를 붙이기 쉬운 코드 형태를 사용합니다.
|
|
17
|
+
|
|
18
|
+
> 목표는 "대충 유효해 보이면 통과"가 아닙니다.
|
|
19
|
+
> TypeSea의 목표는 **런타임 실행, 컴파일 실행, AOT 실행이 같은 판정을 내린다는 사실을 테스트로 고정하는 검증기**입니다.
|
|
20
|
+
> 사용자 코드를 실행하지 않고, 예상 가능한 실패에서 예외를 던지지 않으며, 공개 API 경계 밖으로 변경 가능한 내부 상태를 내보내지 않는 것을 기본 원칙으로 둡니다.
|
|
21
|
+
|
|
22
|
+
> [!IMPORTANT]
|
|
23
|
+
> TypeSea는 **적대적인 경계 입력**을 전제로 설계했습니다.
|
|
24
|
+
> 속성 읽기는 descriptor를 통하므로 **사용자 getter를 실행하지 않습니다**.
|
|
25
|
+
> `__proto__`와 `constructor` key는 null-prototype lookup으로 처리하고, 사용자 regexp는 복제한 뒤 `lastIndex`를 reset하며, 순환 입력도 유한하게 검증합니다.
|
|
26
|
+
> 예상 가능한 실패는 동결된 `Result`로 반환합니다.
|
|
27
|
+
> 불명확한 타입 탈출과 암묵적 예외 흐름에 기대지 않도록 코드베이스 전체에 정책 게이트를 둡니다.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 왜 만들었나
|
|
32
|
+
|
|
33
|
+
검증 라이브러리를 실제 경계 입력에 쓰다 보면 다음 조건을 동시에 만족시키기 어렵습니다.
|
|
34
|
+
|
|
35
|
+
- getter 부작용, prototype pollution key, 위조된 schema object, revoked proxy처럼 검증 자체에 저항하는 입력
|
|
36
|
+
- 런타임 계획, 컴파일된 검증기, AOT로 생성한 검증기 사이의 동일한 판정
|
|
37
|
+
- `throw` 대신 `Result`로 표현되는 명시적 실패
|
|
38
|
+
- 공개 API 경계를 지날 때마다 유지되는 불변성
|
|
39
|
+
|
|
40
|
+
TypeSea는 아래 원칙에 집중합니다.
|
|
41
|
+
|
|
42
|
+
- 검증 중 사용자 코드 실행 금지
|
|
43
|
+
- 런타임, 컴파일, AOT 실행 경로의 판정 일치를 seeded fuzzer로 검증
|
|
44
|
+
- 코드 생성 시 사용자 입력을 소스 문자열에 직접 삽입하지 않기
|
|
45
|
+
- `optional`과 `undefinedable`을 분리하는 명시적 key presence 규칙
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 핵심 속성
|
|
50
|
+
|
|
51
|
+
- **런타임 의존성 없음**: runtime, peer, optional, bundled dependency가 없습니다. 릴리스 전에 package policy가 이를 기계적으로 검증합니다.
|
|
52
|
+
- **세 실행 경로, 하나의 의미**: `is()`와 `check()`는 cached validation plan을 실행하고, `compile()`은 최적화된 IR에서 런타임 predicate를 생성하며, `emitAotModule()`은 standalone validator source를 만듭니다. 일반 `is()`는 per-node interpreter를 타지 않고 schema-specialized kernel을 사용합니다. sparse array, accessor property, symbol key, non-enumerable extra까지 포함해 parity fuzz test를 돌립니다.
|
|
53
|
+
- **동결된 공개 표면**: guard, schema, graph, diagnostic, JSON Schema payload는 공개 API 경계를 넘기 전에 freeze됩니다.
|
|
54
|
+
- **손실 없는 export만 허용**: JSON Schema와 AOT export는 TypeSea 계약을 의미 손실 없이 표현할 수 있을 때만 성공합니다. 런타임 전용 계약은 schema를 약화시키지 않고 typed issue를 반환합니다.
|
|
55
|
+
|
|
56
|
+
> [!NOTE]
|
|
57
|
+
> TypeSea는 **ESM-only** 패키지입니다.
|
|
58
|
+
> `"type": "module"`만 제공하며 CommonJS build는 없습니다.
|
|
59
|
+
> Node.js `>= 20.19`에서는 `default` export condition을 통해 `require(esm)` 로드도 가능합니다.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 빠른 시작
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { compile, t, toJsonSchema, type Infer } from "typesea";
|
|
67
|
+
|
|
68
|
+
const User = t.strictObject({
|
|
69
|
+
id: t.string.uuid(),
|
|
70
|
+
email: t.string.email(),
|
|
71
|
+
age: t.number.int().nonnegative(),
|
|
72
|
+
role: t.enum(["admin", "user"]),
|
|
73
|
+
tags: t.array(t.string.min(1)).max(8)
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
type User = Infer<typeof User>;
|
|
77
|
+
|
|
78
|
+
// 1) Boolean narrowing: 성공 경로에서 진단 객체를 만들지 않습니다.
|
|
79
|
+
if (User.is(input)) {
|
|
80
|
+
input.id; // narrowed
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 2) Immutable diagnostics: 예상 가능한 실패는 Result로 받습니다.
|
|
84
|
+
const checked = User.check(input);
|
|
85
|
+
if (!checked.ok) {
|
|
86
|
+
console.log(checked.error); // path가 포함된 동결 issue 목록
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 3) Hot path: 검증 코드를 생성합니다.
|
|
90
|
+
const FastUser = compile(User, { name: "isUser" });
|
|
91
|
+
|
|
92
|
+
// 4) Interop: 의미 손실이 없을 때만 JSON Schema로 내보냅니다.
|
|
93
|
+
const schema = toJsonSchema(User);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`is()`는 할당이 적은 boolean 경로에 씁니다.
|
|
97
|
+
호출자가 전체 실패 이유와 path를 필요로 하면 `check()`를 씁니다.
|
|
98
|
+
hot rejection path에서 기계가 읽을 첫 번째 실패만 필요하면 `checkFirst()`를 씁니다.
|
|
99
|
+
스키마가 안정적이고 호출 빈도가 높다면 `compile()` 또는 `emitAotModule()`을 씁니다.
|
|
100
|
+
compiled/AOT `checkFirst()`는 전체 issue list를 만든 뒤 자르지 않고 전용 first-fault collector를 사용합니다.
|
|
101
|
+
|
|
102
|
+
> [!CAUTION]
|
|
103
|
+
> `compile()`은 `new Function`으로 검증기를 생성합니다.
|
|
104
|
+
> `unsafe-eval`을 금지하는 Content-Security-Policy 환경에서는 사용할 수 없습니다.
|
|
105
|
+
> CSP 제한 환경에서는 `emitAotModule()`로 빌드 시점에 validator source를 생성하세요.
|
|
106
|
+
|
|
107
|
+
### Unsafe FastMode
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const FastButLooseUser = compile(User, {
|
|
111
|
+
name: "isUserFast",
|
|
112
|
+
mode: "unsafe"
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const FastTrustedShapeUser = compile(User, {
|
|
116
|
+
name: "isUserTrustedShape",
|
|
117
|
+
mode: "unchecked"
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`compile(..., { mode: "unsafe" })`와 `emitAotModule(..., { mode: "unsafe" })`는 TypeSea가 생성할 수 있는 가장 V8 친화적인 predicate를 방출합니다.
|
|
122
|
+
required object field는 direct bracket access로 읽고, array와 tuple은 direct indexed load를 쓰며, discriminant는 descriptor read를 피합니다.
|
|
123
|
+
strict-object extra는 allocation-free `for...in` loop로 검사합니다.
|
|
124
|
+
|
|
125
|
+
기본값은 여전히 `mode: "safe"`입니다.
|
|
126
|
+
unsafe mode는 getter를 실행할 수 있고, prototype-backed value를 받아들일 수 있으며, strict object에서 symbol 또는 non-enumerable extra를 거부하지 않습니다.
|
|
127
|
+
호출자가 객체 그래프를 소유하고 있거나 입력을 plain data record로 이미 정규화한 경우에만 사용하세요.
|
|
128
|
+
|
|
129
|
+
`mode: "unchecked"`는 한 단계 더 나아가 object shape을 신뢰하고 strict extra-key loop 자체를 건너뜁니다.
|
|
130
|
+
이미 소유한 DTO에서는 가장 빠른 경로지만, strict object가 더 이상 extra key를 거부하지 않습니다.
|
|
131
|
+
|
|
132
|
+
unsafe와 unchecked mode에서 successful compiled `check()`는 frozen success result 대신 raw `{ ok: true, value }` object를 반환합니다.
|
|
133
|
+
실패 진단은 계속 freeze됩니다.
|
|
134
|
+
safe mode는 success와 failure 모두 frozen `Result` 계약을 유지합니다.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Key Presence
|
|
139
|
+
|
|
140
|
+
객체 key 존재 여부는 명시적으로 표현합니다.
|
|
141
|
+
서로 다른 wrapper는 서로 다른 계약을 뜻합니다.
|
|
142
|
+
|
|
143
|
+
| Wrapper | key 생략 허용 | value `undefined` 허용 | 추론 타입 |
|
|
144
|
+
| --- | --- | --- | --- |
|
|
145
|
+
| `t.optional(inner)` | yes | no | `key?: T` |
|
|
146
|
+
| `t.undefinedable(inner)` | no | yes | `key: T \| undefined` |
|
|
147
|
+
| `t.nullable(inner)` | - | value may be `null` | `key: T \| null` |
|
|
148
|
+
|
|
149
|
+
> [!NOTE]
|
|
150
|
+
> presence는 wrapper composition을 지나도 유지됩니다.
|
|
151
|
+
> `t.nullable(t.optional(x))`는 여전히 "key가 없어도 된다"는 뜻입니다.
|
|
152
|
+
> `exactOptionalPropertyTypes` 아래에서 타입 추론과 런타임 동작은 같은 의미를 가집니다.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 실행 모델
|
|
157
|
+
|
|
158
|
+
TypeSea는 builder validation과 diagnostic을 위해 public schema tree를 유지합니다.
|
|
159
|
+
그 뒤 각 schema identity를 cached validation plan으로 낮춥니다.
|
|
160
|
+
plan은 최적화된 Sea-of-Nodes graph와 schema-specialized predicate kernel을 소유합니다.
|
|
161
|
+
`Guard.is()`는 per-node interpreter dispatch를 피하려고 kernel을 사용하고, `compile()`과 `emitAotModule()`은 optimized graph에서 predicate를 방출합니다.
|
|
162
|
+
`check()`는 먼저 같은 plan으로 판정을 얻고, 실패한 값만 schema-aware diagnostic collector로 replay해서 issue path와 code를 만듭니다.
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
builder -> frozen schema -> lower -> Sea-of-Nodes IR -> optimize
|
|
166
|
+
optimize -> ValidationPlan { graph, schema kernel }
|
|
167
|
+
schema kernel -> Guard.is() / check() preflight
|
|
168
|
+
graph -> compile() predicate / emitAotModule() predicate / Guard.graph()
|
|
169
|
+
failed check() -> schema-aware diagnostic collector
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
> [!IMPORTANT]
|
|
173
|
+
> generated validator는 **사용자가 제어하는 값을 소스 문자열에 넣지 않습니다**.
|
|
174
|
+
> literal, regexp, object key, keyset, dynamic schema fallback은 numeric index로 참조되는 **side table**에 둡니다.
|
|
175
|
+
> 적대적인 property name이 generated code 밖으로 탈출할 수 없으며, dedicated injection-audit test가 이 속성을 고정합니다.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 성능 스냅샷
|
|
180
|
+
|
|
181
|
+
마지막 로컬 벤치마크는 2026-07-04 KST에 실행했습니다.
|
|
182
|
+
`npm run bench -- bench/ecosystem.bench.ts --run`을 사용했고, benchmark strict-object 계약을 대상으로 했습니다.
|
|
183
|
+
아래 값은 단일 머신의 초당 실행 횟수이며 릴리스 성능 보증값은 아닙니다.
|
|
184
|
+
|
|
185
|
+
| 유효한 객체: boolean 경로 | hz |
|
|
186
|
+
| --- | ---: |
|
|
187
|
+
| TypeSea interpreted `is()` | 513,701 |
|
|
188
|
+
| TypeSea compiled safe `is()` | 4,297,306 |
|
|
189
|
+
| TypeSea compiled unsafe `is()` | 36,297,653 |
|
|
190
|
+
| TypeSea compiled unchecked `is()` | 42,581,174 |
|
|
191
|
+
| Zod `safeParse` | 1,343,756 |
|
|
192
|
+
| Valibot `safeParse` | 1,406,528 |
|
|
193
|
+
| Ajv compiled | 4,275,389 |
|
|
194
|
+
|
|
195
|
+
| 유효한 객체: 진단 경로 | hz |
|
|
196
|
+
| --- | ---: |
|
|
197
|
+
| TypeSea interpreted `check()` | 503,232 |
|
|
198
|
+
| TypeSea compiled safe `check()` | 3,903,929 |
|
|
199
|
+
| TypeSea compiled unsafe `check()` | 35,568,425 |
|
|
200
|
+
| TypeSea compiled unchecked `check()` | 40,084,605 |
|
|
201
|
+
| Zod `safeParse` | 1,355,014 |
|
|
202
|
+
| Valibot `safeParse` | 1,378,266 |
|
|
203
|
+
| Ajv compiled | 4,278,587 |
|
|
204
|
+
|
|
205
|
+
| 잘못된 객체: boolean 경로 | hz |
|
|
206
|
+
| --- | ---: |
|
|
207
|
+
| TypeSea interpreted `is()` | 3,636,369 |
|
|
208
|
+
| TypeSea compiled safe `is()` | 42,080,241 |
|
|
209
|
+
| TypeSea compiled unsafe `is()` | 49,654,076 |
|
|
210
|
+
| TypeSea compiled unchecked `is()` | 50,482,732 |
|
|
211
|
+
| Zod `safeParse` | 84,272 |
|
|
212
|
+
| Valibot `safeParse` | 878,521 |
|
|
213
|
+
| Ajv compiled | 27,820,643 |
|
|
214
|
+
|
|
215
|
+
| 잘못된 객체: 진단 경로 | hz |
|
|
216
|
+
| --- | ---: |
|
|
217
|
+
| TypeSea interpreted `check()` | 420,446 |
|
|
218
|
+
| TypeSea compiled safe `check()` | 2,086,129 |
|
|
219
|
+
| TypeSea compiled unsafe `check()` | 3,077,367 |
|
|
220
|
+
| TypeSea compiled unchecked `check()` | 3,673,508 |
|
|
221
|
+
| Zod `safeParse` | 79,613 |
|
|
222
|
+
| Valibot `safeParse` | 887,991 |
|
|
223
|
+
| Ajv compiled | 28,713,035 |
|
|
224
|
+
|
|
225
|
+
safe compiled path는 TypeSea의 적대적 입력 방어를 유지하면서 Ajv에 가깝게 동작합니다.
|
|
226
|
+
descriptor 기반 property read, symbol/non-enumerable strict-key rejection, key presence semantics, immutable diagnostics, TypeScript guard inference를 유지합니다.
|
|
227
|
+
unsafe와 unchecked compiled mode는 그 방어 계약 일부를 의도적으로 포기하기 때문에 더 빠릅니다.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## API 레퍼런스 요약
|
|
232
|
+
|
|
233
|
+
모든 공개 진입점은 package root에서 export됩니다.
|
|
234
|
+
builder는 `t` table 아래에도 묶여 있습니다.
|
|
235
|
+
|
|
236
|
+
### Builders
|
|
237
|
+
|
|
238
|
+
| 영역 | Entry points |
|
|
239
|
+
| --- | --- |
|
|
240
|
+
| Scalar guard | `t.unknown`, `t.never`, `t.string`, `t.number`, `t.date`, `t.bigint`, `t.symbol`, `t.boolean`, `t.null`, `t.undefined`, `t.void` |
|
|
241
|
+
| String check | `.min`, `.max`, `.length`, `.nonempty`, `.regex`, `.startsWith`, `.endsWith`, `.includes`, `.uuid`, `.email`, `.url`, `.isoDate`, `.isoDateTime`, `.ulid`, `.ipv4`, `.ipv6` |
|
|
242
|
+
| Number check | `.int`, `.finite`, `.safe`, `.gte`, `.lte`, `.min`, `.max`, `.gt`, `.lt`, `.multipleOf`, `.positive`, `.nonnegative`, `.negative`, `.nonpositive` |
|
|
243
|
+
| Date check | `.min`, `.max` |
|
|
244
|
+
| Literal과 container | `t.literal`, `t.enum`, `t.array`, `t.tuple`, tuple rest, `t.record`, `t.map`, `t.set`, `t.json` |
|
|
245
|
+
| Array check | `.min`, `.max`, `.length`, `.nonempty` |
|
|
246
|
+
| Object | `t.object`, `t.strictObject`, `extend`, `safeExtend`, `merge`, `pick`, `omit`, `partial`, `deepPartial`, `required`, `strict`, `passthrough`, `strip`, `catchall` |
|
|
247
|
+
| Runtime object contract | `t.instanceOf`, `t.property`, `guard.property` |
|
|
248
|
+
| Composition | `t.union`, `t.discriminatedUnion`, `t.intersect`, `guard.intersect` |
|
|
249
|
+
| Presence wrapper | `t.optional`, `t.undefinedable`, `t.nullable`, `t.nullish` |
|
|
250
|
+
| Dynamic contract | `t.lazy`, `t.refine` |
|
|
251
|
+
|
|
252
|
+
### Decoders
|
|
253
|
+
|
|
254
|
+
| 영역 | Entry points |
|
|
255
|
+
| --- | --- |
|
|
256
|
+
| Sync decoder | `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()` |
|
|
257
|
+
| Async decoder | `t.asyncDecoder`, `t.asyncRefine`, `t.asyncTransform`, `t.asyncPipe` |
|
|
258
|
+
|
|
259
|
+
### Execution & Export
|
|
260
|
+
|
|
261
|
+
| 영역 | Entry points |
|
|
262
|
+
| --- | --- |
|
|
263
|
+
| Guard method | `guard.is()`, `guard.check()`, `guard.checkFirst()`, `guard.graph()` |
|
|
264
|
+
| Generated validator | `compile`, `emitAotModule` |
|
|
265
|
+
| JSON Schema | `toJsonSchema` |
|
|
266
|
+
|
|
267
|
+
### Messages & Adapters
|
|
268
|
+
|
|
269
|
+
| 영역 | Entry points |
|
|
270
|
+
| --- | --- |
|
|
271
|
+
| Messages / i18n | `formatIssue`, `formatIssues`, `flattenIssues`, `withMessages`, `defineMessages` |
|
|
272
|
+
| tRPC | `toTrpcParser`, `toAsyncTrpcParser` |
|
|
273
|
+
| Fastify | `toFastifyRouteSchema`, `toFastifyValidatorCompiler` |
|
|
274
|
+
| React Hook Form | `toReactHookFormResolver` |
|
|
275
|
+
|
|
276
|
+
adapter도 compiled guard를 받을 수 있습니다.
|
|
277
|
+
startup에서 한 번 compile한 뒤 parser나 validator-compiler adapter에 넘기면 framework hot path가 generated predicate를 재사용합니다.
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
const FastUser = compile(User);
|
|
281
|
+
const trpcParser = toTrpcParser(FastUser);
|
|
282
|
+
const fastifyCompiler = toFastifyValidatorCompiler(FastUser);
|
|
283
|
+
|
|
284
|
+
// 신뢰된 정규화 데이터 전용: 적대적 입력 방어를 direct read 성능과 맞바꿉니다.
|
|
285
|
+
const UnsafeUser = compile(User, { mode: "unsafe" });
|
|
286
|
+
const internalParser = toTrpcParser(UnsafeUser);
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
> [!TIP]
|
|
290
|
+
> source kind에 맞는 inference alias를 쓰세요.
|
|
291
|
+
> guard에는 `Infer<>`, decoder에는 `InferDecoder<>`, async decoder에는 `InferAsyncDecoder<>`를 씁니다.
|
|
292
|
+
> decoder에 `Infer<>`를 적용하면 `never`가 됩니다.
|
|
293
|
+
> downstream type이 갑자기 collapse되면 먼저 이 부분을 확인하세요.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## 경계 동작
|
|
298
|
+
|
|
299
|
+
의도적으로 정한 동작이며 테스트로 고정되어 있습니다.
|
|
300
|
+
|
|
301
|
+
| 입력 | 동작 |
|
|
302
|
+
| --- | --- |
|
|
303
|
+
| `NaN`, `Infinity` | `t.number`는 거부합니다. finite number만 허용합니다. `t.literal(NaN)`은 `NaN`을 match합니다. |
|
|
304
|
+
| `-0` vs `0` | literal은 `Object.is`로 match합니다. diagnostic은 `-0`을 구분해서 format합니다. |
|
|
305
|
+
| Getter-backed properties | 실행하지 않습니다. missing 또는 invalid data로 취급합니다. |
|
|
306
|
+
| `__proto__`, `constructor` keys | pollution 없이 plain own key로 검증합니다. |
|
|
307
|
+
| Sparse array holes | accessor 실행 없이 `undefined`로 읽습니다. |
|
|
308
|
+
| Strict object extras | `Reflect.ownKeys`로 거부합니다. symbol key와 non-enumerable property도 포함합니다. |
|
|
309
|
+
| `catchall` extras | unknown own key는 descriptor로 읽고 catchall schema로 검증합니다. |
|
|
310
|
+
| `strip()` | 출력 객체를 복사하지 않는 검증 전용 alias입니다. TypeSea에서는 extra key 허용 의미가 `passthrough()`와 같습니다. |
|
|
311
|
+
| `t.date` | 유효한 JavaScript `Date` 객체만 허용합니다. `.min`과 `.max`는 사용자가 덮어쓸 수 있는 Date method를 읽지 않고 epoch millisecond로 비교합니다. |
|
|
312
|
+
| `t.map`, `t.set`, `t.instanceOf` | runtime-only contract입니다. JSON Schema와 AOT export에서는 의미를 약화시키지 않고 명시적으로 거부합니다. |
|
|
313
|
+
| `property` | own data property만 검증합니다. getter-backed property는 거부합니다. |
|
|
314
|
+
| Global-flag regexes | construction 시 clone하고, 매 test 전에 `lastIndex`를 reset합니다. |
|
|
315
|
+
| UUID | RFC 9562 version 1-8과 nil UUID를 허용합니다. |
|
|
316
|
+
| Cyclic input values | value x schema active-pair tracking으로 유한하게 검증합니다. |
|
|
317
|
+
| Nesting depth | recursive frame 256에서 cap을 둡니다. 더 깊은 input은 stack overflow 대신 실패합니다. |
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 사용 팁과 주의점
|
|
322
|
+
|
|
323
|
+
> [!WARNING]
|
|
324
|
+
> **recursive guard에는 명시적 type annotation이 필요합니다.**
|
|
325
|
+
> TypeScript는 self-referential initializer를 추론하지 못합니다(TS7022).
|
|
326
|
+
>
|
|
327
|
+
> ```ts
|
|
328
|
+
> interface ListNode {
|
|
329
|
+
> readonly value: string;
|
|
330
|
+
> readonly next?: ListNode;
|
|
331
|
+
> }
|
|
332
|
+
>
|
|
333
|
+
> const Node: Guard<ListNode> = t.lazy((): Guard<ListNode> =>
|
|
334
|
+
> t.object({ value: t.string, next: t.optional(Node) })
|
|
335
|
+
> );
|
|
336
|
+
> ```
|
|
337
|
+
|
|
338
|
+
- **경계 데이터는 `unknown`으로 들어옵니다.** `as`로 미리 좁히지 마세요. builder API는 validation을 통해 narrowing이 일어나도록 typed되어 있습니다.
|
|
339
|
+
- **recursive contract는 `t.lazy`를 통합니다.** 직접 순환하는 schema object는 construction에서 거부합니다.
|
|
340
|
+
- **schema lifetime에 맞춰 engine을 고르세요.** 일회성 schema는 runtime plan, 안정적인 hot schema는 `compile()`, CSP 환경이나 build-time generation은 `emitAotModule()`이 맞습니다.
|
|
341
|
+
- **decoder는 object shape 안에 넣지 않습니다.** decoder를 `t.object` entry와 섞지 말고, validated shape 바깥에서 `t.pipe`로 transformation을 합성하세요.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## 검증
|
|
346
|
+
|
|
347
|
+
CI가 실행하는 gate는 전부 로컬 npm script입니다.
|
|
348
|
+
|
|
349
|
+
```sh
|
|
350
|
+
npm run check # policy, docs, typecheck, lint, tests, build, dist, API snapshot, pack
|
|
351
|
+
npm run check:consumer # tarball install + runtime/type smoke in a temp project
|
|
352
|
+
npm run bench -- --run # benchmark smoke
|
|
353
|
+
npm run pack:dry # package contents dry run
|
|
354
|
+
npm run release:check # the full pre-publish gate
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
`npm run release:check`는 publish 전에 기대하는 동일한 gate를 실행합니다.
|
|
358
|
+
typecheck, lint, tests, build, docs smoke, dist policy, public API snapshot, package contents, consumer install, benchmark smoke, pack dry run을 포함합니다.
|
|
359
|
+
CI는 Node 20.19, 22, 24에서 실행하고, release는 npm provenance와 함께 publish합니다.
|
|
360
|
+
|
|
361
|
+
> [!NOTE]
|
|
362
|
+
> benchmark 비교 패키지인 Zod, Valibot, Ajv는 dev dependency일 뿐입니다.
|
|
363
|
+
> package policy는 이들이 runtime dependency field에 들어가는 것을 거부합니다.
|
|
364
|
+
> benchmark suite는 boolean path와 diagnostic path(`check()` vs `safeParse`)를 모두 보고하므로 비교 기준을 맞춥니다.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## 문서
|
|
369
|
+
|
|
370
|
+
- [문서 사이트](https://feralthedogg.github.io/TypeSea/)
|
|
371
|
+
- [API 레퍼런스](../api.md)
|
|
372
|
+
- [엔진 노트](../engine-notes.md)
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## 라이선스
|
|
377
|
+
|
|
378
|
+
MIT License. 자세한 내용은 [LICENSE](../../LICENSE)를 보세요.
|
package/package.json
CHANGED
|
@@ -1,68 +1,69 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
"name": "typesea",
|
|
3
|
+
"version": "0.3.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/build-docs-site.mjs --check && node scripts/docs-site-check.mjs",
|
|
43
|
+
"check:dist": "node scripts/dist-policy.mjs",
|
|
44
|
+
"check:pack": "node scripts/package-contents.mjs",
|
|
45
|
+
"docs:build": "node scripts/build-docs-site.mjs",
|
|
46
|
+
"lint": "eslint .",
|
|
47
|
+
"pack:dry": "npm pack --dry-run --ignore-scripts",
|
|
48
|
+
"policy": "node scripts/source-policy.mjs",
|
|
49
|
+
"prepack": "npm run check",
|
|
50
|
+
"release:check": "node scripts/release-gate.mjs",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20.19"
|
|
56
|
+
},
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@eslint/js": "^10.0.1",
|
|
60
|
+
"@types/node": "^26.1.0",
|
|
61
|
+
"ajv": "^8.20.0",
|
|
62
|
+
"eslint": "^10.6.0",
|
|
63
|
+
"typescript": "^6.0.3",
|
|
64
|
+
"typescript-eslint": "^8.62.1",
|
|
65
|
+
"valibot": "^1.4.2",
|
|
66
|
+
"vitest": "^4.1.9",
|
|
67
|
+
"zod": "^4.4.3"
|
|
19
68
|
}
|
|
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
69
|
}
|