@ontrails/core 1.0.0-beta.2 → 1.0.0-beta.21

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.
Files changed (245) hide show
  1. package/CHANGELOG.md +283 -5
  2. package/README.md +113 -33
  3. package/package.json +11 -1
  4. package/src/activation-provenance.ts +111 -0
  5. package/src/activation-source-compatibility.ts +430 -0
  6. package/src/activation-source-projection.ts +221 -0
  7. package/src/activation-source.ts +91 -0
  8. package/src/blob-ref.ts +51 -0
  9. package/src/branded.ts +1 -1
  10. package/src/compose-batch.ts +69 -0
  11. package/src/compose-schema.ts +36 -0
  12. package/src/context.ts +44 -10
  13. package/src/contour.ts +346 -0
  14. package/src/derive.ts +59 -18
  15. package/src/detours.ts +8 -0
  16. package/src/draft.ts +342 -0
  17. package/src/error-projection.ts +51 -0
  18. package/src/errors.ts +309 -48
  19. package/src/execute.ts +1577 -0
  20. package/src/fire.ts +1169 -0
  21. package/src/index.ts +477 -32
  22. package/src/internal/fork-ctx.ts +69 -0
  23. package/src/layer-projection.ts +193 -0
  24. package/src/layer.ts +43 -6
  25. package/src/observe.ts +361 -0
  26. package/src/path-security.ts +1 -1
  27. package/src/permits.ts +12 -0
  28. package/src/redaction/patterns.ts +6 -3
  29. package/src/resilience.ts +11 -11
  30. package/src/resource-config.ts +792 -0
  31. package/src/resource.ts +194 -0
  32. package/src/result.ts +36 -4
  33. package/src/run.ts +76 -0
  34. package/src/schedule-runtime.ts +689 -0
  35. package/src/schedule.ts +326 -0
  36. package/src/serialization.ts +119 -39
  37. package/src/signal-diagnostics.ts +633 -0
  38. package/src/signal-ref.ts +87 -0
  39. package/src/signal.ts +104 -0
  40. package/src/store/accessor-protocol.ts +56 -0
  41. package/src/store/index.ts +4 -0
  42. package/src/structured-examples.ts +248 -0
  43. package/src/surface-derivation.ts +91 -0
  44. package/src/surface-filter.ts +176 -0
  45. package/src/surface-versioning.ts +42 -0
  46. package/src/topo.ts +769 -57
  47. package/src/tracing.ts +345 -0
  48. package/src/trail.ts +1161 -29
  49. package/src/trails/derive-trail.ts +842 -0
  50. package/src/trails/index.ts +9 -0
  51. package/src/trails/ingest.ts +139 -0
  52. package/src/trails-db.ts +208 -0
  53. package/src/transport-error-map.ts +174 -0
  54. package/src/type-utils.ts +87 -0
  55. package/src/types.ts +254 -12
  56. package/src/validate-established-topo.ts +69 -0
  57. package/src/validate-topo.ts +442 -35
  58. package/src/validation.ts +152 -4
  59. package/src/version-marker.ts +716 -0
  60. package/src/version-resolution.ts +308 -0
  61. package/src/version-runtime.ts +120 -0
  62. package/src/webhook.ts +278 -0
  63. package/src/workspace.ts +1 -1
  64. package/src/zod-wrappers.ts +72 -0
  65. package/.turbo/turbo-build.log +0 -1
  66. package/.turbo/turbo-lint.log +0 -3
  67. package/.turbo/turbo-typecheck.log +0 -1
  68. package/dist/adapters.d.ts +0 -39
  69. package/dist/adapters.d.ts.map +0 -1
  70. package/dist/adapters.js +0 -2
  71. package/dist/adapters.js.map +0 -1
  72. package/dist/blob-ref.d.ts +0 -20
  73. package/dist/blob-ref.d.ts.map +0 -1
  74. package/dist/blob-ref.js +0 -22
  75. package/dist/blob-ref.js.map +0 -1
  76. package/dist/branded.d.ts +0 -36
  77. package/dist/branded.d.ts.map +0 -1
  78. package/dist/branded.js +0 -89
  79. package/dist/branded.js.map +0 -1
  80. package/dist/collections.d.ts +0 -31
  81. package/dist/collections.d.ts.map +0 -1
  82. package/dist/collections.js +0 -60
  83. package/dist/collections.js.map +0 -1
  84. package/dist/context.d.ts +0 -10
  85. package/dist/context.d.ts.map +0 -1
  86. package/dist/context.js +0 -15
  87. package/dist/context.js.map +0 -1
  88. package/dist/derive.d.ts +0 -33
  89. package/dist/derive.d.ts.map +0 -1
  90. package/dist/derive.js +0 -122
  91. package/dist/derive.js.map +0 -1
  92. package/dist/errors.d.ts +0 -83
  93. package/dist/errors.d.ts.map +0 -1
  94. package/dist/errors.js +0 -142
  95. package/dist/errors.js.map +0 -1
  96. package/dist/event.d.ts +0 -45
  97. package/dist/event.d.ts.map +0 -1
  98. package/dist/event.js +0 -17
  99. package/dist/event.js.map +0 -1
  100. package/dist/fetch.d.ts +0 -15
  101. package/dist/fetch.d.ts.map +0 -1
  102. package/dist/fetch.js +0 -102
  103. package/dist/fetch.js.map +0 -1
  104. package/dist/guards.d.ts +0 -17
  105. package/dist/guards.d.ts.map +0 -1
  106. package/dist/guards.js +0 -25
  107. package/dist/guards.js.map +0 -1
  108. package/dist/health.d.ts +0 -18
  109. package/dist/health.d.ts.map +0 -1
  110. package/dist/health.js +0 -5
  111. package/dist/health.js.map +0 -1
  112. package/dist/hike.d.ts +0 -36
  113. package/dist/hike.d.ts.map +0 -1
  114. package/dist/hike.js +0 -20
  115. package/dist/hike.js.map +0 -1
  116. package/dist/index.d.ts +0 -34
  117. package/dist/index.d.ts.map +0 -1
  118. package/dist/index.js +0 -38
  119. package/dist/index.js.map +0 -1
  120. package/dist/job.d.ts +0 -24
  121. package/dist/job.d.ts.map +0 -1
  122. package/dist/job.js +0 -17
  123. package/dist/job.js.map +0 -1
  124. package/dist/layer.d.ts +0 -17
  125. package/dist/layer.d.ts.map +0 -1
  126. package/dist/layer.js +0 -21
  127. package/dist/layer.js.map +0 -1
  128. package/dist/path-security.d.ts +0 -28
  129. package/dist/path-security.d.ts.map +0 -1
  130. package/dist/path-security.js +0 -63
  131. package/dist/path-security.js.map +0 -1
  132. package/dist/patterns/bulk.d.ts +0 -15
  133. package/dist/patterns/bulk.d.ts.map +0 -1
  134. package/dist/patterns/bulk.js +0 -14
  135. package/dist/patterns/bulk.js.map +0 -1
  136. package/dist/patterns/change.d.ts +0 -10
  137. package/dist/patterns/change.d.ts.map +0 -1
  138. package/dist/patterns/change.js +0 -10
  139. package/dist/patterns/change.js.map +0 -1
  140. package/dist/patterns/date-range.d.ts +0 -10
  141. package/dist/patterns/date-range.d.ts.map +0 -1
  142. package/dist/patterns/date-range.js +0 -10
  143. package/dist/patterns/date-range.js.map +0 -1
  144. package/dist/patterns/index.d.ts +0 -9
  145. package/dist/patterns/index.d.ts.map +0 -1
  146. package/dist/patterns/index.js +0 -9
  147. package/dist/patterns/index.js.map +0 -1
  148. package/dist/patterns/pagination.d.ts +0 -18
  149. package/dist/patterns/pagination.d.ts.map +0 -1
  150. package/dist/patterns/pagination.js +0 -18
  151. package/dist/patterns/pagination.js.map +0 -1
  152. package/dist/patterns/progress.d.ts +0 -11
  153. package/dist/patterns/progress.d.ts.map +0 -1
  154. package/dist/patterns/progress.js +0 -11
  155. package/dist/patterns/progress.js.map +0 -1
  156. package/dist/patterns/sorting.d.ts +0 -13
  157. package/dist/patterns/sorting.d.ts.map +0 -1
  158. package/dist/patterns/sorting.js +0 -10
  159. package/dist/patterns/sorting.js.map +0 -1
  160. package/dist/patterns/status.d.ts +0 -15
  161. package/dist/patterns/status.d.ts.map +0 -1
  162. package/dist/patterns/status.js +0 -9
  163. package/dist/patterns/status.js.map +0 -1
  164. package/dist/patterns/timestamps.d.ts +0 -10
  165. package/dist/patterns/timestamps.d.ts.map +0 -1
  166. package/dist/patterns/timestamps.js +0 -10
  167. package/dist/patterns/timestamps.js.map +0 -1
  168. package/dist/redaction/index.d.ts +0 -4
  169. package/dist/redaction/index.d.ts.map +0 -1
  170. package/dist/redaction/index.js +0 -3
  171. package/dist/redaction/index.js.map +0 -1
  172. package/dist/redaction/patterns.d.ts +0 -9
  173. package/dist/redaction/patterns.d.ts.map +0 -1
  174. package/dist/redaction/patterns.js +0 -39
  175. package/dist/redaction/patterns.js.map +0 -1
  176. package/dist/redaction/redactor.d.ts +0 -27
  177. package/dist/redaction/redactor.d.ts.map +0 -1
  178. package/dist/redaction/redactor.js +0 -89
  179. package/dist/redaction/redactor.js.map +0 -1
  180. package/dist/resilience.d.ts +0 -34
  181. package/dist/resilience.d.ts.map +0 -1
  182. package/dist/resilience.js +0 -164
  183. package/dist/resilience.js.map +0 -1
  184. package/dist/result.d.ts +0 -57
  185. package/dist/result.d.ts.map +0 -1
  186. package/dist/result.js +0 -145
  187. package/dist/result.js.map +0 -1
  188. package/dist/serialization.d.ts +0 -27
  189. package/dist/serialization.d.ts.map +0 -1
  190. package/dist/serialization.js +0 -115
  191. package/dist/serialization.js.map +0 -1
  192. package/dist/topo.d.ts +0 -18
  193. package/dist/topo.d.ts.map +0 -1
  194. package/dist/topo.js +0 -74
  195. package/dist/topo.js.map +0 -1
  196. package/dist/trail.d.ts +0 -83
  197. package/dist/trail.d.ts.map +0 -1
  198. package/dist/trail.js +0 -16
  199. package/dist/trail.js.map +0 -1
  200. package/dist/types.d.ts +0 -46
  201. package/dist/types.d.ts.map +0 -1
  202. package/dist/types.js +0 -2
  203. package/dist/types.js.map +0 -1
  204. package/dist/validate-topo.d.ts +0 -24
  205. package/dist/validate-topo.d.ts.map +0 -1
  206. package/dist/validate-topo.js +0 -108
  207. package/dist/validate-topo.js.map +0 -1
  208. package/dist/validation.d.ts +0 -27
  209. package/dist/validation.d.ts.map +0 -1
  210. package/dist/validation.js +0 -134
  211. package/dist/validation.js.map +0 -1
  212. package/dist/workspace.d.ts +0 -25
  213. package/dist/workspace.d.ts.map +0 -1
  214. package/dist/workspace.js +0 -57
  215. package/dist/workspace.js.map +0 -1
  216. package/src/__tests__/blob-ref.test.ts +0 -103
  217. package/src/__tests__/branded.test.ts +0 -148
  218. package/src/__tests__/collections.test.ts +0 -126
  219. package/src/__tests__/context.test.ts +0 -66
  220. package/src/__tests__/derive.test.ts +0 -159
  221. package/src/__tests__/errors.test.ts +0 -309
  222. package/src/__tests__/event.test.ts +0 -82
  223. package/src/__tests__/fetch.test.ts +0 -217
  224. package/src/__tests__/guards.test.ts +0 -102
  225. package/src/__tests__/hike.test.ts +0 -117
  226. package/src/__tests__/job.test.ts +0 -98
  227. package/src/__tests__/layer.test.ts +0 -224
  228. package/src/__tests__/path-security.test.ts +0 -114
  229. package/src/__tests__/patterns.test.ts +0 -273
  230. package/src/__tests__/redaction.test.ts +0 -244
  231. package/src/__tests__/resilience.test.ts +0 -246
  232. package/src/__tests__/result.test.ts +0 -155
  233. package/src/__tests__/serialization.test.ts +0 -236
  234. package/src/__tests__/topo.test.ts +0 -184
  235. package/src/__tests__/trail.test.ts +0 -179
  236. package/src/__tests__/validate-topo.test.ts +0 -201
  237. package/src/__tests__/validation.test.ts +0 -283
  238. package/src/__tests__/workspace.test.ts +0 -183
  239. package/src/adapters.ts +0 -68
  240. package/src/event.ts +0 -77
  241. package/src/health.ts +0 -23
  242. package/src/hike.ts +0 -77
  243. package/src/job.ts +0 -20
  244. package/tsconfig.json +0 -9
  245. package/tsconfig.tsbuildinfo +0 -1
package/src/errors.ts CHANGED
@@ -10,17 +10,20 @@
10
10
  // Category
11
11
  // ---------------------------------------------------------------------------
12
12
 
13
- export type ErrorCategory =
14
- | 'validation'
15
- | 'not_found'
16
- | 'conflict'
17
- | 'permission'
18
- | 'timeout'
19
- | 'rate_limit'
20
- | 'network'
21
- | 'internal'
22
- | 'auth'
23
- | 'cancelled';
13
+ export const errorCategories = [
14
+ 'validation',
15
+ 'not_found',
16
+ 'conflict',
17
+ 'permission',
18
+ 'timeout',
19
+ 'rate_limit',
20
+ 'network',
21
+ 'internal',
22
+ 'auth',
23
+ 'cancelled',
24
+ ] as const;
25
+
26
+ export type ErrorCategory = (typeof errorCategories)[number];
24
27
 
25
28
  // ---------------------------------------------------------------------------
26
29
  // Base class
@@ -65,6 +68,64 @@ export class NotFoundError extends TrailsError {
65
68
  readonly retryable = false as const;
66
69
  }
67
70
 
71
+ export class VersionNotSupportedError extends NotFoundError {
72
+ readonly reason?: string | undefined;
73
+ readonly requested?: number | string | undefined;
74
+ readonly supported?: readonly number[] | undefined;
75
+ readonly trailId?: string | undefined;
76
+
77
+ constructor(
78
+ message: string,
79
+ options?: { cause?: Error; context?: Record<string, unknown> }
80
+ );
81
+ constructor(
82
+ trailId: string,
83
+ requested: number | string,
84
+ supported: readonly number[],
85
+ reason?: string | undefined
86
+ );
87
+ constructor(
88
+ messageOrTrailId: string,
89
+ optionsOrRequested?:
90
+ | { cause?: Error; context?: Record<string, unknown> }
91
+ | number
92
+ | string,
93
+ supported?: readonly number[],
94
+ reason?: string | undefined
95
+ ) {
96
+ if (supported === undefined) {
97
+ super(
98
+ messageOrTrailId,
99
+ optionsOrRequested as
100
+ | { cause?: Error; context?: Record<string, unknown> }
101
+ | undefined
102
+ );
103
+ this.name = 'VersionNotSupportedError';
104
+ return;
105
+ }
106
+
107
+ const requested = optionsOrRequested as number | string;
108
+ const supportedLabel =
109
+ supported.length === 0 ? 'none' : supported.join(', ');
110
+ super(
111
+ `Trail "${messageOrTrailId}" version ${String(requested)} is not supported (supported: ${supportedLabel})`,
112
+ {
113
+ context: {
114
+ ...(reason === undefined ? {} : { reason }),
115
+ requested,
116
+ supported,
117
+ trailId: messageOrTrailId,
118
+ },
119
+ }
120
+ );
121
+ this.name = 'VersionNotSupportedError';
122
+ this.reason = reason;
123
+ this.requested = requested;
124
+ this.supported = supported;
125
+ this.trailId = messageOrTrailId;
126
+ }
127
+ }
128
+
68
129
  export class AlreadyExistsError extends TrailsError {
69
130
  readonly category = 'conflict' as const;
70
131
  readonly retryable = false as const;
@@ -80,6 +141,16 @@ export class PermissionError extends TrailsError {
80
141
  readonly retryable = false as const;
81
142
  }
82
143
 
144
+ export class PermitError extends PermissionError {
145
+ constructor(
146
+ message: string,
147
+ options?: { cause?: Error; context?: Record<string, unknown> }
148
+ ) {
149
+ super(message, options);
150
+ this.name = 'PermitError';
151
+ }
152
+ }
153
+
83
154
  export class TimeoutError extends TrailsError {
84
155
  readonly category = 'timeout' as const;
85
156
  readonly retryable = true as const;
@@ -109,10 +180,17 @@ export class NetworkError extends TrailsError {
109
180
  }
110
181
 
111
182
  export class InternalError extends TrailsError {
183
+ readonly category: ErrorCategory = 'internal';
184
+ readonly retryable = false as const;
185
+ }
186
+
187
+ export class DerivationError extends TrailsError {
112
188
  readonly category = 'internal' as const;
113
189
  readonly retryable = false as const;
114
190
  }
115
191
 
192
+ export class RecoverableCompletionError extends InternalError {}
193
+
116
194
  export class AuthError extends TrailsError {
117
195
  readonly category = 'auth' as const;
118
196
  readonly retryable = false as const;
@@ -123,48 +201,231 @@ export class CancelledError extends TrailsError {
123
201
  readonly retryable = false as const;
124
202
  }
125
203
 
204
+ /**
205
+ * Returned when a detour exhausts all recovery attempts.
206
+ *
207
+ * Inherits the wrapped error's category for surface mapping (e.g. a
208
+ * `RetryExhaustedError<ConflictError>` maps to HTTP 409), but always
209
+ * sets `retryable = false` to prevent amplification across `ctx.compose()`
210
+ * boundaries or stacked layers.
211
+ */
212
+ export class RetryExhaustedError<
213
+ TErr extends TrailsError = TrailsError,
214
+ > extends InternalError {
215
+ readonly category: ErrorCategory;
216
+ readonly cause: TErr;
217
+
218
+ /** Number of recovery attempts made before exhaustion. */
219
+ readonly attempts: number;
220
+
221
+ /** Name of the detour whose recovery was exhausted. */
222
+ readonly detour: string;
223
+
224
+ constructor(
225
+ wrapped: TErr,
226
+ metadata: { readonly attempts: number; readonly detour: string }
227
+ ) {
228
+ super(
229
+ `Recovery exhausted after ${metadata.attempts} attempts: ${wrapped.message}`,
230
+ { cause: wrapped }
231
+ );
232
+ this.cause = wrapped;
233
+ this.attempts = metadata.attempts;
234
+ this.detour = metadata.detour;
235
+ // Dynamic — inherited from wrapped error at construction time.
236
+ this.category = wrapped.category;
237
+ }
238
+ }
239
+
240
+ // ---------------------------------------------------------------------------
241
+ // Class registry
242
+ // ---------------------------------------------------------------------------
243
+
244
+ export type ErrorClassConstructor = new (...args: never[]) => TrailsError;
245
+
246
+ export interface FixedErrorClassRegistryEntry {
247
+ readonly category: ErrorCategory;
248
+ readonly ctor: ErrorClassConstructor;
249
+ readonly name: string;
250
+ readonly retryable: boolean;
251
+ }
252
+
253
+ export interface DynamicErrorClassRegistryEntry {
254
+ readonly category: 'dynamic';
255
+ readonly ctor: ErrorClassConstructor;
256
+ readonly inheritsCategoryFrom: 'wrapped-error';
257
+ readonly name: string;
258
+ readonly retryable: false;
259
+ }
260
+
261
+ export type ErrorClassRegistryEntry =
262
+ | DynamicErrorClassRegistryEntry
263
+ | FixedErrorClassRegistryEntry;
264
+
265
+ /**
266
+ * Authored registry of concrete TrailsError classes.
267
+ *
268
+ * JavaScript cannot enumerate subclasses at runtime, so rule and projection
269
+ * tooling should walk this owner-held list instead of hardcoding parallel
270
+ * class-name tables. `RetryExhaustedError` is marked dynamic because it
271
+ * inherits its runtime category from the wrapped error rather than always
272
+ * mapping as `internal`.
273
+ */
274
+ export const errorClasses = [
275
+ {
276
+ category: 'validation',
277
+ ctor: ValidationError,
278
+ name: 'ValidationError',
279
+ retryable: false,
280
+ },
281
+ {
282
+ category: 'validation',
283
+ ctor: AmbiguousError,
284
+ name: 'AmbiguousError',
285
+ retryable: false,
286
+ },
287
+ {
288
+ category: 'internal',
289
+ ctor: AssertionError,
290
+ name: 'AssertionError',
291
+ retryable: false,
292
+ },
293
+ {
294
+ category: 'not_found',
295
+ ctor: NotFoundError,
296
+ name: 'NotFoundError',
297
+ retryable: false,
298
+ },
299
+ {
300
+ category: 'not_found',
301
+ ctor: VersionNotSupportedError,
302
+ name: 'VersionNotSupportedError',
303
+ retryable: false,
304
+ },
305
+ {
306
+ category: 'conflict',
307
+ ctor: AlreadyExistsError,
308
+ name: 'AlreadyExistsError',
309
+ retryable: false,
310
+ },
311
+ {
312
+ category: 'conflict',
313
+ ctor: ConflictError,
314
+ name: 'ConflictError',
315
+ retryable: false,
316
+ },
317
+ {
318
+ category: 'permission',
319
+ ctor: PermissionError,
320
+ name: 'PermissionError',
321
+ retryable: false,
322
+ },
323
+ {
324
+ category: 'permission',
325
+ ctor: PermitError,
326
+ name: 'PermitError',
327
+ retryable: false,
328
+ },
329
+ {
330
+ category: 'timeout',
331
+ ctor: TimeoutError,
332
+ name: 'TimeoutError',
333
+ retryable: true,
334
+ },
335
+ {
336
+ category: 'rate_limit',
337
+ ctor: RateLimitError,
338
+ name: 'RateLimitError',
339
+ retryable: true,
340
+ },
341
+ {
342
+ category: 'network',
343
+ ctor: NetworkError,
344
+ name: 'NetworkError',
345
+ retryable: true,
346
+ },
347
+ {
348
+ category: 'internal',
349
+ ctor: InternalError,
350
+ name: 'InternalError',
351
+ retryable: false,
352
+ },
353
+ {
354
+ category: 'internal',
355
+ ctor: DerivationError,
356
+ name: 'DerivationError',
357
+ retryable: false,
358
+ },
359
+ {
360
+ category: 'internal',
361
+ ctor: RecoverableCompletionError,
362
+ name: 'RecoverableCompletionError',
363
+ retryable: false,
364
+ },
365
+ { category: 'auth', ctor: AuthError, name: 'AuthError', retryable: false },
366
+ {
367
+ category: 'cancelled',
368
+ ctor: CancelledError,
369
+ name: 'CancelledError',
370
+ retryable: false,
371
+ },
372
+ {
373
+ category: 'dynamic',
374
+ ctor: RetryExhaustedError,
375
+ inheritsCategoryFrom: 'wrapped-error',
376
+ name: 'RetryExhaustedError',
377
+ retryable: false,
378
+ },
379
+ ] as const satisfies readonly ErrorClassRegistryEntry[];
380
+
126
381
  // ---------------------------------------------------------------------------
127
382
  // Taxonomy maps
128
383
  // ---------------------------------------------------------------------------
129
384
 
130
- export const exitCodeMap: Record<ErrorCategory, number> = {
131
- auth: 9,
132
- cancelled: 130,
133
- conflict: 3,
134
- internal: 8,
135
- network: 7,
136
- not_found: 2,
137
- permission: 4,
138
- rate_limit: 6,
139
- timeout: 5,
140
- validation: 1,
141
- } as const;
385
+ export interface ErrorCategoryCodes {
386
+ readonly exit: number;
387
+ readonly http: number;
388
+ readonly jsonRpc: number;
389
+ }
142
390
 
143
- export const statusCodeMap: Record<ErrorCategory, number> = {
144
- auth: 401,
145
- cancelled: 499,
146
- conflict: 409,
147
- internal: 500,
148
- network: 502,
149
- not_found: 404,
150
- permission: 403,
151
- rate_limit: 429,
152
- timeout: 504,
153
- validation: 400,
154
- } as const;
391
+ export const codesByCategory = {
392
+ auth: { exit: 9, http: 401, jsonRpc: -32_600 },
393
+ cancelled: { exit: 130, http: 499, jsonRpc: -32_603 },
394
+ conflict: { exit: 3, http: 409, jsonRpc: -32_603 },
395
+ internal: { exit: 8, http: 500, jsonRpc: -32_603 },
396
+ network: { exit: 7, http: 502, jsonRpc: -32_603 },
397
+ not_found: { exit: 2, http: 404, jsonRpc: -32_601 },
398
+ permission: { exit: 4, http: 403, jsonRpc: -32_600 },
399
+ rate_limit: { exit: 6, http: 429, jsonRpc: -32_603 },
400
+ timeout: { exit: 5, http: 504, jsonRpc: -32_603 },
401
+ validation: { exit: 1, http: 400, jsonRpc: -32_602 },
402
+ } as const satisfies Record<ErrorCategory, ErrorCategoryCodes>;
155
403
 
156
- export const jsonRpcCodeMap: Record<ErrorCategory, number> = {
157
- auth: -32_600,
158
- cancelled: -32_603,
159
- conflict: -32_603,
160
- internal: -32_603,
161
- network: -32_603,
162
- not_found: -32_601,
163
- permission: -32_600,
164
- rate_limit: -32_603,
165
- timeout: -32_603,
166
- validation: -32_602,
167
- } as const;
404
+ const deriveCodeMap = <TCode extends keyof ErrorCategoryCodes>(
405
+ code: TCode
406
+ ): {
407
+ readonly [TCategory in ErrorCategory]: (typeof codesByCategory)[TCategory][TCode];
408
+ } => ({
409
+ auth: codesByCategory.auth[code],
410
+ cancelled: codesByCategory.cancelled[code],
411
+ conflict: codesByCategory.conflict[code],
412
+ internal: codesByCategory.internal[code],
413
+ network: codesByCategory.network[code],
414
+ not_found: codesByCategory.not_found[code],
415
+ permission: codesByCategory.permission[code],
416
+ rate_limit: codesByCategory.rate_limit[code],
417
+ timeout: codesByCategory.timeout[code],
418
+ validation: codesByCategory.validation[code],
419
+ });
420
+
421
+ /** @deprecated Prefer `codesByCategory[category].exit`. */
422
+ export const exitCodeMap = deriveCodeMap('exit');
423
+
424
+ /** @deprecated Prefer `codesByCategory[category].http`. */
425
+ export const statusCodeMap = deriveCodeMap('http');
426
+
427
+ /** @deprecated Prefer `codesByCategory[category].jsonRpc`. */
428
+ export const jsonRpcCodeMap = deriveCodeMap('jsonRpc');
168
429
 
169
430
  export const retryableMap: Record<ErrorCategory, boolean> = {
170
431
  auth: false,
@@ -190,7 +451,7 @@ export const isTrailsError = (error?: unknown): error is TrailsError =>
190
451
  /** Returns true if the error is retryable (TrailsError with retryable category). */
191
452
  export const isRetryable = (error: Error): boolean => {
192
453
  if (isTrailsError(error)) {
193
- return retryableMap[error.category];
454
+ return error.retryable;
194
455
  }
195
456
  return false;
196
457
  };