@igniter-js/jobs 0.1.12 → 0.1.14

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 (40) hide show
  1. package/AGENTS.md +117 -243
  2. package/README.md +311 -153
  3. package/dist/{adapter-CXZxomI9.d.mts → adapter-Cax_40HW.d.mts} +27 -6
  4. package/dist/{adapter-CXZxomI9.d.ts → adapter-Cax_40HW.d.ts} +27 -6
  5. package/dist/adapters/bun.d.mts +93 -0
  6. package/dist/adapters/bun.d.ts +93 -0
  7. package/dist/adapters/bun.js +914 -0
  8. package/dist/adapters/bun.js.map +1 -0
  9. package/dist/adapters/bun.mjs +912 -0
  10. package/dist/adapters/bun.mjs.map +1 -0
  11. package/dist/adapters/{memory.adapter.d.ts → mock.d.mts} +1 -3
  12. package/dist/adapters/{memory.adapter.d.mts → mock.d.ts} +1 -3
  13. package/dist/adapters/{memory.adapter.js → mock.js} +58 -25
  14. package/dist/adapters/mock.js.map +1 -0
  15. package/dist/adapters/{memory.adapter.mjs → mock.mjs} +58 -25
  16. package/dist/adapters/mock.mjs.map +1 -0
  17. package/dist/adapters/{bullmq.adapter.d.ts → node.d.mts} +1 -3
  18. package/dist/adapters/{bullmq.adapter.d.mts → node.d.ts} +1 -3
  19. package/dist/adapters/{bullmq.adapter.js → node.js} +117 -40
  20. package/dist/adapters/node.js.map +1 -0
  21. package/dist/adapters/{bullmq.adapter.mjs → node.mjs} +117 -40
  22. package/dist/adapters/node.mjs.map +1 -0
  23. package/dist/index.d.mts +17 -21
  24. package/dist/index.d.ts +17 -21
  25. package/dist/index.js +20 -1854
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +21 -1852
  28. package/dist/index.mjs.map +1 -1
  29. package/package.json +28 -40
  30. package/CHANGELOG.md +0 -13
  31. package/dist/adapters/bullmq.adapter.js.map +0 -1
  32. package/dist/adapters/bullmq.adapter.mjs.map +0 -1
  33. package/dist/adapters/index.d.mts +0 -143
  34. package/dist/adapters/index.d.ts +0 -143
  35. package/dist/adapters/index.js +0 -1891
  36. package/dist/adapters/index.js.map +0 -1
  37. package/dist/adapters/index.mjs +0 -1887
  38. package/dist/adapters/index.mjs.map +0 -1
  39. package/dist/adapters/memory.adapter.js.map +0 -1
  40. package/dist/adapters/memory.adapter.mjs.map +0 -1
package/README.md CHANGED
@@ -57,7 +57,7 @@ bun add @igniter-js/jobs zod
57
57
 
58
58
  ```typescript
59
59
  import { IgniterJobs, IgniterQueue } from "@igniter-js/jobs";
60
- import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters";
60
+ import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters/mock";
61
61
  import { z } from "zod";
62
62
 
63
63
  type AppContext = { mailer: { sendWelcome: (email: string) => Promise<void> } };
@@ -109,7 +109,7 @@ await jobs.email.sendWelcome.dispatch({ input: { email: "user@example.com" } });
109
109
 
110
110
  ┌─────────────────────────────────────────────────────────────┐
111
111
  │ Adapter Layer │
112
- │ Memory Adapter • SQLite Adapter • BullMQ Adapter
112
+ │ Memory Adapter • Bun SQLite Adapter • BullMQ Adapter
113
113
  └────────────┬────────────────────────────────────────────────┘
114
114
 
115
115
 
@@ -184,8 +184,8 @@ await jobs.email.sendWelcome.dispatch({ input: { email: "user@example.com" } });
184
184
  48. Graceful shutdown in process
185
185
  49. Global events to analytics
186
186
  50. Event filtering pattern
187
- 51. SQLite adapter usage
188
- 52. SQLite adapter persistence
187
+ 51. Bun SQLite adapter usage
188
+ 52. Bun SQLite adapter persistence
189
189
  53. Memory adapter testing
190
190
  54. BullMQ adapter usage
191
191
  55. Custom adapter skeleton
@@ -229,7 +229,7 @@ const uploadQueue = IgniterQueue.create("uploads")
229
229
 
230
230
  ```typescript
231
231
  import { IgniterJobs } from "@igniter-js/jobs";
232
- import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters";
232
+ import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters/mock";
233
233
 
234
234
  const jobs = IgniterJobs.create()
235
235
  .withAdapter(IgniterJobsMemoryAdapter.create())
@@ -402,16 +402,7 @@ await jobs.email.sendWelcome.many(["job-1", "job-2"]).retry();
402
402
  await jobs.email.sendWelcome.many(["job-1", "job-2"]).remove();
403
403
  ```
404
404
 
405
- ### 22) Pause/Resume Job Type
406
-
407
- ```typescript
408
- await jobs.email.sendWelcome.pause();
409
- await jobs.email.sendWelcome.resume();
410
- ```
411
-
412
- > Note: The BullMQ adapter throws `JOBS_QUEUE_OPERATION_FAILED` for pause/resume job type.
413
-
414
- ### 23) Create a Worker
405
+ ### 22) Create a Worker
415
406
 
416
407
  ```typescript
417
408
  const worker = await jobs.worker
@@ -712,21 +703,24 @@ const unsubscribe = await jobs.subscribe((event) => {
712
703
  });
713
704
  ```
714
705
 
715
- ### 51) SQLite Adapter Usage
706
+ ### 51) Bun SQLite Adapter Usage
716
707
 
717
708
  ```typescript
718
- const adapter = IgniterJobsSQLiteAdapter.create({
709
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
719
710
  path: "./jobs.sqlite",
720
- pollingInterval: 500,
721
- enableWAL: true,
711
+ durable: true,
722
712
  });
723
713
  ```
724
714
 
725
- ### 52) SQLite Adapter Persistence
715
+ ### 52) Bun SQLite Adapter Persistence
726
716
 
727
717
  ```typescript
728
- const adapter = IgniterJobsSQLiteAdapter.create({ path: "./jobs.sqlite" });
729
- await adapter.dispatch({ queue: "emails", jobName: "send", input: { id: "1" } });
718
+ const adapter = IgniterJobsBunSQLiteAdapter.create({ path: "./jobs.sqlite" });
719
+ await adapter.dispatch({
720
+ queue: "emails",
721
+ jobName: "send",
722
+ input: { id: "1" },
723
+ });
730
724
  await adapter.shutdown();
731
725
  ```
732
726
 
@@ -748,39 +742,120 @@ const adapter = IgniterJobsBullMQAdapter.create({ redis });
748
742
  class CustomAdapter implements IgniterJobsAdapter {
749
743
  readonly client = {};
750
744
  readonly queues = null as any;
751
- async dispatch(params: IgniterJobsAdapterDispatchParams) { return "job-id"; }
752
- async schedule(params: IgniterJobsAdapterScheduleParams) { return "job-id"; }
753
- async getJob(jobId: string) { return null; }
754
- async getJobState(jobId: string) { return null; }
755
- async getJobLogs(jobId: string) { return []; }
756
- async getJobProgress(jobId: string) { return 0; }
757
- async retryJob(jobId: string) { /* ... */ }
758
- async removeJob(jobId: string) { /* ... */ }
759
- async promoteJob(jobId: string) { /* ... */ }
760
- async moveJobToFailed(jobId: string, reason: string) { /* ... */ }
761
- async retryManyJobs(jobIds: string[]) { /* ... */ }
762
- async removeManyJobs(jobIds: string[]) { /* ... */ }
763
- async getQueueInfo(queue: string) { return null; }
764
- async getQueueJobCounts(queue: string) { return { waiting: 0, active: 0, completed: 0, failed: 0, delayed: 0, paused: 0 }; }
765
- async listQueues() { return []; }
766
- async pauseQueue(queue: string) { /* ... */ }
767
- async resumeQueue(queue: string) { /* ... */ }
768
- async drainQueue(queue: string) { return 0; }
769
- async cleanQueue(queue: string, options: IgniterJobsQueueCleanOptions) { return 0; }
770
- async obliterateQueue(queue: string, options?: { force?: boolean }) { /* ... */ }
771
- async retryAllInQueue(queue: string) { return 0; }
772
- async pauseJobType(queue: string, jobName: string) { /* ... */ }
773
- async resumeJobType(queue: string, jobName: string) { /* ... */ }
774
- async searchJobs(filter: Record<string, unknown>) { return []; }
775
- async searchQueues(filter: Record<string, unknown>) { return []; }
776
- async searchWorkers(filter: Record<string, unknown>) { return []; }
777
- async createWorker(config: IgniterJobsWorkerBuilderConfig) { return {} as IgniterJobsWorkerHandle; }
778
- getWorkers() { return new Map(); }
779
- async publishEvent(channel: string, payload: unknown) { /* ... */ }
780
- async subscribeEvent(channel: string, handler: IgniterJobsEventHandler) { return async () => {}; }
781
- registerJob(queueName: string, jobName: string, definition: IgniterJobDefinition<any, any, any>) { /* ... */ }
782
- registerCron(queueName: string, cronName: string, definition: IgniterCronDefinition<any, any>) { /* ... */ }
783
- async shutdown() { /* ... */ }
745
+ async dispatch(params: IgniterJobsAdapterDispatchParams) {
746
+ return "job-id";
747
+ }
748
+ async schedule(params: IgniterJobsAdapterScheduleParams) {
749
+ return "job-id";
750
+ }
751
+ async getJob(jobId: string) {
752
+ return null;
753
+ }
754
+ async getJobState(jobId: string) {
755
+ return null;
756
+ }
757
+ async getJobLogs(jobId: string) {
758
+ return [];
759
+ }
760
+ async getJobProgress(jobId: string) {
761
+ return 0;
762
+ }
763
+ async retryJob(jobId: string) {
764
+ /* ... */
765
+ }
766
+ async removeJob(jobId: string) {
767
+ /* ... */
768
+ }
769
+ async promoteJob(jobId: string) {
770
+ /* ... */
771
+ }
772
+ async moveJobToFailed(jobId: string, reason: string) {
773
+ /* ... */
774
+ }
775
+ async retryManyJobs(jobIds: string[]) {
776
+ /* ... */
777
+ }
778
+ async removeManyJobs(jobIds: string[]) {
779
+ /* ... */
780
+ }
781
+ async getQueueInfo(queue: string) {
782
+ return null;
783
+ }
784
+ async getQueueJobCounts(queue: string) {
785
+ return {
786
+ waiting: 0,
787
+ active: 0,
788
+ completed: 0,
789
+ failed: 0,
790
+ delayed: 0,
791
+ paused: 0,
792
+ };
793
+ }
794
+ async listQueues() {
795
+ return [];
796
+ }
797
+ async pauseQueue(queue: string) {
798
+ /* ... */
799
+ }
800
+ async resumeQueue(queue: string) {
801
+ /* ... */
802
+ }
803
+ async drainQueue(queue: string) {
804
+ return 0;
805
+ }
806
+ async cleanQueue(queue: string, options: IgniterJobsQueueCleanOptions) {
807
+ return 0;
808
+ }
809
+ async obliterateQueue(queue: string, options?: { force?: boolean }) {
810
+ /* ... */
811
+ }
812
+ async retryAllInQueue(queue: string) {
813
+ return 0;
814
+ }
815
+ async pauseJobType(queue: string, jobName: string) {
816
+ /* ... */
817
+ }
818
+ async resumeJobType(queue: string, jobName: string) {
819
+ /* ... */
820
+ }
821
+ async searchJobs(filter: Record<string, unknown>) {
822
+ return [];
823
+ }
824
+ async searchQueues(filter: Record<string, unknown>) {
825
+ return [];
826
+ }
827
+ async searchWorkers(filter: Record<string, unknown>) {
828
+ return [];
829
+ }
830
+ async createWorker(config: IgniterJobsWorkerBuilderConfig) {
831
+ return {} as IgniterJobsWorkerHandle;
832
+ }
833
+ getWorkers() {
834
+ return new Map();
835
+ }
836
+ async publishEvent(channel: string, payload: unknown) {
837
+ /* ... */
838
+ }
839
+ async subscribeEvent(channel: string, handler: IgniterJobsEventHandler) {
840
+ return async () => {};
841
+ }
842
+ registerJob(
843
+ queueName: string,
844
+ jobName: string,
845
+ definition: IgniterJobDefinition<any, any, any>,
846
+ ) {
847
+ /* ... */
848
+ }
849
+ registerCron(
850
+ queueName: string,
851
+ cronName: string,
852
+ definition: IgniterCronDefinition<any, any>,
853
+ ) {
854
+ /* ... */
855
+ }
856
+ async shutdown() {
857
+ /* ... */
858
+ }
784
859
  }
785
860
  ```
786
861
 
@@ -798,7 +873,9 @@ const telemetry = IgniterTelemetry.create()
798
873
 
799
874
  ```typescript
800
875
  export async function POST() {
801
- const id = await jobs.email.sendWelcome.dispatch({ input: { email: "user@example.com" } });
876
+ const id = await jobs.email.sendWelcome.dispatch({
877
+ input: { email: "user@example.com" },
878
+ });
802
879
  return NextResponse.json({ jobId: id });
803
880
  }
804
881
  ```
@@ -807,7 +884,9 @@ export async function POST() {
807
884
 
808
885
  ```typescript
809
886
  app.post("/send", async (_req, res) => {
810
- const jobId = await jobs.email.sendWelcome.dispatch({ input: { email: "user@example.com" } });
887
+ const jobId = await jobs.email.sendWelcome.dispatch({
888
+ input: { email: "user@example.com" },
889
+ });
811
890
  res.json({ jobId });
812
891
  });
813
892
  ```
@@ -816,7 +895,9 @@ app.post("/send", async (_req, res) => {
816
895
 
817
896
  ```typescript
818
897
  app.post("/send", async (_req, res) => {
819
- const jobId = await jobs.email.sendWelcome.dispatch({ input: { email: "user@example.com" } });
898
+ const jobId = await jobs.email.sendWelcome.dispatch({
899
+ input: { email: "user@example.com" },
900
+ });
820
901
  return res.send({ jobId });
821
902
  });
822
903
  ```
@@ -1019,44 +1100,45 @@ const jobs = IgniterJobs.create()
1019
1100
 
1020
1101
  ## 🔌 Adapters
1021
1102
 
1022
- Adapters implement the `IgniterJobsAdapter` interface and are exported via:
1103
+ Adapters implement the `IgniterJobsAdapter` interface and are grouped by runtime:
1023
1104
 
1024
1105
  ```typescript
1025
- import { IgniterJobsMemoryAdapter, IgniterJobsSQLiteAdapter, IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters";
1106
+ import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters/mock";
1107
+ import { IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters/node";
1108
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
1026
1109
  ```
1027
1110
 
1028
1111
  ### Adapter Comparison
1029
1112
 
1030
- | Adapter | Persistence | Multi-process | Use Case |
1031
- |--------|-------------|---------------|---------|
1032
- | Memory | ❌ | ❌ | Unit tests, local dev |
1033
- | SQLite | ✅ | ⚠️ (single process) | Desktop, CLI, local |
1034
- | BullMQ | ✅ | ✅ | Production scale |
1113
+ | Adapter | Persistence | Multi-process | Use Case |
1114
+ | ------- | ----------- | ------------------- | --------------------- |
1115
+ | Memory | ❌ | ❌ | Unit tests, local dev |
1116
+ | SQLite | ✅ | ⚠️ (single process) | Desktop, CLI, local |
1117
+ | BullMQ | ✅ | ✅ | Production scale |
1035
1118
 
1036
1119
  ### Memory Adapter
1037
1120
 
1038
1121
  ```typescript
1039
- import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters";
1122
+ import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters/mock";
1040
1123
 
1041
1124
  const adapter = IgniterJobsMemoryAdapter.create();
1042
1125
  ```
1043
1126
 
1044
- ### SQLite Adapter
1127
+ ### Bun SQLite Adapter
1045
1128
 
1046
1129
  ```typescript
1047
- import { IgniterJobsSQLiteAdapter } from "@igniter-js/jobs/adapters";
1130
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
1048
1131
 
1049
- const adapter = IgniterJobsSQLiteAdapter.create({
1132
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
1050
1133
  path: "./data/jobs.sqlite",
1051
- pollingInterval: 500,
1052
- enableWAL: true,
1134
+ durable: true,
1053
1135
  });
1054
1136
  ```
1055
1137
 
1056
1138
  ### BullMQ Adapter
1057
1139
 
1058
1140
  ```typescript
1059
- import { IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters";
1141
+ import { IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters/node";
1060
1142
  import Redis from "ioredis";
1061
1143
 
1062
1144
  const redis = new Redis(process.env.REDIS_URL);
@@ -1067,12 +1149,23 @@ const adapter = IgniterJobsBullMQAdapter.create({ redis });
1067
1149
 
1068
1150
  ## 🧪 Testing
1069
1151
 
1152
+ ### Bun SQLite Adapter
1153
+
1154
+ ```typescript
1155
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
1156
+
1157
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
1158
+ path: "./data/jobs.sqlite",
1159
+ durable: true,
1160
+ });
1161
+ ```
1162
+
1070
1163
  ### Unit Testing with Memory Adapter
1071
1164
 
1072
1165
  ```typescript
1073
1166
  import { describe, it, expect } from "vitest";
1074
1167
  import { IgniterJobs, IgniterQueue } from "@igniter-js/jobs";
1075
- import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters";
1168
+ import { IgniterJobsMemoryAdapter } from "@igniter-js/jobs/adapters/mock";
1076
1169
 
1077
1170
  describe("jobs", () => {
1078
1171
  it("dispatches and processes a job", async () => {
@@ -1121,22 +1214,21 @@ describe("jobs", () => {
1121
1214
  const adapter = IgniterJobsMemoryAdapter.create({ maxJobHistory: 1000 });
1122
1215
  ```
1123
1216
 
1124
- ### SQLite Adapter
1217
+ ### Bun SQLite Adapter
1125
1218
 
1126
1219
  Use for desktop apps, CLI tools, or local persistence without Redis.
1127
1220
 
1128
1221
  Key traits:
1129
1222
 
1130
1223
  - Persistent storage on disk
1131
- - Single-process (WAL helps but not distributed)
1224
+ - Single-process local runtime (persistent, but not distributed)
1132
1225
  - Polling-based worker loop
1133
1226
  - Great for edge or MCP servers
1134
1227
 
1135
1228
  ```typescript
1136
- const adapter = IgniterJobsSQLiteAdapter.create({
1229
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
1137
1230
  path: "./data/jobs.sqlite",
1138
- pollingInterval: 500,
1139
- enableWAL: true,
1231
+ durable: true,
1140
1232
  });
1141
1233
  ```
1142
1234
 
@@ -1195,10 +1287,10 @@ describe("jobs", () => {
1195
1287
  - Use `withLimiter()` for API-bound workloads.
1196
1288
  - Shard by queue when jobs have very different resource needs.
1197
1289
 
1198
- ### Polling (SQLite)
1290
+ ### Local Bun SQLite Runtime
1199
1291
 
1200
- - Lower `pollingInterval` means faster reaction but higher CPU.
1201
- - Higher `pollingInterval` reduces CPU at the cost of latency.
1292
+ - Use `durable: true` only for jobs that must survive abrupt exits.
1293
+ - Tune `batchSize`, `pollTimeout`, and `heartbeatInterval` for throughput-sensitive workloads.
1202
1294
 
1203
1295
  ---
1204
1296
 
@@ -1705,17 +1797,40 @@ export const IgniterJobs: {
1705
1797
  class IgniterJobsBuilder<TContext, TQueues, TScope> {
1706
1798
  static create(): IgniterJobsBuilder<unknown>;
1707
1799
 
1708
- withAdapter(adapter: IgniterJobsAdapter): IgniterJobsBuilder<TContext, TQueues, TScope>;
1800
+ withAdapter(
1801
+ adapter: IgniterJobsAdapter,
1802
+ ): IgniterJobsBuilder<TContext, TQueues, TScope>;
1709
1803
  withService(service: string): IgniterJobsBuilder<TContext, TQueues, TScope>;
1710
- withEnvironment(environment: string): IgniterJobsBuilder<TContext, TQueues, TScope>;
1711
- withContext<TNewContext>(factory: () => TNewContext | Promise<TNewContext>): IgniterJobsBuilder<TNewContext, {}, TScope>;
1712
- addScope(name: string, options?: IgniterJobsScopeOptions): IgniterJobsBuilder<TContext, TQueues, TScope | string>;
1713
- addQueue(queue: IgniterJobsQueue<TContext, any, any> & { name: string }): IgniterJobsBuilder<TContext, TQueues & Record<string, any>, TScope>;
1714
- withQueueDefaults(defaults: Partial<IgniterJobDefinition<TContext, any, any>>): IgniterJobsBuilder<TContext, TQueues, TScope>;
1715
- withWorkerDefaults(defaults: Partial<IgniterJobsWorkerBuilderConfig>): IgniterJobsBuilder<TContext, TQueues, TScope>;
1716
- withAutoStartWorker(config: { queues: (keyof TQueues)[]; concurrency?: number; limiter?: IgniterJobsLimiter }): IgniterJobsBuilder<TContext, TQueues, TScope>;
1717
- withTelemetry(telemetry: IgniterJobsTelemetry): IgniterJobsBuilder<TContext, TQueues, TScope>;
1718
- withLogger(logger: IgniterLogger): IgniterJobsBuilder<TContext, TQueues, TScope>;
1804
+ withEnvironment(
1805
+ environment: string,
1806
+ ): IgniterJobsBuilder<TContext, TQueues, TScope>;
1807
+ withContext<TNewContext>(
1808
+ factory: () => TNewContext | Promise<TNewContext>,
1809
+ ): IgniterJobsBuilder<TNewContext, {}, TScope>;
1810
+ addScope(
1811
+ name: string,
1812
+ options?: IgniterJobsScopeOptions,
1813
+ ): IgniterJobsBuilder<TContext, TQueues, TScope | string>;
1814
+ addQueue(
1815
+ queue: IgniterJobsQueue<TContext, any, any> & { name: string },
1816
+ ): IgniterJobsBuilder<TContext, TQueues & Record<string, any>, TScope>;
1817
+ withQueueDefaults(
1818
+ defaults: Partial<IgniterJobDefinition<TContext, any, any>>,
1819
+ ): IgniterJobsBuilder<TContext, TQueues, TScope>;
1820
+ withWorkerDefaults(
1821
+ defaults: Partial<IgniterJobsWorkerBuilderConfig>,
1822
+ ): IgniterJobsBuilder<TContext, TQueues, TScope>;
1823
+ withAutoStartWorker(config: {
1824
+ queues: (keyof TQueues)[];
1825
+ concurrency?: number;
1826
+ limiter?: IgniterJobsLimiter;
1827
+ }): IgniterJobsBuilder<TContext, TQueues, TScope>;
1828
+ withTelemetry(
1829
+ telemetry: IgniterJobsTelemetry,
1830
+ ): IgniterJobsBuilder<TContext, TQueues, TScope>;
1831
+ withLogger(
1832
+ logger: IgniterLogger,
1833
+ ): IgniterJobsBuilder<TContext, TQueues, TScope>;
1719
1834
  build(): IgniterJobsRuntime<IgniterJobsConfig<TContext, TQueues, TScope>>;
1720
1835
  }
1721
1836
  ```
@@ -1726,7 +1841,9 @@ class IgniterJobsBuilder<TContext, TQueues, TScope> {
1726
1841
 
1727
1842
  ```typescript
1728
1843
  class IgniterQueue {
1729
- static create<const TName extends string>(name: TName): IgniterQueueBuilder<unknown, {}, {}, TName>;
1844
+ static create<const TName extends string>(
1845
+ name: TName,
1846
+ ): IgniterQueueBuilder<unknown, {}, {}, TName>;
1730
1847
  }
1731
1848
  ```
1732
1849
 
@@ -1736,13 +1853,23 @@ class IgniterQueue {
1736
1853
  class IgniterQueueBuilder<TContext, TJobs, TCron, TName> {
1737
1854
  addJob<TJobName extends string, TInput, TResult>(
1738
1855
  jobName: TJobName,
1739
- definition: IgniterJobDefinition<TContext, TInput, TResult>
1740
- ): IgniterQueueBuilder<TContext, TJobs & Record<TJobName, IgniterJobDefinition<TContext, TInput, TResult>>, TCron, TName>;
1856
+ definition: IgniterJobDefinition<TContext, TInput, TResult>,
1857
+ ): IgniterQueueBuilder<
1858
+ TContext,
1859
+ TJobs & Record<TJobName, IgniterJobDefinition<TContext, TInput, TResult>>,
1860
+ TCron,
1861
+ TName
1862
+ >;
1741
1863
 
1742
1864
  addCron<TCronName extends string, TResult>(
1743
1865
  cronName: TCronName,
1744
- definition: IgniterCronDefinition<TContext, TResult>
1745
- ): IgniterQueueBuilder<TContext, TJobs, TCron & Record<TCronName, IgniterCronDefinition<TContext, TResult>>, TName>;
1866
+ definition: IgniterCronDefinition<TContext, TResult>,
1867
+ ): IgniterQueueBuilder<
1868
+ TContext,
1869
+ TJobs,
1870
+ TCron & Record<TCronName, IgniterCronDefinition<TContext, TResult>>,
1871
+ TName
1872
+ >;
1746
1873
 
1747
1874
  build(): IgniterJobsQueue<TContext, TJobs, TCron> & { name: TName };
1748
1875
  }
@@ -1754,10 +1881,17 @@ class IgniterQueueBuilder<TContext, TJobs, TCron, TName> {
1754
1881
  interface IgniterJobsRuntime<TConfig> {
1755
1882
  config: TConfig;
1756
1883
  subscribe(handler: IgniterJobsEventHandler): Promise<() => Promise<void>>;
1757
- search(target: "jobs" | "queues" | "workers", filter: Record<string, unknown>): Promise<unknown[]>;
1884
+ search(
1885
+ target: "jobs" | "queues" | "workers",
1886
+ filter: Record<string, unknown>,
1887
+ ): Promise<unknown[]>;
1758
1888
  shutdown(): Promise<void>;
1759
1889
  worker: { create(): IgniterWorkerBuilder<keyof TConfig["queues"] & string> };
1760
- scope(type: string, id: string | number, tags?: Record<string, unknown>): IgniterJobsRuntime<TConfig>;
1890
+ scope(
1891
+ type: string,
1892
+ id: string | number,
1893
+ tags?: Record<string, unknown>,
1894
+ ): IgniterJobsRuntime<TConfig>;
1761
1895
 
1762
1896
  // Queue accessors (dynamic)
1763
1897
  [queueName: string]: IgniterJobsQueueAccessor<any>;
@@ -1777,7 +1911,11 @@ interface IgniterJobsQueueAccessor {
1777
1911
  obliterate(options?: { force?: boolean }): Promise<void>;
1778
1912
  retryAll(): Promise<number>;
1779
1913
  };
1780
- list(filter?: { status?: IgniterJobStatus[]; limit?: number; offset?: number }): Promise<IgniterJobSearchResult[]>;
1914
+ list(filter?: {
1915
+ status?: IgniterJobStatus[];
1916
+ limit?: number;
1917
+ offset?: number;
1918
+ }): Promise<IgniterJobSearchResult[]>;
1781
1919
  subscribe(handler: IgniterJobsEventHandler): Promise<() => Promise<void>>;
1782
1920
  jobs: Record<string, IgniterJobsJobAccessor>;
1783
1921
  }
@@ -1800,8 +1938,6 @@ interface IgniterJobsJobAccessor<TInput = unknown> {
1800
1938
  logs(): Promise<IgniterJobsJobLog[]>;
1801
1939
  };
1802
1940
  many(ids: string[]): { retry(): Promise<void>; remove(): Promise<void> };
1803
- pause(): Promise<void>;
1804
- resume(): Promise<void>;
1805
1941
  subscribe(handler: IgniterJobsEventHandler): Promise<() => Promise<void>>;
1806
1942
  }
1807
1943
  ```
@@ -1811,12 +1947,30 @@ interface IgniterJobsJobAccessor<TInput = unknown> {
1811
1947
  ```typescript
1812
1948
  interface IgniterJobsWorkerFluentBuilder<TQueueNames extends string> {
1813
1949
  addQueue(queue: TQueueNames): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1814
- withConcurrency(concurrency: number): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1815
- withLimiter(limiter: IgniterJobsLimiter): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1816
- onActive(handler: (ctx: { job: IgniterJobSearchResult }) => void | Promise<void>): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1817
- onSuccess(handler: (ctx: { job: IgniterJobSearchResult; result: unknown }) => void | Promise<void>): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1818
- onFailure(handler: (ctx: { job: IgniterJobSearchResult; error: Error }) => void | Promise<void>): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1819
- onIdle(handler: () => void | Promise<void>): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1950
+ withConcurrency(
1951
+ concurrency: number,
1952
+ ): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1953
+ withLimiter(
1954
+ limiter: IgniterJobsLimiter,
1955
+ ): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1956
+ onActive(
1957
+ handler: (ctx: { job: IgniterJobSearchResult }) => void | Promise<void>,
1958
+ ): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1959
+ onSuccess(
1960
+ handler: (ctx: {
1961
+ job: IgniterJobSearchResult;
1962
+ result: unknown;
1963
+ }) => void | Promise<void>,
1964
+ ): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1965
+ onFailure(
1966
+ handler: (ctx: {
1967
+ job: IgniterJobSearchResult;
1968
+ error: Error;
1969
+ }) => void | Promise<void>,
1970
+ ): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1971
+ onIdle(
1972
+ handler: () => void | Promise<void>,
1973
+ ): IgniterJobsWorkerFluentBuilder<TQueueNames>;
1820
1974
  start(): Promise<IgniterJobsWorkerHandle>;
1821
1975
  }
1822
1976
  ```
@@ -1825,13 +1979,17 @@ interface IgniterJobsWorkerFluentBuilder<TQueueNames extends string> {
1825
1979
 
1826
1980
  ## ⚙️ Configuration Reference
1827
1981
 
1828
- ### IgniterJobsSQLiteAdapterOptions
1982
+ ### IgniterJobsBunSQLiteAdapterOptions
1829
1983
 
1830
1984
  ```typescript
1831
- interface IgniterJobsSQLiteAdapterOptions {
1985
+ interface IgniterJobsBunSQLiteAdapterOptions {
1832
1986
  path: string;
1833
- pollingInterval?: number; // default: 500
1834
- enableWAL?: boolean; // default: true
1987
+ durable?: boolean;
1988
+ heartbeatInterval?: number;
1989
+ pollTimeout?: number;
1990
+ batchSize?: number;
1991
+ lockDuration?: number;
1992
+ maxStalledCount?: number;
1835
1993
  }
1836
1994
  ```
1837
1995
 
@@ -1857,22 +2015,22 @@ interface IgniterJobsScheduleOptions {
1857
2015
 
1858
2016
  ## ✅ Best Practices
1859
2017
 
1860
- | Do | Why | Example |
1861
- |----|-----|---------|
1862
- | ✅ Use input schemas | Prevent invalid jobs | `input: z.object({ ... })` |
1863
- | ✅ Keep payloads small | Faster serialization | `{ id: "order_1" }` |
1864
- | ✅ Use scopes | Tenant isolation | `jobs.scope("org", "org_1")` |
1865
- | ✅ Use retries | Resilience | `attempts: 5` |
1866
- | ✅ Use worker hooks | Observability | `onFailure(...)` |
2018
+ | Do | Why | Example |
2019
+ | ---------------------- | -------------------- | ---------------------------- |
2020
+ | ✅ Use input schemas | Prevent invalid jobs | `input: z.object({ ... })` |
2021
+ | ✅ Keep payloads small | Faster serialization | `{ id: "order_1" }` |
2022
+ | ✅ Use scopes | Tenant isolation | `jobs.scope("org", "org_1")` |
2023
+ | ✅ Use retries | Resilience | `attempts: 5` |
2024
+ | ✅ Use worker hooks | Observability | `onFailure(...)` |
1867
2025
 
1868
2026
  ### Anti-Patterns
1869
2027
 
1870
- | Don’t | Why | Alternative |
1871
- |------|-----|-------------|
1872
- | ❌ Store PII in metadata | Metadata is observable | Store IDs only |
1873
- | ❌ Use sync I/O in handlers | Blocks workers | Use async I/O |
1874
- | ❌ Dispatch without schema | Runtime surprises | Add `input` schema |
1875
- | ❌ Long-running jobs without progress | No visibility | Use `onProgress` |
2028
+ | Don’t | Why | Alternative |
2029
+ | ------------------------------------- | ---------------------- | ------------------ |
2030
+ | ❌ Store PII in metadata | Metadata is observable | Store IDs only |
2031
+ | ❌ Use sync I/O in handlers | Blocks workers | Use async I/O |
2032
+ | ❌ Dispatch without schema | Runtime surprises | Add `input` schema |
2033
+ | ❌ Long-running jobs without progress | No visibility | Use `onProgress` |
1876
2034
 
1877
2035
  ---
1878
2036
 
@@ -1966,9 +2124,9 @@ Do not import this package in client-side bundles.
1966
2124
  ### Memory → SQLite
1967
2125
 
1968
2126
  ```typescript
1969
- import { IgniterJobsSQLiteAdapter } from "@igniter-js/jobs/adapters";
2127
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
1970
2128
 
1971
- const adapter = IgniterJobsSQLiteAdapter.create({
2129
+ const adapter = IgniterJobsBunSQLiteAdapter.create({
1972
2130
  path: "./jobs.sqlite",
1973
2131
  });
1974
2132
  ```
@@ -1976,7 +2134,7 @@ const adapter = IgniterJobsSQLiteAdapter.create({
1976
2134
  ### SQLite → BullMQ
1977
2135
 
1978
2136
  ```typescript
1979
- import { IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters";
2137
+ import { IgniterJobsBullMQAdapter } from "@igniter-js/jobs/adapters/node";
1980
2138
  import Redis from "ioredis";
1981
2139
 
1982
2140
  const adapter = IgniterJobsBullMQAdapter.create({
@@ -2012,7 +2170,7 @@ Yes. The adapter interface is stable and jobs/queues remain unchanged.
2012
2170
 
2013
2171
  ```typescript
2014
2172
  import { IgniterJobs, IgniterQueue } from "@igniter-js/jobs";
2015
- import { IgniterJobsSQLiteAdapter } from "@igniter-js/jobs/adapters";
2173
+ import { IgniterJobsBunSQLiteAdapter } from "@igniter-js/jobs/adapters/bun";
2016
2174
  import { z } from "zod";
2017
2175
 
2018
2176
  type AppContext = { uploads: { process: (id: string) => Promise<void> } };
@@ -2027,7 +2185,7 @@ const queue = IgniterQueue.create("uploads")
2027
2185
  .build();
2028
2186
 
2029
2187
  const jobs = IgniterJobs.create()
2030
- .withAdapter(IgniterJobsSQLiteAdapter.create({ path: "./jobs.sqlite" }))
2188
+ .withAdapter(IgniterJobsBunSQLiteAdapter.create({ path: "./jobs.sqlite" }))
2031
2189
  .withService("uploader")
2032
2190
  .withEnvironment("local")
2033
2191
  .withContext(async () => ({ uploads }))
@@ -2054,14 +2212,14 @@ await jobs.shutdown();
2054
2212
 
2055
2213
  ### Job Events (Runtime)
2056
2214
 
2057
- | Event | When | Payload Keys |
2058
- |------|------|--------------|
2059
- | `enqueued` | After dispatch | `jobId`, `queue`, `jobName` |
2060
- | `scheduled` | After schedule | `jobId`, `queue`, `jobName` |
2061
- | `started` | Before handler | `jobId`, `jobName`, `queue`, `attemptsMade`, `startedAt` |
2062
- | `completed` | After handler | `jobId`, `jobName`, `queue`, `result`, `duration`, `completedAt` |
2063
- | `failed` | On error | `jobId`, `jobName`, `queue`, `error`, `attemptsMade`, `isFinalAttempt`, `duration`, `failedAt` |
2064
- | `progress` | On progress hook | `jobId`, `jobName`, `queue`, `progress`, `message`, `timestamp` |
2215
+ | Event | When | Payload Keys |
2216
+ | ----------- | ---------------- | ---------------------------------------------------------------------------------------------- |
2217
+ | `enqueued` | After dispatch | `jobId`, `queue`, `jobName` |
2218
+ | `scheduled` | After schedule | `jobId`, `queue`, `jobName` |
2219
+ | `started` | Before handler | `jobId`, `jobName`, `queue`, `attemptsMade`, `startedAt` |
2220
+ | `completed` | After handler | `jobId`, `jobName`, `queue`, `result`, `duration`, `completedAt` |
2221
+ | `failed` | On error | `jobId`, `jobName`, `queue`, `error`, `attemptsMade`, `isFinalAttempt`, `duration`, `failedAt` |
2222
+ | `progress` | On progress hook | `jobId`, `jobName`, `queue`, `progress`, `message`, `timestamp` |
2065
2223
 
2066
2224
  ### Telemetry Event Attributes
2067
2225
 
@@ -2104,22 +2262,22 @@ await jobs.shutdown();
2104
2262
 
2105
2263
  ## 📑 Appendix: Adapter API Matrix
2106
2264
 
2107
- | API | Memory | SQLite | BullMQ |
2108
- |-----|--------|--------|--------|
2109
- | `dispatch()` | ✅ | ✅ | ✅ |
2110
- | `schedule()` | ✅ | ✅ | ✅ |
2111
- | `getJob()` | ✅ | ✅ | ✅ |
2112
- | `getJobState()` | ✅ | ✅ | ✅ |
2113
- | `getJobLogs()` | ✅ | ✅ | ✅ |
2114
- | `getJobProgress()` | ✅ | ✅ | ✅ |
2115
- | `pauseJobType()` | ✅ | ✅ | ❌ |
2116
- | `resumeJobType()` | ✅ | ✅ | ❌ |
2117
- | `pauseQueue()` | ✅ | ✅ | ✅ |
2118
- | `resumeQueue()` | ✅ | ✅ | ✅ |
2119
- | `drainQueue()` | ✅ | ✅ | ✅ |
2120
- | `cleanQueue()` | ✅ | ✅ | ✅ |
2121
- | `obliterateQueue()` | ✅ | ✅ | ✅ |
2122
- | `retryAllInQueue()` | ✅ | ✅ | ✅ |
2265
+ | API | Memory | SQLite | BullMQ |
2266
+ | ------------------- | ------ | ------ | ------ |
2267
+ | `dispatch()` | ✅ | ✅ | ✅ |
2268
+ | `schedule()` | ✅ | ✅ | ✅ |
2269
+ | `getJob()` | ✅ | ✅ | ✅ |
2270
+ | `getJobState()` | ✅ | ✅ | ✅ |
2271
+ | `getJobLogs()` | ✅ | ✅ | ✅ |
2272
+ | `getJobProgress()` | ✅ | ✅ | ✅ |
2273
+ | `pauseJobType()` | ✅ | ✅ | ❌ |
2274
+ | `resumeJobType()` | ✅ | ✅ | ❌ |
2275
+ | `pauseQueue()` | ✅ | ✅ | ✅ |
2276
+ | `resumeQueue()` | ✅ | ✅ | ✅ |
2277
+ | `drainQueue()` | ✅ | ✅ | ✅ |
2278
+ | `cleanQueue()` | ✅ | ✅ | ✅ |
2279
+ | `obliterateQueue()` | ✅ | ✅ | ✅ |
2280
+ | `retryAllInQueue()` | ✅ | ✅ | ✅ |
2123
2281
 
2124
2282
  ---
2125
2283