@spfn/core 0.1.0-alpha.88 → 0.2.0-beta.10

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 (97) hide show
  1. package/README.md +298 -466
  2. package/dist/boss-DI1r4kTS.d.ts +244 -0
  3. package/dist/cache/index.d.ts +13 -33
  4. package/dist/cache/index.js +14 -703
  5. package/dist/cache/index.js.map +1 -1
  6. package/dist/codegen/index.d.ts +214 -17
  7. package/dist/codegen/index.js +231 -1420
  8. package/dist/codegen/index.js.map +1 -1
  9. package/dist/config/index.d.ts +1227 -0
  10. package/dist/config/index.js +273 -0
  11. package/dist/config/index.js.map +1 -0
  12. package/dist/db/index.d.ts +741 -59
  13. package/dist/db/index.js +1063 -1226
  14. package/dist/db/index.js.map +1 -1
  15. package/dist/env/index.d.ts +658 -308
  16. package/dist/env/index.js +503 -928
  17. package/dist/env/index.js.map +1 -1
  18. package/dist/env/loader.d.ts +87 -0
  19. package/dist/env/loader.js +70 -0
  20. package/dist/env/loader.js.map +1 -0
  21. package/dist/errors/index.d.ts +417 -29
  22. package/dist/errors/index.js +359 -98
  23. package/dist/errors/index.js.map +1 -1
  24. package/dist/event/index.d.ts +41 -0
  25. package/dist/event/index.js +131 -0
  26. package/dist/event/index.js.map +1 -0
  27. package/dist/event/sse/client.d.ts +82 -0
  28. package/dist/event/sse/client.js +115 -0
  29. package/dist/event/sse/client.js.map +1 -0
  30. package/dist/event/sse/index.d.ts +40 -0
  31. package/dist/event/sse/index.js +92 -0
  32. package/dist/event/sse/index.js.map +1 -0
  33. package/dist/job/index.d.ts +218 -0
  34. package/dist/job/index.js +410 -0
  35. package/dist/job/index.js.map +1 -0
  36. package/dist/logger/index.d.ts +20 -79
  37. package/dist/logger/index.js +82 -387
  38. package/dist/logger/index.js.map +1 -1
  39. package/dist/middleware/index.d.ts +102 -20
  40. package/dist/middleware/index.js +51 -705
  41. package/dist/middleware/index.js.map +1 -1
  42. package/dist/nextjs/index.d.ts +120 -0
  43. package/dist/nextjs/index.js +448 -0
  44. package/dist/nextjs/index.js.map +1 -0
  45. package/dist/{client/nextjs/index.d.ts → nextjs/server.d.ts} +335 -262
  46. package/dist/nextjs/server.js +637 -0
  47. package/dist/nextjs/server.js.map +1 -0
  48. package/dist/route/index.d.ts +879 -25
  49. package/dist/route/index.js +697 -1271
  50. package/dist/route/index.js.map +1 -1
  51. package/dist/route/types.d.ts +9 -0
  52. package/dist/route/types.js +3 -0
  53. package/dist/route/types.js.map +1 -0
  54. package/dist/router-Di7ENoah.d.ts +151 -0
  55. package/dist/server/index.d.ts +345 -64
  56. package/dist/server/index.js +1174 -3233
  57. package/dist/server/index.js.map +1 -1
  58. package/dist/types-B-e_f2dQ.d.ts +121 -0
  59. package/dist/types-BGl4QL1w.d.ts +77 -0
  60. package/dist/types-BOPTApC2.d.ts +245 -0
  61. package/docs/cache.md +133 -0
  62. package/docs/codegen.md +74 -0
  63. package/docs/database.md +346 -0
  64. package/docs/entity.md +539 -0
  65. package/docs/env.md +477 -0
  66. package/docs/errors.md +319 -0
  67. package/docs/event.md +116 -0
  68. package/docs/file-upload.md +717 -0
  69. package/docs/job.md +131 -0
  70. package/docs/logger.md +108 -0
  71. package/docs/middleware.md +337 -0
  72. package/docs/nextjs.md +241 -0
  73. package/docs/repository.md +496 -0
  74. package/docs/route.md +497 -0
  75. package/docs/server.md +307 -0
  76. package/package.json +68 -48
  77. package/dist/auto-loader-JFaZ9gON.d.ts +0 -80
  78. package/dist/client/index.d.ts +0 -358
  79. package/dist/client/index.js +0 -357
  80. package/dist/client/index.js.map +0 -1
  81. package/dist/client/nextjs/index.js +0 -371
  82. package/dist/client/nextjs/index.js.map +0 -1
  83. package/dist/codegen/generators/index.d.ts +0 -19
  84. package/dist/codegen/generators/index.js +0 -1404
  85. package/dist/codegen/generators/index.js.map +0 -1
  86. package/dist/database-errors-BNNmLTJE.d.ts +0 -86
  87. package/dist/events/index.d.ts +0 -183
  88. package/dist/events/index.js +0 -77
  89. package/dist/events/index.js.map +0 -1
  90. package/dist/index-DHiAqhKv.d.ts +0 -101
  91. package/dist/index.d.ts +0 -8
  92. package/dist/index.js +0 -3674
  93. package/dist/index.js.map +0 -1
  94. package/dist/types/index.d.ts +0 -121
  95. package/dist/types/index.js +0 -38
  96. package/dist/types/index.js.map +0 -1
  97. package/dist/types-BXibIEyj.d.ts +0 -60
@@ -0,0 +1,218 @@
1
+ import { a as JobOptions, C as CompensateHandler, b as JobHandler, c as JobDef, d as JobRouterEntry, J as JobRouter } from '../boss-DI1r4kTS.js';
2
+ export { k as BossConfig, B as BossOptions, I as InferJobInput, f as InferJobOutput, e as JobSendOptions, g as getBoss, i as initBoss, h as isBossRunning, j as shouldClearOnStart, s as stopBoss } from '../boss-DI1r4kTS.js';
3
+ import * as _sinclair_typebox from '@sinclair/typebox';
4
+ import { Static } from '@sinclair/typebox';
5
+ import { EventDef, InferEventPayload } from '@spfn/core/event';
6
+ import 'pg-boss';
7
+
8
+ /**
9
+ * Job builder class with fluent API
10
+ */
11
+ declare class JobBuilder<TInput = void, TOutput = void> {
12
+ private readonly _name;
13
+ private _inputSchema?;
14
+ private _outputSchema?;
15
+ private _cronExpression?;
16
+ private _runOnce?;
17
+ private _subscribedEvent?;
18
+ private _subscribedEventDef?;
19
+ private _options?;
20
+ private _handler?;
21
+ private _compensate?;
22
+ constructor(name: string);
23
+ /**
24
+ * Define input schema with TypeBox
25
+ */
26
+ input<TSchema extends _sinclair_typebox.TSchema>(schema: TSchema): JobBuilder<Static<TSchema>, TOutput>;
27
+ /**
28
+ * Define output schema with TypeBox (for workflow integration)
29
+ */
30
+ output<TSchema extends _sinclair_typebox.TSchema>(schema: TSchema): JobBuilder<TInput, Static<TSchema>>;
31
+ /**
32
+ * Subscribe to an event (decoupled triggering)
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const userCreated = defineEvent('user.created', Type.Object({
37
+ * userId: Type.String(),
38
+ * }));
39
+ *
40
+ * const sendWelcomeEmail = job('send-welcome-email')
41
+ * .on(userCreated)
42
+ * .handler(async (payload) => {
43
+ * // payload is typed as { userId: string }
44
+ * });
45
+ * ```
46
+ */
47
+ on<TEvent extends EventDef<any>>(event: TEvent): JobBuilder<InferEventPayload<TEvent>, TOutput>;
48
+ /**
49
+ * Set cron expression for scheduled execution
50
+ */
51
+ cron(expression: string): this;
52
+ /**
53
+ * Mark job to run once on server start
54
+ */
55
+ runOnce(): this;
56
+ /**
57
+ * Set job options (retry, expiration, etc.)
58
+ */
59
+ options(options: JobOptions): this;
60
+ /**
61
+ * Set job timeout in milliseconds
62
+ * (Converts to expireInSeconds for pg-boss)
63
+ */
64
+ timeout(ms: number): this;
65
+ /**
66
+ * Define compensate handler for rollback (workflow integration)
67
+ */
68
+ compensate(fn: CompensateHandler<TInput, TOutput>): this;
69
+ /**
70
+ * Define the job handler and finalize the job definition
71
+ */
72
+ handler(fn: JobHandler<TInput, TOutput>): JobDef<TInput, TOutput>;
73
+ }
74
+ /**
75
+ * Create a new job definition
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * // Simple job without input
80
+ * export const cleanupJob = job('cleanup')
81
+ * .handler(async () => {
82
+ * await db.cleanup();
83
+ * });
84
+ *
85
+ * // Job with typed input
86
+ * export const sendEmailJob = job('send-email')
87
+ * .input(Type.Object({
88
+ * to: Type.String(),
89
+ * subject: Type.String(),
90
+ * body: Type.String(),
91
+ * }))
92
+ * .handler(async (input) => {
93
+ * await emailService.send(input.to, input.subject, input.body);
94
+ * });
95
+ *
96
+ * // Cron job
97
+ * export const dailyReportJob = job('daily-report')
98
+ * .cron('0 9 * * *')
99
+ * .handler(async () => {
100
+ * await reportService.generateDaily();
101
+ * });
102
+ *
103
+ * // Run once on server start
104
+ * export const initCacheJob = job('init-cache')
105
+ * .runOnce()
106
+ * .handler(async () => {
107
+ * await cache.warmup();
108
+ * });
109
+ *
110
+ * // With options
111
+ * export const importantJob = job('important-task')
112
+ * .input(Type.Object({ id: Type.String() }))
113
+ * .options({
114
+ * retryLimit: 5,
115
+ * retryDelay: 5000,
116
+ * priority: 10,
117
+ * })
118
+ * .handler(async (input) => {
119
+ * await processImportant(input.id);
120
+ * });
121
+ * ```
122
+ */
123
+ declare function job(name: string): JobBuilder<void>;
124
+
125
+ /**
126
+ * Job Router
127
+ *
128
+ * Groups job definitions for registration with the server
129
+ */
130
+
131
+ /**
132
+ * Type guard to check if value is a JobDef
133
+ */
134
+ declare function isJobDef(value: unknown): value is JobDef<any>;
135
+ /**
136
+ * Type guard to check if value is a JobRouter
137
+ */
138
+ declare function isJobRouter(value: unknown): value is JobRouter<any>;
139
+ /**
140
+ * Define a job router to group jobs together
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * // Flat structure
145
+ * export const jobRouter = defineJobRouter({
146
+ * sendWelcomeEmail,
147
+ * dailyReport,
148
+ * initCache,
149
+ * });
150
+ *
151
+ * // Nested structure
152
+ * export const jobRouter = defineJobRouter({
153
+ * email: defineJobRouter({
154
+ * sendWelcome: sendWelcomeEmailJob,
155
+ * sendReset: sendResetPasswordJob,
156
+ * }),
157
+ * reports: defineJobRouter({
158
+ * daily: dailyReportJob,
159
+ * weekly: weeklyReportJob,
160
+ * }),
161
+ * });
162
+ *
163
+ * // Mixed
164
+ * export const jobRouter = defineJobRouter({
165
+ * initCache, // flat
166
+ * email: defineJobRouter({ ... }), // nested
167
+ * });
168
+ * ```
169
+ */
170
+ declare function defineJobRouter<TJobs extends Record<string, JobRouterEntry>>(jobs: TJobs): JobRouter<TJobs>;
171
+ /**
172
+ * Collect all JobDefs from a JobRouter (including nested)
173
+ */
174
+ declare function collectJobs(router: JobRouter<any>, prefix?: string): JobDef<any>[];
175
+
176
+ /**
177
+ * Job Registration
178
+ *
179
+ * Registers jobs with pg-boss
180
+ */
181
+
182
+ /**
183
+ * Register all jobs from a JobRouter with pg-boss
184
+ *
185
+ * This function:
186
+ * 1. Collects all jobs from the router (including nested routers)
187
+ * 2. Optionally clears existing jobs (if clearOnStart is enabled)
188
+ * 3. Registers each job's worker handler with pg-boss
189
+ * 4. Sets up cron schedules for scheduled jobs
190
+ * 5. Queues runOnce jobs
191
+ * 6. Connects event subscriptions to job queues
192
+ *
193
+ * @param router - JobRouter containing job definitions
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * // Define jobs
198
+ * const sendEmail = job('send-email')
199
+ * .input(Type.Object({ to: Type.String() }))
200
+ * .handler(async (input) => { ... });
201
+ *
202
+ * const dailyReport = job('daily-report')
203
+ * .cron('0 9 * * *')
204
+ * .handler(async () => { ... });
205
+ *
206
+ * // Create router
207
+ * const jobRouter = defineJobRouter({ sendEmail, dailyReport });
208
+ *
209
+ * // Initialize pg-boss first
210
+ * await initBoss({ connectionString: process.env.DATABASE_URL! });
211
+ *
212
+ * // Register jobs
213
+ * await registerJobs(jobRouter);
214
+ * ```
215
+ */
216
+ declare function registerJobs(router: JobRouter<any>): Promise<void>;
217
+
218
+ export { CompensateHandler, JobDef, JobHandler, JobOptions, JobRouter, JobRouterEntry, collectJobs, defineJobRouter, isJobDef, isJobRouter, job, registerJobs };
@@ -0,0 +1,410 @@
1
+ import PgBoss from 'pg-boss';
2
+ import { logger } from '@spfn/core/logger';
3
+
4
+ // src/job/boss.ts
5
+ var jobLogger = logger.child("@spfn/core:job");
6
+ var bossInstance = null;
7
+ var bossConfig = null;
8
+ async function initBoss(options) {
9
+ if (bossInstance) {
10
+ jobLogger.warn("pg-boss already initialized, returning existing instance");
11
+ return bossInstance;
12
+ }
13
+ jobLogger.info("Initializing pg-boss...");
14
+ bossConfig = options;
15
+ const pgBossOptions = {
16
+ connectionString: options.connectionString,
17
+ schema: options.schema ?? "spfn_queue",
18
+ maintenanceIntervalSeconds: options.maintenanceIntervalSeconds ?? 120
19
+ };
20
+ if (options.monitorIntervalSeconds !== void 0 && options.monitorIntervalSeconds >= 1) {
21
+ pgBossOptions.monitorIntervalSeconds = options.monitorIntervalSeconds;
22
+ }
23
+ bossInstance = new PgBoss(pgBossOptions);
24
+ bossInstance.on("error", (error) => {
25
+ jobLogger.error("pg-boss error:", error);
26
+ });
27
+ await bossInstance.start();
28
+ jobLogger.info("pg-boss started successfully");
29
+ return bossInstance;
30
+ }
31
+ function getBoss() {
32
+ return bossInstance;
33
+ }
34
+ async function stopBoss() {
35
+ if (!bossInstance) {
36
+ return;
37
+ }
38
+ jobLogger.info("Stopping pg-boss...");
39
+ try {
40
+ await bossInstance.stop({ graceful: true, timeout: 3e4 });
41
+ jobLogger.info("pg-boss stopped gracefully");
42
+ } catch (error) {
43
+ jobLogger.error("Error stopping pg-boss:", error);
44
+ throw error;
45
+ } finally {
46
+ bossInstance = null;
47
+ bossConfig = null;
48
+ }
49
+ }
50
+ function isBossRunning() {
51
+ return bossInstance !== null;
52
+ }
53
+ function shouldClearOnStart() {
54
+ return bossConfig?.clearOnStart ?? false;
55
+ }
56
+
57
+ // src/job/job-builder.ts
58
+ function buildPgBossOptions(defaults, sendOptions) {
59
+ const options = {};
60
+ if (sendOptions?.startAfter) {
61
+ options.startAfter = sendOptions.startAfter;
62
+ }
63
+ if (sendOptions?.singletonKey) {
64
+ options.singletonKey = sendOptions.singletonKey;
65
+ }
66
+ if (sendOptions?.priority !== void 0) {
67
+ options.priority = sendOptions.priority;
68
+ }
69
+ if (defaults?.retryLimit !== void 0) {
70
+ options.retryLimit = defaults.retryLimit;
71
+ }
72
+ if (defaults?.retryDelay !== void 0) {
73
+ options.retryDelay = defaults.retryDelay;
74
+ }
75
+ if (defaults?.expireInSeconds !== void 0) {
76
+ options.expireInSeconds = defaults.expireInSeconds;
77
+ }
78
+ if (defaults?.priority !== void 0 && sendOptions?.priority === void 0) {
79
+ options.priority = defaults.priority;
80
+ }
81
+ if (defaults?.singletonKey && !sendOptions?.singletonKey) {
82
+ options.singletonKey = defaults.singletonKey;
83
+ }
84
+ if (defaults?.retentionSeconds !== void 0) {
85
+ options.retentionSeconds = defaults.retentionSeconds;
86
+ }
87
+ return options;
88
+ }
89
+ var JobBuilder = class _JobBuilder {
90
+ _name;
91
+ _inputSchema;
92
+ _outputSchema;
93
+ _cronExpression;
94
+ _runOnce;
95
+ _subscribedEvent;
96
+ _subscribedEventDef;
97
+ _options;
98
+ _handler;
99
+ _compensate;
100
+ constructor(name) {
101
+ this._name = name;
102
+ }
103
+ /**
104
+ * Define input schema with TypeBox
105
+ */
106
+ input(schema) {
107
+ const builder = new _JobBuilder(this._name);
108
+ builder._inputSchema = schema;
109
+ builder._outputSchema = this._outputSchema;
110
+ builder._cronExpression = this._cronExpression;
111
+ builder._runOnce = this._runOnce;
112
+ builder._subscribedEvent = this._subscribedEvent;
113
+ builder._options = this._options;
114
+ return builder;
115
+ }
116
+ /**
117
+ * Define output schema with TypeBox (for workflow integration)
118
+ */
119
+ output(schema) {
120
+ const builder = new _JobBuilder(this._name);
121
+ builder._inputSchema = this._inputSchema;
122
+ builder._outputSchema = schema;
123
+ builder._cronExpression = this._cronExpression;
124
+ builder._runOnce = this._runOnce;
125
+ builder._subscribedEvent = this._subscribedEvent;
126
+ builder._options = this._options;
127
+ return builder;
128
+ }
129
+ /**
130
+ * Subscribe to an event (decoupled triggering)
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * const userCreated = defineEvent('user.created', Type.Object({
135
+ * userId: Type.String(),
136
+ * }));
137
+ *
138
+ * const sendWelcomeEmail = job('send-welcome-email')
139
+ * .on(userCreated)
140
+ * .handler(async (payload) => {
141
+ * // payload is typed as { userId: string }
142
+ * });
143
+ * ```
144
+ */
145
+ on(event) {
146
+ const builder = new _JobBuilder(this._name);
147
+ builder._inputSchema = event.schema;
148
+ builder._outputSchema = this._outputSchema;
149
+ builder._subscribedEvent = event.name;
150
+ builder._subscribedEventDef = event;
151
+ builder._cronExpression = this._cronExpression;
152
+ builder._runOnce = this._runOnce;
153
+ builder._options = this._options;
154
+ return builder;
155
+ }
156
+ /**
157
+ * Set cron expression for scheduled execution
158
+ */
159
+ cron(expression) {
160
+ this._cronExpression = expression;
161
+ return this;
162
+ }
163
+ /**
164
+ * Mark job to run once on server start
165
+ */
166
+ runOnce() {
167
+ this._runOnce = true;
168
+ return this;
169
+ }
170
+ /**
171
+ * Set job options (retry, expiration, etc.)
172
+ */
173
+ options(options) {
174
+ this._options = options;
175
+ return this;
176
+ }
177
+ /**
178
+ * Set job timeout in milliseconds
179
+ * (Converts to expireInSeconds for pg-boss)
180
+ */
181
+ timeout(ms) {
182
+ this._options = {
183
+ ...this._options,
184
+ expireInSeconds: Math.ceil(ms / 1e3)
185
+ };
186
+ return this;
187
+ }
188
+ /**
189
+ * Define compensate handler for rollback (workflow integration)
190
+ */
191
+ compensate(fn) {
192
+ this._compensate = fn;
193
+ return this;
194
+ }
195
+ /**
196
+ * Define the job handler and finalize the job definition
197
+ */
198
+ handler(fn) {
199
+ this._handler = fn;
200
+ const name = this._name;
201
+ const inputSchema = this._inputSchema;
202
+ const outputSchema = this._outputSchema;
203
+ const cronExpression = this._cronExpression;
204
+ const runOnce = this._runOnce;
205
+ const subscribedEvent = this._subscribedEvent;
206
+ const subscribedEventDef = this._subscribedEventDef;
207
+ const options = this._options;
208
+ const handler = this._handler;
209
+ const compensate = this._compensate;
210
+ const send = async (inputOrOptions, maybeOptions) => {
211
+ const boss = getBoss();
212
+ if (!boss) {
213
+ throw new Error(
214
+ `[Job:${name}] pg-boss not initialized. Ensure jobs are registered with defineServerConfig().jobs()`
215
+ );
216
+ }
217
+ const [input, sendOptions] = inputSchema ? [inputOrOptions, maybeOptions] : [void 0, inputOrOptions];
218
+ return await boss.send(
219
+ name,
220
+ input ?? {},
221
+ buildPgBossOptions(options, sendOptions)
222
+ );
223
+ };
224
+ const run = async (input) => {
225
+ if (inputSchema) {
226
+ return await handler(input);
227
+ } else {
228
+ return await handler();
229
+ }
230
+ };
231
+ return {
232
+ name,
233
+ inputSchema,
234
+ outputSchema,
235
+ cronExpression,
236
+ runOnce,
237
+ subscribedEvent,
238
+ _subscribedEventDef: subscribedEventDef,
239
+ options,
240
+ handler,
241
+ compensate,
242
+ send,
243
+ run,
244
+ _input: void 0,
245
+ _output: void 0
246
+ };
247
+ }
248
+ };
249
+ function job(name) {
250
+ return new JobBuilder(name);
251
+ }
252
+
253
+ // src/job/job-router.ts
254
+ function isJobDef(value) {
255
+ return value !== null && typeof value === "object" && "name" in value && "handler" in value && "send" in value && "run" in value;
256
+ }
257
+ function isJobRouter(value) {
258
+ return value !== null && typeof value === "object" && "jobs" in value && "_jobs" in value;
259
+ }
260
+ function defineJobRouter(jobs) {
261
+ return {
262
+ jobs,
263
+ _jobs: jobs
264
+ };
265
+ }
266
+ function collectJobs(router, prefix = "") {
267
+ const jobs = [];
268
+ for (const [key, value] of Object.entries(router.jobs)) {
269
+ const name = prefix ? `${prefix}.${key}` : key;
270
+ if (isJobRouter(value)) {
271
+ jobs.push(...collectJobs(value, name));
272
+ } else if (isJobDef(value)) {
273
+ jobs.push(value);
274
+ }
275
+ }
276
+ return jobs;
277
+ }
278
+ var jobLogger2 = logger.child("@spfn/core:job");
279
+ function getEventQueueName(eventName) {
280
+ return `event:${eventName}`;
281
+ }
282
+ function getDefaultJobOptions(options) {
283
+ return {
284
+ retryLimit: options?.retryLimit ?? 3,
285
+ retryDelay: options?.retryDelay ?? 1e3,
286
+ expireInSeconds: options?.expireInSeconds ?? 300
287
+ };
288
+ }
289
+ async function registerJobs(router) {
290
+ const boss = getBoss();
291
+ if (!boss) {
292
+ throw new Error(
293
+ "pg-boss not initialized. Call initBoss() before registerJobs()"
294
+ );
295
+ }
296
+ const jobs = collectJobs(router);
297
+ const clearOnStart = shouldClearOnStart();
298
+ jobLogger2.info(`Registering ${jobs.length} job(s)...`);
299
+ if (clearOnStart) {
300
+ jobLogger2.info("Clearing existing jobs before registration...");
301
+ for (const job2 of jobs) {
302
+ await boss.deleteAllJobs(job2.name);
303
+ if (job2.subscribedEvent) {
304
+ const eventQueue = getEventQueueName(job2.subscribedEvent);
305
+ await boss.deleteAllJobs(eventQueue);
306
+ }
307
+ }
308
+ jobLogger2.info("Existing jobs cleared");
309
+ }
310
+ for (const job2 of jobs) {
311
+ await registerJob(job2);
312
+ }
313
+ jobLogger2.info("All jobs registered successfully");
314
+ }
315
+ async function ensureQueue(boss, queueName) {
316
+ await boss.createQueue(queueName);
317
+ }
318
+ async function registerWorker(boss, job2, queueName) {
319
+ await ensureQueue(boss, queueName);
320
+ await boss.work(
321
+ queueName,
322
+ { batchSize: 1 },
323
+ async (jobs) => {
324
+ for (const pgBossJob of jobs) {
325
+ jobLogger2.debug(`[Job:${job2.name}] Executing...`, { jobId: pgBossJob.id });
326
+ const startTime = Date.now();
327
+ try {
328
+ if (job2.inputSchema) {
329
+ await job2.handler(pgBossJob.data);
330
+ } else {
331
+ await job2.handler();
332
+ }
333
+ const duration = Date.now() - startTime;
334
+ jobLogger2.info(`[Job:${job2.name}] Completed in ${duration}ms`, {
335
+ jobId: pgBossJob.id,
336
+ duration
337
+ });
338
+ } catch (error) {
339
+ const duration = Date.now() - startTime;
340
+ jobLogger2.error(`[Job:${job2.name}] Failed after ${duration}ms`, {
341
+ jobId: pgBossJob.id,
342
+ duration,
343
+ error: error instanceof Error ? error.message : String(error)
344
+ });
345
+ throw error;
346
+ }
347
+ }
348
+ }
349
+ );
350
+ }
351
+ function connectEventToQueue(boss, job2, queueName) {
352
+ if (!job2._subscribedEventDef) {
353
+ return;
354
+ }
355
+ const eventDef = job2._subscribedEventDef;
356
+ eventDef._registerJobQueue(queueName, async (queue, payload) => {
357
+ await boss.send(queue, payload, getDefaultJobOptions(job2.options));
358
+ });
359
+ jobLogger2.debug(`[Job:${job2.name}] Connected to event: ${job2.subscribedEvent}`);
360
+ }
361
+ async function registerCronSchedule(boss, job2) {
362
+ if (!job2.cronExpression) {
363
+ return;
364
+ }
365
+ jobLogger2.debug(`[Job:${job2.name}] Scheduling cron: ${job2.cronExpression}`);
366
+ await ensureQueue(boss, job2.name);
367
+ await boss.schedule(
368
+ job2.name,
369
+ job2.cronExpression,
370
+ {},
371
+ getDefaultJobOptions(job2.options)
372
+ );
373
+ jobLogger2.info(`[Job:${job2.name}] Cron scheduled: ${job2.cronExpression}`);
374
+ }
375
+ async function queueRunOnceJob(boss, job2) {
376
+ if (!job2.runOnce) {
377
+ return;
378
+ }
379
+ jobLogger2.debug(`[Job:${job2.name}] Queuing runOnce job`);
380
+ await ensureQueue(boss, job2.name);
381
+ await boss.send(
382
+ job2.name,
383
+ {},
384
+ {
385
+ ...getDefaultJobOptions(job2.options),
386
+ singletonKey: `runOnce:${job2.name}`
387
+ }
388
+ );
389
+ jobLogger2.info(`[Job:${job2.name}] runOnce job queued`);
390
+ }
391
+ async function registerJob(job2) {
392
+ const boss = getBoss();
393
+ if (!boss) {
394
+ throw new Error("pg-boss not initialized");
395
+ }
396
+ const queueName = job2.subscribedEvent ? getEventQueueName(job2.subscribedEvent) : job2.name;
397
+ jobLogger2.debug(`Registering job: ${job2.name}`, {
398
+ queueName,
399
+ subscribedEvent: job2.subscribedEvent
400
+ });
401
+ await registerWorker(boss, job2, queueName);
402
+ connectEventToQueue(boss, job2, queueName);
403
+ await registerCronSchedule(boss, job2);
404
+ await queueRunOnceJob(boss, job2);
405
+ jobLogger2.debug(`Job registered: ${job2.name}`);
406
+ }
407
+
408
+ export { collectJobs, defineJobRouter, getBoss, initBoss, isBossRunning, isJobDef, isJobRouter, job, registerJobs, shouldClearOnStart, stopBoss };
409
+ //# sourceMappingURL=index.js.map
410
+ //# sourceMappingURL=index.js.map