duron 0.1.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.
Files changed (82) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +140 -0
  3. package/dist/action-job.d.ts +24 -0
  4. package/dist/action-job.d.ts.map +1 -0
  5. package/dist/action-job.js +108 -0
  6. package/dist/action-manager.d.ts +21 -0
  7. package/dist/action-manager.d.ts.map +1 -0
  8. package/dist/action-manager.js +78 -0
  9. package/dist/action.d.ts +129 -0
  10. package/dist/action.d.ts.map +1 -0
  11. package/dist/action.js +87 -0
  12. package/dist/adapters/adapter.d.ts +92 -0
  13. package/dist/adapters/adapter.d.ts.map +1 -0
  14. package/dist/adapters/adapter.js +424 -0
  15. package/dist/adapters/postgres/drizzle.config.d.ts +3 -0
  16. package/dist/adapters/postgres/drizzle.config.d.ts.map +1 -0
  17. package/dist/adapters/postgres/drizzle.config.js +10 -0
  18. package/dist/adapters/postgres/pglite.d.ts +13 -0
  19. package/dist/adapters/postgres/pglite.d.ts.map +1 -0
  20. package/dist/adapters/postgres/pglite.js +36 -0
  21. package/dist/adapters/postgres/postgres.d.ts +51 -0
  22. package/dist/adapters/postgres/postgres.d.ts.map +1 -0
  23. package/dist/adapters/postgres/postgres.js +867 -0
  24. package/dist/adapters/postgres/schema.d.ts +581 -0
  25. package/dist/adapters/postgres/schema.d.ts.map +1 -0
  26. package/dist/adapters/postgres/schema.default.d.ts +577 -0
  27. package/dist/adapters/postgres/schema.default.d.ts.map +1 -0
  28. package/dist/adapters/postgres/schema.default.js +3 -0
  29. package/dist/adapters/postgres/schema.js +87 -0
  30. package/dist/adapters/schemas.d.ts +516 -0
  31. package/dist/adapters/schemas.d.ts.map +1 -0
  32. package/dist/adapters/schemas.js +184 -0
  33. package/dist/client.d.ts +85 -0
  34. package/dist/client.d.ts.map +1 -0
  35. package/dist/client.js +416 -0
  36. package/dist/constants.d.ts +14 -0
  37. package/dist/constants.d.ts.map +1 -0
  38. package/dist/constants.js +22 -0
  39. package/dist/errors.d.ts +43 -0
  40. package/dist/errors.d.ts.map +1 -0
  41. package/dist/errors.js +75 -0
  42. package/dist/index.d.ts +8 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +6 -0
  45. package/dist/server.d.ts +1193 -0
  46. package/dist/server.d.ts.map +1 -0
  47. package/dist/server.js +516 -0
  48. package/dist/step-manager.d.ts +46 -0
  49. package/dist/step-manager.d.ts.map +1 -0
  50. package/dist/step-manager.js +216 -0
  51. package/dist/utils/checksum.d.ts +2 -0
  52. package/dist/utils/checksum.d.ts.map +1 -0
  53. package/dist/utils/checksum.js +6 -0
  54. package/dist/utils/p-retry.d.ts +19 -0
  55. package/dist/utils/p-retry.d.ts.map +1 -0
  56. package/dist/utils/p-retry.js +130 -0
  57. package/dist/utils/wait-for-abort.d.ts +5 -0
  58. package/dist/utils/wait-for-abort.d.ts.map +1 -0
  59. package/dist/utils/wait-for-abort.js +32 -0
  60. package/migrations/postgres/0000_lethal_speed_demon.sql +64 -0
  61. package/migrations/postgres/meta/0000_snapshot.json +606 -0
  62. package/migrations/postgres/meta/_journal.json +13 -0
  63. package/package.json +88 -0
  64. package/src/action-job.ts +201 -0
  65. package/src/action-manager.ts +166 -0
  66. package/src/action.ts +247 -0
  67. package/src/adapters/adapter.ts +969 -0
  68. package/src/adapters/postgres/drizzle.config.ts +11 -0
  69. package/src/adapters/postgres/pglite.ts +86 -0
  70. package/src/adapters/postgres/postgres.ts +1346 -0
  71. package/src/adapters/postgres/schema.default.ts +5 -0
  72. package/src/adapters/postgres/schema.ts +119 -0
  73. package/src/adapters/schemas.ts +320 -0
  74. package/src/client.ts +859 -0
  75. package/src/constants.ts +37 -0
  76. package/src/errors.ts +205 -0
  77. package/src/index.ts +14 -0
  78. package/src/server.ts +718 -0
  79. package/src/step-manager.ts +471 -0
  80. package/src/utils/checksum.ts +7 -0
  81. package/src/utils/p-retry.ts +213 -0
  82. package/src/utils/wait-for-abort.ts +40 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/server.js ADDED
@@ -0,0 +1,516 @@
1
+ import { Elysia } from 'elysia';
2
+ import { jwtVerify, SignJWT } from 'jose';
3
+ import { z } from 'zod';
4
+ import { GetActionsResultSchema, GetJobStepsResultSchema, GetJobsResultSchema, JobSchema, JobSortFieldSchema, JobStatusResultSchema, JobStatusSchema, JobStepSchema, JobStepStatusResultSchema, SortOrderSchema, } from './adapters/schemas.js';
5
+ export class NotFoundError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = 'NotFoundError';
9
+ }
10
+ }
11
+ export class UnauthorizedError extends Error {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = 'UnauthorizedError';
15
+ }
16
+ }
17
+ export const GetJobStepsQuerySchema = z
18
+ .object({
19
+ page: z.coerce.number().int().min(1).optional(),
20
+ pageSize: z.coerce.number().int().min(1).max(1000).optional(),
21
+ search: z.string().optional(),
22
+ fUpdatedAfter: z.coerce.date().optional(),
23
+ })
24
+ .transform((data) => ({
25
+ page: data.page,
26
+ pageSize: data.pageSize,
27
+ search: data.search,
28
+ updatedAfter: data.fUpdatedAfter,
29
+ }));
30
+ export const GetJobStepsResponseSchema = GetJobStepsResultSchema;
31
+ export const GetJobsQuerySchema = z
32
+ .object({
33
+ page: z.coerce.number().int().min(1).optional(),
34
+ pageSize: z.coerce.number().int().min(1).max(1000).optional(),
35
+ fStatus: z.union([JobStatusSchema, z.array(JobStatusSchema)]).optional(),
36
+ fActionName: z.union([z.string(), z.array(z.string())]).optional(),
37
+ fGroupKey: z.union([z.string(), z.array(z.string())]).optional(),
38
+ fOwnerId: z.union([z.string(), z.array(z.string())]).optional(),
39
+ fCreatedAt: z.union([z.coerce.date(), z.array(z.coerce.date())]).optional(),
40
+ fStartedAt: z.union([z.coerce.date(), z.array(z.coerce.date())]).optional(),
41
+ fFinishedAt: z.union([z.coerce.date(), z.array(z.coerce.date())]).optional(),
42
+ fUpdatedAfter: z.coerce.date().optional(),
43
+ fSearch: z.string().optional(),
44
+ sort: z.string().optional(),
45
+ fInputFilter: z.record(z.string(), z.any()).optional(),
46
+ fOutputFilter: z.record(z.string(), z.any()).optional(),
47
+ })
48
+ .transform((data) => {
49
+ const filters = {};
50
+ if (data.fStatus)
51
+ filters.status = data.fStatus;
52
+ if (data.fActionName)
53
+ filters.actionName = data.fActionName;
54
+ if (data.fGroupKey)
55
+ filters.groupKey = data.fGroupKey;
56
+ if (data.fOwnerId)
57
+ filters.ownerId = data.fOwnerId;
58
+ if (data.fCreatedAt)
59
+ filters.createdAt = data.fCreatedAt;
60
+ if (data.fStartedAt)
61
+ filters.startedAt = data.fStartedAt;
62
+ if (data.fFinishedAt)
63
+ filters.finishedAt = data.fFinishedAt;
64
+ if (data.fUpdatedAfter)
65
+ filters.updatedAfter = data.fUpdatedAfter;
66
+ if (data.fSearch)
67
+ filters.search = data.fSearch;
68
+ if (data.fInputFilter)
69
+ filters.inputFilter = data.fInputFilter;
70
+ if (data.fOutputFilter)
71
+ filters.outputFilter = data.fOutputFilter;
72
+ let sort;
73
+ if (data.sort) {
74
+ const sortParts = data.sort
75
+ .split(',')
76
+ .map((part) => part.trim())
77
+ .filter((part) => part.length > 0);
78
+ const parsedSorts = sortParts
79
+ .map((part) => {
80
+ const [field, order] = part.split(':').map((s) => s.trim());
81
+ if (!field || !order) {
82
+ return null;
83
+ }
84
+ const fieldResult = JobSortFieldSchema.safeParse(field);
85
+ const orderResult = SortOrderSchema.safeParse(order.toLowerCase());
86
+ if (!fieldResult.success || !orderResult.success) {
87
+ return null;
88
+ }
89
+ return {
90
+ field: fieldResult.data,
91
+ order: orderResult.data,
92
+ };
93
+ })
94
+ .filter((s) => s !== null);
95
+ if (parsedSorts.length === 0) {
96
+ sort = undefined;
97
+ }
98
+ else {
99
+ sort = parsedSorts;
100
+ }
101
+ }
102
+ return {
103
+ page: data.page,
104
+ pageSize: data.pageSize,
105
+ filters: Object.keys(filters).length > 0 ? filters : undefined,
106
+ sort,
107
+ };
108
+ });
109
+ export const GetJobsResponseSchema = GetJobsResultSchema;
110
+ export const GetActionsResponseSchema = GetActionsResultSchema;
111
+ export const GetActionsMetadataResponseSchema = z.array(z.object({
112
+ name: z.string(),
113
+ mockInput: z.any(),
114
+ }));
115
+ export const ErrorResponseSchema = z.object({
116
+ error: z.string(),
117
+ message: z.string().optional(),
118
+ });
119
+ const JobIdParamsSchema = z.object({
120
+ id: z.uuid(),
121
+ });
122
+ const StepIdParamsSchema = z.object({
123
+ id: z.uuid(),
124
+ });
125
+ export const CancelJobResponseSchema = z.object({
126
+ success: z.boolean(),
127
+ message: z.string(),
128
+ });
129
+ export const RetryJobResponseSchema = z.object({
130
+ success: z.boolean(),
131
+ message: z.string(),
132
+ newJobId: z.string(),
133
+ });
134
+ export function createServer({ client, prefix, login }) {
135
+ const secretKey = typeof login?.jwtSecret === 'string' ? new TextEncoder().encode(login?.jwtSecret) : login?.jwtSecret;
136
+ const routePrefix = (prefix ?? '/api');
137
+ return new Elysia({
138
+ prefix: routePrefix,
139
+ })
140
+ .onError(({ code, error, set }) => {
141
+ if (code === 'VALIDATION') {
142
+ set.status = 400;
143
+ return error;
144
+ }
145
+ if (error instanceof NotFoundError) {
146
+ set.status = 404;
147
+ return {
148
+ error: 'Not found',
149
+ message: error.message,
150
+ };
151
+ }
152
+ if (error instanceof UnauthorizedError) {
153
+ set.status = 401;
154
+ return {
155
+ error: 'Unauthorized',
156
+ message: error.message,
157
+ };
158
+ }
159
+ set.status = code === 'NOT_FOUND' ? 404 : 500;
160
+ return {
161
+ error: 'Internal server error',
162
+ message: error instanceof Error ? error.message : 'Unknown error',
163
+ };
164
+ })
165
+ .macro('getUser', {
166
+ headers: z.object({
167
+ authorization: z.string().optional(),
168
+ }),
169
+ resolve: async ({ headers }) => {
170
+ if (login) {
171
+ const authHeader = headers.authorization;
172
+ if (!authHeader) {
173
+ return {
174
+ user: null,
175
+ };
176
+ }
177
+ const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : authHeader;
178
+ if (!token) {
179
+ return {
180
+ user: null,
181
+ };
182
+ }
183
+ const { payload } = await jwtVerify(token, secretKey).catch(() => {
184
+ return {
185
+ payload: null,
186
+ };
187
+ });
188
+ return {
189
+ user: payload,
190
+ };
191
+ }
192
+ return {
193
+ user: null,
194
+ };
195
+ },
196
+ })
197
+ .macro('auth', {
198
+ getUser: true,
199
+ beforeHandle: async ({ user }) => {
200
+ if (login && !user) {
201
+ throw new UnauthorizedError('Unauthorized');
202
+ }
203
+ },
204
+ })
205
+ .get('/jobs/:id', async ({ params }) => {
206
+ const job = await client.getJobById(params.id);
207
+ if (!job) {
208
+ throw new NotFoundError(`Job with ID ${params.id} was not found`);
209
+ }
210
+ return job;
211
+ }, {
212
+ params: JobIdParamsSchema,
213
+ response: {
214
+ 200: JobSchema,
215
+ 404: ErrorResponseSchema,
216
+ 500: ErrorResponseSchema,
217
+ 401: ErrorResponseSchema,
218
+ },
219
+ auth: true,
220
+ })
221
+ .get('/jobs/:id/steps', async ({ params, query }) => {
222
+ const options = {
223
+ jobId: params.id,
224
+ page: query.page,
225
+ pageSize: query.pageSize,
226
+ search: query.search,
227
+ updatedAfter: query.updatedAfter,
228
+ };
229
+ return client.getJobSteps(options);
230
+ }, {
231
+ params: JobIdParamsSchema,
232
+ query: GetJobStepsQuerySchema,
233
+ response: {
234
+ 200: GetJobStepsResponseSchema,
235
+ 400: ErrorResponseSchema,
236
+ 500: ErrorResponseSchema,
237
+ 401: ErrorResponseSchema,
238
+ },
239
+ auth: true,
240
+ })
241
+ .get('/jobs', async ({ query }) => {
242
+ const options = {
243
+ page: query.page,
244
+ pageSize: query.pageSize,
245
+ filters: query.filters,
246
+ sort: query.sort,
247
+ };
248
+ return client.getJobs(options);
249
+ }, {
250
+ query: GetJobsQuerySchema,
251
+ response: {
252
+ 200: GetJobsResponseSchema,
253
+ 400: ErrorResponseSchema,
254
+ 500: ErrorResponseSchema,
255
+ 401: ErrorResponseSchema,
256
+ },
257
+ auth: true,
258
+ })
259
+ .get('/steps/:id', async ({ params }) => {
260
+ const step = await client.getJobStepById(params.id);
261
+ if (!step) {
262
+ throw new NotFoundError(`Step with ID ${params.id} was not found`);
263
+ }
264
+ return step;
265
+ }, {
266
+ params: StepIdParamsSchema,
267
+ response: {
268
+ 200: JobStepSchema,
269
+ 404: ErrorResponseSchema,
270
+ 500: ErrorResponseSchema,
271
+ 401: ErrorResponseSchema,
272
+ },
273
+ auth: true,
274
+ })
275
+ .get('/jobs/:id/status', async ({ params }) => {
276
+ const status = await client.getJobStatus(params.id);
277
+ if (!status) {
278
+ throw new NotFoundError(`Job with ID ${params.id} was not found`);
279
+ }
280
+ return status;
281
+ }, {
282
+ params: JobIdParamsSchema,
283
+ response: {
284
+ 200: JobStatusResultSchema,
285
+ 404: ErrorResponseSchema,
286
+ 500: ErrorResponseSchema,
287
+ 401: ErrorResponseSchema,
288
+ },
289
+ auth: true,
290
+ })
291
+ .get('/steps/:id/status', async ({ params }) => {
292
+ const status = await client.getJobStepStatus(params.id);
293
+ if (!status) {
294
+ throw new NotFoundError(`Step with ID ${params.id} was not found`);
295
+ }
296
+ return status;
297
+ }, {
298
+ params: StepIdParamsSchema,
299
+ response: {
300
+ 200: JobStepStatusResultSchema,
301
+ 404: ErrorResponseSchema,
302
+ 500: ErrorResponseSchema,
303
+ 401: ErrorResponseSchema,
304
+ },
305
+ auth: true,
306
+ })
307
+ .post('/jobs/:id/cancel', async ({ params }) => {
308
+ await client.cancelJob(params.id);
309
+ return {
310
+ success: true,
311
+ message: `Job ${params.id} has been cancelled`,
312
+ };
313
+ }, {
314
+ params: JobIdParamsSchema,
315
+ response: {
316
+ 200: CancelJobResponseSchema,
317
+ 400: ErrorResponseSchema,
318
+ 500: ErrorResponseSchema,
319
+ 401: ErrorResponseSchema,
320
+ },
321
+ auth: true,
322
+ })
323
+ .post('/jobs/:id/retry', async ({ params }) => {
324
+ const newJobId = await client.retryJob(params.id);
325
+ if (!newJobId) {
326
+ throw new Error(`Could not retry job ${params.id}. The job may not be in a retryable state.`);
327
+ }
328
+ return {
329
+ success: true,
330
+ message: `Job ${params.id} has been retried`,
331
+ newJobId,
332
+ };
333
+ }, {
334
+ params: JobIdParamsSchema,
335
+ response: {
336
+ 200: RetryJobResponseSchema,
337
+ 400: ErrorResponseSchema,
338
+ 500: ErrorResponseSchema,
339
+ 401: ErrorResponseSchema,
340
+ },
341
+ auth: true,
342
+ })
343
+ .delete('/jobs/:id', async ({ params }) => {
344
+ const deleted = await client.deleteJob(params.id);
345
+ if (!deleted) {
346
+ throw new NotFoundError(`Job with ID ${params.id} was not found or cannot be deleted (active jobs cannot be deleted)`);
347
+ }
348
+ return {
349
+ success: true,
350
+ message: `Job ${params.id} has been deleted`,
351
+ };
352
+ }, {
353
+ params: JobIdParamsSchema,
354
+ response: {
355
+ 200: z.object({
356
+ success: z.boolean(),
357
+ message: z.string(),
358
+ }),
359
+ 404: ErrorResponseSchema,
360
+ 500: ErrorResponseSchema,
361
+ 401: ErrorResponseSchema,
362
+ },
363
+ auth: true,
364
+ })
365
+ .delete('/jobs', async ({ query }) => {
366
+ const options = {
367
+ page: query.page,
368
+ pageSize: query.pageSize,
369
+ filters: query.filters,
370
+ sort: query.sort,
371
+ };
372
+ const deletedCount = await client.deleteJobs(options);
373
+ return {
374
+ success: true,
375
+ message: `Deleted ${deletedCount} job(s)`,
376
+ deletedCount,
377
+ };
378
+ }, {
379
+ query: GetJobsQuerySchema,
380
+ response: {
381
+ 200: z.object({
382
+ success: z.boolean(),
383
+ message: z.string(),
384
+ deletedCount: z.number(),
385
+ }),
386
+ 400: ErrorResponseSchema,
387
+ 500: ErrorResponseSchema,
388
+ 401: ErrorResponseSchema,
389
+ },
390
+ auth: true,
391
+ })
392
+ .get('/actions', async () => {
393
+ return client.getActions();
394
+ }, {
395
+ response: {
396
+ 200: GetActionsResponseSchema,
397
+ 400: ErrorResponseSchema,
398
+ 500: ErrorResponseSchema,
399
+ 401: ErrorResponseSchema,
400
+ },
401
+ auth: true,
402
+ })
403
+ .get('/actions/metadata', async () => {
404
+ return client.getActionsMetadata();
405
+ }, {
406
+ response: {
407
+ 200: GetActionsMetadataResponseSchema,
408
+ 400: ErrorResponseSchema,
409
+ 500: ErrorResponseSchema,
410
+ 401: ErrorResponseSchema,
411
+ },
412
+ auth: true,
413
+ })
414
+ .post('/actions/:actionName/run', async ({ params, body }) => {
415
+ const jobId = await client.runAction(params.actionName, body);
416
+ return {
417
+ success: true,
418
+ jobId,
419
+ };
420
+ }, {
421
+ params: z.object({
422
+ actionName: z.string(),
423
+ }),
424
+ body: z.any(),
425
+ response: {
426
+ 200: z.object({
427
+ success: z.boolean(),
428
+ jobId: z.string(),
429
+ }),
430
+ 400: ErrorResponseSchema,
431
+ 500: ErrorResponseSchema,
432
+ 401: ErrorResponseSchema,
433
+ },
434
+ auth: true,
435
+ })
436
+ .post('/login', async ({ body }) => {
437
+ if (!login || !secretKey) {
438
+ throw new Error('Login is not configured');
439
+ }
440
+ const { email, password } = body;
441
+ const success = await login.onLogin({ email, password });
442
+ if (!success) {
443
+ throw new UnauthorizedError('Invalid credentials');
444
+ }
445
+ const accessToken = await new SignJWT({ email, type: 'access' })
446
+ .setProtectedHeader({ alg: 'HS256' })
447
+ .setIssuedAt()
448
+ .setExpirationTime(login.expirationTime ?? '1h')
449
+ .sign(secretKey);
450
+ const refreshToken = await new SignJWT({ email, type: 'refresh' })
451
+ .setProtectedHeader({ alg: 'HS256' })
452
+ .setIssuedAt()
453
+ .setExpirationTime(login.refreshTokenExpirationTime ?? '7d')
454
+ .sign(secretKey);
455
+ return {
456
+ accessToken,
457
+ refreshToken,
458
+ };
459
+ }, {
460
+ body: z.object({
461
+ email: z.email(),
462
+ password: z.string(),
463
+ }),
464
+ response: {
465
+ 200: z.object({
466
+ accessToken: z.string(),
467
+ refreshToken: z.string(),
468
+ }),
469
+ 401: ErrorResponseSchema,
470
+ 400: ErrorResponseSchema,
471
+ 500: ErrorResponseSchema,
472
+ },
473
+ })
474
+ .post('/refresh', async ({ body }) => {
475
+ if (!login || !secretKey) {
476
+ throw new Error('Login is not configured');
477
+ }
478
+ const { refreshToken: providedRefreshToken } = body;
479
+ if (!providedRefreshToken) {
480
+ throw new UnauthorizedError('Refresh token is required');
481
+ }
482
+ try {
483
+ const { payload } = await jwtVerify(providedRefreshToken, secretKey);
484
+ const typedPayload = payload;
485
+ if (typedPayload.type !== 'refresh') {
486
+ throw new UnauthorizedError('Invalid token type');
487
+ }
488
+ if (!typedPayload.email) {
489
+ throw new UnauthorizedError('Invalid token payload');
490
+ }
491
+ const accessToken = await new SignJWT({ email: typedPayload.email, type: 'access' })
492
+ .setProtectedHeader({ alg: 'HS256' })
493
+ .setIssuedAt()
494
+ .setExpirationTime(login.expirationTime ?? '1h')
495
+ .sign(secretKey);
496
+ return {
497
+ accessToken,
498
+ };
499
+ }
500
+ catch {
501
+ throw new UnauthorizedError('Invalid or expired refresh token');
502
+ }
503
+ }, {
504
+ body: z.object({
505
+ refreshToken: z.string(),
506
+ }),
507
+ response: {
508
+ 200: z.object({
509
+ accessToken: z.string(),
510
+ }),
511
+ 401: ErrorResponseSchema,
512
+ 400: ErrorResponseSchema,
513
+ 500: ErrorResponseSchema,
514
+ },
515
+ });
516
+ }
@@ -0,0 +1,46 @@
1
+ import type { Logger } from 'pino';
2
+ import type { z } from 'zod';
3
+ import { type Action, type ActionHandlerContext, type StepHandlerContext, type StepOptions } from './action.js';
4
+ import type { Adapter } from './adapters/adapter.js';
5
+ import { type StepStatus } from './constants.js';
6
+ export interface TaskStep {
7
+ name: string;
8
+ cb: (ctx: StepHandlerContext) => Promise<any>;
9
+ options: StepOptions;
10
+ abortSignal: AbortSignal;
11
+ }
12
+ export declare class StepStore {
13
+ #private;
14
+ constructor(adapter: Adapter);
15
+ getOrCreate(jobId: string, name: string, timeoutMs: number, retriesLimit: number): Promise<{
16
+ id: string;
17
+ status: "active" | "completed" | "failed" | "cancelled";
18
+ retriesLimit: number;
19
+ retriesCount: number;
20
+ timeoutMs: number;
21
+ error: any;
22
+ output: any;
23
+ isNew: boolean;
24
+ } | null>;
25
+ updateStatus(stepId: string, status: StepStatus, output?: any, error?: any): Promise<boolean>;
26
+ delay(stepId: string, delayMs: number, error: any): Promise<boolean>;
27
+ }
28
+ export interface StepManagerOptions {
29
+ jobId: string;
30
+ actionName: string;
31
+ adapter: Adapter;
32
+ logger: Logger;
33
+ concurrencyLimit: number;
34
+ }
35
+ export declare class StepManager {
36
+ #private;
37
+ constructor(options: StepManagerOptions);
38
+ createActionContext<TInput extends z.ZodObject, TOutput extends z.ZodObject, TVariables = Record<string, unknown>>(job: {
39
+ id: string;
40
+ input: z.infer<TInput>;
41
+ groupKey?: string;
42
+ }, action: Action<TInput, TOutput, TVariables>, variables: TVariables, abortSignal: AbortSignal, logger: Logger): ActionHandlerContext<TInput, TVariables>;
43
+ push(task: TaskStep): Promise<any>;
44
+ drain(): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=step-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-manager.d.ts","sourceRoot":"","sources":["../src/step-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,OAAO,EACL,KAAK,MAAM,EACX,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,OAAO,EAAgC,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAoE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAalH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7C,OAAO,EAAE,WAAW,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;CACzB;AAMD,qBAAa,SAAS;;gBAYR,OAAO,EAAE,OAAO;IAkBtB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;;;;IAsBhF,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB7F,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;CAG3E;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAMD,qBAAa,WAAW;;gBAkBV,OAAO,EAAE,kBAAkB;IA6BvC,mBAAmB,CAAC,MAAM,SAAS,CAAC,CAAC,SAAS,EAAE,OAAO,SAAS,CAAC,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/G,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAC9D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAC3C,SAAS,EAAE,UAAU,EACrB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,GACb,oBAAoB,CAAC,MAAM,EAAE,UAAU,CAAC;IAUrC,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAQlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAkK7B"}