@lunora/codegen 1.0.0-alpha.124 → 1.0.0-alpha.126
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 +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/{GENERATED_HEADER-BTQa3OFD.mjs → GENERATED_HEADER-NWWDWOX4.mjs} +1 -1
- package/dist/packem_shared/{OPENRPC_VERSION-DRHMcH-x.mjs → OPENRPC_VERSION-6XrIwoNr.mjs} +1 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME--CCXsODJ.mjs +9 -0
- package/dist/packem_shared/{buildOpenApiDocument-DvTuBr8Z.mjs → buildOpenApiDocument-DDvSUMD9.mjs} +1 -1
- package/dist/packem_shared/{emit-C_sJaMGR.mjs → emit-GW3Jf9w0.mjs} +315 -214
- package/dist/packem_shared/{emitApp-BuPtPsJ1.mjs → emitApp-D-mz_p6P.mjs} +141 -45
- package/package.json +10 -10
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-Bb_4PKpT.mjs +0 -9
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{agentComponent as
|
|
1
|
+
import{agentComponent as st}from"@lunora/agent/component";import{LunoraError as te}from"@lunora/errors";import{serializeSchemaSnapshot as yn,hashSchemaSnapshot as wn}from"./SCHEMA_SNAPSHOT_VERSION-CftvRWB8.mjs";import{s as N}from"./paths-C-9fwEgQ.mjs";const it=[{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,60 +15,60 @@ import{agentComponent as at}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"}],kn=
|
|
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"}],kn=it,xn=new Map(kn.flatMap(e=>e.serverCtxField?[[e.key,e.serverCtxField]]:[])),Hr=it.flatMap(e=>"appMethod"in e?[{appMethod:e.appMethod,key:e.key}]:[]),lt=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,vn=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),ct=e=>e.column!==void 0,Rn=(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
|
-
`}}
|
|
24
|
-
`}},
|
|
23
|
+
`}},Sn=(e,t)=>{const n=e.literalValue?.trim();if(!(n===void 0||!lt.test(n)))return{out:t,pre:`if (${t} !== ${n}) return DEFER;
|
|
24
|
+
`}},Ke=(e,t,n)=>{if(!ct(e)&&!(e.hasRefinement||e.sourceText!==void 0)){if(vn.has(e.kind))return e.kind==="any"?{out:t,pre:""}:{out:t,pre:Rn(e.kind,t)};switch(e.kind){case"array":return $n(e,t,n);case"literal":return Sn(e,t);case"object":return An(e,t,n);default:return}}},$n=(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=Ke(r,a,n);if(!c)return;const d=`if (!Array.isArray(${t})) return DEFER;
|
|
25
25
|
const ${s} = new Array(${t}.length);
|
|
26
26
|
for (let ${i} = 0; ${i} < ${t}.length; ${i}++) {
|
|
27
27
|
const ${a} = ${t}[${i}];
|
|
28
28
|
${c.pre}${s}[${i}] = ${c.out};
|
|
29
29
|
}
|
|
30
|
-
`;return{out:s,pre:d}},
|
|
30
|
+
`;return{out:s,pre:d}},Nn=(e,t,n,r)=>{const o=JSON.stringify(e);if(t.kind==="optional"){if(t.hasRefinement||t.sourceText!==void 0||ct(t))return;const{inner:i}=t;if(!i)return;const a=Ke(i,n,r);if(!a)return;const c=r.next(),d=`__has${String(c)}`,p=`__val${String(c)}`,m=`let ${d} = false;
|
|
31
31
|
let ${p};
|
|
32
32
|
if (${n} !== undefined) {
|
|
33
33
|
${a.pre}${p} = ${a.out};
|
|
34
34
|
${d} = true;
|
|
35
35
|
}
|
|
36
|
-
`;return{entry:`...(${d} ? { ${o}: ${p} } : {})`,pre:
|
|
37
|
-
`,c=p}const d=
|
|
38
|
-
`},
|
|
39
|
-
${
|
|
40
|
-
`;return{out:i,pre:a}},
|
|
36
|
+
`;return{entry:`...(${d} ? { ${o}: ${p} } : {})`,pre:m}}const s=Ke(t,n,r);if(s)return{entry:`${o}: ${s.out}`,pre:s.pre}},Tn=new Set(Object.getOwnPropertyNames(Object.prototype)),dt=(e,t,n)=>{let r="";const o=[];for(const s of Object.keys(e)){const i=e[s];if(!i)return;const a=JSON.stringify(s);let c=`${t}[${a}]`;if(Tn.has(s)){const p=`__f${String(n.next())}`;r+=`const ${p} = Object.hasOwn(${t}, ${a}) ? ${t}[${a}] : undefined;
|
|
37
|
+
`,c=p}const d=Nn(s,i,c,n);if(!d)return;r+=d.pre,o.push(d.entry)}return{entries:o.join(", "),pre:r}},ut=e=>{const t=`Object.getPrototypeOf(${e})`;return`if (${t} !== Object.prototype && ${t} !== null) return DEFER;
|
|
38
|
+
`},An=(e,t,n)=>{const r=e.shape??{},o=dt(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;
|
|
39
|
+
${ut(t)}${o.pre}const ${i} = { ${o.entries} };
|
|
40
|
+
`;return{out:i,pre:a}},On=e=>{let t=0;const r=dt(e,"source",{next:()=>(t+=1,t)});if(r)return`(source) => {
|
|
41
41
|
if (typeof source !== "object" || source === null || Array.isArray(source)) return DEFER;
|
|
42
|
-
${
|
|
43
|
-
}`}
|
|
42
|
+
${ut("source")}${r.pre}return { ${r.entries} };
|
|
43
|
+
}`},$=`// GENERATED by @lunora/codegen — do not edit.
|
|
44
44
|
// Run \`lunora codegen\` to regenerate.
|
|
45
45
|
|
|
46
|
-
`,ne=(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"},
|
|
46
|
+
`,ne=(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"},pt=/^[A-Za-z_$][\w$]*$/u,In=/^[\w./-]+$/u,g=(e,t)=>{if(!pt.test(e))throw new te("INTERNAL",`@lunora/codegen: ${t} is not a valid JS identifier: ${JSON.stringify(e)}`)},Ue=e=>e.charAt(0).toUpperCase()+e.slice(1),D=e=>pt.test(e)?e:JSON.stringify(e),Cn={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"},Ln=e=>{if(e===void 0)return"unknown";if(!lt.test(e))throw new te("INTERNAL",`@lunora/codegen: v.literal() argument is not a parseable string/number/boolean/null literal: ${JSON.stringify(e)}`);return e},A=e=>{const t=Cn[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 g(n,"v.id() table name"),`Id<"${n}">`}case"literal":return Ln(e.literalValue);case"object":return e.shape?`{ ${Object.entries(e.shape).map(([r,o])=>ht(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"}},ht=(e,t)=>{const n=D(e);if(t.kind==="optional"){const r=t.inner?A(t.inner):"unknown";return`${n}?: ${r}`}return`${n}: ${A(t)}`},we=e=>{const t=Object.entries(e);return t.length===0?"{}":`{ ${t.map(([n,r])=>ht(n,r)).join("; ")} }`},mt=e=>e.kind==="optional"||!!e.column?.hasDefault,re=e=>e.kind==="optional"&&e.inner?e.inner:e,_n=e=>{g(e.name,"table name");const t=Object.entries(e.shape).map(([r,o])=>{const s=re(o),i=A(s),a=D(r);return mt(o)?` ${a}?: ${i};`:` ${a}: ${i};`}).join(`
|
|
47
47
|
`),n=t?`
|
|
48
48
|
${t}
|
|
49
49
|
`:"";return`export interface Insert_${e.name} {
|
|
50
50
|
_id?: Id<"${e.name}">;
|
|
51
|
-
_creationTime?: number;${n}}`},
|
|
51
|
+
_creationTime?: number;${n}}`},Qe="schema",Gr=e=>{for(const u of e.tables)g(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(([R,x])=>{const I=D(R);if(x.kind==="optional"){const T=x.inner?A(x.inner):"unknown";return` ${I}?: ${T};`}return` ${I}: ${A(x)};`}).join(`
|
|
52
52
|
`),f=l?`
|
|
53
53
|
${l}
|
|
54
|
-
`:"",
|
|
54
|
+
`:"",k=u.commitOrdered===!0?`
|
|
55
55
|
_commitSeq: number;`:"";return`export interface Doc_${u.name} {
|
|
56
56
|
_id: Id<"${u.name}">;
|
|
57
|
-
_creationTime: number;${
|
|
57
|
+
_creationTime: number;${k}${f}}`}).join(`
|
|
58
58
|
|
|
59
59
|
`),o=e.tables.map(u=>` ${u.name}: Doc_${u.name};`).join(`
|
|
60
60
|
`),s=e.tables.map(u=>{const l=u.indexes.map(f=>JSON.stringify(f.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
61
61
|
`),i=e.tables.map(u=>{const l=u.searchIndexes.map(f=>JSON.stringify(f.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
62
62
|
`),a=e.tables.map(u=>{const l=u.rankIndexes.map(f=>JSON.stringify(f.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
63
63
|
`),c=e.tables.map(u=>{const l=u.shardMode==="global"?"":(u.geoIndexes??[]).map(f=>JSON.stringify(f.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
64
|
-
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",p=e.tables.map(u=>
|
|
64
|
+
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",p=e.tables.map(u=>_n(u)).join(`
|
|
65
65
|
|
|
66
|
-
`),
|
|
67
|
-
`),y=e.tables.map(u=>{const l=u.relations.map(f=>(g(f.table,"relation target table"),` ${
|
|
66
|
+
`),m=e.tables.map(u=>` ${u.name}: Insert_${u.name};`).join(`
|
|
67
|
+
`),y=e.tables.map(u=>{const l=u.relations.map(f=>(g(f.table,"relation target table"),` ${D(f.name)}: ${f.kind==="one"?"OneRelation":"ManyRelation"}<"${f.table}">;`)).join(`
|
|
68
68
|
`);return l?` ${u.name}: {
|
|
69
69
|
${l}
|
|
70
70
|
};`:` ${u.name}: {};`}).join(`
|
|
71
|
-
`);return
|
|
71
|
+
`);return E(`${$}export type TableName = ${t};
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* The tables **this app declared** — every {@link TableName} except those an add-on
|
|
@@ -135,7 +135,7 @@ ${p}
|
|
|
135
135
|
|
|
136
136
|
/** Per-table insert shape, accepted by \`ctx.db.<table>.insert(...)\`. */
|
|
137
137
|
export interface InsertModel {
|
|
138
|
-
${
|
|
138
|
+
${m}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
export type Insert<T extends keyof DataModel> = InsertModel[T];
|
|
@@ -160,11 +160,11 @@ export interface Relations {
|
|
|
160
160
|
${y}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
`,
|
|
164
|
-
`);return` ${
|
|
163
|
+
`,Qe)},Dn=/import\("(?<spec>(?:\.\.?\/)*_generated\/[^"]+)"\)/gu,gt=/^(?:\.\.?\/)*_generated\//u,ft=/\.[A-Za-z]\w*$/u,En=e=>e.replaceAll(Dn,(t,n)=>{const r=n.replace(gt,"./");return`import("${ft.test(r)?r:`${r}.js`}")`}),Pn=/import\("(?<spec>\.\.?\/[^"]+)"\)/gu,Fn=/^(?:\.\.?\/)+/u,Mn=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("/")},Bn=(e,t)=>e.replaceAll(Pn,(n,r)=>{if(gt.test(r.replace(Fn,"")))return n;const o=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",i=`../${Mn(`${o}/${r}`)}`;return`import("${ft.test(i)?i:`${i}.js`}")`}),E=(e,t)=>En(Bn(e,t)),jn=["client","do","errors","flags","observability","platform","ratelimit","runtime","server","values"],qn=new RegExp(String.raw`import\("@lunora/(?<pkg>${jn.join("|")})(?<subpath>/[^"]*)?"\)`,"gu"),Wn={flags:new Set(["/web"]),platform:new Set},bt=(e,t)=>t?e.replaceAll(qn,(n,r,o)=>{const s=Wn[r];return o&&s&&!s.has(o)?n:`import("lunorash/${r}${o??""}")`}):e,Ve=e=>["Doc","Id"].filter(t=>new RegExp(String.raw`\b${t}<`,"u").test(e)),yt=e=>e.output===void 0||e.output.kind==="any"||e.kind==="stream"?e.returnType:A(e.output),He=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))},ot=e=>{const t=([n,r])=>{const o=r.toSorted((s,i)=>s.exportName.localeCompare(i.exportName)).map(s=>{const i=E(we(s.args),s.filePath),a=E(yt(s),s.filePath);return` ${s.exportName}: FunctionReference<"${s.kind}", ${i}, ${a}>;`}).join(`
|
|
164
|
+
`);return` ${D(N(n))}: {
|
|
165
165
|
${o}
|
|
166
|
-
};`};return
|
|
167
|
-
`)},
|
|
166
|
+
};`};return He(e).map(n=>t(n)).join(`
|
|
167
|
+
`)},Un=(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+=`
|
|
168
168
|
/** A typed reference to a durable workflow, addressable for \`cronJobs()\` targets. Mirrors \`@lunora/scheduler\`'s \`WorkflowReference\` structurally. */
|
|
169
169
|
export interface WorkflowReference<Params = Record<string, unknown>> {
|
|
170
170
|
readonly isLunoraWorkflow: true;
|
|
@@ -196,7 +196,7 @@ export const agents: AgentsRef = {
|
|
|
196
196
|
${i}
|
|
197
197
|
};
|
|
198
198
|
`,n.push(`import type { AgentRunInput } from "@lunora/agent";
|
|
199
|
-
`)}return{block:r,importLine:n.join("")}},
|
|
199
|
+
`)}return{block:r,importLine:n.join("")}},Kn=()=>Object.keys(st().functions).toSorted((e,t)=>e.localeCompare(t)),wt=e=>new Set(e.filter(t=>N(t.filePath)==="agents").map(t=>t.exportName)),Qn=()=>new Set(Object.entries(st().functions).filter(([,e])=>e.visibility==="internal").map(([e])=>e)),Vn=(e,t)=>{const n={importLine:"",lines:"",prelude:""};if(e.length===0)return n;const r=wt(t),o=Qn(),s=t.find(a=>N(a.filePath)==="agents"&&o.has(a.exportName));if(s)throw new te("INTERNAL",`@lunora/codegen: "agents:${s.exportName}" is reserved for the durable agent loop's internal dispatch — rename the "${s.exportName}" export in ${s.filePath}`);const i=Kn().filter(a=>!r.has(a));return i.length===0?n:{importLine:`import { agentComponent } from "@lunora/agent/component";
|
|
200
200
|
`,lines:i.map(a=>` "agents:${a}": lunoraAgentRuntimeFunctions.${a} as unknown as RegisteredLunoraFunction,`).join(`
|
|
201
201
|
`),prelude:`
|
|
202
202
|
/**
|
|
@@ -205,13 +205,13 @@ ${i}
|
|
|
205
205
|
* subscribe to the public queries (\`agents:agentMessages\` is the live thread view).
|
|
206
206
|
*/
|
|
207
207
|
const lunoraAgentRuntimeFunctions = agentComponent().functions;
|
|
208
|
-
`}},
|
|
209
|
-
`,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"}},
|
|
210
|
-
`);return` ${
|
|
208
|
+
`}},Hn=(e,t)=>{if(!e)return{importLine:"",lines:"",prelude:""};const n=t.find(r=>N(r.filePath)==="sandbox"&&r.exportName==="invoke");if(n)throw new te("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";
|
|
209
|
+
`,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"}},Gn=(e,t)=>{if(e.length===0)return[];const n=wt(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))},Jn=(e,t)=>{if(e.length===0)return[];const n=new Set(t.filter(r=>N(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}))},zn=e=>{const t=e.filter(i=>i.stream);if(t.length===0)return{block:"",body:""};const n=He(t),r=n.map(([i,a])=>{const c=a.map(d=>{const p=E(d.chunkType??"unknown",d.filePath),m=E(we(d.searchParams),d.filePath),y=E(we(d.params),d.filePath);return` ${D(d.exportName)}: HttpStreamRef<${p}, ${m}, ${y}>;`}).join(`
|
|
210
|
+
`);return` ${D(N(i))}: {
|
|
211
211
|
${c}
|
|
212
212
|
};`}).join(`
|
|
213
|
-
`),o=n.map(([i,a])=>{const c=a.map(d=>` ${
|
|
214
|
-
`);return` ${
|
|
213
|
+
`),o=n.map(([i,a])=>{const c=a.map(d=>` ${D(d.exportName)}: { method: ${JSON.stringify(d.method)}, path: ${JSON.stringify(d.path)} },`).join(`
|
|
214
|
+
`);return` ${D(N(i))}: {
|
|
215
215
|
${c}
|
|
216
216
|
},`}).join(`
|
|
217
217
|
`);return{block:`
|
|
@@ -223,26 +223,26 @@ ${r}
|
|
|
223
223
|
export const httpStreams: HttpStreamsRef = {
|
|
224
224
|
${o}
|
|
225
225
|
};
|
|
226
|
-
`,body:r}},Jr=e=>{const{agents:t=[],functions:n,httpRoutes:r=[],mutators:o=[],useUmbrella:s=!1,workflows:i=[]}=e,a=ne(s),c=[...n.filter(v=>v.visibility!=="internal"),...
|
|
227
|
-
${
|
|
228
|
-
${y.body}`,l=
|
|
226
|
+
`,body:r}},Jr=e=>{const{agents:t=[],functions:n,httpRoutes:r=[],mutators:o=[],useUmbrella:s=!1,workflows:i=[]}=e,a=ne(s),c=[...n.filter(v=>v.visibility!=="internal"),...Gn(t,n),...Jn(o,n)],d=n.filter(v=>v.visibility==="internal"),p=ot(c),m=ot(d),y=zn(r),u=`${p}
|
|
227
|
+
${m}
|
|
228
|
+
${y.body}`,l=Ve(u),f=l.length>0?`
|
|
229
229
|
import type { ${l.join(", ")} } from "./dataModel.js";
|
|
230
|
-
`:"",
|
|
230
|
+
`:"",k=p?`
|
|
231
231
|
${p}
|
|
232
|
-
`:""
|
|
233
|
-
${
|
|
234
|
-
`:"",x=
|
|
232
|
+
`:"",R=m?`
|
|
233
|
+
${m}
|
|
234
|
+
`:"",x=Un(i,t),I=`export interface ApiTypes {${k}}
|
|
235
235
|
|
|
236
236
|
export const api = anyApi as unknown as ApiTypes;
|
|
237
237
|
|
|
238
238
|
/** Internal functions — callable only server-side via \`ctx.run*\`, never from a client. */
|
|
239
|
-
export interface InternalApiTypes {${
|
|
239
|
+
export interface InternalApiTypes {${R}}
|
|
240
240
|
|
|
241
241
|
export const internal = anyApi as unknown as InternalApiTypes;
|
|
242
242
|
${x.block}${y.block}`,T=[...I.includes("FunctionReference<")?["FunctionReference"]:[],...y.block===""?[]:["HttpStreamRef"]],_=T.length>0?`import type { ${T.join(", ")} } from "${a.client}";
|
|
243
|
-
`:"";return
|
|
243
|
+
`:"";return bt(`${$}import { anyApi } from "${a.client}";
|
|
244
244
|
${_}${x.importLine}${f}
|
|
245
|
-
${I}`,s)},
|
|
245
|
+
${I}`,s)},zr=e=>e?`${$}import { createSeedClient as createSeedClientBase } from "@lunora/seed";
|
|
246
246
|
import type { SeedClient, SeedClientOptions } from "@lunora/seed";
|
|
247
247
|
|
|
248
248
|
import schema from "../schema.js";
|
|
@@ -259,8 +259,8 @@ import type { InsertModel } from "./dataModel.js";
|
|
|
259
259
|
* const { posts } = await seed.posts((x) => x([10, 20]));
|
|
260
260
|
*/
|
|
261
261
|
export const createSeedClient = (options?: SeedClientOptions): SeedClient<InsertModel> => createSeedClientBase<InsertModel>(schema, options);
|
|
262
|
-
`:"",
|
|
263
|
-
export interface ${
|
|
262
|
+
`:"",Yr=(e,t,n=!1)=>{if(e.length===0||!t)return"";const r=ne(n),o=c=>c.table===void 0?"Row":`Doc<${JSON.stringify(c.table)}> & Row`,s=e.map(c=>{g(c.exportName,"shape export name");const d=o(c),p=E(we(c.args),c.filePath),m=Object.keys(c.args).length>0,y=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. */
|
|
263
|
+
export interface ${Ue(l)} {
|
|
264
264
|
${y}
|
|
265
265
|
/**
|
|
266
266
|
* Share the optimistic-overlay gate with other collections + mutators on this
|
|
@@ -285,7 +285,7 @@ ${y}
|
|
|
285
285
|
* \`createCollection\`, plus the \`checkpoints\` registry to hand \`bindMutators\` and
|
|
286
286
|
* \`scope\` to re-point the subscription.
|
|
287
287
|
*/
|
|
288
|
-
export const ${c.exportName}CollectionOptions = (options: ${
|
|
288
|
+
export const ${c.exportName}CollectionOptions = (options: ${Ue(l)}): LunoraCollectionOptions<${d}> =>
|
|
289
289
|
lunoraCollectionOptions<${d}>({
|
|
290
290
|
client: options.client,
|
|
291
291
|
...(options.checkpoints === undefined ? {} : { checkpoints: options.checkpoints }),
|
|
@@ -298,22 +298,22 @@ export const ${c.exportName}CollectionOptions = (options: ${qe(l)}): LunoraColle
|
|
|
298
298
|
|
|
299
299
|
/** Live collection for the \`${c.exportName}\` shape, with its sync controls. */
|
|
300
300
|
export const ${c.exportName}Collection = (
|
|
301
|
-
options: ${
|
|
301
|
+
options: ${Ue(l)},
|
|
302
302
|
): { checkpoints: CheckpointRegistry; collection: Collection<${d}, string>; scope: ${u} } => {
|
|
303
303
|
const { checkpoints, config, scope } = ${c.exportName}CollectionOptions(options);
|
|
304
304
|
|
|
305
305
|
return { checkpoints, collection: createCollection(config), scope };
|
|
306
306
|
};`}).join(`
|
|
307
307
|
|
|
308
|
-
`),i=
|
|
309
|
-
`:"";return`${
|
|
308
|
+
`),i=Ve(s),a=i.length>0?`import type { ${i.join(", ")} } from "./dataModel.js";
|
|
309
|
+
`:"";return`${$}import type { LunoraClient, SubscriptionError } from "${r.client}";
|
|
310
310
|
import { lunoraCollectionOptions } from "@lunora/db/collections";
|
|
311
311
|
import type { CheckpointRegistry, LunoraCollectionOptions, Row } from "@lunora/db";
|
|
312
312
|
import type { Collection } from "@tanstack/db";
|
|
313
313
|
import { createCollection } from "@tanstack/db";
|
|
314
314
|
${a}
|
|
315
315
|
${s}
|
|
316
|
-
`},
|
|
316
|
+
`},Yn=(e,t)=>`lunora_${N(e)}_${String(t)}`,Xn=`const callRegistered = async <R>(context: CallerCtx, functionPath: string, args: Record<string, unknown> | undefined): Promise<R> => {
|
|
317
317
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
318
318
|
|
|
319
319
|
if (!registered) {
|
|
@@ -321,30 +321,30 @@ ${s}
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
return (await registered.handler(context, args ?? {})) as R;
|
|
324
|
-
};`,
|
|
324
|
+
};`,Zn=(e,t,n=[],r=[])=>{const o=new Map,s=l=>{o.has(l)||o.set(l,Yn(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,f])=>{if(!In.test(l))throw new te("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(l)}`);return`import * as ${f} from "../${l}.js";`}).join(`
|
|
325
325
|
`),a=e.map(l=>` "${N(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
326
326
|
`),c=t.map(l=>` ${JSON.stringify(l.id)}: ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredDataMigration,`).join(`
|
|
327
327
|
`),d=n.map(l=>` "${N(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
328
328
|
`),p=r.map(l=>` "${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredShape,`).join(`
|
|
329
|
-
`),
|
|
330
|
-
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const f=
|
|
329
|
+
`),m=n.map(l=>`${N(l.filePath)}:${l.exportName}`),y=[a,d].filter(l=>l.length>0).join(`
|
|
330
|
+
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const f=On(l.args);return f===void 0?void 0:`installCompiledValidatorMap(${o.get(l.filePath)??""}.${l.exportName}.args, ${f});`}).filter(l=>l!==void 0).join(`
|
|
331
331
|
`);return{dispatchBody:y.length>0?`
|
|
332
332
|
${y}
|
|
333
333
|
`:"",importBlock:i.length>0?`${i}
|
|
334
334
|
|
|
335
335
|
`:"",installBlock:u,migrationBody:c.length>0?`
|
|
336
336
|
${c}
|
|
337
|
-
`:"",mutatorPaths:
|
|
337
|
+
`:"",mutatorPaths:m,shapeBody:p.length>0?`
|
|
338
338
|
${p}
|
|
339
|
-
`:""}},
|
|
340
|
-
`);return` ${
|
|
339
|
+
`:""}},er=e=>{const t=He(e),n=t.map(([o,s])=>{const i=s.map(a=>{const c=E(we(a.args),a.filePath),d=c==="{}"?"?":"",p=E(yt(a),a.filePath);return a.kind==="stream"?` ${a.exportName}: (args${d}: ${c}) => Promise<AsyncIterable<${p}>>;`:` ${a.exportName}: (args${d}: ${c}) => Promise<${p}>;`}).join(`
|
|
340
|
+
`);return` ${D(N(o))}: {
|
|
341
341
|
${i}
|
|
342
342
|
};`}).join(`
|
|
343
343
|
`);return{implementation:t.map(([o,s])=>{const i=N(o),a=s.map(c=>` ${c.exportName}: (args) => callRegistered(context, "${i}:${c.exportName}", args),`).join(`
|
|
344
|
-
`);return` ${
|
|
344
|
+
`);return` ${D(i)}: {
|
|
345
345
|
${a}
|
|
346
346
|
},`}).join(`
|
|
347
|
-
`),types:n}},
|
|
347
|
+
`),types:n}},tr=(e,t=[])=>{const n=new Set;for(const r of e.tables)for(const o of Object.values(r.shape)){const s=re(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))]},Xr=({agents:e=[],containers:t=[],env:n,hasAccessFacade:r=!1,hasAi:o=!1,hasAnalytics:s=!1,hasBrowser:i=!1,hasFlags:a=!1,hasHyperdrive:c=!1,hasImages:d=!1,hasKv:p=!1,hasNotify:m=!1,hasPayments:y=!1,hasPipelines:u=!1,hasR2sql:l=!1,hasX402:f=!1,identity:k,queues:R=[],schema:x,storageRuleBuckets:I=[],useUmbrella:T=!1,workflows:_=[]}={})=>{const v=ne(T),w=tr(x??{tables:[]},I).map(h=>JSON.stringify(h)).join(" | "),M=o?`import type { LunoraAi } from "@lunora/ai";
|
|
348
348
|
`:"",oe=o?`
|
|
349
349
|
readonly ai: LunoraAi;`:"",B=y?`import type { LunoraPayment } from "@lunora/payment";
|
|
350
350
|
`:"",ae=y?`
|
|
@@ -352,14 +352,14 @@ ${a}
|
|
|
352
352
|
`:"",W=f?`
|
|
353
353
|
readonly x402: X402Pay;`:"",C=t.length>0?`import type { ContainerAccessor } from "@lunora/container";
|
|
354
354
|
`:"",X=t.length>0?`
|
|
355
|
-
readonly containers: {${t.map(
|
|
356
|
-
readonly ${
|
|
357
|
-
};`:"",L=[...o?[" /** Workers AI binding (the conventional `env.AI`), narrowing `ctx.ai`. */\n readonly AI?: unknown;"]:[],...t.map(
|
|
358
|
-
readonly ${
|
|
359
|
-
readonly ${
|
|
360
|
-
readonly ${
|
|
361
|
-
readonly ${
|
|
362
|
-
`),
|
|
355
|
+
readonly containers: {${t.map(h=>`
|
|
356
|
+
readonly ${h.exportName}: ContainerAccessor;`).join("")}
|
|
357
|
+
};`:"",L=[...o?[" /** Workers AI binding (the conventional `env.AI`), narrowing `ctx.ai`. */\n readonly AI?: unknown;"]:[],...t.map(h=>(g(h.bindingName,`container binding "${h.bindingName}"`),` /** Durable Object namespace for the \`${h.exportName}\` container. */
|
|
358
|
+
readonly ${h.bindingName}?: unknown;`)),..._.map(h=>(g(h.bindingName,`workflow binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` workflow. */
|
|
359
|
+
readonly ${h.bindingName}?: unknown;`)),...R.map(h=>(g(h.bindingName,`queue binding "${h.bindingName}"`),` /** Queue producer binding for the \`${h.exportName}\` queue. */
|
|
360
|
+
readonly ${h.bindingName}?: unknown;`)),...e.map(h=>(g(h.bindingName,`agent binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` agent. */
|
|
361
|
+
readonly ${h.bindingName}?: unknown;`))].join(`
|
|
362
|
+
`),S=`
|
|
363
363
|
|
|
364
364
|
/**
|
|
365
365
|
* This project's Cloudflare bindings, as far as codegen can discover them from
|
|
@@ -377,15 +377,15 @@ ${L}`:""}
|
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
/** Alias for {@link CloudflareBindings} — the typed shape of \`env\`. */
|
|
380
|
-
export type Env = CloudflareBindings;`,j=(
|
|
381
|
-
readonly vectors: VectorSearch<VectorIndexName>;`:"",de=
|
|
382
|
-
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",
|
|
380
|
+
export type Env = CloudflareBindings;`,j=(h,Me)=>Me?xn.get(h)?.field??"":"",ie=j("kv",p),le=j("analytics",s),$e=j("hyperdrive",c),Ne=j("browser",i),Te=j("images",d),ce=j("pipelines",u),V=j("r2sql",l),F=(x?.vectorIndexes.length??0)>0,H=F?' | "vectors"':"",Z=F?`
|
|
381
|
+
readonly vectors: VectorSearch<VectorIndexName>;`:"",de=F?`
|
|
382
|
+
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",G=F?`import type { VectorSearch, VectorSearchReader } from "${v.server}";
|
|
383
383
|
import type { VectorIndexName } from "./dataModel.js";
|
|
384
384
|
`:"",U=r?`
|
|
385
385
|
/** Verified Cloudflare Access identity — a synchronous facade over the resolved claims (email / groups / hasGroup / claims). Anonymous when no Access token is present. */
|
|
386
386
|
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",K=a?`
|
|
387
387
|
/** Feature-flag evaluation (OpenFeature). Reads are memoized per request; evaluations never throw — a provider error resolves to the supplied default. */
|
|
388
|
-
readonly flags: import("${v.flags}").LunoraFlags;`:"",Q=
|
|
388
|
+
readonly flags: import("${v.flags}").LunoraFlags;`:"",Q=m?`
|
|
389
389
|
/** Multi-channel notifications (@lunora/notify): send / chat / inApp / webhook plus the push device sub-facade. Sends are external I/O — confine them to action handlers. */
|
|
390
390
|
readonly notify: import("@lunora/notify").LunoraNotify;
|
|
391
391
|
/** Device push sub-facade — the same object as ctx.notify.push (register / send / broadcast). Sends belong in action handlers. */
|
|
@@ -402,10 +402,10 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
402
402
|
|
|
403
403
|
/** This project's declared workflows, addressable from \`ctx.workflows\` by their \`lunora/workflows.ts\` export name. */
|
|
404
404
|
export interface LunoraWorkflows {
|
|
405
|
-
${_.map(
|
|
405
|
+
${_.map(h=>` get(name: ${JSON.stringify(h.exportName)}): WorkflowHandle<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${h.exportName}>>;`).join(`
|
|
406
406
|
`)}
|
|
407
|
-
}`:"",
|
|
408
|
-
readonly workflows: LunoraWorkflows;`:"",ue
|
|
407
|
+
}`:"",ke=q?' | "workflows"':"",xe=q?`
|
|
408
|
+
readonly workflows: LunoraWorkflows;`:"",ue=R.length>0,Oe=ue?`import type { QueueProducer } from "@lunora/queue";
|
|
409
409
|
import type * as lunoraQueueDefinitions from "../queues.js";
|
|
410
410
|
`:"",Ie=ue?`
|
|
411
411
|
|
|
@@ -414,7 +414,7 @@ type QueueBodyOf<Definition> = Definition extends { __lunoraBody?: infer Body }
|
|
|
414
414
|
|
|
415
415
|
/** This project's declared queues, addressable from \`ctx.queues\` by their \`lunora/queues.ts\` export name. */
|
|
416
416
|
export interface LunoraQueues {
|
|
417
|
-
${
|
|
417
|
+
${R.map(h=>` readonly ${h.exportName}: QueueProducer<QueueBodyOf<typeof lunoraQueueDefinitions.${h.exportName}>>;`).join(`
|
|
418
418
|
`)}
|
|
419
419
|
}`:"",ve=ue?`
|
|
420
420
|
readonly queues: LunoraQueues;`:"",pe=e.length>0,Ce=pe?`import type { AgentHandle } from "@lunora/agent";
|
|
@@ -422,23 +422,23 @@ ${$.map(m=>` readonly ${m.exportName}: QueueProducer<QueueBodyOf<typeof lunor
|
|
|
422
422
|
|
|
423
423
|
/** This project's declared agents, addressable from \`ctx.agents\` by their \`lunora/agents.ts\` export name. */
|
|
424
424
|
export interface LunoraAgents {
|
|
425
|
-
${e.map(
|
|
425
|
+
${e.map(h=>(g(h.exportName,`agent export "${h.exportName}"`),` readonly ${h.exportName}: AgentHandle;`)).join(`
|
|
426
426
|
`)}
|
|
427
|
-
}`:""
|
|
428
|
-
readonly agents: LunoraAgents;`:"",_e=
|
|
427
|
+
}`:"",Re=pe?`
|
|
428
|
+
readonly agents: LunoraAgents;`:"",_e=k?`import type { InferIdentity } from "${v.server}";
|
|
429
429
|
import type * as lunoraIdentityContract from "../identity.js";
|
|
430
|
-
`:"",
|
|
430
|
+
`:"",De=k?`
|
|
431
431
|
|
|
432
432
|
/** 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. */
|
|
433
|
-
export type Identity = InferIdentity<typeof lunoraIdentityContract.${
|
|
433
|
+
export type Identity = InferIdentity<typeof lunoraIdentityContract.${k.exportName}>;
|
|
434
434
|
|
|
435
435
|
/** \`ctx.auth\` narrowed so \`getIdentity()\` resolves the declared {@link Identity} contract instead of the untyped claim bag. */
|
|
436
|
-
type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: () => Promise<Identity | null> };`:"",
|
|
437
|
-
readonly auth: NarrowedAuth;`:"",
|
|
438
|
-
`:"",
|
|
436
|
+
type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: () => Promise<Identity | null> };`:"",he=k?' | "auth"':"",me=k?`
|
|
437
|
+
readonly auth: NarrowedAuth;`:"",Ee=k?", Identity":"",Pe=n?`import type * as lunoraEnvContract from "../env.js";
|
|
438
|
+
`:"",Fe=n?`
|
|
439
439
|
|
|
440
440
|
/** This app's declared env contract (\`defineEnv\` in \`lunora/env.ts\`) — the validated, coercion-aware shape of \`ctx.env\`. */
|
|
441
|
-
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",ge=n?' | "env"':"",fe=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`${
|
|
441
|
+
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",ge=n?' | "env"':"",fe=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`${$}import { createPolicyDsl, defineMutator as defineMutatorBase, initLunora, v as vBase } from "${v.server}";
|
|
442
442
|
import type {
|
|
443
443
|
ActionBuilder,
|
|
444
444
|
ActionCtx as ActionCtxBase,
|
|
@@ -451,6 +451,7 @@ import type {
|
|
|
451
451
|
InternalQueryBuilder,
|
|
452
452
|
MutationBuilder,
|
|
453
453
|
MutationCtx as MutationCtxBase,
|
|
454
|
+
MutationStorage,
|
|
454
455
|
MutatorDefinition,
|
|
455
456
|
QueryBuilder,
|
|
456
457
|
QueryCtx as QueryCtxBase,
|
|
@@ -494,7 +495,7 @@ export type {
|
|
|
494
495
|
} from "${v.serverDataModel}";
|
|
495
496
|
|
|
496
497
|
import type { DataModel, Doc, GeoIndexNamesByTable, Id as IdOfTable, IndexNamesByTable, Insert, InsertModel, RankIndexNamesByTable, Relations, SearchIndexNamesByTable, TableName } from "./dataModel.js";
|
|
497
|
-
${
|
|
498
|
+
${G}${M}${B}${se}${C}${ee}${Oe}${Ce}${_e}${Pe}
|
|
498
499
|
export type { AppTableName, DataModel, Doc, Id, TableName } from "./dataModel.js";
|
|
499
500
|
|
|
500
501
|
/**
|
|
@@ -554,7 +555,7 @@ export interface OrmWriter extends OrmReader {
|
|
|
554
555
|
}
|
|
555
556
|
|
|
556
557
|
/** Storage buckets this schema declares (\`v.storage("name")\`), narrowing \`ctx.storage.bucket(name)\`. */
|
|
557
|
-
export type StorageBucketName = ${
|
|
558
|
+
export type StorageBucketName = ${w};${S}${Ae}${Ie}${Le}${De}${Fe}
|
|
558
559
|
|
|
559
560
|
/**
|
|
560
561
|
* Project-typed contexts. The base contexts from \`@lunora/server\` are
|
|
@@ -617,22 +618,22 @@ type AsIdTable<T extends string> = T extends TableName ? T : string extends T ?
|
|
|
617
618
|
*/
|
|
618
619
|
type TypedAsId = <T extends string>(tableName: AsIdTable<T>, id: string) => IdOfTable<T & TableName>;
|
|
619
620
|
|
|
620
|
-
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${H}${
|
|
621
|
+
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${H}${he}${ge}> {
|
|
621
622
|
readonly db: Omit<DatabaseReader, "asId" | "query" | "get"> & DatabaseReaderFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
622
623
|
readonly orm: OrmReader;
|
|
623
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${de}${U}${ie}${K}${Q}${le}${fe}${
|
|
624
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${de}${U}${ie}${K}${Q}${le}${fe}${me}
|
|
624
625
|
}
|
|
625
626
|
|
|
626
|
-
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${H}${
|
|
627
|
+
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${H}${ke}${he}${ge}> {
|
|
627
628
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
628
629
|
readonly orm: OrmWriter;
|
|
629
|
-
readonly storage:
|
|
630
|
+
readonly storage: MutationStorage<StorageBucketName>;${Z}${U}${ie}${K}${Q}${le}${fe}${xe}${ve}${Re}${me}
|
|
630
631
|
}
|
|
631
632
|
|
|
632
|
-
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${H}${
|
|
633
|
+
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${H}${ke}${he}${ge}> {
|
|
633
634
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
634
635
|
readonly orm: OrmWriter;
|
|
635
|
-
readonly storage: StorageBase<StorageBucketName>;${Z}${U}${oe}${ae}${W}${X}${ie}${K}${Q}${
|
|
636
|
+
readonly storage: StorageBase<StorageBucketName>;${Z}${U}${oe}${ae}${W}${X}${ie}${K}${Q}${$e}${Ne}${Te}${le}${ce}${V}${fe}${xe}${ve}${Re}${me}
|
|
636
637
|
}
|
|
637
638
|
|
|
638
639
|
/**
|
|
@@ -690,7 +691,7 @@ export const defineMutator = defineMutatorBase as unknown as <Args extends Recor
|
|
|
690
691
|
* Runtime-identical to \`@lunora/server\`'s \`definePolicy\`; only the types narrow,
|
|
691
692
|
* so the \`rls()\` chain discovers a policy authored either way the same.
|
|
692
693
|
*/
|
|
693
|
-
export const definePolicy = createPolicyDsl<DataModel, Relations${
|
|
694
|
+
export const definePolicy = createPolicyDsl<DataModel, Relations${Ee}>();
|
|
694
695
|
|
|
695
696
|
/**
|
|
696
697
|
* The validator builder \`v\`, with \`v.id(...)\` constrained to THIS schema's
|
|
@@ -707,12 +708,12 @@ export const definePolicy = createPolicyDsl<DataModel, Relations${De}>();
|
|
|
707
708
|
export const v = vBase as unknown as Omit<typeof vBase, "id"> & {
|
|
708
709
|
id: <T extends TableName>(table: T) => ColumnValidator<IdOfTable<T>, IdOfTable<T>>;
|
|
709
710
|
};
|
|
710
|
-
`},
|
|
711
|
+
`},nr=e=>{const t={connect:[],disconnect:[],init:[],reactor:[]};for(const n of e)n.lifecycle&&t[n.lifecycle].push(`${N(n.filePath)}:${n.exportName}`);return t},Zr=e=>{const{agents:t=[],functions:n,migrations:r=[],mutators:o=[],shapes:s=[],useUmbrella:i=!1,usesSandbox:a=!1}=e,c=n.length>0,d=ne(i),{dispatchBody:p,importBlock:m,installBlock:y,migrationBody:u,mutatorPaths:l,shapeBody:f}=Zn(n,r,o,s),k=Vn(t,n),R=Hn(a,n),x=[k.lines,R.lines].filter(S=>S.length>0).join(`
|
|
711
712
|
`);let I=p;x.length>0&&(I=p.length>0?`${p.trimEnd()}
|
|
712
713
|
${x}
|
|
713
714
|
`:`
|
|
714
715
|
${x}
|
|
715
|
-
`);const T=
|
|
716
|
+
`);const T=nr(n),_=s.length>0?`import type { RegisteredShape } from "${d.server}";
|
|
716
717
|
`:"",v=s.length>0?`
|
|
717
718
|
/**
|
|
718
719
|
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
@@ -721,13 +722,13 @@ ${x}
|
|
|
721
722
|
* \`shape_subscribe\` (reads-as-permissions).
|
|
722
723
|
*/
|
|
723
724
|
export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${f}};
|
|
724
|
-
`:"",
|
|
725
|
+
`:"",w=l.length>0?`
|
|
725
726
|
/**
|
|
726
727
|
* Custom-mutator function paths — the \`LUNORA_FUNCTIONS\` keys the generated
|
|
727
728
|
* ShardDO's \`isCustomMutator\` override routes through the client-watermark push
|
|
728
729
|
* protocol (\`x-lunora-client-id\`/\`x-lunora-client-seq\` ordering).
|
|
729
730
|
*/
|
|
730
|
-
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${l.map(
|
|
731
|
+
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${l.map(S=>JSON.stringify(S)).join(", ")}]);
|
|
731
732
|
`:"",M=y.length>0?`import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${d.values}";
|
|
732
733
|
`:"",oe=y.length>0?`
|
|
733
734
|
/**
|
|
@@ -736,14 +737,14 @@ export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${l.map(R=>JSO
|
|
|
736
737
|
* parser as a zero-allocation fast path; anything it can't model is deferred.
|
|
737
738
|
*/
|
|
738
739
|
${y}
|
|
739
|
-
`:"",B=
|
|
740
|
+
`:"",B=er(n),ae=B.types?`
|
|
740
741
|
${B.types}
|
|
741
742
|
`:"",se=B.implementation?`
|
|
742
743
|
${B.implementation}
|
|
743
|
-
`:"",W=
|
|
744
|
-
`:"",X=c?"context":"_context",L=c?`${
|
|
744
|
+
`:"",W=Ve(B.types),C=W.length>0?`import type { ${W.join(", ")} } from "./dataModel.js";
|
|
745
|
+
`:"",X=c?"context":"_context",L=c?`${Xn}
|
|
745
746
|
|
|
746
|
-
`:"";return
|
|
747
|
+
`:"";return bt(`${$}${m}${k.importLine}${R.importLine}${M}${_}import { LunoraError } from "${d.server}";
|
|
747
748
|
import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
748
749
|
${C}
|
|
749
750
|
/**
|
|
@@ -777,13 +778,13 @@ export interface RegisteredLunoraFunction {
|
|
|
777
778
|
/** \`"internal"\` functions are rejected on the external RPC path; absence === public. */
|
|
778
779
|
visibility?: "internal" | "public";
|
|
779
780
|
}
|
|
780
|
-
${
|
|
781
|
+
${k.prelude}${R.prelude}
|
|
781
782
|
/**
|
|
782
783
|
* Static dispatch table. The key matches the \`__lunoraRef\` the client
|
|
783
784
|
* emits (\`api[namespace][fn].__lunoraRef === "namespace:fn"\`).
|
|
784
785
|
*/
|
|
785
786
|
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${I}};
|
|
786
|
-
${oe}${v}${
|
|
787
|
+
${oe}${v}${w}
|
|
787
788
|
/**
|
|
788
789
|
* Lifecycle manifest: the function paths the generated ShardDO dispatches when a
|
|
789
790
|
* client's WebSocket connects (\`connect\`) or disconnects (\`disconnect\`), once
|
|
@@ -794,10 +795,10 @@ ${oe}${v}${k}
|
|
|
794
795
|
* anonymous — all via system dispatch.
|
|
795
796
|
*/
|
|
796
797
|
export const LUNORA_LIFECYCLE_HOOKS: { connect: readonly string[]; disconnect: readonly string[]; init: readonly string[]; reactor: readonly string[] } = {
|
|
797
|
-
connect: [${T.connect.map(
|
|
798
|
-
disconnect: [${T.disconnect.map(
|
|
799
|
-
init: [${T.init.map(
|
|
800
|
-
reactor: [${T.reactor.map(
|
|
798
|
+
connect: [${T.connect.map(S=>JSON.stringify(S)).join(", ")}],
|
|
799
|
+
disconnect: [${T.disconnect.map(S=>JSON.stringify(S)).join(", ")}],
|
|
800
|
+
init: [${T.init.map(S=>JSON.stringify(S)).join(", ")}],
|
|
801
|
+
reactor: [${T.reactor.map(S=>JSON.stringify(S)).join(", ")}],
|
|
801
802
|
};
|
|
802
803
|
|
|
803
804
|
/**
|
|
@@ -851,7 +852,7 @@ export interface RegisteredDataMigration {
|
|
|
851
852
|
* shard DO's admin RPC and the CLI resolve migrations to run through this map.
|
|
852
853
|
*/
|
|
853
854
|
export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${u}};
|
|
854
|
-
`,i)},
|
|
855
|
+
`,i)},rr=e=>{const t={};for(const n of e.tables){const r={};for(const[o,s]of Object.entries(n.shape)){const i=re(s);i.kind==="id"&&i.tableName!==void 0&&(r[o]=i.tableName)}Object.keys(r).length>0&&(t[n.name]=r)}return t},or=e=>{const t={};for(const n of e.tables){const r=[];for(const[o,s]of Object.entries(n.shape))re(s).kind==="storage"&&r.push(o);r.length>0&&(t[n.name]=r)}return t},ar=e=>{const t={};for(const n of e.tables){const r=[...n.indexes.map(o=>({fields:[...o.fields],name:o.name,type:"index",...o.unique===!0?{unique:!0}:{}})),...n.searchIndexes.map(o=>({fields:[o.field,...o.filterFields??[]],name:o.name,type:"search"})),...(n.geoIndexes??[]).map(o=>({fields:[o.field],name:o.name,type:"geo"})),...n.rankIndexes.map(o=>({fields:o.sortBy.map(s=>s.field),name:o.name,type:"rank"})),...n.vectorIndexes.map(o=>({fields:o.field===void 0?[]:[o.field],name:o.name,type:"vector"}))];r.length>0&&(t[n.name]=r)}return t},sr=e=>{const t=[];for(const n of e.tables)!n.ttl||n.shardMode==="global"||t.push({...n.ttl.after===void 0?{}:{after:n.ttl.after},field:n.ttl.field,...n.softDelete?{softDeleteField:n.softDelete.field}:{},table:n.name});return t},ir=e=>{if(e.kind!=="union"||e.members===void 0||e.members.length===0)return;const t=[];for(const n of e.members){if(n.kind!=="literal"||n.literalValue===void 0)return;try{const r=JSON.parse(n.literalValue);if(typeof r!="string")return;t.push(r)}catch{return}}return t},lr=(e,t)=>{const n=re(t),r={name:e,optional:mt(t),type:n.kind};n.kind==="id"&&n.tableName!==void 0&&(r.ref=n.tableName),n.kind==="storage"&&(r.isStorage=!0,n.bucket!==void 0&&(r.bucket=n.bucket));const o=ir(n);return o!==void 0&&(r.enumValues=o),n.column?.notNull===!1&&(r.nullable=!0),r},cr=e=>{const t={};for(const n of e.tables){const r=[{name:"_id",optional:!1,pk:!0,type:"id"},{name:"_creationTime",optional:!1,type:"number"},...n.commitOrdered===!0?[{name:"_commitSeq",optional:!1,type:"number"}]:[]];for(const[o,s]of Object.entries(n.shape))r.push(lr(o,s));t[n.name]=r}return t},dr=e=>e?{importFragment:"serveRelationFanout, ",override:`
|
|
855
856
|
protected override async runRelationFanoutRead(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
856
857
|
this.ensureMigrated();
|
|
857
858
|
|
|
@@ -859,7 +860,7 @@ export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${u}}
|
|
|
859
860
|
|
|
860
861
|
return serveRelationFanout(schema as unknown as SchemaLike, db, functionPath, args);
|
|
861
862
|
}
|
|
862
|
-
`}:{importFragment:"",override:""},
|
|
863
|
+
`}:{importFragment:"",override:""},ur=e=>{if(!e)return{build:"",configField:"",contextField:"",stub:""};const t='throw new Error("ctx.ai: no AI binding found. Add an \\`ai\\` binding (env.AI) to wrangler.jsonc, or pass \\`ai\\` to createShardDO().");';return{build:`
|
|
863
864
|
const aiBinding = config.ai?.(env) ?? (env as Record<string, unknown>).AI;
|
|
864
865
|
// Correlate AI-Gateway-routed calls with the Lunora trace: thread the
|
|
865
866
|
// function path + trace id into createAi, which folds them into the
|
|
@@ -897,29 +898,38 @@ const aiStub: LunoraAi = {
|
|
|
897
898
|
const ${e} = {
|
|
898
899
|
${s}
|
|
899
900
|
}${r};
|
|
900
|
-
`},
|
|
901
|
+
`},P={build:"",configField:"",contextField:"",importLines:[],stub:""},pr=e=>e?{build:`
|
|
901
902
|
const kvBinding = config.kv?.(env) ?? (env as Record<string, unknown>).KV;
|
|
902
|
-
|
|
903
|
+
// KV is not this shard's SQLite, so nothing appends a \`__cdc_log\` entry
|
|
904
|
+
// when a value changes — a subscription that read one can never be proven
|
|
905
|
+
// current on reconnect and must re-snapshot. Reads only; \`put\`/\`delete\`
|
|
906
|
+
// are writes and stay unstamped.
|
|
907
|
+
const kv: Kv = markUnvouchableReads(kvBinding ? createKv({ namespace: kvBinding as KVNamespaceLike }) : kvStub, options.onRead, [
|
|
908
|
+
"get",
|
|
909
|
+
"getRaw",
|
|
910
|
+
"getWithMetadata",
|
|
911
|
+
"list",
|
|
912
|
+
]);
|
|
903
913
|
`,configField:`
|
|
904
914
|
kv?: (env: Record<string, unknown>) => KVNamespaceLike;`,contextField:`
|
|
905
|
-
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"])}:
|
|
915
|
+
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"])}:P,hr=(e,t)=>e?{build:`
|
|
906
916
|
const flags: import("${t}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
907
917
|
provider: () => config.flags?.(env),
|
|
908
918
|
targetingKey: () => flagsConfig.identify?.({ identity: identity ?? null, userId: userId ?? null }),
|
|
909
919
|
});
|
|
910
920
|
`,configField:`
|
|
911
921
|
flags?: (env: Record<string, unknown>) => import("${t}").Provider;`,contextField:`
|
|
912
|
-
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:
|
|
922
|
+
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:P,mr=e=>e?{build:`
|
|
913
923
|
const { notify, push } = createNotify(notifyConfig, env, { log, metrics });
|
|
914
924
|
`,configField:"",contextField:`
|
|
915
925
|
notify,
|
|
916
|
-
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:
|
|
926
|
+
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:P,gr=e=>e?{build:`
|
|
917
927
|
const envConfig = lunoraEnvContract.${e.exportName}(env);
|
|
918
928
|
`,configField:"",contextField:`
|
|
919
|
-
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:
|
|
929
|
+
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:P,fr=e=>e?{build:`
|
|
920
930
|
const access = accessFacade(identity, userId);
|
|
921
931
|
`,configField:"",contextField:`
|
|
922
|
-
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:
|
|
932
|
+
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:P,br=(e,t,n)=>{if(!t)return{constant:"",evaluateOverride:"",subscriptionOverride:""};const r=a=>`
|
|
923
933
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
924
934
|
const flags: import("${n}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
925
935
|
provider: () => config.flags?.(env),
|
|
@@ -986,20 +996,20 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
986
996
|
const analytics: AnalyticsClient = analyticsBinding ? createAnalytics(analyticsBinding as AnalyticsEngineDatasetLike) : analyticsStub;
|
|
987
997
|
`,configField:`
|
|
988
998
|
analytics?: (env: Record<string, unknown>) => AnalyticsEngineDatasetLike;`,contextField:`
|
|
989
|
-
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"]})}:
|
|
999
|
+
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"]})}:P,wr=e=>e?{build:`
|
|
990
1000
|
const imagesBinding = config.images?.(env) ?? (env as Record<string, unknown>).IMAGES;
|
|
991
1001
|
const images: Images = imagesBinding ? createImages({ binding: imagesBinding as ImagesBindingLike }) : imagesStub;
|
|
992
1002
|
`,configField:`
|
|
993
1003
|
images?: (env: Record<string, unknown>) => ImagesBindingLike;`,contextField:`
|
|
994
|
-
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"])}:
|
|
1004
|
+
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"])}:P,kr=e=>e?{build:`
|
|
995
1005
|
const sql: SqlClient = config.sql ? config.sql(env) : sqlStub;
|
|
996
1006
|
`,configField:`
|
|
997
1007
|
sql?: (env: Record<string, unknown>) => SqlClient;`,contextField:`
|
|
998
|
-
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"])}:
|
|
1008
|
+
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"])}:P,xr=e=>e?{build:`
|
|
999
1009
|
const browser: Browser = config.browser ? config.browser(env) : browserStub;
|
|
1000
1010
|
`,configField:`
|
|
1001
1011
|
browser?: (env: Record<string, unknown>) => Browser;`,contextField:`
|
|
1002
|
-
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"])}:
|
|
1012
|
+
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"])}:P,vr=e=>e?{build:`
|
|
1003
1013
|
const r2sqlEnv = env as Record<string, unknown>;
|
|
1004
1014
|
const r2sqlAccountId = (r2sqlEnv.R2_SQL_ACCOUNT_ID ?? r2sqlEnv.CLOUDFLARE_ACCOUNT_ID) as string | undefined;
|
|
1005
1015
|
const r2sqlToken = r2sqlEnv.R2_SQL_TOKEN as string | undefined;
|
|
@@ -1010,18 +1020,18 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
1010
1020
|
? createR2Sql({ accountId: r2sqlAccountId, apiToken: r2sqlToken, bucket: r2sqlBucket })
|
|
1011
1021
|
: r2sqlStub;
|
|
1012
1022
|
`,configField:`
|
|
1013
|
-
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"]})}:
|
|
1023
|
+
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"]})}:P,Rr=e=>e?{build:`
|
|
1014
1024
|
const pipelinesBinding = config.pipelines?.(env) ?? (env as Record<string, unknown>).PIPELINES;
|
|
1015
1025
|
const pipelines: PipelineClient = pipelinesBinding ? createPipelines({ binding: pipelinesBinding as PipelineBindingLike }) : pipelinesStub;
|
|
1016
1026
|
`,configField:`
|
|
1017
|
-
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"])}:
|
|
1027
|
+
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"])}:P,eo=(e,t)=>{if(e.length===0)return"";const n=t?`, ${JSON.stringify(t)}`:"",r=e.map(s=>(g(s.exportName,`container export "${s.exportName}"`),g(s.className,`container class "${s.className}"`),`/** Container DO for the \`${s.exportName}\` definition (binding \`${s.bindingName}\`). */
|
|
1018
1028
|
export class ${s.className} extends LunoraContainer {
|
|
1019
1029
|
public constructor(ctx: ConstructorParameters<typeof LunoraContainer>[0], env: Record<string, unknown>) {
|
|
1020
1030
|
super(ctx, env, ${s.exportName}, "${s.exportName}"${n});
|
|
1021
1031
|
}
|
|
1022
1032
|
}
|
|
1023
1033
|
`)).join(`
|
|
1024
|
-
`),o=e.map(s=>s.exportName).join(", ");return`${
|
|
1034
|
+
`),o=e.map(s=>s.exportName).join(", ");return`${$}/**
|
|
1025
1035
|
* Container-enabled Durable Object classes for the containers declared in
|
|
1026
1036
|
* \`lunora/containers.ts\`. Re-export them from your worker entry — wrangler
|
|
1027
1037
|
* requires each \`containers[].class_name\` to be exported by the worker:
|
|
@@ -1039,7 +1049,7 @@ import { ${o} } from "../containers.js";
|
|
|
1039
1049
|
|
|
1040
1050
|
export { ContainerProxy } from "@lunora/container/do";
|
|
1041
1051
|
|
|
1042
|
-
${r}`}
|
|
1052
|
+
${r}`},Sr=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const r of e)g(r.exportName,`container export "${r.exportName}"`),g(r.bindingName,`container binding "${r.bindingName}"`);const n=e.map(r=>{const o=r.maxInstances===void 0?"":`, maxInstances: ${String(r.maxInstances)}`;return` { binding: "${r.bindingName}", exportName: "${r.exportName}"${o} },`}).join(`
|
|
1043
1053
|
`);return{build:`
|
|
1044
1054
|
const containers = createContainerContext(env, LUNORA_CONTAINERS, ${t?JSON.stringify(t):"undefined"}, this.getCurrentTraceparent());
|
|
1045
1055
|
`,contextField:`
|
|
@@ -1048,14 +1058,14 @@ ${r}`},$r=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[]
|
|
|
1048
1058
|
const LUNORA_CONTAINERS: ReadonlyArray<ContainerBindingSpec> = [
|
|
1049
1059
|
${n}
|
|
1050
1060
|
];
|
|
1051
|
-
`}},
|
|
1061
|
+
`}},to=e=>{if(e.length===0)return"";const t=e.map(r=>(g(r.exportName,`workflow export "${r.exportName}"`),g(r.className,`workflow class "${r.className}"`),`/** WorkflowEntrypoint for the \`${r.exportName}\` definition (binding \`${r.bindingName}\`). */
|
|
1052
1062
|
export class ${r.className} extends LunoraWorkflow<WorkflowParamsOf<typeof ${r.exportName}>, WorkflowOutputOf<typeof ${r.exportName}>> {
|
|
1053
1063
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1054
1064
|
super(ctx, env, ${r.exportName}, "${r.exportName}");
|
|
1055
1065
|
}
|
|
1056
1066
|
}
|
|
1057
1067
|
`)).join(`
|
|
1058
|
-
`),n=e.map(r=>r.exportName).join(", ");return`${
|
|
1068
|
+
`),n=e.map(r=>r.exportName).join(", ");return`${$}/**
|
|
1059
1069
|
* WorkflowEntrypoint classes for the workflows declared in
|
|
1060
1070
|
* \`lunora/workflows.ts\`. Re-export them from your worker entry — wrangler
|
|
1061
1071
|
* requires each \`workflows[].class_name\` to be exported by the worker:
|
|
@@ -1076,21 +1086,21 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
1076
1086
|
/** Output type carried by a \`defineWorkflow\` definition (its phantom \`__output\`), so each entrypoint keeps the authored return type. */
|
|
1077
1087
|
type WorkflowOutputOf<Definition> = Definition extends { __output?: infer Output } ? Output : unknown;
|
|
1078
1088
|
|
|
1079
|
-
${t}`},
|
|
1089
|
+
${t}`},no=e=>{if(e.length===0)return"";const n=e.filter(a=>a.voice).length>0,r=e.map(a=>{g(a.exportName,`agent export "${a.exportName}"`),g(a.className,`agent class "${a.className}"`);const c=`/** WorkflowEntrypoint for the \`${a.exportName}\` agent (binding \`${a.bindingName}\`). */
|
|
1080
1090
|
export class ${a.className} extends LunoraWorkflow<AgentRunInput, AgentRunResult> {
|
|
1081
1091
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1082
1092
|
super(ctx, env, compileAgentWorkflow(${a.exportName}, "${a.exportName}"), "${a.exportName}");
|
|
1083
1093
|
}
|
|
1084
1094
|
}
|
|
1085
|
-
`;if(!a.voice)return c;const d=a.voiceClassName??"",p=a.voiceBindingName??"";g(d,`agent voice class "${d}"`);const
|
|
1095
|
+
`;if(!a.voice)return c;const d=a.voiceClassName??"",p=a.voiceBindingName??"";g(d,`agent voice class "${d}"`);const m=`
|
|
1086
1096
|
/** Voice-session Durable Object for the \`${a.exportName}\` agent (binding \`${p}\`). */
|
|
1087
1097
|
export class ${d} extends VoiceSessionDO {
|
|
1088
1098
|
public constructor(ctx: ConstructorParameters<typeof VoiceSessionDO>[0], env: Record<string, unknown>) {
|
|
1089
1099
|
super(ctx, env, ${a.exportName}, "${a.exportName}");
|
|
1090
1100
|
}
|
|
1091
1101
|
}
|
|
1092
|
-
`;return`${c}${
|
|
1093
|
-
`),o=e.map(a=>a.exportName).join(", ");return`${
|
|
1102
|
+
`;return`${c}${m}`}).join(`
|
|
1103
|
+
`),o=e.map(a=>a.exportName).join(", ");return`${$}/**
|
|
1094
1104
|
* WorkflowEntrypoint classes for the agents declared in \`lunora/agents.ts\`.
|
|
1095
1105
|
* Each \`defineAgent\` compiles a replay-safe tool-loop onto a Cloudflare
|
|
1096
1106
|
* Workflow. Re-export them from your worker entry — wrangler requires each
|
|
@@ -1104,8 +1114,8 @@ import type { AgentRunInput, AgentRunResult } from "@lunora/agent";
|
|
|
1104
1114
|
|
|
1105
1115
|
import { ${o} } from "../agents.js";
|
|
1106
1116
|
|
|
1107
|
-
${r}`},
|
|
1108
|
-
`);return`${
|
|
1117
|
+
${r}`},ro=e=>{const t=e.filter(o=>o.mode==="push");if(t.length===0)return"";for(const o of t)g(o.exportName,`queue export "${o.exportName}"`);const n=t.map(o=>o.exportName).join(", "),r=t.map(o=>` ${JSON.stringify(o.name)}: { definition: ${o.exportName}, exportName: ${JSON.stringify(o.exportName)} },`).join(`
|
|
1118
|
+
`);return`${$}/**
|
|
1109
1119
|
* Push-consumer registry for the queues declared in \`lunora/queues.ts\`. The
|
|
1110
1120
|
* composed worker's \`queue(batch, env, ctx)\` entry routes each delivered batch
|
|
1111
1121
|
* by \`batch.queue\` to the matching \`defineQueue\` handler. Wired automatically
|
|
@@ -1119,7 +1129,7 @@ import { ${n} } from "../queues.js";
|
|
|
1119
1129
|
export const LUNORA_QUEUE_REGISTRY: QueueRegistry = {
|
|
1120
1130
|
${r}
|
|
1121
1131
|
};
|
|
1122
|
-
`}
|
|
1132
|
+
`},$r=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)g(n.exportName,`workflow export "${n.exportName}"`),g(n.bindingName,`workflow binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}" },`).join(`
|
|
1123
1133
|
`);return{build:`
|
|
1124
1134
|
const workflows = createWorkflowContext(env, LUNORA_WORKFLOWS);
|
|
1125
1135
|
`,contextField:`
|
|
@@ -1128,7 +1138,7 @@ ${r}
|
|
|
1128
1138
|
const LUNORA_WORKFLOWS: ReadonlyArray<WorkflowBindingSpec> = [
|
|
1129
1139
|
${t}
|
|
1130
1140
|
];
|
|
1131
|
-
`}},
|
|
1141
|
+
`}},Nr=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)g(n.exportName,`queue export "${n.exportName}"`),g(n.bindingName,`queue binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}", name: ${JSON.stringify(n.name)} },`).join(`
|
|
1132
1142
|
`);return{build:`
|
|
1133
1143
|
const queues = createQueueContext(env, LUNORA_QUEUES);
|
|
1134
1144
|
`,contextField:`
|
|
@@ -1137,7 +1147,7 @@ ${t}
|
|
|
1137
1147
|
const LUNORA_QUEUES: ReadonlyArray<QueueBindingSpec> = [
|
|
1138
1148
|
${t}
|
|
1139
1149
|
];
|
|
1140
|
-
`}},
|
|
1150
|
+
`}},Tr=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)g(n.exportName,`agent export "${n.exportName}"`),g(n.bindingName,`agent binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}"${n.publicRun===!0?", publicRun: true":""} },`).join(`
|
|
1141
1151
|
`);return{build:`
|
|
1142
1152
|
const agents = createAgentContext(env, LUNORA_AGENTS);
|
|
1143
1153
|
`,contextField:`
|
|
@@ -1153,21 +1163,21 @@ const ${e}: ${t} = ${JSON.stringify(r,void 0,4)};
|
|
|
1153
1163
|
protected override ${n}(): ${t} {
|
|
1154
1164
|
return ${e};
|
|
1155
1165
|
}
|
|
1156
|
-
`}),
|
|
1166
|
+
`}),Ar=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 kt("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. */")},Or=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 kt("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. */")},Ir=e=>e?{imports:['import type { LunoraDatabaseLike as LunoraPaymentDbLike, LunoraPayment, PaymentsFromContextOptions } from "@lunora/payment";','import { paymentsFromContext } from "@lunora/payment";'],build:`
|
|
1157
1167
|
const payments: LunoraPayment = config.payment
|
|
1158
1168
|
? paymentsFromContext({ auth: { userId: userId ?? null }, db: db as unknown as LunoraPaymentDbLike }, config.payment(env))
|
|
1159
1169
|
: paymentStub;
|
|
1160
1170
|
`,configField:`
|
|
1161
1171
|
payment?: (env: Record<string, unknown>) => PaymentsFromContextOptions;`,contextField:`
|
|
1162
|
-
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:""},
|
|
1172
|
+
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:""},Cr=e=>e?{imports:['import type { X402Pay, X402PayConfig } from "@lunora/x402/pay";','import { lazyX402Pay } from "@lunora/x402/pay";'],build:`
|
|
1163
1173
|
const x402: X402Pay = config.x402
|
|
1164
1174
|
? lazyX402Pay(config.x402(env), { getSecret: (name: string) => secrets.get(name) })
|
|
1165
1175
|
: x402Stub;
|
|
1166
1176
|
`,configField:`
|
|
1167
|
-
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:""},
|
|
1177
|
+
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:""},Lr=(e,t,n,r,o)=>["AdvisorProcedure","AdvisoryFinding","DatabaseWriterLike","DataMigrationLike","ExportRow",...r?["FlagsResult"]:[],"ImportShardResult","KeyRange","MaskPoliciesResult","MigrationRunResult",...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"]:[]],oo=({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:y=!1,hasKv:u=!1,hasNotify:l=!1,hasPayments:f=!1,hasPipelines:k=!1,hasR2sql:R=!1,hasX402:x=!1,maskMetadata:I,mutators:T=[],queues:_=[],rlsMetadata:v,schema:w,schemaSnapshot:M,shapes:oe=[],storageRules:B,studioFeatures:ae,useUmbrella:se=!1,workflows:W=[]})=>{const C=ne(se),X=T.length>0,L=oe.length>0,S=M===void 0?"":yn(M),j=M===void 0?"":`
|
|
1168
1178
|
/** 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. */
|
|
1169
|
-
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(
|
|
1170
|
-
`,ie=M===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:le,configField
|
|
1179
|
+
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(wn(M))}, json: ${JSON.stringify(S)} };
|
|
1180
|
+
`,ie=M===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:le,configField:$e,contextField:Ne,stub:Te}=ur(a),ce=fr(i),V=pr(u),F=hr(p,C.flags),H=br(s,p,C.flags),Z=mr(l),de=gr(o),G=yr(c),U=wr(y),K=kr(m),Q=xr(d),q=vr(R),ee=Rr(k),{build:Ae,contextField:ke,importLines:xe,specs:ue}=Nr(_),{build:Oe,contextField:Ie,importLines:ve,specs:pe}=Sr(r,w.jurisdiction),{build:Ce,contextField:Le,importLines:Re,specs:_e}=$r(W),{build:De,contextField:he,importLines:me,specs:Ee}=Tr(n),{build:Pe,configField:Fe,contextField:ge,imports:fe,stub:Je}=Ir(f),{build:h,configField:Me,imports:vt,stub:Rt}=Cr(x),St=e,$t=t,Nt=v??{policies:[],roles:[]},Tt=I??{columns:[]},At=B??{rules:[]},Ot=ae??{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:It,override:Ct}=Ar(W),{constant:Lt,override:_t}=Or(_),J=w.vectorIndexes.length>0,ze=new Set(w.tables.filter(b=>typeof b.shardMode=="object"&&b.shardMode.kind==="shardBy").map(b=>b.name)),Se=w.vectorIndexes.some(b=>ze.has(b.table)),be=w.tables.some(b=>b.shardMode==="global"),Be=w.tables.some(b=>b.shardMode==="global"&&b.globalBackend==="hyperdrive"),Ye=w.tables.some(b=>b.shardMode==="global"&&b.globalBackend!=="hyperdrive"),z=w.tables.some(b=>b.externalSource!==void 0),Xe=w.tables.some(b=>b.memory===!0),je=w.tables.some(b=>b.shardMode!=="global"&&b.searchIndexes.length>0);if(Ye&&Be)throw new te("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=w.tables.length>0,Dt=rr(w),Et=ar(w),Pt=cr(w),Ft=or(w),Ze=sr(w),et=Lr(J,W.length>0,_.length>0,p,je);L&&et.push("WhereInput");const tt=dr(be),Mt=L?`
|
|
1171
1181
|
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 {
|
|
1172
1182
|
const shape = LUNORA_SHAPES[name];
|
|
1173
1183
|
|
|
@@ -1220,30 +1230,37 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
|
|
|
1220
1230
|
|
|
1221
1231
|
return { columns: shape.columns, effectiveWhere, global: isGlobal, table: shape.table };
|
|
1222
1232
|
}
|
|
1223
|
-
`:"",
|
|
1233
|
+
`:"",Bt=X?`
|
|
1224
1234
|
protected override isCustomMutator(functionPath: string): boolean {
|
|
1225
1235
|
return LUNORA_MUTATOR_PATHS.has(functionPath);
|
|
1226
1236
|
}
|
|
1227
|
-
`:"",
|
|
1228
|
-
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",
|
|
1229
|
-
d1?: (env: Record<string, unknown>, request?: { bookmark?: string; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1230
|
-
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1231
|
-
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",
|
|
1237
|
+
`:"",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":"",qt=L?"assertShapeShardable, ":"",ye=[`import type { ${et.join(", ")} } from "${C.do}";`,`import { applyCdcChanges, ${je?"backfillSearchIndexes, ":""}buildReprojectionMigration, ${Xe?"clearMemoryTables, ":""}${qt}createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, ${z?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}markUnvouchableReads, ${Se?"ROOT_SHARD_NAME, ":""}runDataMigration, runShardMigrations, ${tt.importFragment}ShardDO as ShardDOBase } from "${C.do}";`,...z?[`import type { ExternalSourceLike, SourceClientLike, TraceRefLike } from "${C.do}";`]:[],L?`import { asBucketStorage, buildRlsReadRegistry, composeShapeReadWhere, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes } from "${C.server}";`:`import { asBucketStorage, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes } from "${C.server}";`];qe&&ye.push(`import { bindOrm, bindTableFacade } from "${C.server}";`),J&&ye.push('import type { SchemaLike as VectorSchemaLike, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectors, createVectorSyncHook } from "@lunora/bindings/vectors";'),a&&ye.push('import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'),ye.push(...ce.importLines,...V.importLines,...F.importLines,...Z.importLines,...de.importLines,...G.importLines,...U.importLines,...K.importLines,...Q.importLines,...q.importLines,...ee.importLines,...ve,...Re,...xe,...me,...fe,...vt,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...X?["LUNORA_MUTATOR_PATHS"]:[],...L?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const Wt=J?`
|
|
1238
|
+
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",Ut=Ye?`
|
|
1239
|
+
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;`:"",Kt=Be?`
|
|
1240
|
+
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",Qt=z?`
|
|
1241
|
+
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",Vt='throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");',Ht='throw new Error("ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().");',Gt='throw new Error("ctx.scheduler: no scheduler configured. Pass `scheduler` to createShardDO().");',Jt='throw new Error("ctx.storage: no storage configured. Pass `storage` to createShardDO().");',zt=be?O("globalDbStub: DatabaseWriterLike",Vt,["aggregate","count","delete","findFirst","findFirstOrThrow","findMany","get","groupBy","insert","normalizeId","patch","query","rank","rankPage","replace"],{sync:["normalizeId","query"]}):"",Yt=J?O("vectorsStub: VectorSearchLike",Ht,["deleteByIds","getByIds","query","upsert","upsertNow"]):"",Xt=Se?`
|
|
1232
1242
|
const vectorShardKey = this.currentShardKey();
|
|
1233
|
-
`:"",
|
|
1243
|
+
`:"",Zt=Se?"namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, ":"",en=Se?`, { namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, shardedIndexNames: [${w.vectorIndexes.filter(b=>ze.has(b.table)).map(b=>JSON.stringify(b.name)).join(", ")}] }`:"",tn=J?`
|
|
1234
1244
|
let vectors: VectorSearchLike;
|
|
1235
1245
|
let onWrite: WriteHook | undefined;
|
|
1236
1246
|
|
|
1237
1247
|
if (config.vectors) {
|
|
1238
1248
|
const lunora = createVectors({ indexes: config.vectors(env) });
|
|
1239
|
-
${
|
|
1240
|
-
vectors = createContextVectors(lunora${
|
|
1241
|
-
onWrite = createVectorSyncHook({ ${
|
|
1249
|
+
${Xt}
|
|
1250
|
+
vectors = createContextVectors(lunora${en});
|
|
1251
|
+
onWrite = createVectorSyncHook({ ${Zt}schema: schema as unknown as VectorSchemaLike, vectors });
|
|
1242
1252
|
} else {
|
|
1243
1253
|
vectors = vectorsStub;
|
|
1244
1254
|
onWrite = undefined;
|
|
1245
1255
|
}
|
|
1246
|
-
|
|
1256
|
+
|
|
1257
|
+
// Vectorize lives outside this shard's SQLite, so a query whose result
|
|
1258
|
+
// depends on a similarity search cannot be proven current on reconnect —
|
|
1259
|
+
// an unrelated upsert (or a re-index) moves the matches without touching
|
|
1260
|
+
// \`__cdc_log\`. Wrapped AFTER \`onWrite\` is built so the write-through
|
|
1261
|
+
// vector-sync hook keeps calling the bare facade.
|
|
1262
|
+
vectors = markUnvouchableReads(vectors, options.onRead, ["getByIds", "query"]);
|
|
1263
|
+
`:"",nn=`{
|
|
1247
1264
|
auth: { identity: identity ?? null, userId: userId ?? null },
|
|
1248
1265
|
broadcast: (delta) => {
|
|
1249
1266
|
this.recordChangedTable(delta.table, delta.indexKeys);
|
|
@@ -1265,12 +1282,12 @@ ${Yt}
|
|
|
1265
1282
|
inTransaction: () => this.isInTransaction(),
|
|
1266
1283
|
onIndexUse: this.getCtxDbIndexUseHook(),
|
|
1267
1284
|
onRead: options.onRead ?? this.getCtxDbReadHook(),
|
|
1268
|
-
onReadRange: options.onReadRange,${
|
|
1285
|
+
onReadRange: options.onReadRange,${J?`
|
|
1269
1286
|
onWrite,`:""}
|
|
1270
1287
|
scheduler,
|
|
1271
1288
|
schema: schema as unknown as SchemaLike,
|
|
1272
1289
|
sql: this.sql as SqlExec,
|
|
1273
|
-
storage,${
|
|
1290
|
+
storage,${be?`
|
|
1274
1291
|
globalDb,`:""}
|
|
1275
1292
|
}`,Y=` const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1276
1293
|
const scheduler = (config.scheduler?.(env) ?? schedulerStub) as SchedulerLike;
|
|
@@ -1284,18 +1301,18 @@ ${Yt}
|
|
|
1284
1301
|
scheduler,
|
|
1285
1302
|
schema: schema as unknown as SchemaLike,
|
|
1286
1303
|
sql: this.sql as SqlExec,
|
|
1287
|
-
});`,
|
|
1288
|
-
vectors,`:"",
|
|
1289
|
-
orm: bindOrm(facade),`:"",
|
|
1290
|
-
const globalDb: DatabaseWriterLike = ${
|
|
1291
|
-
`:"",
|
|
1304
|
+
});`,rn=J?`
|
|
1305
|
+
vectors,`:"",on=qe?`
|
|
1306
|
+
orm: bindOrm(facade),`:"",We=Be?"config.hyperdriveGlobal":"config.d1",an=be?` const globalRequest = { ...this.globalCdcOptions(config.cdc ?? false), bookmark: this.getInboundBookmark(), identity, onBookmark: (bookmarkValue: string | undefined) => { this.setOutboundBookmark(bookmarkValue); }, userId };
|
|
1307
|
+
const globalDb: DatabaseWriterLike = ${We}?.(env, globalRequest) ?? globalDbStub;
|
|
1308
|
+
`:"",sn=L&&be?`
|
|
1292
1309
|
protected override async readGlobalShapeRows(resolved: { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string }, identity?: { identity?: Record<string, unknown>; userId?: string }): Promise<Array<{ doc: Record<string, unknown>; id: string }>> {
|
|
1293
1310
|
const env = this.env as Record<string, unknown>;
|
|
1294
1311
|
// A shape read performs no writes, so the widened request only needs
|
|
1295
1312
|
// the inbound bookmark (pin the membership drain to the caller's own
|
|
1296
1313
|
// prior writes) — no \`onBookmark\` here.
|
|
1297
|
-
const globalRequest = { ...identity, bookmark: this.getInboundBookmark() };
|
|
1298
|
-
const globalDb: DatabaseWriterLike = ${
|
|
1314
|
+
const globalRequest = { ...identity, ...this.globalCdcOptions(config.cdc ?? false), bookmark: this.getInboundBookmark() };
|
|
1315
|
+
const globalDb: DatabaseWriterLike = ${We}?.(env, globalRequest) ?? globalDbStub;
|
|
1299
1316
|
const rows: Array<{ doc: Record<string, unknown>; id: string }> = [];
|
|
1300
1317
|
|
|
1301
1318
|
let cursor: null | string = null;
|
|
@@ -1322,17 +1339,28 @@ ${Yt}
|
|
|
1322
1339
|
|
|
1323
1340
|
return rows;
|
|
1324
1341
|
}
|
|
1325
|
-
|
|
1342
|
+
|
|
1343
|
+
protected override async readGlobalChangedTables(sinceSeq: number, cursorOnly?: boolean): Promise<{ cursor: number; floor?: number; tables: string[] } | undefined> {
|
|
1344
|
+
const env = this.env as Record<string, unknown>;
|
|
1345
|
+
// Metadata-only: this asks the global changelog which TABLES moved,
|
|
1346
|
+
// never what changed in them, so it costs one small read per poll tick
|
|
1347
|
+
// for the whole shard — and a tick whose answer omits a shape's table
|
|
1348
|
+
// skips that shape's membership drain entirely.
|
|
1349
|
+
const globalDb: DatabaseWriterLike = ${We}?.(env, { ...this.globalCdcOptions(config.cdc ?? false), bookmark: this.getInboundBookmark() }) ?? globalDbStub;
|
|
1350
|
+
|
|
1351
|
+
return globalDb.cdcChangedTables?.(sinceSeq, { cursorOnly });
|
|
1352
|
+
}
|
|
1353
|
+
`:"",ln=z?`
|
|
1326
1354
|
const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
|
|
1327
1355
|
const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
1328
|
-
`:"",
|
|
1356
|
+
`:"",cn=`
|
|
1329
1357
|
protected override async runShardInit(): Promise<void> {
|
|
1330
1358
|
this.ensureMigrated();
|
|
1331
|
-
${
|
|
1359
|
+
${Xe?` clearMemoryTables(this.sql as SqlExec, schema as unknown as SchemaLike);
|
|
1332
1360
|
`:""}
|
|
1333
1361
|
await this.dispatchShardInit();
|
|
1334
1362
|
}
|
|
1335
|
-
`,
|
|
1363
|
+
`,dn=z?`
|
|
1336
1364
|
protected override async pollExternalSources(trace?: TraceRefLike): Promise<number | undefined> {
|
|
1337
1365
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1338
1366
|
const sourced = Object.entries((schema as unknown as SchemaLike).tables)
|
|
@@ -1467,7 +1495,7 @@ ${ze?` clearMemoryTables(this.sql as SqlExec, schema as unknown as Sc
|
|
|
1467
1495
|
|
|
1468
1496
|
return nextDueAt;
|
|
1469
1497
|
}
|
|
1470
|
-
`:"",
|
|
1498
|
+
`:"",nt=Ze.length>0,un=z||nt?`
|
|
1471
1499
|
public constructor(state: ShardDOState, env: unknown) {
|
|
1472
1500
|
super(state, env);
|
|
1473
1501
|
${z?`
|
|
@@ -1480,27 +1508,27 @@ ${z?`
|
|
|
1480
1508
|
if (autoSourced) {
|
|
1481
1509
|
void this.scheduleSourcePoll();
|
|
1482
1510
|
}
|
|
1483
|
-
`:""}${
|
|
1511
|
+
`:""}${nt?`
|
|
1484
1512
|
if (LUNORA_TTL_SWEEPS.length > 0) {
|
|
1485
1513
|
void this.scheduleTtlSweep();
|
|
1486
1514
|
}
|
|
1487
1515
|
`:""} }
|
|
1488
|
-
`:"",
|
|
1516
|
+
`:"",pn=qe?`
|
|
1489
1517
|
const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
|
|
1490
|
-
${
|
|
1518
|
+
${w.tables.map(b=>` facade[${JSON.stringify(b.name)}] = bindTableFacade(db, ${JSON.stringify(b.name)});`).join(`
|
|
1491
1519
|
`)}
|
|
1492
|
-
`:"",
|
|
1520
|
+
`:"",hn=`${ce.build}${V.build}${F.build}${G.build}${de.build}
|
|
1493
1521
|
const secrets = createSecrets(env);
|
|
1494
|
-
`,mn=`${ce.contextField}${V.contextField}${
|
|
1495
|
-
secrets,`,
|
|
1522
|
+
`,mn=`${ce.contextField}${V.contextField}${F.contextField}${Z.contextField}${G.contextField}${de.contextField}
|
|
1523
|
+
secrets,`,gn=Z.build,rt=y||m||d||R||k||x,fn=rt?`
|
|
1496
1524
|
// ActionCtx-only helpers (external, non-deterministic I/O): constructed
|
|
1497
1525
|
// and attached only for an \`action\` so query/mutation ctx never carry them.
|
|
1498
1526
|
if (isAction) {
|
|
1499
|
-
${U.build}${K.build}${Q.build}${q.build}${ee.build}${
|
|
1527
|
+
${U.build}${K.build}${Q.build}${q.build}${ee.build}${h}${[...y?[" ctx.images = images;"]:[],...m?[" ctx.sql = sql;"]:[],...d?[" ctx.browser = browser;"]:[],...R?[" ctx.r2sql = r2sql;"]:[],...k?[" ctx.pipelines = pipelines;"]:[],...x?[" ctx.x402 = x402;"]:[]].join(`
|
|
1500
1528
|
`)}
|
|
1501
1529
|
}
|
|
1502
|
-
`:"",
|
|
1503
|
-
`:"";return`${
|
|
1530
|
+
`:"",bn=rt?` const isAction = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind === "action";
|
|
1531
|
+
`:"";return`${$}${ye.join(`
|
|
1504
1532
|
`)}
|
|
1505
1533
|
|
|
1506
1534
|
type FunctionKind = "action" | "mutation" | "query";
|
|
@@ -1510,7 +1538,7 @@ interface FunctionReference {
|
|
|
1510
1538
|
}
|
|
1511
1539
|
|
|
1512
1540
|
/** Foreign-key columns per table (\`v.id("target")\` fields) for the data browser. */
|
|
1513
|
-
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(
|
|
1541
|
+
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(Dt,void 0,4)};
|
|
1514
1542
|
|
|
1515
1543
|
/** Declared indexes per table (secondary, search, geo, rank, vector) for the schema viewer. */
|
|
1516
1544
|
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(Et,void 0,4)};
|
|
@@ -1519,41 +1547,41 @@ const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: strin
|
|
|
1519
1547
|
const LUNORA_TABLE_COLUMNS: Record<
|
|
1520
1548
|
string,
|
|
1521
1549
|
Array<{ bucket?: string; enumValues?: string[]; isStorage?: boolean; name: string; nullable?: boolean; optional: boolean; pk?: boolean; ref?: string; type: string }>
|
|
1522
|
-
> = ${JSON.stringify(
|
|
1550
|
+
> = ${JSON.stringify(Pt,void 0,4)};
|
|
1523
1551
|
|
|
1524
1552
|
/** Storage-key columns per table (\`v.storage(...)\` fields) for the file browser's records↔files join. */
|
|
1525
1553
|
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(Ft,void 0,4)};
|
|
1526
1554
|
|
|
1527
1555
|
/** Declarative TTL policies (\`.ttl(field, { after? })\`) the DO alarm sweep auto-expires rows for. */
|
|
1528
|
-
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(
|
|
1556
|
+
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(Ze,void 0,4)};
|
|
1529
1557
|
|
|
1530
1558
|
/** Static schema advisories (computed by @lunora/advisor at codegen time) served via \`__lunora_admin__:getAdvisories\`. */
|
|
1531
|
-
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(
|
|
1559
|
+
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(St,void 0,4)};
|
|
1532
1560
|
|
|
1533
1561
|
/** Every declared procedure (discovered by @lunora/codegen) served via \`__lunora_admin__:getAdvisorProcedures\` — the health map's denominator. */
|
|
1534
|
-
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(
|
|
1562
|
+
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify($t,void 0,4)};
|
|
1535
1563
|
|
|
1536
1564
|
/** Read-only RLS metadata (policies + roles discovered from \`.use(rls(...))\` chains) served via \`__lunora_admin__:rlsPolicies\` for the studio's RLS inspector. */
|
|
1537
|
-
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(
|
|
1565
|
+
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(Nt,void 0,4)};
|
|
1538
1566
|
|
|
1539
1567
|
/** 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. */
|
|
1540
|
-
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(
|
|
1568
|
+
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(Tt,void 0,4)};
|
|
1541
1569
|
|
|
1542
1570
|
/** Read-only storage access-rule metadata (discovered from \`.use(storageRules(...))\` chains) served via \`__lunora_admin__:storageRules\` for the studio's access-rules view. */
|
|
1543
|
-
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(
|
|
1571
|
+
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(At,void 0,4)};
|
|
1544
1572
|
|
|
1545
1573
|
/** 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. */
|
|
1546
|
-
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(
|
|
1547
|
-
${j}${H.constant}${
|
|
1574
|
+
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(Ot,void 0,4)};
|
|
1575
|
+
${j}${H.constant}${jt}${It}${Lt}${pe}${_e}${ue}${Ee}
|
|
1548
1576
|
export interface ShardDOConfig {
|
|
1549
1577
|
/** Opt into change-data-capture: records a post-image to \`__cdc_log\` on every write (backs streaming export + replay-PITR). */
|
|
1550
1578
|
cdc?: boolean;
|
|
1551
1579
|
/** Optional telemetry sink. When supplied, each \`ctx.log.*\` call is forwarded to \`sink.onLog\`. Pass the SAME sink you give \`createWorker({ observability })\` (which drives \`onRpc\`) to route both RPC and log events. */
|
|
1552
1580
|
observability?: (env: Record<string, unknown>) => TelemetrySink | undefined;
|
|
1553
1581
|
scheduler?: (env: Record<string, unknown>) => unknown;
|
|
1554
|
-
storage?: (env: Record<string, unknown>) => unknown;${
|
|
1582
|
+
storage?: (env: Record<string, unknown>) => unknown;${Wt}${$e}${V.configField}${F.configField}${G.configField}${U.configField}${K.configField}${Q.configField}${q.configField}${ee.configField}${Fe}${Me}${Ut}${Kt}${Qt}
|
|
1555
1583
|
}
|
|
1556
|
-
${O("schedulerStub",
|
|
1584
|
+
${O("schedulerStub",Gt,["cancel","runAfter","runAt"])}${O("storageStub",Jt,["delete","download","getMetadata","getSignedUrl","getUrl","head","list","upload"],{sync:["getUrl"]})}${zt}${ln}${Yt}${Te}${V.stub}${F.stub}${G.stub}${U.stub}${K.stub}${Q.stub}${q.stub}${ee.stub}${Je}${Rt}
|
|
1557
1585
|
// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
|
|
1558
1586
|
// referencing call fails loudly with a clear error instead of overflowing the
|
|
1559
1587
|
// stack. Tracked across the awaited handler chain (one DO invocation is
|
|
@@ -1590,7 +1618,7 @@ const dispatchRun = async (expected: FunctionKind, functionPath: string, args: R
|
|
|
1590
1618
|
* from the worker entry so wrangler binds it by name.
|
|
1591
1619
|
*/
|
|
1592
1620
|
export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOState, env: unknown) => ShardDOBase =>
|
|
1593
|
-
class extends ShardDOBase {${
|
|
1621
|
+
class extends ShardDOBase {${un}
|
|
1594
1622
|
private migrated = false;
|
|
1595
1623
|
|
|
1596
1624
|
public override async handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker): Promise<unknown> {
|
|
@@ -1628,16 +1656,38 @@ export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOSt
|
|
|
1628
1656
|
// watermark are atomic — a crash can't leave the writes durable without
|
|
1629
1657
|
// the replay guard.
|
|
1630
1658
|
if (registered.kind === "mutation") {
|
|
1631
|
-
|
|
1632
|
-
const
|
|
1659
|
+
const result = await this.runInTransaction(async () => {
|
|
1660
|
+
const value = await registered.handler(ctx, args);
|
|
1633
1661
|
|
|
1634
|
-
this.commitMutationBookkeeping(
|
|
1662
|
+
this.commitMutationBookkeeping(value);
|
|
1635
1663
|
|
|
1636
|
-
return
|
|
1664
|
+
return value;
|
|
1637
1665
|
});
|
|
1666
|
+
|
|
1667
|
+
// The transaction committed, so the rows are durable and the objects
|
|
1668
|
+
// their deletion orphaned can go. Deliberately AFTER the span, never
|
|
1669
|
+
// inside it: an R2 delete cannot roll back, so a delete issued from
|
|
1670
|
+
// within a transaction that later aborts destroys data the surviving
|
|
1671
|
+
// row still points at. A throw above skips this entirely and the
|
|
1672
|
+
// queue dies with \`ctx\`.
|
|
1673
|
+
//
|
|
1674
|
+
// \`flushDeferredDeletes\` never rejects — the mutation has already
|
|
1675
|
+
// succeeded, so a failed cleanup must not turn into a failed response.
|
|
1676
|
+
// A leaked object is reported through \`ctx.log\` instead, with its key.
|
|
1677
|
+
await this.deferPastResponse(flushDeferredDeletes(ctx));
|
|
1678
|
+
|
|
1679
|
+
return result;
|
|
1638
1680
|
}
|
|
1639
1681
|
|
|
1640
|
-
|
|
1682
|
+
const result = await registered.handler(ctx, args);
|
|
1683
|
+
|
|
1684
|
+
// An action is not itself transactional, but \`ctx.runMutation\` runs its
|
|
1685
|
+
// submutations on THIS ctx, so their queued deletes land here — this is
|
|
1686
|
+
// the first point at which those writes are known to have committed. A
|
|
1687
|
+
// dispatch with nothing queued no-ops.
|
|
1688
|
+
await this.deferPastResponse(flushDeferredDeletes(ctx));
|
|
1689
|
+
|
|
1690
|
+
return result;
|
|
1641
1691
|
}
|
|
1642
1692
|
|
|
1643
1693
|
// Only a \`mutation\` may enter the base class's single-writer gate for
|
|
@@ -1648,7 +1698,7 @@ export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOSt
|
|
|
1648
1698
|
protected override isMutationFunction(functionPath: string): boolean {
|
|
1649
1699
|
return LUNORA_FUNCTIONS[functionPath]?.kind === "mutation";
|
|
1650
1700
|
}
|
|
1651
|
-
${
|
|
1701
|
+
${tt.override}
|
|
1652
1702
|
protected override async executeSubscription(functionPath: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): Promise<{ ranges?: Map<string, KeyRange[]>; result: unknown; tables: Set<string> } | null> {
|
|
1653
1703
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
1654
1704
|
|
|
@@ -1684,11 +1734,11 @@ ${Ze.override}
|
|
|
1684
1734
|
iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath }), args, signal),
|
|
1685
1735
|
};
|
|
1686
1736
|
}
|
|
1687
|
-
${
|
|
1737
|
+
${Bt}${Mt}${sn}${dn}
|
|
1688
1738
|
protected override lifecycleHookPaths(event: "connect" | "disconnect" | "init" | "reactor"): readonly string[] {
|
|
1689
1739
|
return LUNORA_LIFECYCLE_HOOKS[event];
|
|
1690
1740
|
}
|
|
1691
|
-
${
|
|
1741
|
+
${cn}
|
|
1692
1742
|
// One \`onQueryChange\` dispatch. Mirrors \`executeSubscription\` — the
|
|
1693
1743
|
// socket-terminated half of the same reactivity — and differs only in who
|
|
1694
1744
|
// consumes the result: the base's \`dispatchReactors\` stores the digest as
|
|
@@ -1722,6 +1772,13 @@ ${ln}
|
|
|
1722
1772
|
ran: boolean;
|
|
1723
1773
|
};
|
|
1724
1774
|
|
|
1775
|
+
// A reactor IS a mutation, so its ctx carries the deferred-delete queue
|
|
1776
|
+
// and its transaction has just committed. Without this the queue would
|
|
1777
|
+
// die with \`ctx\` and the objects would leak with nothing to find: no
|
|
1778
|
+
// error, no warning, no failed request — a reactor that reaps orphaned
|
|
1779
|
+
// rows is a textbook use of one.
|
|
1780
|
+
await this.deferPastResponse(flushDeferredDeletes(ctx));
|
|
1781
|
+
|
|
1725
1782
|
return { digest: outcome.digest, ran: outcome.ran, tables: [...footprint.tables] };
|
|
1726
1783
|
}
|
|
1727
1784
|
|
|
@@ -1763,7 +1820,7 @@ ${ln}
|
|
|
1763
1820
|
protected override studioFeatures(): StudioFeaturesResult {
|
|
1764
1821
|
return LUNORA_STUDIO_FEATURES;
|
|
1765
1822
|
}
|
|
1766
|
-
${H.evaluateOverride}${H.subscriptionOverride}${
|
|
1823
|
+
${H.evaluateOverride}${H.subscriptionOverride}${Ct}${_t}
|
|
1767
1824
|
protected override advisories(): AdvisoryFinding[] {
|
|
1768
1825
|
return LUNORA_ADVISORIES;
|
|
1769
1826
|
}
|
|
@@ -1986,7 +2043,16 @@ ${Y}
|
|
|
1986
2043
|
runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${ie} });
|
|
1987
2044
|
this.migrated = true;
|
|
1988
2045
|
}
|
|
2046
|
+
${je?`
|
|
2047
|
+
protected override runShardSearchBackfill(options: { maxPages?: number }): SearchBackfillProgress {
|
|
2048
|
+
// Migrations create the fts5 companions; without them every backfill
|
|
2049
|
+
// statement would raise "no such table" on a shard that has never
|
|
2050
|
+
// served a request.
|
|
2051
|
+
this.ensureMigrated();
|
|
1989
2052
|
|
|
2053
|
+
return backfillSearchIndexes(this.sql as SqlExec, schema as unknown as SchemaLike, options);
|
|
2054
|
+
}
|
|
2055
|
+
`:""}
|
|
1990
2056
|
private buildCtx(options: { functionPath?: string; headroom?: TransactionHeadroomTracker; identity?: { identity?: Record<string, unknown>; userId?: string }; onRead?: (table: string, idOrScan?: string) => void; onReadRange?: (range: KeyRange) => void; trusted?: boolean } = {}): unknown {
|
|
1991
2057
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1992
2058
|
// When the caller threads an explicit identity (subscription seed /
|
|
@@ -1996,13 +2062,48 @@ ${Y}
|
|
|
1996
2062
|
// dispatch path) fall back to the per-request fields as before.
|
|
1997
2063
|
const userId = options.identity ? options.identity.userId : this.getCurrentUserId();
|
|
1998
2064
|
const identity = options.identity ? options.identity.identity : this.getCurrentIdentity();
|
|
1999
|
-
${
|
|
2000
|
-
|
|
2065
|
+
${tn}${le}${hn}${Oe}${Ce}${Ae}${De}
|
|
2066
|
+
// \`list\`/\`get\` are the two methods \`ctx.db.system.query("_scheduled_functions")\`
|
|
2067
|
+
// reaches through, and pending jobs live in the SchedulerDO — nothing the
|
|
2068
|
+
// CDC changelog records — so reading them must forfeit a delta resume.
|
|
2069
|
+
// The scheduler's own \`runAfter\`/\`runAt\`/\`cancel\` are writes and stay unstamped.
|
|
2070
|
+
const scheduler = markUnvouchableReads((config.scheduler?.(env) ?? schedulerStub) as SchedulerLike, options.onRead, ["get", "list"]);
|
|
2001
2071
|
// Build the storage adapter once and share it between \`ctx.storage\`
|
|
2002
2072
|
// and \`ctx.db.system._storage\` so both read the same R2 binding. The
|
|
2003
2073
|
// \`storageStub\` fallback satisfies SystemReaderStorageLike structurally
|
|
2004
2074
|
// (its \`list\`/\`getMetadata\` throw the "no storage configured" error).
|
|
2005
|
-
|
|
2075
|
+
//
|
|
2076
|
+
// Wrapped BEFORE the split so both consumers share one stamping facade.
|
|
2077
|
+
// Only the methods that actually reach R2 are stamped: \`getUrl\` and
|
|
2078
|
+
// \`getSignedUrl\` build a URL from the configured base (and an HMAC) and
|
|
2079
|
+
// read nothing, and they are what handlers overwhelmingly call — stamping
|
|
2080
|
+
// them would forfeit resumes for a dependency that cannot move the result.
|
|
2081
|
+
// \`bucket\` IS stamped: it hands back a sub-facade this wrapper does not
|
|
2082
|
+
// reach, so the selection is the last point at which the read can be seen.
|
|
2083
|
+
const storage = markUnvouchableReads(asBucketStorage(config.storage?.(env) ?? storageStub) as SystemReaderStorageLike, options.onRead, [
|
|
2084
|
+
"bucket",
|
|
2085
|
+
"download",
|
|
2086
|
+
"getMetadata",
|
|
2087
|
+
"list",
|
|
2088
|
+
]);
|
|
2089
|
+
// \`ctx.storage.deleteAfterCommit(key)\`, on every dispatch that can host
|
|
2090
|
+
// a MUTATION handler — which is not only a mutation dispatch:
|
|
2091
|
+
// \`ctx.runMutation\` hands the CALLER's ctx to the callee, so a mutation
|
|
2092
|
+
// reached from an action runs on the action's ctx. Wrapping mutations
|
|
2093
|
+
// alone made that composition throw a bare TypeError on a method the
|
|
2094
|
+
// handler's own type promises. Queries stay unwrapped: they cannot host
|
|
2095
|
+
// one, and their ctx is built on the hot subscription path.
|
|
2096
|
+
//
|
|
2097
|
+
// Every dispatch wrapped here also flushes (see \`handleRpc\` and
|
|
2098
|
+
// \`runReactor\`) — a queue nothing drains leaks silently, which is worse
|
|
2099
|
+
// than not having the method at all.
|
|
2100
|
+
//
|
|
2101
|
+
// Wrapped OUTSIDE the read-stamping facade so \`bucket(name)\` still
|
|
2102
|
+
// resolves through it and stays stamped, and applied only to
|
|
2103
|
+
// \`ctx.storage\` so \`ctx.db.system._storage\` (which shares the adapter
|
|
2104
|
+
// above) is untouched.
|
|
2105
|
+
const contextKind = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind;
|
|
2106
|
+
const contextStorage = contextKind === "mutation" || contextKind === "action" ? withDeferredDeletes(storage) : storage;
|
|
2006
2107
|
// \`ctx.log\`: the DO base builds the attributed logger (structured
|
|
2007
2108
|
// fields + \`.with(...)\` child + trace correlation) and routes each call
|
|
2008
2109
|
// to the optional \`observability\` sink. It also buffers the line (studio
|
|
@@ -2023,13 +2124,13 @@ ${en}${le}${pn}${Oe}${Ce}${Ae}${Ee}
|
|
|
2023
2124
|
// so both write to the same trace.
|
|
2024
2125
|
const span = this.makeDispatchSpan(traceAnchor, observability);
|
|
2025
2126
|
|
|
2026
|
-
${
|
|
2127
|
+
${an} // \`ctx.db\`, wrapped in automatic instrumentation: by default this
|
|
2027
2128
|
// adds aggregate counters (call count, total time, per-operation
|
|
2028
2129
|
// breakdown) to the wide event rather than a span per call, so a
|
|
2029
2130
|
// handler making hundreds of queries stays readable. See
|
|
2030
2131
|
// \`instrumentDatabase\` for the \`"spans"\` / \`"off"\` levels.
|
|
2031
|
-
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${
|
|
2032
|
-
${
|
|
2132
|
+
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${nn}), logFunctionPath, traceAnchor, observability);
|
|
2133
|
+
${pn}${Pe}
|
|
2033
2134
|
|
|
2034
2135
|
// \`ctx.trace\` / \`ctx.metrics\`: spans and measurements to the same sink.
|
|
2035
2136
|
// The trace anchor is threaded explicitly for the same reason \`identity\`
|
|
@@ -2037,7 +2138,7 @@ ${un}${Fe}
|
|
|
2037
2138
|
// writing mutation's trace from the shared per-request field.
|
|
2038
2139
|
const trace = this.makeTracer(logFunctionPath, observability, traceAnchor);
|
|
2039
2140
|
const metrics = this.makeMetrics(logFunctionPath, observability);
|
|
2040
|
-
${
|
|
2141
|
+
${gn}
|
|
2041
2142
|
// \`ctx.now\`: the wall-clock instant (epoch ms) this function began,
|
|
2042
2143
|
// captured ONCE so the whole handler body sees a single stable value.
|
|
2043
2144
|
// Query/mutation handlers must be deterministic (they may be re-run on
|
|
@@ -2060,13 +2161,13 @@ ${hn}
|
|
|
2060
2161
|
ip: this.getCurrentIp(),
|
|
2061
2162
|
log,
|
|
2062
2163
|
metrics,
|
|
2063
|
-
now,${
|
|
2164
|
+
now,${on}
|
|
2064
2165
|
scheduler,
|
|
2065
2166
|
span,
|
|
2066
|
-
storage,
|
|
2067
|
-
trace,${
|
|
2167
|
+
storage: contextStorage,
|
|
2168
|
+
trace,${rn}${Ne}${mn}${ge}${Ie}${Le}${ke}${he}
|
|
2068
2169
|
};
|
|
2069
|
-
${
|
|
2170
|
+
${bn}${fn}
|
|
2070
2171
|
ctx.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, ctx);
|
|
2071
2172
|
ctx.runMutation = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("mutation", reference.__lunoraRef, fnArgs, ctx);
|
|
2072
2173
|
// \`ctx.runQuery(ref, args, { untracked: true })\` runs the sub-query on
|
|
@@ -2092,21 +2193,21 @@ ${fn}${gn}
|
|
|
2092
2193
|
return ctx;
|
|
2093
2194
|
}
|
|
2094
2195
|
};
|
|
2095
|
-
`},
|
|
2196
|
+
`},Ge=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?Ge(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},xt=(e,t)=>{const n=re(e);return n.kind==="id"&&n.tableName!==void 0&&t.has(n.tableName)?n.tableName:void 0},_r=(e,t,n)=>{g(e,"drizzle column name");const r=Ge(t),o=r.mode?`, { mode: "${r.mode}" }`:"";let s=`${r.builder}("${e}"${o})`;r.typeAnnotation&&(s+=`.$type<${r.typeAnnotation}>()`);const i=xt(t,n);return i!==void 0&&(s+=`.references((): AnySQLiteColumn => ${i}._id)`),r.notNull&&(s+=".notNull()"),s},Dr=e=>{g(e.name,"drizzle index name");const t=e.unique?"uniqueIndex":"index",n=e.fields.map(r=>(g(r,"drizzle index field"),`t.${r}`)).join(", ");return` ${e.name}: ${t}("${e.name}").on(${n}),`},Er=(e,t)=>{g(e.name,"table name");const n=[' _id: text("_id").primaryKey(),',' _creationTime: integer("_creationTime").notNull(),',...Object.entries(e.shape).map(([o,s])=>` ${o}: ${_r(o,s,t)},`)].join(`
|
|
2096
2197
|
`),r=e.indexes.length>0?`, (t) => ({
|
|
2097
|
-
${e.indexes.map(o=>
|
|
2198
|
+
${e.indexes.map(o=>Dr(o)).join(`
|
|
2098
2199
|
`)}
|
|
2099
2200
|
})`:"";return`export const ${e.name} = sqliteTable("${e.name}", {
|
|
2100
2201
|
${n}
|
|
2101
|
-
}${r});`},
|
|
2102
|
-
`;const n=ne(t),r=new Set(e.map(
|
|
2202
|
+
}${r});`},Pr=e=>e.typeAnnotation?.includes('Id<"')??!1,Fr=(e,t)=>{const n=new Set(["integer","sqliteTable","text"]),r=new Set;let o=!1,s=!1;for(const i of e){for(const a of Object.values(i.shape)){const c=Ge(a);n.add(c.builder),s=s||Pr(c),o=o||xt(a,t)!==void 0}for(const a of i.indexes)r.add(a.unique?"uniqueIndex":"index")}return{columns:[...n].toSorted((i,a)=>i.localeCompare(a)),indexes:[...r].toSorted((i,a)=>i.localeCompare(a)),needsAnyColumn:o,needsId:s}},at=(e,t=!1)=>{if(e.length===0)return`${$}export {};
|
|
2203
|
+
`;const n=ne(t),r=new Set(e.map(m=>m.name)),{columns:o,indexes:s,needsAnyColumn:i,needsId:a}=Fr(e,r),c=[...s,...o].toSorted((m,y)=>m.localeCompare(y)),d=e.map(m=>Er(m,r)).join(`
|
|
2103
2204
|
|
|
2104
2205
|
`),p=[i?`import type { AnySQLiteColumn } from "${n.serverDrizzle}";
|
|
2105
2206
|
`:"",a?`import type { Id } from "./dataModel.js";
|
|
2106
|
-
`:""].join("");return`${
|
|
2207
|
+
`:""].join("");return`${$}import { ${c.join(", ")} } from "${n.serverDrizzle}";
|
|
2107
2208
|
${p}
|
|
2108
2209
|
${d}
|
|
2109
|
-
`},
|
|
2210
|
+
`},ao=(e,t=!1)=>{const n=e.tables.filter(o=>o.shardMode==="global"),r=e.tables.filter(o=>o.shardMode!=="global");return{global:E(at(n,t),Qe),shard:E(at(r,t),Qe)}},so=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(`
|
|
2110
2211
|
`),r=n.length>0?`
|
|
2111
2212
|
${n}
|
|
2112
2213
|
`:"",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(`
|
|
@@ -2115,7 +2216,7 @@ ${c}
|
|
|
2115
2216
|
],`}).join(`
|
|
2116
2217
|
`),s=o.length>0?`
|
|
2117
2218
|
${o}
|
|
2118
|
-
`:"";return`${
|
|
2219
|
+
`:"";return`${$}/**
|
|
2119
2220
|
* One scheduled cron invocation. Exactly one target is set: \`functionPath\` is
|
|
2120
2221
|
* the \`namespace:fn\` dispatch ref (matches \`__lunoraRef\`), invoked on the
|
|
2121
2222
|
* shard; \`workflow\` is a \`WORKFLOW_*\` binding name whose durable workflow is
|
|
@@ -2140,10 +2241,10 @@ export const LUNORA_CRON_TRIGGERS: ReadonlyArray<string> = [${r}];
|
|
|
2140
2241
|
* looks up \`event.cron\` here and dispatches every job in the list.
|
|
2141
2242
|
*/
|
|
2142
2243
|
export const LUNORA_CRONS: Record<string, ReadonlyArray<LunoraCronJob>> = {${s}};
|
|
2143
|
-
`},
|
|
2244
|
+
`},io=e=>{const t=[...e].toSorted((r,o)=>r.name.localeCompare(o.name)).map(r=>{const o=[`name: ${JSON.stringify(r.name)}`,`table: ${JSON.stringify(r.table)}`];return r.field!==void 0&&o.push(`field: ${JSON.stringify(r.field)}`),r.dimensions!==void 0&&o.push(`dimensions: ${JSON.stringify(r.dimensions)}`),r.metric!==void 0&&o.push(`metric: ${JSON.stringify(r.metric)}`),r.metadata!==void 0&&o.push(`metadata: ${JSON.stringify(r.metadata)}`),` { ${o.join(", ")} },`}).join(`
|
|
2144
2245
|
`),n=t.length>0?`
|
|
2145
2246
|
${t}
|
|
2146
|
-
`:"";return`${
|
|
2247
|
+
`:"";return`${$}/**
|
|
2147
2248
|
* One vector index declared in \`schema.ts\` — an inline \`.vectorize()\` column
|
|
2148
2249
|
* or a standalone \`defineVectorIndex()\`. \`field\` is the source column (absent
|
|
2149
2250
|
* for a \`select\`-derived Shape B index); \`metadata\` lists the row fields
|
|
@@ -2164,4 +2265,4 @@ export interface LunoraVectorIndex {
|
|
|
2164
2265
|
* \`createWorker({ vectorIntrospector })\` to back the studio's vector browser.
|
|
2165
2266
|
*/
|
|
2166
2267
|
export const LUNORA_VECTOR_INDEXES: ReadonlyArray<LunoraVectorIndex> = [${n}];
|
|
2167
|
-
`},
|
|
2268
|
+
`},lo=e=>[...new Set(e.map(t=>t.cron))];export{Hr as A,kn as C,$ as G,jn as U,Jr as a,Yr as b,eo as c,so as d,no as e,Gr as f,ao as g,Zr as h,Xr as i,oo as j,io as k,to as l,lo as m,or as n,ro as o,zr as p};
|