@coji/durably 0.14.0 → 0.15.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.
@@ -19,6 +19,17 @@ interface RunTriggerEvent extends BaseEvent {
19
19
  input: unknown;
20
20
  labels: Record<string, string>;
21
21
  }
22
+ /**
23
+ * Emitted when a trigger was coalesced onto an existing pending run (same concurrency key).
24
+ */
25
+ interface RunCoalescedEvent extends BaseEvent {
26
+ type: 'run:coalesced';
27
+ runId: string;
28
+ jobName: string;
29
+ labels: Record<string, string>;
30
+ skippedInput: unknown;
31
+ skippedLabels: Record<string, string>;
32
+ }
22
33
  /**
23
34
  * Run leased event
24
35
  */
@@ -173,11 +184,37 @@ interface WorkerErrorEvent extends BaseEvent {
173
184
  /**
174
185
  * All event types as discriminated union
175
186
  */
176
- type DurablyEvent = RunTriggerEvent | RunLeasedEvent | RunLeaseRenewedEvent | RunCompleteEvent | RunFailEvent | RunCancelEvent | RunDeleteEvent | RunProgressEvent | StepStartEvent | StepCompleteEvent | StepFailEvent | StepCancelEvent | LogWriteEvent | WorkerErrorEvent;
187
+ type DurablyEvent = RunTriggerEvent | RunCoalescedEvent | RunLeasedEvent | RunLeaseRenewedEvent | RunCompleteEvent | RunFailEvent | RunCancelEvent | RunDeleteEvent | RunProgressEvent | StepStartEvent | StepCompleteEvent | StepFailEvent | StepCancelEvent | LogWriteEvent | WorkerErrorEvent;
177
188
  /**
178
189
  * Event types for type-safe event names
179
190
  */
180
191
  type EventType = DurablyEvent['type'];
192
+ /**
193
+ * Domain (lifecycle) event names — run state-transition facts.
194
+ * Derived from DOMAIN_EVENT_TYPE_VALUES so the Set and type stay in sync.
195
+ */
196
+ declare const DOMAIN_EVENT_TYPE_VALUES: readonly ["run:trigger", "run:coalesced", "run:complete", "run:fail", "run:cancel", "run:delete"];
197
+ type DomainEventType = (typeof DOMAIN_EVENT_TYPE_VALUES)[number];
198
+ /**
199
+ * Operational / diagnostic event names — execution detail and worker diagnostics.
200
+ */
201
+ type OperationalEventType = 'run:leased' | 'run:lease-renewed' | 'run:progress' | 'step:start' | 'step:complete' | 'step:fail' | 'step:cancel' | 'log:write' | 'worker:error';
202
+ /**
203
+ * Domain events: run lifecycle facts (trigger, terminal outcomes, coalesce, delete).
204
+ */
205
+ type DomainEvent = Extract<DurablyEvent, {
206
+ type: DomainEventType;
207
+ }>;
208
+ /**
209
+ * Operational events: leased/progress/steps/logs/worker diagnostics.
210
+ */
211
+ type OperationalEvent = Extract<DurablyEvent, {
212
+ type: OperationalEventType;
213
+ }>;
214
+ /**
215
+ * True when `event` is a domain (lifecycle) event — uses `event.type` only.
216
+ */
217
+ declare function isDomainEvent(event: DurablyEvent): event is DomainEvent;
181
218
  /**
182
219
  * Extract event by type
183
220
  */
@@ -191,7 +228,7 @@ type EventInput<T extends EventType> = Omit<EventByType<T>, 'timestamp' | 'seque
191
228
  /**
192
229
  * All possible event inputs as a union (properly distributed)
193
230
  */
194
- type AnyEventInput = EventInput<'run:trigger'> | EventInput<'run:leased'> | EventInput<'run:lease-renewed'> | EventInput<'run:complete'> | EventInput<'run:fail'> | EventInput<'run:cancel'> | EventInput<'run:delete'> | EventInput<'run:progress'> | EventInput<'step:start'> | EventInput<'step:complete'> | EventInput<'step:fail'> | EventInput<'step:cancel'> | EventInput<'log:write'> | EventInput<'worker:error'>;
231
+ type AnyEventInput = EventInput<'run:trigger'> | EventInput<'run:coalesced'> | EventInput<'run:leased'> | EventInput<'run:lease-renewed'> | EventInput<'run:complete'> | EventInput<'run:fail'> | EventInput<'run:cancel'> | EventInput<'run:delete'> | EventInput<'run:progress'> | EventInput<'step:start'> | EventInput<'step:complete'> | EventInput<'step:fail'> | EventInput<'step:cancel'> | EventInput<'log:write'> | EventInput<'worker:error'>;
195
232
  /**
196
233
  * Event listener function
197
234
  */
@@ -276,6 +313,11 @@ interface CreateRunInput<TLabels extends Record<string, string> = Record<string,
276
313
  idempotencyKey?: string;
277
314
  concurrencyKey?: string;
278
315
  labels?: TLabels;
316
+ coalesce?: 'skip';
317
+ }
318
+ interface EnqueueResult<TLabels extends Record<string, string> = Record<string, string>> {
319
+ run: Run<TLabels>;
320
+ disposition: Disposition;
279
321
  }
280
322
  /**
281
323
  * Run data returned from storage
@@ -309,7 +351,8 @@ interface Run<TLabels extends Record<string, string> = Record<string, string>> {
309
351
  * Run filter options
310
352
  */
311
353
  interface RunFilter<TLabels extends Record<string, string> = Record<string, string>> {
312
- status?: RunStatus;
354
+ /** Filter by status(es). Pass one status, or an array for multiple (OR). */
355
+ status?: RunStatus | RunStatus[];
313
356
  /** Filter by job name(s). Pass a string for one, or an array for multiple (OR). */
314
357
  jobName?: string | string[];
315
358
  /** Filter by labels (all specified labels must match) */
@@ -392,8 +435,8 @@ interface UpdateRunData {
392
435
  * Unified storage interface used by the runtime.
393
436
  */
394
437
  interface Store<TLabels extends Record<string, string> = Record<string, string>> {
395
- enqueue(input: CreateRunInput<TLabels>): Promise<Run<TLabels>>;
396
- enqueueMany(inputs: CreateRunInput<TLabels>[]): Promise<Run<TLabels>[]>;
438
+ enqueue(input: CreateRunInput<TLabels>): Promise<EnqueueResult<TLabels>>;
439
+ enqueueMany(inputs: CreateRunInput<TLabels>[]): Promise<EnqueueResult<TLabels>[]>;
397
440
  getRun<T extends Run<TLabels> = Run<TLabels>>(runId: string): Promise<T | null>;
398
441
  getRuns<T extends Run<TLabels> = Run<TLabels>>(filter?: RunFilter<TLabels>): Promise<T[]>;
399
442
  updateRun(runId: string, data: UpdateRunData): Promise<void>;
@@ -424,16 +467,17 @@ interface Store<TLabels extends Record<string, string> = Record<string, string>>
424
467
  }
425
468
  /**
426
469
  * A client-safe subset of Run, excluding internal fields like
427
- * leaseOwner, leaseExpiresAt, idempotencyKey, concurrencyKey, and updatedAt.
470
+ * leaseOwner, leaseExpiresAt, idempotencyKey, concurrencyKey, and updatedAt,
471
+ * plus derived `isTerminal` / `isActive` flags from `status`.
428
472
  */
429
- type ClientRun<TLabels extends Record<string, string> = Record<string, string>> = Omit<Run<TLabels>, 'idempotencyKey' | 'concurrencyKey' | 'leaseOwner' | 'leaseExpiresAt' | 'leaseGeneration' | 'updatedAt'>;
473
+ type ClientRun<TLabels extends Record<string, string> = Record<string, string>> = Omit<Run<TLabels>, 'idempotencyKey' | 'concurrencyKey' | 'leaseOwner' | 'leaseExpiresAt' | 'leaseGeneration' | 'updatedAt'> & {
474
+ isTerminal: boolean;
475
+ isActive: boolean;
476
+ };
430
477
  /**
431
478
  * Project a full Run to a ClientRun by stripping internal fields.
432
479
  */
433
480
  declare function toClientRun<TLabels extends Record<string, string> = Record<string, string>>(run: Run<TLabels>): ClientRun<TLabels>;
434
- /**
435
- * Create a Kysely-based Store implementation
436
- */
437
481
  declare function createKyselyStore(db: Kysely<Database>, backend?: DatabaseBackend): Store<Record<string, string>>;
438
482
 
439
483
  /**
@@ -473,6 +517,10 @@ interface StepContext {
473
517
  error(message: string, data?: unknown): void;
474
518
  };
475
519
  }
520
+ /**
521
+ * How a trigger was resolved relative to durable storage.
522
+ */
523
+ type Disposition = 'created' | 'idempotent' | 'coalesced';
476
524
  /**
477
525
  * Trigger options for trigger() and batchTrigger()
478
526
  */
@@ -480,24 +528,41 @@ interface TriggerOptions<TLabels extends Record<string, string> = Record<string,
480
528
  idempotencyKey?: string;
481
529
  concurrencyKey?: string;
482
530
  labels?: TLabels;
531
+ coalesce?: 'skip';
483
532
  }
484
533
  /**
485
- * Options for triggerAndWait() (extends TriggerOptions with wait-specific options)
534
+ * Options for waiting on a run (live onProgress/onLog only; no replay of past events)
486
535
  */
487
- interface TriggerAndWaitOptions<TLabels extends Record<string, string> = Record<string, string>> extends TriggerOptions<TLabels> {
536
+ interface WaitForRunOptions {
488
537
  /** Timeout in milliseconds */
489
538
  timeout?: number;
539
+ /**
540
+ * Storage polling interval when waiting for a non-terminal run (cross-runtime fallback).
541
+ * Omitted values inherit the surrounding `createDurably({ pollingIntervalMs })` setting.
542
+ */
543
+ pollingIntervalMs?: number;
490
544
  /** Called when step.progress() is invoked during execution */
491
545
  onProgress?: (progress: ProgressData$1) => void | Promise<void>;
492
546
  /** Called when step.log is invoked during execution */
493
547
  onLog?: (log: LogData) => void | Promise<void>;
494
548
  }
549
+ /**
550
+ * Options for triggerAndWait() (extends TriggerOptions with wait-specific options)
551
+ */
552
+ interface TriggerAndWaitOptions<TLabels extends Record<string, string> = Record<string, string>> extends TriggerOptions<TLabels>, WaitForRunOptions {
553
+ }
495
554
  /**
496
555
  * Typed run with output type
497
556
  */
498
557
  interface TypedRun<TOutput, TLabels extends Record<string, string> = Record<string, string>> extends Omit<Run<TLabels>, 'output'> {
499
558
  output: TOutput | null;
500
559
  }
560
+ /**
561
+ * Result of trigger() / batchTrigger(): the run plus how it was resolved.
562
+ */
563
+ type TriggerResult<TOutput, TLabels extends Record<string, string> = Record<string, string>> = TypedRun<TOutput, TLabels> & {
564
+ disposition: Disposition;
565
+ };
501
566
  /**
502
567
  * Batch trigger input - either just the input or input with options
503
568
  */
@@ -511,6 +576,7 @@ type BatchTriggerInput<TInput, TLabels extends Record<string, string> = Record<s
511
576
  interface TriggerAndWaitResult<TOutput> {
512
577
  id: string;
513
578
  output: TOutput;
579
+ disposition: Disposition;
514
580
  }
515
581
  /**
516
582
  * Job handle returned by defineJob
@@ -520,7 +586,7 @@ interface JobHandle<TName extends string, TInput, TOutput, TLabels extends Recor
520
586
  /**
521
587
  * Trigger a new run
522
588
  */
523
- trigger(input: TInput, options?: TriggerOptions<TLabels>): Promise<TypedRun<TOutput, TLabels>>;
589
+ trigger(input: TInput, options?: TriggerOptions<TLabels>): Promise<TriggerResult<TOutput, TLabels>>;
524
590
  /**
525
591
  * Trigger a new run and wait for completion
526
592
  * Returns the output directly, throws if the run fails
@@ -530,7 +596,7 @@ interface JobHandle<TName extends string, TInput, TOutput, TLabels extends Recor
530
596
  * Trigger multiple runs in a batch
531
597
  * All inputs are validated before any runs are created
532
598
  */
533
- batchTrigger(inputs: BatchTriggerInput<TInput, TLabels>[]): Promise<TypedRun<TOutput, TLabels>[]>;
599
+ batchTrigger(inputs: BatchTriggerInput<TInput, TLabels>[]): Promise<TriggerResult<TOutput, TLabels>[]>;
534
600
  /**
535
601
  * Get a run by ID
536
602
  */
@@ -612,6 +678,10 @@ interface DurablyOptions<TLabels extends Record<string, string> = Record<string,
612
678
  */
613
679
  singletonKey?: string;
614
680
  pollingIntervalMs?: number;
681
+ /**
682
+ * Maximum number of runs the worker processes concurrently. Defaults to `1` (one run at a time).
683
+ */
684
+ maxConcurrentRuns?: number;
615
685
  leaseRenewIntervalMs?: number;
616
686
  leaseMs?: number;
617
687
  preserveSteps?: boolean;
@@ -639,12 +709,18 @@ interface DurablyOptions<TLabels extends Record<string, string> = Record<string,
639
709
  */
640
710
  retainRuns?: string;
641
711
  }
712
+ /**
713
+ * A Durably instance with erased job types.
714
+ * Use when the function only needs access to Durably's runtime capabilities
715
+ * (trigger, getRun, etc.) without constraining the registered job types.
716
+ */
717
+ type AnyDurably<TLabels extends Record<string, string> = Record<string, string>> = Durably<Record<string, JobHandle<string, unknown, unknown, TLabels>>, TLabels>;
642
718
  /**
643
719
  * Plugin interface for extending Durably
644
720
  */
645
721
  interface DurablyPlugin {
646
722
  name: string;
647
- install(durably: Durably<any, any>): void;
723
+ install(durably: AnyDurably): void;
648
724
  }
649
725
  /**
650
726
  * Helper type to transform JobDefinition record to JobHandle record
@@ -799,6 +875,14 @@ interface Durably<TJobs extends Record<string, JobHandle<string, unknown, unknow
799
875
  * Returns a ReadableStream that can be used for SSE
800
876
  */
801
877
  subscribe(runId: string): ReadableStream<DurablyEvent>;
878
+ /**
879
+ * Wait for an existing run to complete (no new run created).
880
+ * Resolves only when status is completed; failed, cancelled, or missing run throws.
881
+ */
882
+ waitForRun(runId: string, options?: WaitForRunOptions): Promise<Run<TLabels> & {
883
+ status: 'completed';
884
+ output: unknown;
885
+ }>;
802
886
  }
803
887
  /**
804
888
  * Create a Durably instance
@@ -814,4 +898,4 @@ declare function createDurably<TLabels extends Record<string, string> = Record<s
814
898
  */
815
899
  declare function withLogPersistence(): DurablyPlugin;
816
900
 
817
- export { type StepFailEvent as A, type BatchTriggerInput as B, type ClientRun as C, type Durably as D, type ErrorHandler as E, type StepStartEvent as F, type StepsTable as G, type Store as H, type TriggerAndWaitResult as I, type JobDefinition as J, type TriggerOptions as K, type Log as L, createDurably as M, createKyselyStore as N, defineJob as O, type ProgressData$1 as P, toClientRun as Q, type Run as R, type SchemaVersionsTable as S, type TriggerAndWaitOptions as T, type UpdateRunData as U, withLogPersistence as V, 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 RunLeaseRenewedEvent as q, type RunLeasedEvent as r, type RunProgressEvent as s, type RunStatus as t, type RunTriggerEvent as u, type RunsTable as v, type Step as w, type StepCancelEvent as x, type StepCompleteEvent as y, type StepContext as z };
901
+ export { type WorkerErrorEvent as $, type AnyDurably as A, type BatchTriggerInput as B, type ClientRun as C, type Disposition as D, type EnqueueResult as E, type RunTriggerEvent as F, type RunsTable as G, type Step as H, type StepCancelEvent as I, type JobDefinition as J, type StepCompleteEvent as K, type Log as L, type StepContext as M, type StepFailEvent as N, type OperationalEvent as O, type ProgressData$1 as P, type StepStartEvent as Q, type Run as R, type SchemaVersionsTable as S, type StepsTable as T, type Store as U, type TriggerAndWaitOptions as V, type TriggerAndWaitResult as W, type TriggerOptions as X, type TriggerResult as Y, type UpdateRunData as Z, type WaitForRunOptions as _, type RunFilter as a, createDurably as a0, createKyselyStore as a1, defineJob as a2, isDomainEvent as a3, toClientRun as a4, withLogPersistence as a5, type Database as b, type DomainEvent as c, type DomainEventType as d, type Durably as e, type DurablyEvent as f, type DurablyOptions as g, type DurablyPlugin as h, type ErrorHandler as i, type EventType as j, type JobHandle as k, type JobInput as l, type JobOutput as m, type LogData as n, type LogWriteEvent as o, type LogsTable as p, type OperationalEventType as q, type RunCancelEvent as r, type RunCoalescedEvent as s, type RunCompleteEvent as t, type RunDeleteEvent as u, type RunFailEvent as v, type RunLeaseRenewedEvent as w, type RunLeasedEvent as x, type RunProgressEvent as y, type RunStatus as z };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as Run, a as RunFilter, D as Durably } from './index-CDCdrLgw.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 RunLeaseRenewedEvent, r as RunLeasedEvent, s as RunProgressEvent, t as RunStatus, u as RunTriggerEvent, v as RunsTable, S as SchemaVersionsTable, w as Step, x as StepCancelEvent, y as StepCompleteEvent, z as StepContext, A as StepFailEvent, F as StepStartEvent, G as StepsTable, H as Store, T as TriggerAndWaitOptions, I as TriggerAndWaitResult, K as TriggerOptions, U as UpdateRunData, W as WorkerErrorEvent, M as createDurably, N as createKyselyStore, O as defineJob, Q as toClientRun, V as withLogPersistence } from './index-CDCdrLgw.js';
1
+ import { R as Run, a as RunFilter, D as Disposition, A as AnyDurably } from './index-CXH4ozmK.js';
2
+ export { B as BatchTriggerInput, C as ClientRun, b as Database, c as DomainEvent, d as DomainEventType, e as Durably, f as DurablyEvent, g as DurablyOptions, h as DurablyPlugin, E as EnqueueResult, i as ErrorHandler, j as EventType, J as JobDefinition, k as JobHandle, l as JobInput, m as JobOutput, L as Log, n as LogData, o as LogWriteEvent, p as LogsTable, O as OperationalEvent, q as OperationalEventType, P as ProgressData, r as RunCancelEvent, s as RunCoalescedEvent, t as RunCompleteEvent, u as RunDeleteEvent, v as RunFailEvent, w as RunLeaseRenewedEvent, x as RunLeasedEvent, y as RunProgressEvent, z as RunStatus, F as RunTriggerEvent, G as RunsTable, S as SchemaVersionsTable, H as Step, I as StepCancelEvent, K as StepCompleteEvent, M as StepContext, N as StepFailEvent, Q as StepStartEvent, T as StepsTable, U as Store, V as TriggerAndWaitOptions, W as TriggerAndWaitResult, X as TriggerOptions, Y as TriggerResult, Z as UpdateRunData, _ as WaitForRunOptions, $ as WorkerErrorEvent, a0 as createDurably, a1 as createKyselyStore, a2 as defineJob, a3 as isDomainEvent, a4 as toClientRun, a5 as withLogPersistence } from './index-CXH4ozmK.js';
3
3
  import 'kysely';
4
4
  import 'zod';
5
5
 
@@ -55,12 +55,14 @@ interface TriggerRequest<TLabels extends Record<string, string> = Record<string,
55
55
  idempotencyKey?: string;
56
56
  concurrencyKey?: string;
57
57
  labels?: TLabels;
58
+ coalesce?: 'skip';
58
59
  }
59
60
  /**
60
61
  * Response for trigger endpoint
61
62
  */
62
63
  interface TriggerResponse {
63
64
  runId: string;
65
+ disposition: Disposition;
64
66
  }
65
67
  /**
66
68
  * Auth middleware configuration.
@@ -125,6 +127,6 @@ interface CreateDurablyHandlerOptions<TContext = undefined, TLabels extends Reco
125
127
  * Create HTTP handlers for Durably
126
128
  * Uses Web Standard Request/Response for framework-agnostic usage
127
129
  */
128
- declare function createDurablyHandler<TContext = undefined, TLabels extends Record<string, string> = Record<string, string>>(durably: Durably<any, TLabels>, options?: CreateDurablyHandlerOptions<TContext, TLabels>): DurablyHandler;
130
+ declare function createDurablyHandler<TContext = undefined, TLabels extends Record<string, string> = Record<string, string>>(durably: AnyDurably<TLabels>, options?: CreateDurablyHandlerOptions<TContext, TLabels>): DurablyHandler;
129
131
 
130
- export { type AuthConfig, CancelledError, ConflictError, type CreateDurablyHandlerOptions, Durably, DurablyError, type DurablyHandler, LeaseLostError, NotFoundError, Run, RunFilter, type RunOperation, type RunsSubscribeFilter, type TriggerRequest, type TriggerResponse, ValidationError, createDurablyHandler };
132
+ export { AnyDurably, type AuthConfig, CancelledError, ConflictError, type CreateDurablyHandlerOptions, Disposition, DurablyError, type DurablyHandler, LeaseLostError, NotFoundError, Run, RunFilter, type RunOperation, type RunsSubscribeFilter, type TriggerRequest, type TriggerResponse, ValidationError, createDurablyHandler };