nuxt-cf-jobs 0.14.2 → 0.14.3

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/README.md CHANGED
@@ -221,7 +221,7 @@ const route = getJobDefinition(name)
221
221
  const fullDefinition = await loadJobDefinition(name)
222
222
  ```
223
223
 
224
- `getJobDefinition()` reads static routing metadata without loading the handler module. Use `loadJobDefinition()` when you need the full definition. Jobs with `broadcast` also generate `JobBroadcastMessage<Name>` and `JobBroadcastEnvelope<Name>` types.
224
+ `getJobDefinition()` returns static routing and literal policy metadata without loading the job module. It does not include executable fields such as `handle`, `input`, or `uniqueId`. Use `loadJobDefinition()` when you need the full definition. The durable `prepareJob()` helper does this automatically. Jobs with `broadcast` also generate `JobBroadcastMessage<Name>` and `JobBroadcastEnvelope<Name>` types.
225
225
 
226
226
  Runtime validation is available when you want to fail a custom startup check:
227
227
 
@@ -357,7 +357,7 @@ export default defineEventHandler(async (event) => {
357
357
  - `not-dispatched`: the row is safe in D1, but the queue binding was unavailable.
358
358
  - `dispatch-failed`: the row is safe in D1, and `cause` contains the send error.
359
359
 
360
- The generated `prepareJob()` validates the payload, resolves the queue, applies attempts and uniqueness, and checks the Cloudflare message size before inserting anything.
360
+ The generated `prepareJob()` loads the full job definition, validates the payload, resolves the queue, applies attempts and uniqueness, and checks the serialized payload against the durable D1 storage limit before inserting anything.
361
361
 
362
362
  ### Recovery
363
363
 
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-cf-jobs",
3
3
  "configKey": "cfJobs",
4
- "version": "0.14.2",
4
+ "version": "0.14.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -59,7 +59,7 @@ export const jobErrors = {
59
59
  task,
60
60
  bytes,
61
61
  limit,
62
- message: `Job payload exceeds Cloudflare Queue limit of ${limit} bytes for task: ${task}`
62
+ message: `Job payload exceeds durable storage limit of ${limit} bytes for task: ${task}`
63
63
  };
64
64
  },
65
65
  noRoute(task) {
@@ -3,6 +3,14 @@ import type { SendBackpressureOptions } from './queue.js';
3
3
  import type { AnyJobDefinition, JobNameOf, JobPayloadByName, JobQueueByName } from './registry.js';
4
4
  import type { Result } from './result.js';
5
5
  import type { DispatchableJob, DispatchResult, JobContext, JobControlResult, JobDefinition, JobHandler, QueueMessage, QueueSendOptions } from './types.js';
6
+ /**
7
+ * Maximum serialized durable payload size.
8
+ *
9
+ * Durable payloads live in D1. Queue messages only carry `{ jobId, queue }`, so
10
+ * the Cloudflare Queue message limit does not apply here. This leaves 100,000
11
+ * bytes below D1's 2,000,000-byte row limit for storage overhead.
12
+ */
13
+ export declare const DURABLE_JOB_MAX_PAYLOAD_BYTES = 1900000;
6
14
  export interface DurableJobRoute<Queue extends string = string> {
7
15
  queue: Queue;
8
16
  jobType: string;
@@ -77,8 +85,13 @@ export interface DurableJobFailureRepository {
77
85
  recordFailure: (input: RecordDurableJobFailureInput) => Promise<void>;
78
86
  }
79
87
  export interface DurableJobRegistryLike<Env = unknown, Db = unknown, Logger = unknown> {
80
- /** May resolve asynchronously for lazily-loaded jobs. Unused on the producer path. */
88
+ /** May resolve asynchronously for lazily-loaded jobs. */
81
89
  getHandler?: (name: string) => JobHandler<unknown, Env, Db, Logger> | undefined | Promise<JobHandler<unknown, Env, Db, Logger> | undefined>;
90
+ /**
91
+ * Loads the full definition when producer policy depends on executable fields
92
+ * such as `input` or `uniqueId`.
93
+ */
94
+ loadJobDefinition?: (name: string) => Promise<JobDefinition<string, unknown, string, Env, Db, Logger> | undefined>;
82
95
  getJobDefinition?: (name: string) => JobDefinition<string, unknown, string, Env, Db, Logger> | undefined;
83
96
  getJobRoute?: (name: string) => DurableJobRoute<string> | undefined;
84
97
  }
@@ -2,12 +2,13 @@ import { dispatchRegisteredJob } from "./dispatch.js";
2
2
  import { describeCause, describeCauseWithStack, formatJobError, isDurableJobOwnershipError, jobErrors, jobErrorToException } from "./errors.js";
3
3
  import { buildJobPayload } from "./payload.js";
4
4
  import { createJobTraceId, createJobUniqueKey, resolveJobMaxAttempts } from "./policy.js";
5
- import { CF_QUEUE_MAX_MESSAGE_BYTES, sendBatchChunked, withSendBackpressure } from "./queue.js";
5
+ import { sendBatchChunked, withSendBackpressure } from "./queue.js";
6
6
  import { parseJobInput } from "./registry.js";
7
7
  import { err, ok, unwrapResult } from "./result.js";
8
8
  function byteLength(value) {
9
9
  return typeof Buffer !== "undefined" ? Buffer.byteLength(value, "utf8") : new TextEncoder().encode(value).byteLength;
10
10
  }
11
+ export const DURABLE_JOB_MAX_PAYLOAD_BYTES = 19e5;
11
12
  export async function pruneDurableJobs(repository, opts) {
12
13
  const completedJobs = typeof opts.completedBefore === "number" ? await repository.pruneCompletedJobs({ before: opts.completedBefore, limit: opts.limit }) : 0;
13
14
  const failedJobs = typeof opts.failedBefore === "number" ? await repository.pruneFailedJobs({ before: opts.failedBefore, limit: opts.limit }) : 0;
@@ -31,8 +32,8 @@ export async function prepareDurableJobResult(opts) {
31
32
  const payload = buildJobPayload(opts.name, parsedPayload.data);
32
33
  const serialized = JSON.stringify(continuations ? { ...payload, _continuations: continuations } : payload);
33
34
  const bytes = byteLength(serialized);
34
- if (bytes > CF_QUEUE_MAX_MESSAGE_BYTES)
35
- return err(jobErrors.payloadTooLarge(opts.name, bytes, CF_QUEUE_MAX_MESSAGE_BYTES));
35
+ if (bytes > DURABLE_JOB_MAX_PAYLOAD_BYTES)
36
+ return err(jobErrors.payloadTooLarge(opts.name, bytes, DURABLE_JOB_MAX_PAYLOAD_BYTES));
36
37
  return ok({
37
38
  id: opts.id ?? crypto.randomUUID(),
38
39
  queue: route.queue,
@@ -54,9 +55,11 @@ export async function prepareDurableJob(opts) {
54
55
  return unwrapResult(await prepareDurableJobResult(opts), jobErrorToException);
55
56
  }
56
57
  export async function prepareRegisteredDurableJob(registry, opts) {
58
+ const definition = registry.loadJobDefinition ? await registry.loadJobDefinition(opts.name) : registry.getJobDefinition?.(opts.name);
57
59
  return prepareDurableJob({
58
60
  ...opts,
59
- registry
61
+ registry,
62
+ definition
60
63
  });
61
64
  }
62
65
  function resolveDurableJobRoute(name, route, definition, registry) {
@@ -28,10 +28,9 @@ interface DefineJobBaseOptions<Name extends string, Payload extends object, Queu
28
28
  * A build-time registry entry that defers loading the handler module. The
29
29
  * static routing fields are AST-extracted from the job's `defineJob({...})`
30
30
  * call so the producer/consumer can route, validate queues and resolve attempts
31
- * WITHOUT importing (and evaluating) the handler `load()` pulls the full
32
- * definition only when a handler/`input`/`failed` is actually needed (dispatch,
33
- * or a producer of a job that declares `input`/`unique`). This is what keeps a
34
- * worker from evaluating all job modules to run one job.
31
+ * WITHOUT importing (and evaluating) the handler. `load()` pulls the full
32
+ * definition for dispatch and durable producer preparation. This keeps a worker
33
+ * from evaluating every job module to run or prepare one job.
35
34
  */
36
35
  export interface LazyJobEntry<Name extends string = string, Queue extends string = string> {
37
36
  name: Name;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-cf-jobs",
3
3
  "type": "module",
4
- "version": "0.14.2",
4
+ "version": "0.14.3",
5
5
  "description": "Nuxt module for typed Cloudflare queue jobs.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",