@lunora/testing 1.0.0-alpha.266 → 1.0.0-alpha.268
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.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{agentHarness as o,finalTurn as t,toolCallTurn as a}from"./packem_shared/agentHarness-DA9onGVO.mjs";import{evaluationAttributes as l,recordEvaluation as n}from"./packem_shared/evaluationAttributes-CYLgTP1P.mjs";import{createArtifactsFake as s}from"./packem_shared/createArtifactsFake-L0tjki11.mjs";import{lunoraTest as p}from"./packem_shared/lunoraTest-
|
|
1
|
+
import{agentHarness as o,finalTurn as t,toolCallTurn as a}from"./packem_shared/agentHarness-DA9onGVO.mjs";import{evaluationAttributes as l,recordEvaluation as n}from"./packem_shared/evaluationAttributes-CYLgTP1P.mjs";import{createArtifactsFake as s}from"./packem_shared/createArtifactsFake-L0tjki11.mjs";import{lunoraTest as p}from"./packem_shared/lunoraTest-VecnFIun.mjs";import{groundednessScorer as f,mrrScorer as u,ndcgAtK as S,precisionAtK as d,recallAtK as A}from"./packem_shared/groundednessScorer-kgXJCZDg.mjs";import{containsScorer as k,evaluate as v,exactMatchScorer as K,keywordScorer as M,llmScorer as T,regexScorer as w,scoreSample as C}from"./packem_shared/containsScorer-DoLfFOs6.mjs";import{extractLink as b,listCapturedMail as h,waitForMail as y}from"@lunora/mail/testing";export{o as agentHarness,k as containsScorer,s as createArtifactsFake,v as evaluate,l as evaluationAttributes,K as exactMatchScorer,b as extractLink,t as finalTurn,f as groundednessScorer,M as keywordScorer,h as listCapturedMail,T as llmScorer,p as lunoraTest,u as mrrScorer,S as ndcgAtK,d as precisionAtK,A as recallAtK,n as recordEvaluation,w as regexScorer,C as scoreSample,a as toolCallTurn,y as waitForMail};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AsyncLocalStorage as ve}from"node:async_hooks";import{LunoraError as N}from"@lunora/errors";import{withDeferredSchedules as me}from"@lunora/server";import{createInProcessRuntime as pe,resolveInProcessIdentity as ye,runRegisteredFunction as C,registeredFunctionKind as Q}from"@lunora/server/in-process";import{evaluationAttributes as ge}from"./evaluationAttributes-CYLgTP1P.mjs";import{memorySubscriptionStore as we,createNotify as be}from"@lunora/notify";import{createNotification as Se}from"@visulima/notification";import{serialize as Ae,deserialize as Ee}from"node:v8";import{createQueues as Ne,createTopicContext as Pe}from"@lunora/queue";import{assertScheduleDelay as Re,MAX_RETRY_ATTEMPTS as Te,RETRY_BASE_DELAY_MS as Ie}from"@lunora/scheduler";import{encodeWire as xe,decodeWire as Oe}from"@lunora/wire";import{DatabaseSync as ke}from"node:sqlite";const x=(e,t)=>{throw new N("INTERNAL",t===void 0?`ctx.${e} is not available in the in-memory @lunora/testing harness (v1)`:`ctx.${e} is not enabled in the @lunora/testing harness — pass lunoraTest(schema, { ${t} })`)},qe=new Set(["$$typeof","asymmetricMatch","then","toJSON"]),$e=e=>new Proxy({...e},{get(t,r){if(!(qe.has(r)&&!Object.hasOwn(t,r))){if(typeof r=="symbol"||Object.hasOwn(t,r)||r in Object.prototype)return Reflect.get(t,r);throw new N("INTERNAL",`ctx.services.${r} has no fake in the @lunora/testing harness — pass lunoraTest(schema, { services: { ${r}: … } })`)}}}),A=(e,t)=>new Proxy((...r)=>x(e,t),{apply:()=>x(e,t),get:()=>x(e,t)}),re={spanId:"0000000000000001",traceId:"00000000000000000000000000000001"},_e={addEvent:()=>{},addLink:()=>{},recordEvaluation:()=>{},recordException:()=>{},setAttribute:()=>{},setAttributes:()=>{},spanContext:()=>re},Ce=()=>{const e={attributes:{},events:[],links:[]},t={addEvent:(r,s)=>{e.events.push({...s===void 0?{}:{attributes:{...s}},name:r})},addLink:r=>{e.links.push({spanId:r.spanId,traceId:r.traceId})},recordEvaluation:r=>{Object.assign(e.attributes,ge(r))},recordException:r=>{const s={"exception.message":r instanceof Error?r.message:String(r),"exception.type":r instanceof Error?r.constructor.name:"Error"};r instanceof Error&&r.stack!==void 0&&(s["exception.stacktrace"]=r.stack),t.addEvent("exception",s)},setAttribute:(r,s)=>{e.attributes[r]=s},setAttributes:r=>{Object.assign(e.attributes,r)},spanContext:()=>re};return{handle:t,recorded:e}},V=async(e,t)=>await t(V,_e),H={count:()=>{},gauge:()=>{},record:()=>{}},Y={debug:()=>{},error:()=>{},event:()=>{},fatal:()=>{},info:()=>{},log:()=>{},trace:()=>{},warn:()=>{},with:()=>Y},U="notify",De=e=>{let t=e;if(typeof e=="string"){if(!e.startsWith("{"))return;try{t=JSON.parse(e)}catch{return}}const r=t?.endpoint;return typeof r=="string"?r:void 0},D=(e,t)=>typeof e=="function"?e(t):e,Le=(e,t)=>{const r=[],s=(l,g)=>(r.push({channel:l,payload:structuredClone(g)}),{data:{messageId:`${l}-${String(r.length)}`,sent:!0,timestamp:new Date},success:!0}),y=l=>({channel:l,id:`lunora-testing-${l}`,initialize:()=>{},isAvailable:()=>!0,send:g=>s(l,g)}),c=D(e.webPush,t)!==void 0,b=D(e.fcm,t)!==void 0,a={...y("push"),send:l=>{const g=Array.isArray(l.to)?l.to:[l.to];if(g.length===0)throw new N("BAD_REQUEST","@lunora/notify: push send has no recipients — `to` is an empty array");for(const O of g){const R=De(O)!==void 0;if(R?!c:!b)throw new Error(R?"@lunora/notify: received a web-push target but no `webPush` channel is configured":"@lunora/notify: received an FCM token target but no `fcm` channel is configured")}return s("push",l)}},p={...c||b?{push:a}:{},...D(e.chat,t)===void 0?{}:{chat:y("chat")},...D(e.inApp,t)===void 0?{}:{inapp:y("inapp")},...D(e.webhook,t)===void 0?{}:{webhook:y("webhook")}},u=we(),{notify:d,push:E}=be({...e,store:()=>u},t,{engine:Se(p),silent:!0});return{controls:{clear:()=>{r.length=0},sent:l=>l===void 0?[...r]:r.filter(g=>g.channel===l)},surfaces:{notify:d,push:E}}},Fe=(e,t)=>e!==void 0?Le(e,t):{controls:{clear:()=>x("notify",U),sent:()=>x("notify",U)},surfaces:{notify:A("notify",U),push:A("push",U)}},K="queues: [...]",Z=128*1024,ee=256*1024,Me="json",te=new TextEncoder,je=(e,t)=>{if(t==="v8"){const s=Ae(e);return{body:Ee(s),bytes:s.byteLength}}if(t==="text"){if(typeof e!="string")throw new N("VALIDATION_ERROR",`@lunora/queue: a "text" message body must be a string, got ${typeof e}`);return{body:e,bytes:te.encode(e).byteLength}}if(t==="bytes"){if(!(e instanceof ArrayBuffer)&&!ArrayBuffer.isView(e))throw new N("VALIDATION_ERROR",'@lunora/queue: a "bytes" message body must be an ArrayBuffer or an ArrayBufferView');return{body:e,bytes:e.byteLength}}const r=JSON.stringify(e);if(typeof r!="string")throw new N("VALIDATION_ERROR",`@lunora/queue: a "json" message body must be JSON-serializable, got ${typeof e}`);return{body:JSON.parse(r),bytes:te.encode(r).byteLength}},ne=e=>{const t=new Set(e),r=[],s=(c,b,a)=>{const p=a?.contentType??Me,u=je(b,p);if(u.bytes>Z)throw new N("VALIDATION_ERROR",`@lunora/queue: ${c} message is ${String(u.bytes)} bytes, over the Cloudflare Queues limit of ${String(Z)} (128 KB)`);return{bytes:u.bytes,message:{body:u.body,contentType:p,...a?.delaySeconds===void 0?{}:{delaySeconds:a.delaySeconds},destination:c}}},y=c=>({send:(b,a)=>(r.push(s(c,b,a).message),Promise.resolve()),sendBatch:(b,a)=>{const p=[...b].map(d=>s(c,d.body,{contentType:d.contentType,delaySeconds:d.delaySeconds??a?.delaySeconds})),u=p.reduce((d,E)=>d+E.bytes,0);if(u>ee)throw new N("VALIDATION_ERROR",`@lunora/queue: ${c} batch is ${String(u)} bytes, over the Cloudflare Queues limit of ${String(ee)} (256 KB)`);return r.push(...p.map(d=>d.message)),Promise.resolve()}});return{bindings:Object.fromEntries([...t].map(c=>[c,y(c)])),clear:()=>{r.length=0},read:(c,b,a)=>{if(c===void 0)return[...r];if(!t.has(c))throw new N("INTERNAL",`${b}("${c}"): no such ${a} — declared: ${[...t].join(", ")||"(none)"}`);return r.filter(p=>p.destination===c)}}},Be=e=>{const t=ne(e);return{controls:{clear:t.clear,sent:r=>t.read(r,"harness.queues.sent","queue").map(({destination:s,...y})=>({...y,queue:s}))},surfaces:{queues:Ne({bindings:t.bindings})}}},Ue=e=>e!==void 0?Be(e):{controls:{clear:()=>x("queues",K),sent:()=>x("queues",K)},surfaces:{queues:A("queues",K)}},Qe=(e,t,r,s,y)=>{let c=y,b=1;const a=new Map,p=[],u=(o,w,h={},v)=>{const n=xe(h);JSON.stringify(n);const f=Oe(n),S=v??`fake-job-${String(b)}`;return b+=1,a.set(S,{args:f,enqueuedAt:c,functionPath:w,id:S,scheduledFor:o}),S},d=o=>typeof o=="string"?o:"__lunoraRef"in o?o.__lunoraRef:o.name??o.className??"",E={cancel:o=>{const w=a.has(o);return a.delete(o),Promise.resolve({cancelled:w})},get:o=>Promise.resolve(a.get(o)??null),list:()=>Promise.resolve([...a.values()]),runAfter:(o,w,h,v)=>{Re(o,"ctx.scheduler.runAfter");const n=u(c+o,d(w),h,v?.id);return Promise.resolve(n)},runAt:(o,w,h,v)=>{const n=u(o,d(w),h,v?.id);return Promise.resolve(n)}},l=async o=>{a.delete(o.id);const w=s(),h=o.functionPath===void 0?void 0:w.get(o.functionPath);if(h===void 0)throw new N("FUNCTION_NOT_FOUND",`unknown functionPath "${o.functionPath??"(workflow-targeted)"}"`,{status:404});if(h.kind!=="mutation"&&h.kind!=="action")throw new N("FUNCTION_NOT_FOUND",`functionPath "${o.functionPath??"(workflow-targeted)"}" is a ${h.kind} — only mutations and actions can be scheduled`,{status:404});const v=e(),n=h.kind==="action"?r():t();await v(h.kind,h,{...n,now:c},o.args)},g=async o=>{const w=[...a.values()].filter(n=>n.scheduledFor<=o).toSorted((n,f)=>n.scheduledFor-f.scheduledFor),h=[];let v=0;for(const n of w)if(a.has(n.id)){v+=1;try{await l(n)}catch(f){const S=(n.attempts??0)+1;if(S>Te){const T={args:n.args,error:f,functionPath:n.functionPath??"",id:n.id};h.push(T),p.push(T)}else{const T=Ie*2**(S-1);a.set(n.id,{...n,attempts:S,scheduledFor:c+T})}}}return{executed:v,failed:h}},O=async(o,w)=>{const{executed:h,failed:v}=await g(o);if(v.length>0&&(w?.throwOnError??!0)){const[n]=v;throw v.length===1&&n!==void 0?n.error:new AggregateError(v.map(f=>f.error),`${String(v.length)} scheduled jobs failed: ${v.map(f=>f.functionPath).join(", ")}`)}return h};return{controls:{advance:(o,w)=>(c+=o,O(c,w)),failures:()=>[...p],list:()=>[...a.values()],runPending:o=>O(Number.POSITIVE_INFINITY,o)},scheduler:E}},X="topics: [...]",Ve=e=>{if(e===void 0)return{controls:{clear:()=>x("topics",X),published:()=>x("topics",X)},surfaces:{topics:A("topics",X)}};const t=ne(e),r=Pe(t.bindings,e.map(s=>({exportName:s,subscriptions:[{binding:s,exportName:s}]})));return{controls:{clear:t.clear,published:s=>t.read(s,"harness.topics.published","topic").map(({destination:y,...c})=>({...c,topic:y}))},surfaces:{topics:r}}},Ye=()=>{const e=new ke(":memory:"),t=s=>({one(){if(s.length!==1)throw new N("INTERNAL",`expected exactly one row, received ${String(s.length)}`);const[y]=s;return y},[Symbol.iterator](){return s[Symbol.iterator]()},toArray(){return s}});return{close:()=>{e.close()},sql:{exec:(s,...y)=>{const b=e.prepare(s).all(...y);return t(b)}}}},L=new ve,Je=(e,t,r,s)=>(c,b)=>{let a=!1;const p=[];let u,d,E=0,l=0;const g=()=>L.run(s(),()=>Q(c)?e("query",c,t,b,!1):Promise.resolve(c(t))),O=(n,f)=>{if(n<l)return;l=n;const S={done:!1,value:f};if(p.length===0)u=S,d=void 0;else{u=void 0,d=void 0;for(const T of p.splice(0))T.resolve(S)}},R=(n,f)=>{if(!(n<l))if(l=n,p.length===0)d={error:f},u=void 0;else{u=void 0,d=void 0;for(const S of p.splice(0))S.reject(f)}},o=n=>f=>{O(n,f)},w=n=>f=>{R(n,f)},h=()=>{if(a)return;E+=1;const n=E;g().then(o(n)).catch(w(n))};r.add(h);const v={[Symbol.asyncIterator](){return v},next:()=>{if(a)return Promise.resolve({done:!0,value:void 0});if(l===E){if(d!==void 0){const{error:n}=d;return d=void 0,Promise.reject(n)}if(u!==void 0){const n=u;return u=void 0,Promise.resolve(n)}}return l<E?new Promise((n,f)=>{p.push({reject:f,resolve:n})}):g().then(n=>{if(d!==void 0){const{error:f}=d;throw d=void 0,f}if(u!==void 0){const f=u;return u=void 0,f}return{done:!1,value:n}})},return:()=>{a=!0,r.delete(h);for(const n of p.splice(0))n.resolve({done:!0,value:void 0});return Promise.resolve({done:!0,value:void 0})}};return g().then(o(0)).catch(w(0)),v},ct=(e,t)=>{const{close:r,sql:s}=Ye();let y=!1;const c=()=>{y||(y=!0,r())},b=new Map(Object.entries(t?.functions??{}).map(([P,I])=>[P,I])),a=new Set,p=()=>{for(const P of a)P()},u=P=>(p(),P);let d,E,l;const g=()=>t?.now??Date.now(),O=g(),R=P=>((...I)=>L.run(g(),()=>P(...I))),o=Ce(),{controls:w,surfaces:h}=Ue(t?.queues),{controls:v,surfaces:n}=Ve(t?.topics),{controls:f,surfaces:S}=Fe(t?.notify,t?.env??{}),T=(P,I)=>{if(P===void 0)throw new N("INTERNAL",`[fake-scheduler] ${I} not yet available — scheduler.advance called before harness construction completed`);return P},{controls:oe,scheduler:se}=Qe(()=>T(d,"dispatch"),()=>T(E,"mutationContext"),()=>T(l,"actionContext"),()=>b,O),J=me(se),{createWriters:ce,resetHeadroom:F,runInTransaction:M}=pe(e,{enforceRls:t?.enforceRls,scheduler:J,sql:s}),G=P=>{const I=ye(P),W={getIdentity:()=>Promise.resolve(I.claims),userId:I.userId},{database:z,rawDatabase:ie}=ce(I),q={...S,auth:W,db:z,env:t?.env,log:Y,metrics:H,get now(){return L.getStore()??g()},newId:()=>crypto.randomUUID(),span:o.handle,trace:V,runQuery:((i,m)=>k("query",i,q,m)),secrets:A("secrets"),storage:A("storage"),vectors:A("vectors")},$={...S,...h,...n,auth:W,db:z,env:t?.env,log:Y,metrics:H,get now(){return L.getStore()??g()},newId:()=>crypto.randomUUID(),span:o.handle,trace:V,runMutation:((i,m)=>k("mutation",i,$,m)),runQuery:((i,m)=>k("query",i,q,m)),scheduler:J,secrets:A("secrets"),storage:A("storage"),vectors:A("vectors"),workflows:A("workflows")};E??=$;const ae=Object.defineProperties({},{...Object.getOwnPropertyDescriptors($),db:{enumerable:!0,value:ie}}),j={...S,...h,...n,auth:W,db:z,env:t?.env,fetch:t?.fetch??A("fetch"),log:Y,metrics:H,get now(){return L.getStore()??g()},newId:()=>crypto.randomUUID(),span:o.handle,trace:V,runAction:((i,m)=>k("action",i,j,m)),runMutation:((i,m)=>M(()=>k("mutation",i,$,m)).then(u)),runQuery:((i,m)=>k("query",i,q,m)),scheduler:J,secrets:A("secrets"),services:$e(t?.services),storage:A("storage"),vectors:A("vectors"),workflows:A("workflows")};l??=j;const k=(i,m,_,B)=>C(i,m,_,B,!0);d??=(i,m,_,B)=>i==="mutation"?M(()=>C("mutation",m,_,B,!0)).then(u):(F(),k("action",m,_,B));const ue=((i,m)=>(F(),Q(i)?C("query",i,q,m,!1):Promise.resolve(i(q)))),de=((i,m)=>{const _=Q(i)?()=>C("mutation",i,$,m,!1):()=>i($);return M(_).then(u)}),le=((i,m)=>(F(),Q(i)?C("action",i,j,m,!1):Promise.resolve(i(j)))),fe=Je((...i)=>(F(),C(...i)),q,a,()=>t?.now??Date.now()),he=i=>M(()=>i(ae)).then(u);return{action:R(le),close:c,mutation:R(de),notify:f,query:R(ue),queues:w,run:R(he),scheduler:oe,subscribe:fe,topics:v,wideEvent:()=>o.recorded,withIdentity:i=>G(i)}};return G(null)};export{ct as lunoraTest};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/testing",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.268",
|
|
4
4
|
"description": "Testing toolkit for Lunora: an in-memory harness for queries, mutations, and actions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -50,14 +50,15 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@lunora/agent": "1.0.0-alpha.
|
|
54
|
-
"@lunora/bindings": "1.0.0-alpha.
|
|
53
|
+
"@lunora/agent": "1.0.0-alpha.211",
|
|
54
|
+
"@lunora/bindings": "1.0.0-alpha.114",
|
|
55
55
|
"@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
|
|
56
|
-
"@lunora/mail": "1.0.0-alpha.
|
|
57
|
-
"@lunora/notify": "1.0.0-alpha.
|
|
58
|
-
"@lunora/queue": "1.0.0-alpha.
|
|
59
|
-
"@lunora/scheduler": "1.0.0-alpha.
|
|
60
|
-
"@lunora/server": "1.0.0-alpha.
|
|
56
|
+
"@lunora/mail": "1.0.0-alpha.108",
|
|
57
|
+
"@lunora/notify": "1.0.0-alpha.81",
|
|
58
|
+
"@lunora/queue": "1.0.0-alpha.107",
|
|
59
|
+
"@lunora/scheduler": "1.0.0-alpha.128",
|
|
60
|
+
"@lunora/server": "1.0.0-alpha.204",
|
|
61
|
+
"@lunora/wire": "1.0.0-alpha.1",
|
|
61
62
|
"@visulima/notification": "1.2.0"
|
|
62
63
|
},
|
|
63
64
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{AsyncLocalStorage as Se}from"node:async_hooks";import{LunoraError as T}from"@lunora/errors";import{withDeferredSchedules as Re}from"@lunora/server";import{createInProcessRuntime as Te,resolveInProcessIdentity as Oe,runRegisteredFunction as L,registeredFunctionKind as J}from"@lunora/server/in-process";import{evaluationAttributes as Ne}from"./evaluationAttributes-CYLgTP1P.mjs";import{memorySubscriptionStore as Pe,createNotify as Ie}from"@lunora/notify";import{createNotification as xe}from"@visulima/notification";import{serialize as ke,deserialize as _e}from"node:v8";import{createQueues as $e,createTopicContext as je}from"@lunora/queue";import{assertScheduleDelay as qe,MAX_RETRY_ATTEMPTS as Ce,RETRY_BASE_DELAY_MS as De}from"@lunora/scheduler";import{DatabaseSync as Le}from"node:sqlite";const _=(e,r)=>{throw new T("INTERNAL",r===void 0?`ctx.${e} is not available in the in-memory @lunora/testing harness (v1)`:`ctx.${e} is not enabled in the @lunora/testing harness — pass lunoraTest(schema, { ${r} })`)},Ue=new Set(["$$typeof","asymmetricMatch","then","toJSON"]),Fe=e=>new Proxy({...e},{get(r,n){if(!(Ue.has(n)&&!Object.hasOwn(r,n))){if(typeof n=="symbol"||Object.hasOwn(r,n)||n in Object.prototype)return Reflect.get(r,n);throw new T("INTERNAL",`ctx.services.${n} has no fake in the @lunora/testing harness — pass lunoraTest(schema, { services: { ${n}: … } })`)}}}),S=(e,r)=>new Proxy((...n)=>_(e,r),{apply:()=>_(e,r),get:()=>_(e,r)}),fe={spanId:"0000000000000001",traceId:"00000000000000000000000000000001"},Be={addEvent:()=>{},addLink:()=>{},recordEvaluation:()=>{},recordException:()=>{},setAttribute:()=>{},setAttributes:()=>{},spanContext:()=>fe},Me=()=>{const e={attributes:{},events:[],links:[]},r={addEvent:(n,o)=>{e.events.push({...o===void 0?{}:{attributes:{...o}},name:n})},addLink:n=>{e.links.push({spanId:n.spanId,traceId:n.traceId})},recordEvaluation:n=>{Object.assign(e.attributes,Ne(n))},recordException:n=>{const o={"exception.message":n instanceof Error?n.message:String(n),"exception.type":n instanceof Error?n.constructor.name:"Error"};n instanceof Error&&n.stack!==void 0&&(o["exception.stacktrace"]=n.stack),r.addEvent("exception",o)},setAttribute:(n,o)=>{e.attributes[n]=o},setAttributes:n=>{Object.assign(e.attributes,n)},spanContext:()=>fe};return{handle:r,recorded:e}},W=async(e,r)=>await r(W,Be),te={count:()=>{},gauge:()=>{},record:()=>{}},X={debug:()=>{},error:()=>{},event:()=>{},fatal:()=>{},info:()=>{},log:()=>{},trace:()=>{},warn:()=>{},with:()=>X},V="notify",Ye=e=>{let r=e;if(typeof e=="string"){if(!e.startsWith("{"))return;try{r=JSON.parse(e)}catch{return}}const n=r?.endpoint;return typeof n=="string"?n:void 0},U=(e,r)=>typeof e=="function"?e(r):e,Qe=(e,r)=>{const n=[],o=(m,w)=>(n.push({channel:m,payload:structuredClone(w)}),{data:{messageId:`${m}-${String(n.length)}`,sent:!0,timestamp:new Date},success:!0}),l=m=>({channel:m,id:`lunora-testing-${m}`,initialize:()=>{},isAvailable:()=>!0,send:w=>o(m,w)}),t=U(e.webPush,r)!==void 0,c=U(e.fcm,r)!==void 0,i={...l("push"),send:m=>{const w=Array.isArray(m.to)?m.to:[m.to];if(w.length===0)throw new T("BAD_REQUEST","@lunora/notify: push send has no recipients — `to` is an empty array");for(const $ of w){const P=Ye($)!==void 0;if(P?!t:!c)throw new Error(P?"@lunora/notify: received a web-push target but no `webPush` channel is configured":"@lunora/notify: received an FCM token target but no `fcm` channel is configured")}return o("push",m)}},d={...t||c?{push:i}:{},...U(e.chat,r)===void 0?{}:{chat:l("chat")},...U(e.inApp,r)===void 0?{}:{inapp:l("inapp")},...U(e.webhook,r)===void 0?{}:{webhook:l("webhook")}},u=Pe(),{notify:y,push:R}=Ie({...e,store:()=>u},r,{engine:xe(d),silent:!0});return{controls:{clear:()=>{n.length=0},sent:m=>m===void 0?[...n]:n.filter(w=>w.channel===m)},surfaces:{notify:y,push:R}}},Ve=(e,r)=>e!==void 0?Qe(e,r):{controls:{clear:()=>_("notify",V),sent:()=>_("notify",V)},surfaces:{notify:S("notify",V),push:S("push",V)}},re="queues: [...]",ce=128*1024,ie=256*1024,Je="json",ae=new TextEncoder,We=(e,r)=>{if(r==="v8"){const o=ke(e);return{body:_e(o),bytes:o.byteLength}}if(r==="text"){if(typeof e!="string")throw new T("VALIDATION_ERROR",`@lunora/queue: a "text" message body must be a string, got ${typeof e}`);return{body:e,bytes:ae.encode(e).byteLength}}if(r==="bytes"){if(!(e instanceof ArrayBuffer)&&!ArrayBuffer.isView(e))throw new T("VALIDATION_ERROR",'@lunora/queue: a "bytes" message body must be an ArrayBuffer or an ArrayBufferView');return{body:e,bytes:e.byteLength}}const n=JSON.stringify(e);if(typeof n!="string")throw new T("VALIDATION_ERROR",`@lunora/queue: a "json" message body must be JSON-serializable, got ${typeof e}`);return{body:JSON.parse(n),bytes:ae.encode(n).byteLength}},le=e=>{const r=new Set(e),n=[],o=(t,c,i)=>{const d=i?.contentType??Je,u=We(c,d);if(u.bytes>ce)throw new T("VALIDATION_ERROR",`@lunora/queue: ${t} message is ${String(u.bytes)} bytes, over the Cloudflare Queues limit of ${String(ce)} (128 KB)`);return{bytes:u.bytes,message:{body:u.body,contentType:d,...i?.delaySeconds===void 0?{}:{delaySeconds:i.delaySeconds},destination:t}}},l=t=>({send:(c,i)=>(n.push(o(t,c,i).message),Promise.resolve()),sendBatch:(c,i)=>{const d=[...c].map(y=>o(t,y.body,{contentType:y.contentType,delaySeconds:y.delaySeconds??i?.delaySeconds})),u=d.reduce((y,R)=>y+R.bytes,0);if(u>ie)throw new T("VALIDATION_ERROR",`@lunora/queue: ${t} batch is ${String(u)} bytes, over the Cloudflare Queues limit of ${String(ie)} (256 KB)`);return n.push(...d.map(y=>y.message)),Promise.resolve()}});return{bindings:Object.fromEntries([...r].map(t=>[t,l(t)])),clear:()=>{n.length=0},read:(t,c,i)=>{if(t===void 0)return[...n];if(!r.has(t))throw new T("INTERNAL",`${c}("${t}"): no such ${i} — declared: ${[...r].join(", ")||"(none)"}`);return n.filter(d=>d.destination===t)}}},Xe=e=>{const r=le(e);return{controls:{clear:r.clear,sent:n=>r.read(n,"harness.queues.sent","queue").map(({destination:o,...l})=>({...l,queue:o}))},surfaces:{queues:$e({bindings:r.bindings})}}},He=e=>e!==void 0?Xe(e):{controls:{clear:()=>_("queues",re),sent:()=>_("queues",re)},surfaces:{queues:S("queues",re)}},H=e=>{let r="";for(let o=0;o<e.length;o+=32768)r+=String.fromCharCode(...e.subarray(o,o+32768));return btoa(r)},Ke=e=>{const r=atob(e),n=new Uint8Array(r.length);for(let o=0;o<r.length;o+=1)n[o]=r.codePointAt(o)??0;return n},E="$lunora.wire$",K=64,z=1024,oe="__proto__",ue={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},de={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},ze=e=>{if(e===null||typeof e!="object")return!1;const r=Object.getPrototypeOf(e);return r===null||r===Object.prototype},k=(e,r=0)=>{if(r>K)throw new RangeError(`wire-codec: value nesting exceeds the ${K}-level limit`);if(e===void 0)return[E,"undefined"];if(e===null)return null;const n=typeof e;if(n==="bigint"){const t=e.toString();if(t.length>z)throw new RangeError(`wire-codec: over-long bigint (max ${z} digits)`);return[E,"bigint",t]}if(n==="number"){const t=e;return Number.isNaN(t)?[E,"nan"]:t===1/0?[E,"inf"]:t===-1/0?[E,"-inf"]:t}if(n!=="object")return e;if(e instanceof Date)return[E,"date",k(e.getTime(),r+1)];if(e instanceof Error){const t=e,c=k(Object.fromEntries(Object.keys(t).map(d=>[d,t[d]])),r+1),i=[E,"error",String(t.name),String(t.message),c];return t.cause!==void 0&&i.push(k(t.cause,r+1)),i}if(e instanceof URL)return[E,"url",e.href];if(e instanceof Map)return[E,"map",[...e.entries()].map(([t,c])=>[k(t,r+1),k(c,r+1)])];if(e instanceof Set)return[E,"set",[...e].map(t=>k(t,r+1))];if(e instanceof ArrayBuffer)return[E,"bytes",H(new Uint8Array(e)),"ArrayBuffer"];if(ArrayBuffer.isView(e)){const t=e,c=t.constructor.name,i=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return c==="Uint8Array"?[E,"bytes",H(i)]:[E,"bytes",H(i),c]}if(Array.isArray(e)){const t=e.map(c=>k(c,r+1));return t.length>0&&t[0]===E?[E,"arr",t]:t}if(!ze(e)){const t=e.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 o=e,l={};for(const t of Object.keys(o)){const c=o[t];if(c===void 0)continue;const i=k(c,r+1);t===oe?Object.defineProperty(l,t,{configurable:!0,enumerable:!0,value:i,writable:!0}):l[t]=i}return l},N=(e,r=0)=>{if(r>K)throw new RangeError(`wire-codec: value nesting exceeds the ${K}-level limit`);if(e===null||typeof e!="object")return e;if(Array.isArray(e)){if(e[0]===E)switch(e[1]){case"-inf":return-1/0;case"arr":return e[2].map(t=>N(t,r+1));case"bigint":{const t=e[2];if(typeof t!="string"||t.length>z||!/^-?\d+$/.test(t))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${z} digits)`);return BigInt(t)}case"date":{const t=N(e[2],r+1);if(typeof t!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(t)}case"map":{const t=e[2];return new Map(t.map(c=>{if(!Array.isArray(c)||c.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[N(c[0],r+1),N(c[1],r+1)]}))}case"set":return new Set(e[2].map(t=>N(t,r+1)));case"url":{const t=e[2];if(typeof t!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(t)}case"error":{const t=e[2],c=e[3];if(typeof t!="string"||typeof c!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const i=(Object.hasOwn(de,t)?de[t]:void 0)??Error,d=new i(c);d.name!==t&&Object.defineProperty(d,"name",{configurable:!0,value:t,writable:!0});const u=N(e[4],r+1);if(u===null||typeof u!="object"||Array.isArray(u))throw new TypeError("wire-codec: malformed error — props must be an object");for(const y of Object.keys(u))y===oe?Object.defineProperty(d,y,{configurable:!0,enumerable:!0,value:u[y],writable:!0}):d[y]=u[y];return e.length>5&&Object.defineProperty(d,"cause",{configurable:!0,value:N(e[5],r+1),writable:!0}),d}case"bytes":{const t=e[2];if(typeof t!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const c=Ke(t);if(H(c)!==t)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const i=e[3]??"Uint8Array";if(i==="ArrayBuffer")return c.buffer.byteLength===c.byteLength?c.buffer:c.slice().buffer;const d=Object.hasOwn(ue,i)?ue[i]:void 0;return d?new d(c.slice().buffer):c}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return e.map(t=>N(t,r+1))}return e.map(l=>N(l,r+1))}const n=e,o={};for(const l of Object.keys(n)){const t=N(n[l],r+1);l===oe?Object.defineProperty(o,l,{configurable:!0,enumerable:!0,value:t,writable:!0}):o[l]=t}return o},Ge=(e,r,n,o,l)=>{let t=l,c=1;const i=new Map,d=[],u=(a,v,b={},p)=>{const s=k(b);JSON.stringify(s);const h=N(s),A=p??`fake-job-${String(c)}`;return c+=1,i.set(A,{args:h,enqueuedAt:t,functionPath:v,id:A,scheduledFor:a}),A},y=a=>typeof a=="string"?a:"__lunoraRef"in a?a.__lunoraRef:a.name??a.className??"",R={cancel:a=>{const v=i.has(a);return i.delete(a),Promise.resolve({cancelled:v})},get:a=>Promise.resolve(i.get(a)??null),list:()=>Promise.resolve([...i.values()]),runAfter:(a,v,b,p)=>{qe(a,"ctx.scheduler.runAfter");const s=u(t+a,y(v),b,p?.id);return Promise.resolve(s)},runAt:(a,v,b,p)=>{const s=u(a,y(v),b,p?.id);return Promise.resolve(s)}},m=async a=>{i.delete(a.id);const v=o(),b=a.functionPath===void 0?void 0:v.get(a.functionPath);if(b===void 0)throw new T("FUNCTION_NOT_FOUND",`unknown functionPath "${a.functionPath??"(workflow-targeted)"}"`,{status:404});if(b.kind!=="mutation"&&b.kind!=="action")throw new T("FUNCTION_NOT_FOUND",`functionPath "${a.functionPath??"(workflow-targeted)"}" is a ${b.kind} — only mutations and actions can be scheduled`,{status:404});const p=e(),s=b.kind==="action"?n():r();await p(b.kind,b,{...s,now:t},a.args)},w=async a=>{const v=[...i.values()].filter(s=>s.scheduledFor<=a).toSorted((s,h)=>s.scheduledFor-h.scheduledFor),b=[];let p=0;for(const s of v)if(i.has(s.id)){p+=1;try{await m(s)}catch(h){const A=(s.attempts??0)+1;if(A>Ce){const I={args:s.args,error:h,functionPath:s.functionPath??"",id:s.id};b.push(I),d.push(I)}else{const I=De*2**(A-1);i.set(s.id,{...s,attempts:A,scheduledFor:t+I})}}}return{executed:p,failed:b}},$=async(a,v)=>{const{executed:b,failed:p}=await w(a);if(p.length>0&&(v?.throwOnError??!0)){const[s]=p;throw p.length===1&&s!==void 0?s.error:new AggregateError(p.map(h=>h.error),`${String(p.length)} scheduled jobs failed: ${p.map(h=>h.functionPath).join(", ")}`)}return b};return{controls:{advance:(a,v)=>(t+=a,$(t,v)),failures:()=>[...d],list:()=>[...i.values()],runPending:a=>$(Number.POSITIVE_INFINITY,a)},scheduler:R}},ne="topics: [...]",Ze=e=>{if(e===void 0)return{controls:{clear:()=>_("topics",ne),published:()=>_("topics",ne)},surfaces:{topics:S("topics",ne)}};const r=le(e),n=je(r.bindings,e.map(o=>({exportName:o,subscriptions:[{binding:o,exportName:o}]})));return{controls:{clear:r.clear,published:o=>r.read(o,"harness.topics.published","topic").map(({destination:l,...t})=>({...t,topic:l}))},surfaces:{topics:n}}},et=()=>{const e=new Le(":memory:"),r=o=>({one(){if(o.length!==1)throw new T("INTERNAL",`expected exactly one row, received ${String(o.length)}`);const[l]=o;return l},[Symbol.iterator](){return o[Symbol.iterator]()},toArray(){return o}});return{close:()=>{e.close()},sql:{exec:(o,...l)=>{const c=e.prepare(o).all(...l);return r(c)}}}},F=new Se,tt=(e,r,n,o)=>(t,c)=>{let i=!1;const d=[];let u,y,R=0,m=0;const w=()=>F.run(o(),()=>J(t)?e("query",t,r,c,!1):Promise.resolve(t(r))),$=(s,h)=>{if(s<m)return;m=s;const A={done:!1,value:h};if(d.length===0)u=A,y=void 0;else{u=void 0,y=void 0;for(const I of d.splice(0))I.resolve(A)}},P=(s,h)=>{if(!(s<m))if(m=s,d.length===0)y={error:h},u=void 0;else{u=void 0,y=void 0;for(const A of d.splice(0))A.reject(h)}},a=s=>h=>{$(s,h)},v=s=>h=>{P(s,h)},b=()=>{if(i)return;R+=1;const s=R;w().then(a(s)).catch(v(s))};n.add(b);const p={[Symbol.asyncIterator](){return p},next:()=>{if(i)return Promise.resolve({done:!0,value:void 0});if(m===R){if(y!==void 0){const{error:s}=y;return y=void 0,Promise.reject(s)}if(u!==void 0){const s=u;return u=void 0,Promise.resolve(s)}}return m<R?new Promise((s,h)=>{d.push({reject:h,resolve:s})}):w().then(s=>{if(y!==void 0){const{error:h}=y;throw y=void 0,h}if(u!==void 0){const h=u;return u=void 0,h}return{done:!1,value:s}})},return:()=>{i=!0,n.delete(b);for(const s of d.splice(0))s.resolve({done:!0,value:void 0});return Promise.resolve({done:!0,value:void 0})}};return w().then(a(0)).catch(v(0)),p},mt=(e,r)=>{const{close:n,sql:o}=et();let l=!1;const t=()=>{l||(l=!0,n())},c=new Map(Object.entries(r?.functions??{}).map(([O,x])=>[O,x])),i=new Set,d=()=>{for(const O of i)O()},u=O=>(d(),O);let y,R,m;const w=()=>r?.now??Date.now(),$=w(),P=O=>((...x)=>F.run(w(),()=>O(...x))),a=Me(),{controls:v,surfaces:b}=He(r?.queues),{controls:p,surfaces:s}=Ze(r?.topics),{controls:h,surfaces:A}=Ve(r?.notify,r?.env??{}),I=(O,x)=>{if(O===void 0)throw new T("INTERNAL",`[fake-scheduler] ${x} not yet available — scheduler.advance called before harness construction completed`);return O},{controls:ye,scheduler:me}=Ge(()=>I(y,"dispatch"),()=>I(R,"mutationContext"),()=>I(m,"actionContext"),()=>c,$),G=Re(me),{createWriters:he,resetHeadroom:B,runInTransaction:M}=Te(e,{enforceRls:r?.enforceRls,scheduler:G,sql:o}),se=O=>{const x=Oe(O),Z={getIdentity:()=>Promise.resolve(x.claims),userId:x.userId},{database:ee,rawDatabase:be}=he(x),q={...A,auth:Z,db:ee,env:r?.env,log:X,metrics:te,get now(){return F.getStore()??w()},newId:()=>crypto.randomUUID(),span:a.handle,trace:W,runQuery:((f,g)=>j("query",f,q,g)),secrets:S("secrets"),storage:S("storage"),vectors:S("vectors")},C={...A,...b,...s,auth:Z,db:ee,env:r?.env,log:X,metrics:te,get now(){return F.getStore()??w()},newId:()=>crypto.randomUUID(),span:a.handle,trace:W,runMutation:((f,g)=>j("mutation",f,C,g)),runQuery:((f,g)=>j("query",f,q,g)),scheduler:G,secrets:S("secrets"),storage:S("storage"),vectors:S("vectors"),workflows:S("workflows")};R??=C;const pe=Object.defineProperties({},{...Object.getOwnPropertyDescriptors(C),db:{enumerable:!0,value:be}}),Y={...A,...b,...s,auth:Z,db:ee,env:r?.env,fetch:r?.fetch??S("fetch"),log:X,metrics:te,get now(){return F.getStore()??w()},newId:()=>crypto.randomUUID(),span:a.handle,trace:W,runAction:((f,g)=>j("action",f,Y,g)),runMutation:((f,g)=>M(()=>j("mutation",f,C,g)).then(u)),runQuery:((f,g)=>j("query",f,q,g)),scheduler:G,secrets:S("secrets"),services:Fe(r?.services),storage:S("storage"),vectors:S("vectors"),workflows:S("workflows")};m??=Y;const j=(f,g,D,Q)=>L(f,g,D,Q,!0);y??=(f,g,D,Q)=>f==="mutation"?M(()=>L("mutation",g,D,Q,!0)).then(u):(B(),j("action",g,D,Q));const ge=((f,g)=>(B(),J(f)?L("query",f,q,g,!1):Promise.resolve(f(q)))),we=((f,g)=>{const D=J(f)?()=>L("mutation",f,C,g,!1):()=>f(C);return M(D).then(u)}),ve=((f,g)=>(B(),J(f)?L("action",f,Y,g,!1):Promise.resolve(f(Y)))),Ae=tt((...f)=>(B(),L(...f)),q,i,()=>r?.now??Date.now()),Ee=f=>M(()=>f(pe)).then(u);return{action:P(ve),close:t,mutation:P(we),notify:h,query:P(ge),queues:v,run:P(Ee),scheduler:ye,subscribe:Ae,topics:p,wideEvent:()=>a.recorded,withIdentity:f=>se(f)}};return se(null)};export{mt as lunoraTest};
|