edgemindroboticslabs commited on
Commit
6dec997
·
verified ·
1 Parent(s): 62519a4

Initial contract-kit library

Browse files
Files changed (16) hide show
  1. .gitignore +6 -0
  2. LICENSE +21 -0
  3. README.md +77 -0
  4. examples/basic.ts +26 -0
  5. package-lock.json +1487 -0
  6. package.json +47 -0
  7. src/adapters.ts +51 -0
  8. src/contract.ts +108 -0
  9. src/errors.ts +27 -0
  10. src/index.ts +20 -0
  11. src/issues.ts +37 -0
  12. src/json.ts +75 -0
  13. src/types.ts +95 -0
  14. test/contract.test.ts +118 -0
  15. tsconfig.json +18 -0
  16. vitest.config.ts +7 -0
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ node_modules
2
+ dist
3
+ coverage
4
+ .npm-cache
5
+ .DS_Store
6
+ *.tgz
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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.
README.md ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contract Kit
2
+
3
+ Schema-first reliability helpers for structured AI outputs.
4
+
5
+ Contract Kit wraps model calls with the guardrails production teams usually end up rebuilding:
6
+
7
+ - JSON extraction from model responses
8
+ - schema validation with Zod or any compatible `.parse()` schema
9
+ - automatic repair retries
10
+ - replayable failure artifacts
11
+ - lightweight event hooks for observability
12
+ - provider adapters without forcing provider SDKs into your dependency tree
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ npm install @krishthesmart/contract-kit zod
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```ts
23
+ import { z } from "zod";
24
+ import { generateContract, openAIResponsesAdapter } from "@krishthesmart/contract-kit";
25
+ import OpenAI from "openai";
26
+
27
+ const client = new OpenAI();
28
+
29
+ const UserProfile = z.object({
30
+ name: z.string(),
31
+ role: z.string(),
32
+ risk: z.enum(["low", "medium", "high"])
33
+ });
34
+
35
+ const result = await generateContract({
36
+ model: openAIResponsesAdapter(client, {
37
+ model: "gpt-4.1-mini",
38
+ temperature: 0
39
+ }),
40
+ schema: UserProfile,
41
+ prompt: "Extract the user's profile from this support ticket: ...",
42
+ retries: 2,
43
+ onEvent(event) {
44
+ console.log(event.type);
45
+ }
46
+ });
47
+
48
+ console.log(result.data);
49
+ ```
50
+
51
+ `result.data` is guaranteed to be the schema output type if the call succeeds.
52
+ If every attempt fails, Contract Kit throws a typed error containing `replay`, which can be saved as a test fixture.
53
+
54
+ ## Model Interface
55
+
56
+ Any model can be used by implementing one method:
57
+
58
+ ```ts
59
+ const model = {
60
+ async generate(prompt: string) {
61
+ return callYourModel(prompt);
62
+ }
63
+ };
64
+ ```
65
+
66
+ ## Why This Exists
67
+
68
+ Structured AI output is still brittle in production. Responses arrive with markdown fences, invalid JSON, changed enum values, missing fields, and provider-specific edge cases. Contract Kit gives application teams a small, auditable boundary where those failures are retried, logged, and turned into reproducible tests.
69
+
70
+ ## Roadmap
71
+
72
+ - Anthropic adapter
73
+ - Vercel AI SDK adapter
74
+ - OpenTelemetry event exporter
75
+ - schema version diffing
76
+ - fixture runner for replay files
77
+ - CLI to turn production failures into regression tests
examples/basic.ts ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { z } from "zod";
2
+ import { generateContract, staticModel } from "@krishthesmart/contract-kit";
3
+
4
+ const UserProfile = z.object({
5
+ name: z.string(),
6
+ role: z.string(),
7
+ risk: z.enum(["low", "medium", "high"])
8
+ });
9
+
10
+ const result = await generateContract({
11
+ model: staticModel([
12
+ JSON.stringify({
13
+ name: "Priya Shah",
14
+ role: "Security Engineering Manager",
15
+ risk: "medium"
16
+ })
17
+ ]),
18
+ schema: UserProfile,
19
+ prompt: "Extract the user's profile from the support ticket.",
20
+ retries: 2,
21
+ onEvent(event) {
22
+ console.log(event.type);
23
+ }
24
+ });
25
+
26
+ console.log(result.data);
package-lock.json ADDED
@@ -0,0 +1,1487 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "@contract-kit/core",
3
+ "version": "0.1.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "@contract-kit/core",
9
+ "version": "0.1.0",
10
+ "license": "MIT",
11
+ "dependencies": {
12
+ "@contract-kit/core": "file:../../outputs/contract-kit-core-0.1.0.tgz"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^22.10.2",
16
+ "typescript": "^5.7.2",
17
+ "vitest": "^2.1.8",
18
+ "zod": "^3.25.76"
19
+ },
20
+ "peerDependencies": {
21
+ "zod": "^3.23.0 || ^4.0.0"
22
+ }
23
+ },
24
+ "node_modules/@contract-kit/core": {
25
+ "version": "0.1.0",
26
+ "resolved": "file:../../outputs/contract-kit-core-0.1.0.tgz",
27
+ "integrity": "sha512-YhwUhwJaHwiAyzJvt7lsK5GzV5/y6h8gCXe7d4ACL9S77qHox6vRkNF1s8PkzTjdddJHLVLknV4HPlT5XZUBGg==",
28
+ "license": "MIT",
29
+ "peerDependencies": {
30
+ "zod": "^3.23.0 || ^4.0.0"
31
+ }
32
+ },
33
+ "node_modules/@esbuild/aix-ppc64": {
34
+ "version": "0.21.5",
35
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
36
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
37
+ "cpu": [
38
+ "ppc64"
39
+ ],
40
+ "dev": true,
41
+ "license": "MIT",
42
+ "optional": true,
43
+ "os": [
44
+ "aix"
45
+ ],
46
+ "engines": {
47
+ "node": ">=12"
48
+ }
49
+ },
50
+ "node_modules/@esbuild/android-arm": {
51
+ "version": "0.21.5",
52
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
53
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
54
+ "cpu": [
55
+ "arm"
56
+ ],
57
+ "dev": true,
58
+ "license": "MIT",
59
+ "optional": true,
60
+ "os": [
61
+ "android"
62
+ ],
63
+ "engines": {
64
+ "node": ">=12"
65
+ }
66
+ },
67
+ "node_modules/@esbuild/android-arm64": {
68
+ "version": "0.21.5",
69
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
70
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
71
+ "cpu": [
72
+ "arm64"
73
+ ],
74
+ "dev": true,
75
+ "license": "MIT",
76
+ "optional": true,
77
+ "os": [
78
+ "android"
79
+ ],
80
+ "engines": {
81
+ "node": ">=12"
82
+ }
83
+ },
84
+ "node_modules/@esbuild/android-x64": {
85
+ "version": "0.21.5",
86
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
87
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
88
+ "cpu": [
89
+ "x64"
90
+ ],
91
+ "dev": true,
92
+ "license": "MIT",
93
+ "optional": true,
94
+ "os": [
95
+ "android"
96
+ ],
97
+ "engines": {
98
+ "node": ">=12"
99
+ }
100
+ },
101
+ "node_modules/@esbuild/darwin-arm64": {
102
+ "version": "0.21.5",
103
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
104
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
105
+ "cpu": [
106
+ "arm64"
107
+ ],
108
+ "dev": true,
109
+ "license": "MIT",
110
+ "optional": true,
111
+ "os": [
112
+ "darwin"
113
+ ],
114
+ "engines": {
115
+ "node": ">=12"
116
+ }
117
+ },
118
+ "node_modules/@esbuild/darwin-x64": {
119
+ "version": "0.21.5",
120
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
121
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
122
+ "cpu": [
123
+ "x64"
124
+ ],
125
+ "dev": true,
126
+ "license": "MIT",
127
+ "optional": true,
128
+ "os": [
129
+ "darwin"
130
+ ],
131
+ "engines": {
132
+ "node": ">=12"
133
+ }
134
+ },
135
+ "node_modules/@esbuild/freebsd-arm64": {
136
+ "version": "0.21.5",
137
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
138
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
139
+ "cpu": [
140
+ "arm64"
141
+ ],
142
+ "dev": true,
143
+ "license": "MIT",
144
+ "optional": true,
145
+ "os": [
146
+ "freebsd"
147
+ ],
148
+ "engines": {
149
+ "node": ">=12"
150
+ }
151
+ },
152
+ "node_modules/@esbuild/freebsd-x64": {
153
+ "version": "0.21.5",
154
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
155
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
156
+ "cpu": [
157
+ "x64"
158
+ ],
159
+ "dev": true,
160
+ "license": "MIT",
161
+ "optional": true,
162
+ "os": [
163
+ "freebsd"
164
+ ],
165
+ "engines": {
166
+ "node": ">=12"
167
+ }
168
+ },
169
+ "node_modules/@esbuild/linux-arm": {
170
+ "version": "0.21.5",
171
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
172
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
173
+ "cpu": [
174
+ "arm"
175
+ ],
176
+ "dev": true,
177
+ "license": "MIT",
178
+ "optional": true,
179
+ "os": [
180
+ "linux"
181
+ ],
182
+ "engines": {
183
+ "node": ">=12"
184
+ }
185
+ },
186
+ "node_modules/@esbuild/linux-arm64": {
187
+ "version": "0.21.5",
188
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
189
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
190
+ "cpu": [
191
+ "arm64"
192
+ ],
193
+ "dev": true,
194
+ "license": "MIT",
195
+ "optional": true,
196
+ "os": [
197
+ "linux"
198
+ ],
199
+ "engines": {
200
+ "node": ">=12"
201
+ }
202
+ },
203
+ "node_modules/@esbuild/linux-ia32": {
204
+ "version": "0.21.5",
205
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
206
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
207
+ "cpu": [
208
+ "ia32"
209
+ ],
210
+ "dev": true,
211
+ "license": "MIT",
212
+ "optional": true,
213
+ "os": [
214
+ "linux"
215
+ ],
216
+ "engines": {
217
+ "node": ">=12"
218
+ }
219
+ },
220
+ "node_modules/@esbuild/linux-loong64": {
221
+ "version": "0.21.5",
222
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
223
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
224
+ "cpu": [
225
+ "loong64"
226
+ ],
227
+ "dev": true,
228
+ "license": "MIT",
229
+ "optional": true,
230
+ "os": [
231
+ "linux"
232
+ ],
233
+ "engines": {
234
+ "node": ">=12"
235
+ }
236
+ },
237
+ "node_modules/@esbuild/linux-mips64el": {
238
+ "version": "0.21.5",
239
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
240
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
241
+ "cpu": [
242
+ "mips64el"
243
+ ],
244
+ "dev": true,
245
+ "license": "MIT",
246
+ "optional": true,
247
+ "os": [
248
+ "linux"
249
+ ],
250
+ "engines": {
251
+ "node": ">=12"
252
+ }
253
+ },
254
+ "node_modules/@esbuild/linux-ppc64": {
255
+ "version": "0.21.5",
256
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
257
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
258
+ "cpu": [
259
+ "ppc64"
260
+ ],
261
+ "dev": true,
262
+ "license": "MIT",
263
+ "optional": true,
264
+ "os": [
265
+ "linux"
266
+ ],
267
+ "engines": {
268
+ "node": ">=12"
269
+ }
270
+ },
271
+ "node_modules/@esbuild/linux-riscv64": {
272
+ "version": "0.21.5",
273
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
274
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
275
+ "cpu": [
276
+ "riscv64"
277
+ ],
278
+ "dev": true,
279
+ "license": "MIT",
280
+ "optional": true,
281
+ "os": [
282
+ "linux"
283
+ ],
284
+ "engines": {
285
+ "node": ">=12"
286
+ }
287
+ },
288
+ "node_modules/@esbuild/linux-s390x": {
289
+ "version": "0.21.5",
290
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
291
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
292
+ "cpu": [
293
+ "s390x"
294
+ ],
295
+ "dev": true,
296
+ "license": "MIT",
297
+ "optional": true,
298
+ "os": [
299
+ "linux"
300
+ ],
301
+ "engines": {
302
+ "node": ">=12"
303
+ }
304
+ },
305
+ "node_modules/@esbuild/linux-x64": {
306
+ "version": "0.21.5",
307
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
308
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
309
+ "cpu": [
310
+ "x64"
311
+ ],
312
+ "dev": true,
313
+ "license": "MIT",
314
+ "optional": true,
315
+ "os": [
316
+ "linux"
317
+ ],
318
+ "engines": {
319
+ "node": ">=12"
320
+ }
321
+ },
322
+ "node_modules/@esbuild/netbsd-x64": {
323
+ "version": "0.21.5",
324
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
325
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
326
+ "cpu": [
327
+ "x64"
328
+ ],
329
+ "dev": true,
330
+ "license": "MIT",
331
+ "optional": true,
332
+ "os": [
333
+ "netbsd"
334
+ ],
335
+ "engines": {
336
+ "node": ">=12"
337
+ }
338
+ },
339
+ "node_modules/@esbuild/openbsd-x64": {
340
+ "version": "0.21.5",
341
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
342
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
343
+ "cpu": [
344
+ "x64"
345
+ ],
346
+ "dev": true,
347
+ "license": "MIT",
348
+ "optional": true,
349
+ "os": [
350
+ "openbsd"
351
+ ],
352
+ "engines": {
353
+ "node": ">=12"
354
+ }
355
+ },
356
+ "node_modules/@esbuild/sunos-x64": {
357
+ "version": "0.21.5",
358
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
359
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
360
+ "cpu": [
361
+ "x64"
362
+ ],
363
+ "dev": true,
364
+ "license": "MIT",
365
+ "optional": true,
366
+ "os": [
367
+ "sunos"
368
+ ],
369
+ "engines": {
370
+ "node": ">=12"
371
+ }
372
+ },
373
+ "node_modules/@esbuild/win32-arm64": {
374
+ "version": "0.21.5",
375
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
376
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
377
+ "cpu": [
378
+ "arm64"
379
+ ],
380
+ "dev": true,
381
+ "license": "MIT",
382
+ "optional": true,
383
+ "os": [
384
+ "win32"
385
+ ],
386
+ "engines": {
387
+ "node": ">=12"
388
+ }
389
+ },
390
+ "node_modules/@esbuild/win32-ia32": {
391
+ "version": "0.21.5",
392
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
393
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
394
+ "cpu": [
395
+ "ia32"
396
+ ],
397
+ "dev": true,
398
+ "license": "MIT",
399
+ "optional": true,
400
+ "os": [
401
+ "win32"
402
+ ],
403
+ "engines": {
404
+ "node": ">=12"
405
+ }
406
+ },
407
+ "node_modules/@esbuild/win32-x64": {
408
+ "version": "0.21.5",
409
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
410
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
411
+ "cpu": [
412
+ "x64"
413
+ ],
414
+ "dev": true,
415
+ "license": "MIT",
416
+ "optional": true,
417
+ "os": [
418
+ "win32"
419
+ ],
420
+ "engines": {
421
+ "node": ">=12"
422
+ }
423
+ },
424
+ "node_modules/@jridgewell/sourcemap-codec": {
425
+ "version": "1.5.5",
426
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
427
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
428
+ "dev": true,
429
+ "license": "MIT"
430
+ },
431
+ "node_modules/@rollup/rollup-android-arm-eabi": {
432
+ "version": "4.60.4",
433
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz",
434
+ "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==",
435
+ "cpu": [
436
+ "arm"
437
+ ],
438
+ "dev": true,
439
+ "license": "MIT",
440
+ "optional": true,
441
+ "os": [
442
+ "android"
443
+ ]
444
+ },
445
+ "node_modules/@rollup/rollup-android-arm64": {
446
+ "version": "4.60.4",
447
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz",
448
+ "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==",
449
+ "cpu": [
450
+ "arm64"
451
+ ],
452
+ "dev": true,
453
+ "license": "MIT",
454
+ "optional": true,
455
+ "os": [
456
+ "android"
457
+ ]
458
+ },
459
+ "node_modules/@rollup/rollup-darwin-arm64": {
460
+ "version": "4.60.4",
461
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz",
462
+ "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==",
463
+ "cpu": [
464
+ "arm64"
465
+ ],
466
+ "dev": true,
467
+ "license": "MIT",
468
+ "optional": true,
469
+ "os": [
470
+ "darwin"
471
+ ]
472
+ },
473
+ "node_modules/@rollup/rollup-darwin-x64": {
474
+ "version": "4.60.4",
475
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz",
476
+ "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==",
477
+ "cpu": [
478
+ "x64"
479
+ ],
480
+ "dev": true,
481
+ "license": "MIT",
482
+ "optional": true,
483
+ "os": [
484
+ "darwin"
485
+ ]
486
+ },
487
+ "node_modules/@rollup/rollup-freebsd-arm64": {
488
+ "version": "4.60.4",
489
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz",
490
+ "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==",
491
+ "cpu": [
492
+ "arm64"
493
+ ],
494
+ "dev": true,
495
+ "license": "MIT",
496
+ "optional": true,
497
+ "os": [
498
+ "freebsd"
499
+ ]
500
+ },
501
+ "node_modules/@rollup/rollup-freebsd-x64": {
502
+ "version": "4.60.4",
503
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz",
504
+ "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==",
505
+ "cpu": [
506
+ "x64"
507
+ ],
508
+ "dev": true,
509
+ "license": "MIT",
510
+ "optional": true,
511
+ "os": [
512
+ "freebsd"
513
+ ]
514
+ },
515
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
516
+ "version": "4.60.4",
517
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz",
518
+ "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==",
519
+ "cpu": [
520
+ "arm"
521
+ ],
522
+ "dev": true,
523
+ "license": "MIT",
524
+ "optional": true,
525
+ "os": [
526
+ "linux"
527
+ ]
528
+ },
529
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
530
+ "version": "4.60.4",
531
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz",
532
+ "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==",
533
+ "cpu": [
534
+ "arm"
535
+ ],
536
+ "dev": true,
537
+ "license": "MIT",
538
+ "optional": true,
539
+ "os": [
540
+ "linux"
541
+ ]
542
+ },
543
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
544
+ "version": "4.60.4",
545
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz",
546
+ "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==",
547
+ "cpu": [
548
+ "arm64"
549
+ ],
550
+ "dev": true,
551
+ "license": "MIT",
552
+ "optional": true,
553
+ "os": [
554
+ "linux"
555
+ ]
556
+ },
557
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
558
+ "version": "4.60.4",
559
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz",
560
+ "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==",
561
+ "cpu": [
562
+ "arm64"
563
+ ],
564
+ "dev": true,
565
+ "license": "MIT",
566
+ "optional": true,
567
+ "os": [
568
+ "linux"
569
+ ]
570
+ },
571
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
572
+ "version": "4.60.4",
573
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz",
574
+ "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==",
575
+ "cpu": [
576
+ "loong64"
577
+ ],
578
+ "dev": true,
579
+ "license": "MIT",
580
+ "optional": true,
581
+ "os": [
582
+ "linux"
583
+ ]
584
+ },
585
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
586
+ "version": "4.60.4",
587
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz",
588
+ "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==",
589
+ "cpu": [
590
+ "loong64"
591
+ ],
592
+ "dev": true,
593
+ "license": "MIT",
594
+ "optional": true,
595
+ "os": [
596
+ "linux"
597
+ ]
598
+ },
599
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
600
+ "version": "4.60.4",
601
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz",
602
+ "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==",
603
+ "cpu": [
604
+ "ppc64"
605
+ ],
606
+ "dev": true,
607
+ "license": "MIT",
608
+ "optional": true,
609
+ "os": [
610
+ "linux"
611
+ ]
612
+ },
613
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
614
+ "version": "4.60.4",
615
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz",
616
+ "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==",
617
+ "cpu": [
618
+ "ppc64"
619
+ ],
620
+ "dev": true,
621
+ "license": "MIT",
622
+ "optional": true,
623
+ "os": [
624
+ "linux"
625
+ ]
626
+ },
627
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
628
+ "version": "4.60.4",
629
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz",
630
+ "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==",
631
+ "cpu": [
632
+ "riscv64"
633
+ ],
634
+ "dev": true,
635
+ "license": "MIT",
636
+ "optional": true,
637
+ "os": [
638
+ "linux"
639
+ ]
640
+ },
641
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
642
+ "version": "4.60.4",
643
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz",
644
+ "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==",
645
+ "cpu": [
646
+ "riscv64"
647
+ ],
648
+ "dev": true,
649
+ "license": "MIT",
650
+ "optional": true,
651
+ "os": [
652
+ "linux"
653
+ ]
654
+ },
655
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
656
+ "version": "4.60.4",
657
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz",
658
+ "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==",
659
+ "cpu": [
660
+ "s390x"
661
+ ],
662
+ "dev": true,
663
+ "license": "MIT",
664
+ "optional": true,
665
+ "os": [
666
+ "linux"
667
+ ]
668
+ },
669
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
670
+ "version": "4.60.4",
671
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz",
672
+ "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==",
673
+ "cpu": [
674
+ "x64"
675
+ ],
676
+ "dev": true,
677
+ "license": "MIT",
678
+ "optional": true,
679
+ "os": [
680
+ "linux"
681
+ ]
682
+ },
683
+ "node_modules/@rollup/rollup-linux-x64-musl": {
684
+ "version": "4.60.4",
685
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz",
686
+ "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==",
687
+ "cpu": [
688
+ "x64"
689
+ ],
690
+ "dev": true,
691
+ "license": "MIT",
692
+ "optional": true,
693
+ "os": [
694
+ "linux"
695
+ ]
696
+ },
697
+ "node_modules/@rollup/rollup-openbsd-x64": {
698
+ "version": "4.60.4",
699
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz",
700
+ "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==",
701
+ "cpu": [
702
+ "x64"
703
+ ],
704
+ "dev": true,
705
+ "license": "MIT",
706
+ "optional": true,
707
+ "os": [
708
+ "openbsd"
709
+ ]
710
+ },
711
+ "node_modules/@rollup/rollup-openharmony-arm64": {
712
+ "version": "4.60.4",
713
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz",
714
+ "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==",
715
+ "cpu": [
716
+ "arm64"
717
+ ],
718
+ "dev": true,
719
+ "license": "MIT",
720
+ "optional": true,
721
+ "os": [
722
+ "openharmony"
723
+ ]
724
+ },
725
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
726
+ "version": "4.60.4",
727
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz",
728
+ "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==",
729
+ "cpu": [
730
+ "arm64"
731
+ ],
732
+ "dev": true,
733
+ "license": "MIT",
734
+ "optional": true,
735
+ "os": [
736
+ "win32"
737
+ ]
738
+ },
739
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
740
+ "version": "4.60.4",
741
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz",
742
+ "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==",
743
+ "cpu": [
744
+ "ia32"
745
+ ],
746
+ "dev": true,
747
+ "license": "MIT",
748
+ "optional": true,
749
+ "os": [
750
+ "win32"
751
+ ]
752
+ },
753
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
754
+ "version": "4.60.4",
755
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz",
756
+ "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==",
757
+ "cpu": [
758
+ "x64"
759
+ ],
760
+ "dev": true,
761
+ "license": "MIT",
762
+ "optional": true,
763
+ "os": [
764
+ "win32"
765
+ ]
766
+ },
767
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
768
+ "version": "4.60.4",
769
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz",
770
+ "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==",
771
+ "cpu": [
772
+ "x64"
773
+ ],
774
+ "dev": true,
775
+ "license": "MIT",
776
+ "optional": true,
777
+ "os": [
778
+ "win32"
779
+ ]
780
+ },
781
+ "node_modules/@types/estree": {
782
+ "version": "1.0.9",
783
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
784
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
785
+ "dev": true,
786
+ "license": "MIT"
787
+ },
788
+ "node_modules/@types/node": {
789
+ "version": "22.19.19",
790
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz",
791
+ "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==",
792
+ "dev": true,
793
+ "license": "MIT",
794
+ "dependencies": {
795
+ "undici-types": "~6.21.0"
796
+ }
797
+ },
798
+ "node_modules/@vitest/expect": {
799
+ "version": "2.1.9",
800
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz",
801
+ "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==",
802
+ "dev": true,
803
+ "license": "MIT",
804
+ "dependencies": {
805
+ "@vitest/spy": "2.1.9",
806
+ "@vitest/utils": "2.1.9",
807
+ "chai": "^5.1.2",
808
+ "tinyrainbow": "^1.2.0"
809
+ },
810
+ "funding": {
811
+ "url": "https://opencollective.com/vitest"
812
+ }
813
+ },
814
+ "node_modules/@vitest/mocker": {
815
+ "version": "2.1.9",
816
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz",
817
+ "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==",
818
+ "dev": true,
819
+ "license": "MIT",
820
+ "dependencies": {
821
+ "@vitest/spy": "2.1.9",
822
+ "estree-walker": "^3.0.3",
823
+ "magic-string": "^0.30.12"
824
+ },
825
+ "funding": {
826
+ "url": "https://opencollective.com/vitest"
827
+ },
828
+ "peerDependencies": {
829
+ "msw": "^2.4.9",
830
+ "vite": "^5.0.0"
831
+ },
832
+ "peerDependenciesMeta": {
833
+ "msw": {
834
+ "optional": true
835
+ },
836
+ "vite": {
837
+ "optional": true
838
+ }
839
+ }
840
+ },
841
+ "node_modules/@vitest/pretty-format": {
842
+ "version": "2.1.9",
843
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz",
844
+ "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==",
845
+ "dev": true,
846
+ "license": "MIT",
847
+ "dependencies": {
848
+ "tinyrainbow": "^1.2.0"
849
+ },
850
+ "funding": {
851
+ "url": "https://opencollective.com/vitest"
852
+ }
853
+ },
854
+ "node_modules/@vitest/runner": {
855
+ "version": "2.1.9",
856
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz",
857
+ "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==",
858
+ "dev": true,
859
+ "license": "MIT",
860
+ "dependencies": {
861
+ "@vitest/utils": "2.1.9",
862
+ "pathe": "^1.1.2"
863
+ },
864
+ "funding": {
865
+ "url": "https://opencollective.com/vitest"
866
+ }
867
+ },
868
+ "node_modules/@vitest/snapshot": {
869
+ "version": "2.1.9",
870
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz",
871
+ "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==",
872
+ "dev": true,
873
+ "license": "MIT",
874
+ "dependencies": {
875
+ "@vitest/pretty-format": "2.1.9",
876
+ "magic-string": "^0.30.12",
877
+ "pathe": "^1.1.2"
878
+ },
879
+ "funding": {
880
+ "url": "https://opencollective.com/vitest"
881
+ }
882
+ },
883
+ "node_modules/@vitest/spy": {
884
+ "version": "2.1.9",
885
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz",
886
+ "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==",
887
+ "dev": true,
888
+ "license": "MIT",
889
+ "dependencies": {
890
+ "tinyspy": "^3.0.2"
891
+ },
892
+ "funding": {
893
+ "url": "https://opencollective.com/vitest"
894
+ }
895
+ },
896
+ "node_modules/@vitest/utils": {
897
+ "version": "2.1.9",
898
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz",
899
+ "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==",
900
+ "dev": true,
901
+ "license": "MIT",
902
+ "dependencies": {
903
+ "@vitest/pretty-format": "2.1.9",
904
+ "loupe": "^3.1.2",
905
+ "tinyrainbow": "^1.2.0"
906
+ },
907
+ "funding": {
908
+ "url": "https://opencollective.com/vitest"
909
+ }
910
+ },
911
+ "node_modules/assertion-error": {
912
+ "version": "2.0.1",
913
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
914
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
915
+ "dev": true,
916
+ "license": "MIT",
917
+ "engines": {
918
+ "node": ">=12"
919
+ }
920
+ },
921
+ "node_modules/cac": {
922
+ "version": "6.7.14",
923
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
924
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
925
+ "dev": true,
926
+ "license": "MIT",
927
+ "engines": {
928
+ "node": ">=8"
929
+ }
930
+ },
931
+ "node_modules/chai": {
932
+ "version": "5.3.3",
933
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
934
+ "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
935
+ "dev": true,
936
+ "license": "MIT",
937
+ "dependencies": {
938
+ "assertion-error": "^2.0.1",
939
+ "check-error": "^2.1.1",
940
+ "deep-eql": "^5.0.1",
941
+ "loupe": "^3.1.0",
942
+ "pathval": "^2.0.0"
943
+ },
944
+ "engines": {
945
+ "node": ">=18"
946
+ }
947
+ },
948
+ "node_modules/check-error": {
949
+ "version": "2.1.3",
950
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
951
+ "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
952
+ "dev": true,
953
+ "license": "MIT",
954
+ "engines": {
955
+ "node": ">= 16"
956
+ }
957
+ },
958
+ "node_modules/debug": {
959
+ "version": "4.4.3",
960
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
961
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
962
+ "dev": true,
963
+ "license": "MIT",
964
+ "dependencies": {
965
+ "ms": "^2.1.3"
966
+ },
967
+ "engines": {
968
+ "node": ">=6.0"
969
+ },
970
+ "peerDependenciesMeta": {
971
+ "supports-color": {
972
+ "optional": true
973
+ }
974
+ }
975
+ },
976
+ "node_modules/deep-eql": {
977
+ "version": "5.0.2",
978
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
979
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
980
+ "dev": true,
981
+ "license": "MIT",
982
+ "engines": {
983
+ "node": ">=6"
984
+ }
985
+ },
986
+ "node_modules/es-module-lexer": {
987
+ "version": "1.7.0",
988
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
989
+ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
990
+ "dev": true,
991
+ "license": "MIT"
992
+ },
993
+ "node_modules/esbuild": {
994
+ "version": "0.21.5",
995
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
996
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
997
+ "dev": true,
998
+ "hasInstallScript": true,
999
+ "license": "MIT",
1000
+ "bin": {
1001
+ "esbuild": "bin/esbuild"
1002
+ },
1003
+ "engines": {
1004
+ "node": ">=12"
1005
+ },
1006
+ "optionalDependencies": {
1007
+ "@esbuild/aix-ppc64": "0.21.5",
1008
+ "@esbuild/android-arm": "0.21.5",
1009
+ "@esbuild/android-arm64": "0.21.5",
1010
+ "@esbuild/android-x64": "0.21.5",
1011
+ "@esbuild/darwin-arm64": "0.21.5",
1012
+ "@esbuild/darwin-x64": "0.21.5",
1013
+ "@esbuild/freebsd-arm64": "0.21.5",
1014
+ "@esbuild/freebsd-x64": "0.21.5",
1015
+ "@esbuild/linux-arm": "0.21.5",
1016
+ "@esbuild/linux-arm64": "0.21.5",
1017
+ "@esbuild/linux-ia32": "0.21.5",
1018
+ "@esbuild/linux-loong64": "0.21.5",
1019
+ "@esbuild/linux-mips64el": "0.21.5",
1020
+ "@esbuild/linux-ppc64": "0.21.5",
1021
+ "@esbuild/linux-riscv64": "0.21.5",
1022
+ "@esbuild/linux-s390x": "0.21.5",
1023
+ "@esbuild/linux-x64": "0.21.5",
1024
+ "@esbuild/netbsd-x64": "0.21.5",
1025
+ "@esbuild/openbsd-x64": "0.21.5",
1026
+ "@esbuild/sunos-x64": "0.21.5",
1027
+ "@esbuild/win32-arm64": "0.21.5",
1028
+ "@esbuild/win32-ia32": "0.21.5",
1029
+ "@esbuild/win32-x64": "0.21.5"
1030
+ }
1031
+ },
1032
+ "node_modules/estree-walker": {
1033
+ "version": "3.0.3",
1034
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
1035
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
1036
+ "dev": true,
1037
+ "license": "MIT",
1038
+ "dependencies": {
1039
+ "@types/estree": "^1.0.0"
1040
+ }
1041
+ },
1042
+ "node_modules/expect-type": {
1043
+ "version": "1.3.0",
1044
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
1045
+ "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
1046
+ "dev": true,
1047
+ "license": "Apache-2.0",
1048
+ "engines": {
1049
+ "node": ">=12.0.0"
1050
+ }
1051
+ },
1052
+ "node_modules/fsevents": {
1053
+ "version": "2.3.3",
1054
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1055
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1056
+ "dev": true,
1057
+ "hasInstallScript": true,
1058
+ "license": "MIT",
1059
+ "optional": true,
1060
+ "os": [
1061
+ "darwin"
1062
+ ],
1063
+ "engines": {
1064
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1065
+ }
1066
+ },
1067
+ "node_modules/loupe": {
1068
+ "version": "3.2.1",
1069
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
1070
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
1071
+ "dev": true,
1072
+ "license": "MIT"
1073
+ },
1074
+ "node_modules/magic-string": {
1075
+ "version": "0.30.21",
1076
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
1077
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
1078
+ "dev": true,
1079
+ "license": "MIT",
1080
+ "dependencies": {
1081
+ "@jridgewell/sourcemap-codec": "^1.5.5"
1082
+ }
1083
+ },
1084
+ "node_modules/ms": {
1085
+ "version": "2.1.3",
1086
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1087
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1088
+ "dev": true,
1089
+ "license": "MIT"
1090
+ },
1091
+ "node_modules/nanoid": {
1092
+ "version": "3.3.12",
1093
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
1094
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
1095
+ "dev": true,
1096
+ "funding": [
1097
+ {
1098
+ "type": "github",
1099
+ "url": "https://github.com/sponsors/ai"
1100
+ }
1101
+ ],
1102
+ "license": "MIT",
1103
+ "bin": {
1104
+ "nanoid": "bin/nanoid.cjs"
1105
+ },
1106
+ "engines": {
1107
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1108
+ }
1109
+ },
1110
+ "node_modules/pathe": {
1111
+ "version": "1.1.2",
1112
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
1113
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
1114
+ "dev": true,
1115
+ "license": "MIT"
1116
+ },
1117
+ "node_modules/pathval": {
1118
+ "version": "2.0.1",
1119
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
1120
+ "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
1121
+ "dev": true,
1122
+ "license": "MIT",
1123
+ "engines": {
1124
+ "node": ">= 14.16"
1125
+ }
1126
+ },
1127
+ "node_modules/picocolors": {
1128
+ "version": "1.1.1",
1129
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1130
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1131
+ "dev": true,
1132
+ "license": "ISC"
1133
+ },
1134
+ "node_modules/postcss": {
1135
+ "version": "8.5.15",
1136
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
1137
+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
1138
+ "dev": true,
1139
+ "funding": [
1140
+ {
1141
+ "type": "opencollective",
1142
+ "url": "https://opencollective.com/postcss/"
1143
+ },
1144
+ {
1145
+ "type": "tidelift",
1146
+ "url": "https://tidelift.com/funding/github/npm/postcss"
1147
+ },
1148
+ {
1149
+ "type": "github",
1150
+ "url": "https://github.com/sponsors/ai"
1151
+ }
1152
+ ],
1153
+ "license": "MIT",
1154
+ "dependencies": {
1155
+ "nanoid": "^3.3.12",
1156
+ "picocolors": "^1.1.1",
1157
+ "source-map-js": "^1.2.1"
1158
+ },
1159
+ "engines": {
1160
+ "node": "^10 || ^12 || >=14"
1161
+ }
1162
+ },
1163
+ "node_modules/rollup": {
1164
+ "version": "4.60.4",
1165
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz",
1166
+ "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==",
1167
+ "dev": true,
1168
+ "license": "MIT",
1169
+ "dependencies": {
1170
+ "@types/estree": "1.0.8"
1171
+ },
1172
+ "bin": {
1173
+ "rollup": "dist/bin/rollup"
1174
+ },
1175
+ "engines": {
1176
+ "node": ">=18.0.0",
1177
+ "npm": ">=8.0.0"
1178
+ },
1179
+ "optionalDependencies": {
1180
+ "@rollup/rollup-android-arm-eabi": "4.60.4",
1181
+ "@rollup/rollup-android-arm64": "4.60.4",
1182
+ "@rollup/rollup-darwin-arm64": "4.60.4",
1183
+ "@rollup/rollup-darwin-x64": "4.60.4",
1184
+ "@rollup/rollup-freebsd-arm64": "4.60.4",
1185
+ "@rollup/rollup-freebsd-x64": "4.60.4",
1186
+ "@rollup/rollup-linux-arm-gnueabihf": "4.60.4",
1187
+ "@rollup/rollup-linux-arm-musleabihf": "4.60.4",
1188
+ "@rollup/rollup-linux-arm64-gnu": "4.60.4",
1189
+ "@rollup/rollup-linux-arm64-musl": "4.60.4",
1190
+ "@rollup/rollup-linux-loong64-gnu": "4.60.4",
1191
+ "@rollup/rollup-linux-loong64-musl": "4.60.4",
1192
+ "@rollup/rollup-linux-ppc64-gnu": "4.60.4",
1193
+ "@rollup/rollup-linux-ppc64-musl": "4.60.4",
1194
+ "@rollup/rollup-linux-riscv64-gnu": "4.60.4",
1195
+ "@rollup/rollup-linux-riscv64-musl": "4.60.4",
1196
+ "@rollup/rollup-linux-s390x-gnu": "4.60.4",
1197
+ "@rollup/rollup-linux-x64-gnu": "4.60.4",
1198
+ "@rollup/rollup-linux-x64-musl": "4.60.4",
1199
+ "@rollup/rollup-openbsd-x64": "4.60.4",
1200
+ "@rollup/rollup-openharmony-arm64": "4.60.4",
1201
+ "@rollup/rollup-win32-arm64-msvc": "4.60.4",
1202
+ "@rollup/rollup-win32-ia32-msvc": "4.60.4",
1203
+ "@rollup/rollup-win32-x64-gnu": "4.60.4",
1204
+ "@rollup/rollup-win32-x64-msvc": "4.60.4",
1205
+ "fsevents": "~2.3.2"
1206
+ }
1207
+ },
1208
+ "node_modules/rollup/node_modules/@types/estree": {
1209
+ "version": "1.0.8",
1210
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1211
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1212
+ "dev": true,
1213
+ "license": "MIT"
1214
+ },
1215
+ "node_modules/siginfo": {
1216
+ "version": "2.0.0",
1217
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
1218
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
1219
+ "dev": true,
1220
+ "license": "ISC"
1221
+ },
1222
+ "node_modules/source-map-js": {
1223
+ "version": "1.2.1",
1224
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
1225
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1226
+ "dev": true,
1227
+ "license": "BSD-3-Clause",
1228
+ "engines": {
1229
+ "node": ">=0.10.0"
1230
+ }
1231
+ },
1232
+ "node_modules/stackback": {
1233
+ "version": "0.0.2",
1234
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
1235
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
1236
+ "dev": true,
1237
+ "license": "MIT"
1238
+ },
1239
+ "node_modules/std-env": {
1240
+ "version": "3.10.0",
1241
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
1242
+ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
1243
+ "dev": true,
1244
+ "license": "MIT"
1245
+ },
1246
+ "node_modules/tinybench": {
1247
+ "version": "2.9.0",
1248
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
1249
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
1250
+ "dev": true,
1251
+ "license": "MIT"
1252
+ },
1253
+ "node_modules/tinyexec": {
1254
+ "version": "0.3.2",
1255
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
1256
+ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
1257
+ "dev": true,
1258
+ "license": "MIT"
1259
+ },
1260
+ "node_modules/tinypool": {
1261
+ "version": "1.1.1",
1262
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
1263
+ "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
1264
+ "dev": true,
1265
+ "license": "MIT",
1266
+ "engines": {
1267
+ "node": "^18.0.0 || >=20.0.0"
1268
+ }
1269
+ },
1270
+ "node_modules/tinyrainbow": {
1271
+ "version": "1.2.0",
1272
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
1273
+ "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
1274
+ "dev": true,
1275
+ "license": "MIT",
1276
+ "engines": {
1277
+ "node": ">=14.0.0"
1278
+ }
1279
+ },
1280
+ "node_modules/tinyspy": {
1281
+ "version": "3.0.2",
1282
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
1283
+ "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
1284
+ "dev": true,
1285
+ "license": "MIT",
1286
+ "engines": {
1287
+ "node": ">=14.0.0"
1288
+ }
1289
+ },
1290
+ "node_modules/typescript": {
1291
+ "version": "5.9.3",
1292
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
1293
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
1294
+ "dev": true,
1295
+ "license": "Apache-2.0",
1296
+ "bin": {
1297
+ "tsc": "bin/tsc",
1298
+ "tsserver": "bin/tsserver"
1299
+ },
1300
+ "engines": {
1301
+ "node": ">=14.17"
1302
+ }
1303
+ },
1304
+ "node_modules/undici-types": {
1305
+ "version": "6.21.0",
1306
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
1307
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
1308
+ "dev": true,
1309
+ "license": "MIT"
1310
+ },
1311
+ "node_modules/vite": {
1312
+ "version": "5.4.21",
1313
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
1314
+ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
1315
+ "dev": true,
1316
+ "license": "MIT",
1317
+ "dependencies": {
1318
+ "esbuild": "^0.21.3",
1319
+ "postcss": "^8.4.43",
1320
+ "rollup": "^4.20.0"
1321
+ },
1322
+ "bin": {
1323
+ "vite": "bin/vite.js"
1324
+ },
1325
+ "engines": {
1326
+ "node": "^18.0.0 || >=20.0.0"
1327
+ },
1328
+ "funding": {
1329
+ "url": "https://github.com/vitejs/vite?sponsor=1"
1330
+ },
1331
+ "optionalDependencies": {
1332
+ "fsevents": "~2.3.3"
1333
+ },
1334
+ "peerDependencies": {
1335
+ "@types/node": "^18.0.0 || >=20.0.0",
1336
+ "less": "*",
1337
+ "lightningcss": "^1.21.0",
1338
+ "sass": "*",
1339
+ "sass-embedded": "*",
1340
+ "stylus": "*",
1341
+ "sugarss": "*",
1342
+ "terser": "^5.4.0"
1343
+ },
1344
+ "peerDependenciesMeta": {
1345
+ "@types/node": {
1346
+ "optional": true
1347
+ },
1348
+ "less": {
1349
+ "optional": true
1350
+ },
1351
+ "lightningcss": {
1352
+ "optional": true
1353
+ },
1354
+ "sass": {
1355
+ "optional": true
1356
+ },
1357
+ "sass-embedded": {
1358
+ "optional": true
1359
+ },
1360
+ "stylus": {
1361
+ "optional": true
1362
+ },
1363
+ "sugarss": {
1364
+ "optional": true
1365
+ },
1366
+ "terser": {
1367
+ "optional": true
1368
+ }
1369
+ }
1370
+ },
1371
+ "node_modules/vite-node": {
1372
+ "version": "2.1.9",
1373
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz",
1374
+ "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==",
1375
+ "dev": true,
1376
+ "license": "MIT",
1377
+ "dependencies": {
1378
+ "cac": "^6.7.14",
1379
+ "debug": "^4.3.7",
1380
+ "es-module-lexer": "^1.5.4",
1381
+ "pathe": "^1.1.2",
1382
+ "vite": "^5.0.0"
1383
+ },
1384
+ "bin": {
1385
+ "vite-node": "vite-node.mjs"
1386
+ },
1387
+ "engines": {
1388
+ "node": "^18.0.0 || >=20.0.0"
1389
+ },
1390
+ "funding": {
1391
+ "url": "https://opencollective.com/vitest"
1392
+ }
1393
+ },
1394
+ "node_modules/vitest": {
1395
+ "version": "2.1.9",
1396
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz",
1397
+ "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==",
1398
+ "dev": true,
1399
+ "license": "MIT",
1400
+ "dependencies": {
1401
+ "@vitest/expect": "2.1.9",
1402
+ "@vitest/mocker": "2.1.9",
1403
+ "@vitest/pretty-format": "^2.1.9",
1404
+ "@vitest/runner": "2.1.9",
1405
+ "@vitest/snapshot": "2.1.9",
1406
+ "@vitest/spy": "2.1.9",
1407
+ "@vitest/utils": "2.1.9",
1408
+ "chai": "^5.1.2",
1409
+ "debug": "^4.3.7",
1410
+ "expect-type": "^1.1.0",
1411
+ "magic-string": "^0.30.12",
1412
+ "pathe": "^1.1.2",
1413
+ "std-env": "^3.8.0",
1414
+ "tinybench": "^2.9.0",
1415
+ "tinyexec": "^0.3.1",
1416
+ "tinypool": "^1.0.1",
1417
+ "tinyrainbow": "^1.2.0",
1418
+ "vite": "^5.0.0",
1419
+ "vite-node": "2.1.9",
1420
+ "why-is-node-running": "^2.3.0"
1421
+ },
1422
+ "bin": {
1423
+ "vitest": "vitest.mjs"
1424
+ },
1425
+ "engines": {
1426
+ "node": "^18.0.0 || >=20.0.0"
1427
+ },
1428
+ "funding": {
1429
+ "url": "https://opencollective.com/vitest"
1430
+ },
1431
+ "peerDependencies": {
1432
+ "@edge-runtime/vm": "*",
1433
+ "@types/node": "^18.0.0 || >=20.0.0",
1434
+ "@vitest/browser": "2.1.9",
1435
+ "@vitest/ui": "2.1.9",
1436
+ "happy-dom": "*",
1437
+ "jsdom": "*"
1438
+ },
1439
+ "peerDependenciesMeta": {
1440
+ "@edge-runtime/vm": {
1441
+ "optional": true
1442
+ },
1443
+ "@types/node": {
1444
+ "optional": true
1445
+ },
1446
+ "@vitest/browser": {
1447
+ "optional": true
1448
+ },
1449
+ "@vitest/ui": {
1450
+ "optional": true
1451
+ },
1452
+ "happy-dom": {
1453
+ "optional": true
1454
+ },
1455
+ "jsdom": {
1456
+ "optional": true
1457
+ }
1458
+ }
1459
+ },
1460
+ "node_modules/why-is-node-running": {
1461
+ "version": "2.3.0",
1462
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
1463
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
1464
+ "dev": true,
1465
+ "license": "MIT",
1466
+ "dependencies": {
1467
+ "siginfo": "^2.0.0",
1468
+ "stackback": "0.0.2"
1469
+ },
1470
+ "bin": {
1471
+ "why-is-node-running": "cli.js"
1472
+ },
1473
+ "engines": {
1474
+ "node": ">=8"
1475
+ }
1476
+ },
1477
+ "node_modules/zod": {
1478
+ "version": "3.25.76",
1479
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
1480
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
1481
+ "license": "MIT",
1482
+ "funding": {
1483
+ "url": "https://github.com/sponsors/colinhacks"
1484
+ }
1485
+ }
1486
+ }
1487
+ }
package.json ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "@krishthesmart/contract-kit",
3
+ "version": "0.1.0",
4
+ "description": "Schema-first reliability helpers for structured AI outputs.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "",
8
+ "sideEffects": false,
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json",
22
+ "test": "vitest run",
23
+ "typecheck": "tsc -p tsconfig.json --noEmit",
24
+ "prepack": "npm run build"
25
+ },
26
+ "keywords": [
27
+ "ai",
28
+ "llm",
29
+ "schema",
30
+ "zod",
31
+ "validation",
32
+ "structured-output",
33
+ "reliability"
34
+ ],
35
+ "peerDependencies": {
36
+ "zod": "^3.23.0 || ^4.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.10.2",
40
+ "typescript": "^5.7.2",
41
+ "vitest": "^2.1.8",
42
+ "zod": "^3.25.76"
43
+ },
44
+ "dependencies": {
45
+ "@contract-kit/core": "file:../../outputs/contract-kit-core-0.1.0.tgz"
46
+ }
47
+ }
src/adapters.ts ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { ContractModel, ContractModelContext } from "./types.js";
2
+
3
+ export type OpenAIResponsesLikeClient = {
4
+ responses: {
5
+ create(input: {
6
+ model: string;
7
+ input: string;
8
+ temperature?: number;
9
+ signal?: AbortSignal;
10
+ }): Promise<{ output_text?: string }>;
11
+ };
12
+ };
13
+
14
+ export function openAIResponsesAdapter(
15
+ client: OpenAIResponsesLikeClient,
16
+ options: { model: string; temperature?: number }
17
+ ): ContractModel {
18
+ return {
19
+ async generate(prompt: string, context: ContractModelContext) {
20
+ const response = await client.responses.create({
21
+ model: options.model,
22
+ input: prompt,
23
+ temperature: options.temperature,
24
+ signal: context.signal
25
+ });
26
+
27
+ if (typeof response.output_text !== "string") {
28
+ throw new Error("OpenAI response did not include output_text.");
29
+ }
30
+
31
+ return response.output_text;
32
+ }
33
+ };
34
+ }
35
+
36
+ export function staticModel(responses: string[]): ContractModel {
37
+ let index = 0;
38
+
39
+ return {
40
+ async generate() {
41
+ const response = responses[index];
42
+ index = Math.min(index + 1, responses.length - 1);
43
+
44
+ if (response === undefined) {
45
+ throw new Error("No static model responses configured.");
46
+ }
47
+
48
+ return response;
49
+ }
50
+ };
51
+ }
src/contract.ts ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ContractParseError, ContractValidationError } from "./errors.js";
2
+ import { normalizeIssues } from "./issues.js";
3
+ import { parseJsonObject } from "./json.js";
4
+ import type {
5
+ ContractIssue,
6
+ ContractOptions,
7
+ ContractReplay,
8
+ ContractReplayAttempt,
9
+ ContractResult,
10
+ RepairPromptInput
11
+ } from "./types.js";
12
+
13
+ export async function generateContract<T>(options: ContractOptions<T>): Promise<ContractResult<T>> {
14
+ const maxAttempts = Math.max(1, (options.retries ?? 0) + 1);
15
+ const replay: ContractReplay = {
16
+ prompt: options.prompt,
17
+ attempts: [],
18
+ createdAt: new Date().toISOString()
19
+ };
20
+ let prompt = options.prompt;
21
+ let lastIssues: ContractIssue[] = [];
22
+
23
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
24
+ options.onEvent?.({ type: "attempt", attempt, prompt });
25
+
26
+ const previous = replay.attempts.at(-1);
27
+ const response = await options.model.generate(prompt, {
28
+ attempt,
29
+ signal: options.signal,
30
+ previous
31
+ });
32
+ const rawText = typeof response === "string" ? response : response.text;
33
+ const replayAttempt: ContractReplayAttempt = { attempt, prompt, rawText };
34
+ replay.attempts.push(replayAttempt);
35
+
36
+ let parsed: unknown;
37
+ try {
38
+ parsed = parseJsonObject(rawText);
39
+ replayAttempt.parsed = parsed;
40
+ } catch (error) {
41
+ const message = error instanceof Error ? error.message : "Unknown JSON parse error.";
42
+ replayAttempt.error = message;
43
+ options.onEvent?.({ type: "parse_error", attempt, rawText, error: message });
44
+ prompt = buildRepairPrompt({
45
+ originalPrompt: options.prompt,
46
+ lastAttempt: replayAttempt,
47
+ issues: [{ path: "", message }]
48
+ }, options.repairPrompt);
49
+ continue;
50
+ }
51
+
52
+ try {
53
+ const data = options.schema.parse(parsed);
54
+ options.onEvent?.({ type: "success", attempt, rawText, data });
55
+ return {
56
+ data,
57
+ attempts: attempt,
58
+ rawText,
59
+ replay
60
+ };
61
+ } catch (error) {
62
+ const issues = normalizeIssues(error);
63
+ lastIssues = issues;
64
+ replayAttempt.issues = issues;
65
+ options.onEvent?.({ type: "validation_error", attempt, rawText, parsed, issues });
66
+ prompt = buildRepairPrompt({
67
+ originalPrompt: options.prompt,
68
+ lastAttempt: replayAttempt,
69
+ issues
70
+ }, options.repairPrompt);
71
+ }
72
+ }
73
+
74
+ options.onEvent?.({ type: "failure", attempts: replay.attempts.length, replay });
75
+
76
+ const lastAttempt = replay.attempts.at(-1);
77
+ if (lastAttempt?.parsed === undefined) {
78
+ throw new ContractParseError(replay);
79
+ }
80
+
81
+ throw new ContractValidationError(replay, lastIssues);
82
+ }
83
+
84
+ function buildRepairPrompt(
85
+ input: RepairPromptInput,
86
+ customRepairPrompt: ContractOptions<unknown>["repairPrompt"]
87
+ ): string {
88
+ if (customRepairPrompt) {
89
+ return customRepairPrompt(input);
90
+ }
91
+
92
+ const issueText = input.issues
93
+ .map((issue) => `- ${issue.path || "(root)"}: ${issue.message}`)
94
+ .join("\n");
95
+
96
+ return [
97
+ input.originalPrompt,
98
+ "",
99
+ "The previous response failed the output contract.",
100
+ "Return only corrected JSON. Do not include markdown or explanatory text.",
101
+ "",
102
+ "Issues:",
103
+ issueText,
104
+ "",
105
+ "Previous response:",
106
+ input.lastAttempt.rawText ?? input.lastAttempt.error ?? ""
107
+ ].join("\n");
108
+ }
src/errors.ts ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { ContractIssue, ContractReplay } from "./types.js";
2
+
3
+ export class ContractError extends Error {
4
+ readonly replay: ContractReplay;
5
+ readonly issues: ContractIssue[];
6
+
7
+ constructor(message: string, replay: ContractReplay, issues: ContractIssue[] = []) {
8
+ super(message);
9
+ this.name = "ContractError";
10
+ this.replay = replay;
11
+ this.issues = issues;
12
+ }
13
+ }
14
+
15
+ export class ContractParseError extends ContractError {
16
+ constructor(replay: ContractReplay) {
17
+ super("Model response was not valid JSON.", replay);
18
+ this.name = "ContractParseError";
19
+ }
20
+ }
21
+
22
+ export class ContractValidationError extends ContractError {
23
+ constructor(replay: ContractReplay, issues: ContractIssue[]) {
24
+ super("Model response did not satisfy the contract schema.", replay, issues);
25
+ this.name = "ContractValidationError";
26
+ }
27
+ }
src/index.ts ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export { generateContract } from "./contract.js";
2
+ export { openAIResponsesAdapter, staticModel } from "./adapters.js";
3
+ export {
4
+ ContractError,
5
+ ContractParseError,
6
+ ContractValidationError
7
+ } from "./errors.js";
8
+ export type {
9
+ ContractEvent,
10
+ ContractIssue,
11
+ ContractModel,
12
+ ContractModelContext,
13
+ ContractModelResponse,
14
+ ContractOptions,
15
+ ContractReplay,
16
+ ContractReplayAttempt,
17
+ ContractResult,
18
+ ContractSchema,
19
+ RepairPromptInput
20
+ } from "./types.js";
src/issues.ts ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { ContractIssue } from "./types.js";
2
+
3
+ type ZodLikeIssue = {
4
+ path?: Array<string | number>;
5
+ message?: string;
6
+ code?: string;
7
+ };
8
+
9
+ type ZodLikeError = {
10
+ issues: ZodLikeIssue[];
11
+ };
12
+
13
+ export function normalizeIssues(error: unknown): ContractIssue[] {
14
+ if (isZodLikeError(error)) {
15
+ return error.issues.map((issue) => ({
16
+ path: issue.path?.map(String).join(".") ?? "",
17
+ message: issue.message ?? "Invalid value.",
18
+ code: issue.code
19
+ }));
20
+ }
21
+
22
+ return [
23
+ {
24
+ path: "",
25
+ message: error instanceof Error ? error.message : "Schema validation failed."
26
+ }
27
+ ];
28
+ }
29
+
30
+ function isZodLikeError(error: unknown): error is ZodLikeError {
31
+ return (
32
+ typeof error === "object" &&
33
+ error !== null &&
34
+ "issues" in error &&
35
+ Array.isArray(error.issues)
36
+ );
37
+ }
src/json.ts ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function parseJsonObject(rawText: string): unknown {
2
+ const trimmed = stripCodeFence(rawText.trim());
3
+
4
+ try {
5
+ return JSON.parse(trimmed);
6
+ } catch {
7
+ const extracted = extractFirstJsonValue(trimmed);
8
+ if (extracted === undefined) {
9
+ throw new SyntaxError("No JSON value found in model response.");
10
+ }
11
+
12
+ return JSON.parse(extracted);
13
+ }
14
+ }
15
+
16
+ function stripCodeFence(value: string): string {
17
+ const match = value.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
18
+ return match?.[1]?.trim() ?? value;
19
+ }
20
+
21
+ function extractFirstJsonValue(value: string): string | undefined {
22
+ const start = findFirstJsonStart(value);
23
+ if (start === -1) {
24
+ return undefined;
25
+ }
26
+
27
+ const opener = value[start];
28
+ const closer = opener === "{" ? "}" : "]";
29
+ let depth = 0;
30
+ let inString = false;
31
+ let escaping = false;
32
+
33
+ for (let index = start; index < value.length; index += 1) {
34
+ const char = value[index];
35
+
36
+ if (inString) {
37
+ if (escaping) {
38
+ escaping = false;
39
+ } else if (char === "\\") {
40
+ escaping = true;
41
+ } else if (char === "\"") {
42
+ inString = false;
43
+ }
44
+ continue;
45
+ }
46
+
47
+ if (char === "\"") {
48
+ inString = true;
49
+ } else if (char === opener) {
50
+ depth += 1;
51
+ } else if (char === closer) {
52
+ depth -= 1;
53
+ if (depth === 0) {
54
+ return value.slice(start, index + 1);
55
+ }
56
+ }
57
+ }
58
+
59
+ return undefined;
60
+ }
61
+
62
+ function findFirstJsonStart(value: string): number {
63
+ const objectStart = value.indexOf("{");
64
+ const arrayStart = value.indexOf("[");
65
+
66
+ if (objectStart === -1) {
67
+ return arrayStart;
68
+ }
69
+
70
+ if (arrayStart === -1) {
71
+ return objectStart;
72
+ }
73
+
74
+ return Math.min(objectStart, arrayStart);
75
+ }
src/types.ts ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export type ContractEvent =
2
+ | {
3
+ type: "attempt";
4
+ attempt: number;
5
+ prompt: string;
6
+ }
7
+ | {
8
+ type: "parse_error";
9
+ attempt: number;
10
+ rawText: string;
11
+ error: string;
12
+ }
13
+ | {
14
+ type: "validation_error";
15
+ attempt: number;
16
+ rawText: string;
17
+ parsed: unknown;
18
+ issues: ContractIssue[];
19
+ }
20
+ | {
21
+ type: "success";
22
+ attempt: number;
23
+ rawText: string;
24
+ data: unknown;
25
+ }
26
+ | {
27
+ type: "failure";
28
+ attempts: number;
29
+ replay: ContractReplay;
30
+ };
31
+
32
+ export type ContractIssue = {
33
+ path: string;
34
+ message: string;
35
+ code?: string;
36
+ };
37
+
38
+ export type ContractReplay = {
39
+ prompt: string;
40
+ attempts: ContractReplayAttempt[];
41
+ createdAt: string;
42
+ };
43
+
44
+ export type ContractReplayAttempt = {
45
+ attempt: number;
46
+ prompt: string;
47
+ rawText?: string;
48
+ parsed?: unknown;
49
+ error?: string;
50
+ issues?: ContractIssue[];
51
+ };
52
+
53
+ export type ContractSchema<T> = {
54
+ parse(value: unknown): T;
55
+ };
56
+
57
+ export type ContractModel = {
58
+ generate(prompt: string, context: ContractModelContext): Promise<ContractModelResponse>;
59
+ };
60
+
61
+ export type ContractModelContext = {
62
+ attempt: number;
63
+ signal?: AbortSignal;
64
+ previous?: ContractReplayAttempt;
65
+ };
66
+
67
+ export type ContractModelResponse =
68
+ | string
69
+ | {
70
+ text: string;
71
+ metadata?: Record<string, unknown>;
72
+ };
73
+
74
+ export type ContractOptions<T> = {
75
+ model: ContractModel;
76
+ schema: ContractSchema<T>;
77
+ prompt: string;
78
+ retries?: number;
79
+ signal?: AbortSignal;
80
+ onEvent?: (event: ContractEvent) => void;
81
+ repairPrompt?: (input: RepairPromptInput) => string;
82
+ };
83
+
84
+ export type RepairPromptInput = {
85
+ originalPrompt: string;
86
+ lastAttempt: ContractReplayAttempt;
87
+ issues: ContractIssue[];
88
+ };
89
+
90
+ export type ContractResult<T> = {
91
+ data: T;
92
+ attempts: number;
93
+ rawText: string;
94
+ replay: ContractReplay;
95
+ };
test/contract.test.ts ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { describe, expect, it } from "vitest";
2
+ import { z } from "zod";
3
+ import {
4
+ ContractParseError,
5
+ ContractValidationError,
6
+ generateContract,
7
+ staticModel
8
+ } from "../src/index.js";
9
+
10
+ const Profile = z.object({
11
+ name: z.string(),
12
+ seniority: z.enum(["junior", "mid", "senior"]),
13
+ skills: z.array(z.string()).min(1)
14
+ });
15
+
16
+ describe("generateContract", () => {
17
+ it("returns validated data from strict JSON", async () => {
18
+ const result = await generateContract({
19
+ model: staticModel([
20
+ JSON.stringify({ name: "Mira", seniority: "senior", skills: ["infra"] })
21
+ ]),
22
+ schema: Profile,
23
+ prompt: "Extract the profile."
24
+ });
25
+
26
+ expect(result.data.name).toBe("Mira");
27
+ expect(result.attempts).toBe(1);
28
+ });
29
+
30
+ it("extracts JSON from a fenced response", async () => {
31
+ const result = await generateContract({
32
+ model: staticModel([
33
+ "```json\n{\"name\":\"Lee\",\"seniority\":\"mid\",\"skills\":[\"ml\"]}\n```"
34
+ ]),
35
+ schema: Profile,
36
+ prompt: "Extract the profile."
37
+ });
38
+
39
+ expect(result.data).toEqual({
40
+ name: "Lee",
41
+ seniority: "mid",
42
+ skills: ["ml"]
43
+ });
44
+ });
45
+
46
+ it("repairs validation failures using a retry prompt", async () => {
47
+ const prompts: string[] = [];
48
+
49
+ const result = await generateContract({
50
+ model: {
51
+ async generate(prompt) {
52
+ prompts.push(prompt);
53
+ if (prompts.length === 1) {
54
+ return JSON.stringify({ name: "Ari", seniority: "principal", skills: [] });
55
+ }
56
+
57
+ return JSON.stringify({ name: "Ari", seniority: "senior", skills: ["platform"] });
58
+ }
59
+ },
60
+ schema: Profile,
61
+ prompt: "Extract the profile.",
62
+ retries: 1
63
+ });
64
+
65
+ expect(result.data.seniority).toBe("senior");
66
+ expect(result.attempts).toBe(2);
67
+ expect(prompts[1]).toContain("Return only corrected JSON");
68
+ expect(result.replay.attempts[0]?.issues).toHaveLength(2);
69
+ });
70
+
71
+ it("emits useful events", async () => {
72
+ const events: string[] = [];
73
+
74
+ await generateContract({
75
+ model: staticModel([
76
+ JSON.stringify({ name: "Noor", seniority: "junior", skills: ["ops"] })
77
+ ]),
78
+ schema: Profile,
79
+ prompt: "Extract the profile.",
80
+ onEvent(event) {
81
+ events.push(event.type);
82
+ }
83
+ });
84
+
85
+ expect(events).toEqual(["attempt", "success"]);
86
+ });
87
+
88
+ it("throws validation errors with replay data", async () => {
89
+ await expect(
90
+ generateContract({
91
+ model: staticModel([JSON.stringify({ name: "Kai", seniority: "staff", skills: [] })]),
92
+ schema: Profile,
93
+ prompt: "Extract the profile."
94
+ })
95
+ ).rejects.toMatchObject({
96
+ name: "ContractValidationError",
97
+ replay: {
98
+ attempts: [
99
+ expect.objectContaining({
100
+ attempt: 1,
101
+ rawText: expect.any(String)
102
+ })
103
+ ]
104
+ }
105
+ } satisfies Partial<ContractValidationError>);
106
+ });
107
+
108
+ it("throws parse errors after retries are exhausted", async () => {
109
+ await expect(
110
+ generateContract({
111
+ model: staticModel(["not json", "still not json"]),
112
+ schema: Profile,
113
+ prompt: "Extract the profile.",
114
+ retries: 1
115
+ })
116
+ ).rejects.toBeInstanceOf(ContractParseError);
117
+ });
118
+ });
tsconfig.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "sourceMap": true,
10
+ "outDir": "dist",
11
+ "rootDir": "src",
12
+ "skipLibCheck": true,
13
+ "verbatimModuleSyntax": true
14
+ },
15
+ "include": [
16
+ "src/**/*.ts"
17
+ ]
18
+ }
vitest.config.ts ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ["test/**/*.test.ts"]
6
+ }
7
+ });