@lunora/queue 1.0.0-alpha.67 → 1.0.0-alpha.69

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/dist/index.d.mts CHANGED
@@ -181,6 +181,13 @@ interface QueueBindingSpec {
181
181
  }
182
182
  /** One declared queue, keyed for batch routing by its stable wrangler name. */
183
183
  interface QueueRegistryEntry {
184
+ /**
185
+ * The queue's own producer binding on `env` (`QUEUE_*`). A message whose
186
+ * dispatch is declined on its last delivery is re-enqueued through it (see
187
+ * {@link resolveDeclinedBatch}); without it that message is dead-lettered or
188
+ * dropped, and logged. Codegen always emits it.
189
+ */
190
+ binding?: string;
184
191
  /**
185
192
  * The `defineQueue` result (carries the push handler). The body type is
186
193
  * erased to `any` here because the registry is heterogeneous — different
@@ -220,12 +227,15 @@ interface CapturedQueueMessage {
220
227
  * true of the deployed broker only as far as Lunora's binding reconcile (run
221
228
  * by `lunora dev`, `deploy` and `prepare`) keeps the two in step: it writes
222
229
  * every declared tuning field onto the consumer, including onto one that
223
- * already exists. It does NOT remove a field taken out of `defineQueue` —
224
- * dropping `deadLetterQueue` leaves the deployed DLQ in place, so this then
225
- * reads `false` for messages that were in fact dead-lettered — and it never
226
- * writes wrangler's `env.<name>` blocks, so a `--env` deploy uses whatever
227
- * that block says. A bare `wrangler deploy` over a hand-edited consumer can
228
- * disagree too, and nothing on this side can see any of it.
230
+ * already exists, and takes a field back out once `defineQueue` drops it
231
+ * (it records what `defineQueue` declared in `package.json`
232
+ * `lunora.queueTuning`). The gaps that remain: a field changed by hand to
233
+ * another value than the declared one is
234
+ * kept when the declaration drops it, so a hand-set DLQ still reads
235
+ * `false` here; a `--env` deploy retunes the `env.<name>` consumers but
236
+ * never writes their `dead_letter_queue`, which that block names itself;
237
+ * and a bare `wrangler deploy` over a hand-edited consumer can disagree
238
+ * too. Nothing on this side can see any of it.
229
239
  */
230
240
  deadLettered: boolean;
231
241
  /** Handler error message when `outcome` is `error`; absent otherwise. */
package/dist/index.d.ts CHANGED
@@ -181,6 +181,13 @@ interface QueueBindingSpec {
181
181
  }
182
182
  /** One declared queue, keyed for batch routing by its stable wrangler name. */
183
183
  interface QueueRegistryEntry {
184
+ /**
185
+ * The queue's own producer binding on `env` (`QUEUE_*`). A message whose
186
+ * dispatch is declined on its last delivery is re-enqueued through it (see
187
+ * {@link resolveDeclinedBatch}); without it that message is dead-lettered or
188
+ * dropped, and logged. Codegen always emits it.
189
+ */
190
+ binding?: string;
184
191
  /**
185
192
  * The `defineQueue` result (carries the push handler). The body type is
186
193
  * erased to `any` here because the registry is heterogeneous — different
@@ -220,12 +227,15 @@ interface CapturedQueueMessage {
220
227
  * true of the deployed broker only as far as Lunora's binding reconcile (run
221
228
  * by `lunora dev`, `deploy` and `prepare`) keeps the two in step: it writes
222
229
  * every declared tuning field onto the consumer, including onto one that
223
- * already exists. It does NOT remove a field taken out of `defineQueue` —
224
- * dropping `deadLetterQueue` leaves the deployed DLQ in place, so this then
225
- * reads `false` for messages that were in fact dead-lettered — and it never
226
- * writes wrangler's `env.<name>` blocks, so a `--env` deploy uses whatever
227
- * that block says. A bare `wrangler deploy` over a hand-edited consumer can
228
- * disagree too, and nothing on this side can see any of it.
230
+ * already exists, and takes a field back out once `defineQueue` drops it
231
+ * (it records what `defineQueue` declared in `package.json`
232
+ * `lunora.queueTuning`). The gaps that remain: a field changed by hand to
233
+ * another value than the declared one is
234
+ * kept when the declaration drops it, so a hand-set DLQ still reads
235
+ * `false` here; a `--env` deploy retunes the `env.<name>` consumers but
236
+ * never writes their `dead_letter_queue`, which that block names itself;
237
+ * and a bare `wrangler deploy` over a hand-edited consumer can disagree
238
+ * too. Nothing on this side can see any of it.
229
239
  */
230
240
  deadLettered: boolean;
231
241
  /** Handler error message when `outcome` is `error`; absent otherwise. */
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createQueueCaptureSink as t,shouldCaptureQueue as r}from"./packem_shared/createQueueCaptureSink-CSOPftvj.mjs";import{createQueueContext as a}from"./packem_shared/createQueueContext-BszRoc-a.mjs";import{default as i}from"./packem_shared/createQueues-CMitFS1K.mjs";import{defineQueue as p,isQueueDefinition as m,queueBindingName as x,queueDefaultName as Q}from"./packem_shared/defineQueue-TY4-i3nG.mjs";import{dispatchQueueBatch as s}from"./packem_shared/dispatchQueueBatch-CgThRuXz.mjs";import{c as C}from"./packem_shared/run-context-DbF7bpEy.mjs";export{t as createQueueCaptureSink,a as createQueueContext,C as createQueueRunContext,i as createQueues,p as defineQueue,s as dispatchQueueBatch,m as isQueueDefinition,x as queueBindingName,Q as queueDefaultName,r as shouldCaptureQueue};
1
+ import{createQueueCaptureSink as t,shouldCaptureQueue as r}from"./packem_shared/createQueueCaptureSink-CSOPftvj.mjs";import{createQueueContext as a}from"./packem_shared/createQueueContext-CZ3ZpUFb.mjs";import{default as i}from"./packem_shared/createQueues-BVwkHkeb.mjs";import{defineQueue as p,isQueueDefinition as m,queueBindingName as x,queueDefaultName as Q}from"./packem_shared/defineQueue-TY4-i3nG.mjs";import{dispatchQueueBatch as s}from"./packem_shared/dispatchQueueBatch-B8GbPNBs.mjs";import{c as C}from"./packem_shared/run-context-wO-J6k6F.mjs";export{t as createQueueCaptureSink,a as createQueueContext,C as createQueueRunContext,i as createQueues,p as defineQueue,s as dispatchQueueBatch,m as isQueueDefinition,x as queueBindingName,Q as queueDefaultName,r as shouldCaptureQueue};
@@ -1 +1 @@
1
- import i from"./createQueues-CMitFS1K.mjs";const s=(o,c)=>{const n={};for(const t of c){const e=o[t.binding];e&&typeof e.send=="function"&&typeof e.sendBatch=="function"&&(n[t.exportName]=e)}return i({bindings:n})};export{s as createQueueContext};
1
+ import i from"./createQueues-BVwkHkeb.mjs";const s=(o,c)=>{const n={};for(const t of c){const e=o[t.binding];e&&typeof e.send=="function"&&typeof e.sendBatch=="function"&&(n[t.exportName]=e)}return i({bindings:n})};export{s as createQueueContext};
@@ -0,0 +1 @@
1
+ import{c as o}from"./run-context-wO-J6k6F.mjs";export{o as createQueueRunContext};
@@ -0,0 +1 @@
1
+ import{LunoraError as u}from"@lunora/errors";import{h as g,R as f}from"./requeue-envelope-BjL4JftH.mjs";const i=100,l=43200,c=(e,n)=>{if(e!==void 0&&e>l)throw new u("VALIDATION_ERROR",`@lunora/queue: ${n} delaySeconds is ${String(e)}, over the Cloudflare Queues ceiling of ${String(l)} (12 hours) — use @lunora/scheduler for longer schedules`)},h=(e,n)=>{if(g(e))throw new u("VALIDATION_ERROR",`@lunora/queue: ${n} body may not contain the reserved key "${f}"`)},w=e=>({send:async(n,s)=>{c(s?.delaySeconds,"send"),h(n,"send"),await e.send(n,s)},sendBatch:async(n,s)=>{c(s?.delaySeconds,"sendBatch");const o=[...n];if(o.length>i)throw new u("VALIDATION_ERROR",`@lunora/queue: sendBatch exceeds ${String(i)} (got ${String(o.length)}) — split across calls`);for(const[a,r]of o.entries())c(r.delaySeconds,`sendBatch message ${String(a)}`),h(r.body,`sendBatch message ${String(a)}`);await e.sendBatch(o,s)}}),m=e=>{const n=e.bindings??{},s=Object.create(null);for(const[r,t]of Object.entries(n))s[r]=w(t);const o=Object.keys(s),a=r=>{const t=o.length===0?"no queues are declared":`known queues: ${o.join(", ")}`,d=()=>Promise.reject(new Error(`@lunora/queue: no queue named "${r}" (${t})`));return{send:d,sendBatch:d}};return new Proxy(s,{get(r,t){if(typeof t=="string")return Object.hasOwn(r,t)?r[t]:a(t)}})};export{m as default};
@@ -0,0 +1 @@
1
+ import{c as h,u as x,f as N,a as q,d as k,o as R}from"./run-context-wO-J6k6F.mjs";import{LunoraError as $,toErrorBody as M}from"@lunora/errors";import{s as A,o as I}from"./requeue-envelope-BjL4JftH.mjs";const b=e=>typeof e.definition.maxRetries=="number"?e.definition.maxRetries:R,O=e=>{if(e instanceof Date)return e.getTime();const t=typeof e=="number"?e:Number(e);return Number.isFinite(t)?t:0},T=async(e,t)=>{const o=await I(t,e.body).catch(()=>{});return o===void 0?{body:e.body,id:e.id,requeued:!1}:{...o,requeued:!0}},g=e=>{const t=e.LUNORA_ADMIN_TOKEN;return typeof t=="string"&&t.length>0?t:void 0},B=(e,t)=>{let o=0;return(i,n,r)=>(o+=1,e(i,n,{...r,dedupId:`${t}#${String(o)}`,messageId:t}))},L=(e,t,o,i)=>{const n=B(i,t.id);return new Proxy(e,{get:(r,s)=>s==="id"?t.id:s==="body"?t.body:s==="ack"?()=>{o.set(r,"ack"),r.ack()}:s==="retry"?f=>{o.set(r,"retry"),r.retry(f)}:s==="run"?n:Reflect.get(r,s,r)})},S=(e,t,o)=>new Proxy(e,{get:(i,n)=>n==="ackAll"?()=>{o("ack"),i.ackAll()}:n==="retryAll"?r=>{o("retry"),i.retryAll(r)}:n==="messages"?t:Reflect.get(i,n,i)}),j=async(e,t,o)=>{const i=new Map,n=e.messages,r=new Map,s=[];for(const c of n){const u=await T(c,o);r.set(c,u),s.push(L(c,u,i,t))}const l=S(e,s,c=>{for(const u of n)i.has(u)||i.set(u,c)});return{dispositions:i,originals:n,requeued:new Set,views:r,wrappedBatch:l}},w=(e,t)=>e.views.get(t)??{body:t.body,id:t.id,requeued:!1},v=(e,t)=>w(e,t).id,Q=e=>{if(e instanceof Error)return e.message;if(typeof e=="string")return e;if(e!==null&&typeof e=="object")try{return JSON.stringify(e)}catch{return"[unserializable thrown value]"}return String(e)},D=(e,t,o,i,n,r)=>{const s=i?Q(n):void 0,f=b(t),l=i?"error":"ack",c=typeof t.definition.deadLetterQueue=="string"&&t.definition.deadLetterQueue.length>0;return e.originals.map(u=>{const d=u===r,a=e.dispositions.get(u),p=d?"error":a??l,m=typeof u.attempts=="number"?u.attempts:1,y=w(e,u);return{attempts:m,body:y.body,deadLettered:c&&!d&&!e.requeued.has(u)&&p!=="ack"&&m>f,error:p==="error"?s:void 0,exportName:t.exportName,messageId:y.id,outcome:p,queue:o,timestamp:O(u.timestamp)}})},C=(e,t,o)=>{if(!t||!N(o))return;const i=q(o);if(i===void 0)return;const n=e.originals.find(r=>v(e,r)===i);if(!(n===void 0||e.dispositions.has(n)))return n},P=(e,t)=>{t.ack();for(const o of e.originals)o!==t&&!e.dispositions.has(o)&&(e.dispositions.set(o,"retry"),o.retry())},F=async(e,t,o,i,n)=>{const r=g(n),s=q(t),f=e.originals.find(d=>v(e,d)===s&&!e.dispositions.has(d)),l=`@lunora/queue: queue "${i}" (${o.exportName})`,c=o.binding===void 0?void 0:n[o.binding],u=[];for(const d of e.originals)if(!e.dispositions.has(d)){if(e.dispositions.set(d,"retry"),f!==void 0&&d!==f){d.retry();continue}u.push(d)}await Promise.all(u.map(async d=>{const a=w(e,d),p=typeof c?.send!="function"||a.requeued||r===void 0?void 0:async m=>{await c.send(await A(r,a.id,a.body),{contentType:"json",delaySeconds:m})};await k(d,{maxRetries:b(o),requeue:p,where:l})==="requeued"&&e.requeued.add(d)}))},E=async(e,t,o)=>{const i=Object.hasOwn(t,e.queue)?t[e.queue]:void 0;if(i===void 0){const a=Object.keys(t),p=a.length===0?"no push queues are declared":`known push queues: ${a.join(", ")}`;throw new $("INTERNAL",`@lunora/queue: received a batch for queue "${e.queue}" but no push handler is registered (${p})`)}const{handler:n}=i.definition;if(typeof n!="function")throw new TypeError(`@lunora/queue: queue "${e.queue}" (${i.exportName}) has no push handler — it is declared as a pull consumer`);const r=h({env:o.env,exportName:i.exportName,fetchImpl:o.fetchImpl,...o.traceparent===void 0?{}:{traceparent:o.traceparent}}),s=await j(e,r.run,g(o.env));let f=!1,l;try{await n(r,s.wrappedBatch)}catch(a){f=!0,l=a}const c=C(s,f,l);if(c!==void 0){P(s,c);const{body:a,status:p}=M(l,{redactedMessage:"internal error"});console.error(`@lunora/queue: dropped message ${v(s,c)} on queue "${e.queue}" (${i.exportName}) — a dispatch it made failed with a deterministic ${String(p)} (${a.code}: ${a.message}), so it was acked, not retried. Its retries are NOT exhausted and it is not dead-lettered — it will never be redelivered.`)}const u=f&&x(l);u&&await F(s,l,i,e.queue,o.env);const d=f&&c===void 0&&!u;if(o.capture!==void 0)try{await o.capture(D(s,i,e.queue,f,l,c))}catch(a){console.warn("@lunora/queue: capture sink failed (delivery unaffected):",a)}if(d)throw l};export{E as dispatchQueueBatch};
@@ -0,0 +1,4 @@
1
+ const T="lunora.requeue.v1",O=new TextEncoder,j=async(r,t)=>crypto.subtle.importKey("raw",O.encode(r),{hash:"SHA-256",name:"HMAC"},!1,[t]),S=(r,t,o)=>O.encode(`${T}
2
+ ${r}
3
+ ${t}
4
+ ${o}`),U=r=>[...new Uint8Array(r)].map(t=>t.toString(16).padStart(2,"0")).join(""),$=/^[\da-f]{64}$/u,I=async(r,t,o,i)=>U(await crypto.subtle.sign("HMAC",await j(r,"sign"),S(t,o,i))),N=async(r,t,o,i,s)=>{if(typeof s!="string"||!$.test(s))return!1;const e=Uint8Array.from({length:s.length/2},(n,c)=>Number.parseInt(s.slice(c*2,c*2+2),16));return crypto.subtle.verify("HMAC",await j(r,"verify"),e,S(t,o,i))},m=r=>{let t="";for(let i=0;i<r.length;i+=32768)t+=String.fromCharCode(...r.subarray(i,i+32768));return btoa(t)},_=r=>{const t=atob(r),o=new Uint8Array(t.length);for(let i=0;i<t.length;i+=1)o[i]=t.codePointAt(i)??0;return o},a="$lunora.wire$",w=64,l=1024,g="__proto__",A={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},E={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},k=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},b=(r,t=0)=>{if(t>w)throw new RangeError(`wire-codec: value nesting exceeds the ${w}-level limit`);if(r===void 0)return[a,"undefined"];if(r===null)return null;const o=typeof r;if(o==="bigint")return[a,"bigint",r.toString()];if(o==="number"){const e=r;return Number.isNaN(e)?[a,"nan"]:e===1/0?[a,"inf"]:e===-1/0?[a,"-inf"]:e}if(o!=="object")return r;if(r instanceof Date)return[a,"date",b(r.getTime(),t+1)];if(r instanceof Error){const e=r,n={};for(const f of Object.keys(e)){if(e[f]===void 0)continue;const u=b(e[f],t+1);f===g?Object.defineProperty(n,f,{configurable:!0,enumerable:!0,value:u,writable:!0}):n[f]=u}const c=[a,"error",String(e.name),String(e.message),n];return e.cause!==void 0&&c.push(b(e.cause,t+1)),c}if(r instanceof URL)return[a,"url",r.href];if(r instanceof Map)return[a,"map",[...r.entries()].map(([e,n])=>[b(e,t+1),b(n,t+1)])];if(r instanceof Set)return[a,"set",[...r].map(e=>b(e,t+1))];if(r instanceof ArrayBuffer)return[a,"bytes",m(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,n=e.constructor.name,c=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return n==="Uint8Array"?[a,"bytes",m(c)]:[a,"bytes",m(c),n]}if(Array.isArray(r)){const e=r.map(n=>b(n,t+1));return e.length>0&&e[0]===a?[a,"arr",e]:e}if(!k(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const i=r,s={};for(const e of Object.keys(i)){const n=i[e];if(n===void 0)continue;const c=b(n,t+1);e===g?Object.defineProperty(s,e,{configurable:!0,enumerable:!0,value:c,writable:!0}):s[e]=c}return s},y=(r,t=0)=>{if(t>w)throw new RangeError(`wire-codec: value nesting exceeds the ${w}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===a)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(e=>y(e,t+1));case"bigint":{const e=r[2];if(typeof e!="string"||e.length>l||!/^-?\d+$/.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${l} digits)`);return BigInt(e)}case"date":{const e=y(r[2],t+1);if(typeof e!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(e)}case"map":{const e=r[2];return new Map(e.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[y(n[0],t+1),y(n[1],t+1)]}))}case"set":return new Set(r[2].map(e=>y(e,t+1)));case"url":{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(e)}case"error":{const e=r[2],n=r[3];if(typeof e!="string"||typeof n!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const c=(Object.hasOwn(E,e)?E[e]:void 0)??Error,f=new c(n);f.name!==e&&Object.defineProperty(f,"name",{configurable:!0,value:e,writable:!0});const u=y(r[4],t+1);if(u===null||typeof u!="object"||Array.isArray(u))throw new TypeError("wire-codec: malformed error — props must be an object");for(const d of Object.keys(u))d===g?Object.defineProperty(f,d,{configurable:!0,enumerable:!0,value:u[d],writable:!0}):f[d]=u[d];return r.length>5&&Object.defineProperty(f,"cause",{configurable:!0,value:y(r[5],t+1),writable:!0}),f}case"bytes":{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const n=_(e);if(m(n)!==e)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const c=r[3]??"Uint8Array";if(c==="ArrayBuffer")return n.buffer.byteLength===n.byteLength?n.buffer:n.slice().buffer;const f=Object.hasOwn(A,c)?A[c]:void 0;return f?new f(n.slice().buffer):n}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(e=>y(e,t+1))}return r.map(s=>y(s,t+1))}const o=r,i={};for(const s of Object.keys(o)){const e=y(o[s],t+1);s===g?Object.defineProperty(i,s,{configurable:!0,enumerable:!0,value:e,writable:!0}):i[s]=e}return i},p="$lunora.requeued$",R="queue",h=128*1024,B=r=>typeof r=="object"&&r!==null&&Object.hasOwn(r,p),P=async(r,t,o)=>{const i=JSON.stringify(b(o)),s={[p]:{body:i,id:t,mac:await I(r,R,t,i)}},e=new TextEncoder().encode(JSON.stringify(s)).byteLength;if(e>h)throw new RangeError(`the copy would be ${String(e)} bytes, over the ${String(h)}-byte queue message limit`);return s},C=async(r,t)=>{if(r===void 0||!B(t))return;const o=t[p];if(!(typeof o?.id!="string"||typeof o.body!="string")&&await N(r,R,o.id,o.body,o.mac))return{body:y(JSON.parse(o.body)),id:o.id}};export{p as R,B as h,C as o,P as s};
@@ -0,0 +1 @@
1
+ import{LunoraError as b,isLunoraError as _}from"@lunora/errors";const J=r=>({debug:(e,...o)=>{console.debug(r,e,...o)},error:(e,...o)=>{console.error(r,e,...o)},info:(e,...o)=>{console.info(r,e,...o)},warn:(e,...o)=>{console.warn(r,e,...o)}}),K=9e5,L="DISPATCH_IN_PROGRESS",F="x-lunora-dispatch-declined",H=(r,e,o)=>{if(e===void 0)return{dispose:()=>{},signal:r};const a=new AbortController,n=setTimeout(()=>{a.abort(o())},e);return{dispose:()=>{clearTimeout(n)},signal:a.signal}},A=r=>{let e="";for(let o=0;o<r.length;o+=32768)e+=String.fromCharCode(...r.subarray(o,o+32768));return btoa(e)},W=r=>{const e=atob(r),o=new Uint8Array(e.length);for(let a=0;a<e.length;a+=1)o[a]=e.codePointAt(a)??0;return o},p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",U=r=>{let e="",o=0;const a=r.length-2;for(;o<a;o+=3){const t=r[o]<<16|r[o+1]<<8|r[o+2];e+=p.charAt(t>>18&63)+p.charAt(t>>12&63)+p.charAt(t>>6&63)+p.charAt(t&63)}const n=r.length-o;if(n===1){const t=r[o]<<16;e+=p.charAt(t>>18&63)+p.charAt(t>>12&63)}else if(n===2){const t=r[o]<<16|r[o+1]<<8;e+=p.charAt(t>>18&63)+p.charAt(t>>12&63)+p.charAt(t>>6&63)}return e};new TextDecoder;const x=new TextEncoder,S="=",G=r=>{for(let e=0;e<r.length;e+=1)if(r.charCodeAt(e)>255)return!1;return!0},Q=r=>U(x.encode(JSON.stringify(r))),z=r=>!r.startsWith(S)&&G(r)?r:`${S}${U(x.encode(r))}`,u="$lunora.wire$",v=64,T=1024,E="__proto__",I={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},R={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},V=r=>{if(r===null||typeof r!="object")return!1;const e=Object.getPrototypeOf(r);return e===null||e===Object.prototype},h=(r,e=0)=>{if(e>v)throw new RangeError(`wire-codec: value nesting exceeds the ${v}-level limit`);if(r===void 0)return[u,"undefined"];if(r===null)return null;const o=typeof r;if(o==="bigint")return[u,"bigint",r.toString()];if(o==="number"){const t=r;return Number.isNaN(t)?[u,"nan"]:t===1/0?[u,"inf"]:t===-1/0?[u,"-inf"]:t}if(o!=="object")return r;if(r instanceof Date)return[u,"date",h(r.getTime(),e+1)];if(r instanceof Error){const t=r,s={};for(const c of Object.keys(t)){if(t[c]===void 0)continue;const l=h(t[c],e+1);c===E?Object.defineProperty(s,c,{configurable:!0,enumerable:!0,value:l,writable:!0}):s[c]=l}const i=[u,"error",String(t.name),String(t.message),s];return t.cause!==void 0&&i.push(h(t.cause,e+1)),i}if(r instanceof URL)return[u,"url",r.href];if(r instanceof Map)return[u,"map",[...r.entries()].map(([t,s])=>[h(t,e+1),h(s,e+1)])];if(r instanceof Set)return[u,"set",[...r].map(t=>h(t,e+1))];if(r instanceof ArrayBuffer)return[u,"bytes",A(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const t=r,s=t.constructor.name,i=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return s==="Uint8Array"?[u,"bytes",A(i)]:[u,"bytes",A(i),s]}if(Array.isArray(r)){const t=r.map(s=>h(s,e+1));return t.length>0&&t[0]===u?[u,"arr",t]:t}if(!V(r)){const t=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${t} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const a=r,n={};for(const t of Object.keys(a)){const s=a[t];if(s===void 0)continue;const i=h(s,e+1);t===E?Object.defineProperty(n,t,{configurable:!0,enumerable:!0,value:i,writable:!0}):n[t]=i}return n},f=(r,e=0)=>{if(e>v)throw new RangeError(`wire-codec: value nesting exceeds the ${v}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===u)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(n=>f(n,e+1));case"bigint":{const n=r[2];if(typeof n!="string"||n.length>T||!/^-?\d+$/.test(n))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${T} digits)`);return BigInt(n)}case"date":{const n=f(r[2],e+1);if(typeof n!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(n)}case"map":{const n=r[2];return new Map(n.map(t=>{if(!Array.isArray(t)||t.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[f(t[0],e+1),f(t[1],e+1)]}))}case"set":return new Set(r[2].map(n=>f(n,e+1)));case"url":{const n=r[2];if(typeof n!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(n)}case"error":{const n=r[2],t=r[3];if(typeof n!="string"||typeof t!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const s=(Object.hasOwn(R,n)?R[n]:void 0)??Error,i=new s(t);i.name!==n&&Object.defineProperty(i,"name",{configurable:!0,value:n,writable:!0});const c=f(r[4],e+1);if(c===null||typeof c!="object"||Array.isArray(c))throw new TypeError("wire-codec: malformed error — props must be an object");for(const l of Object.keys(c))l===E?Object.defineProperty(i,l,{configurable:!0,enumerable:!0,value:c[l],writable:!0}):i[l]=c[l];return r.length>5&&Object.defineProperty(i,"cause",{configurable:!0,value:f(r[5],e+1),writable:!0}),i}case"bytes":{const n=r[2];if(typeof n!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const t=W(n);if(A(t)!==n)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const s=r[3]??"Uint8Array";if(s==="ArrayBuffer")return t.buffer.byteLength===t.byteLength?t.buffer:t.slice().buffer;const i=Object.hasOwn(I,s)?I[s]:void 0;return i?new i(t.slice().buffer):t}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(n=>f(n,e+1))}return r.map(n=>f(n,e+1))}const o=r,a={};for(const n of Object.keys(o)){const t=f(o[n],e+1);n===E?Object.defineProperty(a,n,{configurable:!0,enumerable:!0,value:t,writable:!0}):a[n]=t}return a},X=(r,e,o)=>{try{return h(o)}catch(a){throw new TypeError(`${r}: cannot encode args for '${e}' — ${a instanceof Error?a.message:String(a)}`,a instanceof Error?{cause:a}:void 0)}},Y="/_lunora/scheduler/dispatch",Z=3e4,rr=r=>{let e=r.length;for(;e>0&&r[e-1]==="/";)e-=1;return r.slice(0,e)},P=Symbol("lunoraDispatchFailure"),D=Symbol("lunoraDispatchDecline"),k=Symbol("lunoraDispatchMessageId"),B=(r,e)=>(e!==void 0&&Object.defineProperty(r,k,{value:e}),r),er=(r,e)=>(Object.defineProperty(r,P,{value:!0}),B(r,e)),ur=r=>_(r)?r[k]:void 0,tr=(r,e,o,a)=>{const{status:n}=e;try{const t=JSON.parse(o)?.error;if(typeof t=="object"&&t!==null&&typeof t.code=="string"){const{code:s,data:i,message:c}=t,l=er(new b(s,typeof c=="string"?c:void 0,{data:i,status:n}),a);return e.headers.get(F)==="1"&&Object.defineProperty(l,D,{value:!0}),l}}catch{}return B(new b("INTERNAL",`${r}: function dispatch failed (${String(n)}): ${o}`,{status:n}),a)},nr=new Set([400,403,404,422]),or=new Set([L,"DISPATCH_UNAUTHENTICATED"]),C=r=>_(r)&&r[P]===!0,lr=r=>C(r)&&nr.has(r.status)&&!or.has(r.code),fr=r=>C(r)&&r[D]===!0,j=K/1e3,ar=3,dr=async(r,e)=>{const o=e.maxRetries??ar,a=typeof r.attempts=="number"&&r.attempts>o;let n="";if(a&&e.requeue!==void 0)try{return await e.requeue(j),r.ack(),"requeued"}catch(t){n=` Re-enqueueing a delayed copy failed (${t instanceof Error?t.message:String(t)}).`}return r.retry({delaySeconds:j}),a&&console.error(`${e.where}: message ${r.id} was declined (${L}) on its last delivery (attempt ${String(r.attempts)} of ${String(o+1)}) — its earlier delivery is still running the call.${n} It is retried anyway, but its retries are exhausted, so it will be dead-lettered if the queue has a deadLetterQueue and dropped if not. Raise max_retries so a slow call cannot exhaust it.`),"retried"},sr=(r,e,o)=>new b("INTERNAL",`${r}: function dispatch to "${e}" timed out after ${String(o)}ms`,{status:503}),ir=r=>{const{label:e}=r,o=globalThis.fetch,a=r.fetchImpl??(typeof o=="function"?o.bind(globalThis):void 0);return async(n,t,s={})=>{if(typeof a!="function")throw new TypeError(`${e}: no fetch implementation available — pass fetchImpl or run on a platform with global fetch`);const i=()=>r.argsAlreadyEncoded===!0?t??{}:X(e,n.__lunoraRef,t??{}),c=r.env.LUNORA_ORIGIN_URL;if(typeof c!="string"||c.length===0)throw new b("INTERNAL",`${e}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);const l=r.env.LUNORA_ADMIN_TOKEN;if(typeof l!="string"||l.length===0)throw new b("INTERNAL",`${e}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);const M=`${rr(c)}${Y}`,w={authorization:`Bearer ${l}`,"content-type":"application/json"};r.traceparent!==void 0&&r.traceparent.length>0&&(w.traceparent=r.traceparent),r.identity?.userId!==void 0&&(w["x-lunora-userid"]=z(r.identity.userId)),r.identity?.claims!==void 0&&(w["x-lunora-identity"]=Q(r.identity.claims));const $=s.timeoutMs??Z,O=H(void 0,$,()=>new DOMException(`dispatch timed out after ${String($)}ms`,"TimeoutError")),N=y=>{throw y instanceof Error&&y.name==="TimeoutError"?sr(e,n.__lunoraRef,$):y};let d;try{try{d=await a(M,{body:JSON.stringify({args:i(),functionPath:n.__lunoraRef,id:s.dedupId,shardKey:s.shardKey}),headers:w,method:"POST",signal:O.signal})}catch(m){return N(m)}if(!d.ok){let m;try{m=await d.text()}catch(q){return N(q)}throw tr(e,d,m,s.messageId)}let y;try{y=await d.text()}catch(m){return N(m)}if(y.length===0)return;let g;try{g=JSON.parse(y)}catch{throw new b("INTERNAL",`${e}: function dispatch returned a non-JSON body (${String(d.status)}): ${y}`,{status:d.status})}if(g===null||typeof g!="object"||Array.isArray(g)||!("result"in g))throw new b("INTERNAL",`${e}: function dispatch returned a JSON body that is not a { result } envelope (${String(d.status)}): ${y}`,{status:d.status});return f(g.result)}finally{O.dispose()}}},yr=r=>({env:r.env,log:J(`[queue:${r.exportName}]`),run:ir({env:r.env,fetchImpl:r.fetchImpl,label:"@lunora/queue",...r.traceparent===void 0?{}:{traceparent:r.traceparent}})});export{ur as a,yr as c,dr as d,lr as f,ar as o,fr as u};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/queue",
3
- "version": "1.0.0-alpha.67",
3
+ "version": "1.0.0-alpha.69",
4
4
  "description": "Cloudflare Queues for Lunora: defineQueue producers + consumers, the ctx.queues surface, and the generated queue() worker handler",
5
5
  "keywords": [
6
6
  "background-jobs",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@lunora/errors": "1.0.0-alpha.41",
48
- "@lunora/platform": "1.0.0-alpha.38"
48
+ "@lunora/platform": "1.0.0-alpha.39"
49
49
  },
50
50
  "engines": {
51
51
  "node": "^22.15.0 || >=24.11.0"
@@ -1 +0,0 @@
1
- import{c as o}from"./run-context-DbF7bpEy.mjs";export{o as createQueueRunContext};
@@ -1 +0,0 @@
1
- import{LunoraError as l}from"@lunora/errors";const d=100,i=43200,u=(n,t)=>{if(n!==void 0&&n>i)throw new l("VALIDATION_ERROR",`@lunora/queue: ${t} delaySeconds is ${String(n)}, over the Cloudflare Queues ceiling of ${String(i)} (12 hours) — use @lunora/scheduler for longer schedules`)},g=n=>({send:async(t,e)=>{u(e?.delaySeconds,"send"),await n.send(t,e)},sendBatch:async(t,e)=>{u(e?.delaySeconds,"sendBatch");const o=[...t];if(o.length>d)throw new l("VALIDATION_ERROR",`@lunora/queue: sendBatch exceeds ${String(d)} (got ${String(o.length)}) — split across calls`);for(const[c,s]of o.entries())u(s.delaySeconds,`sendBatch message ${String(c)}`);await n.sendBatch(o,e)}}),f=n=>{const t=n.bindings??{},e=Object.create(null);for(const[s,r]of Object.entries(t))e[s]=g(r);const o=Object.keys(e),c=s=>{const r=o.length===0?"no queues are declared":`known queues: ${o.join(", ")}`,a=()=>Promise.reject(new Error(`@lunora/queue: no queue named "${s}" (${r})`));return{send:a,sendBatch:a}};return new Proxy(e,{get(s,r){if(typeof r=="string")return Object.hasOwn(s,r)?s[r]:c(r)}})};export{f as default};
@@ -1 +0,0 @@
1
- import{c as v,u as x,f as y,a as w,d as q,o as g}from"./run-context-DbF7bpEy.mjs";import{LunoraError as $,toErrorBody as k}from"@lunora/errors";const h=e=>typeof e.definition.maxRetries=="number"?e.definition.maxRetries:g,N=e=>{if(e instanceof Date)return e.getTime();const r=typeof e=="number"?e:Number(e);return Number.isFinite(r)?r:0},b=(e,r)=>{let t=0;return(i,n,s)=>(t+=1,e(i,n,{...s,dedupId:`${r}#${String(t)}`,messageId:r}))},R=(e,r,t)=>{const i=b(t,e.id);return new Proxy(e,{get:(n,s)=>s==="ack"?()=>{r.set(n,"ack"),n.ack()}:s==="retry"?u=>{r.set(n,"retry"),n.retry(u)}:s==="run"?i:Reflect.get(n,s,n)})},M=(e,r,t)=>new Proxy(e,{get:(i,n)=>n==="ackAll"?()=>{t("ack"),i.ackAll()}:n==="retryAll"?s=>{t("retry"),i.retryAll(s)}:n==="messages"?r:Reflect.get(i,n,i)}),A=(e,r)=>{const t=new Map,i=e.messages,n=i.map(o=>R(o,t,r)),u=M(e,n,o=>{for(const c of i)t.has(c)||t.set(c,o)});return{dispositions:t,originals:i,wrappedBatch:u}},B=e=>{if(e instanceof Error)return e.message;if(typeof e=="string")return e;if(e!==null&&typeof e=="object")try{return JSON.stringify(e)}catch{return"[unserializable thrown value]"}return String(e)},I=(e,r,t,i,n,s)=>{const u=i?B(n):void 0,o=h(r),c=i?"error":"ack",f=typeof r.definition.deadLetterQueue=="string"&&r.definition.deadLetterQueue.length>0;return e.originals.map(d=>{const p=d===s,a=e.dispositions.get(d),l=p?"error":a??c,m=typeof d.attempts=="number"?d.attempts:1;return{attempts:m,body:d.body,deadLettered:f&&!p&&l!=="ack"&&m>o,error:l==="error"?u:void 0,exportName:r.exportName,messageId:d.id,outcome:l,queue:t,timestamp:N(d.timestamp)}})},T=(e,r,t)=>{if(!r||!y(t))return;const i=w(t);if(i===void 0)return;const n=e.originals.find(s=>s.id===i);if(!(n===void 0||e.dispositions.has(n)))return n},L=(e,r)=>{r.ack();for(const t of e.originals)t!==r&&!e.dispositions.has(t)&&(e.dispositions.set(t,"retry"),t.retry())},O=(e,r,t,i)=>{const n=w(r),s=e.originals.find(o=>o.id===n&&!e.dispositions.has(o)),u=`@lunora/queue: queue "${i}" (${t.exportName})`;for(const o of e.originals)if(!e.dispositions.has(o)){if(e.dispositions.set(o,"retry"),s!==void 0&&o!==s){o.retry();continue}q(o,{maxRetries:h(t),where:u})}},S=async(e,r,t)=>{const i=Object.hasOwn(r,e.queue)?r[e.queue]:void 0;if(i===void 0){const a=Object.keys(r),l=a.length===0?"no push queues are declared":`known push queues: ${a.join(", ")}`;throw new $("INTERNAL",`@lunora/queue: received a batch for queue "${e.queue}" but no push handler is registered (${l})`)}const{handler:n}=i.definition;if(typeof n!="function")throw new TypeError(`@lunora/queue: queue "${e.queue}" (${i.exportName}) has no push handler — it is declared as a pull consumer`);const s=v({env:t.env,exportName:i.exportName,fetchImpl:t.fetchImpl,...t.traceparent===void 0?{}:{traceparent:t.traceparent}}),u=A(e,s.run);let o=!1,c;try{await n(s,u.wrappedBatch)}catch(a){o=!0,c=a}const f=T(u,o,c);if(f!==void 0){L(u,f);const{body:a,status:l}=k(c,{redactedMessage:"internal error"});console.error(`@lunora/queue: dropped message ${f.id} on queue "${e.queue}" (${i.exportName}) — a dispatch it made failed with a deterministic ${String(l)} (${a.code}: ${a.message}), so it was acked, not retried. Its retries are NOT exhausted and it is not dead-lettered — it will never be redelivered.`)}const d=o&&x(c);d&&O(u,c,i,e.queue);const p=o&&f===void 0&&!d;if(t.capture!==void 0)try{await t.capture(I(u,i,e.queue,o,c,f))}catch(a){console.warn("@lunora/queue: capture sink failed (delivery unaffected):",a)}if(p)throw c};export{S as dispatchQueueBatch};
@@ -1 +0,0 @@
1
- import{LunoraError as b,isLunoraError as j}from"@lunora/errors";const J=r=>({debug:(t,...o)=>{console.debug(r,t,...o)},error:(t,...o)=>{console.error(r,t,...o)},info:(t,...o)=>{console.info(r,t,...o)},warn:(t,...o)=>{console.warn(r,t,...o)}}),K=9e5,_="DISPATCH_IN_PROGRESS",q="x-lunora-dispatch-declined",H=(r,t,o)=>{if(t===void 0)return{dispose:()=>{},signal:r};const a=new AbortController,n=setTimeout(()=>{a.abort(o())},t);return{dispose:()=>{clearTimeout(n)},signal:a.signal}},A=r=>{let t="";for(let o=0;o<r.length;o+=32768)t+=String.fromCharCode(...r.subarray(o,o+32768));return btoa(t)},W=r=>{const t=atob(r),o=new Uint8Array(t.length);for(let a=0;a<t.length;a+=1)o[a]=t.codePointAt(a)??0;return o},p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",L=r=>{let t="",o=0;const a=r.length-2;for(;o<a;o+=3){const e=r[o]<<16|r[o+1]<<8|r[o+2];t+=p.charAt(e>>18&63)+p.charAt(e>>12&63)+p.charAt(e>>6&63)+p.charAt(e&63)}const n=r.length-o;if(n===1){const e=r[o]<<16;t+=p.charAt(e>>18&63)+p.charAt(e>>12&63)}else if(n===2){const e=r[o]<<16|r[o+1]<<8;t+=p.charAt(e>>18&63)+p.charAt(e>>12&63)+p.charAt(e>>6&63)}return t};new TextDecoder;const U=new TextEncoder,S="=",F=r=>{for(let t=0;t<r.length;t+=1)if(r.charCodeAt(t)>255)return!1;return!0},G=r=>L(U.encode(JSON.stringify(r))),Q=r=>!r.startsWith(S)&&F(r)?r:`${S}${L(U.encode(r))}`,u="$lunora.wire$",v=64,T=1024,E="__proto__",I={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},R={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},z=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},h=(r,t=0)=>{if(t>v)throw new RangeError(`wire-codec: value nesting exceeds the ${v}-level limit`);if(r===void 0)return[u,"undefined"];if(r===null)return null;const o=typeof r;if(o==="bigint")return[u,"bigint",r.toString()];if(o==="number"){const e=r;return Number.isNaN(e)?[u,"nan"]:e===1/0?[u,"inf"]:e===-1/0?[u,"-inf"]:e}if(o!=="object")return r;if(r instanceof Date)return[u,"date",h(r.getTime(),t+1)];if(r instanceof Error){const e=r,s={};for(const c of Object.keys(e)){if(e[c]===void 0)continue;const l=h(e[c],t+1);c===E?Object.defineProperty(s,c,{configurable:!0,enumerable:!0,value:l,writable:!0}):s[c]=l}const i=[u,"error",String(e.name),String(e.message),s];return e.cause!==void 0&&i.push(h(e.cause,t+1)),i}if(r instanceof URL)return[u,"url",r.href];if(r instanceof Map)return[u,"map",[...r.entries()].map(([e,s])=>[h(e,t+1),h(s,t+1)])];if(r instanceof Set)return[u,"set",[...r].map(e=>h(e,t+1))];if(r instanceof ArrayBuffer)return[u,"bytes",A(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,s=e.constructor.name,i=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return s==="Uint8Array"?[u,"bytes",A(i)]:[u,"bytes",A(i),s]}if(Array.isArray(r)){const e=r.map(s=>h(s,t+1));return e.length>0&&e[0]===u?[u,"arr",e]:e}if(!z(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const a=r,n={};for(const e of Object.keys(a)){const s=a[e];if(s===void 0)continue;const i=h(s,t+1);e===E?Object.defineProperty(n,e,{configurable:!0,enumerable:!0,value:i,writable:!0}):n[e]=i}return n},f=(r,t=0)=>{if(t>v)throw new RangeError(`wire-codec: value nesting exceeds the ${v}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===u)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(n=>f(n,t+1));case"bigint":{const n=r[2];if(typeof n!="string"||n.length>T||!/^-?\d+$/.test(n))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${T} digits)`);return BigInt(n)}case"date":{const n=f(r[2],t+1);if(typeof n!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(n)}case"map":{const n=r[2];return new Map(n.map(e=>{if(!Array.isArray(e)||e.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[f(e[0],t+1),f(e[1],t+1)]}))}case"set":return new Set(r[2].map(n=>f(n,t+1)));case"url":{const n=r[2];if(typeof n!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(n)}case"error":{const n=r[2],e=r[3];if(typeof n!="string"||typeof e!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const s=(Object.hasOwn(R,n)?R[n]:void 0)??Error,i=new s(e);i.name!==n&&Object.defineProperty(i,"name",{configurable:!0,value:n,writable:!0});const c=f(r[4],t+1);if(c===null||typeof c!="object"||Array.isArray(c))throw new TypeError("wire-codec: malformed error — props must be an object");for(const l of Object.keys(c))l===E?Object.defineProperty(i,l,{configurable:!0,enumerable:!0,value:c[l],writable:!0}):i[l]=c[l];return r.length>5&&Object.defineProperty(i,"cause",{configurable:!0,value:f(r[5],t+1),writable:!0}),i}case"bytes":{const n=r[2];if(typeof n!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const e=W(n);if(A(e)!==n)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const s=r[3]??"Uint8Array";if(s==="ArrayBuffer")return e.buffer.byteLength===e.byteLength?e.buffer:e.slice().buffer;const i=Object.hasOwn(I,s)?I[s]:void 0;return i?new i(e.slice().buffer):e}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(n=>f(n,t+1))}return r.map(n=>f(n,t+1))}const o=r,a={};for(const n of Object.keys(o)){const e=f(o[n],t+1);n===E?Object.defineProperty(a,n,{configurable:!0,enumerable:!0,value:e,writable:!0}):a[n]=e}return a},V=(r,t,o)=>{try{return h(o)}catch(a){throw new TypeError(`${r}: cannot encode args for '${t}' — ${a instanceof Error?a.message:String(a)}`,a instanceof Error?{cause:a}:void 0)}},X="/_lunora/scheduler/dispatch",Y=3e4,Z=r=>{let t=r.length;for(;t>0&&r[t-1]==="/";)t-=1;return r.slice(0,t)},x=Symbol("lunoraDispatchFailure"),P=Symbol("lunoraDispatchDecline"),D=Symbol("lunoraDispatchMessageId"),k=(r,t)=>(t!==void 0&&Object.defineProperty(r,D,{value:t}),r),rr=(r,t)=>(Object.defineProperty(r,x,{value:!0}),k(r,t)),ur=r=>j(r)?r[D]:void 0,tr=(r,t,o,a)=>{const{status:n}=t;try{const e=JSON.parse(o)?.error;if(typeof e=="object"&&e!==null&&typeof e.code=="string"){const{code:s,data:i,message:c}=e,l=rr(new b(s,typeof c=="string"?c:void 0,{data:i,status:n}),a);return t.headers.get(q)==="1"&&Object.defineProperty(l,P,{value:!0}),l}}catch{}return k(new b("INTERNAL",`${r}: function dispatch failed (${String(n)}): ${o}`,{status:n}),a)},er=new Set([400,403,404,422]),nr=new Set([_,"DISPATCH_UNAUTHENTICATED"]),B=r=>j(r)&&r[x]===!0,lr=r=>B(r)&&er.has(r.status)&&!nr.has(r.code),fr=r=>B(r)&&r[P]===!0,or=K/1e3,ar=3,dr=(r,t)=>{const o=t.maxRetries??ar;r.retry({delaySeconds:or}),typeof r.attempts=="number"&&r.attempts>o&&console.error(`${t.where}: message ${r.id} was declined (${_}) on its last delivery (attempt ${String(r.attempts)} of ${String(o+1)}) — its earlier delivery is still running the call. It is retried anyway, but its retries are exhausted, so it will be dead-lettered if the queue has a deadLetterQueue and dropped if not. Raise max_retries so a slow call cannot exhaust it.`)},sr=(r,t,o)=>new b("INTERNAL",`${r}: function dispatch to "${t}" timed out after ${String(o)}ms`,{status:503}),ir=r=>{const{label:t}=r,o=globalThis.fetch,a=r.fetchImpl??(typeof o=="function"?o.bind(globalThis):void 0);return async(n,e,s={})=>{if(typeof a!="function")throw new TypeError(`${t}: no fetch implementation available — pass fetchImpl or run on a platform with global fetch`);const i=()=>r.argsAlreadyEncoded===!0?e??{}:V(t,n.__lunoraRef,e??{}),c=r.env.LUNORA_ORIGIN_URL;if(typeof c!="string"||c.length===0)throw new b("INTERNAL",`${t}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);const l=r.env.LUNORA_ADMIN_TOKEN;if(typeof l!="string"||l.length===0)throw new b("INTERNAL",`${t}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);const C=`${Z(c)}${X}`,w={authorization:`Bearer ${l}`,"content-type":"application/json"};r.traceparent!==void 0&&r.traceparent.length>0&&(w.traceparent=r.traceparent),r.identity?.userId!==void 0&&(w["x-lunora-userid"]=Q(r.identity.userId)),r.identity?.claims!==void 0&&(w["x-lunora-identity"]=G(r.identity.claims));const N=s.timeoutMs??Y,$=H(void 0,N,()=>new DOMException(`dispatch timed out after ${String(N)}ms`,"TimeoutError")),O=y=>{throw y instanceof Error&&y.name==="TimeoutError"?sr(t,n.__lunoraRef,N):y};let d;try{try{d=await a(C,{body:JSON.stringify({args:i(),functionPath:n.__lunoraRef,id:s.dedupId,shardKey:s.shardKey}),headers:w,method:"POST",signal:$.signal})}catch(m){return O(m)}if(!d.ok){let m;try{m=await d.text()}catch(M){return O(M)}throw tr(t,d,m,s.messageId)}let y;try{y=await d.text()}catch(m){return O(m)}if(y.length===0)return;let g;try{g=JSON.parse(y)}catch{throw new b("INTERNAL",`${t}: function dispatch returned a non-JSON body (${String(d.status)}): ${y}`,{status:d.status})}if(g===null||typeof g!="object"||Array.isArray(g)||!("result"in g))throw new b("INTERNAL",`${t}: function dispatch returned a JSON body that is not a { result } envelope (${String(d.status)}): ${y}`,{status:d.status});return f(g.result)}finally{$.dispose()}}},yr=r=>({env:r.env,log:J(`[queue:${r.exportName}]`),run:ir({env:r.env,fetchImpl:r.fetchImpl,label:"@lunora/queue",...r.traceparent===void 0?{}:{traceparent:r.traceparent}})});export{ur as a,yr as c,dr as d,lr as f,ar as o,fr as u};