@outfitter/contracts 0.4.2 → 0.5.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/dist/actions.d.ts +8 -3
- package/dist/assert/index.d.ts +7 -3
- package/dist/assert/index.js +32 -1
- package/dist/context.d.ts +8 -3
- package/dist/context.js +1 -1
- package/dist/envelope.d.ts +6 -2
- package/dist/envelope.js +5 -6
- package/dist/errors.d.ts +6 -2
- package/dist/errors.js +7 -1
- package/dist/from-fetch.d.ts +7 -0
- package/dist/from-fetch.js +110 -0
- package/dist/handler.d.ts +7 -2
- package/dist/hints.d.ts +2 -0
- package/dist/hints.js +1 -0
- package/dist/index.d.ts +24 -13
- package/dist/index.js +5 -3
- package/dist/internal/error-base.d.ts +2 -0
- package/dist/internal/error-base.js +31 -0
- package/dist/internal/error-operational.d.ts +3 -0
- package/dist/internal/error-operational.js +125 -0
- package/dist/internal/error-serialization.d.ts +7 -0
- package/dist/{shared/@outfitter/contracts-5k6q4n48.js → internal/error-serialization.js} +28 -67
- package/dist/internal/error-taxonomy.d.ts +2 -0
- package/dist/internal/error-taxonomy.js +21 -0
- package/dist/internal/error-validation.d.ts +3 -0
- package/dist/internal/error-validation.js +121 -0
- package/dist/internal/safe-json.d.ts +7 -0
- package/dist/internal/safe-json.js +66 -0
- package/dist/internal/schema-converters.d.ts +26 -0
- package/dist/internal/schema-converters.js +12 -0
- package/dist/internal/schema-primitives.d.ts +10 -0
- package/dist/internal/schema-primitives.js +9 -0
- package/dist/internal/schema-types.d.ts +2 -0
- package/dist/internal/schema-types.js +9 -0
- package/dist/recovery.d.ts +6 -2
- package/dist/resilience.d.ts +6 -2
- package/dist/resilience.js +6 -2
- package/dist/schema.d.ts +2 -1
- package/dist/schema.js +15 -187
- package/dist/serialization.d.ts +8 -2
- package/dist/serialization.js +1 -3
- package/dist/shared/@outfitter/{contracts-k71jqd1m.d.ts → contracts-10p5q75w.d.ts} +1 -1
- package/dist/shared/@outfitter/contracts-1zzcpfyg.d.ts +40 -0
- package/dist/shared/@outfitter/contracts-3f5k5tg5.d.ts +28 -0
- package/dist/shared/@outfitter/contracts-3qmyq81n.d.ts +78 -0
- package/dist/shared/@outfitter/contracts-3re9d4bp.js +114 -0
- package/dist/shared/@outfitter/contracts-735ecmbq.d.ts +107 -0
- package/dist/shared/@outfitter/contracts-7a0xmwbg.d.ts +11 -0
- package/dist/shared/@outfitter/contracts-8cmkh2db.d.ts +31 -0
- package/dist/shared/@outfitter/{contracts-agmt8915.js → contracts-c3qfce25.js} +3 -0
- package/dist/shared/@outfitter/{contracts-1waabxbk.d.ts → contracts-drwd9ywk.d.ts} +4 -1
- package/dist/shared/@outfitter/contracts-hgh47193.js +46 -0
- package/dist/shared/@outfitter/contracts-hrepwwne.js +62 -0
- package/dist/shared/@outfitter/contracts-jtn6b927.js +18 -0
- package/dist/shared/@outfitter/contracts-jtt6dnmg.js +2 -0
- package/dist/shared/@outfitter/contracts-jyhqr766.js +25 -0
- package/dist/shared/@outfitter/contracts-mehpmvwp.d.ts +164 -0
- package/dist/shared/@outfitter/contracts-msxdg52h.d.ts +125 -0
- package/dist/shared/@outfitter/{contracts-95cc3y06.d.ts → contracts-mt027fqj.d.ts} +2 -1
- package/dist/shared/@outfitter/contracts-njb2art4.d.ts +174 -0
- package/dist/shared/@outfitter/contracts-p77yjs4g.d.ts +46 -0
- package/dist/shared/@outfitter/contracts-qpbv29bg.d.ts +59 -0
- package/dist/shared/@outfitter/contracts-sawwfgb5.js +111 -0
- package/dist/shared/@outfitter/{contracts-e4m948m7.d.ts → contracts-t4txv24h.d.ts} +2 -1
- package/dist/shared/@outfitter/contracts-vbgt9rfn.d.ts +74 -0
- package/dist/shared/@outfitter/{contracts-56pcsavx.d.ts → contracts-vhajx4gg.d.ts} +8 -2
- package/dist/shared/@outfitter/contracts-vhr2ep6b.js +3 -0
- package/dist/shared/@outfitter/contracts-w7nvcwrp.d.ts +44 -0
- package/dist/shared/@outfitter/contracts-x0ppyt7e.d.ts +76 -0
- package/dist/shared/@outfitter/{contracts-0akf2sm6.d.ts → contracts-zma4mscd.d.ts} +16 -1
- package/dist/shared/@outfitter/contracts-zsgxsa91.d.ts +84 -0
- package/dist/stream.d.ts +2 -0
- package/dist/stream.js +1 -0
- package/dist/validation.d.ts +7 -3
- package/dist/validation.js +8 -36
- package/dist/wrap-error.d.ts +7 -0
- package/dist/wrap-error.js +71 -0
- package/package.json +41 -17
- package/dist/shared/@outfitter/contracts-31penhwa.d.ts +0 -81
- package/dist/shared/@outfitter/contracts-3gswmhb1.d.ts +0 -446
- package/dist/shared/@outfitter/contracts-9wtm5nsw.d.ts +0 -42
- package/dist/shared/@outfitter/contracts-mmg0npfk.d.ts +0 -30
- package/dist/shared/@outfitter/contracts-phjhz5q3.js +0 -293
- package/dist/shared/@outfitter/contracts-t79engf9.d.ts +0 -60
package/dist/schema.js
CHANGED
|
@@ -1,29 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
convertNumber,
|
|
4
|
+
convertString
|
|
5
|
+
} from "./shared/@outfitter/contracts-3re9d4bp.js";
|
|
6
|
+
import {
|
|
7
|
+
convertArray,
|
|
8
|
+
convertObject
|
|
9
|
+
} from "./shared/@outfitter/contracts-hrepwwne.js";
|
|
10
|
+
import {
|
|
11
|
+
getDef,
|
|
12
|
+
getDescription
|
|
13
|
+
} from "./shared/@outfitter/contracts-jyhqr766.js";
|
|
14
|
+
|
|
2
15
|
// packages/contracts/src/schema.ts
|
|
3
16
|
function zodToJsonSchema(schema) {
|
|
4
17
|
return convertZodType(schema);
|
|
5
18
|
}
|
|
6
|
-
function getDef(schemaOrDef) {
|
|
7
|
-
if (!schemaOrDef) {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
if (schemaOrDef._def) {
|
|
11
|
-
return schemaOrDef._def;
|
|
12
|
-
}
|
|
13
|
-
if (schemaOrDef.def) {
|
|
14
|
-
return schemaOrDef.def;
|
|
15
|
-
}
|
|
16
|
-
return schemaOrDef;
|
|
17
|
-
}
|
|
18
|
-
function getDescription(schema, def) {
|
|
19
|
-
if (typeof schema?.description === "string") {
|
|
20
|
-
return schema.description;
|
|
21
|
-
}
|
|
22
|
-
if (typeof def?.description === "string") {
|
|
23
|
-
return def.description;
|
|
24
|
-
}
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
19
|
function convertZodType(schema) {
|
|
28
20
|
const def = getDef(schema);
|
|
29
21
|
if (!def) {
|
|
@@ -54,11 +46,11 @@ function convertZodType(schema) {
|
|
|
54
46
|
break;
|
|
55
47
|
case "ZodArray":
|
|
56
48
|
case "array":
|
|
57
|
-
jsonSchema = convertArray(def);
|
|
49
|
+
jsonSchema = convertArray(def, convertZodType);
|
|
58
50
|
break;
|
|
59
51
|
case "ZodObject":
|
|
60
52
|
case "object":
|
|
61
|
-
jsonSchema = convertObject(def);
|
|
53
|
+
jsonSchema = convertObject(def, convertZodType);
|
|
62
54
|
break;
|
|
63
55
|
case "ZodOptional":
|
|
64
56
|
case "optional":
|
|
@@ -173,170 +165,6 @@ function convertZodType(schema) {
|
|
|
173
165
|
}
|
|
174
166
|
return jsonSchema;
|
|
175
167
|
}
|
|
176
|
-
function convertString(def) {
|
|
177
|
-
const schema = { type: "string" };
|
|
178
|
-
if (def.checks) {
|
|
179
|
-
for (const check of def.checks) {
|
|
180
|
-
const normalizedCheck = check?._zod?.def ?? check?.def ?? check;
|
|
181
|
-
if (normalizedCheck?.kind) {
|
|
182
|
-
switch (normalizedCheck.kind) {
|
|
183
|
-
case "min":
|
|
184
|
-
schema.minLength = normalizedCheck.value;
|
|
185
|
-
break;
|
|
186
|
-
case "max":
|
|
187
|
-
schema.maxLength = normalizedCheck.value;
|
|
188
|
-
break;
|
|
189
|
-
case "length":
|
|
190
|
-
schema.minLength = normalizedCheck.value;
|
|
191
|
-
schema.maxLength = normalizedCheck.value;
|
|
192
|
-
break;
|
|
193
|
-
case "email":
|
|
194
|
-
schema.pattern = "^[^@]+@[^@]+\\.[^@]+$";
|
|
195
|
-
break;
|
|
196
|
-
case "url":
|
|
197
|
-
schema.pattern = "^https?://";
|
|
198
|
-
break;
|
|
199
|
-
case "uuid":
|
|
200
|
-
schema.pattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";
|
|
201
|
-
break;
|
|
202
|
-
case "regex":
|
|
203
|
-
schema.pattern = normalizedCheck.regex?.source ?? normalizedCheck.pattern?.source ?? (typeof normalizedCheck.pattern === "string" ? normalizedCheck.pattern : undefined);
|
|
204
|
-
break;
|
|
205
|
-
default:
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
if (!normalizedCheck?.check) {
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
switch (normalizedCheck.check) {
|
|
214
|
-
case "min_length":
|
|
215
|
-
schema.minLength = normalizedCheck.minimum;
|
|
216
|
-
break;
|
|
217
|
-
case "max_length":
|
|
218
|
-
schema.maxLength = normalizedCheck.maximum;
|
|
219
|
-
break;
|
|
220
|
-
case "string_format":
|
|
221
|
-
if (normalizedCheck.pattern) {
|
|
222
|
-
schema.pattern = typeof normalizedCheck.pattern === "string" ? normalizedCheck.pattern : normalizedCheck.pattern.source;
|
|
223
|
-
}
|
|
224
|
-
if (normalizedCheck.format && normalizedCheck.format !== "regex") {
|
|
225
|
-
schema.format = normalizedCheck.format;
|
|
226
|
-
}
|
|
227
|
-
break;
|
|
228
|
-
default:
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return schema;
|
|
234
|
-
}
|
|
235
|
-
function convertNumber(def) {
|
|
236
|
-
const schema = { type: "number" };
|
|
237
|
-
if (def.checks) {
|
|
238
|
-
for (const check of def.checks) {
|
|
239
|
-
const normalizedCheck = check?._zod?.def ?? check?.def ?? check;
|
|
240
|
-
if (normalizedCheck?.kind) {
|
|
241
|
-
switch (normalizedCheck.kind) {
|
|
242
|
-
case "min":
|
|
243
|
-
schema.minimum = normalizedCheck.value;
|
|
244
|
-
break;
|
|
245
|
-
case "max":
|
|
246
|
-
schema.maximum = normalizedCheck.value;
|
|
247
|
-
break;
|
|
248
|
-
case "int":
|
|
249
|
-
schema.type = "integer";
|
|
250
|
-
break;
|
|
251
|
-
default:
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
if (!normalizedCheck?.check) {
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
switch (normalizedCheck.check) {
|
|
260
|
-
case "greater_than":
|
|
261
|
-
if (normalizedCheck.inclusive) {
|
|
262
|
-
schema.minimum = normalizedCheck.value;
|
|
263
|
-
} else {
|
|
264
|
-
schema.exclusiveMinimum = normalizedCheck.value;
|
|
265
|
-
}
|
|
266
|
-
break;
|
|
267
|
-
case "less_than":
|
|
268
|
-
if (normalizedCheck.inclusive) {
|
|
269
|
-
schema.maximum = normalizedCheck.value;
|
|
270
|
-
} else {
|
|
271
|
-
schema.exclusiveMaximum = normalizedCheck.value;
|
|
272
|
-
}
|
|
273
|
-
break;
|
|
274
|
-
case "number_format":
|
|
275
|
-
if (normalizedCheck.format === "int" || normalizedCheck.format === "safeint") {
|
|
276
|
-
schema.type = "integer";
|
|
277
|
-
}
|
|
278
|
-
break;
|
|
279
|
-
default:
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return schema;
|
|
285
|
-
}
|
|
286
|
-
function convertArray(def) {
|
|
287
|
-
const element = def.element ?? def.type;
|
|
288
|
-
const schema = {
|
|
289
|
-
type: "array",
|
|
290
|
-
items: element ? convertZodType(element) : {}
|
|
291
|
-
};
|
|
292
|
-
return schema;
|
|
293
|
-
}
|
|
294
|
-
function isFieldOptional(fieldDef) {
|
|
295
|
-
if (!(fieldDef?.typeName || fieldDef?.type)) {
|
|
296
|
-
return false;
|
|
297
|
-
}
|
|
298
|
-
const typeName = fieldDef.typeName ?? fieldDef.type;
|
|
299
|
-
if (typeName === "ZodOptional" || typeName === "ZodDefault" || typeName === "optional" || typeName === "default") {
|
|
300
|
-
return true;
|
|
301
|
-
}
|
|
302
|
-
if (typeName === "ZodEffects") {
|
|
303
|
-
return isFieldOptional(getDef(fieldDef.schema));
|
|
304
|
-
}
|
|
305
|
-
if (typeName === "ZodPipeline" || typeName === "pipe") {
|
|
306
|
-
const inputOptional = isFieldOptional(getDef(fieldDef.in));
|
|
307
|
-
const outputDef = getDef(fieldDef.out);
|
|
308
|
-
const outputType = outputDef?.typeName ?? outputDef?.type;
|
|
309
|
-
if (outputType === "transform") {
|
|
310
|
-
return inputOptional;
|
|
311
|
-
}
|
|
312
|
-
const outputOptional = isFieldOptional(outputDef);
|
|
313
|
-
return inputOptional && outputOptional;
|
|
314
|
-
}
|
|
315
|
-
if (typeName === "ZodNullable" || typeName === "nullable") {
|
|
316
|
-
return isFieldOptional(getDef(fieldDef.innerType));
|
|
317
|
-
}
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
function convertObject(def) {
|
|
321
|
-
const properties = {};
|
|
322
|
-
const required = [];
|
|
323
|
-
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
324
|
-
for (const [key, value] of Object.entries(shape ?? {})) {
|
|
325
|
-
properties[key] = convertZodType(value);
|
|
326
|
-
const fieldDef = getDef(value);
|
|
327
|
-
if (!isFieldOptional(fieldDef)) {
|
|
328
|
-
required.push(key);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
const schema = {
|
|
332
|
-
type: "object",
|
|
333
|
-
properties
|
|
334
|
-
};
|
|
335
|
-
if (required.length > 0) {
|
|
336
|
-
schema.required = required;
|
|
337
|
-
}
|
|
338
|
-
return schema;
|
|
339
|
-
}
|
|
340
168
|
export {
|
|
341
169
|
zodToJsonSchema
|
|
342
170
|
};
|
package/dist/serialization.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import "./shared/@outfitter/contracts-
|
|
1
|
+
import "./shared/@outfitter/contracts-f6fnz6h9.js";
|
|
2
|
+
import { SerializeErrorOptions, deserializeError, serializeError } from "./shared/@outfitter/contracts-p77yjs4g.js";
|
|
3
|
+
import { safeParse, safeStringify } from "./shared/@outfitter/contracts-1zzcpfyg.js";
|
|
4
|
+
import "./shared/@outfitter/contracts-7a0xmwbg.js";
|
|
5
|
+
import "./shared/@outfitter/contracts-735ecmbq.js";
|
|
6
|
+
import "./shared/@outfitter/contracts-mehpmvwp.js";
|
|
7
|
+
import "./shared/@outfitter/contracts-qpbv29bg.js";
|
|
8
|
+
import "./shared/@outfitter/contracts-njb2art4.js";
|
|
3
9
|
export { serializeError, safeStringify, safeParse, deserializeError, SerializeErrorOptions };
|
package/dist/serialization.js
CHANGED
|
@@ -4,9 +4,7 @@ import {
|
|
|
4
4
|
safeParse,
|
|
5
5
|
safeStringify,
|
|
6
6
|
serializeError
|
|
7
|
-
} from "./shared/@outfitter/contracts-
|
|
8
|
-
import"./shared/@outfitter/contracts-phjhz5q3.js";
|
|
9
|
-
import"./shared/@outfitter/contracts-s15x2rs4.js";
|
|
7
|
+
} from "./shared/@outfitter/contracts-jtt6dnmg.js";
|
|
10
8
|
export {
|
|
11
9
|
serializeError,
|
|
12
10
|
safeStringify,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ValidationError } from "./contracts-mehpmvwp.js";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* Safely stringify any value to JSON.
|
|
6
|
+
*
|
|
7
|
+
* Handles circular references, BigInt, and other non-JSON-safe values.
|
|
8
|
+
* Applies redaction to sensitive values.
|
|
9
|
+
*
|
|
10
|
+
* @param value - Value to stringify
|
|
11
|
+
* @param space - Indentation (default: undefined for compact)
|
|
12
|
+
* @returns JSON string
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const json = safeStringify({ apiKey: "sk-secret", data: "safe" });
|
|
17
|
+
* // '{"apiKey":"[REDACTED]","data":"safe"}'
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function safeStringify(value: unknown, space?: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* Safely parse JSON string with optional schema validation.
|
|
23
|
+
*
|
|
24
|
+
* Returns Result instead of throwing on invalid JSON.
|
|
25
|
+
*
|
|
26
|
+
* @typeParam T - Expected parsed type (or unknown if no schema)
|
|
27
|
+
* @param json - JSON string to parse
|
|
28
|
+
* @param schema - Optional Zod schema for validation
|
|
29
|
+
* @returns Result with parsed value or ValidationError
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const result = safeParse<Config>('{"port": 3000}', ConfigSchema);
|
|
34
|
+
* if (result.isOk()) {
|
|
35
|
+
* const config = result.unwrap();
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function safeParse<T = unknown>(json: string, schema?: z.ZodType<T>): Result<T, ValidationError>;
|
|
40
|
+
export { safeStringify, safeParse };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { OutfitterError } from "./contracts-7a0xmwbg.js";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
/**
|
|
4
|
+
* Convert an HTTP {@link Response} into a `Result<Response, OutfitterError>`.
|
|
5
|
+
*
|
|
6
|
+
* - **2xx** status codes return `Ok` with the original Response.
|
|
7
|
+
* - Known error codes map to specific categories per the taxonomy using
|
|
8
|
+
* {@link statusCodeMap} plus {@link HTTP_STATUS_ALIASES} for 408 and 503.
|
|
9
|
+
* - Unmapped 4xx → validation, unmapped 5xx → internal.
|
|
10
|
+
* - All other codes (1xx, 3xx) → internal.
|
|
11
|
+
*
|
|
12
|
+
* @param response - The HTTP Response to inspect
|
|
13
|
+
* @returns `Result.ok(response)` for 2xx, `Result.err(OutfitterError)` otherwise
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const response = await fetch("https://api.example.com/data");
|
|
18
|
+
* const result = fromFetch(response);
|
|
19
|
+
*
|
|
20
|
+
* if (result.isOk()) {
|
|
21
|
+
* const data = await result.value.json();
|
|
22
|
+
* } else {
|
|
23
|
+
* console.error(result.error.category, result.error.message);
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
declare function fromFetch(response: Response): Result<Response, OutfitterError>;
|
|
28
|
+
export { fromFetch };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { AssertionError } from "./contracts-mehpmvwp.js";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
/**
|
|
4
|
+
* Array type guaranteed to have at least one element.
|
|
5
|
+
*/
|
|
6
|
+
type NonEmptyArray<T> = [T, ...T[]];
|
|
7
|
+
/**
|
|
8
|
+
* Type guard for NonEmptyArray.
|
|
9
|
+
*/
|
|
10
|
+
declare const isNonEmptyArray: <T>(arr: readonly T[]) => arr is NonEmptyArray<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Assert a value is defined (not null or undefined).
|
|
13
|
+
* Returns Result instead of throwing.
|
|
14
|
+
*/
|
|
15
|
+
declare const assertDefined: <T>(value: T | null | undefined, message?: string) => Result<T, InstanceType<typeof AssertionError>>;
|
|
16
|
+
/**
|
|
17
|
+
* Assert array has at least one element.
|
|
18
|
+
* Returns NonEmptyArray on success.
|
|
19
|
+
*/
|
|
20
|
+
declare const assertNonEmpty: <T>(arr: readonly T[], message?: string) => Result<NonEmptyArray<T>, InstanceType<typeof AssertionError>>;
|
|
21
|
+
/**
|
|
22
|
+
* Assert value matches a predicate.
|
|
23
|
+
* Supports type guard predicates for narrowing.
|
|
24
|
+
*/
|
|
25
|
+
declare function assertMatches<
|
|
26
|
+
T,
|
|
27
|
+
U extends T
|
|
28
|
+
>(value: T, predicate: (v: T) => v is U, message?: string): Result<U, InstanceType<typeof AssertionError>>;
|
|
29
|
+
declare function assertMatches<T>(value: T, predicate: (v: T) => boolean, message?: string): Result<T, InstanceType<typeof AssertionError>>;
|
|
30
|
+
/**
|
|
31
|
+
* Assert a Result is Ok and return the narrowed value.
|
|
32
|
+
*
|
|
33
|
+
* Throws a descriptive error if the Result is Err, making it ideal for
|
|
34
|
+
* test assertions with Bun's test runner.
|
|
35
|
+
*
|
|
36
|
+
* @param result - The Result to assert
|
|
37
|
+
* @param message - Optional context message prepended to the error
|
|
38
|
+
* @returns The unwrapped Ok value with type narrowing to `T`
|
|
39
|
+
* @throws Error with descriptive message if Result is Err
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { expectOk } from "@outfitter/contracts";
|
|
44
|
+
*
|
|
45
|
+
* const result = await fetchUser(id);
|
|
46
|
+
* const user = expectOk(result); // throws if Err, returns User if Ok
|
|
47
|
+
* expect(user.name).toBe("Alice");
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare const expectOk: <
|
|
51
|
+
T,
|
|
52
|
+
E
|
|
53
|
+
>(result: Result<T, E>, message?: string) => T;
|
|
54
|
+
/**
|
|
55
|
+
* Assert a Result is Err and return the narrowed error.
|
|
56
|
+
*
|
|
57
|
+
* Throws a descriptive error if the Result is Ok, making it ideal for
|
|
58
|
+
* test assertions with Bun's test runner.
|
|
59
|
+
*
|
|
60
|
+
* @param result - The Result to assert
|
|
61
|
+
* @param message - Optional context message prepended to the error
|
|
62
|
+
* @returns The unwrapped Err value with type narrowing to `E`
|
|
63
|
+
* @throws Error with descriptive message if Result is Ok
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* import { expectErr } from "@outfitter/contracts";
|
|
68
|
+
*
|
|
69
|
+
* const result = validateInput(invalidData);
|
|
70
|
+
* const error = expectErr(result); // throws if Ok, returns error if Err
|
|
71
|
+
* expect(error.category).toBe("validation");
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare const expectErr: <
|
|
75
|
+
T,
|
|
76
|
+
E
|
|
77
|
+
>(result: Result<T, E>, message?: string) => E;
|
|
78
|
+
export { NonEmptyArray, isNonEmptyArray, assertDefined, assertNonEmpty, assertMatches, expectOk, expectErr };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/contracts/src/internal/schema-primitives.ts
|
|
3
|
+
function convertString(def) {
|
|
4
|
+
const schema = { type: "string" };
|
|
5
|
+
if (def.checks) {
|
|
6
|
+
for (const check of def.checks) {
|
|
7
|
+
const normalizedCheck = check?._zod?.def ?? check?.def ?? check;
|
|
8
|
+
if (normalizedCheck?.kind) {
|
|
9
|
+
switch (normalizedCheck.kind) {
|
|
10
|
+
case "min":
|
|
11
|
+
schema.minLength = normalizedCheck.value;
|
|
12
|
+
break;
|
|
13
|
+
case "max":
|
|
14
|
+
schema.maxLength = normalizedCheck.value;
|
|
15
|
+
break;
|
|
16
|
+
case "length":
|
|
17
|
+
schema.minLength = normalizedCheck.value;
|
|
18
|
+
schema.maxLength = normalizedCheck.value;
|
|
19
|
+
break;
|
|
20
|
+
case "email":
|
|
21
|
+
schema.pattern = "^[^@]+@[^@]+\\.[^@]+$";
|
|
22
|
+
break;
|
|
23
|
+
case "url":
|
|
24
|
+
schema.pattern = "^https?://";
|
|
25
|
+
break;
|
|
26
|
+
case "uuid":
|
|
27
|
+
schema.pattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";
|
|
28
|
+
break;
|
|
29
|
+
case "regex":
|
|
30
|
+
schema.pattern = normalizedCheck.regex?.source ?? normalizedCheck.pattern?.source ?? (typeof normalizedCheck.pattern === "string" ? normalizedCheck.pattern : undefined);
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (!normalizedCheck?.check) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
switch (normalizedCheck.check) {
|
|
41
|
+
case "min_length":
|
|
42
|
+
schema.minLength = normalizedCheck.minimum;
|
|
43
|
+
break;
|
|
44
|
+
case "max_length":
|
|
45
|
+
schema.maxLength = normalizedCheck.maximum;
|
|
46
|
+
break;
|
|
47
|
+
case "string_format":
|
|
48
|
+
if (normalizedCheck.pattern) {
|
|
49
|
+
schema.pattern = typeof normalizedCheck.pattern === "string" ? normalizedCheck.pattern : normalizedCheck.pattern.source;
|
|
50
|
+
}
|
|
51
|
+
if (normalizedCheck.format && normalizedCheck.format !== "regex") {
|
|
52
|
+
schema.format = normalizedCheck.format;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return schema;
|
|
61
|
+
}
|
|
62
|
+
function convertNumber(def) {
|
|
63
|
+
const schema = { type: "number" };
|
|
64
|
+
if (def.checks) {
|
|
65
|
+
for (const check of def.checks) {
|
|
66
|
+
const normalizedCheck = check?._zod?.def ?? check?.def ?? check;
|
|
67
|
+
if (normalizedCheck?.kind) {
|
|
68
|
+
switch (normalizedCheck.kind) {
|
|
69
|
+
case "min":
|
|
70
|
+
schema.minimum = normalizedCheck.value;
|
|
71
|
+
break;
|
|
72
|
+
case "max":
|
|
73
|
+
schema.maximum = normalizedCheck.value;
|
|
74
|
+
break;
|
|
75
|
+
case "int":
|
|
76
|
+
schema.type = "integer";
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!normalizedCheck?.check) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
switch (normalizedCheck.check) {
|
|
87
|
+
case "greater_than":
|
|
88
|
+
if (normalizedCheck.inclusive) {
|
|
89
|
+
schema.minimum = normalizedCheck.value;
|
|
90
|
+
} else {
|
|
91
|
+
schema.exclusiveMinimum = normalizedCheck.value;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case "less_than":
|
|
95
|
+
if (normalizedCheck.inclusive) {
|
|
96
|
+
schema.maximum = normalizedCheck.value;
|
|
97
|
+
} else {
|
|
98
|
+
schema.exclusiveMaximum = normalizedCheck.value;
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
case "number_format":
|
|
102
|
+
if (normalizedCheck.format === "int" || normalizedCheck.format === "safeint") {
|
|
103
|
+
schema.type = "integer";
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return schema;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { convertString, convertNumber };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { AuthErrorBase, CancelledErrorBase, InternalErrorBase, NetworkErrorBase, PermissionErrorBase, RateLimitErrorBase, TimeoutErrorBase } from "./contracts-qpbv29bg.js";
|
|
2
|
+
/**
|
|
3
|
+
* Authorization denied.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* new PermissionError({ message: "Cannot delete read-only resource" });
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
declare class PermissionError extends PermissionErrorBase {
|
|
11
|
+
readonly category: "permission";
|
|
12
|
+
/** Create a PermissionError with optional context. */
|
|
13
|
+
static create(message: string, context?: Record<string, unknown>): PermissionError;
|
|
14
|
+
exitCode(): number;
|
|
15
|
+
statusCode(): number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Operation timed out.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* new TimeoutError({ message: "Database query timed out after 5000ms", operation: "Database query", timeoutMs: 5000 });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare class TimeoutError extends TimeoutErrorBase {
|
|
26
|
+
readonly category: "timeout";
|
|
27
|
+
/** Create a TimeoutError with auto-generated message. */
|
|
28
|
+
static create(operation: string, timeoutMs: number): TimeoutError;
|
|
29
|
+
exitCode(): number;
|
|
30
|
+
statusCode(): number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Rate limit exceeded.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* new RateLimitError({ message: "Rate limit exceeded, retry after 60s", retryAfterSeconds: 60 });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare class RateLimitError extends RateLimitErrorBase {
|
|
41
|
+
readonly category: "rate_limit";
|
|
42
|
+
/** Create a RateLimitError with optional retry hint. */
|
|
43
|
+
static create(message: string, retryAfterSeconds?: number): RateLimitError;
|
|
44
|
+
exitCode(): number;
|
|
45
|
+
statusCode(): number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Network/transport failure.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* new NetworkError({ message: "Connection refused to api.example.com" });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
declare class NetworkError extends NetworkErrorBase {
|
|
56
|
+
readonly category: "network";
|
|
57
|
+
/** Create a NetworkError with optional context. */
|
|
58
|
+
static create(message: string, context?: Record<string, unknown>): NetworkError;
|
|
59
|
+
exitCode(): number;
|
|
60
|
+
statusCode(): number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Unexpected internal error.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* new InternalError({ message: "Unexpected state in processor" });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
declare class InternalError extends InternalErrorBase {
|
|
71
|
+
readonly category: "internal";
|
|
72
|
+
/** Create an InternalError with optional context. */
|
|
73
|
+
static create(message: string, context?: Record<string, unknown>): InternalError;
|
|
74
|
+
exitCode(): number;
|
|
75
|
+
statusCode(): number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Authentication failed (missing or invalid credentials).
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* new AuthError({ message: "Invalid API key", reason: "invalid" });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
declare class AuthError extends AuthErrorBase {
|
|
86
|
+
readonly category: "auth";
|
|
87
|
+
/** Create an AuthError with optional reason. */
|
|
88
|
+
static create(message: string, reason?: "missing" | "invalid" | "expired"): AuthError;
|
|
89
|
+
exitCode(): number;
|
|
90
|
+
statusCode(): number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Operation cancelled by user or signal.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* new CancelledError({ message: "Operation cancelled by user" });
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
declare class CancelledError extends CancelledErrorBase {
|
|
101
|
+
readonly category: "cancelled";
|
|
102
|
+
/** Create a CancelledError. */
|
|
103
|
+
static create(message: string): CancelledError;
|
|
104
|
+
exitCode(): number;
|
|
105
|
+
statusCode(): number;
|
|
106
|
+
}
|
|
107
|
+
export { PermissionError, TimeoutError, RateLimitError, NetworkError, InternalError, AuthError, CancelledError };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AuthError, CancelledError, InternalError, NetworkError, PermissionError, RateLimitError, TimeoutError } from "./contracts-735ecmbq.js";
|
|
2
|
+
import { AlreadyExistsError, AmbiguousError, AssertionError, ConflictError, NotFoundError, ValidationError } from "./contracts-mehpmvwp.js";
|
|
3
|
+
/**
|
|
4
|
+
* Canonical union type of all concrete error class instances.
|
|
5
|
+
*/
|
|
6
|
+
type OutfitterError = InstanceType<typeof ValidationError> | InstanceType<typeof AmbiguousError> | InstanceType<typeof AssertionError> | InstanceType<typeof NotFoundError> | InstanceType<typeof AlreadyExistsError> | InstanceType<typeof ConflictError> | InstanceType<typeof PermissionError> | InstanceType<typeof TimeoutError> | InstanceType<typeof RateLimitError> | InstanceType<typeof NetworkError> | InstanceType<typeof InternalError> | InstanceType<typeof AuthError> | InstanceType<typeof CancelledError>;
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Use `OutfitterError` instead. This alias will be removed in v1.0.
|
|
9
|
+
*/
|
|
10
|
+
type AnyKitError = OutfitterError;
|
|
11
|
+
export { OutfitterError, AnyKitError };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { JsonSchema } from "./contracts-w7nvcwrp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Convert a Zod schema to JSON Schema format.
|
|
5
|
+
*
|
|
6
|
+
* This is a simplified converter that handles common Zod types.
|
|
7
|
+
* For complex schemas, consider using a full zod-to-json-schema library.
|
|
8
|
+
*
|
|
9
|
+
* @param schema - Zod schema to convert
|
|
10
|
+
* @returns JSON Schema representation
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const zodSchema = z.object({
|
|
15
|
+
* name: z.string(),
|
|
16
|
+
* age: z.number().optional(),
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const jsonSchema = zodToJsonSchema(zodSchema);
|
|
20
|
+
* // {
|
|
21
|
+
* // type: "object",
|
|
22
|
+
* // properties: {
|
|
23
|
+
* // name: { type: "string" },
|
|
24
|
+
* // age: { type: "number" },
|
|
25
|
+
* // },
|
|
26
|
+
* // required: ["name"],
|
|
27
|
+
* // }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function zodToJsonSchema(schema: z.ZodType<unknown>): JsonSchema;
|
|
31
|
+
export { zodToJsonSchema };
|
|
@@ -22,6 +22,9 @@ function createContext(options) {
|
|
|
22
22
|
if (options.signal !== undefined) {
|
|
23
23
|
ctx.signal = options.signal;
|
|
24
24
|
}
|
|
25
|
+
if (options.progress !== undefined) {
|
|
26
|
+
ctx.progress = options.progress;
|
|
27
|
+
}
|
|
25
28
|
if (options.workspaceRoot !== undefined) {
|
|
26
29
|
ctx.workspaceRoot = options.workspaceRoot;
|
|
27
30
|
}
|