@lunora/testing 1.0.0-alpha.243 → 1.0.0-alpha.244
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
|
@@ -386,14 +386,7 @@ interface RecordedWideEvent {
|
|
|
386
386
|
traceId: string;
|
|
387
387
|
}[];
|
|
388
388
|
}
|
|
389
|
-
/**
|
|
390
|
-
* The schema value produced by `@lunora/server`'s `defineSchema`. Accepted
|
|
391
|
-
* structurally; internally it is handed to `@lunora/do`'s `runShardMigrations` /
|
|
392
|
-
* `createShardCtxDb`, whose `SchemaLike` is the same shape declared in the DO
|
|
393
|
-
* package — the two are structurally compatible at runtime (only their
|
|
394
|
-
* independently-declared trigger nesting drifts at the type level), so the
|
|
395
|
-
* boundary cast below is sound.
|
|
396
|
-
*/
|
|
389
|
+
/** The schema value produced by `@lunora/server`'s `defineSchema`. */
|
|
397
390
|
type TestSchema = Schema<Record<string, TableDefinition>>;
|
|
398
391
|
/**
|
|
399
392
|
* A user-supplied identity, surfaced to handlers via `ctx.auth`. `userId` is the
|
package/dist/index.d.ts
CHANGED
|
@@ -386,14 +386,7 @@ interface RecordedWideEvent {
|
|
|
386
386
|
traceId: string;
|
|
387
387
|
}[];
|
|
388
388
|
}
|
|
389
|
-
/**
|
|
390
|
-
* The schema value produced by `@lunora/server`'s `defineSchema`. Accepted
|
|
391
|
-
* structurally; internally it is handed to `@lunora/do`'s `runShardMigrations` /
|
|
392
|
-
* `createShardCtxDb`, whose `SchemaLike` is the same shape declared in the DO
|
|
393
|
-
* package — the two are structurally compatible at runtime (only their
|
|
394
|
-
* independently-declared trigger nesting drifts at the type level), so the
|
|
395
|
-
* boundary cast below is sound.
|
|
396
|
-
*/
|
|
389
|
+
/** The schema value produced by `@lunora/server`'s `defineSchema`. */
|
|
397
390
|
type TestSchema = Schema<Record<string, TableDefinition>>;
|
|
398
391
|
/**
|
|
399
392
|
* A user-supplied identity, surfaced to handlers via `ctx.auth`. `userId` is the
|
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-oQEDNSxM.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{LunoraError as U}from"@lunora/errors";import{withDeferredSchedules as se}from"@lunora/server";import{createInProcessRuntime as ie,resolveInProcessIdentity as ce,registeredFunctionKind as L,runRegisteredFunction as $}from"@lunora/server/in-process";import{evaluationAttributes as ae}from"./evaluationAttributes-CYLgTP1P.mjs";import{assertScheduleDelay as ue,MAX_RETRY_ATTEMPTS as de,RETRY_BASE_DELAY_MS as fe}from"@lunora/scheduler";import{DatabaseSync as le}from"node:sqlite";const X=e=>{throw new U("INTERNAL",`ctx.${e} is not available in the in-memory @lunora/testing harness (v1)`)},me=new Set(["$$typeof","asymmetricMatch","then","toJSON"]),ye=e=>new Proxy({...e},{get(r,n){if(!(me.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 U("INTERNAL",`ctx.services.${n} has no fake in the @lunora/testing harness — pass lunoraTest(schema, { services: { ${n}: … } })`)}}}),A=e=>new Proxy((...r)=>X(e),{apply:()=>X(e),get:()=>X(e)}),z={spanId:"0000000000000001",traceId:"00000000000000000000000000000001"},we={addEvent:()=>{},addLink:()=>{},recordEvaluation:()=>{},recordException:()=>{},setAttribute:()=>{},setAttributes:()=>{},spanContext:()=>z},be=()=>{const e={attributes:{},events:[],links:[]},r={addEvent:(n,a)=>{e.events.push({...a===void 0?{}:{attributes:{...a}},name:n})},addLink:n=>{e.links.push({spanId:n.spanId,traceId:n.traceId})},recordEvaluation:n=>{Object.assign(e.attributes,ae(n))},recordException:n=>{const a={"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&&(a["exception.stacktrace"]=n.stack),r.addEvent("exception",a)},setAttribute:(n,a)=>{e.attributes[n]=a},setAttributes:n=>{Object.assign(e.attributes,n)},spanContext:()=>z};return{handle:r,recorded:e}},F=async(e,r)=>await r(F,we),G={count:()=>{},gauge:()=>{},record:()=>{}},q={debug:()=>{},error:()=>{},event:()=>{},fatal:()=>{},info:()=>{},log:()=>{},trace:()=>{},warn:()=>{},with:()=>q},B=e=>{let r="";for(let a=0;a<e.length;a+=32768)r+=String.fromCharCode(...e.subarray(a,a+32768));return btoa(r)},he=e=>{const r=atob(e),n=new Uint8Array(r.length);for(let a=0;a<r.length;a+=1)n[a]=r.codePointAt(a)??0;return n},p="$lunora.wire$",Y=64,H=1024,J="__proto__",K={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},V={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},ge=e=>{if(e===null||typeof e!="object")return!1;const r=Object.getPrototypeOf(e);return r===null||r===Object.prototype},x=(e,r=0)=>{if(r>Y)throw new RangeError(`wire-codec: value nesting exceeds the ${Y}-level limit`);if(e===void 0)return[p,"undefined"];if(e===null)return null;const n=typeof e;if(n==="bigint"){const t=e.toString();if(t.length>H)throw new RangeError(`wire-codec: over-long bigint (max ${H} digits)`);return[p,"bigint",t]}if(n==="number"){const t=e;return Number.isNaN(t)?[p,"nan"]:t===1/0?[p,"inf"]:t===-1/0?[p,"-inf"]:t}if(n!=="object")return e;if(e instanceof Date)return[p,"date",x(e.getTime(),r+1)];if(e instanceof Error){const t=e,i=x(Object.fromEntries(Object.keys(t).map(f=>[f,t[f]])),r+1),u=[p,"error",String(t.name),String(t.message),i];return t.cause!==void 0&&u.push(x(t.cause,r+1)),u}if(e instanceof URL)return[p,"url",e.href];if(e instanceof Map)return[p,"map",[...e.entries()].map(([t,i])=>[x(t,r+1),x(i,r+1)])];if(e instanceof Set)return[p,"set",[...e].map(t=>x(t,r+1))];if(e instanceof ArrayBuffer)return[p,"bytes",B(new Uint8Array(e)),"ArrayBuffer"];if(ArrayBuffer.isView(e)){const t=e,i=t.constructor.name,u=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return i==="Uint8Array"?[p,"bytes",B(u)]:[p,"bytes",B(u),i]}if(Array.isArray(e)){const t=e.map(i=>x(i,r+1));return t.length>0&&t[0]===p?[p,"arr",t]:t}if(!ge(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 a=e,y={};for(const t of Object.keys(a)){const i=a[t];if(i===void 0)continue;const u=x(i,r+1);t===J?Object.defineProperty(y,t,{configurable:!0,enumerable:!0,value:u,writable:!0}):y[t]=u}return y},P=(e,r=0)=>{if(r>Y)throw new RangeError(`wire-codec: value nesting exceeds the ${Y}-level limit`);if(e===null||typeof e!="object")return e;if(Array.isArray(e)){if(e[0]===p)switch(e[1]){case"-inf":return-1/0;case"arr":return e[2].map(t=>P(t,r+1));case"bigint":{const t=e[2];if(typeof t!="string"||t.length>H||!/^-?\d+$/.test(t))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${H} digits)`);return BigInt(t)}case"date":{const t=P(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(i=>{if(!Array.isArray(i)||i.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[P(i[0],r+1),P(i[1],r+1)]}))}case"set":return new Set(e[2].map(t=>P(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],i=e[3];if(typeof t!="string"||typeof i!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const u=(Object.hasOwn(V,t)?V[t]:void 0)??Error,f=new u(i);f.name!==t&&Object.defineProperty(f,"name",{configurable:!0,value:t,writable:!0});const l=P(e[4],r+1);if(l===null||typeof l!="object"||Array.isArray(l))throw new TypeError("wire-codec: malformed error — props must be an object");for(const g of Object.keys(l))g===J?Object.defineProperty(f,g,{configurable:!0,enumerable:!0,value:l[g],writable:!0}):f[g]=l[g];return e.length>5&&Object.defineProperty(f,"cause",{configurable:!0,value:P(e[5],r+1),writable:!0}),f}case"bytes":{const t=e[2];if(typeof t!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const i=he(t);if(B(i)!==t)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const u=e[3]??"Uint8Array";if(u==="ArrayBuffer")return i.buffer.byteLength===i.byteLength?i.buffer:i.slice().buffer;const f=Object.hasOwn(K,u)?K[u]:void 0;return f?new f(i.slice().buffer):i}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return e.map(t=>P(t,r+1))}return e.map(y=>P(y,r+1))}const n=e,a={};for(const y of Object.keys(n)){const t=P(n[y],r+1);y===J?Object.defineProperty(a,y,{configurable:!0,enumerable:!0,value:t,writable:!0}):a[y]=t}return a},pe=(e,r,n,a,y)=>{let t=y,i=1;const u=new Map,f=[],l=(c,b,m={},s)=>{const o=x(m);JSON.stringify(o);const h=P(o),E=s??`fake-job-${String(i)}`;return i+=1,u.set(E,{args:h,enqueuedAt:t,functionPath:b,id:E,scheduledFor:c}),E},g=c=>typeof c=="string"?c:"__lunoraRef"in c?c.__lunoraRef:c.name??c.className??"",S={cancel:c=>{const b=u.has(c);return u.delete(c),Promise.resolve({cancelled:b})},get:c=>Promise.resolve(u.get(c)??null),list:()=>Promise.resolve([...u.values()]),runAfter:(c,b,m,s)=>{ue(c,"ctx.scheduler.runAfter");const o=l(t+c,g(b),m,s?.id);return Promise.resolve(o)},runAt:(c,b,m,s)=>{const o=l(c,g(b),m,s?.id);return Promise.resolve(o)}},T=async c=>{u.delete(c.id);const b=a(),m=c.functionPath===void 0?void 0:b.get(c.functionPath);if(m===void 0)throw new U("FUNCTION_NOT_FOUND",`unknown functionPath "${c.functionPath??"(workflow-targeted)"}"`,{status:404});if(m.kind!=="mutation"&&m.kind!=="action")throw new U("FUNCTION_NOT_FOUND",`functionPath "${c.functionPath??"(workflow-targeted)"}" is a ${m.kind} — only mutations and actions can be scheduled`,{status:404});const s=e(),o=m.kind==="action"?n():r();await s(m.kind,m,{...o,now:t},c.args)},N=async c=>{const b=[...u.values()].filter(o=>o.scheduledFor<=c).toSorted((o,h)=>o.scheduledFor-h.scheduledFor),m=[];let s=0;for(const o of b)if(u.has(o.id)){s+=1;try{await T(o)}catch(h){const E=(o.attempts??0)+1;if(E>de){const v={args:o.args,error:h,functionPath:o.functionPath??"",id:o.id};m.push(v),f.push(v)}else{const v=fe*2**(E-1);u.set(o.id,{...o,attempts:E,scheduledFor:t+v})}}}return{executed:s,failed:m}},R=async(c,b)=>{const{executed:m,failed:s}=await N(c);if(s.length>0&&(b?.throwOnError??!0)){const[o]=s;throw s.length===1&&o!==void 0?o.error:new AggregateError(s.map(h=>h.error),`${String(s.length)} scheduled jobs failed: ${s.map(h=>h.functionPath).join(", ")}`)}return m};return{controls:{advance:(c,b)=>(t+=c,R(t,b)),failures:()=>[...f],list:()=>[...u.values()],runPending:c=>R(Number.POSITIVE_INFINITY,c)},scheduler:S}},ve=()=>{const e=new le(":memory:"),r=a=>({one(){if(a.length!==1)throw new U("INTERNAL",`expected exactly one row, received ${String(a.length)}`);const[y]=a;return y},[Symbol.iterator](){return a[Symbol.iterator]()},toArray(){return a}});return{close:()=>{e.close()},sql:{exec:(a,...y)=>{const i=e.prepare(a).all(...y);return r(i)}}}},Ee=(e,r,n)=>(y,t)=>{let i=!1;const u=[];let f,l,g=0,S=0;const T=()=>L(y)?e("query",y,r,t,!1):Promise.resolve(y(r)),N=(s,o)=>{if(s<S)return;S=s;const h={done:!1,value:o};if(u.length===0)f=h,l=void 0;else{f=void 0,l=void 0;for(const E of u.splice(0))E.resolve(h)}},R=(s,o)=>{if(!(s<S))if(S=s,u.length===0)l={error:o},f=void 0;else{f=void 0,l=void 0;for(const h of u.splice(0))h.reject(o)}},k=s=>o=>{N(s,o)},c=s=>o=>{R(s,o)},b=()=>{if(i)return;g+=1;const s=g;T().then(k(s)).catch(c(s))};n.add(b);const m={[Symbol.asyncIterator](){return m},next:()=>{if(i)return Promise.resolve({done:!0,value:void 0});if(S===g){if(l!==void 0){const{error:s}=l;return l=void 0,Promise.reject(s)}if(f!==void 0){const s=f;return f=void 0,Promise.resolve(s)}}return S<g?new Promise((s,o)=>{u.push({reject:o,resolve:s})}):T().then(s=>{if(l!==void 0){const{error:o}=l;throw l=void 0,o}if(f!==void 0){const o=f;return f=void 0,o}return{done:!1,value:s}})},return:()=>{i=!0,n.delete(b);for(const s of u.splice(0))s.resolve({done:!0,value:void 0});return Promise.resolve({done:!0,value:void 0})}};return T().then(k(0)).catch(c(0)),m},ke=(e,r)=>{const{close:n,sql:a}=ve();let y=!1;const t=()=>{y||(y=!0,n())},i=new Map(Object.entries(r?.functions??{}).map(([v,I])=>[v,I])),u=new Set,f=()=>{for(const v of u)v()},l=v=>(f(),v);let g,S,T;const N=r?.now??Date.now(),R=be(),k=(v,I)=>{if(v===void 0)throw new U("INTERNAL",`[fake-scheduler] ${I} not yet available — scheduler.advance called before harness construction completed`);return v},{controls:c,scheduler:b}=pe(()=>k(g,"dispatch"),()=>k(S,"mutationContext"),()=>k(T,"actionContext"),()=>i,N),m=se(b),{createWriters:s,resetHeadroom:o,runInTransaction:h}=ie(e,{enforceRls:r?.enforceRls,scheduler:m,sql:a}),E=v=>{const I=ce(v),Q={getIdentity:()=>Promise.resolve(I.claims),userId:I.userId},{database:W,rawDatabase:Z}=s(I),_={auth:Q,db:W,env:r?.env,log:q,metrics:G,now:N,span:R.handle,trace:F,runQuery:((d,w)=>O("query",d,_,w)),secrets:A("secrets"),storage:A("storage"),vectors:A("vectors")},j={auth:Q,db:W,env:r?.env,log:q,metrics:G,now:N,span:R.handle,trace:F,runMutation:((d,w)=>O("mutation",d,j,w)),runQuery:((d,w)=>O("query",d,_,w)),scheduler:m,secrets:A("secrets"),storage:A("storage"),vectors:A("vectors"),workflows:A("workflows")};S??=j;const ee={...j,db:Z},D={auth:Q,db:W,env:r?.env,fetch:r?.fetch??A("fetch"),log:q,metrics:G,now:N,span:R.handle,trace:F,runAction:((d,w)=>O("action",d,D,w)),runMutation:((d,w)=>h(()=>O("mutation",d,j,w)).then(l)),runQuery:((d,w)=>O("query",d,_,w)),scheduler:m,secrets:A("secrets"),services:ye(r?.services),storage:A("storage"),vectors:A("vectors"),workflows:A("workflows")};T??=D;const O=(d,w,C,M)=>$(d,w,C,M,!0);g??=(d,w,C,M)=>d==="mutation"?h(()=>$("mutation",w,C,M,!0)).then(l):(o(),O("action",w,C,M));const te=((d,w)=>(o(),L(d)?$("query",d,_,w,!1):Promise.resolve(d(_)))),re=((d,w)=>{const C=L(d)?()=>$("mutation",d,j,w,!1):()=>d(j);return h(C).then(l)}),ne=((d,w)=>(o(),L(d)?$("action",d,D,w,!1):Promise.resolve(d(D)))),oe=Ee((...d)=>(o(),$(...d)),_,u);return{action:ne,close:t,mutation:re,query:te,run:d=>h(()=>d(ee)).then(l),scheduler:c,subscribe:oe,wideEvent:()=>R.recorded,withIdentity:d=>E(d)}};return E(null)};export{ke 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.244",
|
|
4
4
|
"description": "Testing toolkit for Lunora: an in-memory harness for queries, mutations, and actions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -50,13 +50,12 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@lunora/agent": "1.0.0-alpha.
|
|
54
|
-
"@lunora/bindings": "1.0.0-alpha.
|
|
55
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
56
|
-
"@lunora/mail": "1.0.0-alpha.
|
|
57
|
-
"@lunora/scheduler": "1.0.0-alpha.
|
|
58
|
-
"@lunora/server": "1.0.0-alpha.185"
|
|
59
|
-
"@lunora/shard-engine": "1.0.0-alpha.116"
|
|
53
|
+
"@lunora/agent": "1.0.0-alpha.187",
|
|
54
|
+
"@lunora/bindings": "1.0.0-alpha.101",
|
|
55
|
+
"@lunora/errors": "1.0.0-alpha.51",
|
|
56
|
+
"@lunora/mail": "1.0.0-alpha.102",
|
|
57
|
+
"@lunora/scheduler": "1.0.0-alpha.114",
|
|
58
|
+
"@lunora/server": "1.0.0-alpha.185"
|
|
60
59
|
},
|
|
61
60
|
"peerDependencies": {
|
|
62
61
|
"@playwright/test": "^1.61.1"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as I}from"@lunora/errors";import{withDeferredSchedules as le,bindTableFacade as me,beginDeferredSchedules as he}from"@lunora/server";import{runShardMigrations as ye,TransactionHeadroomTracker as J,createShardCtxDb as be,RLS_UNWRAP_SYMBOL as we}from"@lunora/shard-engine";import{evaluationAttributes as ge}from"./evaluationAttributes-CYLgTP1P.mjs";import{assertScheduleDelay as pe,MAX_RETRY_ATTEMPTS as ve,RETRY_BASE_DELAY_MS as Ae}from"@lunora/scheduler";import{DatabaseSync as Ee}from"node:sqlite";const V=e=>{throw new I("INTERNAL",`ctx.${e} is not available in the in-memory @lunora/testing harness (v1)`)},Se=new Set(["$$typeof","asymmetricMatch","then","toJSON"]),Re=e=>new Proxy({...e},{get(r,n){if(!(Se.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 I("INTERNAL",`ctx.services.${n} has no fake in the @lunora/testing harness — pass lunoraTest(schema, { services: { ${n}: … } })`)}}}),S=e=>new Proxy((...r)=>V(e),{apply:()=>V(e),get:()=>V(e)}),oe={spanId:"0000000000000001",traceId:"00000000000000000000000000000001"},Te={addEvent:()=>{},addLink:()=>{},recordEvaluation:()=>{},recordException:()=>{},setAttribute:()=>{},setAttributes:()=>{},spanContext:()=>oe},Pe=()=>{const e={attributes:{},events:[],links:[]},r={addEvent:(n,c)=>{e.events.push({...c===void 0?{}:{attributes:{...c}},name:n})},addLink:n=>{e.links.push({spanId:n.spanId,traceId:n.traceId})},recordEvaluation:n=>{Object.assign(e.attributes,ge(n))},recordException:n=>{const c={"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&&(c["exception.stacktrace"]=n.stack),r.addEvent("exception",c)},setAttribute:(n,c)=>{e.attributes[n]=c},setAttributes:n=>{Object.assign(e.attributes,n)},spanContext:()=>oe};return{handle:r,recorded:e}},W=async(e,r)=>await r(W,Te),z={count:()=>{},gauge:()=>{},record:()=>{}},H={debug:()=>{},error:()=>{},event:()=>{},fatal:()=>{},info:()=>{},log:()=>{},trace:()=>{},warn:()=>{},with:()=>H},Q=e=>{let r="";for(let c=0;c<e.length;c+=32768)r+=String.fromCharCode(...e.subarray(c,c+32768));return btoa(r)},xe=e=>{const r=atob(e),n=new Uint8Array(r.length);for(let c=0;c<r.length;c+=1)n[c]=r.codePointAt(c)??0;return n},A="$lunora.wire$",G=64,K=1024,Z="__proto__",re={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},ne={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},Ne=e=>{if(e===null||typeof e!="object")return!1;const r=Object.getPrototypeOf(e);return r===null||r===Object.prototype},x=(e,r=0)=>{if(r>G)throw new RangeError(`wire-codec: value nesting exceeds the ${G}-level limit`);if(e===void 0)return[A,"undefined"];if(e===null)return null;const n=typeof e;if(n==="bigint"){const t=e.toString();if(t.length>K)throw new RangeError(`wire-codec: over-long bigint (max ${K} digits)`);return[A,"bigint",t]}if(n==="number"){const t=e;return Number.isNaN(t)?[A,"nan"]:t===1/0?[A,"inf"]:t===-1/0?[A,"-inf"]:t}if(n!=="object")return e;if(e instanceof Date)return[A,"date",x(e.getTime(),r+1)];if(e instanceof Error){const t=e,a=x(Object.fromEntries(Object.keys(t).map(f=>[f,t[f]])),r+1),d=[A,"error",String(t.name),String(t.message),a];return t.cause!==void 0&&d.push(x(t.cause,r+1)),d}if(e instanceof URL)return[A,"url",e.href];if(e instanceof Map)return[A,"map",[...e.entries()].map(([t,a])=>[x(t,r+1),x(a,r+1)])];if(e instanceof Set)return[A,"set",[...e].map(t=>x(t,r+1))];if(e instanceof ArrayBuffer)return[A,"bytes",Q(new Uint8Array(e)),"ArrayBuffer"];if(ArrayBuffer.isView(e)){const t=e,a=t.constructor.name,d=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return a==="Uint8Array"?[A,"bytes",Q(d)]:[A,"bytes",Q(d),a]}if(Array.isArray(e)){const t=e.map(a=>x(a,r+1));return t.length>0&&t[0]===A?[A,"arr",t]:t}if(!Ne(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 c=e,m={};for(const t of Object.keys(c)){const a=c[t];if(a===void 0)continue;const d=x(a,r+1);t===Z?Object.defineProperty(m,t,{configurable:!0,enumerable:!0,value:d,writable:!0}):m[t]=d}return m},P=(e,r=0)=>{if(r>G)throw new RangeError(`wire-codec: value nesting exceeds the ${G}-level limit`);if(e===null||typeof e!="object")return e;if(Array.isArray(e)){if(e[0]===A)switch(e[1]){case"-inf":return-1/0;case"arr":return e[2].map(t=>P(t,r+1));case"bigint":{const t=e[2];if(typeof t!="string"||t.length>K||!/^-?\d+$/.test(t))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${K} digits)`);return BigInt(t)}case"date":{const t=P(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(a=>{if(!Array.isArray(a)||a.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[P(a[0],r+1),P(a[1],r+1)]}))}case"set":return new Set(e[2].map(t=>P(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],a=e[3];if(typeof t!="string"||typeof a!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const d=(Object.hasOwn(ne,t)?ne[t]:void 0)??Error,f=new d(a);f.name!==t&&Object.defineProperty(f,"name",{configurable:!0,value:t,writable:!0});const y=P(e[4],r+1);if(y===null||typeof y!="object"||Array.isArray(y))throw new TypeError("wire-codec: malformed error — props must be an object");for(const p of Object.keys(y))p===Z?Object.defineProperty(f,p,{configurable:!0,enumerable:!0,value:y[p],writable:!0}):f[p]=y[p];return e.length>5&&Object.defineProperty(f,"cause",{configurable:!0,value:P(e[5],r+1),writable:!0}),f}case"bytes":{const t=e[2];if(typeof t!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const a=xe(t);if(Q(a)!==t)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const d=e[3]??"Uint8Array";if(d==="ArrayBuffer")return a.buffer.byteLength===a.byteLength?a.buffer:a.slice().buffer;const f=Object.hasOwn(re,d)?re[d]:void 0;return f?new f(a.slice().buffer):a}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return e.map(t=>P(t,r+1))}return e.map(m=>P(m,r+1))}const n=e,c={};for(const m of Object.keys(n)){const t=P(n[m],r+1);m===Z?Object.defineProperty(c,m,{configurable:!0,enumerable:!0,value:t,writable:!0}):c[m]=t}return c},Ie=(e,r,n,c,m)=>{let t=m,a=1;const d=new Map,f=[],y=(i,b,h={},s)=>{const o=x(h);JSON.stringify(o);const g=P(o),E=s??`fake-job-${String(a)}`;return a+=1,d.set(E,{args:g,enqueuedAt:t,functionPath:b,id:E,scheduledFor:i}),E},p=i=>typeof i=="string"?i:"__lunoraRef"in i?i.__lunoraRef:i.name??i.className??"",R={cancel:i=>{const b=d.has(i);return d.delete(i),Promise.resolve({cancelled:b})},get:i=>Promise.resolve(d.get(i)??null),list:()=>Promise.resolve([...d.values()]),runAfter:(i,b,h,s)=>{pe(i,"ctx.scheduler.runAfter");const o=y(t+i,p(b),h,s?.id);return Promise.resolve(o)},runAt:(i,b,h,s)=>{const o=y(i,p(b),h,s?.id);return Promise.resolve(o)}},k=async i=>{d.delete(i.id);const b=c(),h=i.functionPath===void 0?void 0:b.get(i.functionPath);if(h===void 0)throw new I("FUNCTION_NOT_FOUND",`unknown functionPath "${i.functionPath??"(workflow-targeted)"}"`,{status:404});if(h.kind!=="mutation"&&h.kind!=="action")throw new I("FUNCTION_NOT_FOUND",`functionPath "${i.functionPath??"(workflow-targeted)"}" is a ${h.kind} — only mutations and actions can be scheduled`,{status:404});const s=e(),o=h.kind==="action"?n():r();await s(h.kind,h,{...o,now:t},i.args)},U=async i=>{const b=[...d.values()].filter(o=>o.scheduledFor<=i).toSorted((o,g)=>o.scheduledFor-g.scheduledFor),h=[];let s=0;for(const o of b)if(d.has(o.id)){s+=1;try{await k(o)}catch(g){const E=(o.attempts??0)+1;if(E>ve){const _={args:o.args,error:g,functionPath:o.functionPath??"",id:o.id};h.push(_),f.push(_)}else{const _=Ae*2**(E-1);d.set(o.id,{...o,attempts:E,scheduledFor:t+_})}}}return{executed:s,failed:h}},O=async(i,b)=>{const{executed:h,failed:s}=await U(i);if(s.length>0&&(b?.throwOnError??!0)){const[o]=s;throw s.length===1&&o!==void 0?o.error:new AggregateError(s.map(g=>g.error),`${String(s.length)} scheduled jobs failed: ${s.map(g=>g.functionPath).join(", ")}`)}return h};return{controls:{advance:(i,b)=>(t+=i,O(t,b)),failures:()=>[...f],list:()=>[...d.values()],runPending:i=>O(Number.POSITIVE_INFINITY,i)},scheduler:R}},ke=()=>{const e=new Ee(":memory:"),r=c=>({one(){if(c.length!==1)throw new I("INTERNAL",`expected exactly one row, received ${String(c.length)}`);const[m]=c;return m},[Symbol.iterator](){return c[Symbol.iterator]()},toArray(){return c}});return{close:()=>{e.close()},sql:{exec:(c,...m)=>{const a=e.prepare(c).all(...m);return r(a)}}}},Oe=e=>{if(e===null||typeof e.userId!="string"||e.userId.length===0)return{claims:null,userId:null};const{userId:r,...n}=e;return{claims:Object.keys(n).length>0?n:null,userId:r}};class je extends J{current=new J;reset(){this.current=new J}headroom(){return this.current.headroom()}recordRead(r){this.current.recordRead(r)}recordWrite(r){this.current.recordWrite(r)}}const q=e=>{if(typeof e!="object"||e===null)return;const{kind:r}=e;if(r==="query"||r==="mutation"||r==="action")return r},_e=e=>typeof e=="object"&&e!==null&&e.visibility==="internal"?"internal":"public",Ce=(e,r,n)=>(m,t)=>{let a=!1;const d=[];let f,y,p=0,R=0;const k=()=>q(m)?e("query",m,r,t,!1):Promise.resolve(m(r)),U=(s,o)=>{if(s<R)return;R=s;const g={done:!1,value:o};if(d.length===0)f=g,y=void 0;else{f=void 0,y=void 0;for(const E of d.splice(0))E.resolve(g)}},O=(s,o)=>{if(!(s<R))if(R=s,d.length===0)y={error:o},f=void 0;else{f=void 0,y=void 0;for(const g of d.splice(0))g.reject(o)}},F=s=>o=>{U(s,o)},i=s=>o=>{O(s,o)},b=()=>{if(a)return;p+=1;const s=p;k().then(F(s)).catch(i(s))};n.add(b);const h={[Symbol.asyncIterator](){return h},next:()=>{if(a)return Promise.resolve({done:!0,value:void 0});if(R===p){if(y!==void 0){const{error:s}=y;return y=void 0,Promise.reject(s)}if(f!==void 0){const s=f;return f=void 0,Promise.resolve(s)}}return R<p?new Promise((s,o)=>{d.push({reject:o,resolve:s})}):k().then(s=>{if(y!==void 0){const{error:o}=y;throw y=void 0,o}if(f!==void 0){const o=f;return f=void 0,o}return{done:!1,value:s}})},return:()=>{a=!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 k().then(F(0)).catch(i(0)),h},qe=(e,r)=>{const{close:n,sql:c}=ke(),m=e;ye(c,m);const t=new je,a=w=>{const v=w;for(const T of Object.keys(m.tables))v[T]=me(w,T);return w},d=w=>{const v=be({auth:{identity:w.claims,userId:w.userId},enforceRls:r?.enforceRls??!0,headroom:t,schema:m,sql:c}),T=v[we]??v;return{database:a(v),rawDatabase:a(T)}},f=w=>{c.exec.call(c,w)};let y=Promise.resolve();const p=w=>{const v=async()=>{const C=he({scheduler:X});t.reset(),f("BEGIN");try{const B=await w();return f("COMMIT"),await C(!0),B}catch(B){try{f("ROLLBACK")}catch{}throw await C(!1),B}},T=y.then(v);return y=T.then(()=>{},()=>{}),T};let R=!1;const k=()=>{R||(R=!0,n())},U=new Map(Object.entries(r?.functions??{}).map(([w,v])=>[w,v])),O=new Set,F=()=>{for(const w of O)w()},i=w=>(F(),w);let b,h,s;const o=r?.now??Date.now(),g=Pe(),E=(w,v)=>{if(w===void 0)throw new I("INTERNAL",`[fake-scheduler] ${v} not yet available — scheduler.advance called before harness construction completed`);return w},{controls:_,scheduler:se}=Ie(()=>E(b,"dispatch"),()=>E(h,"mutationContext"),()=>E(s,"actionContext"),()=>U,o),X=le(se),ee=w=>{const v=Oe(w),T={getIdentity:()=>Promise.resolve(v.claims),userId:v.userId},{database:C,rawDatabase:B}=d(v),$={auth:T,db:C,env:r?.env,log:H,metrics:z,now:o,span:g.handle,trace:W,runQuery:((u,l)=>j("query",u,$,l)),secrets:S("secrets"),storage:S("storage"),vectors:S("vectors")},D={auth:T,db:C,env:r?.env,log:H,metrics:z,now:o,span:g.handle,trace:W,runMutation:((u,l)=>j("mutation",u,D,l)),runQuery:((u,l)=>j("query",u,$,l)),scheduler:X,secrets:S("secrets"),storage:S("storage"),vectors:S("vectors"),workflows:S("workflows")};h??=D;const ie={...D,db:B},Y={auth:T,db:C,env:r?.env,fetch:r?.fetch??S("fetch"),log:H,metrics:z,now:o,span:g.handle,trace:W,runAction:((u,l)=>j("action",u,Y,l)),runMutation:((u,l)=>p(()=>j("mutation",u,D,l)).then(i)),runQuery:((u,l)=>j("query",u,$,l)),scheduler:X,secrets:S("secrets"),services:Re(r?.services),storage:S("storage"),vectors:S("vectors"),workflows:S("workflows")};s??=Y;const L=(u,l,N,M,fe)=>{const te=q(l);if(te!==u)throw new I("INTERNAL",`expected a registered ${u}, received a ${te??"non-function"} reference`);if(!fe&&_e(l)==="internal")throw new I("INTERNAL",`This ${u} is an internal function — it is unreachable from the external RPC boundary in production. Call it through ctx.run${u.charAt(0).toUpperCase()}${u.slice(1)} from another function instead.`);return Promise.resolve(l.handler(N,M??{}))},j=(u,l,N,M)=>L(u,l,N,M,!0);b??=(u,l,N,M)=>u==="mutation"?p(()=>L("mutation",l,N,M,!0)).then(i):(t.reset(),j("action",l,N,M));const ce=((u,l)=>(t.reset(),q(u)?L("query",u,$,l,!1):Promise.resolve(u($)))),ae=((u,l)=>{const N=q(u)?()=>L("mutation",u,D,l,!1):()=>u(D);return p(N).then(i)}),ue=((u,l)=>(t.reset(),q(u)?L("action",u,Y,l,!1):Promise.resolve(u(Y)))),de=Ce((...u)=>(t.reset(),L(...u)),$,O);return{action:ue,close:k,mutation:ae,query:ce,run:u=>p(()=>u(ie)).then(i),scheduler:_,subscribe:de,wideEvent:()=>g.recorded,withIdentity:u=>ee(u)}};return ee(null)};export{qe as lunoraTest};
|