@ontrails/core 1.0.0-beta.4 → 1.0.0-beta.41

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 (247) hide show
  1. package/CHANGELOG.md +412 -12
  2. package/README.md +112 -28
  3. package/package.json +11 -1
  4. package/src/activation-provenance.ts +116 -0
  5. package/src/activation-source-compatibility.ts +430 -0
  6. package/src/activation-source-projection.ts +227 -0
  7. package/src/activation-source.ts +93 -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 +59 -11
  13. package/src/derive.ts +271 -19
  14. package/src/detours.ts +8 -0
  15. package/src/diagnostics.ts +21 -0
  16. package/src/draft.ts +350 -0
  17. package/src/entity.ts +346 -0
  18. package/src/error-projection.ts +51 -0
  19. package/src/errors.ts +335 -48
  20. package/src/execute.ts +1577 -0
  21. package/src/fire.ts +1172 -0
  22. package/src/glob.ts +81 -0
  23. package/src/index.ts +568 -32
  24. package/src/internal/fork-ctx.ts +69 -0
  25. package/src/layer-projection.ts +193 -0
  26. package/src/layer.ts +43 -6
  27. package/src/observe.ts +361 -0
  28. package/src/path-scope.ts +66 -0
  29. package/src/path-security.ts +11 -3
  30. package/src/permits.ts +12 -0
  31. package/src/queue.ts +163 -0
  32. package/src/redaction/patterns.ts +6 -3
  33. package/src/resilience.ts +11 -11
  34. package/src/resource-config.ts +804 -0
  35. package/src/resource.ts +194 -0
  36. package/src/result.ts +18 -0
  37. package/src/run.ts +76 -0
  38. package/src/runtime-builtins.ts +69 -0
  39. package/src/schedule-runtime.ts +689 -0
  40. package/src/schedule.ts +326 -0
  41. package/src/serialization.ts +92 -55
  42. package/src/sha256.ts +136 -0
  43. package/src/signal-diagnostics.ts +633 -0
  44. package/src/signal-ref.ts +111 -0
  45. package/src/signal.ts +104 -0
  46. package/src/store/accessor-protocol.ts +56 -0
  47. package/src/store/index.ts +4 -0
  48. package/src/structured-examples.ts +248 -0
  49. package/src/surface-derivation.ts +91 -0
  50. package/src/surface-filter.ts +101 -0
  51. package/src/surface-overlay.ts +694 -0
  52. package/src/surface-versioning.ts +42 -0
  53. package/src/topo.ts +762 -38
  54. package/src/tracing.ts +346 -0
  55. package/src/trail-id-glob.ts +15 -0
  56. package/src/trail.ts +1244 -34
  57. package/src/trails/derive-trail.ts +835 -0
  58. package/src/trails/index.ts +9 -0
  59. package/src/trails/ingest.ts +152 -0
  60. package/src/trails-db.ts +212 -0
  61. package/src/transport-error-map.ts +174 -0
  62. package/src/type-utils.ts +87 -0
  63. package/src/types.ts +254 -12
  64. package/src/validate-established-topo.ts +73 -0
  65. package/src/validate-topo.ts +569 -55
  66. package/src/validation.ts +152 -4
  67. package/src/version-marker.ts +716 -0
  68. package/src/version-resolution.ts +308 -0
  69. package/src/version-runtime.ts +120 -0
  70. package/src/webhook.ts +461 -0
  71. package/src/workspace.ts +183 -16
  72. package/src/zod-wrappers.ts +72 -0
  73. package/.turbo/turbo-build.log +0 -1
  74. package/.turbo/turbo-lint.log +0 -3
  75. package/.turbo/turbo-typecheck.log +0 -1
  76. package/dist/adapters.d.ts +0 -39
  77. package/dist/adapters.d.ts.map +0 -1
  78. package/dist/adapters.js +0 -2
  79. package/dist/adapters.js.map +0 -1
  80. package/dist/blob-ref.d.ts +0 -20
  81. package/dist/blob-ref.d.ts.map +0 -1
  82. package/dist/blob-ref.js +0 -22
  83. package/dist/blob-ref.js.map +0 -1
  84. package/dist/branded.d.ts +0 -36
  85. package/dist/branded.d.ts.map +0 -1
  86. package/dist/branded.js +0 -89
  87. package/dist/branded.js.map +0 -1
  88. package/dist/collections.d.ts +0 -31
  89. package/dist/collections.d.ts.map +0 -1
  90. package/dist/collections.js +0 -60
  91. package/dist/collections.js.map +0 -1
  92. package/dist/context.d.ts +0 -10
  93. package/dist/context.d.ts.map +0 -1
  94. package/dist/context.js +0 -15
  95. package/dist/context.js.map +0 -1
  96. package/dist/derive.d.ts +0 -33
  97. package/dist/derive.d.ts.map +0 -1
  98. package/dist/derive.js +0 -125
  99. package/dist/derive.js.map +0 -1
  100. package/dist/errors.d.ts +0 -83
  101. package/dist/errors.d.ts.map +0 -1
  102. package/dist/errors.js +0 -142
  103. package/dist/errors.js.map +0 -1
  104. package/dist/event.d.ts +0 -45
  105. package/dist/event.d.ts.map +0 -1
  106. package/dist/event.js +0 -17
  107. package/dist/event.js.map +0 -1
  108. package/dist/fetch.d.ts +0 -15
  109. package/dist/fetch.d.ts.map +0 -1
  110. package/dist/fetch.js +0 -102
  111. package/dist/fetch.js.map +0 -1
  112. package/dist/guards.d.ts +0 -17
  113. package/dist/guards.d.ts.map +0 -1
  114. package/dist/guards.js +0 -25
  115. package/dist/guards.js.map +0 -1
  116. package/dist/health.d.ts +0 -18
  117. package/dist/health.d.ts.map +0 -1
  118. package/dist/health.js +0 -5
  119. package/dist/health.js.map +0 -1
  120. package/dist/index.d.ts +0 -34
  121. package/dist/index.d.ts.map +0 -1
  122. package/dist/index.js +0 -38
  123. package/dist/index.js.map +0 -1
  124. package/dist/job.d.ts +0 -24
  125. package/dist/job.d.ts.map +0 -1
  126. package/dist/job.js +0 -17
  127. package/dist/job.js.map +0 -1
  128. package/dist/layer.d.ts +0 -17
  129. package/dist/layer.d.ts.map +0 -1
  130. package/dist/layer.js +0 -21
  131. package/dist/layer.js.map +0 -1
  132. package/dist/path-security.d.ts +0 -28
  133. package/dist/path-security.d.ts.map +0 -1
  134. package/dist/path-security.js +0 -63
  135. package/dist/path-security.js.map +0 -1
  136. package/dist/patterns/bulk.d.ts +0 -15
  137. package/dist/patterns/bulk.d.ts.map +0 -1
  138. package/dist/patterns/bulk.js +0 -14
  139. package/dist/patterns/bulk.js.map +0 -1
  140. package/dist/patterns/change.d.ts +0 -10
  141. package/dist/patterns/change.d.ts.map +0 -1
  142. package/dist/patterns/change.js +0 -10
  143. package/dist/patterns/change.js.map +0 -1
  144. package/dist/patterns/date-range.d.ts +0 -10
  145. package/dist/patterns/date-range.d.ts.map +0 -1
  146. package/dist/patterns/date-range.js +0 -10
  147. package/dist/patterns/date-range.js.map +0 -1
  148. package/dist/patterns/index.d.ts +0 -9
  149. package/dist/patterns/index.d.ts.map +0 -1
  150. package/dist/patterns/index.js +0 -9
  151. package/dist/patterns/index.js.map +0 -1
  152. package/dist/patterns/pagination.d.ts +0 -18
  153. package/dist/patterns/pagination.d.ts.map +0 -1
  154. package/dist/patterns/pagination.js +0 -18
  155. package/dist/patterns/pagination.js.map +0 -1
  156. package/dist/patterns/progress.d.ts +0 -11
  157. package/dist/patterns/progress.d.ts.map +0 -1
  158. package/dist/patterns/progress.js +0 -11
  159. package/dist/patterns/progress.js.map +0 -1
  160. package/dist/patterns/sorting.d.ts +0 -13
  161. package/dist/patterns/sorting.d.ts.map +0 -1
  162. package/dist/patterns/sorting.js +0 -10
  163. package/dist/patterns/sorting.js.map +0 -1
  164. package/dist/patterns/status.d.ts +0 -15
  165. package/dist/patterns/status.d.ts.map +0 -1
  166. package/dist/patterns/status.js +0 -9
  167. package/dist/patterns/status.js.map +0 -1
  168. package/dist/patterns/timestamps.d.ts +0 -10
  169. package/dist/patterns/timestamps.d.ts.map +0 -1
  170. package/dist/patterns/timestamps.js +0 -10
  171. package/dist/patterns/timestamps.js.map +0 -1
  172. package/dist/redaction/index.d.ts +0 -4
  173. package/dist/redaction/index.d.ts.map +0 -1
  174. package/dist/redaction/index.js +0 -3
  175. package/dist/redaction/index.js.map +0 -1
  176. package/dist/redaction/patterns.d.ts +0 -9
  177. package/dist/redaction/patterns.d.ts.map +0 -1
  178. package/dist/redaction/patterns.js +0 -39
  179. package/dist/redaction/patterns.js.map +0 -1
  180. package/dist/redaction/redactor.d.ts +0 -27
  181. package/dist/redaction/redactor.d.ts.map +0 -1
  182. package/dist/redaction/redactor.js +0 -89
  183. package/dist/redaction/redactor.js.map +0 -1
  184. package/dist/resilience.d.ts +0 -34
  185. package/dist/resilience.d.ts.map +0 -1
  186. package/dist/resilience.js +0 -164
  187. package/dist/resilience.js.map +0 -1
  188. package/dist/result.d.ts +0 -57
  189. package/dist/result.d.ts.map +0 -1
  190. package/dist/result.js +0 -156
  191. package/dist/result.js.map +0 -1
  192. package/dist/serialization.d.ts +0 -27
  193. package/dist/serialization.d.ts.map +0 -1
  194. package/dist/serialization.js +0 -153
  195. package/dist/serialization.js.map +0 -1
  196. package/dist/topo.d.ts +0 -16
  197. package/dist/topo.d.ts.map +0 -1
  198. package/dist/topo.js +0 -66
  199. package/dist/topo.js.map +0 -1
  200. package/dist/trail.d.ts +0 -89
  201. package/dist/trail.d.ts.map +0 -1
  202. package/dist/trail.js +0 -18
  203. package/dist/trail.js.map +0 -1
  204. package/dist/types.d.ts +0 -46
  205. package/dist/types.d.ts.map +0 -1
  206. package/dist/types.js +0 -2
  207. package/dist/types.js.map +0 -1
  208. package/dist/validate-topo.d.ts +0 -24
  209. package/dist/validate-topo.d.ts.map +0 -1
  210. package/dist/validate-topo.js +0 -158
  211. package/dist/validate-topo.js.map +0 -1
  212. package/dist/validation.d.ts +0 -27
  213. package/dist/validation.d.ts.map +0 -1
  214. package/dist/validation.js +0 -134
  215. package/dist/validation.js.map +0 -1
  216. package/dist/workspace.d.ts +0 -25
  217. package/dist/workspace.d.ts.map +0 -1
  218. package/dist/workspace.js +0 -57
  219. package/dist/workspace.js.map +0 -1
  220. package/src/__tests__/blob-ref.test.ts +0 -103
  221. package/src/__tests__/branded.test.ts +0 -148
  222. package/src/__tests__/collections.test.ts +0 -126
  223. package/src/__tests__/context.test.ts +0 -66
  224. package/src/__tests__/derive.test.ts +0 -203
  225. package/src/__tests__/errors.test.ts +0 -309
  226. package/src/__tests__/event.test.ts +0 -82
  227. package/src/__tests__/fetch.test.ts +0 -217
  228. package/src/__tests__/guards.test.ts +0 -102
  229. package/src/__tests__/job.test.ts +0 -98
  230. package/src/__tests__/layer.test.ts +0 -212
  231. package/src/__tests__/path-security.test.ts +0 -114
  232. package/src/__tests__/patterns.test.ts +0 -273
  233. package/src/__tests__/redaction.test.ts +0 -244
  234. package/src/__tests__/resilience.test.ts +0 -246
  235. package/src/__tests__/result.test.ts +0 -155
  236. package/src/__tests__/serialization.test.ts +0 -401
  237. package/src/__tests__/topo.test.ts +0 -181
  238. package/src/__tests__/trail.test.ts +0 -217
  239. package/src/__tests__/validate-topo.test.ts +0 -278
  240. package/src/__tests__/validation.test.ts +0 -283
  241. package/src/__tests__/workspace.test.ts +0 -183
  242. package/src/adapters.ts +0 -68
  243. package/src/event.ts +0 -77
  244. package/src/health.ts +0 -23
  245. package/src/job.ts +0 -20
  246. package/tsconfig.json +0 -9
  247. package/tsconfig.tsbuildinfo +0 -1
@@ -1,283 +0,0 @@
1
- import { describe, test, expect } from 'bun:test';
2
-
3
- import { z } from 'zod';
4
-
5
- import { ValidationError } from '../errors.js';
6
- import {
7
- validateInput,
8
- validateOutput,
9
- formatZodIssues,
10
- zodToJsonSchema,
11
- } from '../validation.js';
12
-
13
- // ---------------------------------------------------------------------------
14
- // validateInput
15
- // ---------------------------------------------------------------------------
16
-
17
- describe('validateInput', () => {
18
- const schema = z.object({
19
- age: z.number().min(0),
20
- name: z.string(),
21
- });
22
-
23
- test('returns Ok for valid data', () => {
24
- const result = validateInput(schema, { age: 30, name: 'Alice' });
25
- expect(result.isOk()).toBe(true);
26
- expect(result.unwrap()).toEqual({ age: 30, name: 'Alice' });
27
- });
28
-
29
- test('returns Err with ValidationError for invalid data', () => {
30
- const result = validateInput(schema, { name: 123 });
31
- expect(result.isErr()).toBe(true);
32
- const err = result as unknown as { error: ValidationError };
33
- expect(err.error).toBeInstanceOf(ValidationError);
34
- expect(err.error.category).toBe('validation');
35
- });
36
-
37
- test('includes formatted issues in error message', () => {
38
- const result = validateInput(schema, {});
39
- expect(result.isErr()).toBe(true);
40
- const err = result as unknown as { error: ValidationError };
41
- expect(err.error.message).toContain('name');
42
- });
43
-
44
- test('attaches ZodError as cause', () => {
45
- const result = validateInput(schema, {});
46
- expect(result.isErr()).toBe(true);
47
- const err = result as unknown as { error: ValidationError };
48
- expect(err.error.cause).toBeInstanceOf(z.ZodError);
49
- });
50
-
51
- test('attaches issues in context', () => {
52
- const result = validateInput(schema, {});
53
- expect(result.isErr()).toBe(true);
54
- const err = result as unknown as { error: ValidationError };
55
- expect(err.error.context).toBeDefined();
56
- expect(Array.isArray(err.error.context?.['issues'])).toBe(true);
57
- });
58
-
59
- test('works with simple string schema', () => {
60
- const str = z.string().min(1);
61
- expect(validateInput(str, 'hello').isOk()).toBe(true);
62
- expect(validateInput(str, '').isErr()).toBe(true);
63
- expect(validateInput(str, 42).isErr()).toBe(true);
64
- });
65
- });
66
-
67
- // ---------------------------------------------------------------------------
68
- // validateOutput
69
- // ---------------------------------------------------------------------------
70
-
71
- describe('validateOutput', () => {
72
- const schema = z.object({
73
- id: z.string(),
74
- score: z.number(),
75
- });
76
-
77
- test('returns Ok for valid data', () => {
78
- const result = validateOutput(schema, { id: 'abc', score: 42 });
79
- expect(result.isOk()).toBe(true);
80
- expect(result.unwrap()).toEqual({ id: 'abc', score: 42 });
81
- });
82
-
83
- test('returns Err with ValidationError for invalid data', () => {
84
- const result = validateOutput(schema, { id: 123 });
85
- expect(result.isErr()).toBe(true);
86
- const err = result as unknown as { error: ValidationError };
87
- expect(err.error).toBeInstanceOf(ValidationError);
88
- expect(err.error.category).toBe('validation');
89
- });
90
-
91
- test('error message includes "Output validation failed" prefix', () => {
92
- const result = validateOutput(schema, {});
93
- expect(result.isErr()).toBe(true);
94
- const err = result as unknown as { error: ValidationError };
95
- expect(err.error.message).toContain('Output validation failed');
96
- });
97
-
98
- test('attaches ZodError as cause', () => {
99
- const result = validateOutput(schema, {});
100
- expect(result.isErr()).toBe(true);
101
- const err = result as unknown as { error: ValidationError };
102
- expect(err.error.cause).toBeInstanceOf(z.ZodError);
103
- });
104
-
105
- test('attaches issues in context', () => {
106
- const result = validateOutput(schema, {});
107
- expect(result.isErr()).toBe(true);
108
- const err = result as unknown as { error: ValidationError };
109
- expect(err.error.context).toBeDefined();
110
- expect(Array.isArray(err.error.context?.['issues'])).toBe(true);
111
- });
112
- });
113
-
114
- // ---------------------------------------------------------------------------
115
- // formatZodIssues
116
- // ---------------------------------------------------------------------------
117
-
118
- describe('formatZodIssues', () => {
119
- test('formats issues with paths', () => {
120
- const schema = z.object({ email: z.string().email() });
121
- const parsed = schema.safeParse({ email: 'not-email' });
122
- expect(parsed.success).toBe(false);
123
- const failed1 = parsed as unknown as { error: z.ZodError };
124
- const messages1 = formatZodIssues(failed1.error.issues);
125
- expect(messages1.length).toBeGreaterThan(0);
126
- expect(messages1[0]).toMatch(/^email: /);
127
- });
128
-
129
- test('formats root-level issues without path prefix', () => {
130
- const schema = z.string();
131
- const parsed = schema.safeParse(42);
132
- expect(parsed.success).toBe(false);
133
- const failed = parsed as unknown as { error: z.ZodError };
134
- const messages = formatZodIssues(failed.error.issues);
135
- expect(messages.length).toBeGreaterThan(0);
136
- // Root issues have no "path: " prefix — message starts directly
137
- // (the message itself may contain colons, but won't start with "path: ")
138
- expect(messages[0]).not.toMatch(/^\w+: /);
139
- });
140
-
141
- test('formats nested paths with dot notation', () => {
142
- const schema = z.object({
143
- user: z.object({ name: z.string() }),
144
- });
145
- const parsed = schema.safeParse({ user: { name: 123 } });
146
- expect(parsed.success).toBe(false);
147
- const failed = parsed as unknown as { error: z.ZodError };
148
- const messages = formatZodIssues(failed.error.issues);
149
- expect(messages[0]).toMatch(/^user\.name: /);
150
- });
151
- });
152
-
153
- // ---------------------------------------------------------------------------
154
- // zodToJsonSchema
155
- // ---------------------------------------------------------------------------
156
-
157
- describe('zodToJsonSchema', () => {
158
- describe('primitives', () => {
159
- test('converts z.string()', () => {
160
- expect(zodToJsonSchema(z.string())).toEqual({ type: 'string' });
161
- });
162
-
163
- test('converts z.number()', () => {
164
- expect(zodToJsonSchema(z.number())).toEqual({ type: 'number' });
165
- });
166
-
167
- test('converts z.boolean()', () => {
168
- expect(zodToJsonSchema(z.boolean())).toEqual({ type: 'boolean' });
169
- });
170
-
171
- test('converts z.literal()', () => {
172
- expect(zodToJsonSchema(z.literal('hello'))).toEqual({ const: 'hello' });
173
- expect(zodToJsonSchema(z.literal(42))).toEqual({ const: 42 });
174
- });
175
-
176
- test('converts z.enum()', () => {
177
- expect(zodToJsonSchema(z.enum(['a', 'b', 'c']))).toEqual({
178
- enum: ['a', 'b', 'c'],
179
- type: 'string',
180
- });
181
- });
182
-
183
- test('converts z.array()', () => {
184
- expect(zodToJsonSchema(z.array(z.string()))).toEqual({
185
- items: { type: 'string' },
186
- type: 'array',
187
- });
188
- });
189
- });
190
-
191
- describe('objects', () => {
192
- test('converts z.object() with required fields', () => {
193
- const schema = z.object({ age: z.number(), name: z.string() });
194
- const result = zodToJsonSchema(schema);
195
- expect(result).toEqual({
196
- properties: {
197
- age: { type: 'number' },
198
- name: { type: 'string' },
199
- },
200
- required: ['age', 'name'],
201
- type: 'object',
202
- });
203
- });
204
-
205
- test('converts z.object() with optional fields', () => {
206
- const schema = z.object({
207
- name: z.string(),
208
- nickname: z.string().optional(),
209
- });
210
- const result = zodToJsonSchema(schema);
211
- expect(result).toEqual({
212
- properties: {
213
- name: { type: 'string' },
214
- nickname: { type: 'string' },
215
- },
216
- required: ['name'],
217
- type: 'object',
218
- });
219
- });
220
-
221
- test('converts z.object() with default fields', () => {
222
- const schema = z.object({
223
- name: z.string(),
224
- role: z.string().default('user'),
225
- });
226
- const result = zodToJsonSchema(schema);
227
- expect(result).toEqual({
228
- properties: {
229
- name: { type: 'string' },
230
- role: { default: 'user', type: 'string' },
231
- },
232
- required: ['name'],
233
- type: 'object',
234
- });
235
- });
236
-
237
- test('handles nested objects', () => {
238
- const schema = z.object({
239
- user: z.object({ name: z.string() }),
240
- });
241
- expect(zodToJsonSchema(schema)).toEqual({
242
- properties: {
243
- user: {
244
- properties: { name: { type: 'string' } },
245
- required: ['name'],
246
- type: 'object',
247
- },
248
- },
249
- required: ['user'],
250
- type: 'object',
251
- });
252
- });
253
- });
254
-
255
- describe('modifiers and combinators', () => {
256
- test('converts z.union()', () => {
257
- const schema = z.union([z.string(), z.number()]);
258
- expect(zodToJsonSchema(schema)).toEqual({
259
- anyOf: [{ type: 'string' }, { type: 'number' }],
260
- });
261
- });
262
-
263
- test('preserves z.describe()', () => {
264
- const schema = z.string().describe('A user name');
265
- expect(zodToJsonSchema(schema)).toEqual({
266
- description: 'A user name',
267
- type: 'string',
268
- });
269
- });
270
-
271
- test('handles z.nullable()', () => {
272
- const schema = z.string().nullable();
273
- expect(zodToJsonSchema(schema)).toEqual({
274
- anyOf: [{ type: 'string' }, { type: 'null' }],
275
- });
276
- });
277
-
278
- test('returns empty object for unknown types', () => {
279
- // z.any() is not in our coverage list
280
- expect(zodToJsonSchema(z.any())).toEqual({});
281
- });
282
- });
283
- });
@@ -1,183 +0,0 @@
1
- import { describe, test, expect } from 'bun:test';
2
- import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { resolve, join } from 'node:path';
5
-
6
- import { NotFoundError } from '../errors.js';
7
- import {
8
- findWorkspaceRoot,
9
- isInsideWorkspace,
10
- getRelativePath,
11
- } from '../workspace.js';
12
-
13
- // ---------------------------------------------------------------------------
14
- // Helpers
15
- // ---------------------------------------------------------------------------
16
-
17
- const createTempDir = (): string =>
18
- mkdtempSync(join(tmpdir(), 'trails-ws-test-'));
19
-
20
- const writeJson = (dir: string, filename: string, data: unknown): void => {
21
- writeFileSync(join(dir, filename), JSON.stringify(data, null, 2));
22
- };
23
-
24
- /** Set up nested workspaces: outer > inner > packages/lib. Returns the deepest path. */
25
- const setupNestedWorkspaces = (outer: string): string => {
26
- writeJson(outer, 'package.json', { name: 'outer', workspaces: ['inner/*'] });
27
- const inner = join(outer, 'inner', 'nested');
28
- mkdirSync(inner, { recursive: true });
29
- writeJson(join(outer, 'inner'), 'package.json', {
30
- name: 'inner',
31
- workspaces: ['packages/*'],
32
- });
33
- const deep = join(inner, 'packages', 'lib');
34
- mkdirSync(deep, { recursive: true });
35
- return deep;
36
- };
37
-
38
- // ---------------------------------------------------------------------------
39
- // findWorkspaceRoot
40
- // ---------------------------------------------------------------------------
41
-
42
- describe('findWorkspaceRoot', () => {
43
- test('finds workspace root when started inside a nested directory', async () => {
44
- const root = createTempDir();
45
- try {
46
- writeJson(root, 'package.json', {
47
- name: 'my-workspace',
48
- workspaces: ['packages/*'],
49
- });
50
-
51
- const nested = join(root, 'packages', 'core', 'src');
52
- mkdirSync(nested, { recursive: true });
53
-
54
- const result = await findWorkspaceRoot(nested);
55
- expect(result.isOk()).toBe(true);
56
- expect(result.unwrap()).toBe(resolve(root));
57
- } finally {
58
- rmSync(root, { force: true, recursive: true });
59
- }
60
- });
61
-
62
- test('skips package.json without workspaces field', async () => {
63
- const root = createTempDir();
64
- try {
65
- // Root has workspaces
66
- writeJson(root, 'package.json', {
67
- name: 'root',
68
- workspaces: ['packages/*'],
69
- });
70
-
71
- // Nested package has no workspaces
72
- const pkg = join(root, 'packages', 'core');
73
- mkdirSync(pkg, { recursive: true });
74
- writeJson(pkg, 'package.json', { name: '@scope/core' });
75
-
76
- const result = await findWorkspaceRoot(pkg);
77
- expect(result.isOk()).toBe(true);
78
- expect(result.unwrap()).toBe(resolve(root));
79
- } finally {
80
- rmSync(root, { force: true, recursive: true });
81
- }
82
- });
83
-
84
- test('returns the closest workspace root', async () => {
85
- const outer = createTempDir();
86
- try {
87
- const deep = setupNestedWorkspaces(outer);
88
- const result = await findWorkspaceRoot(deep);
89
- expect(result.isOk()).toBe(true);
90
- // Should find inner workspace first (closest ancestor)
91
- expect(result.unwrap()).toBe(resolve(join(outer, 'inner')));
92
- } finally {
93
- rmSync(outer, { force: true, recursive: true });
94
- }
95
- });
96
-
97
- test('returns NotFoundError when no workspace root exists', async () => {
98
- const dir = createTempDir();
99
- try {
100
- // No package.json at all
101
- const result = await findWorkspaceRoot(dir);
102
- // This will either find one above in the actual filesystem or fail.
103
- // We walk up to /, so it depends on the host. Use a deep isolated path.
104
- // Since tmpdir might be under a workspace, let's just check the type
105
- // is correct if it does fail. When the host has a workspace root above
106
- // tmpdir, the result will be Ok — both outcomes are acceptable.
107
- const isAcceptable =
108
- // oxlint-disable-next-line no-conditional-in-test -- host-dependent: tmpdir may sit under a real workspace
109
- result.isOk() ||
110
- (result as unknown as { error: Error }).error instanceof NotFoundError;
111
- expect(isAcceptable).toBe(true);
112
- } finally {
113
- rmSync(dir, { force: true, recursive: true });
114
- }
115
- });
116
-
117
- test('handles malformed package.json gracefully', async () => {
118
- const root = createTempDir();
119
- try {
120
- // Write invalid JSON
121
- writeFileSync(join(root, 'package.json'), 'not json {{{');
122
-
123
- const result = await findWorkspaceRoot(root);
124
- // Should not throw — just skip and keep walking.
125
- // On some hosts tmpdir sits under a real workspace, so Ok is valid too.
126
- const isAcceptable =
127
- // oxlint-disable-next-line no-conditional-in-test -- host-dependent: tmpdir may sit under a real workspace
128
- result.isOk() ||
129
- (result as unknown as { error: Error }).error instanceof NotFoundError;
130
- expect(isAcceptable).toBe(true);
131
- } finally {
132
- rmSync(root, { force: true, recursive: true });
133
- }
134
- });
135
- });
136
-
137
- // ---------------------------------------------------------------------------
138
- // isInsideWorkspace
139
- // ---------------------------------------------------------------------------
140
-
141
- describe('isInsideWorkspace', () => {
142
- test('returns true for a file inside the workspace', () => {
143
- expect(
144
- isInsideWorkspace('/project/packages/core/src/index.ts', '/project')
145
- ).toBe(true);
146
- });
147
-
148
- test('returns false for a file outside the workspace', () => {
149
- expect(isInsideWorkspace('/other/file.ts', '/project')).toBe(false);
150
- });
151
-
152
- test('returns false for the workspace root itself', () => {
153
- // The root directory itself is not \"inside\" the workspace
154
- expect(isInsideWorkspace('/project', '/project')).toBe(false);
155
- });
156
-
157
- test('handles relative-looking paths by resolving them', () => {
158
- expect(
159
- isInsideWorkspace('/project/packages/../packages/core', '/project')
160
- ).toBe(true);
161
- });
162
- });
163
-
164
- // ---------------------------------------------------------------------------
165
- // getRelativePath
166
- // ---------------------------------------------------------------------------
167
-
168
- describe('getRelativePath', () => {
169
- test('returns relative path from workspace root', () => {
170
- expect(
171
- getRelativePath('/project/packages/core/src/index.ts', '/project')
172
- ).toBe('packages/core/src/index.ts');
173
- });
174
-
175
- test('returns .. segments for paths outside workspace', () => {
176
- const rel = getRelativePath('/other/file.ts', '/project');
177
- expect(rel.startsWith('..')).toBe(true);
178
- });
179
-
180
- test('returns empty string for the root itself', () => {
181
- expect(getRelativePath('/project', '/project')).toBe('');
182
- });
183
- });
package/src/adapters.ts DELETED
@@ -1,68 +0,0 @@
1
- import type { Result } from './result.js';
2
-
3
- // ---------------------------------------------------------------------------
4
- // Shared option types
5
- // ---------------------------------------------------------------------------
6
-
7
- /** Options for search queries */
8
- export interface SearchOptions {
9
- readonly limit?: number | undefined;
10
- readonly offset?: number | undefined;
11
- readonly filters?: Readonly<Record<string, unknown>> | undefined;
12
- }
13
-
14
- /** A single search hit */
15
- export interface SearchResult {
16
- readonly id: string;
17
- readonly score: number;
18
- readonly document: Readonly<Record<string, unknown>>;
19
- }
20
-
21
- /** Options for storage writes */
22
- export interface StorageOptions {
23
- /** Time-to-live in milliseconds */
24
- readonly ttl?: number | undefined;
25
- }
26
-
27
- // ---------------------------------------------------------------------------
28
- // Adapter port interfaces
29
- // ---------------------------------------------------------------------------
30
-
31
- /** Full-text / vector index adapter */
32
- export interface IndexAdapter {
33
- index(
34
- id: string,
35
- document: Readonly<Record<string, unknown>>
36
- ): Promise<Result<void, Error>>;
37
-
38
- search(
39
- query: string,
40
- options?: SearchOptions
41
- ): Promise<Result<readonly SearchResult[], Error>>;
42
-
43
- remove(id: string): Promise<Result<void, Error>>;
44
- }
45
-
46
- /** Key-value storage adapter */
47
- export interface StorageAdapter {
48
- get(key: string): Promise<Result<unknown, Error>>;
49
- set(
50
- key: string,
51
- value: unknown,
52
- options?: StorageOptions
53
- ): Promise<Result<void, Error>>;
54
- delete(key: string): Promise<Result<void, Error>>;
55
- has(key: string): Promise<Result<boolean, Error>>;
56
- }
57
-
58
- /** Cache adapter with typed get/set and bulk clear */
59
- export interface CacheAdapter {
60
- get<T>(key: string): Promise<Result<T | undefined, Error>>;
61
- set<T>(
62
- key: string,
63
- value: T,
64
- options?: StorageOptions
65
- ): Promise<Result<void, Error>>;
66
- delete(key: string): Promise<Result<void, Error>>;
67
- clear(): Promise<Result<void, Error>>;
68
- }
package/src/event.ts DELETED
@@ -1,77 +0,0 @@
1
- /**
2
- * Event — a named payload schema with optional provenance metadata.
3
- */
4
-
5
- import type { z } from 'zod';
6
-
7
- // ---------------------------------------------------------------------------
8
- // Spec (input to the factory)
9
- // ---------------------------------------------------------------------------
10
-
11
- export interface EventSpec<T> {
12
- readonly payload: z.ZodType<T>;
13
- readonly description?: string | undefined;
14
- readonly metadata?: Readonly<Record<string, unknown>> | undefined;
15
- /** Trail IDs that produce this event (e.g. the trails it originates from). */
16
- readonly from?: readonly string[] | undefined;
17
- }
18
-
19
- // ---------------------------------------------------------------------------
20
- // Shape (output of the factory)
21
- // ---------------------------------------------------------------------------
22
-
23
- export interface Event<T> {
24
- readonly id: string;
25
- readonly kind: 'event';
26
- readonly payload: z.ZodType<T>;
27
- readonly description?: string | undefined;
28
- readonly metadata?: Readonly<Record<string, unknown>> | undefined;
29
- /** Trail IDs that produce this event (e.g. the trails it originates from). */
30
- readonly from?: readonly string[] | undefined;
31
- }
32
-
33
- // ---------------------------------------------------------------------------
34
- // Factory
35
- // ---------------------------------------------------------------------------
36
-
37
- /**
38
- * Create an event definition.
39
- *
40
- * An event is a named payload schema describing something that happened.
41
- * Returns a frozen object with `kind: "event"` and all spec fields.
42
- *
43
- * @example
44
- * ```typescript
45
- * // ID as first argument
46
- * const updated = event("entity.updated", {
47
- * payload: EntityUpdatedSchema,
48
- * from: ["entity.add", "entity.update"],
49
- * });
50
- *
51
- * // Full spec object (programmatic)
52
- * const updated = event({ id: "entity.updated", payload: ..., from: [...] });
53
- * ```
54
- */
55
- export function event<T>(id: string, spec: EventSpec<T>): Event<T>;
56
- export function event<T>(
57
- spec: EventSpec<T> & { readonly id: string }
58
- ): Event<T>;
59
- export function event<T>(
60
- idOrSpec: string | (EventSpec<T> & { readonly id: string }),
61
- maybeSpec?: EventSpec<T>
62
- ): Event<T> {
63
- const resolvedId = typeof idOrSpec === 'string' ? idOrSpec : idOrSpec.id;
64
- // oxlint-disable-next-line no-non-null-assertion -- overload guarantees maybeSpec when idOrSpec is string
65
- const resolvedSpec = typeof idOrSpec === 'string' ? maybeSpec! : idOrSpec;
66
- return Object.freeze({
67
- description: resolvedSpec.description,
68
- from: resolvedSpec.from ? Object.freeze([...resolvedSpec.from]) : undefined,
69
- id: resolvedId,
70
- kind: 'event' as const,
71
- metadata: resolvedSpec.metadata,
72
- payload: resolvedSpec.payload,
73
- });
74
- }
75
-
76
- /** Existential type for heterogeneous event collections */
77
- export type AnyEvent = Event<unknown>;
package/src/health.ts DELETED
@@ -1,23 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Health check types
3
- // ---------------------------------------------------------------------------
4
-
5
- /** Aggregate health status */
6
- export type HealthStatus = 'healthy' | 'degraded' | 'unhealthy';
7
-
8
- /** Individual component check result */
9
- export interface HealthCheck {
10
- readonly status: HealthStatus;
11
- readonly message?: string | undefined;
12
- /** Latency in milliseconds */
13
- readonly latency?: number | undefined;
14
- }
15
-
16
- /** Full health report returned by a health endpoint */
17
- export interface HealthResult {
18
- readonly status: HealthStatus;
19
- readonly checks: Readonly<Record<string, HealthCheck>>;
20
- readonly version?: string | undefined;
21
- /** Uptime in seconds */
22
- readonly uptime?: number | undefined;
23
- }
package/src/job.ts DELETED
@@ -1,20 +0,0 @@
1
- import { z } from 'zod';
2
-
3
- import { progressFields } from './patterns/progress.js';
4
- import { statusFields } from './patterns/status.js';
5
-
6
- /**
7
- * Proof: job-style output schema composes from existing pattern helpers.
8
- * No dedicated `kind: "job"` needed — regular trails with status+progress output work.
9
- */
10
- export const jobOutputSchema = z.object({
11
- ...progressFields().shape,
12
- ...statusFields().shape,
13
- completedAt: z.string().optional(),
14
- error: z.string().optional(),
15
- jobId: z.string(),
16
- result: z.unknown().optional(),
17
- startedAt: z.string().optional(),
18
- });
19
-
20
- export type JobOutput = z.infer<typeof jobOutputSchema>;
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src"
6
- },
7
- "include": ["src"],
8
- "exclude": ["**/__tests__/**", "**/*.test.ts", "dist"]
9
- }
@@ -1 +0,0 @@
1
- {"root":["./src/adapters.ts","./src/blob-ref.ts","./src/branded.ts","./src/collections.ts","./src/context.ts","./src/derive.ts","./src/errors.ts","./src/event.ts","./src/fetch.ts","./src/guards.ts","./src/health.ts","./src/index.ts","./src/job.ts","./src/layer.ts","./src/path-security.ts","./src/resilience.ts","./src/result.ts","./src/serialization.ts","./src/topo.ts","./src/trail.ts","./src/types.ts","./src/validate-topo.ts","./src/validation.ts","./src/workspace.ts","./src/patterns/bulk.ts","./src/patterns/change.ts","./src/patterns/date-range.ts","./src/patterns/index.ts","./src/patterns/pagination.ts","./src/patterns/progress.ts","./src/patterns/sorting.ts","./src/patterns/status.ts","./src/patterns/timestamps.ts","./src/redaction/index.ts","./src/redaction/patterns.ts","./src/redaction/redactor.ts"],"version":"5.9.3"}