@outfitter/contracts 0.4.1 → 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/README.md +18 -15
- package/dist/actions.d.ts +8 -3
- package/dist/actions.js +25 -6
- package/dist/assert/index.d.ts +7 -3
- package/dist/assert/index.js +59 -6
- package/dist/capabilities.js +57 -8
- package/dist/context.d.ts +8 -3
- package/dist/context.js +1 -1
- package/dist/envelope.d.ts +6 -2
- package/dist/envelope.js +49 -7
- 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/index.d.ts +25 -14
- package/dist/index.js +17 -153
- 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-3wj7xghe.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/logging.js +11 -3
- package/dist/recovery.d.ts +6 -2
- package/dist/recovery.js +49 -6
- package/dist/resilience.d.ts +6 -2
- package/dist/resilience.js +80 -4
- package/dist/result/index.js +1 -16
- package/dist/result/utilities.js +29 -7
- package/dist/schema.d.ts +2 -1
- package/dist/schema.js +165 -2
- 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-0snpmkdt.js → contracts-hgh47193.js} +10 -4
- 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 +6 -2
- package/dist/wrap-error.d.ts +7 -0
- package/dist/wrap-error.js +71 -0
- package/package.json +44 -20
- 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-4zaj7ejb.js +0 -52
- package/dist/shared/@outfitter/contracts-85nd53s9.js +0 -53
- package/dist/shared/@outfitter/contracts-9wtm5nsw.d.ts +0 -42
- package/dist/shared/@outfitter/contracts-cp5c6dws.js +0 -32
- package/dist/shared/@outfitter/contracts-d0tq2adf.js +0 -60
- package/dist/shared/@outfitter/contracts-mmg0npfk.d.ts +0 -30
- package/dist/shared/@outfitter/contracts-phjhz5q3.js +0 -293
- package/dist/shared/@outfitter/contracts-q0v44kef.js +0 -28
- package/dist/shared/@outfitter/contracts-r21yet6j.js +0 -80
- package/dist/shared/@outfitter/contracts-sm6vak1a.js +0 -14
- package/dist/shared/@outfitter/contracts-t79engf9.d.ts +0 -60
- package/dist/shared/@outfitter/contracts-wfht4q2b.js +0 -341
- package/dist/shared/@outfitter/contracts-zx72gyh1.js +0 -32
- /package/dist/{shared/@outfitter/contracts-37gpc56f.js → hints.js} +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_PATTERNS,
|
|
4
|
+
DEFAULT_SENSITIVE_KEYS,
|
|
5
|
+
createRedactor
|
|
6
|
+
} from "../shared/@outfitter/contracts-s15x2rs4.js";
|
|
7
|
+
import {
|
|
8
|
+
formatZodIssues
|
|
9
|
+
} from "../shared/@outfitter/contracts-hgh47193.js";
|
|
10
|
+
import {
|
|
11
|
+
ValidationError
|
|
12
|
+
} from "../shared/@outfitter/contracts-vhr2ep6b.js";
|
|
13
|
+
|
|
14
|
+
// packages/contracts/src/internal/safe-json.ts
|
|
15
|
+
import { Result } from "better-result";
|
|
16
|
+
var defaultRedactor = createRedactor({
|
|
17
|
+
patterns: [...DEFAULT_PATTERNS],
|
|
18
|
+
keys: [...DEFAULT_SENSITIVE_KEYS]
|
|
19
|
+
});
|
|
20
|
+
function safeStringify(value, space) {
|
|
21
|
+
const seen = new WeakSet;
|
|
22
|
+
const replacer = (key, val) => {
|
|
23
|
+
if (typeof val === "bigint") {
|
|
24
|
+
return val.toString();
|
|
25
|
+
}
|
|
26
|
+
if (typeof val === "object" && val !== null) {
|
|
27
|
+
if (seen.has(val)) {
|
|
28
|
+
return "[Circular]";
|
|
29
|
+
}
|
|
30
|
+
seen.add(val);
|
|
31
|
+
}
|
|
32
|
+
if (key !== "" && defaultRedactor.isSensitiveKey(key) && val !== null && val !== undefined) {
|
|
33
|
+
return "[REDACTED]";
|
|
34
|
+
}
|
|
35
|
+
if (typeof val === "string") {
|
|
36
|
+
return defaultRedactor.redactString(val);
|
|
37
|
+
}
|
|
38
|
+
return val;
|
|
39
|
+
};
|
|
40
|
+
return JSON.stringify(value, replacer, space);
|
|
41
|
+
}
|
|
42
|
+
function safeParse(json, schema) {
|
|
43
|
+
let parsed;
|
|
44
|
+
try {
|
|
45
|
+
parsed = JSON.parse(json);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
const errorMessage = err instanceof Error ? err.message : "Unknown parse error";
|
|
48
|
+
return Result.err(new ValidationError({
|
|
49
|
+
message: `JSON parse error: ${errorMessage}`
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
if (schema === undefined) {
|
|
53
|
+
return Result.ok(parsed);
|
|
54
|
+
}
|
|
55
|
+
const parseResult = schema.safeParse(parsed);
|
|
56
|
+
if (parseResult.success) {
|
|
57
|
+
return Result.ok(parseResult.data);
|
|
58
|
+
}
|
|
59
|
+
return Result.err(new ValidationError({
|
|
60
|
+
message: `Schema validation failed: ${formatZodIssues(parseResult.error.issues)}`
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
safeStringify,
|
|
65
|
+
safeParse
|
|
66
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { JsonSchema } from "../shared/@outfitter/contracts-w7nvcwrp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Converter function type for the main dispatch function.
|
|
5
|
+
*
|
|
6
|
+
* This is injected to avoid circular dependencies between the converters
|
|
7
|
+
* and the dispatcher in schema.ts.
|
|
8
|
+
*/
|
|
9
|
+
type ZodTypeConverter = (schema: z.ZodType<unknown>) => JsonSchema;
|
|
10
|
+
/**
|
|
11
|
+
* Convert Zod array schema.
|
|
12
|
+
*/
|
|
13
|
+
declare function convertArray(def: any, convertZodType: ZodTypeConverter): JsonSchema;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a Zod field is optional by unwrapping wrapper types.
|
|
16
|
+
*
|
|
17
|
+
* This handles cases where optional fields are wrapped in ZodEffects
|
|
18
|
+
* (refinements, transforms) or ZodPipeline, which would otherwise
|
|
19
|
+
* incorrectly appear as required.
|
|
20
|
+
*/
|
|
21
|
+
declare function isFieldOptional(fieldDef: any): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Convert Zod object schema.
|
|
24
|
+
*/
|
|
25
|
+
declare function convertObject(def: any, convertZodType: ZodTypeConverter): JsonSchema;
|
|
26
|
+
export { isFieldOptional, convertObject, convertArray, ZodTypeConverter };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { JsonSchema } from "../shared/@outfitter/contracts-w7nvcwrp.js";
|
|
2
|
+
/**
|
|
3
|
+
* Convert Zod string schema with checks.
|
|
4
|
+
*/
|
|
5
|
+
declare function convertString(def: any): JsonSchema;
|
|
6
|
+
/**
|
|
7
|
+
* Convert Zod number schema with checks.
|
|
8
|
+
*/
|
|
9
|
+
declare function convertNumber(def: any): JsonSchema;
|
|
10
|
+
export { convertString, convertNumber };
|
package/dist/logging.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
// packages/contracts/src/logging.ts
|
|
3
|
+
function createLoggerFactory(adapter) {
|
|
4
|
+
return {
|
|
5
|
+
createLogger(config) {
|
|
6
|
+
return adapter.createLogger(config);
|
|
7
|
+
},
|
|
8
|
+
async flush() {
|
|
9
|
+
await adapter.flush?.();
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
5
13
|
export {
|
|
6
14
|
createLoggerFactory
|
|
7
15
|
};
|
package/dist/recovery.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import { BackoffOptions, getBackoffDelay, isRecoverable, isRetryable, shouldRetry } from "./shared/@outfitter/contracts-
|
|
2
|
-
import "./shared/@outfitter/contracts-
|
|
1
|
+
import { BackoffOptions, getBackoffDelay, isRecoverable, isRetryable, shouldRetry } from "./shared/@outfitter/contracts-10p5q75w.js";
|
|
2
|
+
import "./shared/@outfitter/contracts-7a0xmwbg.js";
|
|
3
|
+
import "./shared/@outfitter/contracts-735ecmbq.js";
|
|
4
|
+
import "./shared/@outfitter/contracts-mehpmvwp.js";
|
|
5
|
+
import "./shared/@outfitter/contracts-qpbv29bg.js";
|
|
6
|
+
import "./shared/@outfitter/contracts-njb2art4.js";
|
|
3
7
|
export { shouldRetry, isRetryable, isRecoverable, getBackoffDelay, BackoffOptions };
|
package/dist/recovery.js
CHANGED
|
@@ -1,10 +1,53 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
// packages/contracts/src/recovery.ts
|
|
3
|
+
var RECOVERABLE_CATEGORIES = [
|
|
4
|
+
"network",
|
|
5
|
+
"timeout",
|
|
6
|
+
"rate_limit",
|
|
7
|
+
"conflict"
|
|
8
|
+
];
|
|
9
|
+
var RETRYABLE_CATEGORIES = ["network", "timeout"];
|
|
10
|
+
var isRecoverable = (error) => {
|
|
11
|
+
return RECOVERABLE_CATEGORIES.includes(error.category);
|
|
12
|
+
};
|
|
13
|
+
var isRetryable = (error) => {
|
|
14
|
+
return RETRYABLE_CATEGORIES.includes(error.category);
|
|
15
|
+
};
|
|
16
|
+
var getBackoffDelay = (attempt, options = {}) => {
|
|
17
|
+
const {
|
|
18
|
+
baseDelayMs = 100,
|
|
19
|
+
maxDelayMs = 30000,
|
|
20
|
+
strategy = "exponential",
|
|
21
|
+
useJitter = true
|
|
22
|
+
} = options;
|
|
23
|
+
let delay;
|
|
24
|
+
switch (strategy) {
|
|
25
|
+
case "constant": {
|
|
26
|
+
delay = baseDelayMs;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case "linear": {
|
|
30
|
+
delay = baseDelayMs * (attempt + 1);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
default: {
|
|
34
|
+
delay = baseDelayMs * 2 ** attempt;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
delay = Math.min(delay, maxDelayMs);
|
|
38
|
+
if (useJitter) {
|
|
39
|
+
const jitterFactor = 0.1;
|
|
40
|
+
const jitter = delay * jitterFactor * (Math.random() * 2 - 1);
|
|
41
|
+
delay = Math.round(delay + jitter);
|
|
42
|
+
}
|
|
43
|
+
return Math.min(delay, maxDelayMs);
|
|
44
|
+
};
|
|
45
|
+
var shouldRetry = (error, attempt, maxAttempts = 3) => {
|
|
46
|
+
if (attempt >= maxAttempts) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return isRetryable(error);
|
|
50
|
+
};
|
|
8
51
|
export {
|
|
9
52
|
shouldRetry,
|
|
10
53
|
isRetryable,
|
package/dist/resilience.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import { RetryOptions, TimeoutOptions, retry, withTimeout } from "./shared/@outfitter/contracts-
|
|
2
|
-
import "./shared/@outfitter/contracts-
|
|
1
|
+
import { RetryOptions, TimeoutOptions, retry, withTimeout } from "./shared/@outfitter/contracts-mt027fqj.js";
|
|
2
|
+
import "./shared/@outfitter/contracts-7a0xmwbg.js";
|
|
3
|
+
import "./shared/@outfitter/contracts-735ecmbq.js";
|
|
4
|
+
import "./shared/@outfitter/contracts-mehpmvwp.js";
|
|
5
|
+
import "./shared/@outfitter/contracts-qpbv29bg.js";
|
|
6
|
+
import "./shared/@outfitter/contracts-njb2art4.js";
|
|
3
7
|
export { withTimeout, retry, TimeoutOptions, RetryOptions };
|
package/dist/resilience.js
CHANGED
|
@@ -1,9 +1,85 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "./shared/@outfitter/contracts-
|
|
6
|
-
|
|
3
|
+
InternalError,
|
|
4
|
+
TimeoutError
|
|
5
|
+
} from "./shared/@outfitter/contracts-vhr2ep6b.js";
|
|
6
|
+
|
|
7
|
+
// packages/contracts/src/resilience.ts
|
|
8
|
+
import { Result } from "better-result";
|
|
9
|
+
function defaultIsRetryable(error) {
|
|
10
|
+
return error.category === "network" || error.category === "timeout" || error.category === "rate_limit";
|
|
11
|
+
}
|
|
12
|
+
function calculateDelay(attempt, initialDelayMs, maxDelayMs, backoffMultiplier, jitter) {
|
|
13
|
+
const baseDelay = initialDelayMs * backoffMultiplier ** (attempt - 1);
|
|
14
|
+
const cappedDelay = Math.min(baseDelay, maxDelayMs);
|
|
15
|
+
if (jitter) {
|
|
16
|
+
const jitterFactor = 0.5 + Math.random();
|
|
17
|
+
return Math.floor(cappedDelay * jitterFactor);
|
|
18
|
+
}
|
|
19
|
+
return cappedDelay;
|
|
20
|
+
}
|
|
21
|
+
function sleep(ms) {
|
|
22
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
23
|
+
}
|
|
24
|
+
async function retry(fn, options) {
|
|
25
|
+
const maxAttempts = options?.maxAttempts ?? 3;
|
|
26
|
+
if (!(maxAttempts >= 1)) {
|
|
27
|
+
return Result.err(InternalError.create("maxAttempts must be >= 1", { maxAttempts }));
|
|
28
|
+
}
|
|
29
|
+
const initialDelayMs = options?.initialDelayMs ?? 1000;
|
|
30
|
+
const maxDelayMs = options?.maxDelayMs ?? 30000;
|
|
31
|
+
const backoffMultiplier = options?.backoffMultiplier ?? 2;
|
|
32
|
+
const jitter = options?.jitter ?? true;
|
|
33
|
+
const isRetryable = options?.isRetryable ?? defaultIsRetryable;
|
|
34
|
+
const onRetry = options?.onRetry;
|
|
35
|
+
const signal = options?.signal;
|
|
36
|
+
let lastError;
|
|
37
|
+
let attempt = 0;
|
|
38
|
+
while (attempt < maxAttempts) {
|
|
39
|
+
attempt++;
|
|
40
|
+
if (signal?.aborted) {
|
|
41
|
+
return Result.err(lastError ?? new TimeoutError({
|
|
42
|
+
message: "Operation cancelled",
|
|
43
|
+
operation: "retry",
|
|
44
|
+
timeoutMs: 0
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
const result = await fn();
|
|
48
|
+
if (result.isOk()) {
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
lastError = result.error;
|
|
52
|
+
if (attempt >= maxAttempts || !isRetryable(lastError)) {
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
const delayMs = calculateDelay(attempt, initialDelayMs, maxDelayMs, backoffMultiplier, jitter);
|
|
56
|
+
if (onRetry) {
|
|
57
|
+
onRetry(attempt, lastError, delayMs);
|
|
58
|
+
}
|
|
59
|
+
await sleep(delayMs);
|
|
60
|
+
}
|
|
61
|
+
return Result.err(InternalError.create("Unexpected: retry loop completed without returning a result"));
|
|
62
|
+
}
|
|
63
|
+
async function withTimeout(fn, options) {
|
|
64
|
+
const { timeoutMs, operation = "operation" } = options;
|
|
65
|
+
let timeoutId;
|
|
66
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
67
|
+
timeoutId = setTimeout(() => {
|
|
68
|
+
resolve(Result.err(new TimeoutError({
|
|
69
|
+
message: `${operation} timed out after ${timeoutMs}ms`,
|
|
70
|
+
operation,
|
|
71
|
+
timeoutMs
|
|
72
|
+
})));
|
|
73
|
+
}, timeoutMs);
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
return await Promise.race([fn(), timeoutPromise]);
|
|
77
|
+
} finally {
|
|
78
|
+
if (timeoutId !== undefined) {
|
|
79
|
+
clearTimeout(timeoutId);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
7
83
|
export {
|
|
8
84
|
withTimeout,
|
|
9
85
|
retry
|
package/dist/result/index.js
CHANGED
|
@@ -1,16 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import"../shared/@outfitter/contracts-37gpc56f.js";
|
|
3
|
-
import {
|
|
4
|
-
combine2,
|
|
5
|
-
combine3,
|
|
6
|
-
expect,
|
|
7
|
-
orElse,
|
|
8
|
-
unwrapOrElse
|
|
9
|
-
} from "../shared/@outfitter/contracts-zx72gyh1.js";
|
|
10
|
-
export {
|
|
11
|
-
unwrapOrElse,
|
|
12
|
-
orElse,
|
|
13
|
-
expect,
|
|
14
|
-
combine3,
|
|
15
|
-
combine2
|
|
16
|
-
};
|
|
1
|
+
export { combine2, combine3, expect, orElse, unwrapOrElse } from "./utilities.js";
|
package/dist/result/utilities.js
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
// packages/contracts/src/result/utilities.ts
|
|
3
|
+
import { Result } from "better-result";
|
|
4
|
+
var unwrapOrElse = (result, defaultFn) => {
|
|
5
|
+
return result.isOk() ? result.value : defaultFn(result.error);
|
|
6
|
+
};
|
|
7
|
+
var orElse = (result, fallback) => {
|
|
8
|
+
return result.isOk() ? result : fallback;
|
|
9
|
+
};
|
|
10
|
+
var combine2 = (r1, r2) => {
|
|
11
|
+
if (r1.isErr())
|
|
12
|
+
return r1;
|
|
13
|
+
if (r2.isErr())
|
|
14
|
+
return r2;
|
|
15
|
+
return Result.ok([r1.value, r2.value]);
|
|
16
|
+
};
|
|
17
|
+
var combine3 = (r1, r2, r3) => {
|
|
18
|
+
if (r1.isErr())
|
|
19
|
+
return r1;
|
|
20
|
+
if (r2.isErr())
|
|
21
|
+
return r2;
|
|
22
|
+
if (r3.isErr())
|
|
23
|
+
return r3;
|
|
24
|
+
return Result.ok([r1.value, r2.value, r3.value]);
|
|
25
|
+
};
|
|
26
|
+
var expect = (result, message) => {
|
|
27
|
+
if (result.isOk())
|
|
28
|
+
return result.value;
|
|
29
|
+
throw new Error(`${message}: ${String(result.error)}`);
|
|
30
|
+
};
|
|
9
31
|
export {
|
|
10
32
|
unwrapOrElse,
|
|
11
33
|
orElse,
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { zodToJsonSchema } from "./shared/@outfitter/contracts-8cmkh2db.js";
|
|
2
|
+
import { JsonSchema } from "./shared/@outfitter/contracts-w7nvcwrp.js";
|
|
2
3
|
export { zodToJsonSchema, JsonSchema };
|
package/dist/schema.js
CHANGED
|
@@ -1,7 +1,170 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
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
|
+
|
|
15
|
+
// packages/contracts/src/schema.ts
|
|
16
|
+
function zodToJsonSchema(schema) {
|
|
17
|
+
return convertZodType(schema);
|
|
18
|
+
}
|
|
19
|
+
function convertZodType(schema) {
|
|
20
|
+
const def = getDef(schema);
|
|
21
|
+
if (!def) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
const typeName = def.typeName ?? def.type;
|
|
25
|
+
let jsonSchema;
|
|
26
|
+
switch (typeName) {
|
|
27
|
+
case "ZodString":
|
|
28
|
+
case "string":
|
|
29
|
+
jsonSchema = convertString(def);
|
|
30
|
+
break;
|
|
31
|
+
case "ZodNumber":
|
|
32
|
+
case "number":
|
|
33
|
+
jsonSchema = convertNumber(def);
|
|
34
|
+
break;
|
|
35
|
+
case "ZodBoolean":
|
|
36
|
+
case "boolean":
|
|
37
|
+
jsonSchema = { type: "boolean" };
|
|
38
|
+
break;
|
|
39
|
+
case "ZodNull":
|
|
40
|
+
case "null":
|
|
41
|
+
jsonSchema = { type: "null" };
|
|
42
|
+
break;
|
|
43
|
+
case "ZodUndefined":
|
|
44
|
+
case "undefined":
|
|
45
|
+
jsonSchema = {};
|
|
46
|
+
break;
|
|
47
|
+
case "ZodArray":
|
|
48
|
+
case "array":
|
|
49
|
+
jsonSchema = convertArray(def, convertZodType);
|
|
50
|
+
break;
|
|
51
|
+
case "ZodObject":
|
|
52
|
+
case "object":
|
|
53
|
+
jsonSchema = convertObject(def, convertZodType);
|
|
54
|
+
break;
|
|
55
|
+
case "ZodOptional":
|
|
56
|
+
case "optional":
|
|
57
|
+
jsonSchema = convertZodType(def.innerType);
|
|
58
|
+
break;
|
|
59
|
+
case "ZodNullable":
|
|
60
|
+
case "nullable":
|
|
61
|
+
jsonSchema = {
|
|
62
|
+
anyOf: [convertZodType(def.innerType), { type: "null" }]
|
|
63
|
+
};
|
|
64
|
+
break;
|
|
65
|
+
case "ZodDefault":
|
|
66
|
+
case "default": {
|
|
67
|
+
const defaultValue = typeof def.defaultValue === "function" ? def.defaultValue() : def.defaultValue;
|
|
68
|
+
jsonSchema = {
|
|
69
|
+
...convertZodType(def.innerType),
|
|
70
|
+
default: defaultValue
|
|
71
|
+
};
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "ZodEnum":
|
|
75
|
+
case "enum": {
|
|
76
|
+
const values = def.values ?? Object.values(def.entries ?? {});
|
|
77
|
+
jsonSchema = {
|
|
78
|
+
type: "string",
|
|
79
|
+
enum: values
|
|
80
|
+
};
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case "ZodNativeEnum":
|
|
84
|
+
jsonSchema = {
|
|
85
|
+
enum: Object.values(def.values ?? def.entries ?? {})
|
|
86
|
+
};
|
|
87
|
+
break;
|
|
88
|
+
case "ZodLiteral":
|
|
89
|
+
case "literal": {
|
|
90
|
+
const literalValues = Array.isArray(def.values) ? def.values : [def.value].filter((value) => value !== undefined);
|
|
91
|
+
if (literalValues.length > 1) {
|
|
92
|
+
jsonSchema = {
|
|
93
|
+
enum: literalValues
|
|
94
|
+
};
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
jsonSchema = literalValues.length ? {
|
|
98
|
+
const: literalValues[0]
|
|
99
|
+
} : {};
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case "ZodUnion":
|
|
103
|
+
case "union":
|
|
104
|
+
jsonSchema = {
|
|
105
|
+
anyOf: def.options.map(convertZodType)
|
|
106
|
+
};
|
|
107
|
+
break;
|
|
108
|
+
case "ZodIntersection":
|
|
109
|
+
case "intersection":
|
|
110
|
+
jsonSchema = {
|
|
111
|
+
allOf: [convertZodType(def.left), convertZodType(def.right)]
|
|
112
|
+
};
|
|
113
|
+
break;
|
|
114
|
+
case "ZodRecord":
|
|
115
|
+
case "record":
|
|
116
|
+
jsonSchema = {
|
|
117
|
+
type: "object",
|
|
118
|
+
additionalProperties: def.valueType ? convertZodType(def.valueType) : {}
|
|
119
|
+
};
|
|
120
|
+
break;
|
|
121
|
+
case "ZodTuple":
|
|
122
|
+
case "tuple":
|
|
123
|
+
jsonSchema = {
|
|
124
|
+
type: "array",
|
|
125
|
+
items: def.items.map(convertZodType)
|
|
126
|
+
};
|
|
127
|
+
break;
|
|
128
|
+
case "ZodAny":
|
|
129
|
+
case "any":
|
|
130
|
+
jsonSchema = {};
|
|
131
|
+
break;
|
|
132
|
+
case "ZodUnknown":
|
|
133
|
+
case "unknown":
|
|
134
|
+
jsonSchema = {};
|
|
135
|
+
break;
|
|
136
|
+
case "ZodVoid":
|
|
137
|
+
case "void":
|
|
138
|
+
jsonSchema = {};
|
|
139
|
+
break;
|
|
140
|
+
case "ZodNever":
|
|
141
|
+
case "never":
|
|
142
|
+
jsonSchema = { not: {} };
|
|
143
|
+
break;
|
|
144
|
+
case "ZodEffects":
|
|
145
|
+
jsonSchema = convertZodType(def.schema);
|
|
146
|
+
break;
|
|
147
|
+
case "ZodPipeline":
|
|
148
|
+
case "pipe": {
|
|
149
|
+
const outputDef = getDef(def.out);
|
|
150
|
+
const outputType = outputDef?.typeName ?? outputDef?.type;
|
|
151
|
+
jsonSchema = outputType === "transform" ? convertZodType(def.in) : convertZodType(def.out);
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case "ZodLazy":
|
|
155
|
+
case "lazy":
|
|
156
|
+
jsonSchema = {};
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
jsonSchema = {};
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
const description = getDescription(schema, def);
|
|
163
|
+
if (description && !jsonSchema.description) {
|
|
164
|
+
jsonSchema.description = description;
|
|
165
|
+
}
|
|
166
|
+
return jsonSchema;
|
|
167
|
+
}
|
|
5
168
|
export {
|
|
6
169
|
zodToJsonSchema
|
|
7
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-s15x2rs4.js";
|
|
9
|
-
import"./shared/@outfitter/contracts-phjhz5q3.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 };
|