@igniter-js/jobs 0.1.14 → 0.1.15

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/AGENTS.md CHANGED
@@ -27,6 +27,7 @@ In modern distributed systems, background processing is usually the first point
27
27
  2. **Resource-Aware Context:** The `withContext()` factory ensures that every job execution starts with a fresh, validated set of resources, exactly like a standard API request.
28
28
  3. **Multi-Platform Support (Adapters):** Whether using **BullMQ** for massive production scale or an **In-Memory** adapter for unit tests, the business logic remains identical.
29
29
  4. **Native Observability:** Telemetry and internal event publishing are "baked in," providing immediate visibility into enqueuing, execution times, failures, and retries without writing a single line of logging code.
30
+ 5. **Typed Job Streams:** Jobs can emit typed per-job stream events for live consumers and optional persisted replay.
30
31
 
31
32
  ---
32
33
 
@@ -55,6 +56,7 @@ Maintainers must respect the following directory structure and responsibilities:
55
56
  - `adapter.ts`: `IgniterJobsAdapter` interface.
56
57
  - `runtime.ts`: Accessor interfaces for the proxy API.
57
58
  - `job.ts`: authoritative types for job definitions, contexts, and hooks.
59
+ - `stream.ts`: typed per-job stream definitions, emit/read/subscribe contracts, and inference helpers.
58
60
  - **`src/utils/`**: Static helper library.
59
61
  - `events.utils.ts`: Pub/sub event helpers and channel composition.
60
62
  - `id-generator.ts`: Deterministic ID utilities for adapters.
package/README.md CHANGED
@@ -25,6 +25,7 @@ Background processing is notoriously hard to keep reliable and observable. `@ign
25
25
  - ✅ **Runtime validation** — Zod or Standard Schema V1 input validation.
26
26
  - ✅ **Scoped jobs** — First-class multi-tenant support via `scope()`.
27
27
  - ✅ **Observability built-in** — Telemetry events and pub/sub job lifecycle events.
28
+ - ✅ **Typed job streams** — Emit live per-job stream events with optional persistence and replay.
28
29
  - ✅ **Adapter-based backends** — In-memory for tests, SQLite for local, BullMQ for production.
29
30
 
30
31
  ---
@@ -636,7 +637,42 @@ const queue = IgniterQueue.create("import")
636
637
  .build();
637
638
  ```
638
639
 
639
- ### 44) Job Logs Inspection
640
+ ### 44) Typed Job Streams
641
+
642
+ ```typescript
643
+ const queue = IgniterQueue.create("ai")
644
+ .addJob("generate", {
645
+ stream: {
646
+ persistence: { enabled: true, maxEvents: 1000 },
647
+ events: {
648
+ "text-delta": z.string(),
649
+ status: z.object({ phase: z.string() }),
650
+ done: z.object({ finishReason: z.string() }),
651
+ },
652
+ },
653
+ handler: async ({ job }) => {
654
+ await job.stream.emit("status", { phase: "thinking" });
655
+ await job.stream.emit("text-delta", "Hello");
656
+ await job.stream.emit("done", { finishReason: "stop" });
657
+ return { ok: true };
658
+ },
659
+ })
660
+ .build();
661
+
662
+ const jobId = await jobs.ai.generate.dispatch({ input: {} });
663
+
664
+ const off = await jobs.ai.generate
665
+ .get(jobId)
666
+ .stream()
667
+ .subscribe((event) => {
668
+ console.log(event.type, event.data);
669
+ });
670
+
671
+ const history = await jobs.ai.generate.get(jobId).stream().read({ limit: 100 });
672
+ await off();
673
+ ```
674
+
675
+ ### 45) Job Logs Inspection
640
676
 
641
677
  ```typescript
642
678
  const logs = await jobs.email.sendWelcome.get("job-id").logs();
@@ -645,7 +681,7 @@ for (const entry of logs) {
645
681
  }
646
682
  ```
647
683
 
648
- ### 45) Queue List with Paging
684
+ ### 46) Queue List with Paging
649
685
 
650
686
  ```typescript
651
687
  const jobsInQueue = await jobs.email.list({
@@ -655,7 +691,7 @@ const jobsInQueue = await jobs.email.list({
655
691
  });
656
692
  ```
657
693
 
658
- ### 46) Worker Limiter Pattern
694
+ ### 47) Worker Limiter Pattern
659
695
 
660
696
  ```typescript
661
697
  const worker = await jobs.worker
@@ -665,14 +701,14 @@ const worker = await jobs.worker
665
701
  .start();
666
702
  ```
667
703
 
668
- ### 47) Worker Sharding by Queue
704
+ ### 48) Worker Sharding by Queue
669
705
 
670
706
  ```typescript
671
707
  const workerA = await jobs.worker.create().addQueue("email").start();
672
708
  const workerB = await jobs.worker.create().addQueue("analytics").start();
673
709
  ```
674
710
 
675
- ### 48) Graceful Shutdown in Process
711
+ ### 49) Graceful Shutdown in Process
676
712
 
677
713
  ```typescript
678
714
  process.on("SIGINT", async () => {
@@ -127,6 +127,62 @@ type IgniterJobsInferSchemaOutput<TSchema> = TSchema extends StandardSchemaV1 ?
127
127
  _output?: infer TOutput;
128
128
  } ? TOutput : unknown;
129
129
 
130
+ type IgniterJobsJobStreamSchemaMap = Record<string, IgniterJobsSchema>;
131
+ interface IgniterJobsJobStreamPersistenceConfig {
132
+ enabled: boolean;
133
+ maxEvents?: number;
134
+ }
135
+ interface IgniterJobsJobStreamDefinition<TEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> {
136
+ persistence?: IgniterJobsJobStreamPersistenceConfig;
137
+ events?: TEvents;
138
+ }
139
+ interface IgniterJobsJobStreamEvent<TType extends string = string, TData = unknown> {
140
+ id: string;
141
+ type: TType;
142
+ data: TData;
143
+ timestamp: Date;
144
+ jobId: string;
145
+ jobName: string;
146
+ queue: string;
147
+ scope?: IgniterJobsScopeEntry;
148
+ }
149
+ interface IgniterJobsJobStreamReadParams {
150
+ after?: string;
151
+ limit?: number;
152
+ }
153
+ type IgniterJobsJobStreamReadResult<TEvent extends IgniterJobsJobStreamEvent = IgniterJobsJobStreamEvent> = {
154
+ items: TEvent[];
155
+ nextCursor?: string;
156
+ hasMore: boolean;
157
+ };
158
+ type IgniterJobsStreamEventsFromDefinition<TDef> = TDef extends {
159
+ stream?: {
160
+ events?: infer TEvents;
161
+ };
162
+ } ? TEvents extends IgniterJobsJobStreamSchemaMap ? TEvents : {} : {};
163
+ type IgniterJobsStreamEventKeys<TDef> = Extract<keyof IgniterJobsStreamEventsFromDefinition<TDef>, string>;
164
+ type IgniterJobsInferStreamType<TDef> = [
165
+ IgniterJobsStreamEventKeys<TDef>
166
+ ] extends [never] ? string : IgniterJobsStreamEventKeys<TDef>;
167
+ type IgniterJobsInferStreamEmitData<TDef, TType extends string> = [
168
+ IgniterJobsStreamEventKeys<TDef>
169
+ ] extends [never] ? unknown : TType extends IgniterJobsStreamEventKeys<TDef> ? IgniterJobsInferSchemaInput<IgniterJobsStreamEventsFromDefinition<TDef>[TType]> : unknown;
170
+ type IgniterJobsInferStreamReadData<TDef, TType extends string> = [
171
+ IgniterJobsStreamEventKeys<TDef>
172
+ ] extends [never] ? unknown : TType extends IgniterJobsStreamEventKeys<TDef> ? IgniterJobsInferSchemaOutput<IgniterJobsStreamEventsFromDefinition<TDef>[TType]> : unknown;
173
+ type IgniterJobsInferJobStreamEvent<TDef> = [
174
+ IgniterJobsStreamEventKeys<TDef>
175
+ ] extends [never] ? IgniterJobsJobStreamEvent<string, unknown> : {
176
+ [K in IgniterJobsStreamEventKeys<TDef>]: IgniterJobsJobStreamEvent<K, IgniterJobsInferStreamReadData<TDef, K>>;
177
+ }[IgniterJobsStreamEventKeys<TDef>];
178
+ interface IgniterJobsExecutionStreamEmitter<TDef = unknown, TType extends string = IgniterJobsInferStreamType<TDef>> {
179
+ emit<TEventType extends TType>(type: TEventType, data: IgniterJobsInferStreamEmitData<TDef, TEventType>): Promise<string>;
180
+ }
181
+ interface IgniterJobsJobStreamAccessor<TDef = unknown> {
182
+ subscribe(handler: (event: IgniterJobsInferJobStreamEvent<TDef>) => void | Promise<void>): Promise<() => Promise<void>>;
183
+ read(params?: IgniterJobsJobStreamReadParams): Promise<IgniterJobsJobStreamReadResult<IgniterJobsInferJobStreamEvent<TDef>>>;
184
+ }
185
+
130
186
  /**
131
187
  * Rate limiter configuration applied to job dispatch or worker level.
132
188
  */
@@ -152,7 +208,7 @@ interface IgniterJobsInvokeOptions {
152
208
  /**
153
209
  * Runtime execution context passed to handlers.
154
210
  */
155
- interface IgniterJobsExecutionContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown> {
211
+ interface IgniterJobsExecutionContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> {
156
212
  input: IgniterJobsInferSchemaInput<TInput>;
157
213
  context: TContext;
158
214
  job: {
@@ -171,45 +227,51 @@ interface IgniterJobsExecutionContext<TContext, TInput extends IgniterJobsSchema
171
227
  * Reports job progress and triggers the public progress hook when supported by the adapter.
172
228
  */
173
229
  updateProgress?: (progress: number, message?: string) => Promise<void>;
230
+ /**
231
+ * Emits typed stream events for the current job execution.
232
+ */
233
+ stream: IgniterJobsExecutionStreamEmitter<IgniterJobDefinition<TContext, TInput, unknown, TStreamEvents>>;
174
234
  };
175
235
  scope?: IgniterJobsScopeEntry;
176
236
  }
177
237
  /**
178
238
  * Hook context shared by lifecycle handlers.
179
239
  */
180
- interface IgniterJobsHookContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown> extends IgniterJobsExecutionContext<TContext, TInput> {
240
+ interface IgniterJobsHookContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> extends IgniterJobsExecutionContext<TContext, TInput, TStreamEvents> {
181
241
  startedAt?: Date;
182
242
  duration?: number;
183
243
  }
184
- type IgniterJobsStartHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown> = (context: IgniterJobsHookContext<TContext, TInput>) => void | Promise<void>;
185
- type IgniterJobsSuccessHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown> = (context: IgniterJobsHookContext<TContext, TInput> & {
244
+ type IgniterJobsStartHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents>) => void | Promise<void>;
245
+ type IgniterJobsSuccessHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents> & {
186
246
  result: TResult;
187
247
  }) => void | Promise<void>;
188
- type IgniterJobsFailureHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown> = (context: IgniterJobsHookContext<TContext, TInput> & {
248
+ type IgniterJobsFailureHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents> & {
189
249
  error: Error;
190
250
  isFinalAttempt: boolean;
191
251
  }) => void | Promise<void>;
192
- type IgniterJobsProgressHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown> = (context: IgniterJobsHookContext<TContext, TInput> & {
252
+ type IgniterJobsProgressHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents> & {
193
253
  progress: number;
194
254
  message?: string;
195
255
  }) => void | Promise<void>;
196
256
  /**
197
257
  * Definition of a job registered on a queue.
198
258
  */
199
- interface IgniterJobDefinition<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown> extends IgniterJobsInvokeOptions {
259
+ interface IgniterJobDefinition<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> extends IgniterJobsInvokeOptions {
200
260
  /** Optional input schema for validation. */
201
261
  input?: TInput;
202
262
  /** Optional output schema (validation handled externally). */
203
263
  output?: IgniterJobsSchema;
204
264
  /** Optional queue override (creates child queue in adapters). */
205
265
  queue?: string;
266
+ /** Optional stream configuration for live and persisted per-job events. */
267
+ stream?: IgniterJobsJobStreamDefinition<TStreamEvents>;
206
268
  /** Job handler implementation. */
207
- handler: (context: IgniterJobsExecutionContext<TContext, TInput>) => Promise<TResult> | TResult;
269
+ handler: (context: IgniterJobsExecutionContext<TContext, TInput, TStreamEvents>) => Promise<TResult> | TResult;
208
270
  /** Lifecycle hooks */
209
- onStart?: IgniterJobsStartHook<TContext, TInput>;
210
- onProgress?: IgniterJobsProgressHook<TContext, TInput>;
211
- onSuccess?: IgniterJobsSuccessHook<TContext, TInput, TResult>;
212
- onFailure?: IgniterJobsFailureHook<TContext, TInput>;
271
+ onStart?: IgniterJobsStartHook<TContext, TInput, TStreamEvents>;
272
+ onProgress?: IgniterJobsProgressHook<TContext, TInput, TStreamEvents>;
273
+ onSuccess?: IgniterJobsSuccessHook<TContext, TInput, TResult, TStreamEvents>;
274
+ onFailure?: IgniterJobsFailureHook<TContext, TInput, TStreamEvents>;
213
275
  }
214
276
  /**
215
277
  * Definition for cron-style recurring tasks.
@@ -303,11 +365,11 @@ type IgniterJobsScheduleParams<TInput = unknown> = IgniterJobsDispatchParams<TIn
303
365
  /**
304
366
  * Queue configuration produced by `IgniterQueueBuilder`.
305
367
  */
306
- interface IgniterJobsQueue<TContext, TJobs extends Record<string, IgniterJobDefinition<TContext, any, any>>, TCron extends Record<string, IgniterCronDefinition<TContext, any>>> {
368
+ interface IgniterJobsQueue<TContext, TJobs extends Record<string, IgniterJobDefinition<TContext, any, any, any>>, TCron extends Record<string, IgniterCronDefinition<TContext, any>>> {
307
369
  name: string;
308
370
  jobs: TJobs;
309
371
  crons: TCron;
310
- defaultJobOptions?: Partial<IgniterJobDefinition<TContext, any, any>>;
372
+ defaultJobOptions?: Partial<IgniterJobDefinition<TContext, any, any, any>>;
311
373
  }
312
374
  /**
313
375
  * Information about a queue used by management APIs.
@@ -481,6 +543,25 @@ interface IgniterJobsJobLog {
481
543
  message: string;
482
544
  level: "info" | "warn" | "error";
483
545
  }
546
+ interface IgniterJobsAdapterJobStreamWriteParams {
547
+ queue: string;
548
+ jobName: string;
549
+ jobId: string;
550
+ scope?: IgniterJobsScopeEntry;
551
+ persistence?: IgniterJobsJobStreamPersistenceConfig;
552
+ event: Omit<IgniterJobsJobStreamEvent<string, unknown>, "id">;
553
+ }
554
+ interface IgniterJobsAdapterJobStreamReadParams {
555
+ queue: string;
556
+ jobId: string;
557
+ after?: string;
558
+ limit?: number;
559
+ }
560
+ interface IgniterJobsAdapterJobStreamSubscribeParams {
561
+ queue: string;
562
+ jobId: string;
563
+ handler: (event: IgniterJobsJobStreamEvent<string, unknown>) => void | Promise<void>;
564
+ }
484
565
  /**
485
566
  * Adapter contract for jobs backends.
486
567
  */
@@ -517,6 +598,9 @@ interface IgniterJobsAdapter {
517
598
  getWorkers(): Map<string, IgniterJobsWorkerHandle>;
518
599
  publishEvent(channel: string, payload: unknown): Promise<void>;
519
600
  subscribeEvent(channel: string, handler: IgniterJobsEventHandler): Promise<() => Promise<void>>;
601
+ writeJobStreamEvent(params: IgniterJobsAdapterJobStreamWriteParams): Promise<string>;
602
+ readJobStream(params: IgniterJobsAdapterJobStreamReadParams): Promise<IgniterJobsJobStreamReadResult<IgniterJobsJobStreamEvent<string, unknown>>>;
603
+ subscribeJobStream(params: IgniterJobsAdapterJobStreamSubscribeParams): Promise<() => Promise<void>>;
520
604
  registerJob(queueName: string, jobName: string, definition: IgniterJobDefinition<any, any, any>): void;
521
605
  registerCron(queueName: string, cronName: string, definition: IgniterCronDefinition<any, any>): void;
522
606
  shutdown(): Promise<void>;
@@ -547,4 +631,4 @@ interface IgniterJobsBunSQLiteAdapterOptions {
547
631
  maxStalledCount?: number;
548
632
  }
549
633
 
550
- export type { IgniterJobsExecutionContext as A, IgniterJobsFailureHook as B, IgniterJobsHookContext as C, IgniterJobsInferSchemaOutput as D, IgniterJobsInvokeOptions as E, IgniterJobsJobLog as F, IgniterJobsProgressHook as G, IgniterJobsQueueManager as H, IgniterJobsQueue as I, IgniterJobsScheduleOptions as J, IgniterJobsStartHook as K, IgniterJobsSuccessHook as L, IgniterJobsWorkerMetrics as M, IgniterJobsAdapter as a, IgniterJobsScopeDefinition as b, IgniterJobDefinition as c, IgniterJobsWorkerBuilderConfig as d, IgniterJobsTelemetry as e, IgniterJobsEventHandler as f, IgniterJobSearchResult as g, IgniterJobsQueueInfo as h, IgniterJobsWorkerHandle as i, IgniterJobsLimiter as j, IgniterJobsWorkerHandlers as k, IgniterJobsQueueCleanOptions as l, IgniterJobStatus as m, IgniterJobsDispatchParams as n, IgniterJobsScheduleParams as o, IgniterJobsInferSchemaInput as p, IgniterCronDefinition as q, IgniterJobsScopeEntry as r, IgniterJobsSchema as s, IgniterJobsScopeOptions as t, IgniterJobCounts as u, IgniterJobsAdapterDispatchParams as v, IgniterJobsAdapterScheduleParams as w, IgniterJobsBullMQAdapterOptions as x, IgniterJobsBunSQLiteAdapterOptions as y, IgniterJobsEvent as z };
634
+ export type { IgniterJobsSuccessHook as $, IgniterJobsAdapterJobStreamWriteParams as A, IgniterJobsAdapterScheduleParams as B, IgniterJobsBullMQAdapterOptions as C, IgniterJobsBunSQLiteAdapterOptions as D, IgniterJobsEvent as E, IgniterJobsExecutionContext as F, IgniterJobsExecutionStreamEmitter as G, IgniterJobsFailureHook as H, IgniterJobsQueue as I, IgniterJobsHookContext as J, IgniterJobsInferJobStreamEvent as K, IgniterJobsInferSchemaOutput as L, IgniterJobsInferStreamEmitData as M, IgniterJobsInferStreamReadData as N, IgniterJobsInferStreamType as O, IgniterJobsInvokeOptions as P, IgniterJobsJobLog as Q, IgniterJobsJobStreamDefinition as R, IgniterJobsJobStreamEvent as S, IgniterJobsJobStreamPersistenceConfig as T, IgniterJobsJobStreamReadParams as U, IgniterJobsJobStreamReadResult as V, IgniterJobsProgressHook as W, IgniterJobsQueueManager as X, IgniterJobsScheduleOptions as Y, IgniterJobsStartHook as Z, IgniterJobsStreamEventsFromDefinition as _, IgniterJobsAdapter as a, IgniterJobsWorkerMetrics as a0, IgniterJobsScopeDefinition as b, IgniterJobDefinition as c, IgniterJobsWorkerBuilderConfig as d, IgniterJobsTelemetry as e, IgniterJobsEventHandler as f, IgniterJobSearchResult as g, IgniterJobsQueueInfo as h, IgniterJobsWorkerHandle as i, IgniterJobsLimiter as j, IgniterJobsWorkerHandlers as k, IgniterJobsQueueCleanOptions as l, IgniterJobStatus as m, IgniterJobsDispatchParams as n, IgniterJobsInferSchemaInput as o, IgniterJobsScheduleParams as p, IgniterJobsJobStreamAccessor as q, IgniterCronDefinition as r, IgniterJobsScopeEntry as s, IgniterJobsSchema as t, IgniterJobsJobStreamSchemaMap as u, IgniterJobsScopeOptions as v, IgniterJobCounts as w, IgniterJobsAdapterDispatchParams as x, IgniterJobsAdapterJobStreamReadParams as y, IgniterJobsAdapterJobStreamSubscribeParams as z };
@@ -127,6 +127,62 @@ type IgniterJobsInferSchemaOutput<TSchema> = TSchema extends StandardSchemaV1 ?
127
127
  _output?: infer TOutput;
128
128
  } ? TOutput : unknown;
129
129
 
130
+ type IgniterJobsJobStreamSchemaMap = Record<string, IgniterJobsSchema>;
131
+ interface IgniterJobsJobStreamPersistenceConfig {
132
+ enabled: boolean;
133
+ maxEvents?: number;
134
+ }
135
+ interface IgniterJobsJobStreamDefinition<TEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> {
136
+ persistence?: IgniterJobsJobStreamPersistenceConfig;
137
+ events?: TEvents;
138
+ }
139
+ interface IgniterJobsJobStreamEvent<TType extends string = string, TData = unknown> {
140
+ id: string;
141
+ type: TType;
142
+ data: TData;
143
+ timestamp: Date;
144
+ jobId: string;
145
+ jobName: string;
146
+ queue: string;
147
+ scope?: IgniterJobsScopeEntry;
148
+ }
149
+ interface IgniterJobsJobStreamReadParams {
150
+ after?: string;
151
+ limit?: number;
152
+ }
153
+ type IgniterJobsJobStreamReadResult<TEvent extends IgniterJobsJobStreamEvent = IgniterJobsJobStreamEvent> = {
154
+ items: TEvent[];
155
+ nextCursor?: string;
156
+ hasMore: boolean;
157
+ };
158
+ type IgniterJobsStreamEventsFromDefinition<TDef> = TDef extends {
159
+ stream?: {
160
+ events?: infer TEvents;
161
+ };
162
+ } ? TEvents extends IgniterJobsJobStreamSchemaMap ? TEvents : {} : {};
163
+ type IgniterJobsStreamEventKeys<TDef> = Extract<keyof IgniterJobsStreamEventsFromDefinition<TDef>, string>;
164
+ type IgniterJobsInferStreamType<TDef> = [
165
+ IgniterJobsStreamEventKeys<TDef>
166
+ ] extends [never] ? string : IgniterJobsStreamEventKeys<TDef>;
167
+ type IgniterJobsInferStreamEmitData<TDef, TType extends string> = [
168
+ IgniterJobsStreamEventKeys<TDef>
169
+ ] extends [never] ? unknown : TType extends IgniterJobsStreamEventKeys<TDef> ? IgniterJobsInferSchemaInput<IgniterJobsStreamEventsFromDefinition<TDef>[TType]> : unknown;
170
+ type IgniterJobsInferStreamReadData<TDef, TType extends string> = [
171
+ IgniterJobsStreamEventKeys<TDef>
172
+ ] extends [never] ? unknown : TType extends IgniterJobsStreamEventKeys<TDef> ? IgniterJobsInferSchemaOutput<IgniterJobsStreamEventsFromDefinition<TDef>[TType]> : unknown;
173
+ type IgniterJobsInferJobStreamEvent<TDef> = [
174
+ IgniterJobsStreamEventKeys<TDef>
175
+ ] extends [never] ? IgniterJobsJobStreamEvent<string, unknown> : {
176
+ [K in IgniterJobsStreamEventKeys<TDef>]: IgniterJobsJobStreamEvent<K, IgniterJobsInferStreamReadData<TDef, K>>;
177
+ }[IgniterJobsStreamEventKeys<TDef>];
178
+ interface IgniterJobsExecutionStreamEmitter<TDef = unknown, TType extends string = IgniterJobsInferStreamType<TDef>> {
179
+ emit<TEventType extends TType>(type: TEventType, data: IgniterJobsInferStreamEmitData<TDef, TEventType>): Promise<string>;
180
+ }
181
+ interface IgniterJobsJobStreamAccessor<TDef = unknown> {
182
+ subscribe(handler: (event: IgniterJobsInferJobStreamEvent<TDef>) => void | Promise<void>): Promise<() => Promise<void>>;
183
+ read(params?: IgniterJobsJobStreamReadParams): Promise<IgniterJobsJobStreamReadResult<IgniterJobsInferJobStreamEvent<TDef>>>;
184
+ }
185
+
130
186
  /**
131
187
  * Rate limiter configuration applied to job dispatch or worker level.
132
188
  */
@@ -152,7 +208,7 @@ interface IgniterJobsInvokeOptions {
152
208
  /**
153
209
  * Runtime execution context passed to handlers.
154
210
  */
155
- interface IgniterJobsExecutionContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown> {
211
+ interface IgniterJobsExecutionContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> {
156
212
  input: IgniterJobsInferSchemaInput<TInput>;
157
213
  context: TContext;
158
214
  job: {
@@ -171,45 +227,51 @@ interface IgniterJobsExecutionContext<TContext, TInput extends IgniterJobsSchema
171
227
  * Reports job progress and triggers the public progress hook when supported by the adapter.
172
228
  */
173
229
  updateProgress?: (progress: number, message?: string) => Promise<void>;
230
+ /**
231
+ * Emits typed stream events for the current job execution.
232
+ */
233
+ stream: IgniterJobsExecutionStreamEmitter<IgniterJobDefinition<TContext, TInput, unknown, TStreamEvents>>;
174
234
  };
175
235
  scope?: IgniterJobsScopeEntry;
176
236
  }
177
237
  /**
178
238
  * Hook context shared by lifecycle handlers.
179
239
  */
180
- interface IgniterJobsHookContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown> extends IgniterJobsExecutionContext<TContext, TInput> {
240
+ interface IgniterJobsHookContext<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> extends IgniterJobsExecutionContext<TContext, TInput, TStreamEvents> {
181
241
  startedAt?: Date;
182
242
  duration?: number;
183
243
  }
184
- type IgniterJobsStartHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown> = (context: IgniterJobsHookContext<TContext, TInput>) => void | Promise<void>;
185
- type IgniterJobsSuccessHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown> = (context: IgniterJobsHookContext<TContext, TInput> & {
244
+ type IgniterJobsStartHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents>) => void | Promise<void>;
245
+ type IgniterJobsSuccessHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents> & {
186
246
  result: TResult;
187
247
  }) => void | Promise<void>;
188
- type IgniterJobsFailureHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown> = (context: IgniterJobsHookContext<TContext, TInput> & {
248
+ type IgniterJobsFailureHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents> & {
189
249
  error: Error;
190
250
  isFinalAttempt: boolean;
191
251
  }) => void | Promise<void>;
192
- type IgniterJobsProgressHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown> = (context: IgniterJobsHookContext<TContext, TInput> & {
252
+ type IgniterJobsProgressHook<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> = (context: IgniterJobsHookContext<TContext, TInput, TStreamEvents> & {
193
253
  progress: number;
194
254
  message?: string;
195
255
  }) => void | Promise<void>;
196
256
  /**
197
257
  * Definition of a job registered on a queue.
198
258
  */
199
- interface IgniterJobDefinition<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown> extends IgniterJobsInvokeOptions {
259
+ interface IgniterJobDefinition<TContext, TInput extends IgniterJobsSchema | unknown = unknown, TResult = unknown, TStreamEvents extends IgniterJobsJobStreamSchemaMap | undefined = undefined> extends IgniterJobsInvokeOptions {
200
260
  /** Optional input schema for validation. */
201
261
  input?: TInput;
202
262
  /** Optional output schema (validation handled externally). */
203
263
  output?: IgniterJobsSchema;
204
264
  /** Optional queue override (creates child queue in adapters). */
205
265
  queue?: string;
266
+ /** Optional stream configuration for live and persisted per-job events. */
267
+ stream?: IgniterJobsJobStreamDefinition<TStreamEvents>;
206
268
  /** Job handler implementation. */
207
- handler: (context: IgniterJobsExecutionContext<TContext, TInput>) => Promise<TResult> | TResult;
269
+ handler: (context: IgniterJobsExecutionContext<TContext, TInput, TStreamEvents>) => Promise<TResult> | TResult;
208
270
  /** Lifecycle hooks */
209
- onStart?: IgniterJobsStartHook<TContext, TInput>;
210
- onProgress?: IgniterJobsProgressHook<TContext, TInput>;
211
- onSuccess?: IgniterJobsSuccessHook<TContext, TInput, TResult>;
212
- onFailure?: IgniterJobsFailureHook<TContext, TInput>;
271
+ onStart?: IgniterJobsStartHook<TContext, TInput, TStreamEvents>;
272
+ onProgress?: IgniterJobsProgressHook<TContext, TInput, TStreamEvents>;
273
+ onSuccess?: IgniterJobsSuccessHook<TContext, TInput, TResult, TStreamEvents>;
274
+ onFailure?: IgniterJobsFailureHook<TContext, TInput, TStreamEvents>;
213
275
  }
214
276
  /**
215
277
  * Definition for cron-style recurring tasks.
@@ -303,11 +365,11 @@ type IgniterJobsScheduleParams<TInput = unknown> = IgniterJobsDispatchParams<TIn
303
365
  /**
304
366
  * Queue configuration produced by `IgniterQueueBuilder`.
305
367
  */
306
- interface IgniterJobsQueue<TContext, TJobs extends Record<string, IgniterJobDefinition<TContext, any, any>>, TCron extends Record<string, IgniterCronDefinition<TContext, any>>> {
368
+ interface IgniterJobsQueue<TContext, TJobs extends Record<string, IgniterJobDefinition<TContext, any, any, any>>, TCron extends Record<string, IgniterCronDefinition<TContext, any>>> {
307
369
  name: string;
308
370
  jobs: TJobs;
309
371
  crons: TCron;
310
- defaultJobOptions?: Partial<IgniterJobDefinition<TContext, any, any>>;
372
+ defaultJobOptions?: Partial<IgniterJobDefinition<TContext, any, any, any>>;
311
373
  }
312
374
  /**
313
375
  * Information about a queue used by management APIs.
@@ -481,6 +543,25 @@ interface IgniterJobsJobLog {
481
543
  message: string;
482
544
  level: "info" | "warn" | "error";
483
545
  }
546
+ interface IgniterJobsAdapterJobStreamWriteParams {
547
+ queue: string;
548
+ jobName: string;
549
+ jobId: string;
550
+ scope?: IgniterJobsScopeEntry;
551
+ persistence?: IgniterJobsJobStreamPersistenceConfig;
552
+ event: Omit<IgniterJobsJobStreamEvent<string, unknown>, "id">;
553
+ }
554
+ interface IgniterJobsAdapterJobStreamReadParams {
555
+ queue: string;
556
+ jobId: string;
557
+ after?: string;
558
+ limit?: number;
559
+ }
560
+ interface IgniterJobsAdapterJobStreamSubscribeParams {
561
+ queue: string;
562
+ jobId: string;
563
+ handler: (event: IgniterJobsJobStreamEvent<string, unknown>) => void | Promise<void>;
564
+ }
484
565
  /**
485
566
  * Adapter contract for jobs backends.
486
567
  */
@@ -517,6 +598,9 @@ interface IgniterJobsAdapter {
517
598
  getWorkers(): Map<string, IgniterJobsWorkerHandle>;
518
599
  publishEvent(channel: string, payload: unknown): Promise<void>;
519
600
  subscribeEvent(channel: string, handler: IgniterJobsEventHandler): Promise<() => Promise<void>>;
601
+ writeJobStreamEvent(params: IgniterJobsAdapterJobStreamWriteParams): Promise<string>;
602
+ readJobStream(params: IgniterJobsAdapterJobStreamReadParams): Promise<IgniterJobsJobStreamReadResult<IgniterJobsJobStreamEvent<string, unknown>>>;
603
+ subscribeJobStream(params: IgniterJobsAdapterJobStreamSubscribeParams): Promise<() => Promise<void>>;
520
604
  registerJob(queueName: string, jobName: string, definition: IgniterJobDefinition<any, any, any>): void;
521
605
  registerCron(queueName: string, cronName: string, definition: IgniterCronDefinition<any, any>): void;
522
606
  shutdown(): Promise<void>;
@@ -547,4 +631,4 @@ interface IgniterJobsBunSQLiteAdapterOptions {
547
631
  maxStalledCount?: number;
548
632
  }
549
633
 
550
- export type { IgniterJobsExecutionContext as A, IgniterJobsFailureHook as B, IgniterJobsHookContext as C, IgniterJobsInferSchemaOutput as D, IgniterJobsInvokeOptions as E, IgniterJobsJobLog as F, IgniterJobsProgressHook as G, IgniterJobsQueueManager as H, IgniterJobsQueue as I, IgniterJobsScheduleOptions as J, IgniterJobsStartHook as K, IgniterJobsSuccessHook as L, IgniterJobsWorkerMetrics as M, IgniterJobsAdapter as a, IgniterJobsScopeDefinition as b, IgniterJobDefinition as c, IgniterJobsWorkerBuilderConfig as d, IgniterJobsTelemetry as e, IgniterJobsEventHandler as f, IgniterJobSearchResult as g, IgniterJobsQueueInfo as h, IgniterJobsWorkerHandle as i, IgniterJobsLimiter as j, IgniterJobsWorkerHandlers as k, IgniterJobsQueueCleanOptions as l, IgniterJobStatus as m, IgniterJobsDispatchParams as n, IgniterJobsScheduleParams as o, IgniterJobsInferSchemaInput as p, IgniterCronDefinition as q, IgniterJobsScopeEntry as r, IgniterJobsSchema as s, IgniterJobsScopeOptions as t, IgniterJobCounts as u, IgniterJobsAdapterDispatchParams as v, IgniterJobsAdapterScheduleParams as w, IgniterJobsBullMQAdapterOptions as x, IgniterJobsBunSQLiteAdapterOptions as y, IgniterJobsEvent as z };
634
+ export type { IgniterJobsSuccessHook as $, IgniterJobsAdapterJobStreamWriteParams as A, IgniterJobsAdapterScheduleParams as B, IgniterJobsBullMQAdapterOptions as C, IgniterJobsBunSQLiteAdapterOptions as D, IgniterJobsEvent as E, IgniterJobsExecutionContext as F, IgniterJobsExecutionStreamEmitter as G, IgniterJobsFailureHook as H, IgniterJobsQueue as I, IgniterJobsHookContext as J, IgniterJobsInferJobStreamEvent as K, IgniterJobsInferSchemaOutput as L, IgniterJobsInferStreamEmitData as M, IgniterJobsInferStreamReadData as N, IgniterJobsInferStreamType as O, IgniterJobsInvokeOptions as P, IgniterJobsJobLog as Q, IgniterJobsJobStreamDefinition as R, IgniterJobsJobStreamEvent as S, IgniterJobsJobStreamPersistenceConfig as T, IgniterJobsJobStreamReadParams as U, IgniterJobsJobStreamReadResult as V, IgniterJobsProgressHook as W, IgniterJobsQueueManager as X, IgniterJobsScheduleOptions as Y, IgniterJobsStartHook as Z, IgniterJobsStreamEventsFromDefinition as _, IgniterJobsAdapter as a, IgniterJobsWorkerMetrics as a0, IgniterJobsScopeDefinition as b, IgniterJobDefinition as c, IgniterJobsWorkerBuilderConfig as d, IgniterJobsTelemetry as e, IgniterJobsEventHandler as f, IgniterJobSearchResult as g, IgniterJobsQueueInfo as h, IgniterJobsWorkerHandle as i, IgniterJobsLimiter as j, IgniterJobsWorkerHandlers as k, IgniterJobsQueueCleanOptions as l, IgniterJobStatus as m, IgniterJobsDispatchParams as n, IgniterJobsInferSchemaInput as o, IgniterJobsScheduleParams as p, IgniterJobsJobStreamAccessor as q, IgniterCronDefinition as r, IgniterJobsScopeEntry as s, IgniterJobsSchema as t, IgniterJobsJobStreamSchemaMap as u, IgniterJobsScopeOptions as v, IgniterJobCounts as w, IgniterJobsAdapterDispatchParams as x, IgniterJobsAdapterJobStreamReadParams as y, IgniterJobsAdapterJobStreamSubscribeParams as z };
@@ -1,4 +1,4 @@
1
- import { a as IgniterJobsAdapter, H as IgniterJobsQueueManager, y as IgniterJobsBunSQLiteAdapterOptions, c as IgniterJobDefinition, q as IgniterCronDefinition, v as IgniterJobsAdapterDispatchParams, w as IgniterJobsAdapterScheduleParams, g as IgniterJobSearchResult, m as IgniterJobStatus, F as IgniterJobsJobLog, h as IgniterJobsQueueInfo, u as IgniterJobCounts, l as IgniterJobsQueueCleanOptions, i as IgniterJobsWorkerHandle, d as IgniterJobsWorkerBuilderConfig, f as IgniterJobsEventHandler } from '../adapter-Cax_40HW.mjs';
1
+ import { a as IgniterJobsAdapter, X as IgniterJobsQueueManager, D as IgniterJobsBunSQLiteAdapterOptions, c as IgniterJobDefinition, r as IgniterCronDefinition, x as IgniterJobsAdapterDispatchParams, B as IgniterJobsAdapterScheduleParams, g as IgniterJobSearchResult, m as IgniterJobStatus, Q as IgniterJobsJobLog, h as IgniterJobsQueueInfo, w as IgniterJobCounts, l as IgniterJobsQueueCleanOptions, i as IgniterJobsWorkerHandle, d as IgniterJobsWorkerBuilderConfig, f as IgniterJobsEventHandler, A as IgniterJobsAdapterJobStreamWriteParams, y as IgniterJobsAdapterJobStreamReadParams, V as IgniterJobsJobStreamReadResult, S as IgniterJobsJobStreamEvent, z as IgniterJobsAdapterJobStreamSubscribeParams } from '../adapter-DDyMVche.mjs';
2
2
  import 'ioredis';
3
3
  import '@igniter-js/common';
4
4
 
@@ -21,7 +21,9 @@ declare class IgniterJobsBunSQLiteAdapter implements IgniterJobsAdapter {
21
21
  private readonly queueRuntimes;
22
22
  private readonly workers;
23
23
  private readonly subscribers;
24
+ private readonly streamSubscribers;
24
25
  private readonly registeredJobs;
26
+ private streamDatabasePromise;
25
27
  private readonly registeredCrons;
26
28
  private constructor();
27
29
  static create(options: IgniterJobsBunSQLiteAdapterOptions): IgniterJobsAdapter;
@@ -57,8 +59,12 @@ declare class IgniterJobsBunSQLiteAdapter implements IgniterJobsAdapter {
57
59
  getWorkers(): Map<string, IgniterJobsWorkerHandle>;
58
60
  publishEvent(channel: string, payload: unknown): Promise<void>;
59
61
  subscribeEvent(channel: string, handler: IgniterJobsEventHandler): Promise<() => Promise<void>>;
62
+ writeJobStreamEvent(params: IgniterJobsAdapterJobStreamWriteParams): Promise<string>;
63
+ readJobStream(params: IgniterJobsAdapterJobStreamReadParams): Promise<IgniterJobsJobStreamReadResult<IgniterJobsJobStreamEvent<string, unknown>>>;
64
+ subscribeJobStream(params: IgniterJobsAdapterJobStreamSubscribeParams): Promise<() => Promise<void>>;
60
65
  shutdown(): Promise<void>;
61
66
  private loadBunqueue;
67
+ private getStreamDatabase;
62
68
  private getQueue;
63
69
  private getAllQueueNames;
64
70
  private markQueueCronsDirty;
@@ -75,6 +81,8 @@ declare class IgniterJobsBunSQLiteAdapter implements IgniterJobsAdapter {
75
81
  private closeWorkerState;
76
82
  private requireJob;
77
83
  private findQueueByJobId;
84
+ private getStreamKey;
85
+ private mapStreamRow;
78
86
  private mapJob;
79
87
  private mapJobSync;
80
88
  private normalizeEnvelope;
@@ -1,4 +1,4 @@
1
- import { a as IgniterJobsAdapter, H as IgniterJobsQueueManager, y as IgniterJobsBunSQLiteAdapterOptions, c as IgniterJobDefinition, q as IgniterCronDefinition, v as IgniterJobsAdapterDispatchParams, w as IgniterJobsAdapterScheduleParams, g as IgniterJobSearchResult, m as IgniterJobStatus, F as IgniterJobsJobLog, h as IgniterJobsQueueInfo, u as IgniterJobCounts, l as IgniterJobsQueueCleanOptions, i as IgniterJobsWorkerHandle, d as IgniterJobsWorkerBuilderConfig, f as IgniterJobsEventHandler } from '../adapter-Cax_40HW.js';
1
+ import { a as IgniterJobsAdapter, X as IgniterJobsQueueManager, D as IgniterJobsBunSQLiteAdapterOptions, c as IgniterJobDefinition, r as IgniterCronDefinition, x as IgniterJobsAdapterDispatchParams, B as IgniterJobsAdapterScheduleParams, g as IgniterJobSearchResult, m as IgniterJobStatus, Q as IgniterJobsJobLog, h as IgniterJobsQueueInfo, w as IgniterJobCounts, l as IgniterJobsQueueCleanOptions, i as IgniterJobsWorkerHandle, d as IgniterJobsWorkerBuilderConfig, f as IgniterJobsEventHandler, A as IgniterJobsAdapterJobStreamWriteParams, y as IgniterJobsAdapterJobStreamReadParams, V as IgniterJobsJobStreamReadResult, S as IgniterJobsJobStreamEvent, z as IgniterJobsAdapterJobStreamSubscribeParams } from '../adapter-DDyMVche.js';
2
2
  import 'ioredis';
3
3
  import '@igniter-js/common';
4
4
 
@@ -21,7 +21,9 @@ declare class IgniterJobsBunSQLiteAdapter implements IgniterJobsAdapter {
21
21
  private readonly queueRuntimes;
22
22
  private readonly workers;
23
23
  private readonly subscribers;
24
+ private readonly streamSubscribers;
24
25
  private readonly registeredJobs;
26
+ private streamDatabasePromise;
25
27
  private readonly registeredCrons;
26
28
  private constructor();
27
29
  static create(options: IgniterJobsBunSQLiteAdapterOptions): IgniterJobsAdapter;
@@ -57,8 +59,12 @@ declare class IgniterJobsBunSQLiteAdapter implements IgniterJobsAdapter {
57
59
  getWorkers(): Map<string, IgniterJobsWorkerHandle>;
58
60
  publishEvent(channel: string, payload: unknown): Promise<void>;
59
61
  subscribeEvent(channel: string, handler: IgniterJobsEventHandler): Promise<() => Promise<void>>;
62
+ writeJobStreamEvent(params: IgniterJobsAdapterJobStreamWriteParams): Promise<string>;
63
+ readJobStream(params: IgniterJobsAdapterJobStreamReadParams): Promise<IgniterJobsJobStreamReadResult<IgniterJobsJobStreamEvent<string, unknown>>>;
64
+ subscribeJobStream(params: IgniterJobsAdapterJobStreamSubscribeParams): Promise<() => Promise<void>>;
60
65
  shutdown(): Promise<void>;
61
66
  private loadBunqueue;
67
+ private getStreamDatabase;
62
68
  private getQueue;
63
69
  private getAllQueueNames;
64
70
  private markQueueCronsDirty;
@@ -75,6 +81,8 @@ declare class IgniterJobsBunSQLiteAdapter implements IgniterJobsAdapter {
75
81
  private closeWorkerState;
76
82
  private requireJob;
77
83
  private findQueueByJobId;
84
+ private getStreamKey;
85
+ private mapStreamRow;
78
86
  private mapJob;
79
87
  private mapJobSync;
80
88
  private normalizeEnvelope;