@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
@@ -1,159 +0,0 @@
1
- import { describe, test, expect } from 'bun:test';
2
-
3
- import { z } from 'zod';
4
-
5
- import { deriveFields } from '../derive.js';
6
-
7
- // ---------------------------------------------------------------------------
8
- // Tests
9
- // ---------------------------------------------------------------------------
10
-
11
- describe('derive', () => {
12
- describe('primitive types', () => {
13
- test('z.string() derives string field', () => {
14
- const schema = z.object({ name: z.string() });
15
- const fields = deriveFields(schema);
16
- expect(fields).toHaveLength(1);
17
- expect(fields[0]).toMatchObject({
18
- label: 'Name',
19
- name: 'name',
20
- required: true,
21
- type: 'string',
22
- });
23
- });
24
-
25
- test('z.number() derives number field', () => {
26
- const schema = z.object({ count: z.number() });
27
- const fields = deriveFields(schema);
28
- expect(fields[0]).toMatchObject({
29
- name: 'count',
30
- required: true,
31
- type: 'number',
32
- });
33
- });
34
-
35
- test('z.boolean() derives boolean field', () => {
36
- const schema = z.object({ verbose: z.boolean() });
37
- const fields = deriveFields(schema);
38
- expect(fields[0]).toMatchObject({
39
- name: 'verbose',
40
- required: true,
41
- type: 'boolean',
42
- });
43
- });
44
- });
45
-
46
- describe('enum and multiselect', () => {
47
- test('z.enum() derives enum field with options', () => {
48
- const schema = z.object({ color: z.enum(['red', 'green', 'blue']) });
49
- const fields = deriveFields(schema);
50
- expect(fields[0]).toMatchObject({
51
- name: 'color',
52
- required: true,
53
- type: 'enum',
54
- });
55
- expect(fields[0]?.options).toEqual([
56
- { value: 'red' },
57
- { value: 'green' },
58
- { value: 'blue' },
59
- ]);
60
- });
61
-
62
- test('z.array(z.enum()) derives multiselect field', () => {
63
- const schema = z.object({
64
- tags: z.array(z.enum(['a', 'b', 'c'])),
65
- });
66
- const fields = deriveFields(schema);
67
- expect(fields[0]).toMatchObject({
68
- name: 'tags',
69
- required: true,
70
- type: 'multiselect',
71
- });
72
- expect(fields[0]?.options).toEqual([
73
- { value: 'a' },
74
- { value: 'b' },
75
- { value: 'c' },
76
- ]);
77
- });
78
- });
79
-
80
- describe('modifiers', () => {
81
- test('.describe() sets label', () => {
82
- const schema = z.object({
83
- name: z.string().describe('Your full name'),
84
- });
85
- const fields = deriveFields(schema);
86
- expect(fields[0]?.label).toBe('Your full name');
87
- });
88
-
89
- test('.default() sets default and marks not required', () => {
90
- const schema = z.object({
91
- port: z.number().default(3000),
92
- });
93
- const fields = deriveFields(schema);
94
- expect(fields[0]?.required).toBe(false);
95
- expect(fields[0]?.default).toBe(3000);
96
- });
97
-
98
- test('.optional() marks not required', () => {
99
- const schema = z.object({
100
- nickname: z.string().optional(),
101
- });
102
- const fields = deriveFields(schema);
103
- expect(fields[0]?.required).toBe(false);
104
- });
105
- });
106
-
107
- describe('overrides', () => {
108
- test('override label replaces derived label', () => {
109
- const schema = z.object({
110
- name: z.string().describe('Derived label'),
111
- });
112
- const fields = deriveFields(schema, {
113
- name: { label: 'Override label' },
114
- });
115
- expect(fields[0]?.label).toBe('Override label');
116
- });
117
-
118
- test('override options enrich enum values with labels and hints', () => {
119
- const schema = z.object({
120
- color: z.enum(['red', 'green', 'blue']),
121
- });
122
- const fields = deriveFields(schema, {
123
- color: {
124
- options: [
125
- { hint: 'Hot color', label: 'Red', value: 'red' },
126
- { label: 'Green', value: 'green' },
127
- ],
128
- },
129
- });
130
- expect(fields[0]?.options).toEqual([
131
- { hint: 'Hot color', label: 'Red', value: 'red' },
132
- { label: 'Green', value: 'green' },
133
- { value: 'blue' },
134
- ]);
135
- });
136
- });
137
-
138
- describe('sorting and edge cases', () => {
139
- test('returns fields sorted by name', () => {
140
- const schema = z.object({
141
- alpha: z.string(),
142
- middle: z.string(),
143
- zebra: z.string(),
144
- });
145
- const fields = deriveFields(schema);
146
- expect(fields.map((f) => f.name)).toEqual(['alpha', 'middle', 'zebra']);
147
- });
148
-
149
- test('returns empty array for non-object schema', () => {
150
- expect(deriveFields(z.string())).toEqual([]);
151
- });
152
-
153
- test('humanizes camelCase field names', () => {
154
- const schema = z.object({ firstName: z.string() });
155
- const fields = deriveFields(schema);
156
- expect(fields[0]?.label).toBe('First Name');
157
- });
158
- });
159
- });
@@ -1,309 +0,0 @@
1
- import { describe, test, expect } from 'bun:test';
2
-
3
- import {
4
- TrailsError,
5
- ValidationError,
6
- AmbiguousError,
7
- AssertionError,
8
- NotFoundError,
9
- AlreadyExistsError,
10
- ConflictError,
11
- PermissionError,
12
- TimeoutError,
13
- RateLimitError,
14
- NetworkError,
15
- InternalError,
16
- AuthError,
17
- CancelledError,
18
- exitCodeMap,
19
- statusCodeMap,
20
- jsonRpcCodeMap,
21
- retryableMap,
22
- isRetryable,
23
- isTrailsError,
24
- } from '../errors.js';
25
- import type { ErrorCategory } from '../errors.js';
26
-
27
- // ---------------------------------------------------------------------------
28
- // Error class matrix
29
- // ---------------------------------------------------------------------------
30
-
31
- const errorMatrix: readonly {
32
- Class: new (
33
- message: string,
34
- options?: { cause?: Error; context?: Record<string, unknown> }
35
- ) => TrailsError;
36
- category: ErrorCategory;
37
- retryable: boolean;
38
- name: string;
39
- }[] = [
40
- {
41
- Class: ValidationError,
42
- category: 'validation',
43
- name: 'ValidationError',
44
- retryable: false,
45
- },
46
- {
47
- Class: AmbiguousError,
48
- category: 'validation',
49
- name: 'AmbiguousError',
50
- retryable: false,
51
- },
52
- {
53
- Class: AssertionError,
54
- category: 'internal',
55
- name: 'AssertionError',
56
- retryable: false,
57
- },
58
- {
59
- Class: NotFoundError,
60
- category: 'not_found',
61
- name: 'NotFoundError',
62
- retryable: false,
63
- },
64
- {
65
- Class: AlreadyExistsError,
66
- category: 'conflict',
67
- name: 'AlreadyExistsError',
68
- retryable: false,
69
- },
70
- {
71
- Class: ConflictError,
72
- category: 'conflict',
73
- name: 'ConflictError',
74
- retryable: false,
75
- },
76
- {
77
- Class: PermissionError,
78
- category: 'permission',
79
- name: 'PermissionError',
80
- retryable: false,
81
- },
82
- {
83
- Class: TimeoutError,
84
- category: 'timeout',
85
- name: 'TimeoutError',
86
- retryable: true,
87
- },
88
- {
89
- Class: RateLimitError,
90
- category: 'rate_limit',
91
- name: 'RateLimitError',
92
- retryable: true,
93
- },
94
- {
95
- Class: NetworkError,
96
- category: 'network',
97
- name: 'NetworkError',
98
- retryable: true,
99
- },
100
- {
101
- Class: InternalError,
102
- category: 'internal',
103
- name: 'InternalError',
104
- retryable: false,
105
- },
106
- { Class: AuthError, category: 'auth', name: 'AuthError', retryable: false },
107
- {
108
- Class: CancelledError,
109
- category: 'cancelled',
110
- name: 'CancelledError',
111
- retryable: false,
112
- },
113
- ];
114
-
115
- describe('error classes', () => {
116
- // oxlint-disable-next-line prefer-each -- describe.each loses type safety on heterogeneous class matrix
117
- for (const { Class, category, retryable, name } of errorMatrix) {
118
- describe(name, () => {
119
- test('sets correct category', () => {
120
- const err = new Class('test');
121
- expect(err.category).toBe(category);
122
- });
123
-
124
- test('sets correct retryable', () => {
125
- const err = new Class('test');
126
- expect(err.retryable).toBe(retryable);
127
- });
128
-
129
- test('sets message', () => {
130
- const err = new Class('something went wrong');
131
- expect(err.message).toBe('something went wrong');
132
- });
133
-
134
- test('sets name to constructor name', () => {
135
- const err = new Class('test');
136
- expect(err.name).toBe(name);
137
- });
138
-
139
- test('sets cause when provided', () => {
140
- const cause = new Error('root cause');
141
- const err = new Class('test', { cause });
142
- expect(err.cause).toBe(cause);
143
- });
144
-
145
- test('sets context when provided', () => {
146
- const ctx = { action: 'delete', userId: 'u_123' };
147
- const err = new Class('test', { context: ctx });
148
- expect(err.context).toEqual(ctx);
149
- });
150
-
151
- test('context is undefined when not provided', () => {
152
- const err = new Class('test');
153
- expect(err.context).toBeUndefined();
154
- });
155
-
156
- test('is instanceof TrailsError', () => {
157
- const err = new Class('test');
158
- expect(err).toBeInstanceOf(TrailsError);
159
- });
160
-
161
- test('is instanceof Error', () => {
162
- const err = new Class('test');
163
- expect(err).toBeInstanceOf(Error);
164
- });
165
-
166
- test('is instanceof its own class', () => {
167
- const err = new Class('test');
168
- expect(err).toBeInstanceOf(Class);
169
- });
170
- });
171
- }
172
- });
173
-
174
- // ---------------------------------------------------------------------------
175
- // RateLimitError.retryAfter
176
- // ---------------------------------------------------------------------------
177
-
178
- describe('RateLimitError.retryAfter', () => {
179
- test('stores retryAfter when provided', () => {
180
- const err = new RateLimitError('slow down', { retryAfter: 30 });
181
- expect(err.retryAfter).toBe(30);
182
- });
183
-
184
- test('retryAfter is undefined when not provided', () => {
185
- const err = new RateLimitError('slow down');
186
- expect(err.retryAfter).toBeUndefined();
187
- });
188
-
189
- test('retryAfter coexists with cause and context', () => {
190
- const cause = new Error('upstream');
191
- const err = new RateLimitError('slow down', {
192
- cause,
193
- context: { endpoint: '/api' },
194
- retryAfter: 60,
195
- });
196
- expect(err.retryAfter).toBe(60);
197
- expect(err.cause).toBe(cause);
198
- expect(err.context).toEqual({ endpoint: '/api' });
199
- });
200
- });
201
-
202
- // ---------------------------------------------------------------------------
203
- // Taxonomy maps
204
- // ---------------------------------------------------------------------------
205
-
206
- describe('exitCodeMap', () => {
207
- test('maps all categories to expected exit codes', () => {
208
- expect(exitCodeMap.validation).toBe(1);
209
- expect(exitCodeMap.not_found).toBe(2);
210
- expect(exitCodeMap.conflict).toBe(3);
211
- expect(exitCodeMap.permission).toBe(4);
212
- expect(exitCodeMap.timeout).toBe(5);
213
- expect(exitCodeMap.rate_limit).toBe(6);
214
- expect(exitCodeMap.network).toBe(7);
215
- expect(exitCodeMap.internal).toBe(8);
216
- expect(exitCodeMap.auth).toBe(9);
217
- expect(exitCodeMap.cancelled).toBe(130);
218
- });
219
- });
220
-
221
- describe('statusCodeMap', () => {
222
- test('maps all categories to expected HTTP status codes', () => {
223
- expect(statusCodeMap.validation).toBe(400);
224
- expect(statusCodeMap.not_found).toBe(404);
225
- expect(statusCodeMap.conflict).toBe(409);
226
- expect(statusCodeMap.permission).toBe(403);
227
- expect(statusCodeMap.timeout).toBe(504);
228
- expect(statusCodeMap.rate_limit).toBe(429);
229
- expect(statusCodeMap.network).toBe(502);
230
- expect(statusCodeMap.internal).toBe(500);
231
- expect(statusCodeMap.auth).toBe(401);
232
- expect(statusCodeMap.cancelled).toBe(499);
233
- });
234
- });
235
-
236
- describe('jsonRpcCodeMap', () => {
237
- test('maps all categories to expected JSON-RPC codes', () => {
238
- expect(jsonRpcCodeMap.validation).toBe(-32_602);
239
- expect(jsonRpcCodeMap.not_found).toBe(-32_601);
240
- expect(jsonRpcCodeMap.conflict).toBe(-32_603);
241
- expect(jsonRpcCodeMap.permission).toBe(-32_600);
242
- expect(jsonRpcCodeMap.timeout).toBe(-32_603);
243
- expect(jsonRpcCodeMap.rate_limit).toBe(-32_603);
244
- expect(jsonRpcCodeMap.network).toBe(-32_603);
245
- expect(jsonRpcCodeMap.internal).toBe(-32_603);
246
- expect(jsonRpcCodeMap.auth).toBe(-32_600);
247
- expect(jsonRpcCodeMap.cancelled).toBe(-32_603);
248
- });
249
- });
250
-
251
- describe('retryableMap', () => {
252
- test('only timeout, rate_limit, and network are retryable', () => {
253
- expect(retryableMap.timeout).toBe(true);
254
- expect(retryableMap.rate_limit).toBe(true);
255
- expect(retryableMap.network).toBe(true);
256
-
257
- expect(retryableMap.validation).toBe(false);
258
- expect(retryableMap.not_found).toBe(false);
259
- expect(retryableMap.conflict).toBe(false);
260
- expect(retryableMap.permission).toBe(false);
261
- expect(retryableMap.internal).toBe(false);
262
- expect(retryableMap.auth).toBe(false);
263
- expect(retryableMap.cancelled).toBe(false);
264
- });
265
- });
266
-
267
- // ---------------------------------------------------------------------------
268
- // Helper functions
269
- // ---------------------------------------------------------------------------
270
-
271
- describe('isRetryable', () => {
272
- test('returns true for retryable errors', () => {
273
- expect(isRetryable(new TimeoutError('timed out'))).toBe(true);
274
- expect(isRetryable(new RateLimitError('too fast'))).toBe(true);
275
- expect(isRetryable(new NetworkError('disconnected'))).toBe(true);
276
- });
277
-
278
- test('returns false for non-retryable errors', () => {
279
- expect(isRetryable(new ValidationError('bad input'))).toBe(false);
280
- expect(isRetryable(new NotFoundError('missing'))).toBe(false);
281
- expect(isRetryable(new AuthError('unauthorized'))).toBe(false);
282
- expect(isRetryable(new InternalError('oops'))).toBe(false);
283
- expect(isRetryable(new CancelledError('aborted'))).toBe(false);
284
- });
285
-
286
- test('returns false for plain Error', () => {
287
- expect(isRetryable(new Error('generic'))).toBe(false);
288
- });
289
- });
290
-
291
- describe('isTrailsError', () => {
292
- test('returns true for TrailsError subclasses', () => {
293
- expect(isTrailsError(new ValidationError('bad'))).toBe(true);
294
- expect(isTrailsError(new NetworkError('down'))).toBe(true);
295
- expect(isTrailsError(new CancelledError('stop'))).toBe(true);
296
- });
297
-
298
- test('returns false for plain Error', () => {
299
- expect(isTrailsError(new Error('nope'))).toBe(false);
300
- });
301
-
302
- test('returns false for non-error values', () => {
303
- expect(isTrailsError(null)).toBe(false);
304
- expect(isTrailsError()).toBe(false);
305
- expect(isTrailsError('string')).toBe(false);
306
- expect(isTrailsError(42)).toBe(false);
307
- expect(isTrailsError({})).toBe(false);
308
- });
309
- });
@@ -1,82 +0,0 @@
1
- import { describe, test, expect } from 'bun:test';
2
-
3
- import { z } from 'zod';
4
-
5
- import { event } from '../event';
6
-
7
- const payloadSchema = z.object({
8
- action: z.string(),
9
- userId: z.string(),
10
- });
11
-
12
- const userAction = event('user.action', {
13
- description: 'A user performed an action',
14
- from: ['auth.login', 'auth.signup'],
15
- markers: { domain: 'auth', priority: 1 },
16
- payload: payloadSchema,
17
- });
18
-
19
- describe('event() basics', () => {
20
- test("returns kind 'event'", () => {
21
- expect(userAction.kind).toBe('event');
22
- });
23
-
24
- test('returns correct id', () => {
25
- expect(userAction.id).toBe('user.action');
26
- });
27
-
28
- test('preserves payload schema', () => {
29
- const parsed = userAction.payload.safeParse({
30
- action: 'click',
31
- userId: 'u-1',
32
- });
33
- expect(parsed.success).toBe(true);
34
-
35
- const bad = userAction.payload.safeParse({ userId: 42 });
36
- expect(bad.success).toBe(false);
37
- });
38
-
39
- test('preserves description', () => {
40
- expect(userAction.description).toBe('A user performed an action');
41
- });
42
-
43
- test('result object is frozen', () => {
44
- expect(Object.isFrozen(userAction)).toBe(true);
45
- });
46
- });
47
-
48
- describe('event() from and markers', () => {
49
- test('preserves from', () => {
50
- expect(userAction.from).toEqual(['auth.login', 'auth.signup']);
51
- });
52
-
53
- test('from array is frozen', () => {
54
- expect(Object.isFrozen(userAction.from)).toBe(true);
55
- });
56
-
57
- test('preserves markers', () => {
58
- expect(userAction.markers).toEqual({ domain: 'auth', priority: 1 });
59
- });
60
-
61
- test('optional fields default to undefined', () => {
62
- const minimal = event('minimal', {
63
- payload: z.string(),
64
- });
65
- expect(minimal.description).toBeUndefined();
66
- expect(minimal.from).toBeUndefined();
67
- expect(minimal.markers).toBeUndefined();
68
- });
69
- });
70
-
71
- describe('event() single-object overload', () => {
72
- test('accepts spec with id property', () => {
73
- const e = event({
74
- from: ['entity.add', 'entity.delete'],
75
- id: 'entity.updated',
76
- payload: z.object({ entityId: z.string() }),
77
- });
78
- expect(e.id).toBe('entity.updated');
79
- expect(e.kind).toBe('event');
80
- expect(e.from).toEqual(['entity.add', 'entity.delete']);
81
- });
82
- });