@lunora/codegen 1.0.0-alpha.150 → 1.0.0-alpha.152
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 +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/AGENTS_FILENAME-CRdh_pOr.mjs +1 -0
- package/dist/packem_shared/CONTAINERS_FILENAME-BssQL6eI.mjs +1 -0
- package/dist/packem_shared/FLAGS_FILENAME-Bn_wWM4d.mjs +1 -0
- package/dist/packem_shared/{GENERATED_HEADER--PCtJMQc.mjs → GENERATED_HEADER-w7DB5GZI.mjs} +1 -1
- package/dist/packem_shared/NOTIFY_FILENAME-BH0djo6F.mjs +1 -0
- package/dist/packem_shared/{OPENRPC_VERSION-C4UXIUyy.mjs → OPENRPC_VERSION-BAgBIsQM.mjs} +1 -1
- package/dist/packem_shared/QUEUES_FILENAME-CIfuMMG3.mjs +1 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-S3Ey8df4.mjs +9 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-CWESEYLi.mjs +2 -0
- package/dist/packem_shared/{SchemaSnapshotParseError-yZc-1mxR.mjs → SchemaSnapshotParseError-yrVM8bTa.mjs} +1 -1
- package/dist/packem_shared/WORKFLOWS_FILENAME-CSqONfHS.mjs +1 -0
- package/dist/packem_shared/{buildOpenApiDocument-D5xOB07T.mjs → buildOpenApiDocument-ZdoDQXmt.mjs} +1 -1
- package/dist/packem_shared/chain-DboeOxBl.mjs +1 -0
- package/dist/packem_shared/classify-procedure-call-CRm5Etni.mjs +1 -0
- package/dist/packem_shared/context-property-calls-CBUh7oAY.mjs +1 -0
- package/dist/packem_shared/discoverAuthApiCalls-B5Qmjmyk.mjs +1 -0
- package/dist/packem_shared/discoverCrons-c0ig327z.mjs +1 -0
- package/dist/packem_shared/discoverFunctions-DeuEs6Ce.mjs +1 -0
- package/dist/packem_shared/discoverHttpRoutes-zWSSyyOj.mjs +1 -0
- package/dist/packem_shared/discoverHyperdriveCalls-C6kV2CPz.mjs +1 -0
- package/dist/packem_shared/discoverInserts-BB7o_8pU.mjs +1 -0
- package/dist/packem_shared/discoverMaskProcedures-CNqwOwXv.mjs +1 -0
- package/dist/packem_shared/discoverMigrations-CQjGLKW-.mjs +1 -0
- package/dist/packem_shared/discoverNondeterministicCalls-B07wjsd2.mjs +1 -0
- package/dist/packem_shared/discoverQueries-Dz2vDpE9.mjs +1 -0
- package/dist/packem_shared/discoverR2sqlCalls-CuHe5smg.mjs +1 -0
- package/dist/packem_shared/discoverRlsMetadata-CXWVNLk4.mjs +1 -0
- package/dist/packem_shared/discoverRlsProcedures-DXdr9YHi.mjs +1 -0
- package/dist/packem_shared/discoverSandboxUsage-BJHLHZR_.mjs +1 -0
- package/dist/packem_shared/discoverStorageRulesMetadata-CUa2Dtb4.mjs +1 -0
- package/dist/packem_shared/{emit-CXfWb_pY.mjs → emit-Dsr5DNpc.mjs} +291 -129
- package/dist/packem_shared/{emitApp-DcrQNgaz.mjs → emitApp-kFg_xYlc.mjs} +10 -2
- package/dist/packem_shared/{exported-procedure-chains-M40rbSYM.mjs → exported-procedure-chains-Cmt3Pr92.mjs} +1 -1
- package/dist/packem_shared/index-BsVoa-4F.mjs +1 -0
- package/dist/packem_shared/listLunoraSourceFiles-BvqYMy81.mjs +1 -0
- package/dist/packem_shared/queries-D8DheHbi.mjs +1 -0
- package/package.json +10 -10
- package/dist/packem_shared/AGENTS_FILENAME-B1Abt3Gl.mjs +0 -1
- package/dist/packem_shared/CONTAINERS_FILENAME-CtcysaKS.mjs +0 -1
- package/dist/packem_shared/FLAGS_FILENAME-B3VZ6vTw.mjs +0 -1
- package/dist/packem_shared/NOTIFY_FILENAME-CKO5gtGe.mjs +0 -1
- package/dist/packem_shared/QUEUES_FILENAME-C-pzLGy4.mjs +0 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-DazENDSB.mjs +0 -9
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-B1BUjuG5.mjs +0 -2
- package/dist/packem_shared/WORKFLOWS_FILENAME-BfvqsG9Z.mjs +0 -1
- package/dist/packem_shared/ast-BYoSZlae.mjs +0 -1
- package/dist/packem_shared/chain-Dygm2apY.mjs +0 -1
- package/dist/packem_shared/classify-procedure-call-Ib2EMtFH.mjs +0 -1
- package/dist/packem_shared/context-property-calls-Br0sVv8E.mjs +0 -1
- package/dist/packem_shared/discoverAuthApiCalls-DoNQSgso.mjs +0 -1
- package/dist/packem_shared/discoverCrons-DCxl4hty.mjs +0 -1
- package/dist/packem_shared/discoverFunctions-CXURzTDU.mjs +0 -1
- package/dist/packem_shared/discoverHttpRoutes-2XhMbeh5.mjs +0 -1
- package/dist/packem_shared/discoverHyperdriveCalls-DTq4PKT5.mjs +0 -1
- package/dist/packem_shared/discoverInserts-qU5F4W4g.mjs +0 -1
- package/dist/packem_shared/discoverMaskProcedures-BZsC5dHd.mjs +0 -1
- package/dist/packem_shared/discoverMigrations-BFkJQ8Sy.mjs +0 -1
- package/dist/packem_shared/discoverNondeterministicCalls-B-NNzzPW.mjs +0 -1
- package/dist/packem_shared/discoverQueries-B4emAFn5.mjs +0 -1
- package/dist/packem_shared/discoverR2sqlCalls-C2GtrFnl.mjs +0 -1
- package/dist/packem_shared/discoverRlsMetadata-BKcUnSNr.mjs +0 -1
- package/dist/packem_shared/discoverRlsProcedures-fAhxiIyD.mjs +0 -1
- package/dist/packem_shared/discoverSandboxUsage-CJhnKA0_.mjs +0 -1
- package/dist/packem_shared/discoverStorageRulesMetadata-C7XmORWp.mjs +0 -1
- package/dist/packem_shared/index-xGhyK9J_.mjs +0 -1
- package/dist/packem_shared/queries-Ddvo5dCs.mjs +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{agentComponent as dt}from"@lunora/agent/component";import{LunoraError as Z}from"@lunora/errors";import{serializeSchemaSnapshot as xn,hashSchemaSnapshot as vn}from"./SCHEMA_SNAPSHOT_VERSION-
|
|
1
|
+
import{agentComponent as dt}from"@lunora/agent/component";import{LunoraError as Z}from"@lunora/errors";import{serializeSchemaSnapshot as xn,hashSchemaSnapshot as vn}from"./SCHEMA_SNAPSHOT_VERSION-CWESEYLi.mjs";import{s as $}from"./paths-C-9fwEgQ.mjs";const ut=[{contextProperty:"access",key:"access",moduleSpecifier:"@lunora/cloudflare-access"},{appMethod:{configKey:"ai",doc:"Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`).",method:"ai"},contextProperty:"ai",key:"ai",moduleSpecifier:"@lunora/ai"},{appMethod:{configKey:"analytics",doc:"Override the Analytics Engine dataset backing `ctx.analytics` (defaults to `env.ANALYTICS`).",method:"analytics"},contextProperty:"analytics",key:"analytics",moduleSpecifier:"@lunora/bindings/analytics",serverCtxField:{field:`
|
|
2
2
|
/** Analytics Engine telemetry sink. Fire-and-forget and sampled; do not read it back in-handler. */
|
|
3
3
|
readonly analytics: import("@lunora/bindings/analytics").AnalyticsClient;`,tier:"every"}},{appMethod:{configKey:"browser",doc:"Override the Browser Rendering binding backing `ctx.browser` (defaults to `env.BROWSER`).",method:"browser"},contextProperty:"browser",key:"browser",moduleSpecifier:"@lunora/browser",serverCtxField:{field:`
|
|
4
4
|
/** Browser Rendering (screenshots/PDF/scrape). Non-deterministic — available only in actions. */
|
|
@@ -15,14 +15,14 @@ import{agentComponent as dt}from"@lunora/agent/component";import{LunoraError as
|
|
|
15
15
|
/**
|
|
16
16
|
* R2 SQL over Apache Iceberg tables (window functions, DISTINCT, set operations). Non-deterministic — available only in actions. Reads here are NOT tracked by Lunora live queries.
|
|
17
17
|
*/
|
|
18
|
-
readonly r2sql: import("@lunora/bindings/r2sql").R2SqlClient;`,tier:"action"}},{contextProperty:"scheduler",key:"scheduler",moduleSpecifier:"@lunora/scheduler"},{contextProperty:"storage",key:"storage",moduleSpecifier:"@lunora/storage"},{appMethod:{configKey:"vectors",doc:"Wire the Vectorize index map backing `ctx.vectors`.",method:"vectors"},contextProperty:"vectors",key:"vectors",moduleSpecifier:"@lunora/bindings/vectors"},{contextProperty:"workflows",key:"workflows",moduleSpecifier:"@lunora/workflow"}],Rn=ut,Sn=new Map(Rn.flatMap(e=>e.serverCtxField?[[e.key,e.serverCtxField]]:[])),eo=ut.flatMap(e=>"appMethod"in e?[{appMethod:e.appMethod,key:e.key}]:[]),pt=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,$n=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),ht=e=>e.column!==void 0,
|
|
18
|
+
readonly r2sql: import("@lunora/bindings/r2sql").R2SqlClient;`,tier:"action"}},{contextProperty:"scheduler",key:"scheduler",moduleSpecifier:"@lunora/scheduler"},{contextProperty:"storage",key:"storage",moduleSpecifier:"@lunora/storage"},{appMethod:{configKey:"vectors",doc:"Wire the Vectorize index map backing `ctx.vectors`.",method:"vectors"},contextProperty:"vectors",key:"vectors",moduleSpecifier:"@lunora/bindings/vectors"},{contextProperty:"workflows",key:"workflows",moduleSpecifier:"@lunora/workflow"}],Rn=ut,Sn=new Map(Rn.flatMap(e=>e.serverCtxField?[[e.key,e.serverCtxField]]:[])),eo=ut.flatMap(e=>"appMethod"in e?[{appMethod:e.appMethod,key:e.key}]:[]),pt=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,$n=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),ht=e=>e.column!==void 0,Tn=(e,t)=>{switch(e){case"bigint":return`if (typeof ${t} !== "bigint") return DEFER;
|
|
19
19
|
`;case"boolean":return`if (typeof ${t} !== "boolean") return DEFER;
|
|
20
20
|
`;case"date":case"number":case"timestamp":return`if (typeof ${t} !== "number" || !Number.isFinite(${t})) return DEFER;
|
|
21
21
|
`;case"null":return`if (${t} !== null) return DEFER;
|
|
22
22
|
`;default:return`if (typeof ${t} !== "string") return DEFER;
|
|
23
|
-
`}},
|
|
23
|
+
`}},Nn=(e,t)=>e.stringMaxLength===void 0?"":`if (${t}.length > ${String(e.stringMaxLength)}) return DEFER;
|
|
24
24
|
`,An=(e,t)=>{const n=e.literalValue?.trim();if(!(n===void 0||!pt.test(n)))return{out:t,pre:`if (${t} !== ${n}) return DEFER;
|
|
25
|
-
`}},Ge=(e,t,n)=>{if(!ht(e)&&!(e.unmodelledRefinement||e.sourceText!==void 0)){if($n.has(e.kind))return e.kind==="any"?{out:t,pre:""}:{out:t,pre:
|
|
25
|
+
`}},Ge=(e,t,n)=>{if(!ht(e)&&!(e.unmodelledRefinement||e.sourceText!==void 0)){if($n.has(e.kind))return e.kind==="any"?{out:t,pre:""}:{out:t,pre:Tn(e.kind,t)+Nn(e,t)};switch(e.kind){case"array":return On(e,t,n);case"literal":return An(e,t);case"object":return Ln(e,t,n);default:return}}},On=(e,t,n)=>{const{inner:r}=e;if(!r)return;const o=n.next(),s=`__arr${String(o)}`,i=`__i${String(o)}`,a=`__e${String(o)}`,c=Ge(r,a,n);if(!c)return;const d=`if (!Array.isArray(${t})) return DEFER;
|
|
26
26
|
const ${s} = new Array(${t}.length);
|
|
27
27
|
for (let ${i} = 0; ${i} < ${t}.length; ${i}++) {
|
|
28
28
|
const ${a} = ${t}[${i}];
|
|
@@ -38,18 +38,18 @@ ${d} = true;
|
|
|
38
38
|
`,c=p}const d=In(s,i,c,n);if(!d)return;r+=d.pre,o.push(d.entry)}return{entries:o.join(", "),pre:r}},gt=e=>{const t=`Object.getPrototypeOf(${e})`;return`if (${t} !== Object.prototype && ${t} !== null) return DEFER;
|
|
39
39
|
`},Ln=(e,t,n)=>{const r=e.shape??{},o=mt(r,t,n);if(!o)return;const s=n.next(),i=`__obj${String(s)}`,a=`if (typeof ${t} !== "object" || ${t} === null || Array.isArray(${t})) return DEFER;
|
|
40
40
|
${gt(t)}${o.pre}const ${i} = { ${o.entries} };
|
|
41
|
-
`;return{out:i,pre:a}},
|
|
41
|
+
`;return{out:i,pre:a}},En=e=>{let t=0;const r=mt(e,"source",{next:()=>(t+=1,t)});if(r)return`(source) => {
|
|
42
42
|
if (typeof source !== "object" || source === null || Array.isArray(source)) return DEFER;
|
|
43
43
|
${gt("source")}${r.pre}return { ${r.entries} };
|
|
44
44
|
}`},S=`// GENERATED by @lunora/codegen — do not edit.
|
|
45
45
|
// Run \`lunora codegen\` to regenerate.
|
|
46
46
|
|
|
47
|
-
`,ae=(e=!1)=>e?{client:"lunorash/client",do:"lunorash/do",flags:"lunorash/flags",server:"lunorash/server",serverDataModel:"lunorash/server/data-model",serverDrizzle:"lunorash/server/drizzle",serverTypes:"lunorash/server/types",values:"lunorash/values"}:{client:"@lunora/client",do:"@lunora/do",flags:"@lunora/flags",server:"@lunora/server",serverDataModel:"@lunora/server/data-model",serverDrizzle:"@lunora/server/drizzle",serverTypes:"@lunora/server/types",values:"@lunora/values"},ft=/^[A-Za-z_$][\w$]*$/u,
|
|
47
|
+
`,ae=(e=!1)=>e?{client:"lunorash/client",do:"lunorash/do",flags:"lunorash/flags",server:"lunorash/server",serverDataModel:"lunorash/server/data-model",serverDrizzle:"lunorash/server/drizzle",serverTypes:"lunorash/server/types",values:"lunorash/values"}:{client:"@lunora/client",do:"@lunora/do",flags:"@lunora/flags",server:"@lunora/server",serverDataModel:"@lunora/server/data-model",serverDrizzle:"@lunora/server/drizzle",serverTypes:"@lunora/server/types",values:"@lunora/values"},ft=/^[A-Za-z_$][\w$]*$/u,_n=/^[\w./-]+$/u,b=(e,t)=>{if(!ft.test(e))throw new Z("INTERNAL",`@lunora/codegen: ${t} is not a valid JS identifier: ${JSON.stringify(e)}`)},He=e=>e.charAt(0).toUpperCase()+e.slice(1),q=e=>ft.test(e)?e:JSON.stringify(e),X=e=>e==="__proto__"?`[${JSON.stringify(e)}]`:q(e),Dn={any:"unknown",bigint:"bigint",boolean:"boolean",bytes:"ArrayBuffer",date:"number",geoPoint:"{ lat: number; lng: number }",null:"null",number:"number",storage:"string",string:"string",timestamp:"number"},Pn=e=>{if(e===void 0)return"unknown";if(!pt.test(e))throw new Z("INTERNAL",`@lunora/codegen: v.literal() argument is not a parseable string/number/boolean/null literal: ${JSON.stringify(e)}`);return e},A=e=>{const t=Dn[e.kind];if(t!==void 0)return t;switch(e.kind){case"array":return`Array<${e.inner?A(e.inner):"unknown"}>`;case"from":return e.tsType??"unknown";case"id":{const n=e.tableName??"_unknown_";return b(n,"v.id() table name"),`Id<"${n}">`}case"literal":return Pn(e.literalValue);case"object":return e.shape?`{ ${Object.entries(e.shape).map(([r,o])=>bt(r,o)).join("; ")} }`:"Record<string, unknown>";case"optional":return`${e.inner?A(e.inner):"unknown"} | undefined`;case"record":{const n=e.keyType?A(e.keyType):"string",r=e.valueType?A(e.valueType):"unknown";return`Record<${n}, ${r}>`}case"union":return e.members&&e.members.length>0?e.members.map(n=>A(n)).join(" | "):"never";default:return"unknown"}},bt=(e,t)=>{const n=q(e);if(t.kind==="optional"){const r=t.inner?A(t.inner):"unknown";return`${n}?: ${r}`}return`${n}: ${A(t)}`},xe=e=>{const t=Object.entries(e);return t.length===0?"{}":`{ ${t.map(([n,r])=>bt(n,r)).join("; ")} }`},yt=e=>e.kind==="optional"||!!e.column?.hasDefault,se=e=>e.kind==="optional"&&e.inner?e.inner:e,Mn=e=>{b(e.name,"table name");const t=Object.entries(e.shape).map(([r,o])=>{const s=se(o),i=A(s),a=q(r);return yt(o)?` ${a}?: ${i};`:` ${a}: ${i};`}).join(`
|
|
48
48
|
`),n=t?`
|
|
49
49
|
${t}
|
|
50
50
|
`:"";return`export interface Insert_${e.name} {
|
|
51
51
|
_id?: Id<"${e.name}">;
|
|
52
|
-
_creationTime?: number;${n}}`},Je="schema",to=e=>{for(const u of e.tables)b(u.name,"table name");const t=e.tables.map(u=>`"${u.name}"`).join(" | ")||"never",n=e.tables.filter(u=>u.extensionKey===void 0).map(u=>`"${u.name}"`).join(" | ")||"never",r=e.tables.map(u=>{const l=Object.entries(u.shape).map(([x,k])=>{const
|
|
52
|
+
_creationTime?: number;${n}}`},Je="schema",to=e=>{for(const u of e.tables)b(u.name,"table name");const t=e.tables.map(u=>`"${u.name}"`).join(" | ")||"never",n=e.tables.filter(u=>u.extensionKey===void 0).map(u=>`"${u.name}"`).join(" | ")||"never",r=e.tables.map(u=>{const l=Object.entries(u.shape).map(([x,k])=>{const T=q(x);if(k.kind==="optional"){const N=k.inner?A(k.inner):"unknown";return` ${T}?: ${N};`}return` ${T}: ${A(k)};`}).join(`
|
|
53
53
|
`),y=l?`
|
|
54
54
|
${l}
|
|
55
55
|
`:"",R=u.commitOrdered===!0?`
|
|
@@ -62,14 +62,14 @@ ${l}
|
|
|
62
62
|
`),i=e.tables.map(u=>{const l=u.searchIndexes.map(y=>JSON.stringify(y.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
63
63
|
`),a=e.tables.map(u=>{const l=u.rankIndexes.map(y=>JSON.stringify(y.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
64
64
|
`),c=e.tables.map(u=>{const l=u.shardMode==="global"?"":(u.geoIndexes??[]).map(y=>JSON.stringify(y.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
65
|
-
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",p=e.tables.map(u=>
|
|
65
|
+
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",p=e.tables.map(u=>Mn(u)).join(`
|
|
66
66
|
|
|
67
67
|
`),m=e.tables.map(u=>` ${u.name}: Insert_${u.name};`).join(`
|
|
68
|
-
`),w=e.tables.map(u=>{const l=u.relations.map(y=>(b(y.table,"relation target table"),` ${
|
|
68
|
+
`),w=e.tables.map(u=>{const l=u.relations.map(y=>(b(y.table,"relation target table"),` ${q(y.name)}: ${y.kind==="one"?"OneRelation":"ManyRelation"}<"${y.table}">;`)).join(`
|
|
69
69
|
`);return l?` ${u.name}: {
|
|
70
70
|
${l}
|
|
71
71
|
};`:` ${u.name}: {};`}).join(`
|
|
72
|
-
`);return
|
|
72
|
+
`);return E(`${S}export type TableName = ${t};
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* The tables **this app declared** — every {@link TableName} except those an add-on
|
|
@@ -161,8 +161,8 @@ export interface Relations {
|
|
|
161
161
|
${w}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
`,Je)},
|
|
165
|
-
`);return` ${
|
|
164
|
+
`,Je)},Fn=/import\("(?<spec>(?:\.\.?\/)*_generated\/[^"]+)"\)/gu,wt=/^(?:\.\.?\/)*_generated\//u,kt=/\.[A-Za-z]\w*$/u,Bn=e=>e.replaceAll(Fn,(t,n)=>{const r=n.replace(wt,"./");return`import("${kt.test(r)?r:`${r}.js`}")`}),qn=/import\("(?<spec>[^"]+)"\)/gu,it="node_modules/",jn=/^@types\//u,Wn=e=>e.replaceAll(qn,(t,n)=>{const r=n.lastIndexOf(it);if(r===-1||r>0&&n[r-1]!=="/")return t;const o=n.slice(r+it.length);return o===""||jn.test(o)?t:`import("${o}")`}),Un=/import\("(?<spec>\.\.?\/[^"]+)"\)/gu,Kn=/^(?:\.\.?\/)+/u,Qn=e=>{const t=[];for(const n of e.split("/"))if(!(n===""||n===".")){if(n===".."&&t.length>0&&t.at(-1)!==".."){t.pop();continue}t.push(n)}return t.join("/")},Vn=(e,t)=>e.replaceAll(Un,(n,r)=>{if(wt.test(r.replace(Kn,"")))return n;const o=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",i=`../${Qn(`${o}/${r}`)}`;return`import("${kt.test(i)?i:`${i}.js`}")`}),E=(e,t)=>Bn(Vn(Wn(e),t)),Hn=["client","do","errors","flags","observability","platform","ratelimit","runtime","server","values"],Gn=new RegExp(String.raw`import\("@lunora/(?<pkg>${Hn.join("|")})(?<subpath>/[^"]*)?"\)`,"gu"),Jn={flags:new Set(["/web"]),platform:new Set},xt=(e,t)=>t?e.replaceAll(Gn,(n,r,o)=>{const s=Jn[r];return o&&s&&!s.has(o)?n:`import("lunorash/${r}${o??""}")`}):e,ze=e=>["Doc","Id"].filter(t=>new RegExp(String.raw`(?<![.$\w])${t}<`,"u").test(e)),vt=e=>e.output===void 0||e.output.kind==="any"||e.kind==="stream"?e.returnType:A(e.output),Ye=e=>{const t=new Map;for(const n of e){const r=t.get(n.filePath)??[];r.push(n),t.set(n.filePath,r)}return[...t.entries()].toSorted(([n],[r])=>n.localeCompare(r))},lt=e=>{const t=([n,r])=>{const o=r.toSorted((s,i)=>s.exportName.localeCompare(i.exportName)).map(s=>{const i=E(xe(s.args),s.filePath),a=E(vt(s),s.filePath);return` ${s.exportName}: FunctionReference<"${s.kind}", ${i}, ${a}>;`}).join(`
|
|
165
|
+
`);return` ${q($(n))}: {
|
|
166
166
|
${o}
|
|
167
167
|
};`};return Ye(e).map(n=>t(n)).join(`
|
|
168
168
|
`)},zn=(e,t)=>{if(e.length===0&&t.length===0)return{block:"",importLine:""};const n=[];let r="";if(e.length>0&&(r+="\n/** Params type carried by a `defineWorkflow` definition (its phantom `__params`). */\ntype WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params } ? (unknown extends Params ? Record<string, unknown> : Params) : Record<string, unknown>;\n"),r+=`
|
|
@@ -207,8 +207,8 @@ ${i}
|
|
|
207
207
|
*/
|
|
208
208
|
const lunoraAgentRuntimeFunctions = agentComponent().functions;
|
|
209
209
|
`}},er=(e,t)=>{if(!e)return{importLine:"",lines:"",prelude:""};const n=t.find(r=>$(r.filePath)==="sandbox"&&r.exportName==="invoke");if(n)throw new Z("INTERNAL",`@lunora/codegen: "sandbox:invoke" is reserved for the batteries-included sandbox tool dispatcher (browserTool/containerTool) — rename the "invoke" export in ${n.filePath}`);return{importLine:`import { sandboxComponent } from "@lunora/agent/component";
|
|
210
|
-
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},tr=(e,t)=>{if(e.length===0)return[];const n=Rt(t),r=[{args:{key:{kind:"string"},limit:{inner:{kind:"number"},kind:"optional"}},exportName:"agentMessages",filePath:"agents",kind:"query",returnType:"Record<string, unknown>[]"},{args:{decision:{kind:"union",members:[{kind:"literal",literalValue:'"approve"'},{kind:"literal",literalValue:'"reject"'}]},instanceId:{kind:"string"},note:{inner:{kind:"string"},kind:"optional"},threadKey:{kind:"string"},toolCallId:{kind:"string"}},exportName:"agentResolveApproval",filePath:"agents",kind:"mutation",returnType:"{ resolved: boolean }"},{args:{agent:{kind:"string"},input:{kind:"string"},threadKey:{kind:"string"},title:{inner:{kind:"string"},kind:"optional"}},exportName:"agentRun",filePath:"agents",kind:"mutation",returnType:"{ id: string; threadKey: string }"},{args:{key:{kind:"string"}},exportName:"agentState",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"},{args:{key:{kind:"string"}},exportName:"agentThread",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"}];for(const o of e)o.voice&&r.push({args:{threadKey:{kind:"string"}},exportName:`${o.exportName}Voice`,filePath:"agents",kind:"stream",returnType:"Record<string, unknown>"});return r.filter(o=>!n.has(o.exportName))},nr=(e,t)=>{if(e.length===0)return[];const n=new Set(t.filter(r=>$(r.filePath)==="mutators").map(r=>r.exportName));return e.filter(r=>!n.has(r.exportName)).map(r=>({args:r.args,exportName:r.exportName,filePath:r.filePath,kind:"mutation",returnType:r.returnType}))},rr=e=>{const t=e.filter(i=>i.stream);if(t.length===0)return{block:"",body:""};const n=Ye(t),r=n.map(([i,a])=>{const c=a.map(d=>{const p=
|
|
211
|
-
`);return` ${
|
|
210
|
+
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},tr=(e,t)=>{if(e.length===0)return[];const n=Rt(t),r=[{args:{key:{kind:"string"},limit:{inner:{kind:"number"},kind:"optional"}},exportName:"agentMessages",filePath:"agents",kind:"query",returnType:"Record<string, unknown>[]"},{args:{decision:{kind:"union",members:[{kind:"literal",literalValue:'"approve"'},{kind:"literal",literalValue:'"reject"'}]},instanceId:{kind:"string"},note:{inner:{kind:"string"},kind:"optional"},threadKey:{kind:"string"},toolCallId:{kind:"string"}},exportName:"agentResolveApproval",filePath:"agents",kind:"mutation",returnType:"{ resolved: boolean }"},{args:{agent:{kind:"string"},input:{kind:"string"},threadKey:{kind:"string"},title:{inner:{kind:"string"},kind:"optional"}},exportName:"agentRun",filePath:"agents",kind:"mutation",returnType:"{ id: string; threadKey: string }"},{args:{key:{kind:"string"}},exportName:"agentState",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"},{args:{key:{kind:"string"}},exportName:"agentThread",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"}];for(const o of e)o.voice&&r.push({args:{threadKey:{kind:"string"}},exportName:`${o.exportName}Voice`,filePath:"agents",kind:"stream",returnType:"Record<string, unknown>"});return r.filter(o=>!n.has(o.exportName))},nr=(e,t)=>{if(e.length===0)return[];const n=new Set(t.filter(r=>$(r.filePath)==="mutators").map(r=>r.exportName));return e.filter(r=>!n.has(r.exportName)).map(r=>({args:r.args,exportName:r.exportName,filePath:r.filePath,kind:"mutation",returnType:r.returnType}))},rr=e=>{const t=e.filter(i=>i.stream);if(t.length===0)return{block:"",body:""};const n=Ye(t),r=n.map(([i,a])=>{const c=a.map(d=>{const p=E(d.chunkType??"unknown",d.filePath),m=E(xe(d.searchParams),d.filePath),w=E(xe(d.params),d.filePath);return` ${q(d.exportName)}: HttpStreamRef<${p}, ${m}, ${w}>;`}).join(`
|
|
211
|
+
`);return` ${q($(i))}: {
|
|
212
212
|
${c}
|
|
213
213
|
};`}).join(`
|
|
214
214
|
`),o=n.map(([i,a])=>{const c=a.map(d=>` ${X(d.exportName)}: { method: ${JSON.stringify(d.method)}, path: ${JSON.stringify(d.path)} },`).join(`
|
|
@@ -232,7 +232,7 @@ import type { ${l.join(", ")} } from "./dataModel.js";
|
|
|
232
232
|
${p}
|
|
233
233
|
`:"",x=m?`
|
|
234
234
|
${m}
|
|
235
|
-
`:"",k=zn(i,t),
|
|
235
|
+
`:"",k=zn(i,t),T=`export interface ApiTypes {${R}}
|
|
236
236
|
|
|
237
237
|
export const api = anyApi as unknown as ApiTypes;
|
|
238
238
|
|
|
@@ -240,10 +240,10 @@ export const api = anyApi as unknown as ApiTypes;
|
|
|
240
240
|
export interface InternalApiTypes {${x}}
|
|
241
241
|
|
|
242
242
|
export const internal = anyApi as unknown as InternalApiTypes;
|
|
243
|
-
${k.block}${w.block}`,
|
|
243
|
+
${k.block}${w.block}`,N=[...T.includes("FunctionReference<")?["FunctionReference"]:[],...w.block===""?[]:["HttpStreamRef"]],D=N.length>0?`import type { ${N.join(", ")} } from "${a.client}";
|
|
244
244
|
`:"";return xt(`${S}import { anyApi } from "${a.client}";
|
|
245
245
|
${D}${k.importLine}${y}
|
|
246
|
-
${
|
|
246
|
+
${T}`,s)},ro=e=>e?`${S}import { createSeedClient as createSeedClientBase } from "@lunora/seed";
|
|
247
247
|
import type { SeedClient, SeedClientOptions } from "@lunora/seed";
|
|
248
248
|
|
|
249
249
|
import schema from "../schema.js";
|
|
@@ -260,7 +260,7 @@ import type { InsertModel } from "./dataModel.js";
|
|
|
260
260
|
* const { posts } = await seed.posts((x) => x([10, 20]));
|
|
261
261
|
*/
|
|
262
262
|
export const createSeedClient = (options?: SeedClientOptions): SeedClient<InsertModel> => createSeedClientBase<InsertModel>(schema, options);
|
|
263
|
-
`:"",oo=(e,t,n=!1)=>{if(e.length===0||!t)return"";const r=ae(n),o=c=>c.table===void 0?"Row":`Doc<${JSON.stringify(c.table)}> & Row`,s=e.map(c=>{b(c.exportName,"shape export name");const d=o(c),p=
|
|
263
|
+
`:"",oo=(e,t,n=!1)=>{if(e.length===0||!t)return"";const r=ae(n),o=c=>c.table===void 0?"Row":`Doc<${JSON.stringify(c.table)}> & Row`,s=e.map(c=>{b(c.exportName,"shape export name");const d=o(c),p=E(xe(c.args),c.filePath),m=Object.keys(c.args).length>0,w=m?` args: ${p};`:` args?: ${p};`,u=m?`(args: ${p}) => void`:`(args?: ${p}) => void`,l=`${c.exportName}CollectionOptions`;return`/** Options for the \`${c.exportName}\` shape binding. */
|
|
264
264
|
export interface ${He(l)} {
|
|
265
265
|
${w}
|
|
266
266
|
/**
|
|
@@ -321,14 +321,35 @@ ${s}
|
|
|
321
321
|
throw new LunoraError("FUNCTION_NOT_FOUND", \`function not registered: \${functionPath}\`);
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
+
// A mutation is routed through the caller's own \`ctx.runMutation\` rather than
|
|
325
|
+
// invoked directly, so \`createCaller(ctx).ns.someMutation()\` gets exactly what
|
|
326
|
+
// \`ctx.runMutation(api.ns.someMutation)\` gets: the BEGIN/COMMIT span (or the
|
|
327
|
+
// enclosing one, when the caller is already inside a transaction), the jobs it
|
|
328
|
+
// schedules held until that span commits, and the deferred object deletes
|
|
329
|
+
// flushed only once it has. Called straight, a mutation composed from an action
|
|
330
|
+
// or a stream had none of the three — its writes autocommitted one row at a
|
|
331
|
+
// time and its \`ctx.scheduler\` calls dispatched immediately, so a mid-handler
|
|
332
|
+
// throw left the earlier writes durable and the job already enqueued.
|
|
333
|
+
//
|
|
334
|
+
// The fallback covers a context that is not a shard dispatch (\`runMutation\` is
|
|
335
|
+
// installed by \`buildCtx\` on every kind but a query's TYPE omits it); there is
|
|
336
|
+
// no transaction to join in that case, so a direct call is all there is.
|
|
337
|
+
if (registered.kind === "mutation") {
|
|
338
|
+
const { runMutation } = context as { runMutation?: (reference: { __lunoraRef: string }, args: Record<string, unknown>) => Promise<unknown> };
|
|
339
|
+
|
|
340
|
+
if (typeof runMutation === "function") {
|
|
341
|
+
return (await runMutation.call(context, { __lunoraRef: functionPath }, args ?? {})) as R;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
324
345
|
return (await registered.handler(context, args ?? {})) as R;
|
|
325
|
-
};`,sr=(e,t,n=[],r=[])=>{const o=new Map,s=l=>{o.has(l)||o.set(l,or(l,o.size))};for(const l of e)s(l.filePath);for(const l of t)s(l.filePath);for(const l of n)s(l.filePath);for(const l of r)s(l.filePath);const i=[...o.entries()].map(([l,y])=>{if(!
|
|
346
|
+
};`,sr=(e,t,n=[],r=[])=>{const o=new Map,s=l=>{o.has(l)||o.set(l,or(l,o.size))};for(const l of e)s(l.filePath);for(const l of t)s(l.filePath);for(const l of n)s(l.filePath);for(const l of r)s(l.filePath);const i=[...o.entries()].map(([l,y])=>{if(!_n.test(l))throw new Z("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(l)}`);return`import * as ${y} from "../${l}.js";`}).join(`
|
|
326
347
|
`),a=e.map(l=>` "${$(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
327
348
|
`),c=t.map(l=>` ${JSON.stringify(l.id)}: ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredDataMigration,`).join(`
|
|
328
349
|
`),d=n.map(l=>` "${$(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
329
350
|
`),p=r.map(l=>` "${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredShape,`).join(`
|
|
330
351
|
`),m=n.map(l=>`${$(l.filePath)}:${l.exportName}`),w=[a,d].filter(l=>l.length>0).join(`
|
|
331
|
-
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const y=
|
|
352
|
+
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const y=En(l.args);return y===void 0?void 0:`installCompiledValidatorMap(${o.get(l.filePath)??""}.${l.exportName}.args, ${y});`}).filter(l=>l!==void 0).join(`
|
|
332
353
|
`);return{dispatchBody:w.length>0?`
|
|
333
354
|
${w}
|
|
334
355
|
`:"",importBlock:i.length>0?`${i}
|
|
@@ -337,19 +358,19 @@ ${w}
|
|
|
337
358
|
${c}
|
|
338
359
|
`:"",mutatorPaths:m,shapeBody:p.length>0?`
|
|
339
360
|
${p}
|
|
340
|
-
`:""}},ir=e=>{const t=Ye(e),n=t.map(([o,s])=>{const i=s.map(a=>{const c=
|
|
341
|
-
`);return` ${
|
|
361
|
+
`:""}},ir=e=>{const t=Ye(e),n=t.map(([o,s])=>{const i=s.map(a=>{const c=E(xe(a.args),a.filePath),d=c==="{}"?"?":"",p=E(vt(a),a.filePath);return a.kind==="stream"?` ${a.exportName}: (args${d}: ${c}) => Promise<AsyncIterable<${p}>>;`:` ${a.exportName}: (args${d}: ${c}) => Promise<${p}>;`}).join(`
|
|
362
|
+
`);return` ${q($(o))}: {
|
|
342
363
|
${i}
|
|
343
364
|
};`}).join(`
|
|
344
365
|
`);return{implementation:t.map(([o,s])=>{const i=$(o),a=s.map(c=>` ${X(c.exportName)}: (args) => callRegistered(context, "${i}:${c.exportName}", args),`).join(`
|
|
345
366
|
`);return` ${X(i)}: {
|
|
346
367
|
${a}
|
|
347
368
|
},`}).join(`
|
|
348
|
-
`),types:n}},lr=(e,t=[])=>{const n=new Set;for(const r of e.tables)for(const o of Object.values(r.shape)){const s=se(o);s.kind==="storage"&&typeof s.bucket=="string"&&s.bucket!==""&&n.add(s.bucket)}for(const r of t)r!==""&&r!=="default"&&n.add(r);return["default",...[...n].toSorted((r,o)=>r.localeCompare(o))]},ao=({agents:e=[],containers:t=[],env:n,hasAccessFacade:r=!1,hasAi:o=!1,hasAnalytics:s=!1,hasBrowser:i=!1,hasVectors:a=!0,hasFlags:c=!1,hasHyperdrive:d=!1,hasImages:p=!1,hasKv:m=!1,hasNotify:w=!1,hasPayments:u=!1,hasPipelines:l=!1,hasR2sql:y=!1,hasX402:R=!1,identity:x,queues:k=[],schema:
|
|
349
|
-
`:"",
|
|
369
|
+
`),types:n}},lr=(e,t=[])=>{const n=new Set;for(const r of e.tables)for(const o of Object.values(r.shape)){const s=se(o);s.kind==="storage"&&typeof s.bucket=="string"&&s.bucket!==""&&n.add(s.bucket)}for(const r of t)r!==""&&r!=="default"&&n.add(r);return["default",...[...n].toSorted((r,o)=>r.localeCompare(o))]},ao=({agents:e=[],containers:t=[],env:n,hasAccessFacade:r=!1,hasAi:o=!1,hasAnalytics:s=!1,hasBrowser:i=!1,hasVectors:a=!0,hasFlags:c=!1,hasHyperdrive:d=!1,hasImages:p=!1,hasKv:m=!1,hasNotify:w=!1,hasPayments:u=!1,hasPipelines:l=!1,hasR2sql:y=!1,hasX402:R=!1,identity:x,queues:k=[],schema:T,storageRuleBuckets:N=[],useUmbrella:D=!1,workflows:C=[]}={})=>{const f=ae(D),P=lr(T??{tables:[]},N).map(h=>JSON.stringify(h)).join(" | "),ie=o?`import type { LunoraAi } from "@lunora/ai";
|
|
370
|
+
`:"",M=o?`
|
|
350
371
|
readonly ai: LunoraAi;`:"",le=u?`import type { LunoraPayment } from "@lunora/payment";
|
|
351
372
|
`:"",ce=u?`
|
|
352
|
-
readonly payments: LunoraPayment;`:"",
|
|
373
|
+
readonly payments: LunoraPayment;`:"",j=R?`import type { X402Pay } from "@lunora/x402/pay";
|
|
353
374
|
`:"",I=R?`
|
|
354
375
|
readonly x402: X402Pay;`:"",ee=t.length>0?`import type { ContainerAccessor } from "@lunora/container";
|
|
355
376
|
`:"",L=t.length>0?`
|
|
@@ -378,7 +399,7 @@ ${v}`:""}
|
|
|
378
399
|
}
|
|
379
400
|
|
|
380
401
|
/** Alias for {@link CloudflareBindings} — the typed shape of \`env\`. */
|
|
381
|
-
export type Env = CloudflareBindings;`,
|
|
402
|
+
export type Env = CloudflareBindings;`,F=(h,We,Te)=>{const re=Sn.get(h);if(re!==void 0&&re.tier!==Te)throw new Z("INTERNAL",`@lunora/codegen: capability "${h}" declares tier "${re.tier}" in SERVER_CTX_FIELDS but is emitted onto the "${Te}" context — update whichever is wrong.`);return We?re?.field??"":""},de=F("kv",m,"every"),ue=F("analytics",s,"every"),Oe=F("hyperdrive",d,"action"),Ie=F("browser",i,"action"),pe=F("images",p,"action"),V=F("pipelines",l,"action"),H=F("r2sql",y,"action"),W=a&&(T?.vectorIndexes.length??0)>0,G=W?' | "vectors"':"",te=W?`
|
|
382
403
|
readonly vectors: VectorSearch<VectorIndexName>;`:"",J=W?`
|
|
383
404
|
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",ne=W?`import type { VectorSearch, VectorSearchReader } from "${f.server}";
|
|
384
405
|
import type { VectorIndexName } from "./dataModel.js";
|
|
@@ -406,9 +427,9 @@ export interface LunoraWorkflows {
|
|
|
406
427
|
${C.map(h=>` get(name: ${JSON.stringify(h.exportName)}): WorkflowHandle<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${h.exportName}>>;`).join(`
|
|
407
428
|
`)}
|
|
408
429
|
}`:"",ve=B?' | "workflows"':"",Re=B?`
|
|
409
|
-
readonly workflows: LunoraWorkflows;`:"",he=k.length>0,
|
|
430
|
+
readonly workflows: LunoraWorkflows;`:"",he=k.length>0,Ee=he?`import type { QueueProducer } from "@lunora/queue";
|
|
410
431
|
import type * as lunoraQueueDefinitions from "../queues.js";
|
|
411
|
-
`:"",
|
|
432
|
+
`:"",_e=he?`
|
|
412
433
|
|
|
413
434
|
/** Message body type carried by a \`defineQueue\` definition (its phantom \`__lunoraBody\`). */
|
|
414
435
|
type QueueBodyOf<Definition> = Definition extends { __lunoraBody?: infer Body } ? (unknown extends Body ? unknown : NonNullable<Body>) : unknown;
|
|
@@ -426,17 +447,17 @@ export interface LunoraAgents {
|
|
|
426
447
|
${e.map(h=>(b(h.exportName,`agent export "${h.exportName}"`),` readonly ${h.exportName}: AgentHandle;`)).join(`
|
|
427
448
|
`)}
|
|
428
449
|
}`:"",$e=me?`
|
|
429
|
-
readonly agents: LunoraAgents;`:"",
|
|
450
|
+
readonly agents: LunoraAgents;`:"",Me=x?`import type { InferIdentity } from "${f.server}";
|
|
430
451
|
import type * as lunoraIdentityContract from "../identity.js";
|
|
431
|
-
`:"",
|
|
452
|
+
`:"",Fe=x?`
|
|
432
453
|
|
|
433
454
|
/** This app's declared identity claim contract (\`defineIdentity\` in \`lunora/identity.ts\`) — the typed shape of \`ctx.auth.getIdentity()\`, the RLS policy \`ctx.auth.identity\`, and the \`authorizeShard\`/\`authorizeFanOut\` identity argument. */
|
|
434
455
|
export type Identity = InferIdentity<typeof lunoraIdentityContract.${x.exportName}>;
|
|
435
456
|
|
|
436
457
|
/** \`ctx.auth\` narrowed so \`getIdentity()\` resolves the declared {@link Identity} contract instead of the untyped claim bag. */
|
|
437
458
|
type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: () => Promise<Identity | null> };`:"",ge=x?' | "auth"':"",fe=x?`
|
|
438
|
-
readonly auth: NarrowedAuth;`:"",Be=x?", Identity":"",
|
|
439
|
-
`:"",
|
|
459
|
+
readonly auth: NarrowedAuth;`:"",Be=x?", Identity":"",qe=n?`import type * as lunoraEnvContract from "../env.js";
|
|
460
|
+
`:"",je=n?`
|
|
440
461
|
|
|
441
462
|
/** This app's declared env contract (\`defineEnv\` in \`lunora/env.ts\`) — the validated, coercion-aware shape of \`ctx.env\`. */
|
|
442
463
|
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",be=n?' | "env"':"",ye=n?"\n /** Validated, typed environment declared by `defineEnv` in `lunora/env.ts` — parsed & coercion-aware config values (`ctx.env.STRIPE_KEY`); a missing or invalid value throws at read time. */\n readonly env: LunoraEnv;":"";return`${S}import { createPolicyDsl, defineMutator as defineMutatorBase, initLunora, v as vBase } from "${f.server}";
|
|
@@ -496,7 +517,7 @@ export type {
|
|
|
496
517
|
} from "${f.serverDataModel}";
|
|
497
518
|
|
|
498
519
|
import type { DataModel, Doc, GeoIndexNamesByTable, Id as IdOfTable, IndexNamesByTable, Insert, InsertModel, RankIndexNamesByTable, Relations, SearchIndexNamesByTable, TableName } from "./dataModel.js";
|
|
499
|
-
${ne}${ie}${le}${
|
|
520
|
+
${ne}${ie}${le}${j}${ee}${Ce}${Ee}${De}${Me}${qe}
|
|
500
521
|
export type { AppTableName, DataModel, Doc, Id, TableName } from "./dataModel.js";
|
|
501
522
|
|
|
502
523
|
/**
|
|
@@ -556,7 +577,7 @@ export interface OrmWriter extends OrmReader {
|
|
|
556
577
|
}
|
|
557
578
|
|
|
558
579
|
/** Storage buckets this schema declares (\`v.storage("name")\`), narrowing \`ctx.storage.bucket(name)\`. */
|
|
559
|
-
export type StorageBucketName = ${P};${Ae}${Le}${
|
|
580
|
+
export type StorageBucketName = ${P};${Ae}${Le}${_e}${Pe}${Fe}${je}
|
|
560
581
|
|
|
561
582
|
/**
|
|
562
583
|
* Project-typed contexts. The base contexts from \`@lunora/server\` are
|
|
@@ -634,7 +655,7 @@ export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${G}$
|
|
|
634
655
|
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${G}${ve}${ge}${be}> {
|
|
635
656
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
636
657
|
readonly orm: OrmWriter;
|
|
637
|
-
readonly storage: StorageBase<StorageBucketName>;${te}${U}${
|
|
658
|
+
readonly storage: StorageBase<StorageBucketName>;${te}${U}${M}${ce}${I}${L}${de}${K}${Q}${Oe}${Ie}${pe}${ue}${V}${H}${ye}${Re}${Se}${$e}${fe}
|
|
638
659
|
}
|
|
639
660
|
|
|
640
661
|
/**
|
|
@@ -710,11 +731,11 @@ export const v = vBase as unknown as Omit<typeof vBase, "id"> & {
|
|
|
710
731
|
id: <T extends TableName>(table: T) => ColumnValidator<IdOfTable<T>, IdOfTable<T>>;
|
|
711
732
|
};
|
|
712
733
|
`},cr=e=>{const t={connect:[],disconnect:[],init:[],reactor:[]};for(const n of e)n.lifecycle&&t[n.lifecycle].push(`${$(n.filePath)}:${n.exportName}`);return t},so=e=>{const{agents:t=[],functions:n,migrations:r=[],mutators:o=[],shapes:s=[],useUmbrella:i=!1,usesSandbox:a=!1}=e,c=n.length>0,d=ae(i),{dispatchBody:p,importBlock:m,installBlock:w,migrationBody:u,mutatorPaths:l,shapeBody:y}=sr(n,r,o,s),R=Zn(t,n),x=er(a,n),k=[R.lines,x.lines].filter(v=>v.length>0).join(`
|
|
713
|
-
`);let
|
|
734
|
+
`);let T=p;k.length>0&&(T=p.length>0?`${p.trimEnd()}
|
|
714
735
|
${k}
|
|
715
736
|
`:`
|
|
716
737
|
${k}
|
|
717
|
-
`);const
|
|
738
|
+
`);const N=cr(n),D=s.length>0?`import type { RegisteredShape } from "${d.server}";
|
|
718
739
|
`:"",C=s.length>0?`
|
|
719
740
|
/**
|
|
720
741
|
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
@@ -738,11 +759,11 @@ export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${l.map(v=>JSO
|
|
|
738
759
|
* parser as a zero-allocation fast path; anything it can't model is deferred.
|
|
739
760
|
*/
|
|
740
761
|
${w}
|
|
741
|
-
`:"",
|
|
742
|
-
${
|
|
743
|
-
`:"",ce=
|
|
744
|
-
${
|
|
745
|
-
`:"",
|
|
762
|
+
`:"",M=ir(n),le=M.types?`
|
|
763
|
+
${M.types}
|
|
764
|
+
`:"",ce=M.implementation?`
|
|
765
|
+
${M.implementation}
|
|
766
|
+
`:"",j=ze(M.types),I=j.length>0?`import type { ${j.join(", ")} } from "./dataModel.js";
|
|
746
767
|
`:"",ee=c?"context":"_context",L=c?`${ar}
|
|
747
768
|
|
|
748
769
|
`:"";return xt(`${S}${m}${R.importLine}${x.importLine}${P}${D}import { LunoraError } from "${d.server}";
|
|
@@ -778,13 +799,18 @@ export interface RegisteredLunoraFunction {
|
|
|
778
799
|
lifecycle?: "connect" | "disconnect" | "init" | "reactor";
|
|
779
800
|
/** \`"internal"\` functions are rejected on the external RPC path; absence === public. */
|
|
780
801
|
visibility?: "internal" | "public";
|
|
802
|
+
/**
|
|
803
|
+
* \`.x402({ price })\` tag on a paid public procedure. The origin worker
|
|
804
|
+
* paywalls it; the shard refuses to subscribe it (\`isPaidFunction\`).
|
|
805
|
+
*/
|
|
806
|
+
x402?: { readonly price: number | string };
|
|
781
807
|
}
|
|
782
808
|
${R.prelude}${x.prelude}
|
|
783
809
|
/**
|
|
784
810
|
* Static dispatch table. The key matches the \`__lunoraRef\` the client
|
|
785
811
|
* emits (\`api[namespace][fn].__lunoraRef === "namespace:fn"\`).
|
|
786
812
|
*/
|
|
787
|
-
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${
|
|
813
|
+
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${T}};
|
|
788
814
|
${ie}${C}${f}
|
|
789
815
|
/**
|
|
790
816
|
* Lifecycle manifest: the function paths the generated ShardDO dispatches when a
|
|
@@ -796,10 +822,10 @@ ${ie}${C}${f}
|
|
|
796
822
|
* anonymous — all via system dispatch.
|
|
797
823
|
*/
|
|
798
824
|
export const LUNORA_LIFECYCLE_HOOKS: { connect: readonly string[]; disconnect: readonly string[]; init: readonly string[]; reactor: readonly string[] } = {
|
|
799
|
-
connect: [${
|
|
800
|
-
disconnect: [${
|
|
801
|
-
init: [${
|
|
802
|
-
reactor: [${
|
|
825
|
+
connect: [${N.connect.map(v=>JSON.stringify(v)).join(", ")}],
|
|
826
|
+
disconnect: [${N.disconnect.map(v=>JSON.stringify(v)).join(", ")}],
|
|
827
|
+
init: [${N.init.map(v=>JSON.stringify(v)).join(", ")}],
|
|
828
|
+
reactor: [${N.reactor.map(v=>JSON.stringify(v)).join(", ")}],
|
|
803
829
|
};
|
|
804
830
|
|
|
805
831
|
/**
|
|
@@ -899,7 +925,7 @@ const aiStub: LunoraAi = {
|
|
|
899
925
|
const ${e} = {
|
|
900
926
|
${s}
|
|
901
927
|
}${r};
|
|
902
|
-
`},
|
|
928
|
+
`},_={build:"",configField:"",contextField:"",importLines:[],stub:""},wr=e=>e?{build:`
|
|
903
929
|
const kvBinding = config.kv?.(env) ?? (env as Record<string, unknown>).KV;
|
|
904
930
|
// KV is not this shard's SQLite, so nothing appends a \`__cdc_log\` entry
|
|
905
931
|
// when a value changes — a subscription that read one can never be proven
|
|
@@ -913,24 +939,24 @@ ${s}
|
|
|
913
939
|
]);
|
|
914
940
|
`,configField:`
|
|
915
941
|
kv?: (env: Record<string, unknown>) => KVNamespaceLike;`,contextField:`
|
|
916
|
-
kv,`,importLines:['import type { Kv, KVNamespaceLike } from "@lunora/bindings/kv";','import { createKv } from "@lunora/bindings/kv";'],stub:O("kvStub: Kv",'throw new Error("ctx.kv: no KV binding found. Add a \\`kv_namespaces\\` binding (env.KV) to wrangler.jsonc, or pass \\`kv\\` to createShardDO().");',["delete","get","getRaw","getWithMetadata","list","put"])}:
|
|
942
|
+
kv,`,importLines:['import type { Kv, KVNamespaceLike } from "@lunora/bindings/kv";','import { createKv } from "@lunora/bindings/kv";'],stub:O("kvStub: Kv",'throw new Error("ctx.kv: no KV binding found. Add a \\`kv_namespaces\\` binding (env.KV) to wrangler.jsonc, or pass \\`kv\\` to createShardDO().");',["delete","get","getRaw","getWithMetadata","list","put"])}:_,kr=(e,t)=>e?{build:`
|
|
917
943
|
const flags: import("${t}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
918
944
|
provider: () => config.flags?.(env),
|
|
919
945
|
targetingKey: () => flagsConfig.identify?.({ identity: identity ?? null, userId: userId ?? null }),
|
|
920
946
|
});
|
|
921
947
|
`,configField:`
|
|
922
948
|
flags?: (env: Record<string, unknown>) => import("${t}").Provider;`,contextField:`
|
|
923
|
-
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:
|
|
949
|
+
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:_,xr=e=>e?{build:`
|
|
924
950
|
const { notify, push } = createNotify(notifyConfig, env, { log, metrics });
|
|
925
951
|
`,configField:"",contextField:`
|
|
926
952
|
notify,
|
|
927
|
-
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:
|
|
953
|
+
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:_,vr=e=>e?{build:`
|
|
928
954
|
const envConfig = lunoraEnvContract.${e.exportName}(env);
|
|
929
955
|
`,configField:"",contextField:`
|
|
930
|
-
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:
|
|
956
|
+
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:_,Rr=e=>e?{build:`
|
|
931
957
|
const access = accessFacade(identity, userId);
|
|
932
958
|
`,configField:"",contextField:`
|
|
933
|
-
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:
|
|
959
|
+
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:_,Sr=(e,t,n)=>{if(!t)return{constant:"",evaluateOverride:"",subscriptionOverride:""};const r=a=>`
|
|
934
960
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
935
961
|
const flags: import("${n}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
936
962
|
provider: () => config.flags?.(env),
|
|
@@ -997,20 +1023,20 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
997
1023
|
const analytics: AnalyticsClient = analyticsBinding ? createAnalytics(analyticsBinding as AnalyticsEngineDatasetLike) : analyticsStub;
|
|
998
1024
|
`,configField:`
|
|
999
1025
|
analytics?: (env: Record<string, unknown>) => AnalyticsEngineDatasetLike;`,contextField:`
|
|
1000
|
-
analytics,`,importLines:['import type { AnalyticsClient, AnalyticsEngineDatasetLike } from "@lunora/bindings/analytics";','import { createAnalytics } from "@lunora/bindings/analytics";'],stub:O("analyticsStub: AnalyticsClient",'throw new Error("ctx.analytics: no Analytics Engine binding found. Add an \\`analytics_engine_datasets\\` binding (env.ANALYTICS) to wrangler.jsonc, or pass \\`analytics\\` to createShardDO().");',["track","writeDataPoint"],{sync:["track","writeDataPoint"]})}:
|
|
1026
|
+
analytics,`,importLines:['import type { AnalyticsClient, AnalyticsEngineDatasetLike } from "@lunora/bindings/analytics";','import { createAnalytics } from "@lunora/bindings/analytics";'],stub:O("analyticsStub: AnalyticsClient",'throw new Error("ctx.analytics: no Analytics Engine binding found. Add an \\`analytics_engine_datasets\\` binding (env.ANALYTICS) to wrangler.jsonc, or pass \\`analytics\\` to createShardDO().");',["track","writeDataPoint"],{sync:["track","writeDataPoint"]})}:_,Tr=e=>e?{build:`
|
|
1001
1027
|
const imagesBinding = config.images?.(env) ?? (env as Record<string, unknown>).IMAGES;
|
|
1002
1028
|
const images: Images = imagesBinding ? createImages({ binding: imagesBinding as ImagesBindingLike }) : imagesStub;
|
|
1003
1029
|
`,configField:`
|
|
1004
1030
|
images?: (env: Record<string, unknown>) => ImagesBindingLike;`,contextField:`
|
|
1005
|
-
images,`,importLines:['import type { Images, ImagesBindingLike } from "@lunora/bindings/images";','import { createImages } from "@lunora/bindings/images";'],stub:O("imagesStub: Images",'throw new Error("ctx.images: no Images binding found. Add an \\`images\\` binding (env.IMAGES) to wrangler.jsonc, or pass \\`images\\` to createShardDO().");',["info","transform"])}:
|
|
1031
|
+
images,`,importLines:['import type { Images, ImagesBindingLike } from "@lunora/bindings/images";','import { createImages } from "@lunora/bindings/images";'],stub:O("imagesStub: Images",'throw new Error("ctx.images: no Images binding found. Add an \\`images\\` binding (env.IMAGES) to wrangler.jsonc, or pass \\`images\\` to createShardDO().");',["info","transform"])}:_,Nr=e=>e?{build:`
|
|
1006
1032
|
const sql: SqlClient = config.sql ? config.sql(env) : sqlStub;
|
|
1007
1033
|
`,configField:`
|
|
1008
1034
|
sql?: (env: Record<string, unknown>) => SqlClient;`,contextField:`
|
|
1009
|
-
sql,`,importLines:['import type { SqlClient } from "@lunora/hyperdrive";'],stub:O("sqlStub: SqlClient",'throw new Error("ctx.sql: provide a \\`sql\\` config thunk that builds a SqlClient from your driver, e.g. \\`sql: (env) => fromPostgresJs(postgres(env.HYPERDRIVE.connectionString))\\`.");',["query"])}:
|
|
1035
|
+
sql,`,importLines:['import type { SqlClient } from "@lunora/hyperdrive";'],stub:O("sqlStub: SqlClient",'throw new Error("ctx.sql: provide a \\`sql\\` config thunk that builds a SqlClient from your driver, e.g. \\`sql: (env) => fromPostgresJs(postgres(env.HYPERDRIVE.connectionString))\\`.");',["query"])}:_,Ar=e=>e?{build:`
|
|
1010
1036
|
const browser: Browser = config.browser ? config.browser(env) : browserStub;
|
|
1011
1037
|
`,configField:`
|
|
1012
1038
|
browser?: (env: Record<string, unknown>) => Browser;`,contextField:`
|
|
1013
|
-
browser,`,importLines:['import type { Browser } from "@lunora/browser";'],stub:O("browserStub: Browser","throw new Error(\"ctx.browser: provide a \\`browser\\` config thunk, e.g. \\`browser: (env) => createBrowser({ binding: env.BROWSER, launch })\\` with \\`import { launch } from '@cloudflare/playwright'\\`. Session reuse (connect/sessions) additionally needs those two exports passed the same way.\");",["connect","content","launch","pdf","scrape","screenshot","sessions"])}:
|
|
1039
|
+
browser,`,importLines:['import type { Browser } from "@lunora/browser";'],stub:O("browserStub: Browser","throw new Error(\"ctx.browser: provide a \\`browser\\` config thunk, e.g. \\`browser: (env) => createBrowser({ binding: env.BROWSER, launch })\\` with \\`import { launch } from '@cloudflare/playwright'\\`. Session reuse (connect/sessions) additionally needs those two exports passed the same way.\");",["connect","content","launch","pdf","scrape","screenshot","sessions"])}:_,Or=e=>e?{build:`
|
|
1014
1040
|
const r2sqlEnv = env as Record<string, unknown>;
|
|
1015
1041
|
const r2sqlAccountId = (r2sqlEnv.R2_SQL_ACCOUNT_ID ?? r2sqlEnv.CLOUDFLARE_ACCOUNT_ID) as string | undefined;
|
|
1016
1042
|
const r2sqlToken = r2sqlEnv.R2_SQL_TOKEN as string | undefined;
|
|
@@ -1021,11 +1047,11 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
1021
1047
|
? createR2Sql({ accountId: r2sqlAccountId, apiToken: r2sqlToken, bucket: r2sqlBucket })
|
|
1022
1048
|
: r2sqlStub;
|
|
1023
1049
|
`,configField:`
|
|
1024
|
-
r2sql?: (env: Record<string, unknown>) => R2SqlClient;`,contextField:"",importLines:['import type { R2SqlClient } from "@lunora/bindings/r2sql";','import { createR2Sql } from "@lunora/bindings/r2sql";'],stub:O("r2sqlStub: R2SqlClient",'throw new Error("ctx.r2sql: no R2 SQL credentials found. Set \\`R2_SQL_TOKEN\\`, \\`R2_SQL_ACCOUNT_ID\\` (or \\`CLOUDFLARE_ACCOUNT_ID\\`), and \\`R2_SQL_BUCKET\\` in your env/.dev.vars, or pass an \\`r2sql\\` config thunk to createShardDO().");',["describe","explain","from","query","showDatabases","showTables"],{sync:["from"]})}:
|
|
1050
|
+
r2sql?: (env: Record<string, unknown>) => R2SqlClient;`,contextField:"",importLines:['import type { R2SqlClient } from "@lunora/bindings/r2sql";','import { createR2Sql } from "@lunora/bindings/r2sql";'],stub:O("r2sqlStub: R2SqlClient",'throw new Error("ctx.r2sql: no R2 SQL credentials found. Set \\`R2_SQL_TOKEN\\`, \\`R2_SQL_ACCOUNT_ID\\` (or \\`CLOUDFLARE_ACCOUNT_ID\\`), and \\`R2_SQL_BUCKET\\` in your env/.dev.vars, or pass an \\`r2sql\\` config thunk to createShardDO().");',["describe","explain","from","query","showDatabases","showTables"],{sync:["from"]})}:_,Ir=e=>e?{build:`
|
|
1025
1051
|
const pipelinesBinding = config.pipelines?.(env) ?? (env as Record<string, unknown>).PIPELINES;
|
|
1026
1052
|
const pipelines: PipelineClient = pipelinesBinding ? createPipelines({ binding: pipelinesBinding as PipelineBindingLike }) : pipelinesStub;
|
|
1027
1053
|
`,configField:`
|
|
1028
|
-
pipelines?: (env: Record<string, unknown>) => PipelineBindingLike;`,contextField:"",importLines:['import type { PipelineBindingLike, PipelineClient } from "@lunora/bindings/pipelines";','import { createPipelines } from "@lunora/bindings/pipelines";'],stub:O("pipelinesStub: PipelineClient",'throw new Error("ctx.pipelines: no Pipelines binding found. Add a \\`pipelines\\` binding (env.PIPELINES) to wrangler.jsonc, or pass \\`pipelines\\` to createShardDO().");',["send"])}:
|
|
1054
|
+
pipelines?: (env: Record<string, unknown>) => PipelineBindingLike;`,contextField:"",importLines:['import type { PipelineBindingLike, PipelineClient } from "@lunora/bindings/pipelines";','import { createPipelines } from "@lunora/bindings/pipelines";'],stub:O("pipelinesStub: PipelineClient",'throw new Error("ctx.pipelines: no Pipelines binding found. Add a \\`pipelines\\` binding (env.PIPELINES) to wrangler.jsonc, or pass \\`pipelines\\` to createShardDO().");',["send"])}:_,io=(e,t)=>{if(e.length===0)return"";const n=t?`, ${JSON.stringify(t)}`:"",r=e.map(s=>(b(s.exportName,`container export "${s.exportName}"`),b(s.className,`container class "${s.className}"`),`/** Container DO for the \`${s.exportName}\` definition (binding \`${s.bindingName}\`). */
|
|
1029
1055
|
export class ${s.className} extends LunoraContainer {
|
|
1030
1056
|
public constructor(ctx: ConstructorParameters<typeof LunoraContainer>[0], env: Record<string, unknown>) {
|
|
1031
1057
|
super(ctx, env, ${s.exportName}, "${s.exportName}"${n});
|
|
@@ -1139,7 +1165,7 @@ ${r}
|
|
|
1139
1165
|
const LUNORA_WORKFLOWS: ReadonlyArray<WorkflowBindingSpec> = [
|
|
1140
1166
|
${t}
|
|
1141
1167
|
];
|
|
1142
|
-
`}},
|
|
1168
|
+
`}},Er=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)b(n.exportName,`queue export "${n.exportName}"`),b(n.bindingName,`queue binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}", name: ${JSON.stringify(n.name)} },`).join(`
|
|
1143
1169
|
`);return{build:`
|
|
1144
1170
|
const queues = createQueueContext(env, LUNORA_QUEUES);
|
|
1145
1171
|
`,contextField:`
|
|
@@ -1148,7 +1174,7 @@ ${t}
|
|
|
1148
1174
|
const LUNORA_QUEUES: ReadonlyArray<QueueBindingSpec> = [
|
|
1149
1175
|
${t}
|
|
1150
1176
|
];
|
|
1151
|
-
`}},
|
|
1177
|
+
`}},_r=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)b(n.exportName,`agent export "${n.exportName}"`),b(n.bindingName,`agent binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}"${n.publicRun===!0?", publicRun: true":""} },`).join(`
|
|
1152
1178
|
`);return{build:`
|
|
1153
1179
|
const agents = createAgentContext(env, LUNORA_AGENTS);
|
|
1154
1180
|
`,contextField:`
|
|
@@ -1164,21 +1190,21 @@ const ${e}: ${t} = ${JSON.stringify(r,void 0,4)};
|
|
|
1164
1190
|
protected override ${n}(): ${t} {
|
|
1165
1191
|
return ${e};
|
|
1166
1192
|
}
|
|
1167
|
-
`}),Dr=e=>{if(e.length===0)return{constant:"",override:""};const t={workflows:e.map(n=>({binding:n.bindingName,className:n.className,exportName:n.exportName,name:n.name}))};return St("LUNORA_WORKFLOWS_INFO","WorkflowsResult","workflowsMetadata",t,"/** Read-only declared-workflow metadata (discovered from `lunora/workflows.ts`) served via `__lunora_admin__:listWorkflows` for the studio's workflows view. */")},Pr=e=>{if(e.length===0)return{constant:"",override:""};const t={queues:e.map(n=>({binding:n.bindingName,...n.tuning.deadLetterQueue===void 0?{}:{deadLetterQueue:n.tuning.deadLetterQueue},exportName:n.exportName,mode:n.mode,name:n.name}))};return St("LUNORA_QUEUES_INFO","QueuesResult","queuesMetadata",t,"/** Read-only declared-queue metadata (discovered from `lunora/queues.ts`) served via `__lunora_admin__:listQueues` for the studio's queues view. */")},
|
|
1193
|
+
`}),Dr=e=>{if(e.length===0)return{constant:"",override:""};const t={workflows:e.map(n=>({binding:n.bindingName,className:n.className,exportName:n.exportName,name:n.name}))};return St("LUNORA_WORKFLOWS_INFO","WorkflowsResult","workflowsMetadata",t,"/** Read-only declared-workflow metadata (discovered from `lunora/workflows.ts`) served via `__lunora_admin__:listWorkflows` for the studio's workflows view. */")},Pr=e=>{if(e.length===0)return{constant:"",override:""};const t={queues:e.map(n=>({binding:n.bindingName,...n.tuning.deadLetterQueue===void 0?{}:{deadLetterQueue:n.tuning.deadLetterQueue},exportName:n.exportName,mode:n.mode,name:n.name}))};return St("LUNORA_QUEUES_INFO","QueuesResult","queuesMetadata",t,"/** Read-only declared-queue metadata (discovered from `lunora/queues.ts`) served via `__lunora_admin__:listQueues` for the studio's queues view. */")},Mr=e=>e?{imports:['import type { LunoraDatabaseLike as LunoraPaymentDbLike, LunoraPayment, PaymentsFromContextOptions } from "@lunora/payment";','import { paymentsFromContext } from "@lunora/payment";'],build:`
|
|
1168
1194
|
const payments: LunoraPayment = config.payment
|
|
1169
1195
|
? paymentsFromContext({ auth: { userId: userId ?? null }, db: db as unknown as LunoraPaymentDbLike }, config.payment(env))
|
|
1170
1196
|
: paymentStub;
|
|
1171
1197
|
`,configField:`
|
|
1172
1198
|
payment?: (env: Record<string, unknown>) => PaymentsFromContextOptions;`,contextField:`
|
|
1173
|
-
payments,`,stub:O("paymentStub: LunoraPayment",'throw new Error("ctx.payments: no payment configured. Pass \\`payment\\` to createShardDO().");',["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"],{cast:" as unknown as LunoraPayment",sync:["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"]})}:{build:"",configField:"",contextField:"",imports:[],stub:""},
|
|
1199
|
+
payments,`,stub:O("paymentStub: LunoraPayment",'throw new Error("ctx.payments: no payment configured. Pass \\`payment\\` to createShardDO().");',["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"],{cast:" as unknown as LunoraPayment",sync:["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"]})}:{build:"",configField:"",contextField:"",imports:[],stub:""},Fr=e=>e?{imports:['import type { X402Pay, X402PayConfig } from "@lunora/x402/pay";','import { lazyX402Pay } from "@lunora/x402/pay";'],build:`
|
|
1174
1200
|
const x402: X402Pay = config.x402
|
|
1175
1201
|
? lazyX402Pay(config.x402(env), { getSecret: (name: string) => secrets.get(name) })
|
|
1176
1202
|
: x402Stub;
|
|
1177
1203
|
`,configField:`
|
|
1178
|
-
x402?: (env: Record<string, unknown>) => X402PayConfig;`,stub:O("x402Stub: X402Pay",'throw new Error("ctx.x402: no pay rail configured. Pass \\`x402\\` to createShardDO().");',["fetch"],{cast:" as unknown as X402Pay",sync:["fetch"]})}:{build:"",configField:"",imports:[],stub:""},Br=(e,t,n,r,o)=>["AdvisorProcedure","AdvisoryFinding","DatabaseWriterLike","DataMigrationLike","ExportRow",...r?["FlagsResult"]:[],"ImportShardResult","KeyRange","MaskPoliciesResult","MigrationRunResult","QueryReadScope",...n?["QueuesResult"]:[],"RunShardApplyCdcArgs","RunShardExportArgs","RunShardImportArgs","RunShardMigrationArgs","RlsPoliciesResult","RunShardRankBeforeArgs","RunShardRankPageArgs","RunShardWriteArgs","RunShardWriteResult","SchedulerLike",...o?["SearchBackfillProgress"]:[],"TransactionHeadroomTracker","SchemaLike","ShardDOState","ShardRankPageResult","SqlExec","StorageRulesResult","StudioFeaturesResult","SystemReaderStorageLike","TelemetrySink",...t?["WorkflowsResult"]:[],...e?["WriteHook"]:[]],po=({advisories:e=[],advisorProcedures:t=[],agents:n=[],containers:r=[],env:o,flagKeys:s=[],hasAccessFacade:i=!1,hasAi:a=!1,hasAnalytics:c=!1,hasBrowser:d=!1,hasFlags:p=!1,hasHyperdrive:m=!1,hasImages:w=!1,hasKv:u=!1,hasNotify:l=!1,hasPayments:y=!1,hasPipelines:R=!1,hasR2sql:x=!1,hasX402:k=!1,maskMetadata:
|
|
1204
|
+
x402?: (env: Record<string, unknown>) => X402PayConfig;`,stub:O("x402Stub: X402Pay",'throw new Error("ctx.x402: no pay rail configured. Pass \\`x402\\` to createShardDO().");',["fetch"],{cast:" as unknown as X402Pay",sync:["fetch"]})}:{build:"",configField:"",imports:[],stub:""},Br=(e,t,n,r,o)=>["AdvisorProcedure","AdvisoryFinding","DatabaseWriterLike","DataMigrationLike","ExportRow",...r?["FlagsResult"]:[],"ImportShardResult","KeyRange","MaskPoliciesResult","MigrationRunResult","QueryReadScope",...n?["QueuesResult"]:[],"RunShardApplyCdcArgs","RunShardExportArgs","RunShardImportArgs","RunShardMigrationArgs","RlsPoliciesResult","RunShardRankBeforeArgs","RunShardRankPageArgs","RunShardWriteArgs","RunShardWriteResult","SchedulerLike",...o?["SearchBackfillProgress"]:[],"TransactionHeadroomTracker","SchemaLike","ShardDOState","ShardRankPageResult","SqlExec","StorageRulesResult","StudioFeaturesResult","SystemReaderStorageLike","TelemetrySink",...t?["WorkflowsResult"]:[],...e?["WriteHook"]:[]],po=({advisories:e=[],advisorProcedures:t=[],agents:n=[],containers:r=[],env:o,flagKeys:s=[],hasAccessFacade:i=!1,hasAi:a=!1,hasAnalytics:c=!1,hasBrowser:d=!1,hasFlags:p=!1,hasHyperdrive:m=!1,hasImages:w=!1,hasKv:u=!1,hasNotify:l=!1,hasPayments:y=!1,hasPipelines:R=!1,hasR2sql:x=!1,hasX402:k=!1,maskMetadata:T,mutators:N=[],queues:D=[],rlsMetadata:C,schema:f,schemaSnapshot:P,shapes:ie=[],storageRules:M,studioFeatures:le,useUmbrella:ce=!1,workflows:j=[]})=>{const I=ae(ce),ee=N.length>0,L=ie.length>0,v=P===void 0?"":xn(P),Ae=P===void 0?"":`
|
|
1179
1205
|
/** Structural schema snapshot + its content hash, recorded in the shard's \`__lunora_schema_history\` ledger on cold start so the studio can show a schema-version timeline and diff any two versions. */
|
|
1180
1206
|
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(vn(P))}, json: ${JSON.stringify(v)} };
|
|
1181
|
-
`,
|
|
1207
|
+
`,F=P===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:de,configField:ue,contextField:Oe,stub:Ie}=yr(a),pe=Rr(i),V=wr(u),H=kr(p,I.flags),W=Sr(s,p,I.flags),G=xr(l),te=vr(o),J=$r(c),ne=Tr(w),U=Nr(m),K=Ar(d),Q=Or(x),B=Ir(R),{build:Ce,contextField:Le,importLines:ve,specs:Re}=Er(D),{build:he,contextField:Ee,importLines:_e,specs:Se}=Cr(r,f.jurisdiction),{build:me,contextField:De,importLines:Pe,specs:$e}=Lr(j),{build:Me,contextField:Fe,importLines:ge,specs:fe}=_r(n),{build:Be,configField:qe,contextField:je,imports:be,stub:ye}=Mr(y),{build:Ze,configField:h,imports:We,stub:Te}=Fr(k),re=e,Tt=t,Nt=C??{policies:[],roles:[]},At=T??{columns:[]},Ot=M??{rules:[]},It=le??{analytics:!1,auth:!1,containers:!1,flags:!1,kv:!1,mail:!1,notifications:!1,payments:!1,queues:!1,scheduler:!1,storage:!1,vectors:!1,workflows:!1},{constant:Ct,override:Lt}=Dr(j),{constant:Et,override:_t}=Pr(D),z=f.vectorIndexes.length>0,et=new Set(f.tables.filter(g=>typeof g.shardMode=="object"&&g.shardMode.kind==="shardBy").map(g=>g.name)),Ne=f.vectorIndexes.some(g=>et.has(g.table)),we=f.tables.some(g=>g.shardMode==="global"),Ue=f.tables.some(g=>g.shardMode==="global"&&g.globalBackend==="hyperdrive"),tt=f.tables.some(g=>g.shardMode==="global"&&g.globalBackend!=="hyperdrive"),oe=f.tables.some(g=>g.externalSource!==void 0),nt=f.tables.some(g=>g.memory===!0),Ke=f.tables.some(g=>g.shardMode!=="global"&&g.searchIndexes.length>0);if(tt&&Ue)throw new Z("INTERNAL",'lunora codegen: mixing `.global()` (D1) and `.global({ backend: "hyperdrive" })` tables in one app is not supported yet — use a single global backend.');const Qe=f.tables.length>0,Dt=dr(f),Pt=pr(f),Mt=fr(f),Ft=ur(f),rt=hr(f),ot=Br(z,j.length>0,D.length>0,p,Ke);L&&ot.push("WhereInput");const at=br(we),Bt=L?`
|
|
1182
1208
|
protected override resolveShape(name: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string } | undefined {
|
|
1183
1209
|
const shape = LUNORA_SHAPES[name];
|
|
1184
1210
|
|
|
@@ -1230,17 +1256,17 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
|
|
|
1230
1256
|
|
|
1231
1257
|
return { columns: shape.columns, effectiveWhere, global: isGlobal, table: shape.table };
|
|
1232
1258
|
}
|
|
1233
|
-
`:"",
|
|
1259
|
+
`:"",qt=ee?`
|
|
1234
1260
|
protected override isCustomMutator(functionPath: string): boolean {
|
|
1235
1261
|
return LUNORA_MUTATOR_PATHS.has(functionPath);
|
|
1236
1262
|
}
|
|
1237
|
-
`:"",
|
|
1263
|
+
`:"",jt=L?"\n/** Per-table RLS read policies (hoisted from `.use(rls(...))` chains) the shape resolver AND-merges into each `defineShape` predicate so partial replication honours read policies. */\nconst LUNORA_RLS_READ_REGISTRY = buildRlsReadRegistry(Object.values(LUNORA_FUNCTIONS));\n":"",Wt=L?"assertShapeShardable, ":"",ke=[`import type { ${ot.join(", ")} } from "${I.do}";`,`import { applyCdcChanges, ${Ke?"backfillSearchIndexes, ":""}buildReprojectionMigration, ${nt?"clearMemoryTables, ":""}${Wt}createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, ${oe?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}markUnvouchableReads, ${Ne?"ROOT_SHARD_NAME, ":""}runDataMigration, runShardMigrations, ${at.importFragment}ShardDO as ShardDOBase } from "${I.do}";`,...oe?[`import type { ExternalSourceLike, SourceClientLike, TraceRefLike } from "${I.do}";`]:[],L?`import { asBucketStorage, beginDeferredSchedules, buildRlsReadRegistry, composeShapeReadWhere, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${I.server}";`:`import { asBucketStorage, beginDeferredSchedules, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${I.server}";`];Qe&&ke.push(`import { bindOrm, bindTableFacade } from "${I.server}";`),z&&ke.push('import type { SchemaLike as VectorSchemaLike, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectors, createVectorSyncHook } from "@lunora/bindings/vectors";'),a&&ke.push('import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'),ke.push(...pe.importLines,...V.importLines,...H.importLines,...G.importLines,...te.importLines,...J.importLines,...ne.importLines,...U.importLines,...K.importLines,...Q.importLines,...B.importLines,..._e,...Pe,...ve,...ge,...be,...We,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...ee?["LUNORA_MUTATOR_PATHS"]:[],...L?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const Ut=z?`
|
|
1238
1264
|
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",Kt=tt?`
|
|
1239
1265
|
d1?: (env: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string }) => DatabaseWriterLike | undefined;`:"",Qt=Ue?`
|
|
1240
1266
|
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",Vt=oe?`
|
|
1241
|
-
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",Ht='throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");',Gt='throw new Error("ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().");',Jt='throw new Error("ctx.scheduler: no scheduler configured. Pass `scheduler` to createShardDO().");',zt='throw new Error("ctx.storage: no storage configured. Pass `storage` to createShardDO().");',Yt=we?O("globalDbStub: DatabaseWriterLike",Ht,["aggregate","count","delete","findFirst","findFirstOrThrow","findMany","get","groupBy","insert","normalizeId","patch","query","rank","rankPage","replace"],{sync:["normalizeId","query"]}):"",Xt=z?O("vectorsStub: VectorSearchLike",Gt,["deleteByIds","getByIds","query","upsert","upsertNow"]):"",Zt=
|
|
1267
|
+
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",Ht='throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");',Gt='throw new Error("ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().");',Jt='throw new Error("ctx.scheduler: no scheduler configured. Pass `scheduler` to createShardDO().");',zt='throw new Error("ctx.storage: no storage configured. Pass `storage` to createShardDO().");',Yt=we?O("globalDbStub: DatabaseWriterLike",Ht,["aggregate","count","delete","findFirst","findFirstOrThrow","findMany","get","groupBy","insert","normalizeId","patch","query","rank","rankPage","replace"],{sync:["normalizeId","query"]}):"",Xt=z?O("vectorsStub: VectorSearchLike",Gt,["deleteByIds","getByIds","query","upsert","upsertNow"]):"",Zt=Ne?`
|
|
1242
1268
|
const vectorShardKey = this.currentShardKey();
|
|
1243
|
-
`:"",en=
|
|
1269
|
+
`:"",en=Ne?"namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, ":"",tn=Ne?`, { namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, shardedIndexNames: [${f.vectorIndexes.filter(g=>et.has(g.table)).map(g=>JSON.stringify(g.name)).join(", ")}] }`:"",nn=z?`
|
|
1244
1270
|
let vectors: VectorSearchLike;
|
|
1245
1271
|
let onWrite: WriteHook | undefined;
|
|
1246
1272
|
|
|
@@ -1561,6 +1587,10 @@ ${oe?`
|
|
|
1561
1587
|
protected override isQueryFunction(functionPath: string): boolean {
|
|
1562
1588
|
return LUNORA_FUNCTIONS[functionPath]?.kind === "query";
|
|
1563
1589
|
}
|
|
1590
|
+
|
|
1591
|
+
protected override isPaidFunction(functionPath: string): boolean {
|
|
1592
|
+
return LUNORA_FUNCTIONS[functionPath]?.x402 !== undefined;
|
|
1593
|
+
}
|
|
1564
1594
|
`,gn=Qe?`
|
|
1565
1595
|
const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
|
|
1566
1596
|
${f.tables.map(g=>` facade[${JSON.stringify(g.name)}] = bindTableFacade(db, ${JSON.stringify(g.name)});`).join(`
|
|
@@ -1595,10 +1625,10 @@ const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: strin
|
|
|
1595
1625
|
const LUNORA_TABLE_COLUMNS: Record<
|
|
1596
1626
|
string,
|
|
1597
1627
|
Array<{ bucket?: string; enumValues?: string[]; isStorage?: boolean; name: string; nullable?: boolean; optional: boolean; pk?: boolean; ref?: string; type: string }>
|
|
1598
|
-
> = ${JSON.stringify(
|
|
1628
|
+
> = ${JSON.stringify(Mt,void 0,4)};
|
|
1599
1629
|
|
|
1600
1630
|
/** Storage-key columns per table (\`v.storage(...)\` fields) for the file browser's records↔files join. */
|
|
1601
|
-
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(
|
|
1631
|
+
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(Ft,void 0,4)};
|
|
1602
1632
|
|
|
1603
1633
|
/** Declarative TTL policies (\`.ttl(field, { after? })\`) the DO alarm sweep auto-expires rows for. */
|
|
1604
1634
|
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(rt,void 0,4)};
|
|
@@ -1607,10 +1637,10 @@ const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?
|
|
|
1607
1637
|
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(re,void 0,4)};
|
|
1608
1638
|
|
|
1609
1639
|
/** Every declared procedure (discovered by @lunora/codegen) served via \`__lunora_admin__:getAdvisorProcedures\` — the health map's denominator. */
|
|
1610
|
-
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(
|
|
1640
|
+
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(Tt,void 0,4)};
|
|
1611
1641
|
|
|
1612
1642
|
/** Read-only RLS metadata (policies + roles discovered from \`.use(rls(...))\` chains) served via \`__lunora_admin__:rlsPolicies\` for the studio's RLS inspector. */
|
|
1613
|
-
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(
|
|
1643
|
+
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(Nt,void 0,4)};
|
|
1614
1644
|
|
|
1615
1645
|
/** Read-only masking metadata (table + column + strategy discovered from \`.use(mask(...))\` chains) served via \`__lunora_admin__:maskPolicies\` for the studio's data-browser mask preview. */
|
|
1616
1646
|
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(At,void 0,4)};
|
|
@@ -1620,7 +1650,7 @@ const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(Ot,void 0,4)};
|
|
|
1620
1650
|
|
|
1621
1651
|
/** Which optional package-backed features this app wires up (discovered from imports / \`ctx.*\` reads / schema signals) served via \`__lunora_admin__:studioFeatures\` so the studio hides nav pages whose package isn't enabled. */
|
|
1622
1652
|
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(It,void 0,4)};
|
|
1623
|
-
${Ae}${W.constant}${
|
|
1653
|
+
${Ae}${W.constant}${jt}${Ct}${Et}${Se}${$e}${Re}${fe}
|
|
1624
1654
|
export interface ShardDOConfig {
|
|
1625
1655
|
/** Opt into change-data-capture: records a post-image to \`__cdc_log\` on every write (backs streaming export + replay-PITR). */
|
|
1626
1656
|
cdc?: boolean;
|
|
@@ -1634,9 +1664,9 @@ export interface ShardDOConfig {
|
|
|
1634
1664
|
observability?: (env: Record<string, unknown>) => TelemetrySink | undefined;
|
|
1635
1665
|
/** \`unknown\` because \`@lunora/scheduler\`'s \`Scheduler\` is not assignable to \`SchedulerLike\`; the shard casts it. */
|
|
1636
1666
|
scheduler?: (env: Record<string, unknown>) => unknown;
|
|
1637
|
-
storage?: (env: Record<string, unknown>) => unknown;${Ut}${ue}${V.configField}${H.configField}${J.configField}${ne.configField}${U.configField}${K.configField}${Q.configField}${B.configField}${
|
|
1667
|
+
storage?: (env: Record<string, unknown>) => unknown;${Ut}${ue}${V.configField}${H.configField}${J.configField}${ne.configField}${U.configField}${K.configField}${Q.configField}${B.configField}${qe}${h}${Kt}${Qt}${Vt}
|
|
1638
1668
|
}
|
|
1639
|
-
${O("schedulerStub",Jt,["cancel","runAfter","runAt"])}${O("storageStub",zt,["delete","download","getMetadata","getSignedUrl","getUrl","head","list","upload"],{sync:["getUrl"]})}${Yt}${dn}${Xt}${Ie}${V.stub}${H.stub}${J.stub}${ne.stub}${U.stub}${K.stub}${Q.stub}${B.stub}${ye}${
|
|
1669
|
+
${O("schedulerStub",Jt,["cancel","runAfter","runAt"])}${O("storageStub",zt,["delete","download","getMetadata","getSignedUrl","getUrl","head","list","upload"],{sync:["getUrl"]})}${Yt}${dn}${Xt}${Ie}${V.stub}${H.stub}${J.stub}${ne.stub}${U.stub}${K.stub}${Q.stub}${B.stub}${ye}${Te}
|
|
1640
1670
|
// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
|
|
1641
1671
|
// referencing call fails loudly with a clear error instead of overflowing the
|
|
1642
1672
|
// stack. Tracked across the awaited handler chain (one DO invocation is
|
|
@@ -1644,7 +1674,32 @@ ${O("schedulerStub",Jt,["cancel","runAfter","runAt"])}${O("storageStub",zt,["del
|
|
|
1644
1674
|
const MAX_RUN_DEPTH = 32;
|
|
1645
1675
|
let runDepth = 0;
|
|
1646
1676
|
|
|
1647
|
-
const dispatchRun = async (
|
|
1677
|
+
const dispatchRun = async (
|
|
1678
|
+
expected: FunctionKind,
|
|
1679
|
+
functionPath: string,
|
|
1680
|
+
args: Record<string, unknown>,
|
|
1681
|
+
ctx: unknown,
|
|
1682
|
+
// The kind of the context making the call, and — for a mutation target — the
|
|
1683
|
+
// transaction wrapper to run it under. Both are supplied by \`buildCtx\`, which
|
|
1684
|
+
// is the only place that knows which dispatch this \`ctx\` belongs to. Widened
|
|
1685
|
+
// past \`FunctionKind\` because the registry also carries \`"stream"\`, and
|
|
1686
|
+
// \`undefined\` for a ctx built outside a registered function (admin, migration).
|
|
1687
|
+
callerKind?: "stream" | FunctionKind,
|
|
1688
|
+
runTransactional?: (work: () => Promise<unknown>) => Promise<unknown>,
|
|
1689
|
+
): Promise<unknown> => {
|
|
1690
|
+
// A query is read-only. The ctx object installs \`run*\` on every kind (one
|
|
1691
|
+
// shape, built once), so the TYPE is all that stops a query from writing —
|
|
1692
|
+
// and a cast walks straight past it, inside a subscription re-run that can
|
|
1693
|
+
// execute many times per write. Checked on the CALLER, before the registry
|
|
1694
|
+
// lookup, so \`ctx.runMutation\` from a query fails identically whatever it
|
|
1695
|
+
// aimed at.
|
|
1696
|
+
if (callerKind === "query" && expected !== "query") {
|
|
1697
|
+
throw new LunoraError(
|
|
1698
|
+
"RUN_KIND_FORBIDDEN",
|
|
1699
|
+
\`ctx.run\${expected[0]!.toUpperCase()}\${expected.slice(1)}: a query may only compose other queries (tried to run "\${functionPath}")\`,
|
|
1700
|
+
);
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1648
1703
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
1649
1704
|
|
|
1650
1705
|
if (!registered) {
|
|
@@ -1662,6 +1717,18 @@ const dispatchRun = async (expected: FunctionKind, functionPath: string, args: R
|
|
|
1662
1717
|
runDepth += 1;
|
|
1663
1718
|
|
|
1664
1719
|
try {
|
|
1720
|
+
// A mutation composed from an action (or an http action) is the shape the
|
|
1721
|
+
// docs prescribe for atomicity — "do the transactional reads and writes in
|
|
1722
|
+
// a mutation and call it from the action". It only holds if the composed
|
|
1723
|
+
// dispatch gets the same BEGIN/COMMIT span and single-writer gate the
|
|
1724
|
+
// top-level mutation path gets; without it every write autocommits and a
|
|
1725
|
+
// mid-handler throw leaves the earlier ones durable. A \`runMutation\` from
|
|
1726
|
+
// inside a mutation rides the enclosing span instead of opening a second
|
|
1727
|
+
// one (see \`runMutationTransaction\`).
|
|
1728
|
+
if (runTransactional) {
|
|
1729
|
+
return await runTransactional(async () => registered.handler(ctx, args));
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1665
1732
|
return await registered.handler(ctx, args);
|
|
1666
1733
|
} finally {
|
|
1667
1734
|
runDepth -= 1;
|
|
@@ -1705,51 +1772,114 @@ export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOSt
|
|
|
1705
1772
|
// stamp no deps.
|
|
1706
1773
|
const ctx = this.buildCtx({ functionPath, headroom, scope, trusted: registered.lifecycle === "init" });
|
|
1707
1774
|
|
|
1708
|
-
// A mutation's writes must commit all-or-nothing
|
|
1709
|
-
//
|
|
1710
|
-
//
|
|
1711
|
-
//
|
|
1712
|
-
//
|
|
1713
|
-
//
|
|
1714
|
-
// handleRpc); runInTransaction's own guard rejects accidental nesting.
|
|
1775
|
+
// A mutation's writes must commit all-or-nothing, so its dispatch runs
|
|
1776
|
+
// under \`runMutationTransaction\` — the ONE place that opens the span,
|
|
1777
|
+
// settles the deferred schedules and flushes the deferred deletes. The
|
|
1778
|
+
// same helper backs \`ctx.runMutation\` and \`runReactor\`, because a
|
|
1779
|
+
// mutation reached by composition is promised exactly these guarantees
|
|
1780
|
+
// and used to get none of them.
|
|
1715
1781
|
//
|
|
1716
1782
|
// The replay bookkeeping (idempotency dedup row + custom-mutator
|
|
1717
|
-
// watermark advance) commits INSIDE
|
|
1783
|
+
// watermark advance) commits INSIDE the span via
|
|
1718
1784
|
// \`commitMutationBookkeeping\`, so the writes, the dedup row, and the
|
|
1719
1785
|
// watermark are atomic — a crash can't leave the writes durable without
|
|
1720
|
-
// the replay guard.
|
|
1786
|
+
// the replay guard. It is deliberately NOT in the shared helper: it is
|
|
1787
|
+
// per-REQUEST bookkeeping, and a composed sub-mutation has no request of
|
|
1788
|
+
// its own to record.
|
|
1721
1789
|
if (registered.kind === "mutation") {
|
|
1722
|
-
|
|
1790
|
+
return await this.runMutationTransaction(ctx, async () => {
|
|
1723
1791
|
const value = await registered.handler(ctx, args);
|
|
1724
1792
|
|
|
1725
1793
|
this.commitMutationBookkeeping(value);
|
|
1726
1794
|
|
|
1727
1795
|
return value;
|
|
1728
1796
|
});
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
const result = await registered.handler(ctx, args);
|
|
1800
|
+
|
|
1801
|
+
// An action is not itself transactional, but \`ctx.runMutation\` runs its
|
|
1802
|
+
// submutations on THIS ctx, so anything they queued after their own
|
|
1803
|
+
// transaction settled lands here. A dispatch with nothing queued no-ops.
|
|
1804
|
+
await this.deferPastResponse(flushDeferredDeletes(ctx));
|
|
1805
|
+
|
|
1806
|
+
return result;
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
/**
|
|
1810
|
+
* Run one mutation handler with the atomicity every caller of a mutation is
|
|
1811
|
+
* promised: a BEGIN/COMMIT span (with the single-writer gate
|
|
1812
|
+
* \`ShardRunner.runInTransaction\` composes in front of it), scheduled jobs
|
|
1813
|
+
* held until that span commits, and the deferred object deletes flushed
|
|
1814
|
+
* only once it has.
|
|
1815
|
+
*
|
|
1816
|
+
* Shared by the three entry points that dispatch a mutation handler — the
|
|
1817
|
+
* top-level RPC, \`ctx.runMutation\` from an action or http action, and a
|
|
1818
|
+
* reactor — because the guarantee is a property of the mutation, not of how
|
|
1819
|
+
* it was reached. The docs tell users to put the transactional part in a
|
|
1820
|
+
* mutation and call it from the action precisely so that composition is
|
|
1821
|
+
* atomic.
|
|
1822
|
+
*
|
|
1823
|
+
* A \`ctx.runMutation\` issued from inside a mutation is NESTED: SQLite-in-DO
|
|
1824
|
+
* has no savepoints and \`runInTransaction\` rejects a second open, so it
|
|
1825
|
+
* rides the enclosing span, which also owns its commit and therefore its
|
|
1826
|
+
* scheduler flush.
|
|
1827
|
+
*/
|
|
1828
|
+
private async runMutationTransaction<T>(ctx: unknown, work: () => Promise<T>): Promise<T> {
|
|
1829
|
+
const settleSchedules = beginDeferredSchedules(ctx as { scheduler?: unknown });
|
|
1729
1830
|
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1831
|
+
if (this.isInTransaction()) {
|
|
1832
|
+
try {
|
|
1833
|
+
const nested = await work();
|
|
1834
|
+
|
|
1835
|
+
await settleSchedules(true);
|
|
1836
|
+
|
|
1837
|
+
return nested;
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
await settleSchedules(false);
|
|
1840
|
+
|
|
1841
|
+
throw error;
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
let result: T;
|
|
1846
|
+
|
|
1847
|
+
try {
|
|
1848
|
+
result = await this.runInTransaction(work);
|
|
1849
|
+
} catch (error) {
|
|
1850
|
+
// The span rolled back, so the rows are gone and the jobs that were
|
|
1851
|
+
// to run "after I commit" must go with them. Dropping them is the
|
|
1852
|
+
// whole point of buffering: a persisted job for a write that never
|
|
1853
|
+
// landed fires against state that does not exist.
|
|
1854
|
+
await settleSchedules(false);
|
|
1855
|
+
|
|
1856
|
+
throw error;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// Committed. Schedules first and AWAITED: \`runAfter(0, ...)\` is
|
|
1860
|
+
// documented as the deterministic equivalent of an \`afterCommit\` hook,
|
|
1861
|
+
// so the job must be enqueued after the commit, and a failure to enqueue
|
|
1862
|
+
// it must be visible rather than swallowed.
|
|
1863
|
+
//
|
|
1864
|
+
// In a \`finally\`, because both halves of this are post-commit cleanup
|
|
1865
|
+
// and neither is allowed to cancel the other. \`settleSchedules\` drains
|
|
1866
|
+
// its whole queue and then rethrows what failed, so a SchedulerDO that
|
|
1867
|
+
// refused one job used to take the object cleanup down with it — the
|
|
1868
|
+
// rows were durably gone and their objects leaked with nothing logged.
|
|
1869
|
+
try {
|
|
1870
|
+
await settleSchedules(true);
|
|
1871
|
+
} finally {
|
|
1872
|
+
// Then the objects whose rows are now durably gone. Deliberately AFTER
|
|
1873
|
+
// the span, never inside it: an R2 delete cannot roll back, so a delete
|
|
1874
|
+
// issued from within a transaction that later aborts destroys data the
|
|
1875
|
+
// surviving row still points at.
|
|
1736
1876
|
//
|
|
1737
1877
|
// \`flushDeferredDeletes\` never rejects — the mutation has already
|
|
1738
1878
|
// succeeded, so a failed cleanup must not turn into a failed response.
|
|
1739
1879
|
// A leaked object is reported through \`ctx.log\` instead, with its key.
|
|
1740
1880
|
await this.deferPastResponse(flushDeferredDeletes(ctx));
|
|
1741
|
-
|
|
1742
|
-
return result;
|
|
1743
1881
|
}
|
|
1744
1882
|
|
|
1745
|
-
const result = await registered.handler(ctx, args);
|
|
1746
|
-
|
|
1747
|
-
// An action is not itself transactional, but \`ctx.runMutation\` runs its
|
|
1748
|
-
// submutations on THIS ctx, so their queued deletes land here — this is
|
|
1749
|
-
// the first point at which those writes are known to have committed. A
|
|
1750
|
-
// dispatch with nothing queued no-ops.
|
|
1751
|
-
await this.deferPastResponse(flushDeferredDeletes(ctx));
|
|
1752
|
-
|
|
1753
1883
|
return result;
|
|
1754
1884
|
}
|
|
1755
1885
|
|
|
@@ -1783,7 +1913,7 @@ ${at.override}
|
|
|
1783
1913
|
return { ranges: footprint.ranges(), result, tables: footprint.tables };
|
|
1784
1914
|
}
|
|
1785
1915
|
|
|
1786
|
-
protected override executeStream(functionPath: string, args: Record<string, unknown
|
|
1916
|
+
protected override executeStream(functionPath: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): null | { durable?: { ttlMs?: number }; iterator: (signal: AbortSignal) => AsyncIterable<unknown> } {
|
|
1787
1917
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
1788
1918
|
|
|
1789
1919
|
if (!registered || registered.kind !== "stream" || registered.visibility === "internal") {
|
|
@@ -1794,10 +1924,15 @@ ${at.override}
|
|
|
1794
1924
|
|
|
1795
1925
|
return {
|
|
1796
1926
|
...(registered.durable ? { durable: registered.durable as { ttlMs?: number } } : {}),
|
|
1797
|
-
|
|
1927
|
+
// Identity threaded EXPLICITLY from the socket, exactly as
|
|
1928
|
+
// \`executeSubscription\` above: the iterator is pulled after this
|
|
1929
|
+
// frame returned, interleaved with unrelated dispatches, so
|
|
1930
|
+
// \`buildCtx\`'s per-request fallback would run an \`rls()\` /
|
|
1931
|
+
// \`ctx.auth\` stream as nobody — or as a concurrent RPC's caller.
|
|
1932
|
+
iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath, identity }), args, signal),
|
|
1798
1933
|
};
|
|
1799
1934
|
}
|
|
1800
|
-
${
|
|
1935
|
+
${qt}${Bt}${cn}${pn}
|
|
1801
1936
|
protected override lifecycleHookPaths(event: "connect" | "disconnect" | "init" | "reactor"): readonly string[] {
|
|
1802
1937
|
return LUNORA_LIFECYCLE_HOOKS[event];
|
|
1803
1938
|
}
|
|
@@ -1808,10 +1943,12 @@ ${un}
|
|
|
1808
1943
|
// the new baseline and the footprint as the "should I even re-run this"
|
|
1809
1944
|
// gate, instead of pushing a frame down a socket.
|
|
1810
1945
|
//
|
|
1811
|
-
//
|
|
1812
|
-
//
|
|
1813
|
-
//
|
|
1814
|
-
//
|
|
1946
|
+
// Dispatched through \`runMutationTransaction\` because a reactor handler is
|
|
1947
|
+
// a mutation: its writes must commit all-or-nothing, the jobs it schedules
|
|
1948
|
+
// must wait for that commit, and the objects its row deletes orphaned must
|
|
1949
|
+
// be flushed once it lands. Safe to open a span here: the refresh drain
|
|
1950
|
+
// runs OUTSIDE any dispatch transaction (it is post-flush background work),
|
|
1951
|
+
// so this never nests.
|
|
1815
1952
|
//
|
|
1816
1953
|
// NO identity is threaded, and the ctx is built \`trusted\`. A reactor fires
|
|
1817
1954
|
// because data moved, not because anyone asked, so there is no user for RLS
|
|
@@ -1830,18 +1967,13 @@ ${un}
|
|
|
1830
1967
|
|
|
1831
1968
|
const footprint = createReadFootprint();
|
|
1832
1969
|
const ctx = this.buildCtx({ functionPath, headroom: this.subscriptionHeadroom(), onRead: footprint.onRead, onReadRange: footprint.onReadRange, trusted: true });
|
|
1833
|
-
const outcome = (await this.
|
|
1970
|
+
const outcome = (await this.runMutationTransaction(ctx, async () =>
|
|
1971
|
+
registered.handler(ctx, { previousDigest } as unknown as Record<string, unknown>),
|
|
1972
|
+
)) as {
|
|
1834
1973
|
digest: string;
|
|
1835
1974
|
ran: boolean;
|
|
1836
1975
|
};
|
|
1837
1976
|
|
|
1838
|
-
// A reactor IS a mutation, so its ctx carries the deferred-delete queue
|
|
1839
|
-
// and its transaction has just committed. Without this the queue would
|
|
1840
|
-
// die with \`ctx\` and the objects would leak with nothing to find: no
|
|
1841
|
-
// error, no warning, no failed request — a reactor that reaps orphaned
|
|
1842
|
-
// rows is a textbook use of one.
|
|
1843
|
-
await this.deferPastResponse(flushDeferredDeletes(ctx));
|
|
1844
|
-
|
|
1845
1977
|
return { digest: outcome.digest, ran: outcome.ran, tables: [...footprint.tables] };
|
|
1846
1978
|
}
|
|
1847
1979
|
|
|
@@ -1883,7 +2015,7 @@ ${un}
|
|
|
1883
2015
|
protected override studioFeatures(): StudioFeaturesResult {
|
|
1884
2016
|
return LUNORA_STUDIO_FEATURES;
|
|
1885
2017
|
}
|
|
1886
|
-
${W.evaluateOverride}${W.subscriptionOverride}${Lt}${
|
|
2018
|
+
${W.evaluateOverride}${W.subscriptionOverride}${Lt}${_t}
|
|
1887
2019
|
protected override advisories(): AdvisoryFinding[] {
|
|
1888
2020
|
return LUNORA_ADVISORIES;
|
|
1889
2021
|
}
|
|
@@ -2072,7 +2204,7 @@ ${Y()}
|
|
|
2072
2204
|
return;
|
|
2073
2205
|
}
|
|
2074
2206
|
|
|
2075
|
-
runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${
|
|
2207
|
+
runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${F} });
|
|
2076
2208
|
this.migrated = true;
|
|
2077
2209
|
}
|
|
2078
2210
|
${Ke?`
|
|
@@ -2094,12 +2226,38 @@ ${Ke?`
|
|
|
2094
2226
|
// dispatch path) fall back to the per-request fields as before.
|
|
2095
2227
|
const userId = options.identity ? options.identity.userId : this.getCurrentUserId();
|
|
2096
2228
|
const identity = options.identity ? options.identity.identity : this.getCurrentIdentity();
|
|
2097
|
-
${nn}${de}${fn}${he}${me}${Ce}${
|
|
2229
|
+
${nn}${de}${fn}${he}${me}${Ce}${Me}
|
|
2230
|
+
// Which dispatch this ctx belongs to. Drives the two deferral facades
|
|
2231
|
+
// below and the \`ctx.run*\` caller guard; a ctx built for an
|
|
2232
|
+
// admin/lifecycle path has no registered function, and so no kind.
|
|
2233
|
+
const contextKind = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind;
|
|
2098
2234
|
// \`list\`/\`get\` are the two methods \`ctx.db.system.query("_scheduled_functions")\`
|
|
2099
2235
|
// reaches through, and pending jobs live in the SchedulerDO — nothing the
|
|
2100
2236
|
// CDC changelog records — so reading them must forfeit a delta resume.
|
|
2101
2237
|
// The scheduler's own \`runAfter\`/\`runAt\`/\`cancel\` are writes and stay unstamped.
|
|
2102
|
-
const
|
|
2238
|
+
const schedulerBase = markUnvouchableReads((config.scheduler?.(env) ?? schedulerStub) as SchedulerLike, options.onRead, ["get", "list"]);
|
|
2239
|
+
// \`ctx.scheduler.runAfter(0, ...)\` is documented as the deterministic
|
|
2240
|
+
// equivalent of an \`afterCommit\` hook, and the SchedulerDO persists the
|
|
2241
|
+
// job the moment it is called — so inside a mutation the call is BUFFERED
|
|
2242
|
+
// and replayed after the transaction commits (a rollback drops it).
|
|
2243
|
+
// Wrapped on the same dispatches as the deferred-delete queue and for the
|
|
2244
|
+
// same reason: \`ctx.runMutation\` hands the CALLER's ctx to the callee, so
|
|
2245
|
+
// a mutation reached from an action schedules through the action's ctx.
|
|
2246
|
+
// An action's own schedules stay immediate — the window is only open
|
|
2247
|
+
// while a transaction is (see \`runMutationTransaction\`).
|
|
2248
|
+
//
|
|
2249
|
+
// Every kind but \`query\` is wrapped, because \`runMutationTransaction\`
|
|
2250
|
+
// is installed on \`ctx.runMutation\` for every kind but \`query\`: a
|
|
2251
|
+
// STREAM ctx, and an admin/lifecycle ctx with no registered kind at all,
|
|
2252
|
+
// both get the BEGIN/COMMIT span for a mutation they compose, and used
|
|
2253
|
+
// to get it with the deferral missing — so that mutation's job reached
|
|
2254
|
+
// the SchedulerDO while its transaction was still open, and survived the
|
|
2255
|
+
// rollback. A query cannot host a mutation handler (\`dispatchRun\`
|
|
2256
|
+
// refuses it) and its ctx is built on the hot subscription path, so it
|
|
2257
|
+
// stays unwrapped.
|
|
2258
|
+
//
|
|
2259
|
+
// Wrapped OUTSIDE the read-stamping facade so \`get\`/\`list\` stay stamped.
|
|
2260
|
+
const scheduler = contextKind === "query" ? schedulerBase : withDeferredSchedules(schedulerBase);
|
|
2103
2261
|
// Build the storage adapter once and share it between \`ctx.storage\`
|
|
2104
2262
|
// and \`ctx.db.system._storage\` so both read the same R2 binding. The
|
|
2105
2263
|
// \`storageStub\` fallback satisfies SystemReaderStorageLike structurally
|
|
@@ -2134,7 +2292,6 @@ ${nn}${de}${fn}${he}${me}${Ce}${Fe}
|
|
|
2134
2292
|
// resolves through it and stays stamped, and applied only to
|
|
2135
2293
|
// \`ctx.storage\` so \`ctx.db.system._storage\` (which shares the adapter
|
|
2136
2294
|
// above) is untouched.
|
|
2137
|
-
const contextKind = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind;
|
|
2138
2295
|
const contextStorage = contextKind === "mutation" || contextKind === "action" ? withDeferredDeletes(storage) : storage;
|
|
2139
2296
|
// \`ctx.log\`: the DO base builds the attributed logger (structured
|
|
2140
2297
|
// fields + \`.with(...)\` child + trace correlation) and routes each call
|
|
@@ -2197,11 +2354,15 @@ ${yn}
|
|
|
2197
2354
|
scheduler,
|
|
2198
2355
|
span,
|
|
2199
2356
|
storage: contextStorage,
|
|
2200
|
-
trace,${an}${Oe}${bn}${
|
|
2357
|
+
trace,${an}${Oe}${bn}${je}${Ee}${De}${Le}${Fe}
|
|
2201
2358
|
};
|
|
2202
2359
|
${kn}${wn}
|
|
2203
|
-
ctx.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, ctx);
|
|
2204
|
-
|
|
2360
|
+
ctx.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, ctx, contextKind);
|
|
2361
|
+
// The composed mutation runs under the SAME wrapper the top-level RPC
|
|
2362
|
+
// uses, so "do the transactional work in a mutation and call it from the
|
|
2363
|
+
// action" — the recipe the docs give for atomicity — actually is atomic.
|
|
2364
|
+
ctx.runMutation = (reference: FunctionReference, fnArgs: Record<string, unknown>) =>
|
|
2365
|
+
dispatchRun("mutation", reference.__lunoraRef, fnArgs, ctx, contextKind, async (work) => this.runMutationTransaction(ctx, work));
|
|
2205
2366
|
// \`ctx.runQuery(ref, args, { untracked: true })\` runs the sub-query on
|
|
2206
2367
|
// its OWN context, built without the subscription's read-footprint
|
|
2207
2368
|
// hooks — so its reads never enter this subscription's footprint and a
|
|
@@ -2222,14 +2383,15 @@ ${kn}${wn}
|
|
|
2222
2383
|
runOptions?.untracked === true
|
|
2223
2384
|
? this.buildCtx({ functionPath: options.functionPath, headroom: options.headroom, identity: { identity, userId }, scope: options.scope })
|
|
2224
2385
|
: ctx,
|
|
2386
|
+
contextKind,
|
|
2225
2387
|
);
|
|
2226
2388
|
|
|
2227
2389
|
return ctx;
|
|
2228
2390
|
}
|
|
2229
2391
|
};
|
|
2230
|
-
`},Xe=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:A(e)};case"bigint":return{builder:"blob",mode:"bigint",notNull:!0};case"boolean":return{builder:"integer",mode:"boolean",notNull:!0};case"bytes":return{builder:"blob",mode:"buffer",notNull:!0};case"date":case"timestamp":return{builder:"integer",notNull:!0};case"from":return{builder:"text",notNull:!0,typeAnnotation:A(e)};case"id":return{builder:"text",notNull:!0};case"literal":{const t=e.literalValue??"";return t.startsWith('"')||t.startsWith("'")?{builder:"text",notNull:!0}:t==="true"||t==="false"?{builder:"integer",mode:"boolean",notNull:!0}:t==="null"?{builder:"text",notNull:!0}:{builder:"real",notNull:!0}}case"null":return{builder:"text",notNull:!0};case"number":return{builder:"real",notNull:!0};case"optional":return{...e.inner?Xe(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},$t=(e,t)=>{const n=se(e);return n.kind==="id"&&n.tableName!==void 0&&t.has(n.tableName)?n.tableName:void 0},
|
|
2392
|
+
`},Xe=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:A(e)};case"bigint":return{builder:"blob",mode:"bigint",notNull:!0};case"boolean":return{builder:"integer",mode:"boolean",notNull:!0};case"bytes":return{builder:"blob",mode:"buffer",notNull:!0};case"date":case"timestamp":return{builder:"integer",notNull:!0};case"from":return{builder:"text",notNull:!0,typeAnnotation:A(e)};case"id":return{builder:"text",notNull:!0};case"literal":{const t=e.literalValue??"";return t.startsWith('"')||t.startsWith("'")?{builder:"text",notNull:!0}:t==="true"||t==="false"?{builder:"integer",mode:"boolean",notNull:!0}:t==="null"?{builder:"text",notNull:!0}:{builder:"real",notNull:!0}}case"null":return{builder:"text",notNull:!0};case"number":return{builder:"real",notNull:!0};case"optional":return{...e.inner?Xe(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},$t=(e,t)=>{const n=se(e);return n.kind==="id"&&n.tableName!==void 0&&t.has(n.tableName)?n.tableName:void 0},qr=(e,t,n)=>{b(e,"drizzle column name");const r=Xe(t),o=r.mode?`, { mode: "${r.mode}" }`:"";let s=`${r.builder}("${e}"${o})`;r.typeAnnotation&&(s+=`.$type<${r.typeAnnotation}>()`);const i=$t(t,n);return i!==void 0&&(s+=`.references((): AnySQLiteColumn => ${i}._id)`),r.notNull&&(s+=".notNull()"),s},jr=e=>{const t=e.unique?"uniqueIndex":"index",n=e.fields.map(r=>(b(r,"drizzle index field"),`t.${r}`)).join(", ");return` ${X(e.name)}: ${t}(${JSON.stringify(e.name)}).on(${n}),`},Wr=(e,t)=>{b(e.name,"table name");const n=[' _id: text("_id").primaryKey(),',' _creationTime: integer("_creationTime").notNull(),',...Object.entries(e.shape).map(([o,s])=>` ${o}: ${qr(o,s,t)},`)].join(`
|
|
2231
2393
|
`),r=e.indexes.length>0?`, (t) => ({
|
|
2232
|
-
${e.indexes.map(o=>
|
|
2394
|
+
${e.indexes.map(o=>jr(o)).join(`
|
|
2233
2395
|
`)}
|
|
2234
2396
|
})`:"";return`export const ${e.name} = sqliteTable("${e.name}", {
|
|
2235
2397
|
${n}
|
|
@@ -2241,7 +2403,7 @@ ${n}
|
|
|
2241
2403
|
`:""].join("");return`${S}import { ${c.join(", ")} } from "${n.serverDrizzle}";
|
|
2242
2404
|
${p}
|
|
2243
2405
|
${d}
|
|
2244
|
-
`},ho=(e,t=!1)=>{const n=e.tables.filter(o=>o.shardMode==="global"),r=e.tables.filter(o=>o.shardMode!=="global");return{global:
|
|
2406
|
+
`},ho=(e,t=!1)=>{const n=e.tables.filter(o=>o.shardMode==="global"),r=e.tables.filter(o=>o.shardMode!=="global");return{global:E(ct(n,t),Je),shard:E(ct(r,t),Je)}},mo=e=>{const t=new Map;for(const i of e){const a=t.get(i.cron);a?a.push(i):t.set(i.cron,[i])}const n=[...t.keys()].map(i=>` ${JSON.stringify(i)},`).join(`
|
|
2245
2407
|
`),r=n.length>0?`
|
|
2246
2408
|
${n}
|
|
2247
2409
|
`:"",o=[...t.entries()].map(([i,a])=>{const c=a.map(d=>{const p=d.workflow?`workflow: ${JSON.stringify(d.workflow.binding)}`:`functionPath: ${JSON.stringify(d.functionPath)}`;return` { name: ${JSON.stringify(d.name)}, ${p}, args: ${JSON.stringify(d.args)} },`}).join(`
|