@coji/durably 0.10.0 → 0.11.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/README.md +2 -2
- package/dist/{index-BjlCb0gP.d.ts → index-fppJjkF-.d.ts} +84 -52
- package/dist/index.d.ts +45 -95
- package/dist/index.js +482 -389
- package/dist/index.js.map +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/docs/llms.md +174 -58
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Step-oriented resumable batch execution for Node.js and browsers using SQLite.
|
|
|
12
12
|
npm install @coji/durably kysely zod better-sqlite3
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
See the [
|
|
15
|
+
See the [Quick Start](https://coji.github.io/durably/guide/quick-start) for other SQLite backends (libsql, SQLocal for browsers).
|
|
16
16
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
@@ -30,7 +30,7 @@ const myJob = defineJob({
|
|
|
30
30
|
},
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
-
const durably = createDurably({ dialect
|
|
33
|
+
const durably = createDurably({ dialect, jobs: { myJob } })
|
|
34
34
|
|
|
35
35
|
await durably.init() // migrate + start
|
|
36
36
|
await durably.jobs.myJob.trigger({ id: '123' })
|
|
@@ -78,6 +78,14 @@ interface RunRetryEvent extends BaseEvent {
|
|
|
78
78
|
jobName: string;
|
|
79
79
|
labels: Record<string, string>;
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Progress data reported by step.progress()
|
|
83
|
+
*/
|
|
84
|
+
interface ProgressData {
|
|
85
|
+
current: number;
|
|
86
|
+
total?: number;
|
|
87
|
+
message?: string;
|
|
88
|
+
}
|
|
81
89
|
/**
|
|
82
90
|
* Run progress event
|
|
83
91
|
*/
|
|
@@ -85,11 +93,7 @@ interface RunProgressEvent extends BaseEvent {
|
|
|
85
93
|
type: 'run:progress';
|
|
86
94
|
runId: string;
|
|
87
95
|
jobName: string;
|
|
88
|
-
progress:
|
|
89
|
-
current: number;
|
|
90
|
-
total?: number;
|
|
91
|
-
message?: string;
|
|
92
|
-
};
|
|
96
|
+
progress: ProgressData;
|
|
93
97
|
labels: Record<string, string>;
|
|
94
98
|
}
|
|
95
99
|
/**
|
|
@@ -136,17 +140,24 @@ interface StepCancelEvent extends BaseEvent {
|
|
|
136
140
|
stepIndex: number;
|
|
137
141
|
labels: Record<string, string>;
|
|
138
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Log data reported by step.log
|
|
145
|
+
*/
|
|
146
|
+
interface LogData {
|
|
147
|
+
level: 'info' | 'warn' | 'error';
|
|
148
|
+
message: string;
|
|
149
|
+
data?: unknown;
|
|
150
|
+
stepName?: string | null;
|
|
151
|
+
}
|
|
139
152
|
/**
|
|
140
153
|
* Log write event
|
|
141
154
|
*/
|
|
142
|
-
interface LogWriteEvent extends BaseEvent {
|
|
155
|
+
interface LogWriteEvent extends BaseEvent, LogData {
|
|
143
156
|
type: 'log:write';
|
|
144
157
|
runId: string;
|
|
145
158
|
jobName: string;
|
|
146
159
|
labels: Record<string, string>;
|
|
147
160
|
stepName: string | null;
|
|
148
|
-
level: 'info' | 'warn' | 'error';
|
|
149
|
-
message: string;
|
|
150
161
|
data: unknown;
|
|
151
162
|
}
|
|
152
163
|
/**
|
|
@@ -248,17 +259,17 @@ interface Database {
|
|
|
248
259
|
/**
|
|
249
260
|
* Run data for creating a new run
|
|
250
261
|
*/
|
|
251
|
-
interface CreateRunInput {
|
|
262
|
+
interface CreateRunInput<TLabels extends Record<string, string> = Record<string, string>> {
|
|
252
263
|
jobName: string;
|
|
253
264
|
input: unknown;
|
|
254
265
|
idempotencyKey?: string;
|
|
255
266
|
concurrencyKey?: string;
|
|
256
|
-
labels?:
|
|
267
|
+
labels?: TLabels;
|
|
257
268
|
}
|
|
258
269
|
/**
|
|
259
270
|
* Run data returned from storage
|
|
260
271
|
*/
|
|
261
|
-
interface Run {
|
|
272
|
+
interface Run<TLabels extends Record<string, string> = Record<string, string>> {
|
|
262
273
|
id: string;
|
|
263
274
|
jobName: string;
|
|
264
275
|
input: unknown;
|
|
@@ -274,7 +285,7 @@ interface Run {
|
|
|
274
285
|
} | null;
|
|
275
286
|
output: unknown | null;
|
|
276
287
|
error: string | null;
|
|
277
|
-
labels:
|
|
288
|
+
labels: TLabels;
|
|
278
289
|
heartbeatAt: string;
|
|
279
290
|
startedAt: string | null;
|
|
280
291
|
completedAt: string | null;
|
|
@@ -301,10 +312,14 @@ interface UpdateRunInput {
|
|
|
301
312
|
/**
|
|
302
313
|
* Run filter options
|
|
303
314
|
*/
|
|
304
|
-
interface RunFilter
|
|
315
|
+
interface RunFilter<TLabels extends Record<string, string> = Record<string, string>> {
|
|
305
316
|
status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
306
|
-
|
|
307
|
-
|
|
317
|
+
/** Filter by job name(s). Pass a string for one, or an array for multiple (OR). */
|
|
318
|
+
jobName?: string | string[];
|
|
319
|
+
/** Filter by labels (all specified labels must match) */
|
|
320
|
+
labels?: {
|
|
321
|
+
[K in keyof TLabels]?: TLabels[K];
|
|
322
|
+
};
|
|
308
323
|
/** Maximum number of runs to return */
|
|
309
324
|
limit?: number;
|
|
310
325
|
/** Number of runs to skip (for pagination) */
|
|
@@ -362,11 +377,11 @@ interface Log {
|
|
|
362
377
|
* A client-safe subset of Run, excluding internal fields like
|
|
363
378
|
* heartbeatAt, idempotencyKey, concurrencyKey, and updatedAt.
|
|
364
379
|
*/
|
|
365
|
-
type ClientRun = Omit<Run
|
|
380
|
+
type ClientRun<TLabels extends Record<string, string> = Record<string, string>> = Omit<Run<TLabels>, 'idempotencyKey' | 'concurrencyKey' | 'heartbeatAt' | 'updatedAt'>;
|
|
366
381
|
/**
|
|
367
382
|
* Project a full Run to a ClientRun by stripping internal fields.
|
|
368
383
|
*/
|
|
369
|
-
declare function toClientRun(run: Run): ClientRun
|
|
384
|
+
declare function toClientRun<TLabels extends Record<string, string> = Record<string, string>>(run: Run<TLabels>): ClientRun<TLabels>;
|
|
370
385
|
/**
|
|
371
386
|
* Storage interface for database operations
|
|
372
387
|
*/
|
|
@@ -376,7 +391,7 @@ interface Storage {
|
|
|
376
391
|
updateRun(runId: string, data: UpdateRunInput): Promise<void>;
|
|
377
392
|
deleteRun(runId: string): Promise<void>;
|
|
378
393
|
getRun<T extends Run = Run>(runId: string): Promise<T | null>;
|
|
379
|
-
getRuns<T extends Run = Run>(filter?: RunFilter
|
|
394
|
+
getRuns<T extends Run = Run>(filter?: RunFilter): Promise<T[]>;
|
|
380
395
|
claimNextPendingRun(excludeConcurrencyKeys: string[]): Promise<Run | null>;
|
|
381
396
|
createStep(input: CreateStepInput): Promise<Step>;
|
|
382
397
|
getSteps(runId: string): Promise<Step[]>;
|
|
@@ -411,39 +426,36 @@ interface StepContext {
|
|
|
411
426
|
};
|
|
412
427
|
}
|
|
413
428
|
/**
|
|
414
|
-
* Trigger options
|
|
429
|
+
* Trigger options for trigger() and batchTrigger()
|
|
415
430
|
*/
|
|
416
|
-
interface TriggerOptions {
|
|
431
|
+
interface TriggerOptions<TLabels extends Record<string, string> = Record<string, string>> {
|
|
417
432
|
idempotencyKey?: string;
|
|
418
433
|
concurrencyKey?: string;
|
|
419
|
-
labels?:
|
|
420
|
-
/** Timeout in milliseconds for triggerAndWait() */
|
|
421
|
-
timeout?: number;
|
|
434
|
+
labels?: TLabels;
|
|
422
435
|
}
|
|
423
436
|
/**
|
|
424
|
-
*
|
|
437
|
+
* Options for triggerAndWait() (extends TriggerOptions with wait-specific options)
|
|
425
438
|
*/
|
|
426
|
-
interface
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
offset?: number;
|
|
439
|
+
interface TriggerAndWaitOptions<TLabels extends Record<string, string> = Record<string, string>> extends TriggerOptions<TLabels> {
|
|
440
|
+
/** Timeout in milliseconds */
|
|
441
|
+
timeout?: number;
|
|
442
|
+
/** Called when step.progress() is invoked during execution */
|
|
443
|
+
onProgress?: (progress: ProgressData) => void | Promise<void>;
|
|
444
|
+
/** Called when step.log is invoked during execution */
|
|
445
|
+
onLog?: (log: LogData) => void | Promise<void>;
|
|
434
446
|
}
|
|
435
447
|
/**
|
|
436
448
|
* Typed run with output type
|
|
437
449
|
*/
|
|
438
|
-
interface TypedRun<TOutput> extends Omit<Run
|
|
450
|
+
interface TypedRun<TOutput, TLabels extends Record<string, string> = Record<string, string>> extends Omit<Run<TLabels>, 'output'> {
|
|
439
451
|
output: TOutput | null;
|
|
440
452
|
}
|
|
441
453
|
/**
|
|
442
454
|
* Batch trigger input - either just the input or input with options
|
|
443
455
|
*/
|
|
444
|
-
type BatchTriggerInput<TInput> = TInput | {
|
|
456
|
+
type BatchTriggerInput<TInput, TLabels extends Record<string, string> = Record<string, string>> = TInput | {
|
|
445
457
|
input: TInput;
|
|
446
|
-
options?: TriggerOptions
|
|
458
|
+
options?: TriggerOptions<TLabels>;
|
|
447
459
|
};
|
|
448
460
|
/**
|
|
449
461
|
* Result of triggerAndWait
|
|
@@ -455,30 +467,30 @@ interface TriggerAndWaitResult<TOutput> {
|
|
|
455
467
|
/**
|
|
456
468
|
* Job handle returned by defineJob
|
|
457
469
|
*/
|
|
458
|
-
interface JobHandle<TName extends string, TInput, TOutput> {
|
|
470
|
+
interface JobHandle<TName extends string, TInput, TOutput, TLabels extends Record<string, string> = Record<string, string>> {
|
|
459
471
|
readonly name: TName;
|
|
460
472
|
/**
|
|
461
473
|
* Trigger a new run
|
|
462
474
|
*/
|
|
463
|
-
trigger(input: TInput, options?: TriggerOptions): Promise<TypedRun<TOutput>>;
|
|
475
|
+
trigger(input: TInput, options?: TriggerOptions<TLabels>): Promise<TypedRun<TOutput, TLabels>>;
|
|
464
476
|
/**
|
|
465
477
|
* Trigger a new run and wait for completion
|
|
466
478
|
* Returns the output directly, throws if the run fails
|
|
467
479
|
*/
|
|
468
|
-
triggerAndWait(input: TInput, options?:
|
|
480
|
+
triggerAndWait(input: TInput, options?: TriggerAndWaitOptions<TLabels>): Promise<TriggerAndWaitResult<TOutput>>;
|
|
469
481
|
/**
|
|
470
482
|
* Trigger multiple runs in a batch
|
|
471
483
|
* All inputs are validated before any runs are created
|
|
472
484
|
*/
|
|
473
|
-
batchTrigger(inputs: BatchTriggerInput<TInput>[]): Promise<TypedRun<TOutput>[]>;
|
|
485
|
+
batchTrigger(inputs: BatchTriggerInput<TInput, TLabels>[]): Promise<TypedRun<TOutput, TLabels>[]>;
|
|
474
486
|
/**
|
|
475
487
|
* Get a run by ID
|
|
476
488
|
*/
|
|
477
|
-
getRun(id: string): Promise<TypedRun<TOutput> | null>;
|
|
489
|
+
getRun(id: string): Promise<TypedRun<TOutput, TLabels> | null>;
|
|
478
490
|
/**
|
|
479
491
|
* Get runs with optional filter
|
|
480
492
|
*/
|
|
481
|
-
getRuns(filter?: Omit<RunFilter
|
|
493
|
+
getRuns(filter?: Omit<RunFilter<TLabels>, 'jobName'>): Promise<TypedRun<TOutput, TLabels>[]>;
|
|
482
494
|
}
|
|
483
495
|
|
|
484
496
|
/**
|
|
@@ -544,29 +556,46 @@ declare function defineJob<TName extends string, TInputSchema extends z.ZodType,
|
|
|
544
556
|
/**
|
|
545
557
|
* Options for creating a Durably instance
|
|
546
558
|
*/
|
|
547
|
-
interface DurablyOptions {
|
|
559
|
+
interface DurablyOptions<TLabels extends Record<string, string> = Record<string, string>, TJobs extends Record<string, JobDefinition<string, any, any>> = Record<string, never>> {
|
|
548
560
|
dialect: Dialect;
|
|
549
561
|
pollingInterval?: number;
|
|
550
562
|
heartbeatInterval?: number;
|
|
551
563
|
staleThreshold?: number;
|
|
564
|
+
/**
|
|
565
|
+
* Zod schema for labels. When provided:
|
|
566
|
+
* - Labels are type-checked at compile time
|
|
567
|
+
* - Labels are validated at runtime on trigger()
|
|
568
|
+
*/
|
|
569
|
+
labels?: z.ZodType<TLabels>;
|
|
570
|
+
/**
|
|
571
|
+
* Job definitions to register. Shorthand for calling .register() after creation.
|
|
572
|
+
* @example
|
|
573
|
+
* ```ts
|
|
574
|
+
* const durably = createDurably({
|
|
575
|
+
* dialect,
|
|
576
|
+
* jobs: { importCsv: importCsvJob, syncUsers: syncUsersJob },
|
|
577
|
+
* })
|
|
578
|
+
* ```
|
|
579
|
+
*/
|
|
580
|
+
jobs?: TJobs;
|
|
552
581
|
}
|
|
553
582
|
/**
|
|
554
583
|
* Plugin interface for extending Durably
|
|
555
584
|
*/
|
|
556
585
|
interface DurablyPlugin {
|
|
557
586
|
name: string;
|
|
558
|
-
install(durably: Durably<any>): void;
|
|
587
|
+
install(durably: Durably<any, any>): void;
|
|
559
588
|
}
|
|
560
589
|
/**
|
|
561
590
|
* Helper type to transform JobDefinition record to JobHandle record
|
|
562
591
|
*/
|
|
563
|
-
type TransformToHandles<TJobs extends Record<string, JobDefinition<string, unknown, unknown
|
|
564
|
-
[K in keyof TJobs]: TJobs[K] extends JobDefinition<infer TName, infer TInput, infer TOutput> ? JobHandle<TName & string, TInput, TOutput> : never;
|
|
592
|
+
type TransformToHandles<TJobs extends Record<string, JobDefinition<string, unknown, unknown>>, TLabels extends Record<string, string> = Record<string, string>> = {
|
|
593
|
+
[K in keyof TJobs]: TJobs[K] extends JobDefinition<infer TName, infer TInput, infer TOutput> ? JobHandle<TName & string, TInput, TOutput, TLabels> : never;
|
|
565
594
|
};
|
|
566
595
|
/**
|
|
567
596
|
* Durably instance with type-safe jobs
|
|
568
597
|
*/
|
|
569
|
-
interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknown
|
|
598
|
+
interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknown, Record<string, string>>> = Record<string, never>, TLabels extends Record<string, string> = Record<string, string>> {
|
|
570
599
|
/**
|
|
571
600
|
* Registered job handles (type-safe)
|
|
572
601
|
*/
|
|
@@ -622,7 +651,7 @@ interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknow
|
|
|
622
651
|
* // Usage: durably.jobs.importCsv.trigger({ rows: [...] })
|
|
623
652
|
* ```
|
|
624
653
|
*/
|
|
625
|
-
register<TNewJobs extends Record<string, JobDefinition<string, any, any>>>(jobDefs: TNewJobs): Durably<TJobs & TransformToHandles<TNewJobs
|
|
654
|
+
register<TNewJobs extends Record<string, JobDefinition<string, any, any>>>(jobDefs: TNewJobs): Durably<TJobs & TransformToHandles<TNewJobs, TLabels>, TLabels>;
|
|
626
655
|
/**
|
|
627
656
|
* Start the worker polling loop
|
|
628
657
|
*/
|
|
@@ -658,7 +687,7 @@ interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknow
|
|
|
658
687
|
* const typedRun = await durably.getRun<MyRun>(runId)
|
|
659
688
|
* ```
|
|
660
689
|
*/
|
|
661
|
-
getRun<T extends Run = Run
|
|
690
|
+
getRun<T extends Run<TLabels> = Run<TLabels>>(runId: string): Promise<T | null>;
|
|
662
691
|
/**
|
|
663
692
|
* Get runs with optional filtering
|
|
664
693
|
* @example
|
|
@@ -671,7 +700,7 @@ interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknow
|
|
|
671
700
|
* const typedRuns = await durably.getRuns<MyRun>({ jobName: 'my-job' })
|
|
672
701
|
* ```
|
|
673
702
|
*/
|
|
674
|
-
getRuns<T extends Run = Run
|
|
703
|
+
getRuns<T extends Run<TLabels> = Run<TLabels>>(filter?: RunFilter<TLabels>): Promise<T[]>;
|
|
675
704
|
/**
|
|
676
705
|
* Register a plugin
|
|
677
706
|
*/
|
|
@@ -680,7 +709,7 @@ interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknow
|
|
|
680
709
|
* Get a registered job handle by name
|
|
681
710
|
* Returns undefined if job is not registered
|
|
682
711
|
*/
|
|
683
|
-
getJob<TName extends string = string>(name: TName): JobHandle<TName, Record<string, unknown>, unknown> | undefined;
|
|
712
|
+
getJob<TName extends string = string>(name: TName): JobHandle<TName, Record<string, unknown>, unknown, TLabels> | undefined;
|
|
684
713
|
/**
|
|
685
714
|
* Subscribe to events for a specific run
|
|
686
715
|
* Returns a ReadableStream that can be used for SSE
|
|
@@ -690,11 +719,14 @@ interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknow
|
|
|
690
719
|
/**
|
|
691
720
|
* Create a Durably instance
|
|
692
721
|
*/
|
|
693
|
-
declare function createDurably
|
|
722
|
+
declare function createDurably<TLabels extends Record<string, string> = Record<string, string>, TJobs extends Record<string, JobDefinition<string, any, any>> = Record<string, never>>(options: DurablyOptions<TLabels, TJobs> & {
|
|
723
|
+
jobs: TJobs;
|
|
724
|
+
}): Durably<TransformToHandles<TJobs, TLabels>, TLabels>;
|
|
725
|
+
declare function createDurably<TLabels extends Record<string, string> = Record<string, string>>(options: DurablyOptions<TLabels>): Durably<Record<string, never>, TLabels>;
|
|
694
726
|
|
|
695
727
|
/**
|
|
696
728
|
* Plugin that persists log events to the database
|
|
697
729
|
*/
|
|
698
730
|
declare function withLogPersistence(): DurablyPlugin;
|
|
699
731
|
|
|
700
|
-
export { type
|
|
732
|
+
export { type StepStartEvent as A, type BatchTriggerInput as B, type ClientRun as C, type Durably as D, type ErrorHandler as E, type StepsTable as F, type TriggerAndWaitResult as G, type TriggerOptions as H, createDurably as I, type JobDefinition as J, defineJob as K, type Log as L, toClientRun as M, withLogPersistence as N, type ProgressData as P, type Run as R, type SchemaVersionsTable as S, type TriggerAndWaitOptions as T, type WorkerErrorEvent as W, type RunFilter as a, type Database as b, type DurablyEvent as c, type DurablyOptions as d, type DurablyPlugin as e, type EventType as f, type JobHandle as g, type JobInput as h, type JobOutput as i, type LogData as j, type LogWriteEvent as k, type LogsTable as l, type RunCancelEvent as m, type RunCompleteEvent as n, type RunDeleteEvent as o, type RunFailEvent as p, type RunProgressEvent as q, type RunRetryEvent as r, type RunStartEvent as s, type RunTriggerEvent as t, type RunsTable as u, type Step as v, type StepCancelEvent as w, type StepCompleteEvent as x, type StepContext as y, type StepFailEvent as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as Durably } from './index-
|
|
2
|
-
export { C as ClientRun,
|
|
1
|
+
import { R as Run, a as RunFilter, D as Durably } from './index-fppJjkF-.js';
|
|
2
|
+
export { B as BatchTriggerInput, C as ClientRun, b as Database, c as DurablyEvent, d as DurablyOptions, e as DurablyPlugin, E as ErrorHandler, f as EventType, J as JobDefinition, g as JobHandle, h as JobInput, i as JobOutput, L as Log, j as LogData, k as LogWriteEvent, l as LogsTable, P as ProgressData, m as RunCancelEvent, n as RunCompleteEvent, o as RunDeleteEvent, p as RunFailEvent, q as RunProgressEvent, r as RunRetryEvent, s as RunStartEvent, t as RunTriggerEvent, u as RunsTable, S as SchemaVersionsTable, v as Step, w as StepCancelEvent, x as StepCompleteEvent, y as StepContext, z as StepFailEvent, A as StepStartEvent, F as StepsTable, T as TriggerAndWaitOptions, G as TriggerAndWaitResult, H as TriggerOptions, W as WorkerErrorEvent, I as createDurably, K as defineJob, M as toClientRun, N as withLogPersistence } from './index-fppJjkF-.js';
|
|
3
3
|
import 'kysely';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
@@ -12,15 +12,23 @@ declare class CancelledError extends Error {
|
|
|
12
12
|
constructor(runId: string);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Run operation types for onRunAccess
|
|
17
|
+
*/
|
|
18
|
+
type RunOperation = 'read' | 'subscribe' | 'steps' | 'retry' | 'cancel' | 'delete';
|
|
19
|
+
/**
|
|
20
|
+
* Subscription filter — only fields that SSE subscriptions actually support.
|
|
21
|
+
*/
|
|
22
|
+
type RunsSubscribeFilter<TLabels extends Record<string, string> = Record<string, string>> = Pick<RunFilter<TLabels>, 'jobName' | 'labels'>;
|
|
15
23
|
/**
|
|
16
24
|
* Request body for triggering a job
|
|
17
25
|
*/
|
|
18
|
-
interface TriggerRequest {
|
|
26
|
+
interface TriggerRequest<TLabels extends Record<string, string> = Record<string, string>> {
|
|
19
27
|
jobName: string;
|
|
20
|
-
input:
|
|
28
|
+
input: unknown;
|
|
21
29
|
idempotencyKey?: string;
|
|
22
30
|
concurrencyKey?: string;
|
|
23
|
-
labels?:
|
|
31
|
+
labels?: TLabels;
|
|
24
32
|
}
|
|
25
33
|
/**
|
|
26
34
|
* Response for trigger endpoint
|
|
@@ -28,127 +36,69 @@ interface TriggerRequest {
|
|
|
28
36
|
interface TriggerResponse {
|
|
29
37
|
runId: string;
|
|
30
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Auth middleware configuration.
|
|
41
|
+
* When `auth` is set, `authenticate` is required.
|
|
42
|
+
* TContext is inferred from authenticate's return type.
|
|
43
|
+
* TLabels is inferred from the Durably instance.
|
|
44
|
+
*/
|
|
45
|
+
interface AuthConfig<TContext, TLabels extends Record<string, string> = Record<string, string>> {
|
|
46
|
+
/** Authenticate every request. Return context or throw Response to reject. */
|
|
47
|
+
authenticate: (request: Request) => Promise<TContext> | TContext;
|
|
48
|
+
/** Guard before trigger. Called after body validation and job resolution. */
|
|
49
|
+
onTrigger?: (ctx: TContext, trigger: TriggerRequest<TLabels>) => Promise<void> | void;
|
|
50
|
+
/** Guard before run-level operations. Run is pre-fetched. */
|
|
51
|
+
onRunAccess?: (ctx: TContext, run: Run<TLabels>, info: {
|
|
52
|
+
operation: RunOperation;
|
|
53
|
+
}) => Promise<void> | void;
|
|
54
|
+
/** Scope runs list queries (GET /runs). */
|
|
55
|
+
scopeRuns?: (ctx: TContext, filter: RunFilter<TLabels>) => RunFilter<TLabels> | Promise<RunFilter<TLabels>>;
|
|
56
|
+
/** Scope runs subscribe stream (GET /runs/subscribe). Falls back to scopeRuns if not set. */
|
|
57
|
+
scopeRunsSubscribe?: (ctx: TContext, filter: RunsSubscribeFilter<TLabels>) => RunsSubscribeFilter<TLabels> | Promise<RunsSubscribeFilter<TLabels>>;
|
|
58
|
+
}
|
|
31
59
|
/**
|
|
32
60
|
* Handler interface for HTTP endpoints
|
|
33
61
|
*/
|
|
34
62
|
interface DurablyHandler {
|
|
35
63
|
/**
|
|
36
|
-
* Handle all Durably HTTP requests with automatic routing
|
|
64
|
+
* Handle all Durably HTTP requests with automatic routing + auth
|
|
37
65
|
*
|
|
38
66
|
* Routes:
|
|
39
67
|
* - GET {basePath}/subscribe?runId=xxx - SSE stream
|
|
40
68
|
* - GET {basePath}/runs - List runs
|
|
69
|
+
* - GET {basePath}/runs/subscribe - SSE stream of run updates
|
|
41
70
|
* - GET {basePath}/run?runId=xxx - Get single run
|
|
71
|
+
* - GET {basePath}/steps?runId=xxx - Get steps
|
|
42
72
|
* - POST {basePath}/trigger - Trigger a job
|
|
43
73
|
* - POST {basePath}/retry?runId=xxx - Retry a failed run
|
|
44
74
|
* - POST {basePath}/cancel?runId=xxx - Cancel a run
|
|
45
|
-
*
|
|
46
|
-
* @param request - The incoming HTTP request
|
|
47
|
-
* @param basePath - The base path to strip from the URL (e.g., '/api/durably')
|
|
48
|
-
* @returns Response or null if route not matched
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```ts
|
|
52
|
-
* // React Router / Remix
|
|
53
|
-
* export async function loader({ request }) {
|
|
54
|
-
* return durablyHandler.handle(request, '/api/durably')
|
|
55
|
-
* }
|
|
56
|
-
* export async function action({ request }) {
|
|
57
|
-
* return durablyHandler.handle(request, '/api/durably')
|
|
58
|
-
* }
|
|
59
|
-
* ```
|
|
75
|
+
* - DELETE {basePath}/run?runId=xxx - Delete a run
|
|
60
76
|
*/
|
|
61
77
|
handle(request: Request, basePath: string): Promise<Response>;
|
|
62
|
-
/**
|
|
63
|
-
* Handle job trigger request
|
|
64
|
-
* Expects POST with JSON body: { jobName, input, idempotencyKey?, concurrencyKey? }
|
|
65
|
-
* Returns JSON: { runId }
|
|
66
|
-
*/
|
|
67
|
-
trigger(request: Request): Promise<Response>;
|
|
68
|
-
/**
|
|
69
|
-
* Handle subscription request
|
|
70
|
-
* Expects GET with query param: runId
|
|
71
|
-
* Returns SSE stream of events
|
|
72
|
-
*/
|
|
73
|
-
subscribe(request: Request): Response;
|
|
74
|
-
/**
|
|
75
|
-
* Handle runs list request
|
|
76
|
-
* Expects GET with optional query params: jobName, status, limit, offset
|
|
77
|
-
* Returns JSON array of runs
|
|
78
|
-
*/
|
|
79
|
-
runs(request: Request): Promise<Response>;
|
|
80
|
-
/**
|
|
81
|
-
* Handle single run request
|
|
82
|
-
* Expects GET with query param: runId
|
|
83
|
-
* Returns JSON run object or 404
|
|
84
|
-
*/
|
|
85
|
-
run(request: Request): Promise<Response>;
|
|
86
|
-
/**
|
|
87
|
-
* Handle retry request
|
|
88
|
-
* Expects POST with query param: runId
|
|
89
|
-
* Returns JSON: { success: true }
|
|
90
|
-
*/
|
|
91
|
-
retry(request: Request): Promise<Response>;
|
|
92
|
-
/**
|
|
93
|
-
* Handle cancel request
|
|
94
|
-
* Expects POST with query param: runId
|
|
95
|
-
* Returns JSON: { success: true }
|
|
96
|
-
*/
|
|
97
|
-
cancel(request: Request): Promise<Response>;
|
|
98
|
-
/**
|
|
99
|
-
* Handle delete request
|
|
100
|
-
* Expects DELETE with query param: runId
|
|
101
|
-
* Returns JSON: { success: true }
|
|
102
|
-
*/
|
|
103
|
-
delete(request: Request): Promise<Response>;
|
|
104
|
-
/**
|
|
105
|
-
* Handle steps request
|
|
106
|
-
* Expects GET with query param: runId
|
|
107
|
-
* Returns JSON array of steps
|
|
108
|
-
*/
|
|
109
|
-
steps(request: Request): Promise<Response>;
|
|
110
|
-
/**
|
|
111
|
-
* Handle runs subscription request
|
|
112
|
-
* Expects GET with optional query param: jobName
|
|
113
|
-
* Returns SSE stream of run update notifications
|
|
114
|
-
*/
|
|
115
|
-
runsSubscribe(request: Request): Response;
|
|
116
78
|
}
|
|
117
79
|
/**
|
|
118
80
|
* Options for createDurablyHandler
|
|
119
81
|
*/
|
|
120
|
-
interface CreateDurablyHandlerOptions {
|
|
82
|
+
interface CreateDurablyHandlerOptions<TContext = undefined, TLabels extends Record<string, string> = Record<string, string>> {
|
|
121
83
|
/**
|
|
122
|
-
* Called before handling each request.
|
|
84
|
+
* Called before handling each request (after authentication).
|
|
123
85
|
* Use this to initialize Durably (migrate, start worker, etc.)
|
|
124
|
-
*
|
|
125
|
-
* @example
|
|
126
|
-
* ```ts
|
|
127
|
-
* const durablyHandler = createDurablyHandler(durably, {
|
|
128
|
-
* onRequest: async () => {
|
|
129
|
-
* await durably.migrate()
|
|
130
|
-
* durably.start()
|
|
131
|
-
* }
|
|
132
|
-
* })
|
|
133
|
-
* ```
|
|
134
86
|
*/
|
|
135
87
|
onRequest?: () => Promise<void> | void;
|
|
136
88
|
/**
|
|
137
89
|
* Throttle interval in milliseconds for SSE progress events.
|
|
138
|
-
* When set, `run:progress` events are throttled per run so the client
|
|
139
|
-
* receives at most one progress update per throttle window.
|
|
140
|
-
* The first and last progress events are always delivered.
|
|
141
|
-
* Non-progress events are never throttled.
|
|
142
|
-
*
|
|
143
|
-
* Set to 0 to disable throttling.
|
|
144
90
|
* @default 100
|
|
145
91
|
*/
|
|
146
92
|
sseThrottleMs?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Auth middleware. When set, authenticate is required and auth applies to ALL endpoints.
|
|
95
|
+
*/
|
|
96
|
+
auth?: AuthConfig<TContext, TLabels>;
|
|
147
97
|
}
|
|
148
98
|
/**
|
|
149
99
|
* Create HTTP handlers for Durably
|
|
150
100
|
* Uses Web Standard Request/Response for framework-agnostic usage
|
|
151
101
|
*/
|
|
152
|
-
declare function createDurablyHandler(durably: Durably, options?: CreateDurablyHandlerOptions): DurablyHandler;
|
|
102
|
+
declare function createDurablyHandler<TContext = undefined, TLabels extends Record<string, string> = Record<string, string>>(durably: Durably<any, TLabels>, options?: CreateDurablyHandlerOptions<TContext, TLabels>): DurablyHandler;
|
|
153
103
|
|
|
154
|
-
export { CancelledError, type CreateDurablyHandlerOptions, Durably, type DurablyHandler, type TriggerRequest, type TriggerResponse, createDurablyHandler };
|
|
104
|
+
export { type AuthConfig, CancelledError, type CreateDurablyHandlerOptions, Durably, type DurablyHandler, Run, RunFilter, type RunOperation, type RunsSubscribeFilter, type TriggerRequest, type TriggerResponse, createDurablyHandler };
|