@arkstack/jobs 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Toneflix Technologies Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # @arkstack/jobs
2
+
3
+ [![@arkstack/jobs](https://img.shields.io/npm/dt/@arkstack/jobs?style=flat-square&label=@arkstack/jobs&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F@arkstack/jobs)](https://www.npmjs.com/package/@arkstack/jobs)
4
+
5
+ Jobs module for Arkstack, providing dispatchable job classes and a dispatcher on top of [`@arkstack/queue`](../queue).
6
+
7
+ `@arkstack/jobs` is the **authoring** layer; `@arkstack/queue` is the transport. This package gives you the `Job` base class, the `dispatch()` helper, and a registry so workers can reconstruct your job classes from a stored payload.
8
+
9
+ ## Writing a job
10
+
11
+ ```bash
12
+ ark make:job SendWelcomeEmail
13
+ ```
14
+
15
+ ```ts
16
+ // src/app/jobs/SendWelcomeEmail.ts
17
+ import { Job } from '@arkstack/jobs'
18
+
19
+ export class SendWelcomeEmail extends Job {
20
+ constructor(public userId: number) {
21
+ super()
22
+ }
23
+
24
+ async handle () {
25
+ // ... send the email
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Dispatching
31
+
32
+ ```ts
33
+ import { dispatch } from '@arkstack/jobs'
34
+ import { SendWelcomeEmail } from '@app/jobs/SendWelcomeEmail'
35
+
36
+ // static helper
37
+ await SendWelcomeEmail.dispatch(user.id)
38
+ await SendWelcomeEmail.dispatch(user.id).onQueue('mail').withDelay(60)
39
+ await SendWelcomeEmail.dispatchSync(user.id) // run inline now
40
+
41
+ // functional helper
42
+ await dispatch(new SendWelcomeEmail(user.id))
43
+ await dispatch(new SendWelcomeEmail(user.id), { queue: 'mail', delay: 60 })
44
+ ```
45
+
46
+ With the default `sync` queue connection the job runs immediately. Configure a
47
+ `database` or `redis` connection (see `@arkstack/queue`) and run a worker to
48
+ process jobs in the background:
49
+
50
+ ```bash
51
+ ark queue:work
52
+ ```
53
+
54
+ ## Setup
55
+
56
+ Importing `@arkstack/jobs` anywhere wires the queue (de)serialization
57
+ automatically. For an explicit bootstrap hook (next to `@arkstack/database/setup`):
58
+
59
+ ```ts
60
+ import '@arkstack/jobs/setup'
61
+ ```
62
+
63
+ ## How reconstruction works
64
+
65
+ Each `Job` registers itself with the `JobRegistry` when constructed. When a
66
+ worker pops a payload, the registry rebuilds the instance (bypassing the
67
+ constructor) and assigns the serialized `data` back onto it. For dedicated worker
68
+ **processes**, make sure your job modules are imported — or call
69
+ `JobRegistry.register(MyJob)` — so the names are known before processing.
70
+
71
+ Override `serialize()` on a job for custom payloads.
@@ -0,0 +1,198 @@
1
+ import { Queue } from "@arkstack/queue";
2
+ import { randomUUID } from "node:crypto";
3
+ //#region src/JobRegistry.ts
4
+ /**
5
+ * A registry mapping job names to their classes so a worker can reconstruct job
6
+ * instances from a stored payload.
7
+ *
8
+ * Job classes register themselves when instantiated, which covers same-process
9
+ * dispatch + work. For dedicated worker processes, ensure the job modules are
10
+ * imported (or call {@link JobRegistry.register} explicitly) so the names are
11
+ * known before jobs are processed.
12
+ */
13
+ var JobRegistry = class {
14
+ static classes = /* @__PURE__ */ new Map();
15
+ /**
16
+ * Register a job class under an explicit name (defaults to the class name).
17
+ */
18
+ static register(jobClass, name) {
19
+ this.classes.set(name ?? jobClass.name, jobClass);
20
+ return this;
21
+ }
22
+ /**
23
+ * The registered name for a job instance, if any.
24
+ */
25
+ static nameOf(job) {
26
+ const ctor = job.constructor;
27
+ for (const [name, jobClass] of this.classes) if (jobClass === ctor) return name;
28
+ }
29
+ /**
30
+ * Whether a job name is registered.
31
+ */
32
+ static has(name) {
33
+ return this.classes.has(name);
34
+ }
35
+ /**
36
+ * Reconstruct a job instance from a payload.
37
+ *
38
+ * The constructor is bypassed (via `Object.create`) and the serialized data
39
+ * is assigned onto a fresh instance, so reconstruction never re-runs
40
+ * constructor side effects.
41
+ */
42
+ static resolve(payload) {
43
+ const jobClass = this.classes.get(payload.displayName);
44
+ if (!jobClass) throw new Error(`Job "${payload.displayName}" is not registered. Import the job class or call JobRegistry.register().`);
45
+ const instance = Object.create(jobClass.prototype);
46
+ Object.assign(instance, payload.data);
47
+ return instance;
48
+ }
49
+ /**
50
+ * Remove all registrations. Intended for tests.
51
+ */
52
+ static clear() {
53
+ this.classes.clear();
54
+ }
55
+ };
56
+ //#endregion
57
+ //#region src/PendingDispatch.ts
58
+ /**
59
+ * A fluent, awaitable handle returned by `dispatch()` and `Job.dispatch()`.
60
+ *
61
+ * It collects routing overrides and, when awaited, pushes the job onto the
62
+ * appropriate connection. Being thenable means `await dispatch(job)` works
63
+ * directly, and the chained setters return `this` so they can precede the await:
64
+ *
65
+ * ```ts
66
+ * await dispatch(new SendReport(id)).onQueue('reports').withDelay(30)
67
+ * ```
68
+ */
69
+ var PendingDispatch = class {
70
+ job;
71
+ constructor(job) {
72
+ this.job = job;
73
+ }
74
+ /** Set the connection this job is dispatched to. */
75
+ onConnection(connection) {
76
+ this.job.connection = connection;
77
+ return this;
78
+ }
79
+ /** Set the queue this job is dispatched to. */
80
+ onQueue(queue) {
81
+ this.job.queue = queue;
82
+ return this;
83
+ }
84
+ /** Delay the dispatch by a number of seconds (or until a Date). */
85
+ withDelay(delay) {
86
+ this.job.delay = delay instanceof Date ? Math.max(0, Math.round((delay.getTime() - Date.now()) / 1e3)) : delay;
87
+ return this;
88
+ }
89
+ /** The underlying job instance. */
90
+ getJob() {
91
+ return this.job;
92
+ }
93
+ /**
94
+ * Perform the dispatch, returning the resulting job id.
95
+ */
96
+ send() {
97
+ if (this.job.delay && this.job.delay > 0) return Queue.later(this.job.delay, this.job, this.job.queue);
98
+ return Queue.push(this.job, this.job.queue);
99
+ }
100
+ then(onfulfilled, onrejected) {
101
+ return this.send().then(onfulfilled, onrejected);
102
+ }
103
+ };
104
+ //#endregion
105
+ //#region src/Job.ts
106
+ /**
107
+ * The base class for dispatchable jobs.
108
+ *
109
+ * Extend it and implement {@link handle}. Instances are {@link Queueable}, so
110
+ * they can be pushed straight onto a queue, but the fluent dispatch API is the
111
+ * idiomatic entry point:
112
+ *
113
+ * ```ts
114
+ * class SendWelcomeEmail extends Job {
115
+ * constructor(public userId: number) { super() }
116
+ * async handle() { ... }
117
+ * }
118
+ *
119
+ * await SendWelcomeEmail.dispatch(1) // default connection/queue
120
+ * await SendWelcomeEmail.dispatch(1).onQueue('mail') // fluent overrides
121
+ * await SendWelcomeEmail.dispatch(1).withDelay(60)
122
+ * ```
123
+ */
124
+ var Job = class {
125
+ /** The connection this job should be sent to. */
126
+ connection;
127
+ /** The queue this job should be sent to. */
128
+ queue;
129
+ /** Seconds to delay before the job becomes available. */
130
+ delay;
131
+ /** Maximum number of attempts before the job is marked failed. */
132
+ tries;
133
+ /** Seconds to wait before a released job becomes available again. */
134
+ backoff;
135
+ constructor() {
136
+ JobRegistry.register(this.constructor);
137
+ }
138
+ /**
139
+ * Serialize the job's state for storage. Defaults to a shallow copy of the
140
+ * instance's own properties. Override for custom serialization.
141
+ */
142
+ serialize() {
143
+ return { ...this };
144
+ }
145
+ /** Send this job to the given connection. */
146
+ onConnection(connection) {
147
+ this.connection = connection;
148
+ return this;
149
+ }
150
+ /** Send this job to the given queue. */
151
+ onQueue(queue) {
152
+ this.queue = queue;
153
+ return this;
154
+ }
155
+ /** Delay the job by a number of seconds. */
156
+ withDelay(seconds) {
157
+ this.delay = seconds;
158
+ return this;
159
+ }
160
+ /**
161
+ * Create a pending dispatch for this job class with the given constructor
162
+ * arguments. Await it (or chain `onQueue`/`onConnection`/`withDelay`) to send.
163
+ */
164
+ static dispatch(...args) {
165
+ return new PendingDispatch(new this(...args));
166
+ }
167
+ /**
168
+ * Dispatch immediately on the synchronous connection, running the job inline.
169
+ */
170
+ static dispatchSync(...args) {
171
+ return new PendingDispatch(new this(...args)).onConnection("sync");
172
+ }
173
+ };
174
+ //#endregion
175
+ //#region src/bridge.ts
176
+ let registered = false;
177
+ /**
178
+ * Wire `@arkstack/jobs` into `@arkstack/queue` by registering how jobs are
179
+ * serialized to and resolved from payloads.
180
+ *
181
+ * Importing `@arkstack/jobs` (or `@arkstack/jobs/setup`) runs this once. It is
182
+ * idempotent, so calling it again is a no-op.
183
+ */
184
+ const registerJobsWithQueue = () => {
185
+ if (registered) return;
186
+ registered = true;
187
+ Queue.serializeUsing((job) => ({
188
+ id: randomUUID(),
189
+ displayName: (job instanceof Job ? JobRegistry.nameOf(job) : void 0) ?? job.constructor?.name ?? "Closure",
190
+ attempts: 0,
191
+ maxTries: job.tries ?? null,
192
+ backoff: job.backoff ?? 0,
193
+ data: typeof job.serialize === "function" ? job.serialize() : { ...job }
194
+ }));
195
+ Queue.resolveJobsUsing((payload) => JobRegistry.resolve(payload));
196
+ };
197
+ //#endregion
198
+ export { JobRegistry as i, Job as n, PendingDispatch as r, registerJobsWithQueue as t };
@@ -0,0 +1,14 @@
1
+ import { Command } from "@h3ravel/musket";
2
+
3
+ //#region src/commands/MakeJobCommand.d.ts
4
+ /**
5
+ * Generate a new dispatchable job class.
6
+ */
7
+ declare class MakeJobCommand extends Command {
8
+ protected signature: string;
9
+ protected description: string;
10
+ handle(): Promise<undefined>;
11
+ stub(name: string): string;
12
+ }
13
+ //#endregion
14
+ export { MakeJobCommand };
@@ -0,0 +1,47 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { Arkstack } from "@arkstack/contract";
3
+ import { Command } from "@h3ravel/musket";
4
+ import { dirname, resolve } from "node:path";
5
+ //#region src/commands/MakeJobCommand.ts
6
+ /**
7
+ * Generate a new dispatchable job class.
8
+ */
9
+ var MakeJobCommand = class extends Command {
10
+ signature = `make:job
11
+ {name : The name of the job class to create.}
12
+ `;
13
+ description = "Create a new queued job class.";
14
+ async handle() {
15
+ const name = String(this.argument("name")).replace(/\s+/g, "").replace(/\.ts$/, "").trim();
16
+ if (!name) {
17
+ this.error("Job name is required");
18
+ return;
19
+ }
20
+ const className = name.split("/").pop();
21
+ const filePath = resolve(Arkstack.rootDir(), "src", `app/jobs/${name}.ts`);
22
+ await mkdir(dirname(filePath), { recursive: true });
23
+ await writeFile(filePath, this.stub(className), { flag: "wx" });
24
+ this.success(`Job ${className} created successfully at ${filePath}`);
25
+ }
26
+ stub(name) {
27
+ return [
28
+ "import { Job } from '@arkstack/jobs'",
29
+ "",
30
+ `export class ${name} extends Job {`,
31
+ " constructor() {",
32
+ " super()",
33
+ " }",
34
+ "",
35
+ " /**",
36
+ " * Execute the job.",
37
+ " */",
38
+ " async handle () {",
39
+ " // Job logic goes here",
40
+ " }",
41
+ "}",
42
+ ""
43
+ ].join("\n");
44
+ }
45
+ };
46
+ //#endregion
47
+ export { MakeJobCommand };
@@ -0,0 +1,167 @@
1
+ import { JobPayload, Queueable } from "@arkstack/queue";
2
+
3
+ //#region src/PendingDispatch.d.ts
4
+ /**
5
+ * A fluent, awaitable handle returned by `dispatch()` and `Job.dispatch()`.
6
+ *
7
+ * It collects routing overrides and, when awaited, pushes the job onto the
8
+ * appropriate connection. Being thenable means `await dispatch(job)` works
9
+ * directly, and the chained setters return `this` so they can precede the await:
10
+ *
11
+ * ```ts
12
+ * await dispatch(new SendReport(id)).onQueue('reports').withDelay(30)
13
+ * ```
14
+ */
15
+ declare class PendingDispatch<T extends Job = Job> implements PromiseLike<string> {
16
+ private readonly job;
17
+ constructor(job: T);
18
+ /** Set the connection this job is dispatched to. */
19
+ onConnection(connection: string): this;
20
+ /** Set the queue this job is dispatched to. */
21
+ onQueue(queue: string): this;
22
+ /** Delay the dispatch by a number of seconds (or until a Date). */
23
+ withDelay(delay: number | Date): this;
24
+ /** The underlying job instance. */
25
+ getJob(): T;
26
+ /**
27
+ * Perform the dispatch, returning the resulting job id.
28
+ */
29
+ private send;
30
+ then<TResult1 = string, TResult2 = never>(onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
31
+ }
32
+ //#endregion
33
+ //#region src/Job.d.ts
34
+ /**
35
+ * The base class for dispatchable jobs.
36
+ *
37
+ * Extend it and implement {@link handle}. Instances are {@link Queueable}, so
38
+ * they can be pushed straight onto a queue, but the fluent dispatch API is the
39
+ * idiomatic entry point:
40
+ *
41
+ * ```ts
42
+ * class SendWelcomeEmail extends Job {
43
+ * constructor(public userId: number) { super() }
44
+ * async handle() { ... }
45
+ * }
46
+ *
47
+ * await SendWelcomeEmail.dispatch(1) // default connection/queue
48
+ * await SendWelcomeEmail.dispatch(1).onQueue('mail') // fluent overrides
49
+ * await SendWelcomeEmail.dispatch(1).withDelay(60)
50
+ * ```
51
+ */
52
+ declare abstract class Job implements Queueable {
53
+ /** The connection this job should be sent to. */
54
+ connection?: string;
55
+ /** The queue this job should be sent to. */
56
+ queue?: string;
57
+ /** Seconds to delay before the job becomes available. */
58
+ delay?: number;
59
+ /** Maximum number of attempts before the job is marked failed. */
60
+ tries?: number;
61
+ /** Seconds to wait before a released job becomes available again. */
62
+ backoff?: number;
63
+ constructor();
64
+ /**
65
+ * Perform the work for this job. Implemented by subclasses.
66
+ */
67
+ abstract handle(): unknown | Promise<unknown>;
68
+ /**
69
+ * Serialize the job's state for storage. Defaults to a shallow copy of the
70
+ * instance's own properties. Override for custom serialization.
71
+ */
72
+ serialize(): Record<string, unknown>;
73
+ /** Send this job to the given connection. */
74
+ onConnection(connection: string): this;
75
+ /** Send this job to the given queue. */
76
+ onQueue(queue: string): this;
77
+ /** Delay the job by a number of seconds. */
78
+ withDelay(seconds: number): this;
79
+ /**
80
+ * Create a pending dispatch for this job class with the given constructor
81
+ * arguments. Await it (or chain `onQueue`/`onConnection`/`withDelay`) to send.
82
+ */
83
+ static dispatch<T extends Job>(this: new (...args: any[]) => T, ...args: any[]): PendingDispatch<T>;
84
+ /**
85
+ * Dispatch immediately on the synchronous connection, running the job inline.
86
+ */
87
+ static dispatchSync<T extends Job>(this: new (...args: any[]) => T, ...args: any[]): PendingDispatch<T>;
88
+ }
89
+ //#endregion
90
+ //#region src/types.d.ts
91
+ /**
92
+ * Constructor type for a dispatchable {@link Job} subclass.
93
+ */
94
+ type JobConstructor<T extends Job = Job> = new (...args: any[]) => T;
95
+ /**
96
+ * Options that can be passed to a dispatch call to override routing/retry.
97
+ */
98
+ interface DispatchOptions {
99
+ connection?: string;
100
+ queue?: string;
101
+ delay?: number | Date;
102
+ }
103
+ //#endregion
104
+ //#region src/JobRegistry.d.ts
105
+ /**
106
+ * A registry mapping job names to their classes so a worker can reconstruct job
107
+ * instances from a stored payload.
108
+ *
109
+ * Job classes register themselves when instantiated, which covers same-process
110
+ * dispatch + work. For dedicated worker processes, ensure the job modules are
111
+ * imported (or call {@link JobRegistry.register} explicitly) so the names are
112
+ * known before jobs are processed.
113
+ */
114
+ declare class JobRegistry {
115
+ private static classes;
116
+ /**
117
+ * Register a job class under an explicit name (defaults to the class name).
118
+ */
119
+ static register(jobClass: JobConstructor, name?: string): typeof JobRegistry;
120
+ /**
121
+ * The registered name for a job instance, if any.
122
+ */
123
+ static nameOf(job: Job): string | undefined;
124
+ /**
125
+ * Whether a job name is registered.
126
+ */
127
+ static has(name: string): boolean;
128
+ /**
129
+ * Reconstruct a job instance from a payload.
130
+ *
131
+ * The constructor is bypassed (via `Object.create`) and the serialized data
132
+ * is assigned onto a fresh instance, so reconstruction never re-runs
133
+ * constructor side effects.
134
+ */
135
+ static resolve(payload: JobPayload): Job;
136
+ /**
137
+ * Remove all registrations. Intended for tests.
138
+ */
139
+ static clear(): void;
140
+ }
141
+ //#endregion
142
+ //#region src/dispatch.d.ts
143
+ /**
144
+ * Dispatch a job instance onto a queue.
145
+ *
146
+ * Returns a {@link PendingDispatch} that can be awaited directly, chained with
147
+ * routing overrides, or passed `options` up front:
148
+ *
149
+ * ```ts
150
+ * await dispatch(new SendReport(id))
151
+ * await dispatch(new SendReport(id)).onQueue('reports')
152
+ * await dispatch(new SendReport(id), { queue: 'reports', delay: 30 })
153
+ * ```
154
+ */
155
+ declare const dispatch: <T extends Job>(job: T, options?: DispatchOptions) => PendingDispatch<T>;
156
+ //#endregion
157
+ //#region src/bridge.d.ts
158
+ /**
159
+ * Wire `@arkstack/jobs` into `@arkstack/queue` by registering how jobs are
160
+ * serialized to and resolved from payloads.
161
+ *
162
+ * Importing `@arkstack/jobs` (or `@arkstack/jobs/setup`) runs this once. It is
163
+ * idempotent, so calling it again is a no-op.
164
+ */
165
+ declare const registerJobsWithQueue: () => void;
166
+ //#endregion
167
+ export { DispatchOptions, Job, JobConstructor, JobRegistry, PendingDispatch, dispatch, registerJobsWithQueue };
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import { i as JobRegistry, n as Job, r as PendingDispatch, t as registerJobsWithQueue } from "./bridge-CQ0DHM02.js";
2
+ //#region src/dispatch.ts
3
+ /**
4
+ * Dispatch a job instance onto a queue.
5
+ *
6
+ * Returns a {@link PendingDispatch} that can be awaited directly, chained with
7
+ * routing overrides, or passed `options` up front:
8
+ *
9
+ * ```ts
10
+ * await dispatch(new SendReport(id))
11
+ * await dispatch(new SendReport(id)).onQueue('reports')
12
+ * await dispatch(new SendReport(id), { queue: 'reports', delay: 30 })
13
+ * ```
14
+ */
15
+ const dispatch = (job, options = {}) => {
16
+ const pending = new PendingDispatch(job);
17
+ if (options.connection) pending.onConnection(options.connection);
18
+ if (options.queue) pending.onQueue(options.queue);
19
+ if (options.delay !== void 0) pending.withDelay(options.delay);
20
+ return pending;
21
+ };
22
+ //#endregion
23
+ //#region src/index.ts
24
+ registerJobsWithQueue();
25
+ //#endregion
26
+ export { Job, JobRegistry, PendingDispatch, dispatch, registerJobsWithQueue };
@@ -0,0 +1 @@
1
+ export { };
package/dist/setup.js ADDED
@@ -0,0 +1,12 @@
1
+ import { t as registerJobsWithQueue } from "./bridge-CQ0DHM02.js";
2
+ //#region src/setup.ts
3
+ /**
4
+ * Boot the jobs/queue integration. Import this from your application bootstrap:
5
+ *
6
+ * ```ts
7
+ * import '@arkstack/jobs/setup'
8
+ * ```
9
+ */
10
+ registerJobsWithQueue();
11
+ //#endregion
12
+ export {};
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@arkstack/jobs",
3
+ "version": "0.13.0",
4
+ "type": "module",
5
+ "description": "Jobs module for Arkstack, providing dispatchable job classes and a dispatcher on top of @arkstack/queue.",
6
+ "homepage": "https://arkstack.toneflix.net/guide/jobs",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/arkstack-hq/arkstack.git",
10
+ "directory": "packages/jobs"
11
+ },
12
+ "keywords": [
13
+ "jobs",
14
+ "queue",
15
+ "dispatch",
16
+ "background",
17
+ "dispatchable",
18
+ "worker",
19
+ "arkstack"
20
+ ],
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "exports": {
28
+ ".": "./dist/index.js",
29
+ "./commands/MakeJobCommand": "./dist/commands/MakeJobCommand.js",
30
+ "./setup": "./dist/setup.js",
31
+ "./package.json": "./package.json"
32
+ },
33
+ "dependencies": {
34
+ "@arkstack/common": "^0.13.0",
35
+ "@arkstack/queue": "^0.13.0"
36
+ },
37
+ "peerDependencies": {
38
+ "@h3ravel/musket": "^2.2.0",
39
+ "@arkstack/contract": "^0.13.0"
40
+ },
41
+ "scripts": {
42
+ "build": "tsdown",
43
+ "test": "vitest",
44
+ "version:patch": "pnpm version patch"
45
+ }
46
+ }