duron 0.3.0-beta.8 → 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/dist/action-job.d.ts +33 -2
- package/dist/action-job.d.ts.map +1 -1
- package/dist/action-job.js +93 -26
- package/dist/action-manager.d.ts +44 -2
- package/dist/action-manager.d.ts.map +1 -1
- package/dist/action-manager.js +64 -3
- package/dist/action.d.ts +388 -7
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +44 -23
- package/dist/adapters/adapter.d.ts +365 -8
- package/dist/adapters/adapter.d.ts.map +1 -1
- package/dist/adapters/adapter.js +221 -15
- package/dist/adapters/postgres/base.d.ts +184 -6
- package/dist/adapters/postgres/base.d.ts.map +1 -1
- package/dist/adapters/postgres/base.js +436 -75
- package/dist/adapters/postgres/pglite.d.ts +37 -0
- package/dist/adapters/postgres/pglite.d.ts.map +1 -1
- package/dist/adapters/postgres/pglite.js +38 -0
- package/dist/adapters/postgres/postgres.d.ts +35 -0
- package/dist/adapters/postgres/postgres.d.ts.map +1 -1
- package/dist/adapters/postgres/postgres.js +42 -0
- package/dist/adapters/postgres/schema.d.ts +150 -37
- package/dist/adapters/postgres/schema.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.default.d.ts +151 -38
- package/dist/adapters/postgres/schema.default.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.default.js +2 -2
- package/dist/adapters/postgres/schema.js +60 -23
- package/dist/adapters/schemas.d.ts +124 -80
- package/dist/adapters/schemas.d.ts.map +1 -1
- package/dist/adapters/schemas.js +139 -26
- package/dist/client.d.ts +426 -22
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +370 -20
- package/dist/constants.js +6 -0
- package/dist/errors.d.ts +166 -9
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +189 -19
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/server.d.ts +99 -37
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +84 -25
- package/dist/step-manager.d.ts +111 -4
- package/dist/step-manager.d.ts.map +1 -1
- package/dist/step-manager.js +411 -75
- package/dist/telemetry/index.d.ts +1 -4
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +2 -4
- package/dist/telemetry/local-span-exporter.d.ts +56 -0
- package/dist/telemetry/local-span-exporter.d.ts.map +1 -0
- package/dist/telemetry/local-span-exporter.js +118 -0
- package/dist/utils/p-retry.d.ts +5 -0
- package/dist/utils/p-retry.d.ts.map +1 -1
- package/dist/utils/p-retry.js +8 -0
- package/dist/utils/wait-for-abort.d.ts +1 -0
- package/dist/utils/wait-for-abort.d.ts.map +1 -1
- package/dist/utils/wait-for-abort.js +1 -0
- package/migrations/postgres/{20260119153838_flimsy_thor_girl → 20260121160012_normal_bloodstrike}/migration.sql +32 -20
- package/migrations/postgres/{20260119153838_flimsy_thor_girl → 20260121160012_normal_bloodstrike}/snapshot.json +241 -66
- package/package.json +42 -26
- package/src/action-job.ts +43 -32
- package/src/action-manager.ts +5 -5
- package/src/action.ts +317 -149
- package/src/adapters/adapter.ts +54 -54
- package/src/adapters/postgres/base.ts +266 -86
- package/src/adapters/postgres/schema.default.ts +2 -2
- package/src/adapters/postgres/schema.ts +52 -24
- package/src/adapters/schemas.ts +91 -36
- package/src/client.ts +322 -68
- package/src/errors.ts +141 -30
- package/src/index.ts +2 -0
- package/src/server.ts +39 -37
- package/src/step-manager.ts +254 -91
- package/src/telemetry/index.ts +2 -20
- package/src/telemetry/local-span-exporter.ts +148 -0
- package/dist/telemetry/adapter.d.ts +0 -107
- package/dist/telemetry/adapter.d.ts.map +0 -1
- package/dist/telemetry/adapter.js +0 -134
- package/dist/telemetry/local.d.ts +0 -22
- package/dist/telemetry/local.d.ts.map +0 -1
- package/dist/telemetry/local.js +0 -243
- package/dist/telemetry/noop.d.ts +0 -17
- package/dist/telemetry/noop.d.ts.map +0 -1
- package/dist/telemetry/noop.js +0 -66
- package/dist/telemetry/opentelemetry.d.ts +0 -25
- package/dist/telemetry/opentelemetry.d.ts.map +0 -1
- package/dist/telemetry/opentelemetry.js +0 -312
- package/src/telemetry/adapter.ts +0 -642
- package/src/telemetry/local.ts +0 -429
- package/src/telemetry/noop.ts +0 -141
- package/src/telemetry/opentelemetry.ts +0 -453
package/src/errors.ts
CHANGED
|
@@ -1,8 +1,42 @@
|
|
|
1
|
+
// Error codes for type checking without instanceof
|
|
2
|
+
export const ERROR_CODES = {
|
|
3
|
+
DURON_ERROR: 'DURON_ERROR',
|
|
4
|
+
STEP_ALREADY_EXECUTED: 'STEP_ALREADY_EXECUTED',
|
|
5
|
+
NON_RETRIABLE: 'NON_RETRIABLE',
|
|
6
|
+
ACTION_TIMEOUT: 'ACTION_TIMEOUT',
|
|
7
|
+
STEP_TIMEOUT: 'STEP_TIMEOUT',
|
|
8
|
+
ACTION_CANCEL: 'ACTION_CANCEL',
|
|
9
|
+
UNHANDLED_CHILD_STEPS: 'UNHANDLED_CHILD_STEPS',
|
|
10
|
+
} as const
|
|
11
|
+
|
|
12
|
+
export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES]
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Metadata about the context where an error occurred.
|
|
16
|
+
*/
|
|
17
|
+
export interface ErrorMetadata {
|
|
18
|
+
jobId?: string
|
|
19
|
+
stepId?: string
|
|
20
|
+
parentStepId?: string | null
|
|
21
|
+
actionName?: string
|
|
22
|
+
stepName?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
1
25
|
/**
|
|
2
26
|
* Base class for all built-in errors in Duron.
|
|
3
27
|
* All errors include a cause property that can be serialized.
|
|
4
28
|
*/
|
|
5
29
|
export abstract class DuronError extends Error {
|
|
30
|
+
/**
|
|
31
|
+
* Error code for type checking without instanceof.
|
|
32
|
+
*/
|
|
33
|
+
public readonly code: ErrorCode = ERROR_CODES.DURON_ERROR
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Whether this error should prevent retries.
|
|
37
|
+
*/
|
|
38
|
+
public readonly nonRetriable: boolean = false
|
|
39
|
+
|
|
6
40
|
/**
|
|
7
41
|
* The underlying cause of the error, if any.
|
|
8
42
|
*
|
|
@@ -10,6 +44,11 @@ export abstract class DuronError extends Error {
|
|
|
10
44
|
*/
|
|
11
45
|
public override readonly cause?: unknown
|
|
12
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Metadata about the context where the error occurred.
|
|
49
|
+
*/
|
|
50
|
+
public metadata: ErrorMetadata
|
|
51
|
+
|
|
13
52
|
constructor(
|
|
14
53
|
message: string,
|
|
15
54
|
options?: {
|
|
@@ -19,10 +58,15 @@ export abstract class DuronError extends Error {
|
|
|
19
58
|
* This will be serialized and stored in the database.
|
|
20
59
|
*/
|
|
21
60
|
cause?: unknown
|
|
61
|
+
/**
|
|
62
|
+
* Metadata about the context where the error occurred.
|
|
63
|
+
*/
|
|
64
|
+
metadata?: ErrorMetadata
|
|
22
65
|
},
|
|
23
66
|
) {
|
|
24
67
|
super(message)
|
|
25
68
|
this.cause = options?.cause
|
|
69
|
+
this.metadata = options?.metadata ?? {}
|
|
26
70
|
// Set the name to the class name
|
|
27
71
|
this.name = this.constructor.name
|
|
28
72
|
// Ensure stack trace points to the error location
|
|
@@ -30,12 +74,27 @@ export abstract class DuronError extends Error {
|
|
|
30
74
|
Error.captureStackTrace(this, this.constructor)
|
|
31
75
|
}
|
|
32
76
|
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Set or update metadata about the context where the error occurred.
|
|
80
|
+
* Merges with existing metadata (new values override existing ones).
|
|
81
|
+
*
|
|
82
|
+
* @param metadata - The metadata to set or merge
|
|
83
|
+
* @returns this - Returns the error instance for chaining
|
|
84
|
+
*/
|
|
85
|
+
setMetadata(metadata: ErrorMetadata): this {
|
|
86
|
+
this.metadata = { ...this.metadata, ...metadata }
|
|
87
|
+
return this
|
|
88
|
+
}
|
|
33
89
|
}
|
|
34
90
|
|
|
35
91
|
/**
|
|
36
92
|
* Error thrown when attempting to execute a step that has already been executed.
|
|
37
93
|
*/
|
|
38
94
|
export class StepAlreadyExecutedError extends DuronError {
|
|
95
|
+
public override readonly code = ERROR_CODES.STEP_ALREADY_EXECUTED
|
|
96
|
+
public override readonly nonRetriable = true
|
|
97
|
+
|
|
39
98
|
/**
|
|
40
99
|
* Create a new StepAlreadyExecutedError.
|
|
41
100
|
*
|
|
@@ -44,7 +103,9 @@ export class StepAlreadyExecutedError extends DuronError {
|
|
|
44
103
|
* @param actionName - The name of the action containing the step
|
|
45
104
|
*/
|
|
46
105
|
constructor(stepName: string, jobId: string, actionName: string) {
|
|
47
|
-
super(`Step "${stepName}" has already been executed for job "${jobId}" and action "${actionName}"
|
|
106
|
+
super(`Step "${stepName}" has already been executed for job "${jobId}" and action "${actionName}"`, {
|
|
107
|
+
metadata: { stepName, jobId, actionName },
|
|
108
|
+
})
|
|
48
109
|
}
|
|
49
110
|
}
|
|
50
111
|
|
|
@@ -55,28 +116,37 @@ export class StepAlreadyExecutedError extends DuronError {
|
|
|
55
116
|
* without retrying, even if retry options are configured.
|
|
56
117
|
*/
|
|
57
118
|
export class NonRetriableError extends DuronError {
|
|
58
|
-
|
|
119
|
+
public override readonly code: ErrorCode = ERROR_CODES.NON_RETRIABLE
|
|
120
|
+
public override readonly nonRetriable = true
|
|
59
121
|
}
|
|
60
122
|
|
|
61
123
|
/**
|
|
62
124
|
* Error thrown when an action exceeds its timeout.
|
|
63
125
|
*/
|
|
64
126
|
export class ActionTimeoutError extends DuronError {
|
|
127
|
+
public override readonly code = ERROR_CODES.ACTION_TIMEOUT
|
|
128
|
+
public override readonly nonRetriable = true
|
|
129
|
+
|
|
65
130
|
/**
|
|
66
131
|
* Create a new ActionTimeoutError.
|
|
67
132
|
*
|
|
68
133
|
* @param actionName - The name of the action that timed out
|
|
134
|
+
* @param jobId - The ID of the job containing the action
|
|
69
135
|
* @param timeoutMs - The timeout value in milliseconds
|
|
70
136
|
* @param options - Optional error options including cause
|
|
71
137
|
*/
|
|
72
138
|
constructor(
|
|
73
139
|
actionName: string,
|
|
140
|
+
jobId: string,
|
|
74
141
|
timeoutMs: number,
|
|
75
142
|
options?: {
|
|
76
143
|
cause?: unknown
|
|
77
144
|
},
|
|
78
145
|
) {
|
|
79
|
-
super(`Action "${actionName}" timed out after ${timeoutMs}ms`,
|
|
146
|
+
super(`Action "${actionName}" in job "${jobId}" timed out after ${timeoutMs}ms`, {
|
|
147
|
+
cause: options?.cause,
|
|
148
|
+
metadata: { actionName, jobId },
|
|
149
|
+
})
|
|
80
150
|
}
|
|
81
151
|
}
|
|
82
152
|
|
|
@@ -84,13 +154,16 @@ export class ActionTimeoutError extends DuronError {
|
|
|
84
154
|
* Error thrown when a step exceeds its timeout.
|
|
85
155
|
*/
|
|
86
156
|
export class StepTimeoutError extends DuronError {
|
|
157
|
+
public override readonly code = ERROR_CODES.STEP_TIMEOUT
|
|
158
|
+
public override readonly nonRetriable = false
|
|
159
|
+
|
|
87
160
|
/**
|
|
88
161
|
* Create a new StepTimeoutError.
|
|
89
162
|
*
|
|
90
163
|
* @param stepName - The name of the step that timed out
|
|
91
164
|
* @param jobId - The ID of the job containing the step
|
|
92
165
|
* @param timeoutMs - The timeout value in milliseconds
|
|
93
|
-
* @param options - Optional error options including cause
|
|
166
|
+
* @param options - Optional error options including cause and additional metadata
|
|
94
167
|
*/
|
|
95
168
|
constructor(
|
|
96
169
|
stepName: string,
|
|
@@ -98,9 +171,21 @@ export class StepTimeoutError extends DuronError {
|
|
|
98
171
|
timeoutMs: number,
|
|
99
172
|
options?: {
|
|
100
173
|
cause?: unknown
|
|
174
|
+
stepId?: string
|
|
175
|
+
parentStepId?: string | null
|
|
176
|
+
actionName?: string
|
|
101
177
|
},
|
|
102
178
|
) {
|
|
103
|
-
super(`Step "${stepName}" in job "${jobId}" timed out after ${timeoutMs}ms`,
|
|
179
|
+
super(`Step "${stepName}" in job "${jobId}" timed out after ${timeoutMs}ms`, {
|
|
180
|
+
cause: options?.cause,
|
|
181
|
+
metadata: {
|
|
182
|
+
stepName,
|
|
183
|
+
jobId,
|
|
184
|
+
stepId: options?.stepId,
|
|
185
|
+
parentStepId: options?.parentStepId,
|
|
186
|
+
actionName: options?.actionName,
|
|
187
|
+
},
|
|
188
|
+
})
|
|
104
189
|
}
|
|
105
190
|
}
|
|
106
191
|
|
|
@@ -108,6 +193,9 @@ export class StepTimeoutError extends DuronError {
|
|
|
108
193
|
* Error thrown when an action is cancelled.
|
|
109
194
|
*/
|
|
110
195
|
export class ActionCancelError extends DuronError {
|
|
196
|
+
public override readonly code = ERROR_CODES.ACTION_CANCEL
|
|
197
|
+
public override readonly nonRetriable = true
|
|
198
|
+
|
|
111
199
|
/**
|
|
112
200
|
* Create a new ActionCancelError.
|
|
113
201
|
*
|
|
@@ -122,7 +210,10 @@ export class ActionCancelError extends DuronError {
|
|
|
122
210
|
cause?: unknown
|
|
123
211
|
},
|
|
124
212
|
) {
|
|
125
|
-
super(`Action "${actionName}" in job "${jobId}" was cancelled`,
|
|
213
|
+
super(`Action "${actionName}" in job "${jobId}" was cancelled`, {
|
|
214
|
+
cause: options?.cause,
|
|
215
|
+
metadata: { actionName, jobId },
|
|
216
|
+
})
|
|
126
217
|
}
|
|
127
218
|
}
|
|
128
219
|
|
|
@@ -133,10 +224,7 @@ export class ActionCancelError extends DuronError {
|
|
|
133
224
|
* but not properly awaited. All child steps must be awaited before the parent returns.
|
|
134
225
|
*/
|
|
135
226
|
export class UnhandledChildStepsError extends NonRetriableError {
|
|
136
|
-
|
|
137
|
-
* The name of the parent step that completed with unhandled children.
|
|
138
|
-
*/
|
|
139
|
-
public readonly stepName: string
|
|
227
|
+
public override readonly code = ERROR_CODES.UNHANDLED_CHILD_STEPS
|
|
140
228
|
|
|
141
229
|
/**
|
|
142
230
|
* The number of unhandled child steps.
|
|
@@ -148,12 +236,30 @@ export class UnhandledChildStepsError extends NonRetriableError {
|
|
|
148
236
|
*
|
|
149
237
|
* @param stepName - The name of the parent step
|
|
150
238
|
* @param pendingCount - The number of unhandled child steps
|
|
239
|
+
* @param options - Optional metadata
|
|
151
240
|
*/
|
|
152
|
-
constructor(
|
|
241
|
+
constructor(
|
|
242
|
+
stepName: string,
|
|
243
|
+
pendingCount: number,
|
|
244
|
+
options?: {
|
|
245
|
+
stepId?: string
|
|
246
|
+
parentStepId?: string | null
|
|
247
|
+
jobId?: string
|
|
248
|
+
actionName?: string
|
|
249
|
+
},
|
|
250
|
+
) {
|
|
153
251
|
super(
|
|
154
252
|
`Parent step "${stepName}" completed with ${pendingCount} unhandled child step(s). All child steps must be awaited before the parent returns.`,
|
|
253
|
+
{
|
|
254
|
+
metadata: {
|
|
255
|
+
stepName,
|
|
256
|
+
stepId: options?.stepId,
|
|
257
|
+
parentStepId: options?.parentStepId,
|
|
258
|
+
jobId: options?.jobId,
|
|
259
|
+
actionName: options?.actionName,
|
|
260
|
+
},
|
|
261
|
+
},
|
|
155
262
|
)
|
|
156
|
-
this.stepName = stepName
|
|
157
263
|
this.pendingCount = pendingCount
|
|
158
264
|
}
|
|
159
265
|
}
|
|
@@ -162,45 +268,45 @@ export class UnhandledChildStepsError extends NonRetriableError {
|
|
|
162
268
|
* Checks if an error is a DuronError instance.
|
|
163
269
|
*/
|
|
164
270
|
export function isDuronError(error: unknown): error is DuronError {
|
|
165
|
-
|
|
271
|
+
const code = (error as any)?.code
|
|
272
|
+
return code !== undefined && Object.values(ERROR_CODES).includes(code)
|
|
166
273
|
}
|
|
167
274
|
|
|
168
275
|
/**
|
|
169
276
|
* Checks if an error is a NonRetriableError instance.
|
|
170
277
|
*/
|
|
171
278
|
export function isNonRetriableError(error: unknown): error is NonRetriableError {
|
|
172
|
-
return (
|
|
173
|
-
error instanceof NonRetriableError ||
|
|
174
|
-
error instanceof ActionCancelError ||
|
|
175
|
-
error instanceof ActionTimeoutError ||
|
|
176
|
-
error instanceof UnhandledChildStepsError
|
|
177
|
-
)
|
|
279
|
+
return (error as any)?.nonRetriable === true
|
|
178
280
|
}
|
|
179
281
|
|
|
180
282
|
/**
|
|
181
283
|
* Checks if an error is an UnhandledChildStepsError instance.
|
|
182
284
|
*/
|
|
183
285
|
export function isUnhandledChildStepsError(error: unknown): error is UnhandledChildStepsError {
|
|
184
|
-
return error
|
|
286
|
+
return (error as any)?.code === ERROR_CODES.UNHANDLED_CHILD_STEPS
|
|
185
287
|
}
|
|
186
288
|
|
|
187
289
|
/**
|
|
188
290
|
* Checks if an error is a timeout error (ActionTimeoutError or StepTimeoutError).
|
|
189
291
|
*/
|
|
190
292
|
export function isTimeoutError(error: unknown): error is ActionTimeoutError | StepTimeoutError {
|
|
191
|
-
|
|
293
|
+
const code = (error as any)?.code
|
|
294
|
+
return code === ERROR_CODES.ACTION_TIMEOUT || code === ERROR_CODES.STEP_TIMEOUT
|
|
192
295
|
}
|
|
193
296
|
|
|
194
297
|
/**
|
|
195
298
|
* Checks if an error is a cancel error (ActionCancelError or StepCancelError).
|
|
196
299
|
*/
|
|
197
300
|
export function isCancelError(error: unknown): error is ActionCancelError {
|
|
198
|
-
return error
|
|
301
|
+
return (error as any)?.code === ERROR_CODES.ACTION_CANCEL
|
|
199
302
|
}
|
|
200
303
|
|
|
201
304
|
export type SerializableError = {
|
|
202
305
|
name: string
|
|
203
306
|
message: string
|
|
307
|
+
code?: ErrorCode
|
|
308
|
+
nonRetriable?: boolean
|
|
309
|
+
metadata?: ErrorMetadata
|
|
204
310
|
cause?: unknown
|
|
205
311
|
stack?: string
|
|
206
312
|
}
|
|
@@ -209,25 +315,30 @@ export type SerializableError = {
|
|
|
209
315
|
* Serializes an error for storage in the database.
|
|
210
316
|
* Handles DuronError instances specially to preserve their type information.
|
|
211
317
|
*/
|
|
212
|
-
export function serializeError(error: unknown): {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (error instanceof StepTimeoutError || error instanceof ActionTimeoutError) {
|
|
318
|
+
export function serializeError(error: unknown): SerializableError {
|
|
319
|
+
const code = (error as any)?.code
|
|
320
|
+
const nonRetriable = (error as any)?.nonRetriable
|
|
321
|
+
const metadata = (error as any)?.metadata
|
|
322
|
+
|
|
323
|
+
if (isTimeoutError(error)) {
|
|
219
324
|
return {
|
|
220
325
|
name: error.name,
|
|
221
326
|
message: error.message,
|
|
327
|
+
code,
|
|
328
|
+
nonRetriable,
|
|
329
|
+
metadata,
|
|
222
330
|
cause: error.cause,
|
|
223
331
|
stack: undefined,
|
|
224
332
|
}
|
|
225
333
|
}
|
|
226
334
|
|
|
227
|
-
if (error
|
|
335
|
+
if (isDuronError(error)) {
|
|
228
336
|
return {
|
|
229
337
|
name: error.name,
|
|
230
338
|
message: error.message,
|
|
339
|
+
code,
|
|
340
|
+
nonRetriable,
|
|
341
|
+
metadata,
|
|
231
342
|
cause: error.cause,
|
|
232
343
|
stack: error.stack,
|
|
233
344
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,11 +7,13 @@ export {
|
|
|
7
7
|
type StepDefinition,
|
|
8
8
|
type StepDefinitionHandlerContext,
|
|
9
9
|
type StepDefinitionInput,
|
|
10
|
+
type StepNameContext,
|
|
10
11
|
} from './action.js'
|
|
11
12
|
export * from './client.js'
|
|
12
13
|
export * from './constants.js'
|
|
13
14
|
export { NonRetriableError, UnhandledChildStepsError } from './errors.js'
|
|
14
15
|
export * from './server.js'
|
|
16
|
+
export type { TelemetryContext } from './step-manager.js'
|
|
15
17
|
export * from './telemetry/index.js'
|
|
16
18
|
|
|
17
19
|
export const duron = <
|
package/src/server.ts
CHANGED
|
@@ -2,21 +2,21 @@ import { Elysia } from 'elysia'
|
|
|
2
2
|
import { jwtVerify, SignJWT } from 'jose'
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
|
|
5
|
-
import type { GetJobStepsOptions, GetJobsOptions,
|
|
5
|
+
import type { GetJobStepsOptions, GetJobsOptions, GetSpansOptions } from './adapters/adapter.js'
|
|
6
6
|
import {
|
|
7
7
|
GetActionsResultSchema,
|
|
8
8
|
GetJobStepsResultSchema,
|
|
9
9
|
GetJobsResultSchema,
|
|
10
|
-
|
|
10
|
+
GetSpansResultSchema,
|
|
11
11
|
JobSchema,
|
|
12
12
|
JobSortFieldSchema,
|
|
13
13
|
JobStatusResultSchema,
|
|
14
14
|
JobStatusSchema,
|
|
15
15
|
JobStepSchema,
|
|
16
16
|
JobStepStatusResultSchema,
|
|
17
|
-
MetricSortFieldSchema,
|
|
18
|
-
MetricTypeSchema,
|
|
19
17
|
SortOrderSchema,
|
|
18
|
+
SpanKindSchema,
|
|
19
|
+
SpanSortFieldSchema,
|
|
20
20
|
} from './adapters/schemas.js'
|
|
21
21
|
import type { Client } from './client.js'
|
|
22
22
|
|
|
@@ -86,6 +86,7 @@ export const GetJobsQuerySchema = z
|
|
|
86
86
|
fActionName: z.union([z.string(), z.array(z.string())]).optional(),
|
|
87
87
|
fGroupKey: z.union([z.string(), z.array(z.string())]).optional(),
|
|
88
88
|
fClientId: z.union([z.string(), z.array(z.string())]).optional(),
|
|
89
|
+
fDescription: z.string().optional(),
|
|
89
90
|
// Date filters: can be a single ISO string or JSON array [start, end] - both coerced to Date objects
|
|
90
91
|
fCreatedAt: z.union([z.coerce.date(), z.array(z.coerce.date())]).optional(),
|
|
91
92
|
fStartedAt: z.union([z.coerce.date(), z.array(z.coerce.date())]).optional(),
|
|
@@ -107,6 +108,7 @@ export const GetJobsQuerySchema = z
|
|
|
107
108
|
if (data.fActionName) filters.actionName = data.fActionName
|
|
108
109
|
if (data.fGroupKey) filters.groupKey = data.fGroupKey
|
|
109
110
|
if (data.fClientId) filters.clientId = data.fClientId
|
|
111
|
+
if (data.fDescription) filters.description = data.fDescription
|
|
110
112
|
if (data.fCreatedAt) filters.createdAt = data.fCreatedAt
|
|
111
113
|
if (data.fStartedAt) filters.startedAt = data.fStartedAt
|
|
112
114
|
if (data.fFinishedAt) filters.finishedAt = data.fFinishedAt
|
|
@@ -176,13 +178,13 @@ export const GetActionsMetadataResponseSchema = z.array(
|
|
|
176
178
|
export type GetJobsQueryInput = z.input<typeof GetJobsQuerySchema>
|
|
177
179
|
export type GetJobStepsQueryInput = z.input<typeof GetJobStepsQuerySchema>
|
|
178
180
|
|
|
179
|
-
//
|
|
180
|
-
export const
|
|
181
|
+
// Spans query schema
|
|
182
|
+
export const GetSpansQuerySchema = z
|
|
181
183
|
.object({
|
|
182
184
|
// Filters
|
|
183
185
|
fName: z.union([z.string(), z.array(z.string())]).optional(),
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
fKind: z.union([SpanKindSchema, z.array(SpanKindSchema)]).optional(),
|
|
187
|
+
fTraceId: z.string().optional(),
|
|
186
188
|
fAttributesFilter: z.record(z.string(), z.any()).optional(),
|
|
187
189
|
|
|
188
190
|
// Sort - format: "field:asc" or "field:desc"
|
|
@@ -192,16 +194,16 @@ export const GetMetricsQuerySchema = z
|
|
|
192
194
|
const filters: any = {}
|
|
193
195
|
|
|
194
196
|
if (data.fName) filters.name = data.fName
|
|
195
|
-
if (data.
|
|
196
|
-
if (data.
|
|
197
|
+
if (data.fKind) filters.kind = data.fKind
|
|
198
|
+
if (data.fTraceId) filters.traceId = data.fTraceId
|
|
197
199
|
if (data.fAttributesFilter) filters.attributesFilter = data.fAttributesFilter
|
|
198
200
|
|
|
199
201
|
// Parse sort string: "field:asc" -> { field: 'field', order: 'asc' }
|
|
200
|
-
let sort: { field: z.infer<typeof
|
|
202
|
+
let sort: { field: z.infer<typeof SpanSortFieldSchema>; order: z.infer<typeof SortOrderSchema> } | undefined
|
|
201
203
|
if (data.sort) {
|
|
202
204
|
const [field, order] = data.sort.split(':').map((s) => s.trim())
|
|
203
205
|
if (field && order) {
|
|
204
|
-
const fieldResult =
|
|
206
|
+
const fieldResult = SpanSortFieldSchema.safeParse(field)
|
|
205
207
|
const orderResult = SortOrderSchema.safeParse(order.toLowerCase())
|
|
206
208
|
if (fieldResult.success && orderResult.success) {
|
|
207
209
|
sort = {
|
|
@@ -218,7 +220,7 @@ export const GetMetricsQuerySchema = z
|
|
|
218
220
|
}
|
|
219
221
|
})
|
|
220
222
|
|
|
221
|
-
export type
|
|
223
|
+
export type GetSpansQueryInput = z.input<typeof GetSpansQuerySchema>
|
|
222
224
|
|
|
223
225
|
export const ErrorResponseSchema = z.object({
|
|
224
226
|
error: z.string(),
|
|
@@ -269,12 +271,12 @@ export interface CreateServerOptions<P extends string> {
|
|
|
269
271
|
prefix?: P
|
|
270
272
|
|
|
271
273
|
/**
|
|
272
|
-
* Enable
|
|
273
|
-
* Only works when client is configured with
|
|
274
|
-
* When true, enables the dashboard to show
|
|
275
|
-
* @default auto-detected from client.
|
|
274
|
+
* Enable spans endpoints (/jobs/:id/spans, /steps/:id/spans).
|
|
275
|
+
* Only works when client is configured with telemetry.local enabled.
|
|
276
|
+
* When true, enables the dashboard to show spans buttons.
|
|
277
|
+
* @default auto-detected from client.spansEnabled
|
|
276
278
|
*/
|
|
277
|
-
|
|
279
|
+
spansEnabled?: boolean
|
|
278
280
|
|
|
279
281
|
login?: {
|
|
280
282
|
onLogin: (body: { email: string; password: string }) => Promise<boolean>
|
|
@@ -297,14 +299,14 @@ export interface CreateServerOptions<P extends string> {
|
|
|
297
299
|
* @param options - Configuration options
|
|
298
300
|
* @returns Elysia server instance
|
|
299
301
|
*/
|
|
300
|
-
export function createServer<P extends string>({ client, prefix, login,
|
|
302
|
+
export function createServer<P extends string>({ client, prefix, login, spansEnabled }: CreateServerOptions<P>) {
|
|
301
303
|
// Convert string secret to Uint8Array if needed
|
|
302
304
|
const secretKey = typeof login?.jwtSecret === 'string' ? new TextEncoder().encode(login?.jwtSecret) : login?.jwtSecret
|
|
303
305
|
|
|
304
306
|
const routePrefix = (prefix ?? '/api') as P
|
|
305
307
|
|
|
306
|
-
// Auto-detect
|
|
307
|
-
const
|
|
308
|
+
// Auto-detect spansEnabled from client if not explicitly set
|
|
309
|
+
const isSpansEnabled = spansEnabled ?? client.spansEnabled
|
|
308
310
|
|
|
309
311
|
return new Elysia({
|
|
310
312
|
prefix: routePrefix,
|
|
@@ -670,14 +672,14 @@ export function createServer<P extends string>({ client, prefix, login, metricsE
|
|
|
670
672
|
'/config',
|
|
671
673
|
async () => {
|
|
672
674
|
return {
|
|
673
|
-
|
|
675
|
+
spansEnabled: isSpansEnabled,
|
|
674
676
|
authEnabled: !!login,
|
|
675
677
|
}
|
|
676
678
|
},
|
|
677
679
|
{
|
|
678
680
|
response: {
|
|
679
681
|
200: z.object({
|
|
680
|
-
|
|
682
|
+
spansEnabled: z.boolean(),
|
|
681
683
|
authEnabled: z.boolean(),
|
|
682
684
|
}),
|
|
683
685
|
500: ErrorResponseSchema,
|
|
@@ -685,23 +687,23 @@ export function createServer<P extends string>({ client, prefix, login, metricsE
|
|
|
685
687
|
},
|
|
686
688
|
)
|
|
687
689
|
.get(
|
|
688
|
-
'/jobs/:id/
|
|
690
|
+
'/jobs/:id/spans',
|
|
689
691
|
async ({ params, query }) => {
|
|
690
|
-
if (!
|
|
691
|
-
throw new Error('
|
|
692
|
+
if (!isSpansEnabled) {
|
|
693
|
+
throw new Error('Spans are not enabled. Enable telemetry.local to enable spans.')
|
|
692
694
|
}
|
|
693
|
-
const options:
|
|
695
|
+
const options: GetSpansOptions = {
|
|
694
696
|
jobId: params.id,
|
|
695
697
|
filters: query.filters,
|
|
696
698
|
sort: query.sort,
|
|
697
699
|
}
|
|
698
|
-
return client.
|
|
700
|
+
return client.getSpans(options)
|
|
699
701
|
},
|
|
700
702
|
{
|
|
701
703
|
params: JobIdParamsSchema,
|
|
702
|
-
query:
|
|
704
|
+
query: GetSpansQuerySchema,
|
|
703
705
|
response: {
|
|
704
|
-
200:
|
|
706
|
+
200: GetSpansResultSchema,
|
|
705
707
|
400: ErrorResponseSchema,
|
|
706
708
|
500: ErrorResponseSchema,
|
|
707
709
|
401: ErrorResponseSchema,
|
|
@@ -710,23 +712,23 @@ export function createServer<P extends string>({ client, prefix, login, metricsE
|
|
|
710
712
|
},
|
|
711
713
|
)
|
|
712
714
|
.get(
|
|
713
|
-
'/steps/:id/
|
|
715
|
+
'/steps/:id/spans',
|
|
714
716
|
async ({ params, query }) => {
|
|
715
|
-
if (!
|
|
716
|
-
throw new Error('
|
|
717
|
+
if (!isSpansEnabled) {
|
|
718
|
+
throw new Error('Spans are not enabled. Enable telemetry.local to enable spans.')
|
|
717
719
|
}
|
|
718
|
-
const options:
|
|
720
|
+
const options: GetSpansOptions = {
|
|
719
721
|
stepId: params.id,
|
|
720
722
|
filters: query.filters,
|
|
721
723
|
sort: query.sort,
|
|
722
724
|
}
|
|
723
|
-
return client.
|
|
725
|
+
return client.getSpans(options)
|
|
724
726
|
},
|
|
725
727
|
{
|
|
726
728
|
params: StepIdParamsSchema,
|
|
727
|
-
query:
|
|
729
|
+
query: GetSpansQuerySchema,
|
|
728
730
|
response: {
|
|
729
|
-
200:
|
|
731
|
+
200: GetSpansResultSchema,
|
|
730
732
|
400: ErrorResponseSchema,
|
|
731
733
|
500: ErrorResponseSchema,
|
|
732
734
|
401: ErrorResponseSchema,
|