@shivaedev/jobs 0.21.0 → 0.22.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.22.1 - 2026-10-30
4
+
5
+ ### Changed
6
+
7
+ - Require Effect 4.0.6 and align the Effect companion package peers and generated starter catalog to the same exact release. Install the 4.0.6 Effect stack together.
8
+
9
+ ### Fixed
10
+
11
+ - Register hosted RPC cache-control handling through Effect 4.0.6's request-scoped pre-response API so responses keep `private, no-store`.
12
+ - Accept native RPC's `application/x-ndjson` media type while preserving `application/ndjson` callers at the transport guard.
13
+ - Keep subscriptions open after their HTTP request body completes; closing the socket still cancels them.
14
+
15
+ ## 0.22.0 - 2026-10-28
16
+
17
+ ### Added
18
+
19
+ - Register schedule definitions beside queues on the admin Jobs page, with null payloads in failed runs, dead-letter listings and job lookups. Pages with no queues can register handlers and serve health.
20
+ - Read stored jobs with null payload schemas through the jobs service without changing queue payload validation.
21
+ - Show an empty state in the starter Jobs view when no queues or schedules are registered.
22
+
3
23
  ## 0.21.0 - 2026-10-27
4
24
 
5
25
  ### Added
package/README.md CHANGED
@@ -12,13 +12,11 @@ import { Effect, Schema } from "effect";
12
12
  import { Mail } from "./services.ts";
13
13
 
14
14
  const SendEmail = defineQueue({
15
- name: "send-email",
16
- schema: Schema.Struct({ userId: Schema.NumberFromString }),
15
+ name: "send-email",
16
+ schema: Schema.Struct({ userId: Schema.NumberFromString }),
17
17
  });
18
18
 
19
- const emailWorker = SendEmail.handle(({ userId }) =>
20
- Effect.flatMap(Mail, (mail) => mail.send(userId)),
21
- );
19
+ const emailWorker = SendEmail.handle(({ userId }) => Effect.flatMap(Mail, (mail) => mail.send(userId)));
22
20
  ```
23
21
 
24
22
  `Mail` is the application's Effect service, defined in the guide below. The worker receives a number even though the durable payload stores a string. The same Schema encodes the producer's payload and decodes the worker's input; malformed stored data fails before the handler runs. Provide the worker's services when the jobs Layer starts, and the handler uses that captured context when pg-boss calls it later.
@@ -46,19 +44,19 @@ import { pgBossSchema } from "@shivaedev/jobs/server/schema.ts";
46
44
  import { appDatabase } from "@shivaedev/server/appHost.ts";
47
45
 
48
46
  const database = appDatabase({
49
- migrations: {
50
- loader,
51
- components: [pgBossSchema({ schema: "app_jobs" })],
52
- mode: "migrate",
53
- },
47
+ migrations: {
48
+ loader,
49
+ components: [pgBossSchema({ schema: "app_jobs" })],
50
+ mode: "migrate",
51
+ },
54
52
  });
55
53
  ```
56
54
 
57
55
  The component uses `installPgBossSchema` as its only install and upgrade path. It is pending when the schema is missing or its stored version is below the installed pg-boss package's required schema version; the readiness error names the schema and both versions (`missing` for an absent version). Start every producer and worker with the same schema and `migrate: false`. Use host mode `"wait"` for services that must wait for a deployment's migration process; no additional jobs-layer wait is needed.
58
56
 
59
- With server's `appDatabase({ migrations: { mode: "wait", release, ... } })`, each jobs Layer automatically reads sql's optional `WorkerRelease` Context service. When the database belongs to another release, it calls pg-boss `offWork` for every registered worker queue, lets active jobs finish, logs `Workers paused for another database release` once, and idles. Producers and enqueueing continue. When its release owns the marker again and old workers have drained, it registers workers through the normal path and logs `Workers resumed for database release`. Equality permits rollbacks; no version ordering or payload compatibility policy is added. With no service, registration behaves as before.
57
+ With server's `appDatabase({ migrations: { mode: "wait", release, ... } })`, each jobs Layer automatically reads sql's optional `WorkerRelease` Context service. When the database belongs to another release, it calls pg-boss `offWork` for every registered worker queue, lets active jobs finish, logs `Workers paused for another database release` once, and idles. Producers and enqueueing continue. When its release owns the marker again and old workers have drained, it registers workers through the normal path and logs `Workers resumed for database release`. Equality permits rollbacks; no version ordering or payload compatibility policy is added. Without that service, the Layer registers its workers at startup and never pauses them.
60
58
 
61
- A worker keeps its sql heartbeat row live while draining; the owning release waits for all other live releases to step aside. A crashed worker stops blocking once its heartbeat is older than five polling intervals. Set an explicit queue `expireInSeconds` and a `stop: { graceful: true, timeout }` long enough to cover it. Scope shutdown on SIGTERM waits for the native pg-boss stop before releasing application dependencies. Give the host's termination grace a margin beyond that timeout; the starter uses 60-second expiry, 65-second stop and 75-second Railway draining.
59
+ A paused worker keeps its process registered with sql's worker release while active jobs drain, so the owning release waits for it; [sql's worker release](https://github.com/ShivaeDev/platform/blob/main/packages/sql/README.md) owns the heartbeat and how long a crashed worker can block. Closing the jobs Layer's scope waits for the native pg-boss `stop` before releasing the services the Layer captured. Choose the three bounds together: each queue's `expireInSeconds`, a `stop: { graceful: true, timeout }` in milliseconds that covers it, and a host termination grace beyond that timeout. For example, a queue with `expireInSeconds: 60` pairs with `stop: { graceful: true, timeout: 65_000 }` under a 75-second termination grace.
62
60
 
63
61
  `installPgBossSchema` installs or upgrades pg-boss through the provided Effect SQL client without starting workers or schedules. Run it outside an application transaction, in a release step or the `fixtures` Effect of `makePostgresTestLayer`, so stories inherit the schema from the migrated template:
64
62
 
@@ -82,14 +80,17 @@ import { Context, Effect, Layer } from "effect";
82
80
 
83
81
  export const Jobs = makePgBoss("@app/Jobs");
84
82
 
85
- export class Mail extends Context.Service<Mail, {
86
- readonly send: (userId: number) => Effect.Effect<void>;
87
- readonly removeExpired: Effect.Effect<void>;
88
- }>()("@app/Mail") {}
83
+ export class Mail extends Context.Service<
84
+ Mail,
85
+ {
86
+ readonly send: (userId: number) => Effect.Effect<void>;
87
+ readonly removeExpired: Effect.Effect<void>;
88
+ }
89
+ >()("@app/Mail") {}
89
90
 
90
91
  export const MailLive = Layer.succeed(Mail, {
91
- send: (userId) => Effect.log({ event: "send_email", userId }),
92
- removeExpired: Effect.log({ event: "remove_expired_mail" }),
92
+ send: (userId) => Effect.log({ event: "send_email", userId }),
93
+ removeExpired: Effect.log({ event: "remove_expired_mail" }),
93
94
  });
94
95
  ```
95
96
 
@@ -105,27 +106,25 @@ import { Effect, Schema } from "effect";
105
106
  import { Mail } from "./services.ts";
106
107
 
107
108
  export const SendEmail = defineQueue({
108
- name: "send-email",
109
- schema: Schema.Struct({ userId: Schema.NumberFromString }),
110
- queue: { retryLimit: 5 },
109
+ name: "send-email",
110
+ schema: Schema.Struct({ userId: Schema.NumberFromString }),
111
+ queue: { retryLimit: 5 },
111
112
  });
112
113
 
113
114
  export const emailWorker = SendEmail.handle(({ userId }, job) =>
114
- Effect.gen(function* () {
115
- const mail = yield* Mail;
116
- yield* mail.send(userId);
117
- yield* Effect.log({ jobId: job.id });
118
- }),
115
+ Effect.gen(function* () {
116
+ const mail = yield* Mail;
117
+ yield* mail.send(userId);
118
+ yield* Effect.log({ jobId: job.id });
119
+ }),
119
120
  );
120
121
 
121
122
  export const Cleanup = defineSchedule({
122
- name: "cleanup-mail",
123
- cron: "17 3 * * *",
123
+ name: "cleanup-mail",
124
+ cron: "17 3 * * *",
124
125
  });
125
126
 
126
- export const cleanupWorker = Cleanup.run(
127
- Effect.flatMap(Mail, (mail) => mail.removeExpired),
128
- );
127
+ export const cleanupWorker = Cleanup.run(Effect.flatMap(Mail, (mail) => mail.removeExpired));
129
128
  ```
130
129
 
131
130
  The queue takes `{ userId: number }` in application code and stores `{ userId: string }`. Its handler receives the decoded number and a job context, including the job's `id`. Keep the queue definition available to producers; the runtime registers the worker created by `handle`.
@@ -142,10 +141,10 @@ Queue and schedule workers default to `batchSize: 10` and `burstWhenBatchFull: t
142
141
 
143
142
  ```ts
144
143
  const Compare = defineQueue({
145
- name: "compare",
146
- schema: Schema.Struct({ id: Schema.Number }),
147
- queue: { notify: true },
148
- worker: { batchSize: 2, localConcurrency: 5 },
144
+ name: "compare",
145
+ schema: Schema.Struct({ id: Schema.Number }),
146
+ queue: { notify: true },
147
+ worker: { batchSize: 2, localConcurrency: 5 },
149
148
  });
150
149
  ```
151
150
 
@@ -161,10 +160,12 @@ Fail a queue handler or scheduled Effect with `RetryAt` when a provider gives a
161
160
  import { DateTime, Effect } from "effect";
162
161
  import { RetryAt } from "@shivaedev/jobs/server/definition.ts";
163
162
 
164
- const waitForQuota = Effect.fail(new RetryAt({
165
- at: DateTime.makeUnsafe("2030-01-01T00:01:00Z"),
166
- reason: "Provider quota resets",
167
- }));
163
+ const waitForQuota = Effect.fail(
164
+ new RetryAt({
165
+ at: DateTime.makeUnsafe("2030-01-01T00:01:00Z"),
166
+ reason: "Provider quota resets",
167
+ }),
168
+ );
168
169
  ```
169
170
 
170
171
  The same job returns to waiting with `startAfter` set to `at`; its ID, singleton key, payload and retry count stay unchanged. A past or current `at` is eligible on the next fetch. Deferral does not dead-letter the job or call `onError`. Its job span ends OK with a `job.deferred` event whose `at` is an ISO UTC string and whose `reason` is the supplied string. Deferred jobs rely on polling, including queues using `notify: true`. Stately jobs sharing a singleton key can defer together and still run one at a time. While waiting, their native job metadata reports the adapter's `effect-stately-deferred` policy; a database trigger restores `stately` when pg-boss claims them, preserving its active-job exclusion.
@@ -177,19 +178,17 @@ Put related job kinds in one tagged-union queue and choose the entity key in the
177
178
 
178
179
  ```ts
179
180
  const PullRequestJobs = defineQueue({
180
- name: "pull-request",
181
- schema: Schema.Union([
182
- Schema.TaggedStruct("Refresh", { pullRequestId: Schema.NumberFromString }),
183
- Schema.TaggedStruct("Reconcile", { pullRequestId: Schema.NumberFromString }),
184
- ]),
185
- queue: { policy: "singleton" },
186
- key: ({ pullRequestId }) => `pr:${pullRequestId.toFixed(0)}`,
187
- worker: { batchSize: 1, localConcurrency: 3 },
181
+ name: "pull-request",
182
+ schema: Schema.Union([
183
+ Schema.TaggedStruct("Refresh", { pullRequestId: Schema.NumberFromString }),
184
+ Schema.TaggedStruct("Reconcile", { pullRequestId: Schema.NumberFromString }),
185
+ ]),
186
+ queue: { policy: "singleton" },
187
+ key: ({ pullRequestId }) => `pr:${pullRequestId.toFixed(0)}`,
188
+ worker: { batchSize: 1, localConcurrency: 3 },
188
189
  });
189
190
 
190
- const refresh = Effect.flatMap(Jobs, (jobs) =>
191
- jobs.enqueue(PullRequestJobs, { _tag: "Refresh", pullRequestId: 42 }),
192
- );
191
+ const refresh = Effect.flatMap(Jobs, (jobs) => jobs.enqueue(PullRequestJobs, { _tag: "Refresh", pullRequestId: 42 }));
193
192
  ```
194
193
 
195
194
  `queue.policy` accepts pg-boss's policy literals and rejects typos. The `singleton` policy requires `key: (payload) => string`. The callback sees the decoded payload, so `pullRequestId` is a number. `enqueue` supplies pg-boss's `singletonKey` automatically; callers cannot supply a conflicting key in send options.
@@ -204,15 +203,15 @@ pg-boss marks every job in a fetched batch active together. Each job's expiry wi
204
203
 
205
204
  ```ts
206
205
  const Ingest = defineQueue({
207
- name: "ingest",
208
- schema: Schema.Struct({ sourceId: Schema.String }),
209
- queue: { expireInSeconds: 300 },
210
- worker: { batchSize: 1 },
206
+ name: "ingest",
207
+ schema: Schema.Struct({ sourceId: Schema.String }),
208
+ queue: { expireInSeconds: 300 },
209
+ worker: { batchSize: 1 },
211
210
  });
212
211
 
213
212
  const IndexTitle = defineQueue({
214
- name: "index-title",
215
- schema: Schema.Struct({ titleId: Schema.String }),
213
+ name: "index-title",
214
+ schema: Schema.Struct({ titleId: Schema.String }),
216
215
  });
217
216
  ```
218
217
 
@@ -228,10 +227,10 @@ Queue handlers can yield `job.remainingBudget`, an `Effect.Effect<Duration.Durat
228
227
  import { Duration, Effect } from "effect";
229
228
 
230
229
  const ingestWorker = Ingest.handle(({ sourceId }, job) =>
231
- Effect.gen(function* () {
232
- const budget = yield* job.remainingBudget;
233
- yield* Effect.log({ sourceId, remainingMilliseconds: Duration.toMillis(budget) });
234
- }),
230
+ Effect.gen(function* () {
231
+ const budget = yield* job.remainingBudget;
232
+ yield* Effect.log({ sourceId, remainingMilliseconds: Duration.toMillis(budget) });
233
+ }),
235
234
  );
236
235
  ```
237
236
 
@@ -247,11 +246,11 @@ import { cleanupWorker, emailWorker } from "./jobs.ts";
247
246
  import { Jobs, MailLive } from "./services.ts";
248
247
 
249
248
  export const jobsLayer = (databaseUrl: string) =>
250
- Jobs.layer({
251
- connectionString: databaseUrl,
252
- schema: "app_jobs",
253
- jobs: [emailWorker, cleanupWorker],
254
- }).pipe(Layer.provide(MailLive));
249
+ Jobs.layer({
250
+ connectionString: databaseUrl,
251
+ schema: "app_jobs",
252
+ jobs: [emailWorker, cleanupWorker],
253
+ }).pipe(Layer.provide(MailLive));
255
254
  ```
256
255
 
257
256
  The constructor options belong to pg-boss. `jobs` is the complete list of registrations for this Layer. The Layer captures `MailLive` for both the queue handler and the scheduled Effect. A startup or registration failure fails Layer acquisition with `PgBossError` or `PgBossQueueOptionsError` and releases its acquired client reference. Registration creates a queue again, up to six times with a short backoff, when PostgreSQL rolls the creation back as a deadlock victim (SQLSTATE `40P01`), which a partitioned queue can meet when other queues in the schema have traffic. A shared client stays running while another scope still owns a reference.
@@ -266,12 +265,12 @@ import { jobsLayer } from "./runtime.ts";
266
265
  import { Jobs } from "./services.ts";
267
266
 
268
267
  const inspectJobs = (databaseUrl: string) =>
269
- Effect.scoped(
270
- Effect.gen(function* () {
271
- const jobs = yield* Jobs;
272
- return yield* jobs.health;
273
- }).pipe(Effect.provide(jobsLayer(databaseUrl))),
274
- );
268
+ Effect.scoped(
269
+ Effect.gen(function* () {
270
+ const jobs = yield* Jobs;
271
+ return yield* jobs.health;
272
+ }).pipe(Effect.provide(jobsLayer(databaseUrl))),
273
+ );
275
274
  ```
276
275
 
277
276
  This Effect starts the jobs Layer, reads health and closes the scope. The client stops when that scope closes.
@@ -284,10 +283,10 @@ import { SendEmail } from "./jobs.ts";
284
283
  import { Jobs } from "./services.ts";
285
284
 
286
285
  export const enqueueEmail = (userId: number) =>
287
- Effect.gen(function* () {
288
- const jobs = yield* Jobs;
289
- return yield* jobs.enqueue(SendEmail, { userId });
290
- });
286
+ Effect.gen(function* () {
287
+ const jobs = yield* Jobs;
288
+ return yield* jobs.enqueue(SendEmail, { userId });
289
+ });
291
290
  ```
292
291
 
293
292
  Provide `Jobs` through the application's existing runtime. `enqueue` takes the decoded payload, so passing a string `userId` is a type error. It encodes the number to a string before calling pg-boss. The result type is `Option.Option<string>`: a job identifier becomes `Some`, and a `null` send result becomes `None`.
@@ -309,15 +308,15 @@ import { Effect } from "effect";
309
308
  import { Jobs } from "./services.ts";
310
309
 
311
310
  export const readJobCounts = Effect.gen(function* () {
312
- const jobs = yield* Jobs;
313
- const health = yield* jobs.health;
314
- return {
315
- active: health.activeTotal,
316
- deadLettered: health.deadLetteredTotal,
317
- failed: health.failedTotal,
318
- queued: health.queuedTotal,
319
- ready: health.readyTotal,
320
- };
311
+ const jobs = yield* Jobs;
312
+ const health = yield* jobs.health;
313
+ return {
314
+ active: health.activeTotal,
315
+ deadLettered: health.deadLetteredTotal,
316
+ failed: health.failedTotal,
317
+ queued: health.queuedTotal,
318
+ ready: health.readyTotal,
319
+ };
321
320
  });
322
321
  ```
323
322
 
@@ -330,15 +329,16 @@ import { Effect, Option } from "effect";
330
329
  import { SendEmail } from "./jobs.ts";
331
330
  import { Jobs } from "./services.ts";
332
331
 
333
- export const inspectEmail = (id: string) => Effect.gen(function* () {
334
- const jobs = yield* Jobs;
335
- const job = yield* jobs.getJob(SendEmail, id);
336
- if (Option.isSome(job) && job.value.state === "failed") {
337
- yield* jobs.retry(SendEmail, id);
338
- }
339
- const counts = yield* jobs.counts(SendEmail);
340
- return counts.queuedCount === 0 && counts.activeCount === 0;
341
- });
332
+ export const inspectEmail = (id: string) =>
333
+ Effect.gen(function* () {
334
+ const jobs = yield* Jobs;
335
+ const job = yield* jobs.getJob(SendEmail, id);
336
+ if (Option.isSome(job) && job.value.state === "failed") {
337
+ yield* jobs.retry(SendEmail, id);
338
+ }
339
+ const counts = yield* jobs.counts(SendEmail);
340
+ return counts.queuedCount === 0 && counts.activeCount === 0;
341
+ });
342
342
  ```
343
343
 
344
344
  `counts(queue)` reads the job table directly on each call. `queuedCount` includes created and retry-waiting jobs, including future jobs; `activeCount` counts running jobs, `failedCount` counts retained failures, and `totalCount` includes retained terminal jobs. A queue has drained when queued and active counts are both zero. These counts are a snapshot, so a producer can enqueue more work after the query returns.
@@ -352,16 +352,17 @@ import { Effect, Option } from "effect";
352
352
  import { SendEmail } from "./jobs.ts";
353
353
  import { Jobs } from "./services.ts";
354
354
 
355
- export const failedEmails = (cursor?: string) => Effect.gen(function* () {
356
- const jobs = yield* Jobs;
357
- const failed = yield* jobs.failedJobs(SendEmail, { cursor, limit: 20 });
358
- const deadLettered = yield* jobs.deadLetteredJobs(SendEmail, { limit: 20 });
359
- return {
360
- deadLettered: deadLettered.jobs.map((job) => ({ id: job.id, original: Option.getOrNull(job.sourceId), error: job.sourceOutput })),
361
- failed: failed.jobs.map((job) => ({ id: job.id, attempt: job.attempt, error: job.output, userId: job.data.userId })),
362
- next: Option.getOrUndefined(failed.next),
363
- };
364
- });
355
+ export const failedEmails = (cursor?: string) =>
356
+ Effect.gen(function* () {
357
+ const jobs = yield* Jobs;
358
+ const failed = yield* jobs.failedJobs(SendEmail, { cursor, limit: 20 });
359
+ const deadLettered = yield* jobs.deadLetteredJobs(SendEmail, { limit: 20 });
360
+ return {
361
+ deadLettered: deadLettered.jobs.map((job) => ({ id: job.id, original: Option.getOrNull(job.sourceId), error: job.sourceOutput })),
362
+ failed: failed.jobs.map((job) => ({ id: job.id, attempt: job.attempt, error: job.output, userId: job.data.userId })),
363
+ next: Option.getOrUndefined(failed.next),
364
+ };
365
+ });
365
366
  ```
366
367
 
367
368
  `health` and `counts` say how many jobs failed; these two listings say which ones and why. `failedJobs(queue, options)` lists the queue's jobs in the `failed` state, the ones that used up their retries. `deadLetteredJobs(queue, options)` lists every job in the queue's dead-letter queue. Dead-letter entries live in the `-dlq` queue: each is a new job with its own ID that pg-boss copied there when the original failed for good. Both listings read pg-boss's `job` table on each call, through the jobs Layer's own pg-boss connection and in its configured schema, so applications never query pg-boss tables themselves. A custom client needs the native `getDb` capability for them.
@@ -386,12 +387,12 @@ import { cleanupWorker, emailWorker } from "./jobs.ts";
386
387
  import { Jobs, MailLive } from "./services.ts";
387
388
 
388
389
  const sharedJobsLayer = (databaseUrl: string) =>
389
- Jobs.layer({
390
- connectionString: databaseUrl,
391
- schema: "app_jobs",
392
- clientCacheKey: "app-jobs",
393
- jobs: [emailWorker, cleanupWorker],
394
- }).pipe(Layer.provide(MailLive));
390
+ Jobs.layer({
391
+ connectionString: databaseUrl,
392
+ schema: "app_jobs",
393
+ clientCacheKey: "app-jobs",
394
+ jobs: [emailWorker, cleanupWorker],
395
+ }).pipe(Layer.provide(MailLive));
395
396
  ```
396
397
 
397
398
  Overlapping Layer builds with the same `clientCacheKey` share one started client. The later build replaces the registered worker, and the final scope release stops the shared client. A later build after that release starts a new client. Without a key, each build creates its own client. The application chooses whether to pass a key; give each distinct constructor configuration its own key.
@@ -404,8 +405,7 @@ Pass a queue definition directly in the jobs Layer to create its queue and dead-
404
405
  import { SendEmail } from "./jobs.ts";
405
406
  import { Jobs } from "./services.ts";
406
407
 
407
- export const producerLayer = (databaseUrl: string) =>
408
- Jobs.layer({ connectionString: databaseUrl, jobs: [SendEmail] });
408
+ export const producerLayer = (databaseUrl: string) => Jobs.layer({ connectionString: databaseUrl, jobs: [SendEmail] });
409
409
  ```
410
410
 
411
411
  Provide this Layer to the request runtime and call `jobs.enqueue(SendEmail, { userId })` as above. A separate worker process registers `SendEmail.handle(...)` against the same database. Producer queues use the same retry options and appear in `health`; only worker registrations capture handler services.
@@ -416,22 +416,22 @@ A handler can yield the same `Jobs` service that owns it. The Layer supplies tha
416
416
 
417
417
  ```ts
418
418
  const Receipt = defineQueue({
419
- name: "receipt",
420
- schema: Schema.Struct({ userId: Schema.Number }),
419
+ name: "receipt",
420
+ schema: Schema.Struct({ userId: Schema.Number }),
421
421
  });
422
422
 
423
423
  const sendAndQueueReceipt = SendEmail.handle(({ userId }) =>
424
- Effect.gen(function* () {
425
- const mail = yield* Mail;
426
- yield* mail.send(userId);
427
- const jobs = yield* Jobs;
428
- yield* jobs.enqueue(Receipt, { userId });
429
- }),
424
+ Effect.gen(function* () {
425
+ const mail = yield* Mail;
426
+ yield* mail.send(userId);
427
+ const jobs = yield* Jobs;
428
+ yield* jobs.enqueue(Receipt, { userId });
429
+ }),
430
430
  );
431
431
 
432
432
  const live = Jobs.layer({
433
- connectionString: databaseUrl,
434
- jobs: [sendAndQueueReceipt, Receipt],
433
+ connectionString: databaseUrl,
434
+ jobs: [sendAndQueueReceipt, Receipt],
435
435
  }).pipe(Layer.provide(MailLive));
436
436
  ```
437
437
 
@@ -450,29 +450,29 @@ import { storyKit } from "@shivaedev/test-story/server/storyKit.ts";
450
450
  import { makePgBossTesting, testRetryPolicy } from "@shivaedev/jobs/server/testing.ts";
451
451
 
452
452
  const emailStories = storyKit({
453
- clock: "live",
454
- *create() {
455
- const testing = makePgBossTesting({ retryPolicy: testRetryPolicy });
456
- const context = yield* Layer.build(Jobs.layer({
457
- connectionString: databaseUrl,
458
- clientFactory: testing.clientFactory,
459
- jobs: [SendEmail],
460
- }));
461
- return { jobs: Context.get(context, Jobs), testing };
462
- },
463
- name: "queued email",
464
- stages: ["ready"],
465
- verbs: ({ jobs, testing }) => ({
466
- enqueue: (userId: number) => jobs.enqueue(SendEmail, { userId }),
467
- testing,
468
- }),
453
+ clock: "live",
454
+ *create() {
455
+ const testing = makePgBossTesting({ retryPolicy: testRetryPolicy });
456
+ const context = yield* Layer.build(
457
+ Jobs.layer({
458
+ connectionString: databaseUrl,
459
+ clientFactory: testing.clientFactory,
460
+ jobs: [SendEmail],
461
+ }),
462
+ );
463
+ return { jobs: Context.get(context, Jobs), testing };
464
+ },
465
+ name: "queued email",
466
+ stages: ["ready"],
467
+ verbs: ({ jobs, testing }) => ({
468
+ enqueue: (userId: number) => jobs.enqueue(SendEmail, { userId }),
469
+ testing,
470
+ }),
469
471
  });
470
472
 
471
473
  emailStories.it("decodes the queued email", [], function* ({ enqueue, testing }) {
472
- const id = Option.getOrThrow(yield* enqueue(42));
473
- expect(yield* testing.jobs(SendEmail)).toMatchObject([
474
- { id, data: { userId: 42 }, state: "created" },
475
- ]);
474
+ const id = Option.getOrThrow(yield* enqueue(42));
475
+ expect(yield* testing.jobs(SendEmail)).toMatchObject([{ id, data: { userId: 42 }, state: "created" }]);
476
476
  });
477
477
  ```
478
478
 
@@ -500,15 +500,15 @@ A kit can also capture `revision` before reading jobs and yield `waitForChange(r
500
500
 
501
501
  Import the module that defines the name; the package has no root entry.
502
502
 
503
- | Module | Public names |
504
- | --- | --- |
503
+ | Module | Public names |
504
+ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
505
505
  | `@shivaedev/jobs/server/definition.ts` | `defineQueue`, `defineSchedule`, `jobContext`, `RetryAt`; `DefineQueueOptions`, `DefineScheduleOptions`, `JobContext`, `JobPayloadSchema`, `JobRegistration`, `QueueDefinition`, `QueueOptions`, `QueuePolicy`, `QueueWorker`, `RegistrationRequirements`, `ScheduleDefinition`, `ScheduledWorker` |
506
- | `@shivaedev/jobs/server/service.ts` | `makePgBoss`; `PgBossDefinition`, `PgBossLayerOptions`, `PgBossService` |
507
- | `@shivaedev/jobs/server/schema.ts` | `installPgBossSchema`, `pgBossSchema`; `PgBossSchemaOptions` |
508
- | `@shivaedev/jobs/server/health.ts` | `deadLetterQueueName`; `DeadLetteredJob`, `JobPage`, `JobPageOptions`, `JobsHealth`, `ListedJob`, `QueueCounts`, `QueueHealth` |
509
- | `@shivaedev/jobs/server/error.ts` | `PgBossError`, `PgBossPayloadError`, `PgBossQueueOptionsError`, `PgBossClientOptionsError`, `PgBossTestingError`, `toPgBossError`; `PgBossOperation` |
510
- | `@shivaedev/jobs/server/client.ts` | `defaultClientFactory`; `PgBossClient`, `PgBossClientFactory` |
511
- | `@shivaedev/jobs/server/testing.ts` | `makePgBossTesting`, `testRetryPolicy`; `PgBossTesting`, `PgBossTestingOptions`, `SnapshotQueue`, `UnfinishedJob` |
506
+ | `@shivaedev/jobs/server/service.ts` | `makePgBoss`; `PgBossDefinition`, `PgBossLayerOptions`, `PgBossService` |
507
+ | `@shivaedev/jobs/server/schema.ts` | `installPgBossSchema`, `pgBossSchema`; `PgBossSchemaOptions` |
508
+ | `@shivaedev/jobs/server/health.ts` | `deadLetterQueueName`; `DeadLetteredJob`, `JobPage`, `JobPageOptions`, `JobsHealth`, `ListedJob`, `QueueCounts`, `QueueHealth` |
509
+ | `@shivaedev/jobs/server/error.ts` | `PgBossError`, `PgBossPayloadError`, `PgBossQueueOptionsError`, `PgBossClientOptionsError`, `PgBossTestingError`, `toPgBossError`; `PgBossOperation` |
510
+ | `@shivaedev/jobs/server/client.ts` | `defaultClientFactory`; `PgBossClient`, `PgBossClientFactory` |
511
+ | `@shivaedev/jobs/server/testing.ts` | `makePgBossTesting`, `testRetryPolicy`; `PgBossTesting`, `PgBossTestingOptions`, `SnapshotQueue`, `UnfinishedJob` |
512
512
 
513
513
  The definition options keep the pg-boss names: `queue` uses `QueueOptions` (`Queue` except `name` and `deadLetter`, with literal `QueuePolicy` values and `maxDeferrals`), `worker` uses `WorkOptions`, and a schedule's `schedule` uses `ScheduleOptions`. A queue also requires `name` and `schema`; a schedule requires `name` and `cron`.
514
514
 
@@ -523,11 +523,11 @@ Worker registration always requests `includeMetadata: true`, including when `wor
523
523
  ### Install, setup and limits
524
524
 
525
525
  ```sh
526
- pnpm add @shivaedev/jobs effect@4.0.5 pg-boss@12.37.0
526
+ pnpm add @shivaedev/jobs effect pg-boss
527
527
  ```
528
528
 
529
529
  The package requires Node.js 24 or later and PostgreSQL. `effect` and `pg-boss` are peers; use versions that satisfy the package's published peer ranges.
530
530
 
531
- `connectionString` configures pg-boss's own `pg` Pool, separately from the application's Effect SQL pool. In the default configuration a URL without `sslmode` uses plaintext. Outside a private network, add `sslmode=verify-full` (or `require`) to require TLS. The installed `pg` 8.23 driver verifies certificates for both modes and refuses servers without TLS. For private CAs, start Node with `NODE_EXTRA_CA_CERTS=/path/to/ca.pem`. See the [framework database connection security guide](https://github.com/ShivaeDev/platform/blob/main/docs/framework/quickstart.md#database-connection-security) for all three connection paths and the driver's differences from libpq.
531
+ `connectionString` configures pg-boss's own `pg` Pool, separately from the application's Effect SQL pool, and pg-boss's driver decides how its `sslmode` behaves. Set the TLS mode in that URL; the [framework database connection security guide](https://github.com/ShivaeDev/platform/blob/main/docs/framework/quickstart.md#database-connection-security) compares the drivers and the application's connection paths.
532
532
 
533
533
  Provide the database connection and job registrations at the application runtime boundary. Application services own the domain work and provider calls; pg-boss owns queue execution. When `SqlClient` is provided and a SQL transaction is active, `enqueue` uses pg-boss’s per-call `db` option on that transaction’s connection. The application write and queued jobs commit or roll back together. The jobs client and SQL client must use the same PostgreSQL database. Outside a transaction, enqueueing keeps using the jobs client as usual. To keep enqueueing independent of an application transaction, move it after the transaction returns and handle its failure separately.
@@ -1 +1 @@
1
- {"version":3,"file":"listJobs.js","sourceRoot":"","sources":["../../../src/server/internal/listJobs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"listJobs.js","sourceRoot":"","sources":["../../../src/server/internal/listJobs.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,9 @@
1
- import { Effect } from "effect";
2
- import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
1
+ import { Effect, Schema } from "effect";
2
+ import type { JobPayloadSchema } from "#definition.ts";
3
3
  import { PgBossPayloadError } from "#error.ts";
4
4
  export declare function quotedSchema(schema: string): string;
5
- export declare function decodeStoredData<const TName extends string, const TPayload extends JobPayloadSchema>(queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">, data: unknown): Effect.Effect<TPayload["Type"], PgBossPayloadError, TPayload["DecodingServices"]>;
5
+ export declare function decodeStoredData<const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(queue: {
6
+ readonly name: TName;
7
+ readonly schema: TPayload;
8
+ }, data: unknown): Effect.Effect<TPayload["Type"], PgBossPayloadError, TPayload["DecodingServices"]>;
6
9
  //# sourceMappingURL=storedRows.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storedRows.d.ts","sourceRoot":"","sources":["../../../src/server/internal/storedRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAoB,MAAM,QAAQ,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAG/C,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,KAAK,CAAC,QAAQ,SAAS,gBAAgB,EACnG,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,EAChE,IAAI,EAAE,OAAO,GACX,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAInF"}
1
+ {"version":3,"file":"storedRows.d.ts","sourceRoot":"","sources":["../../../src/server/internal/storedRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAG/C,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,KAAK,CAAC,QAAQ,SAAS,gBAAgB,GAAG,OAAO,MAAM,CAAC,IAAI,EACxH,KAAK,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,EAC1D,IAAI,EAAE,OAAO,GACX,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAInF"}
@@ -1 +1 @@
1
- {"version":3,"file":"storedRows.js","sourceRoot":"","sources":["../../../src/server/internal/storedRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,UAAU,YAAY,CAAC,MAAc;IAC1C,OAAO,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC/B,KAAgE,EAChE,IAAa;IAEb,OAAO,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CACpE,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAC9H,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"storedRows.js","sourceRoot":"","sources":["../../../src/server/internal/storedRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,UAAU,YAAY,CAAC,MAAc;IAC1C,OAAO,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC/B,KAA0D,EAC1D,IAAa;IAEb,OAAO,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CACpE,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAC9H,CAAC;AACH,CAAC"}
@@ -6,12 +6,21 @@ import type { PgBossClientOptionsError, PgBossError, PgBossPayloadError, PgBossQ
6
6
  import type { DeadLetteredJob, JobPage, JobPageOptions, JobsHealth, ListedJob, QueueCounts } from "#health.ts";
7
7
  export interface PgBossService {
8
8
  readonly counts: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<QueueCounts, PgBossError>;
9
- readonly deadLetteredJobs: <const TName extends string, const TPayload extends JobPayloadSchema>(queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">, options: JobPageOptions) => Effect.Effect<JobPage<DeadLetteredJob<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
9
+ readonly deadLetteredJobs: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(queue: {
10
+ readonly name: TName;
11
+ readonly schema: TPayload;
12
+ }, options: JobPageOptions) => Effect.Effect<JobPage<DeadLetteredJob<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
10
13
  readonly enqueue: <const TName extends string, const TPayload extends JobPayloadSchema, const TQueue extends QueueDefinition<TName, TPayload>>(queue: QueueDefinition<TName, TPayload> & TQueue, payload: NoInfer<Schema.Schema.Type<TPayload>>, options?: NoInfer<TQueue["key"] extends undefined ? SendOptions : Omit<SendOptions, "singletonKey"> & {
11
14
  readonly singletonKey?: never;
12
15
  }>) => Effect.Effect<Option.Option<string>, PgBossError | PgBossPayloadError, TPayload["EncodingServices"]>;
13
- readonly failedJobs: <const TName extends string, const TPayload extends JobPayloadSchema>(queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">, options: JobPageOptions) => Effect.Effect<JobPage<ListedJob<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
14
- readonly getJob: <const TName extends string, const TPayload extends JobPayloadSchema>(queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">, id: string) => Effect.Effect<Option.Option<JobWithMetadata<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
16
+ readonly failedJobs: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(queue: {
17
+ readonly name: TName;
18
+ readonly schema: TPayload;
19
+ }, options: JobPageOptions) => Effect.Effect<JobPage<ListedJob<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
20
+ readonly getJob: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(queue: {
21
+ readonly name: TName;
22
+ readonly schema: TPayload;
23
+ }, id: string) => Effect.Effect<Option.Option<JobWithMetadata<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
15
24
  readonly health: Effect.Effect<JobsHealth, PgBossError>;
16
25
  readonly retry: (queue: Pick<QueueDefinition, "name">, id: string) => Effect.Effect<void, PgBossError>;
17
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/jobs",
3
- "version": "0.21.0",
3
+ "version": "0.22.1",
4
4
  "description": "Effect-native jobs and lifecycle management for pg-boss",
5
5
  "keywords": [
6
6
  "effect"
@@ -44,21 +44,21 @@
44
44
  "README.md"
45
45
  ],
46
46
  "dependencies": {
47
- "@shivaedev/sql": "0.23.0"
47
+ "@shivaedev/sql": "0.25.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@shivaedev/quality": "0.42.0",
51
- "@shivaedev/test": "0.10.0",
52
- "@shivaedev/test-sql": "0.10.1",
53
- "@shivaedev/test-story": "0.21.1",
50
+ "@shivaedev/quality": "0.45.0",
51
+ "@shivaedev/test": "0.10.1",
52
+ "@shivaedev/test-sql": "0.11.0",
53
+ "@shivaedev/test-story": "0.24.0",
54
54
  "@types/node": "24.19.2",
55
- "effect": "4.0.5",
55
+ "effect": "4.0.6",
56
56
  "pg-boss": "12.38.0",
57
57
  "typescript": "7.0.2",
58
58
  "vitest": "5.0.5"
59
59
  },
60
60
  "peerDependencies": {
61
- "effect": "4.0.5",
61
+ "effect": "4.0.6",
62
62
  "pg-boss": "12.38.0"
63
63
  },
64
64
  "engines": {
@@ -1,6 +1,6 @@
1
1
  import { Effect, Option, Schema } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
- import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
3
+ import type { JobPayloadSchema } from "#definition.ts";
4
4
  import { type PgBossError, type PgBossPayloadError, toPgBossError } from "#error.ts";
5
5
  import { type DeadLetteredJob, deadLetterQueueName, type JobPage, type JobPageOptions } from "#health.ts";
6
6
  import { decodeStoredData, quotedSchema } from "#internal/storedRows.ts";
@@ -39,11 +39,11 @@ export function deadLetteredJobsFor(client: PgBossClient, schema: string): PgBos
39
39
  return (queue, options) => listJobs(client, schema, "deadLetteredJobs", queue, options);
40
40
  }
41
41
 
42
- function listJobs<const TName extends string, const TPayload extends JobPayloadSchema>(
42
+ function listJobs<const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
43
43
  client: PgBossClient,
44
44
  schema: string,
45
45
  listing: Listing,
46
- queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">,
46
+ queue: { readonly name: TName; readonly schema: TPayload },
47
47
  options: JobPageOptions,
48
48
  ): Effect.Effect<JobPage<DeadLetteredJob<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]> {
49
49
  return Effect.tryPromise({
@@ -1,5 +1,5 @@
1
1
  import { Effect, Redacted, Schema } from "effect";
2
- import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
2
+ import type { JobPayloadSchema } from "#definition.ts";
3
3
  import { PgBossPayloadError } from "#error.ts";
4
4
  import { payloadOf } from "#internal/tracing.ts";
5
5
 
@@ -7,8 +7,8 @@ export function quotedSchema(schema: string): string {
7
7
  return `"${schema.replaceAll('"', '""')}"`;
8
8
  }
9
9
 
10
- export function decodeStoredData<const TName extends string, const TPayload extends JobPayloadSchema>(
11
- queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">,
10
+ export function decodeStoredData<const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
11
+ queue: { readonly name: TName; readonly schema: TPayload },
12
12
  data: unknown,
13
13
  ): Effect.Effect<TPayload["Type"], PgBossPayloadError, TPayload["DecodingServices"]> {
14
14
  return Schema.decodeUnknownEffect(queue.schema)(payloadOf(data)).pipe(
@@ -12,8 +12,8 @@ import { registerReleasedJobs } from "#internal/registerReleasedJobs.ts";
12
12
 
13
13
  export interface PgBossService {
14
14
  readonly counts: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<QueueCounts, PgBossError>;
15
- readonly deadLetteredJobs: <const TName extends string, const TPayload extends JobPayloadSchema>(
16
- queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">,
15
+ readonly deadLetteredJobs: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
16
+ queue: { readonly name: TName; readonly schema: TPayload },
17
17
  options: JobPageOptions,
18
18
  ) => Effect.Effect<JobPage<DeadLetteredJob<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
19
19
  readonly enqueue: <const TName extends string, const TPayload extends JobPayloadSchema, const TQueue extends QueueDefinition<TName, TPayload>>(
@@ -21,12 +21,12 @@ export interface PgBossService {
21
21
  payload: NoInfer<Schema.Schema.Type<TPayload>>,
22
22
  options?: NoInfer<TQueue["key"] extends undefined ? SendOptions : Omit<SendOptions, "singletonKey"> & { readonly singletonKey?: never }>,
23
23
  ) => Effect.Effect<Option.Option<string>, PgBossError | PgBossPayloadError, TPayload["EncodingServices"]>;
24
- readonly failedJobs: <const TName extends string, const TPayload extends JobPayloadSchema>(
25
- queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">,
24
+ readonly failedJobs: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
25
+ queue: { readonly name: TName; readonly schema: TPayload },
26
26
  options: JobPageOptions,
27
27
  ) => Effect.Effect<JobPage<ListedJob<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
28
- readonly getJob: <const TName extends string, const TPayload extends JobPayloadSchema>(
29
- queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">,
28
+ readonly getJob: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
29
+ queue: { readonly name: TName; readonly schema: TPayload },
30
30
  id: string,
31
31
  ) => Effect.Effect<Option.Option<JobWithMetadata<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
32
32
  readonly health: Effect.Effect<JobsHealth, PgBossError>;