standard-typed-config 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,199 @@
1
+ import { expectType } from 'tsd';
2
+ import { createBuilder, type Builder } from '../src/index';
3
+
4
+ // ══════════════════════════════════════════════════════════════════════════════════
5
+ // DOMAIN 1: AI Model Testing — verify types
6
+ // ══════════════════════════════════════════════════════════════════════════════════
7
+
8
+ type AIModelConfig = {
9
+ models: Array<{ provider: string; model: string }>;
10
+ systemPrompt?: string;
11
+ temperature?: number;
12
+ };
13
+
14
+ type AIHooks = {
15
+ beforeEachRun: { input: {}; output: { cost: number } };
16
+ test: { input: { cost: number }; output: Record<string, unknown> };
17
+ afterEachRun: { input: { cost: number }; output: Record<string, unknown> };
18
+ };
19
+
20
+ const { define: aiDefine } = createBuilder<AIModelConfig, AIHooks>([
21
+ 'beforeEachRun',
22
+ 'test',
23
+ 'afterEachRun',
24
+ ]);
25
+
26
+ const aiBuilder = aiDefine({
27
+ opus: { models: [{ provider: "anthropic", model: "claude-opus" }], temperature: 0.7 },
28
+ gpt4: { models: [{ provider: "openai", model: "gpt-4" }] },
29
+ })
30
+ .beforeEachRun((ctx) => {
31
+ expectType<"opus" | "gpt4">(ctx.key);
32
+ expectType<AIModelConfig>(ctx.opus);
33
+ expectType<number>(ctx.opus.temperature!);
34
+ expectType<string>(ctx.gpt4.models[0].provider);
35
+ return { cost: 0.01 };
36
+ })
37
+ .test((ctx) => {
38
+ expectType<"opus" | "gpt4">(ctx.key);
39
+ expectType<number>(ctx.cost);
40
+ expectType<AIModelConfig>(ctx.opus);
41
+ })
42
+ .afterEachRun((ctx) => {
43
+ expectType<"opus" | "gpt4">(ctx.key);
44
+ expectType<number>(ctx.cost);
45
+ expectType<AIModelConfig>(ctx.opus);
46
+ });
47
+
48
+ // ══════════════════════════════════════════════════════════════════════════════════
49
+ // DOMAIN 2: Restaurant — DIFFERENT hook names
50
+ // ══════════════════════════════════════════════════════════════════════════════════
51
+
52
+ type MenuItemConfig = {
53
+ inStock: boolean;
54
+ price: number;
55
+ calories: number;
56
+ allergens: string[];
57
+ };
58
+
59
+ type RestaurantHooks = {
60
+ beforePrep: { input: {}; output: { totalPrice: number; hasAllergens: boolean } };
61
+ receipt: { input: { totalPrice: number; hasAllergens: boolean }; output: Record<string, unknown> };
62
+ };
63
+
64
+ const { define: menuDefine } = createBuilder<MenuItemConfig, RestaurantHooks>([
65
+ 'beforePrep',
66
+ 'receipt',
67
+ ]);
68
+
69
+ const menuBuilder = menuDefine({
70
+ burger: { inStock: true, price: 12.99, calories: 650, allergens: ["gluten", "dairy"] },
71
+ salad: { inStock: true, price: 8.99, calories: 320, allergens: [] },
72
+ })
73
+ .beforePrep((ctx) => {
74
+ expectType<"burger" | "salad">(ctx.key);
75
+ expectType<MenuItemConfig>(ctx.burger);
76
+ expectType<number>(ctx.salad.price);
77
+ return { totalPrice: 15.49, hasAllergens: true };
78
+ })
79
+ .receipt((ctx) => {
80
+ expectType<"burger" | "salad">(ctx.key);
81
+ expectType<number>(ctx.totalPrice);
82
+ expectType<boolean>(ctx.hasAllergens);
83
+ });
84
+
85
+ // ══════════════════════════════════════════════════════════════════════════════════
86
+ // DOMAIN 3: CI/CD — .use() composition
87
+ // ══════════════════════════════════════════════════════════════════════════════════
88
+
89
+ type RunnerConfig = { capabilities: string[]; maxParallel: number; costPerMinute: number; region: string };
90
+
91
+ type CIHooks = {
92
+ beforeJob: { input: {}; output: { estimatedCost: number; region: string } };
93
+ execute: { input: { estimatedCost: number; region: string }; output: Record<string, unknown> };
94
+ afterJob: { input: { estimatedCost: number; region: string }; output: Record<string, unknown> };
95
+ };
96
+
97
+ const { define: ciDefine } = createBuilder<RunnerConfig, CIHooks>([
98
+ 'beforeJob',
99
+ 'execute',
100
+ 'afterJob',
101
+ ]);
102
+
103
+ const gpuRunner = ciDefine({
104
+ "gpu-runner": { capabilities: ["gpu"], maxParallel: 4, costPerMinute: 0.5, region: "us-east" },
105
+ "cpu-runner": { capabilities: ["cpu"], maxParallel: 16, costPerMinute: 0.05, region: "eu-west" },
106
+ });
107
+
108
+ const ciBuilder = ciDefine()
109
+ .use(gpuRunner)
110
+ .beforeJob((ctx) => {
111
+ expectType<"gpu-runner" | "cpu-runner">(ctx.key);
112
+ expectType<string[]>(ctx["gpu-runner"].capabilities);
113
+ return { estimatedCost: 2.5, region: "us-east" };
114
+ })
115
+ .execute((ctx) => {
116
+ expectType<"gpu-runner" | "cpu-runner">(ctx.key);
117
+ expectType<number>(ctx.estimatedCost);
118
+ expectType<string>(ctx.region);
119
+ });
120
+
121
+ // ══════════════════════════════════════════════════════════════════════════════════
122
+ // DOMAIN 4: llm-proxy MatchContext — verify THooksMap generic with unrelated input
123
+ // ══════════════════════════════════════════════════════════════════════════════════
124
+
125
+ type MatchContext = { body: unknown; headers: Record<string, string>; wireFormat: 'anthropic' | 'openai'; requestedModel: string };
126
+
127
+ type ProxyHooks = {
128
+ router: { input: MatchContext; output: { selected: string[] } };
129
+ };
130
+
131
+ const { define: proxyDefine } = createBuilder<
132
+ { model: string },
133
+ ProxyHooks
134
+ >(['router']);
135
+
136
+ const proxyBuilder = proxyDefine({
137
+ smart: { model: 'opus' },
138
+ fast: { model: 'haiku' },
139
+ })
140
+ .router((ctx) => {
141
+ expectType<"smart" | "fast">(ctx.key);
142
+ expectType<'anthropic' | 'openai'>(ctx.wireFormat);
143
+ expectType<string>(ctx.requestedModel);
144
+ expectType<Record<string, string>>(ctx.headers);
145
+ expectType<unknown>(ctx.body);
146
+ return { selected: ctx.wireFormat === 'anthropic' ? ['smart'] : ['fast'] };
147
+ });
148
+
149
+ // ══════════════════════════════════════════════════════════════════════════════════
150
+ // CROSS-DOMAIN REJECTION
151
+ // ══════════════════════════════════════════════════════════════════════════════════
152
+
153
+ // @ts-expect-error — cannot .use() a CI builder in an AI builder
154
+ aiDefine().use(gpuRunner);
155
+
156
+ // @ts-expect-error — AI builder has no .beforePrep()
157
+ aiDefine({ opus: { models: [{ provider: "a", model: "b" }] } }).beforePrep(() => {});
158
+
159
+ // @ts-expect-error — Restaurant builder has no .test()
160
+ menuDefine({ salad: { inStock: true, price: 5, calories: 200, allergens: [] } }).test(() => {});
161
+
162
+ // @ts-expect-error — CI builder has no .beforeEachRun()
163
+ ciDefine({ r: { capabilities: [], maxParallel: 1, costPerMinute: 0, region: "us" } }).beforeEachRun(() => {});
164
+
165
+ // ══════════════════════════════════════════════════════════════════════════════════
166
+ // DOMAIN 4: Terminal Hooks — output: never returns TerminalResult
167
+ // ══════════════════════════════════════════════════════════════════════════════════
168
+
169
+ type TerminalHooks = {
170
+ accumulate: { input: {}; output: { accumulated: string } };
171
+ terminal: { input: { accumulated: string }; output: never };
172
+ };
173
+
174
+ const { define: terminalDefine } = createBuilder<{ value: number }, TerminalHooks>([
175
+ 'accumulate',
176
+ 'terminal',
177
+ ]);
178
+
179
+ // Terminal hook returns TerminalResult with correct types
180
+ const terminalResult = terminalDefine({ item: { value: 42 } })
181
+ .accumulate((ctx) => {
182
+ expectType<"item">(ctx.key);
183
+ expectType<{ value: number }>(ctx.item);
184
+ return { accumulated: "hello" };
185
+ })
186
+ .terminal((ctx) => {
187
+ expectType<"item">(ctx.key);
188
+ expectType<string>(ctx.accumulated);
189
+ });
190
+
191
+ expectType<{ value: number }>(terminalResult.config);
192
+ expectType<{ item: { value: number } }>(terminalResult.items);
193
+ expectType<{ accumulated: string }>(terminalResult.context);
194
+
195
+ const terminalChainResult = terminalDefine({ item: { value: 42 } })
196
+ .accumulate((ctx) => ({ accumulated: "hello" }))
197
+ .terminal((ctx) => {});
198
+ // @ts-expect-error — cannot chain after terminal hook (no return type to continue with)
199
+ terminalChainResult.accumulate;
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["ES2020"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "declaration": true,
8
+ "outDir": "dist",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true
13
+ },
14
+ "include": ["src"],
15
+ "exclude": ["node_modules", "dist", "test"]
16
+ }