@outfitter/contracts 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -2
- package/dist/actions.d.ts +4 -3
- package/dist/assert/index.d.ts +2 -2
- package/dist/assert/index.js +2 -2
- package/dist/context.d.ts +4 -3
- package/dist/context.js +1 -1
- package/dist/envelope.d.ts +2 -2
- package/dist/envelope.js +4 -4
- package/dist/errors.d.ts +2 -2
- package/dist/errors.js +6 -2
- package/dist/handler.d.ts +3 -2
- package/dist/index.d.ts +14 -13
- package/dist/index.js +42 -32
- package/dist/logging.d.ts +2 -0
- package/dist/logging.js +7 -0
- package/dist/recovery.d.ts +2 -2
- package/dist/resilience.d.ts +2 -2
- package/dist/resilience.js +2 -2
- package/dist/result/index.d.ts +2 -2
- package/dist/result/index.js +3 -1
- package/dist/result/utilities.d.ts +2 -2
- package/dist/result/utilities.js +3 -1
- package/dist/serialization.d.ts +2 -2
- package/dist/serialization.js +2 -2
- package/dist/shared/@outfitter/{contracts-sf5p84cc.js → contracts-0snpmkdt.js} +1 -1
- package/dist/shared/@outfitter/{contracts-t3j7fba3.d.ts → contracts-18vcxecr.d.ts} +1 -1
- package/dist/shared/@outfitter/{contracts-wwkk3j4m.d.ts → contracts-25bkj17f.d.ts} +2 -1
- package/dist/shared/@outfitter/contracts-2g8r01zf.d.ts +73 -0
- package/dist/shared/@outfitter/{contracts-dbpj0b4k.js → contracts-5k6q4n48.js} +61 -9
- package/dist/shared/@outfitter/{contracts-g82822x1.d.ts → contracts-6j6z9dsd.d.ts} +1 -1
- package/dist/shared/@outfitter/{contracts-y8qg2nvz.js → contracts-agmt8915.js} +6 -6
- package/dist/shared/@outfitter/{contracts-109drsem.d.ts → contracts-ar0etwtx.d.ts} +23 -1
- package/dist/shared/@outfitter/{contracts-37891j7e.d.ts → contracts-bdwg55c5.d.ts} +1 -1
- package/dist/shared/@outfitter/{contracts-chnm7kvm.js → contracts-btg89x4h.js} +3 -3
- package/dist/shared/@outfitter/{contracts-d1thk8cv.js → contracts-cp5c6dws.js} +1 -1
- package/dist/shared/@outfitter/{contracts-47aemgd3.d.ts → contracts-evxky148.d.ts} +1 -1
- package/dist/shared/@outfitter/{contracts-0taqjz0a.d.ts → contracts-j08e95jw.d.ts} +1 -1
- package/dist/shared/@outfitter/{contracts-q9tjk2zp.d.ts → contracts-jggbn5tn.d.ts} +1 -1
- package/dist/shared/@outfitter/{contracts-jhsgc85s.js → contracts-phjhz5q3.js} +95 -2
- package/dist/shared/@outfitter/{contracts-aq745b7n.js → contracts-r21yet6j.js} +1 -1
- package/dist/shared/@outfitter/{contracts-ev4a68sg.d.ts → contracts-r35bn9p6.d.ts} +124 -3
- package/dist/shared/@outfitter/{contracts-vtrf6rbx.d.ts → contracts-sf1z80yc.d.ts} +2 -2
- package/dist/shared/@outfitter/contracts-sm6vak1a.js +14 -0
- package/dist/shared/@outfitter/{contracts-yp3derbe.d.ts → contracts-ss9vjjft.d.ts} +3 -37
- package/dist/shared/@outfitter/{contracts-r06bafs8.js → contracts-zx72gyh1.js} +6 -1
- package/dist/validation.d.ts +2 -2
- package/dist/validation.js +2 -2
- package/package.json +50 -44
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from "./contracts-s15x2rs4.js";
|
|
7
|
-
import {
|
|
3
|
+
AlreadyExistsError,
|
|
4
|
+
AmbiguousError,
|
|
5
|
+
AssertionError,
|
|
8
6
|
AuthError,
|
|
9
7
|
CancelledError,
|
|
10
8
|
ConflictError,
|
|
@@ -15,13 +13,21 @@ import {
|
|
|
15
13
|
RateLimitError,
|
|
16
14
|
TimeoutError,
|
|
17
15
|
ValidationError
|
|
18
|
-
} from "./contracts-
|
|
16
|
+
} from "./contracts-phjhz5q3.js";
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_PATTERNS,
|
|
19
|
+
DEFAULT_SENSITIVE_KEYS,
|
|
20
|
+
createRedactor
|
|
21
|
+
} from "./contracts-s15x2rs4.js";
|
|
19
22
|
|
|
20
23
|
// packages/contracts/src/serialization.ts
|
|
21
24
|
import { Result } from "better-result";
|
|
22
25
|
var errorRegistry = {
|
|
23
26
|
ValidationError,
|
|
27
|
+
AmbiguousError,
|
|
28
|
+
AssertionError,
|
|
24
29
|
NotFoundError,
|
|
30
|
+
AlreadyExistsError,
|
|
25
31
|
ConflictError,
|
|
26
32
|
PermissionError,
|
|
27
33
|
TimeoutError,
|
|
@@ -46,10 +52,22 @@ function extractContext(error) {
|
|
|
46
52
|
}
|
|
47
53
|
case "NotFoundError": {
|
|
48
54
|
const nfe = error;
|
|
55
|
+
if (nfe.context !== undefined) {
|
|
56
|
+
Object.assign(context, nfe.context);
|
|
57
|
+
}
|
|
49
58
|
context["resourceType"] = nfe.resourceType;
|
|
50
59
|
context["resourceId"] = nfe.resourceId;
|
|
51
60
|
break;
|
|
52
61
|
}
|
|
62
|
+
case "AlreadyExistsError": {
|
|
63
|
+
const aee = error;
|
|
64
|
+
if (aee.context !== undefined) {
|
|
65
|
+
Object.assign(context, aee.context);
|
|
66
|
+
}
|
|
67
|
+
context["resourceType"] = aee.resourceType;
|
|
68
|
+
context["resourceId"] = aee.resourceId;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
53
71
|
case "TimeoutError": {
|
|
54
72
|
const te = error;
|
|
55
73
|
context["operation"] = te.operation;
|
|
@@ -70,6 +88,13 @@ function extractContext(error) {
|
|
|
70
88
|
}
|
|
71
89
|
break;
|
|
72
90
|
}
|
|
91
|
+
case "AmbiguousError": {
|
|
92
|
+
const amb = error;
|
|
93
|
+
context["candidates"] = amb.candidates;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case "AssertionError":
|
|
97
|
+
break;
|
|
73
98
|
case "ConflictError":
|
|
74
99
|
case "PermissionError":
|
|
75
100
|
case "NetworkError":
|
|
@@ -128,12 +153,30 @@ function deserializeError(data) {
|
|
|
128
153
|
}
|
|
129
154
|
return new ValidationError(props);
|
|
130
155
|
}
|
|
131
|
-
case "NotFoundError":
|
|
132
|
-
|
|
156
|
+
case "NotFoundError": {
|
|
157
|
+
const props = {
|
|
133
158
|
message: data.message,
|
|
134
159
|
resourceType: context["resourceType"] ?? "unknown",
|
|
135
160
|
resourceId: context["resourceId"] ?? "unknown"
|
|
136
|
-
}
|
|
161
|
+
};
|
|
162
|
+
const contextWithoutIdentity = Object.fromEntries(Object.entries(context).filter(([key]) => key !== "resourceType" && key !== "resourceId"));
|
|
163
|
+
if (Object.keys(contextWithoutIdentity).length > 0) {
|
|
164
|
+
props.context = contextWithoutIdentity;
|
|
165
|
+
}
|
|
166
|
+
return new NotFoundError(props);
|
|
167
|
+
}
|
|
168
|
+
case "AlreadyExistsError": {
|
|
169
|
+
const props = {
|
|
170
|
+
message: data.message,
|
|
171
|
+
resourceType: context["resourceType"] ?? "unknown",
|
|
172
|
+
resourceId: context["resourceId"] ?? "unknown"
|
|
173
|
+
};
|
|
174
|
+
const contextWithoutIdentity = Object.fromEntries(Object.entries(context).filter(([key]) => key !== "resourceType" && key !== "resourceId"));
|
|
175
|
+
if (Object.keys(contextWithoutIdentity).length > 0) {
|
|
176
|
+
props.context = contextWithoutIdentity;
|
|
177
|
+
}
|
|
178
|
+
return new AlreadyExistsError(props);
|
|
179
|
+
}
|
|
137
180
|
case "ConflictError": {
|
|
138
181
|
const props = {
|
|
139
182
|
message: data.message
|
|
@@ -196,6 +239,15 @@ function deserializeError(data) {
|
|
|
196
239
|
}
|
|
197
240
|
return new AuthError(props);
|
|
198
241
|
}
|
|
242
|
+
case "AmbiguousError":
|
|
243
|
+
return new AmbiguousError({
|
|
244
|
+
message: data.message,
|
|
245
|
+
candidates: context["candidates"] ?? []
|
|
246
|
+
});
|
|
247
|
+
case "AssertionError":
|
|
248
|
+
return new AssertionError({
|
|
249
|
+
message: data.message
|
|
250
|
+
});
|
|
199
251
|
case "CancelledError":
|
|
200
252
|
return new CancelledError({
|
|
201
253
|
message: data.message
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/contracts/src/context.ts
|
|
3
3
|
var noopLogger = {
|
|
4
|
-
trace: () => {},
|
|
5
|
-
debug: () => {},
|
|
6
|
-
info: () => {},
|
|
7
|
-
warn: () => {},
|
|
8
|
-
error: () => {},
|
|
9
|
-
fatal: () => {},
|
|
4
|
+
trace: (..._args) => {},
|
|
5
|
+
debug: (..._args) => {},
|
|
6
|
+
info: (..._args) => {},
|
|
7
|
+
warn: (..._args) => {},
|
|
8
|
+
error: (..._args) => {},
|
|
9
|
+
fatal: (..._args) => {},
|
|
10
10
|
child: () => noopLogger
|
|
11
11
|
};
|
|
12
12
|
function createContext(options) {
|
|
@@ -100,4 +100,26 @@ declare const combine3: <
|
|
|
100
100
|
T3,
|
|
101
101
|
E
|
|
102
102
|
>(r1: Result<T1, E>, r2: Result<T2, E>, r3: Result<T3, E>) => Result<[T1, T2, T3], E>;
|
|
103
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Extract value from Ok, or throw with a contextual error message.
|
|
105
|
+
*
|
|
106
|
+
* Like `unwrap()` but with a caller-provided message for better
|
|
107
|
+
* debugging context. Use at system boundaries (CLI adapters, MCP
|
|
108
|
+
* handlers) where you need the value and want a clear error.
|
|
109
|
+
*
|
|
110
|
+
* @param result - The Result to unwrap
|
|
111
|
+
* @param message - Context message prepended to the error
|
|
112
|
+
* @returns The success value
|
|
113
|
+
* @throws Error with contextual message if Result is Err
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const config = expect(loadConfig(), "Failed to load config");
|
|
118
|
+
* // On Err, throws: "Failed to load config: <error details>"
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
declare const expect: <
|
|
122
|
+
T,
|
|
123
|
+
E
|
|
124
|
+
>(result: Result<T, E>, message: string) => T;
|
|
125
|
+
export { unwrapOrElse, orElse, combine2, combine3, expect };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
serializeError
|
|
4
|
-
} from "./contracts-
|
|
4
|
+
} from "./contracts-5k6q4n48.js";
|
|
5
5
|
import {
|
|
6
6
|
generateRequestId
|
|
7
|
-
} from "./contracts-
|
|
7
|
+
} from "./contracts-agmt8915.js";
|
|
8
8
|
import {
|
|
9
9
|
statusCodeMap
|
|
10
|
-
} from "./contracts-
|
|
10
|
+
} from "./contracts-phjhz5q3.js";
|
|
11
11
|
|
|
12
12
|
// packages/contracts/src/envelope.ts
|
|
13
13
|
function buildMeta(overrides) {
|
|
@@ -30,7 +30,8 @@ var ERROR_CODES = {
|
|
|
30
30
|
FIELD_REQUIRED: 1001,
|
|
31
31
|
INVALID_FORMAT: 1002,
|
|
32
32
|
OUT_OF_RANGE: 1003,
|
|
33
|
-
TYPE_MISMATCH: 1004
|
|
33
|
+
TYPE_MISMATCH: 1004,
|
|
34
|
+
AMBIGUOUS_MATCH: 1005
|
|
34
35
|
},
|
|
35
36
|
not_found: {
|
|
36
37
|
RESOURCE_NOT_FOUND: 2001,
|
|
@@ -76,8 +77,10 @@ function getStatusCode(category) {
|
|
|
76
77
|
return statusCodeMap[category];
|
|
77
78
|
}
|
|
78
79
|
var ValidationErrorBase = TaggedError("ValidationError")();
|
|
80
|
+
var AmbiguousErrorBase = TaggedError("AmbiguousError")();
|
|
79
81
|
var AssertionErrorBase = TaggedError("AssertionError")();
|
|
80
82
|
var NotFoundErrorBase = TaggedError("NotFoundError")();
|
|
83
|
+
var AlreadyExistsErrorBase = TaggedError("AlreadyExistsError")();
|
|
81
84
|
var ConflictErrorBase = TaggedError("ConflictError")();
|
|
82
85
|
var PermissionErrorBase = TaggedError("PermissionError")();
|
|
83
86
|
var TimeoutErrorBase = TaggedError("TimeoutError")();
|
|
@@ -89,6 +92,36 @@ var CancelledErrorBase = TaggedError("CancelledError")();
|
|
|
89
92
|
|
|
90
93
|
class ValidationError extends ValidationErrorBase {
|
|
91
94
|
category = "validation";
|
|
95
|
+
static create(field, reason, context) {
|
|
96
|
+
return new ValidationError({
|
|
97
|
+
message: `${field}: ${reason}`,
|
|
98
|
+
field,
|
|
99
|
+
...context != null && { context }
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
static fromMessage(message, context) {
|
|
103
|
+
return new ValidationError({
|
|
104
|
+
message,
|
|
105
|
+
...context != null && { context }
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
exitCode() {
|
|
109
|
+
return getExitCode(this.category);
|
|
110
|
+
}
|
|
111
|
+
statusCode() {
|
|
112
|
+
return getStatusCode(this.category);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
class AmbiguousError extends AmbiguousErrorBase {
|
|
117
|
+
category = "validation";
|
|
118
|
+
static create(what, candidates, context) {
|
|
119
|
+
return new AmbiguousError({
|
|
120
|
+
message: `Ambiguous ${what}: ${candidates.length} matches found`,
|
|
121
|
+
candidates,
|
|
122
|
+
...context != null && { context }
|
|
123
|
+
});
|
|
124
|
+
}
|
|
92
125
|
exitCode() {
|
|
93
126
|
return getExitCode(this.category);
|
|
94
127
|
}
|
|
@@ -109,6 +142,32 @@ class AssertionError extends AssertionErrorBase {
|
|
|
109
142
|
|
|
110
143
|
class NotFoundError extends NotFoundErrorBase {
|
|
111
144
|
category = "not_found";
|
|
145
|
+
static create(resourceType, resourceId, context) {
|
|
146
|
+
return new NotFoundError({
|
|
147
|
+
message: `${resourceType} not found: ${resourceId}`,
|
|
148
|
+
resourceType,
|
|
149
|
+
resourceId,
|
|
150
|
+
...context != null && { context }
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
exitCode() {
|
|
154
|
+
return getExitCode(this.category);
|
|
155
|
+
}
|
|
156
|
+
statusCode() {
|
|
157
|
+
return getStatusCode(this.category);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
class AlreadyExistsError extends AlreadyExistsErrorBase {
|
|
162
|
+
category = "conflict";
|
|
163
|
+
static create(resourceType, resourceId, context) {
|
|
164
|
+
return new AlreadyExistsError({
|
|
165
|
+
message: `${resourceType} already exists: ${resourceId}`,
|
|
166
|
+
resourceType,
|
|
167
|
+
resourceId,
|
|
168
|
+
...context != null && { context }
|
|
169
|
+
});
|
|
170
|
+
}
|
|
112
171
|
exitCode() {
|
|
113
172
|
return getExitCode(this.category);
|
|
114
173
|
}
|
|
@@ -119,6 +178,9 @@ class NotFoundError extends NotFoundErrorBase {
|
|
|
119
178
|
|
|
120
179
|
class ConflictError extends ConflictErrorBase {
|
|
121
180
|
category = "conflict";
|
|
181
|
+
static create(message, context) {
|
|
182
|
+
return new ConflictError({ message, ...context != null && { context } });
|
|
183
|
+
}
|
|
122
184
|
exitCode() {
|
|
123
185
|
return getExitCode(this.category);
|
|
124
186
|
}
|
|
@@ -129,6 +191,12 @@ class ConflictError extends ConflictErrorBase {
|
|
|
129
191
|
|
|
130
192
|
class PermissionError extends PermissionErrorBase {
|
|
131
193
|
category = "permission";
|
|
194
|
+
static create(message, context) {
|
|
195
|
+
return new PermissionError({
|
|
196
|
+
message,
|
|
197
|
+
...context != null && { context }
|
|
198
|
+
});
|
|
199
|
+
}
|
|
132
200
|
exitCode() {
|
|
133
201
|
return getExitCode(this.category);
|
|
134
202
|
}
|
|
@@ -139,6 +207,13 @@ class PermissionError extends PermissionErrorBase {
|
|
|
139
207
|
|
|
140
208
|
class TimeoutError extends TimeoutErrorBase {
|
|
141
209
|
category = "timeout";
|
|
210
|
+
static create(operation, timeoutMs) {
|
|
211
|
+
return new TimeoutError({
|
|
212
|
+
message: `${operation} timed out after ${timeoutMs}ms`,
|
|
213
|
+
operation,
|
|
214
|
+
timeoutMs
|
|
215
|
+
});
|
|
216
|
+
}
|
|
142
217
|
exitCode() {
|
|
143
218
|
return getExitCode(this.category);
|
|
144
219
|
}
|
|
@@ -149,6 +224,12 @@ class TimeoutError extends TimeoutErrorBase {
|
|
|
149
224
|
|
|
150
225
|
class RateLimitError extends RateLimitErrorBase {
|
|
151
226
|
category = "rate_limit";
|
|
227
|
+
static create(message, retryAfterSeconds) {
|
|
228
|
+
return new RateLimitError({
|
|
229
|
+
message,
|
|
230
|
+
...retryAfterSeconds != null && { retryAfterSeconds }
|
|
231
|
+
});
|
|
232
|
+
}
|
|
152
233
|
exitCode() {
|
|
153
234
|
return getExitCode(this.category);
|
|
154
235
|
}
|
|
@@ -159,6 +240,9 @@ class RateLimitError extends RateLimitErrorBase {
|
|
|
159
240
|
|
|
160
241
|
class NetworkError extends NetworkErrorBase {
|
|
161
242
|
category = "network";
|
|
243
|
+
static create(message, context) {
|
|
244
|
+
return new NetworkError({ message, ...context != null && { context } });
|
|
245
|
+
}
|
|
162
246
|
exitCode() {
|
|
163
247
|
return getExitCode(this.category);
|
|
164
248
|
}
|
|
@@ -169,6 +253,9 @@ class NetworkError extends NetworkErrorBase {
|
|
|
169
253
|
|
|
170
254
|
class InternalError extends InternalErrorBase {
|
|
171
255
|
category = "internal";
|
|
256
|
+
static create(message, context) {
|
|
257
|
+
return new InternalError({ message, ...context != null && { context } });
|
|
258
|
+
}
|
|
172
259
|
exitCode() {
|
|
173
260
|
return getExitCode(this.category);
|
|
174
261
|
}
|
|
@@ -179,6 +266,9 @@ class InternalError extends InternalErrorBase {
|
|
|
179
266
|
|
|
180
267
|
class AuthError extends AuthErrorBase {
|
|
181
268
|
category = "auth";
|
|
269
|
+
static create(message, reason) {
|
|
270
|
+
return new AuthError({ message, ...reason != null && { reason } });
|
|
271
|
+
}
|
|
182
272
|
exitCode() {
|
|
183
273
|
return getExitCode(this.category);
|
|
184
274
|
}
|
|
@@ -189,6 +279,9 @@ class AuthError extends AuthErrorBase {
|
|
|
189
279
|
|
|
190
280
|
class CancelledError extends CancelledErrorBase {
|
|
191
281
|
category = "cancelled";
|
|
282
|
+
static create(message) {
|
|
283
|
+
return new CancelledError({ message });
|
|
284
|
+
}
|
|
192
285
|
exitCode() {
|
|
193
286
|
return getExitCode(this.category);
|
|
194
287
|
}
|
|
@@ -197,4 +290,4 @@ class CancelledError extends CancelledErrorBase {
|
|
|
197
290
|
}
|
|
198
291
|
}
|
|
199
292
|
|
|
200
|
-
export { exitCodeMap, statusCodeMap, ERROR_CODES, getExitCode, getStatusCode, ValidationError, AssertionError, NotFoundError, ConflictError, PermissionError, TimeoutError, RateLimitError, NetworkError, InternalError, AuthError, CancelledError };
|
|
293
|
+
export { exitCodeMap, statusCodeMap, ERROR_CODES, getExitCode, getStatusCode, ValidationError, AmbiguousError, AssertionError, NotFoundError, AlreadyExistsError, ConflictError, PermissionError, TimeoutError, RateLimitError, NetworkError, InternalError, AuthError, CancelledError };
|
|
@@ -40,6 +40,7 @@ declare const ERROR_CODES: {
|
|
|
40
40
|
readonly INVALID_FORMAT: 1002;
|
|
41
41
|
readonly OUT_OF_RANGE: 1003;
|
|
42
42
|
readonly TYPE_MISMATCH: 1004;
|
|
43
|
+
readonly AMBIGUOUS_MATCH: 1005;
|
|
43
44
|
};
|
|
44
45
|
readonly not_found: {
|
|
45
46
|
readonly RESOURCE_NOT_FOUND: 2001;
|
|
@@ -112,6 +113,12 @@ declare function getStatusCode(category: ErrorCategory): number;
|
|
|
112
113
|
declare const ValidationErrorBase: TaggedErrorClass<"ValidationError", {
|
|
113
114
|
message: string;
|
|
114
115
|
field?: string;
|
|
116
|
+
context?: Record<string, unknown>;
|
|
117
|
+
}>;
|
|
118
|
+
declare const AmbiguousErrorBase: TaggedErrorClass<"AmbiguousError", {
|
|
119
|
+
message: string;
|
|
120
|
+
candidates: string[];
|
|
121
|
+
context?: Record<string, unknown>;
|
|
115
122
|
}>;
|
|
116
123
|
declare const AssertionErrorBase: TaggedErrorClass<"AssertionError", {
|
|
117
124
|
message: string;
|
|
@@ -120,6 +127,13 @@ declare const NotFoundErrorBase: TaggedErrorClass<"NotFoundError", {
|
|
|
120
127
|
message: string;
|
|
121
128
|
resourceType: string;
|
|
122
129
|
resourceId: string;
|
|
130
|
+
context?: Record<string, unknown>;
|
|
131
|
+
}>;
|
|
132
|
+
declare const AlreadyExistsErrorBase: TaggedErrorClass<"AlreadyExistsError", {
|
|
133
|
+
message: string;
|
|
134
|
+
resourceType: string;
|
|
135
|
+
resourceId: string;
|
|
136
|
+
context?: Record<string, unknown>;
|
|
123
137
|
}>;
|
|
124
138
|
declare const ConflictErrorBase: TaggedErrorClass<"ConflictError", {
|
|
125
139
|
message: string;
|
|
@@ -159,10 +173,50 @@ declare const CancelledErrorBase: TaggedErrorClass<"CancelledError", {
|
|
|
159
173
|
* @example
|
|
160
174
|
* ```typescript
|
|
161
175
|
* new ValidationError({ message: "Email format invalid", field: "email" });
|
|
176
|
+
* new ValidationError({
|
|
177
|
+
* message: "Value out of range",
|
|
178
|
+
* field: "age",
|
|
179
|
+
* context: { min: 0, max: 150, received: -1 },
|
|
180
|
+
* });
|
|
162
181
|
* ```
|
|
163
182
|
*/
|
|
164
183
|
declare class ValidationError extends ValidationErrorBase {
|
|
165
184
|
readonly category: "validation";
|
|
185
|
+
/** Create a ValidationError with auto-generated message from field name. */
|
|
186
|
+
static create(field: string, reason: string, context?: Record<string, unknown>): ValidationError;
|
|
187
|
+
/**
|
|
188
|
+
* Create a freeform ValidationError without a specific field.
|
|
189
|
+
*
|
|
190
|
+
* Use when the validation failure applies to the input as a whole
|
|
191
|
+
* rather than a single field (e.g., "Invalid pipeline configuration").
|
|
192
|
+
*
|
|
193
|
+
* @param message - Human-readable validation error message
|
|
194
|
+
* @param context - Optional structured context for debugging
|
|
195
|
+
*/
|
|
196
|
+
static fromMessage(message: string, context?: Record<string, unknown>): ValidationError;
|
|
197
|
+
exitCode(): number;
|
|
198
|
+
statusCode(): number;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Multiple matches found — user must disambiguate.
|
|
202
|
+
*
|
|
203
|
+
* Used in search/resolution systems where partial input matches
|
|
204
|
+
* multiple candidates. Carries the candidate list so transport
|
|
205
|
+
* layers can prompt disambiguation.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* new AmbiguousError({
|
|
210
|
+
* message: "Multiple headings match 'Intro'",
|
|
211
|
+
* candidates: ["Introduction", "Intro to APIs"],
|
|
212
|
+
* });
|
|
213
|
+
* AmbiguousError.create("heading", ["Introduction", "Intro to APIs"]);
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
declare class AmbiguousError extends AmbiguousErrorBase {
|
|
217
|
+
readonly category: "validation";
|
|
218
|
+
/** Create an AmbiguousError with auto-generated message. */
|
|
219
|
+
static create(what: string, candidates: string[], context?: Record<string, unknown>): AmbiguousError;
|
|
166
220
|
exitCode(): number;
|
|
167
221
|
statusCode(): number;
|
|
168
222
|
}
|
|
@@ -202,23 +256,76 @@ declare class AssertionError extends AssertionErrorBase {
|
|
|
202
256
|
* @example
|
|
203
257
|
* ```typescript
|
|
204
258
|
* new NotFoundError({ message: "note not found: abc123", resourceType: "note", resourceId: "abc123" });
|
|
259
|
+
* new NotFoundError({
|
|
260
|
+
* message: "Heading not found",
|
|
261
|
+
* resourceType: "heading",
|
|
262
|
+
* resourceId: "h:Intro",
|
|
263
|
+
* context: { availableHeadings: ["Introduction", "Getting Started"] },
|
|
264
|
+
* });
|
|
205
265
|
* ```
|
|
206
266
|
*/
|
|
207
267
|
declare class NotFoundError extends NotFoundErrorBase {
|
|
208
268
|
readonly category: "not_found";
|
|
269
|
+
/** Create a NotFoundError with auto-generated message. */
|
|
270
|
+
static create(resourceType: string, resourceId: string, context?: Record<string, unknown>): NotFoundError;
|
|
209
271
|
exitCode(): number;
|
|
210
272
|
statusCode(): number;
|
|
211
273
|
}
|
|
212
274
|
/**
|
|
213
|
-
*
|
|
275
|
+
* Resource already exists — the inverse of {@link NotFoundError}.
|
|
276
|
+
*
|
|
277
|
+
* Use when a create/write operation fails because the target resource
|
|
278
|
+
* is already present. Carries `resourceType` and `resourceId` to identify
|
|
279
|
+
* what already exists, mirroring {@link NotFoundError}'s structure.
|
|
280
|
+
*
|
|
281
|
+
* Maps to HTTP 409 (Conflict) and exit code 3.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```typescript
|
|
285
|
+
* new AlreadyExistsError({
|
|
286
|
+
* message: "File already exists: notes/meeting.md",
|
|
287
|
+
* resourceType: "file",
|
|
288
|
+
* resourceId: "notes/meeting.md",
|
|
289
|
+
* });
|
|
290
|
+
* AlreadyExistsError.create("file", "notes/meeting.md");
|
|
291
|
+
* ```
|
|
292
|
+
*
|
|
293
|
+
* @see ConflictError - For general state conflicts (version mismatch, concurrent modification)
|
|
294
|
+
* @see NotFoundError - The inverse: resource does not exist
|
|
295
|
+
*/
|
|
296
|
+
declare class AlreadyExistsError extends AlreadyExistsErrorBase {
|
|
297
|
+
readonly category: "conflict";
|
|
298
|
+
/** Create an AlreadyExistsError with auto-generated message. */
|
|
299
|
+
static create(resourceType: string, resourceId: string, context?: Record<string, unknown>): AlreadyExistsError;
|
|
300
|
+
exitCode(): number;
|
|
301
|
+
statusCode(): number;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* State conflict (version mismatch, concurrent modification).
|
|
305
|
+
*
|
|
306
|
+
* Use for general conflicts that don't fit {@link AlreadyExistsError}:
|
|
307
|
+
* optimistic locking failures, concurrent writes, ETag mismatches,
|
|
308
|
+
* or any case where the operation can't proceed due to state divergence.
|
|
309
|
+
*
|
|
310
|
+
* Maps to HTTP 409 (Conflict) and exit code 3.
|
|
311
|
+
*
|
|
312
|
+
* **Choosing the right conflict error:**
|
|
313
|
+
* - Resource already exists? Use {@link AlreadyExistsError}
|
|
314
|
+
* - Version/ETag mismatch? Use {@link ConflictError}
|
|
315
|
+
* - Concurrent modification detected? Use {@link ConflictError}
|
|
214
316
|
*
|
|
215
317
|
* @example
|
|
216
318
|
* ```typescript
|
|
217
319
|
* new ConflictError({ message: "Resource was modified by another process" });
|
|
320
|
+
* ConflictError.create("ETag mismatch: expected abc, got def");
|
|
218
321
|
* ```
|
|
322
|
+
*
|
|
323
|
+
* @see AlreadyExistsError - For "resource already exists" specifically
|
|
219
324
|
*/
|
|
220
325
|
declare class ConflictError extends ConflictErrorBase {
|
|
221
326
|
readonly category: "conflict";
|
|
327
|
+
/** Create a ConflictError with optional context. */
|
|
328
|
+
static create(message: string, context?: Record<string, unknown>): ConflictError;
|
|
222
329
|
exitCode(): number;
|
|
223
330
|
statusCode(): number;
|
|
224
331
|
}
|
|
@@ -232,6 +339,8 @@ declare class ConflictError extends ConflictErrorBase {
|
|
|
232
339
|
*/
|
|
233
340
|
declare class PermissionError extends PermissionErrorBase {
|
|
234
341
|
readonly category: "permission";
|
|
342
|
+
/** Create a PermissionError with optional context. */
|
|
343
|
+
static create(message: string, context?: Record<string, unknown>): PermissionError;
|
|
235
344
|
exitCode(): number;
|
|
236
345
|
statusCode(): number;
|
|
237
346
|
}
|
|
@@ -245,6 +354,8 @@ declare class PermissionError extends PermissionErrorBase {
|
|
|
245
354
|
*/
|
|
246
355
|
declare class TimeoutError extends TimeoutErrorBase {
|
|
247
356
|
readonly category: "timeout";
|
|
357
|
+
/** Create a TimeoutError with auto-generated message. */
|
|
358
|
+
static create(operation: string, timeoutMs: number): TimeoutError;
|
|
248
359
|
exitCode(): number;
|
|
249
360
|
statusCode(): number;
|
|
250
361
|
}
|
|
@@ -258,6 +369,8 @@ declare class TimeoutError extends TimeoutErrorBase {
|
|
|
258
369
|
*/
|
|
259
370
|
declare class RateLimitError extends RateLimitErrorBase {
|
|
260
371
|
readonly category: "rate_limit";
|
|
372
|
+
/** Create a RateLimitError with optional retry hint. */
|
|
373
|
+
static create(message: string, retryAfterSeconds?: number): RateLimitError;
|
|
261
374
|
exitCode(): number;
|
|
262
375
|
statusCode(): number;
|
|
263
376
|
}
|
|
@@ -271,6 +384,8 @@ declare class RateLimitError extends RateLimitErrorBase {
|
|
|
271
384
|
*/
|
|
272
385
|
declare class NetworkError extends NetworkErrorBase {
|
|
273
386
|
readonly category: "network";
|
|
387
|
+
/** Create a NetworkError with optional context. */
|
|
388
|
+
static create(message: string, context?: Record<string, unknown>): NetworkError;
|
|
274
389
|
exitCode(): number;
|
|
275
390
|
statusCode(): number;
|
|
276
391
|
}
|
|
@@ -284,6 +399,8 @@ declare class NetworkError extends NetworkErrorBase {
|
|
|
284
399
|
*/
|
|
285
400
|
declare class InternalError extends InternalErrorBase {
|
|
286
401
|
readonly category: "internal";
|
|
402
|
+
/** Create an InternalError with optional context. */
|
|
403
|
+
static create(message: string, context?: Record<string, unknown>): InternalError;
|
|
287
404
|
exitCode(): number;
|
|
288
405
|
statusCode(): number;
|
|
289
406
|
}
|
|
@@ -297,6 +414,8 @@ declare class InternalError extends InternalErrorBase {
|
|
|
297
414
|
*/
|
|
298
415
|
declare class AuthError extends AuthErrorBase {
|
|
299
416
|
readonly category: "auth";
|
|
417
|
+
/** Create an AuthError with optional reason. */
|
|
418
|
+
static create(message: string, reason?: "missing" | "invalid" | "expired"): AuthError;
|
|
300
419
|
exitCode(): number;
|
|
301
420
|
statusCode(): number;
|
|
302
421
|
}
|
|
@@ -310,16 +429,18 @@ declare class AuthError extends AuthErrorBase {
|
|
|
310
429
|
*/
|
|
311
430
|
declare class CancelledError extends CancelledErrorBase {
|
|
312
431
|
readonly category: "cancelled";
|
|
432
|
+
/** Create a CancelledError. */
|
|
433
|
+
static create(message: string): CancelledError;
|
|
313
434
|
exitCode(): number;
|
|
314
435
|
statusCode(): number;
|
|
315
436
|
}
|
|
316
437
|
/**
|
|
317
438
|
* Union type of all concrete error class instances.
|
|
318
439
|
*/
|
|
319
|
-
type AnyKitError = InstanceType<typeof ValidationError> | InstanceType<typeof AssertionError> | InstanceType<typeof NotFoundError> | InstanceType<typeof ConflictError> | InstanceType<typeof PermissionError> | InstanceType<typeof TimeoutError> | InstanceType<typeof RateLimitError> | InstanceType<typeof NetworkError> | InstanceType<typeof InternalError> | InstanceType<typeof AuthError> | InstanceType<typeof CancelledError>;
|
|
440
|
+
type AnyKitError = 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>;
|
|
320
441
|
/**
|
|
321
442
|
* Type alias for backwards compatibility with handler signatures.
|
|
322
443
|
* Use AnyKitError for the union type.
|
|
323
444
|
*/
|
|
324
445
|
type OutfitterError = AnyKitError;
|
|
325
|
-
export { ErrorCategory, exitCodeMap, statusCodeMap, ERROR_CODES, ErrorCode, SerializedError, KitErrorProps, getExitCode, getStatusCode, ValidationError, AssertionError, NotFoundError, ConflictError, PermissionError, TimeoutError, RateLimitError, NetworkError, InternalError, AuthError, CancelledError, AnyKitError, OutfitterError };
|
|
446
|
+
export { ErrorCategory, exitCodeMap, statusCodeMap, ERROR_CODES, ErrorCode, SerializedError, KitErrorProps, getExitCode, getStatusCode, ValidationError, AmbiguousError, AssertionError, NotFoundError, AlreadyExistsError, ConflictError, PermissionError, TimeoutError, RateLimitError, NetworkError, InternalError, AuthError, CancelledError, AnyKitError, OutfitterError };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Handler, SyncHandler } from "./contracts-
|
|
2
|
-
import { OutfitterError } from "./contracts-
|
|
1
|
+
import { Handler, SyncHandler } from "./contracts-ss9vjjft";
|
|
2
|
+
import { OutfitterError } from "./contracts-r35bn9p6";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
declare const ACTION_SURFACES: readonly ["cli", "mcp", "api", "server"];
|
|
5
5
|
type ActionSurface = (typeof ACTION_SURFACES)[number];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @bun
|
|
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
|
+
}
|
|
13
|
+
|
|
14
|
+
export { createLoggerFactory };
|