@lunora/codegen 1.0.0-alpha.209 → 1.0.0-alpha.210
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 +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/{GENERATED_HEADER-uwXtvaIR.mjs → GENERATED_HEADER-Clwlg6jB.mjs} +1 -1
- package/dist/packem_shared/{OPENRPC_VERSION-BDtZHc87.mjs → OPENRPC_VERSION-BRCNaNPW.mjs} +1 -1
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_FILENAME-D6t1w2ef.mjs → SCHEMA_SNAPSHOT_FILENAME-D2xc36Bb.mjs} +2 -2
- package/dist/packem_shared/{buildOpenApiDocument-Bj_gSM-g.mjs → buildOpenApiDocument-Ck7uULMF.mjs} +1 -1
- package/dist/packem_shared/discoverSchema-ClYGs0dx.mjs +1 -0
- package/dist/packem_shared/{emit-CE9-QEca.mjs → emit-_LUzQG_K.mjs} +232 -210
- package/dist/packem_shared/{emitApp-bdvaYlkn.mjs → emitApp-CgW3zBjL.mjs} +1 -1
- package/package.json +6 -6
- package/dist/packem_shared/discoverSchema-B0GCa2PI.mjs +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{agentComponent as
|
|
1
|
+
import{agentComponent as mt}from"@lunora/agent/component";import{LunoraError as X}from"@lunora/errors";import{serializeSchemaSnapshot as Tn,hashSchemaSnapshot as Nn}from"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import{d as An}from"./declared-output-Iaar469J.mjs";import{isHyperdriveGlobalTable as On,isD1GlobalTable as In}from"./isD1GlobalTable-udvHAAzD.mjs";import{s as A}from"./paths-C-9fwEgQ.mjs";import{acceptsAbsentIr as Cn}from"./LUNORA_ERROR_CODES-C2s0xWQD.mjs";const gt=[{contextProperty:"access",key:"access",moduleSpecifier:"@lunora/cloudflare-access",requiredPackage:"@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",requiredPackage:"@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",requiredPackage:"@lunora/bindings",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:"Build the `ctx.browser` helper, e.g. `(env) => createBrowser({ binding: env.BROWSER, launch })`. REQUIRED: unlike the binding-backed capabilities, `ctx.browser` is not auto-constructed — without this thunk every method throws, because the generated worker deliberately stays free of the optional `@cloudflare/playwright` peer.",method:"browser"},contextProperty:"browser",key:"browser",moduleSpecifier:"@lunora/browser",requiredPackage:"@lunora/browser",serverCtxField:{field:`
|
|
4
4
|
/** Browser Rendering (screenshots/PDF/scrape). Non-deterministic — available only in actions. */
|
|
@@ -15,41 +15,41 @@ import{agentComponent as pt}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"}],
|
|
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"}],Dn=gt,Ln=new Map(Dn.flatMap(e=>e.serverCtxField?[[e.key,e.serverCtxField]]:[])),mo=gt.flatMap(e=>"appMethod"in e?[{appMethod:e.appMethod,key:e.key}]:[]),ft=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,En=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),bt=e=>e.column!==void 0,_n=(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
|
-
`,
|
|
25
|
-
`}},Ge=(e,t,n)=>{if(!
|
|
26
|
-
const ${
|
|
23
|
+
`}},Pn=(e,t)=>e.stringMaxLength===void 0?"":`if (${t}.length > ${String(e.stringMaxLength)}) return DEFER;
|
|
24
|
+
`,Mn=(e,t)=>{const n=e.literalValue?.trim();if(!(n===void 0||!ft.test(n)))return{out:t,pre:`if (${t} !== ${n}) return DEFER;
|
|
25
|
+
`}},Ge=(e,t,n)=>{if(!bt(e)&&!(e.unmodelledRefinement||e.sourceText!==void 0)){if(En.has(e.kind))return e.kind==="any"?{out:t,pre:""}:{out:t,pre:_n(e.kind,t)+Pn(e,t)};switch(e.kind){case"array":return Fn(e,t,n);case"literal":return Mn(e,t);case"object":return jn(e,t,n);default:return}}},Fn=(e,t,n)=>{const{inner:r}=e;if(!r)return;const o=n.next(),a=`__arr${String(o)}`,i=`__i${String(o)}`,s=`__e${String(o)}`,c=Ge(r,s,n);if(!c)return;const d=`if (!Array.isArray(${t})) return DEFER;
|
|
26
|
+
const ${a} = new Array(${t}.length);
|
|
27
27
|
for (let ${i} = 0; ${i} < ${t}.length; ${i}++) {
|
|
28
28
|
const ${s} = ${t}[${i}];
|
|
29
|
-
${c.pre}${
|
|
29
|
+
${c.pre}${a}[${i}] = ${c.out};
|
|
30
30
|
}
|
|
31
|
-
`;return{out:
|
|
31
|
+
`;return{out:a,pre:d}},Bn=(e,t,n,r)=>{const o=JSON.stringify(e);if(t.kind==="optional"){if(t.hasRefinement||t.sourceText!==void 0||bt(t))return;const{inner:i}=t;if(!i)return;const s=Ge(i,n,r);if(!s)return;const c=r.next(),d=`__has${String(c)}`,h=`__val${String(c)}`,g=`let ${d} = false;
|
|
32
32
|
let ${h};
|
|
33
33
|
if (${n} !== undefined) {
|
|
34
34
|
${s.pre}${h} = ${s.out};
|
|
35
35
|
${d} = true;
|
|
36
36
|
}
|
|
37
|
-
`;return{entry:`...(${d} ? { ${
|
|
38
|
-
`,c=h}const d=
|
|
39
|
-
`},
|
|
40
|
-
${
|
|
41
|
-
`;return{out:i,pre:s}},
|
|
37
|
+
`;return{entry:`...(${d} ? { ${o}: ${h} } : {})`,pre:g}}const a=Ge(t,n,r);if(a)return{entry:`${o}: ${a.out}`,pre:a.pre}},qn=new Set(Object.getOwnPropertyNames(Object.prototype)),yt=(e,t,n)=>{let r="";const o=[];for(const a of Object.keys(e)){const i=e[a];if(!i)return;const s=JSON.stringify(a);let c=`${t}[${s}]`;if(qn.has(a)){const h=`__f${String(n.next())}`;r+=`const ${h} = Object.hasOwn(${t}, ${s}) ? ${t}[${s}] : undefined;
|
|
38
|
+
`,c=h}const d=Bn(a,i,c,n);if(!d)return;r+=d.pre,o.push(d.entry)}return{entries:o.join(", "),pre:r}},wt=e=>{const t=`Object.getPrototypeOf(${e})`;return`if (${t} !== Object.prototype && ${t} !== null) return DEFER;
|
|
39
|
+
`},jn=(e,t,n)=>{const r=e.shape??{},o=yt(r,t,n);if(!o)return;const a=n.next(),i=`__obj${String(a)}`,s=`if (typeof ${t} !== "object" || ${t} === null || Array.isArray(${t})) return DEFER;
|
|
40
|
+
${wt(t)}${o.pre}const ${i} = { ${o.entries} };
|
|
41
|
+
`;return{out:i,pre:s}},Wn=e=>{let t=0;const r=yt(e,"source",{next:()=>(t+=1,t)});if(r)return`(source) => {
|
|
42
42
|
if (typeof source !== "object" || source === null || Array.isArray(source)) return DEFER;
|
|
43
|
-
${
|
|
43
|
+
${wt("source")}${r.pre}return { ${r.entries} };
|
|
44
44
|
}`},S=`// GENERATED by @lunora/codegen — do not edit.
|
|
45
45
|
// Run \`lunora codegen\` to regenerate.
|
|
46
46
|
|
|
47
|
-
`,
|
|
47
|
+
`,ae=(e=!1)=>e?{client:"lunorash/client",do:"lunorash/do",flags:"lunorash/flags",server:"lunorash/server",serverDataModel:"lunorash/server/data-model",serverDrizzle:"lunorash/server/drizzle",serverTypes:"lunorash/server/types",values:"lunorash/values"}:{client:"@lunora/client",do:"@lunora/do",flags:"@lunora/flags",server:"@lunora/server",serverDataModel:"@lunora/server/data-model",serverDrizzle:"@lunora/server/drizzle",serverTypes:"@lunora/server/types",values:"@lunora/values"},kt=/^[A-Za-z_$][\w$]*$/u,Un=/^[\w./-]+$/u,f=(e,t)=>{if(!kt.test(e))throw new X("INTERNAL",`@lunora/codegen: ${t} is not a valid JS identifier: ${JSON.stringify(e)}`)},He=e=>e.charAt(0).toUpperCase()+e.slice(1),j=e=>kt.test(e)?e:JSON.stringify(e),Y=e=>e==="__proto__"?`[${JSON.stringify(e)}]`:j(e),Kn={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"},Qn=e=>{if(e===void 0)return"unknown";if(!ft.test(e))throw new X("INTERNAL",`@lunora/codegen: v.literal() argument is not a parseable string/number/boolean/null literal: ${JSON.stringify(e)}`);return e},N=e=>{const t=Kn[e.kind];if(t!==void 0)return t;switch(e.kind){case"array":return`Array<${e.inner?N(e.inner):"unknown"}>`;case"from":return e.tsType??"unknown";case"id":{const n=e.tableName??"_unknown_";return f(n,"v.id() table name"),`Id<"${n}">`}case"literal":return Qn(e.literalValue);case"object":return e.shape?`{ ${Object.entries(e.shape).map(([r,o])=>xt(r,o)).join("; ")} }`:"Record<string, unknown>";case"optional":return`${e.inner?N(e.inner):"unknown"} | undefined`;case"record":{const n=e.keyType?N(e.keyType):"string",r=e.valueType?N(e.valueType):"unknown";return`Record<${n}, ${r}>`}case"union":return e.members&&e.members.length>0?e.members.map(n=>N(n)).join(" | "):"never";default:return"unknown"}},xt=(e,t)=>{const n=j(e);if(t.kind==="optional"){const r=t.inner?N(t.inner):"unknown";return`${n}?: ${r}`}return Cn(t)?`${n}?: ${N(t)}`:`${n}: ${N(t)}`},xe=e=>{const t=Object.entries(e);return t.length===0?"{}":`{ ${t.map(([n,r])=>xt(n,r)).join("; ")} }`},vt=e=>e.kind==="optional"||!!e.column?.hasDefault,se=e=>e.kind==="optional"&&e.inner?e.inner:e,Vn=e=>{f(e.name,"table name");const t=Object.entries(e.shape).map(([r,o])=>{const a=se(o),i=N(a),s=j(r);return vt(o)?` ${s}?: ${i};`:` ${s}: ${i};`}).join(`
|
|
48
48
|
`),n=t?`
|
|
49
49
|
${t}
|
|
50
50
|
`:"";return`export interface Insert_${e.name} {
|
|
51
51
|
_id?: Id<"${e.name}">;
|
|
52
|
-
_creationTime?: number;${n}}`},Je="schema",
|
|
52
|
+
_creationTime?: number;${n}}`},Je="schema",go=e=>{for(const u of e.tables)f(u.name,"table name");const t=e.tables.map(u=>`"${u.name}"`).join(" | ")||"never",n=e.tables.filter(u=>u.extensionKey===void 0).map(u=>`"${u.name}"`).join(" | ")||"never",r=e.tables.map(u=>{const l=Object.entries(u.shape).map(([x,v])=>{const $=j(x);if(v.kind==="optional"){const T=v.inner?N(v.inner):"unknown";return` ${$}?: ${T};`}return` ${$}: ${N(v)};`}).join(`
|
|
53
53
|
`),b=l?`
|
|
54
54
|
${l}
|
|
55
55
|
`:"",R=u.commitOrdered===!0?`
|
|
@@ -57,15 +57,15 @@ ${l}
|
|
|
57
57
|
_id: Id<"${u.name}">;
|
|
58
58
|
_creationTime: number;${R}${b}}`}).join(`
|
|
59
59
|
|
|
60
|
-
`),
|
|
61
|
-
`),
|
|
60
|
+
`),o=e.tables.map(u=>` ${u.name}: Doc_${u.name};`).join(`
|
|
61
|
+
`),a=e.tables.map(u=>{const l=u.indexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
62
62
|
`),i=e.tables.map(u=>{const l=u.searchIndexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
63
63
|
`),s=e.tables.map(u=>{const l=u.rankIndexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
64
64
|
`),c=e.tables.map(u=>{const l=u.shardMode==="global"?"":(u.geoIndexes??[]).map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
65
|
-
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",h=e.tables.map(u=>
|
|
65
|
+
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",h=e.tables.map(u=>Vn(u)).join(`
|
|
66
66
|
|
|
67
67
|
`),g=e.tables.map(u=>` ${u.name}: Insert_${u.name};`).join(`
|
|
68
|
-
`),y=e.tables.map(u=>{const l=u.relations.map(b=>(f(b.table,"relation target table"),` ${
|
|
68
|
+
`),y=e.tables.map(u=>{const l=u.relations.map(b=>(f(b.table,"relation target table"),` ${j(b.name)}: ${b.kind==="one"?"OneRelation":"ManyRelation"}<"${b.table}">;`)).join(`
|
|
69
69
|
`);return l?` ${u.name}: {
|
|
70
70
|
${l}
|
|
71
71
|
};`:` ${u.name}: {};`}).join(`
|
|
@@ -93,7 +93,7 @@ export type Id<TName extends string> = string & { readonly __table: TName };
|
|
|
93
93
|
${r}
|
|
94
94
|
|
|
95
95
|
export interface DataModel {
|
|
96
|
-
${
|
|
96
|
+
${o}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
export type Doc<T extends keyof DataModel> = DataModel[T];
|
|
@@ -103,7 +103,7 @@ export type Doc<T extends keyof DataModel> = DataModel[T];
|
|
|
103
103
|
* Used by \`TableReader.withIndex()\` to constrain callers to declared names.
|
|
104
104
|
*/
|
|
105
105
|
export interface IndexNamesByTable {
|
|
106
|
-
${
|
|
106
|
+
${a}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
export type IndexName<T extends keyof DataModel> = IndexNamesByTable[T];
|
|
@@ -161,9 +161,9 @@ export interface Relations {
|
|
|
161
161
|
${y}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
`,Je)},Hn=/import\("(?<spec>(?:\.\.?\/)*_generated\/[^"]+)"\)/gu,
|
|
165
|
-
`);return` ${
|
|
166
|
-
${
|
|
164
|
+
`,Je)},Hn=/import\("(?<spec>(?:\.\.?\/)*_generated\/[^"]+)"\)/gu,St=/^(?:\.\.?\/)*_generated\//u,Rt=/\.[A-Za-z]\w*$/u,Gn=e=>e.replaceAll(Hn,(t,n)=>{const r=n.replace(St,"./");return`import("${Rt.test(r)?r:`${r}.js`}")`}),Jn=/import\("(?<spec>[^"]+)"\)/gu,ut="node_modules/",zn=/^@types\//u,Yn=e=>e.replaceAll(Jn,(t,n)=>{const r=n.lastIndexOf(ut);if(r===-1||r>0&&n[r-1]!=="/")return t;const o=n.slice(r+ut.length);return o===""||zn.test(o)?t:`import("${o}")`}),Xn=/import\("(?<spec>\.\.?\/[^"]+)"\)/gu,Zn=/^(?:\.\.?\/)+/u,er=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("/")},tr=(e,t)=>e.replaceAll(Xn,(n,r)=>{if(St.test(r.replace(Zn,"")))return n;const o=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",i=`../${er(`${o}/${r}`)}`;return`import("${Rt.test(i)?i:`${i}.js`}")`}),L=(e,t)=>Gn(tr(Yn(e),t)),nr=["client","do","errors","flags","observability","platform","ratelimit","runtime","server","values"],rr=new RegExp(String.raw`import\("@lunora/(?<pkg>${nr.join("|")})(?<subpath>/[^"]*)?"\)`,"gu"),or={flags:new Set(["/web"]),platform:new Set},$t=(e,t)=>t?e.replaceAll(rr,(n,r,o)=>{const a=or[r];return o&&a&&!a.has(o)?n:`import("lunorash/${r}${o??""}")`}):e,ze=e=>["Doc","Id"].filter(t=>new RegExp(String.raw`(?<![.$\w])${t}<`,"u").test(e)),Tt=e=>An(e)?N(e.output):e.returnType,Ye=e=>{const t=new Map;for(const n of e){const r=t.get(n.filePath)??[];r.push(n),t.set(n.filePath,r)}return[...t.entries()].toSorted(([n],[r])=>n.localeCompare(r))},ht=e=>{const t=([n,r])=>{const o=r.toSorted((a,i)=>a.exportName.localeCompare(i.exportName)).map(a=>{const i=L(xe(a.args),a.filePath),s=L(Tt(a),a.filePath);return` ${a.exportName}: FunctionReference<"${a.kind}", ${i}, ${s}>;`}).join(`
|
|
165
|
+
`);return` ${j(A(n))}: {
|
|
166
|
+
${o}
|
|
167
167
|
};`};return Ye(e).map(n=>t(n)).join(`
|
|
168
168
|
`)},ar=(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+=`
|
|
169
169
|
/** A typed reference to a durable workflow, addressable for \`cronJobs()\` targets. Mirrors \`@lunora/scheduler\`'s \`WorkflowReference\` structurally. */
|
|
@@ -173,31 +173,31 @@ export interface WorkflowReference<Params = Record<string, unknown>> {
|
|
|
173
173
|
readonly binding: string;
|
|
174
174
|
readonly name: string;
|
|
175
175
|
}
|
|
176
|
-
`,e.length>0){const
|
|
177
|
-
`),i=
|
|
176
|
+
`,e.length>0){const o=[...e].toSorted((s,c)=>s.exportName.localeCompare(c.exportName)),a=o.map(s=>` ${s.exportName}: WorkflowReference<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${s.exportName}>>;`).join(`
|
|
177
|
+
`),i=o.map(s=>` ${Y(s.exportName)}: { isLunoraWorkflow: true, binding: ${JSON.stringify(s.bindingName)}, name: ${JSON.stringify(s.exportName)} },`).join(`
|
|
178
178
|
`);r+=`
|
|
179
179
|
/** This project's durable workflows, addressable as typed references (e.g. \`crons.daily("digest", …, workflows.digestPipeline, params)\`). */
|
|
180
180
|
export interface WorkflowsRef {
|
|
181
|
-
${
|
|
181
|
+
${a}
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
export const workflows: WorkflowsRef = {
|
|
185
185
|
${i}
|
|
186
186
|
};
|
|
187
187
|
`,n.push(`import type * as lunoraWorkflowDefinitions from "../workflows.js";
|
|
188
|
-
`)}if(t.length>0){const
|
|
189
|
-
`),i=
|
|
188
|
+
`)}if(t.length>0){const o=[...t].toSorted((s,c)=>s.exportName.localeCompare(c.exportName)),a=o.map(s=>` ${s.exportName}: WorkflowReference<AgentRunInput>;`).join(`
|
|
189
|
+
`),i=o.map(s=>` ${Y(s.exportName)}: { isLunoraWorkflow: true, binding: ${JSON.stringify(s.bindingName)}, name: ${JSON.stringify(s.name)} },`).join(`
|
|
190
190
|
`);r+=`
|
|
191
191
|
/** This project's durable agents, addressable as typed references for \`cronJobs()\` — each fire starts a fresh agent run (e.g. \`crons.daily("sweep", …, agents.support, { input, threadKey })\`). */
|
|
192
192
|
export interface AgentsRef {
|
|
193
|
-
${
|
|
193
|
+
${a}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
export const agents: AgentsRef = {
|
|
197
197
|
${i}
|
|
198
198
|
};
|
|
199
199
|
`,n.push(`import type { AgentRunInput } from "@lunora/agent";
|
|
200
|
-
`)}return{block:r,importLine:n.join("")}},
|
|
200
|
+
`)}return{block:r,importLine:n.join("")}},sr=()=>Object.keys(mt().functions).toSorted((e,t)=>e.localeCompare(t)),Nt=e=>new Set(e.filter(t=>A(t.filePath)==="agents").map(t=>t.exportName)),ir=()=>new Set(Object.entries(mt().functions).filter(([,e])=>e.visibility==="internal").map(([e])=>e)),lr=(e,t)=>{const n={importLine:"",lines:"",prelude:""};if(e.length===0)return n;const r=Nt(t),o=ir(),a=t.find(s=>A(s.filePath)==="agents"&&o.has(s.exportName));if(a)throw new X("INTERNAL",`@lunora/codegen: "agents:${a.exportName}" is reserved for the durable agent loop's internal dispatch — rename the "${a.exportName}" export in ${a.filePath}`);const i=sr().filter(s=>!r.has(s));return i.length===0?n:{importLine:`import { agentComponent } from "@lunora/agent/component";
|
|
201
201
|
`,lines:i.map(s=>` "agents:${s}": lunoraAgentRuntimeFunctions.${s} as unknown as RegisteredLunoraFunction,`).join(`
|
|
202
202
|
`),prelude:`
|
|
203
203
|
/**
|
|
@@ -206,12 +206,12 @@ ${i}
|
|
|
206
206
|
* subscribe to the public queries (\`agents:agentMessages\` is the live thread view).
|
|
207
207
|
*/
|
|
208
208
|
const lunoraAgentRuntimeFunctions = agentComponent().functions;
|
|
209
|
-
`}},
|
|
210
|
-
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},
|
|
211
|
-
`);return` ${
|
|
209
|
+
`}},cr=(e,t)=>{if(!e)return{importLine:"",lines:"",prelude:""};const n=t.find(r=>A(r.filePath)==="sandbox"&&r.exportName==="invoke");if(n)throw new X("INTERNAL",`@lunora/codegen: "sandbox:invoke" is reserved for the batteries-included sandbox tool dispatcher (browserTool/containerTool) — rename the "invoke" export in ${n.filePath}`);return{importLine:`import { sandboxComponent } from "@lunora/agent/component";
|
|
210
|
+
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},dr=(e,t)=>{if(e.length===0)return[];const n=Nt(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))},ur=(e,t)=>{if(e.length===0)return[];const n=new Set(t.filter(r=>A(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}))},hr=e=>{const t=e.filter(i=>i.stream);if(t.length===0)return{block:"",body:""};const n=Ye(t),r=n.map(([i,s])=>{const c=s.map(d=>{const h=L(d.chunkType??"unknown",d.filePath),g=L(xe(d.searchParams),d.filePath),y=L(xe(d.params),d.filePath);return` ${j(d.exportName)}: HttpStreamRef<${h}, ${g}, ${y}>;`}).join(`
|
|
211
|
+
`);return` ${j(A(i))}: {
|
|
212
212
|
${c}
|
|
213
213
|
};`}).join(`
|
|
214
|
-
`),
|
|
214
|
+
`),o=n.map(([i,s])=>{const c=s.map(d=>` ${Y(d.exportName)}: { method: ${JSON.stringify(d.method)}, path: ${JSON.stringify(d.path)} },`).join(`
|
|
215
215
|
`);return` ${Y(A(i))}: {
|
|
216
216
|
${c}
|
|
217
217
|
},`}).join(`
|
|
@@ -222,9 +222,9 @@ ${r}
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
export const httpStreams: HttpStreamsRef = {
|
|
225
|
-
${
|
|
225
|
+
${o}
|
|
226
226
|
};
|
|
227
|
-
`,body:r}},
|
|
227
|
+
`,body:r}},fo=e=>{const{agents:t=[],functions:n,httpRoutes:r=[],mutators:o=[],useUmbrella:a=!1,workflows:i=[]}=e,s=ae(a),c=[...n.filter(O=>O.visibility!=="internal"),...dr(t,n),...ur(o,n)],d=n.filter(O=>O.visibility==="internal"),h=ht(c),g=ht(d),y=hr(r),u=`${h}
|
|
228
228
|
${g}
|
|
229
229
|
${y.body}`,l=ze(u),b=l.length>0?`
|
|
230
230
|
import type { ${l.join(", ")} } from "./dataModel.js";
|
|
@@ -240,10 +240,10 @@ export const api = anyApi as unknown as ApiTypes;
|
|
|
240
240
|
export interface InternalApiTypes {${x}}
|
|
241
241
|
|
|
242
242
|
export const internal = anyApi as unknown as InternalApiTypes;
|
|
243
|
-
${v.block}${y.block}`,T=[...$.includes("FunctionReference<")?["FunctionReference"]:[],...y.block===""?[]:["HttpStreamRef"]],
|
|
244
|
-
`:"";return
|
|
245
|
-
${
|
|
246
|
-
${$}`,
|
|
243
|
+
${v.block}${y.block}`,T=[...$.includes("FunctionReference<")?["FunctionReference"]:[],...y.block===""?[]:["HttpStreamRef"]],V=T.length>0?`import type { ${T.join(", ")} } from "${s.client}";
|
|
244
|
+
`:"";return $t(`${S}import { anyApi } from "${s.client}";
|
|
245
|
+
${V}${v.importLine}${b}
|
|
246
|
+
${$}`,a)},bo=e=>e?`${S}import { createSeedClient as createSeedClientBase } from "@lunora/seed";
|
|
247
247
|
import type { SeedClient, SeedClientOptions } from "@lunora/seed";
|
|
248
248
|
|
|
249
249
|
import schema from "../schema.js";
|
|
@@ -260,8 +260,8 @@ import type { InsertModel } from "./dataModel.js";
|
|
|
260
260
|
* const { posts } = await seed.posts((x) => x([10, 20]));
|
|
261
261
|
*/
|
|
262
262
|
export const createSeedClient = (options?: SeedClientOptions): SeedClient<InsertModel> => createSeedClientBase<InsertModel>(schema, options);
|
|
263
|
-
`:"",
|
|
264
|
-
export interface ${
|
|
263
|
+
`:"",yo=(e,t,n=!1)=>{if(e.length===0||!t)return"";const r=ae(n),o=c=>c.table===void 0?"Row":`Doc<${JSON.stringify(c.table)}> & Row`,a=e.map(c=>{f(c.exportName,"shape export name");const d=o(c),h=L(xe(c.args),c.filePath),g=Object.keys(c.args).length>0,y=g?` args: ${h};`:` args?: ${h};`,u=g?`(args: ${h}) => void`:`(args?: ${h}) => void`,l=`${c.exportName}CollectionOptions`;return`/** Options for the \`${c.exportName}\` shape binding. */
|
|
264
|
+
export interface ${He(l)} {
|
|
265
265
|
${y}
|
|
266
266
|
/**
|
|
267
267
|
* Share the optimistic-overlay gate with other collections + mutators on this
|
|
@@ -286,7 +286,7 @@ ${y}
|
|
|
286
286
|
* \`createCollection\`, plus the \`checkpoints\` registry to hand \`bindMutators\` and
|
|
287
287
|
* \`scope\` to re-point the subscription.
|
|
288
288
|
*/
|
|
289
|
-
export const ${c.exportName}CollectionOptions = (options: ${
|
|
289
|
+
export const ${c.exportName}CollectionOptions = (options: ${He(l)}): LunoraCollectionOptions<${d}> =>
|
|
290
290
|
lunoraCollectionOptions<${d}>({
|
|
291
291
|
client: options.client,
|
|
292
292
|
...(options.checkpoints === undefined ? {} : { checkpoints: options.checkpoints }),
|
|
@@ -299,22 +299,22 @@ export const ${c.exportName}CollectionOptions = (options: ${Ve(l)}): LunoraColle
|
|
|
299
299
|
|
|
300
300
|
/** Live collection for the \`${c.exportName}\` shape, with its sync controls. */
|
|
301
301
|
export const ${c.exportName}Collection = (
|
|
302
|
-
options: ${
|
|
302
|
+
options: ${He(l)},
|
|
303
303
|
): { checkpoints: CheckpointRegistry; collection: Collection<${d}, string>; scope: ${u} } => {
|
|
304
304
|
const { checkpoints, config, scope } = ${c.exportName}CollectionOptions(options);
|
|
305
305
|
|
|
306
306
|
return { checkpoints, collection: createCollection(config), scope };
|
|
307
307
|
};`}).join(`
|
|
308
308
|
|
|
309
|
-
`),i=ze(
|
|
309
|
+
`),i=ze(a),s=i.length>0?`import type { ${i.join(", ")} } from "./dataModel.js";
|
|
310
310
|
`:"";return`${S}import type { LunoraClient, SubscriptionError } from "${r.client}";
|
|
311
311
|
import { lunoraCollectionOptions } from "@lunora/db/collections";
|
|
312
312
|
import type { CheckpointRegistry, LunoraCollectionOptions, Row } from "@lunora/db";
|
|
313
313
|
import type { Collection } from "@tanstack/db";
|
|
314
314
|
import { createCollection } from "@tanstack/db";
|
|
315
315
|
${s}
|
|
316
|
-
${
|
|
317
|
-
`},
|
|
316
|
+
${a}
|
|
317
|
+
`},pr=(e,t)=>`lunora_${A(e)}_${String(t)}`,mr=`const callRegistered = async <R>(context: CallerCtx, functionPath: string, args: Record<string, unknown> | undefined): Promise<R> => {
|
|
318
318
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
319
319
|
|
|
320
320
|
if (!registered) {
|
|
@@ -343,13 +343,13 @@ ${o}
|
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
return (await registered.handler(context, args ?? {})) as R;
|
|
346
|
-
};`,
|
|
347
|
-
`),s=e.map(l=>` "${A(l.filePath)}:${l.exportName}": ${
|
|
348
|
-
`),c=t.map(l=>` ${JSON.stringify(l.id)}: ${
|
|
349
|
-
`),d=n.map(l=>` "${A(l.filePath)}:${l.exportName}": ${
|
|
350
|
-
`),h=r.map(l=>` "${l.exportName}": ${
|
|
346
|
+
};`,gr=(e,t,n=[],r=[])=>{const o=new Map,a=l=>{o.has(l)||o.set(l,pr(l,o.size))};for(const l of e)a(l.filePath);for(const l of t)a(l.filePath);for(const l of n)a(l.filePath);for(const l of r)a(l.filePath);const i=[...o.entries()].map(([l,b])=>{if(!Un.test(l))throw new X("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(l)}`);return`import * as ${b} from "../${l}.js";`}).join(`
|
|
347
|
+
`),s=e.map(l=>` "${A(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
348
|
+
`),c=t.map(l=>` ${JSON.stringify(l.id)}: ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredDataMigration,`).join(`
|
|
349
|
+
`),d=n.map(l=>` "${A(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
350
|
+
`),h=r.map(l=>` "${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredShape,`).join(`
|
|
351
351
|
`),g=n.map(l=>`${A(l.filePath)}:${l.exportName}`),y=[s,d].filter(l=>l.length>0).join(`
|
|
352
|
-
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const b=
|
|
352
|
+
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const b=Wn(l.args);return b===void 0?void 0:`installCompiledValidatorMap(${o.get(l.filePath)??""}.${l.exportName}.args, ${b});`}).filter(l=>l!==void 0).join(`
|
|
353
353
|
`);return{dispatchBody:y.length>0?`
|
|
354
354
|
${y}
|
|
355
355
|
`:"",importBlock:i.length>0?`${i}
|
|
@@ -358,25 +358,25 @@ ${y}
|
|
|
358
358
|
${c}
|
|
359
359
|
`:"",mutatorPaths:g,shapeBody:h.length>0?`
|
|
360
360
|
${h}
|
|
361
|
-
`:""}},
|
|
362
|
-
`);return` ${
|
|
361
|
+
`:""}},fr=e=>{const t=Ye(e),n=t.map(([o,a])=>{const i=a.map(s=>{const c=L(xe(s.args),s.filePath),d=c==="{}"?"?":"",h=L(Tt(s),s.filePath);return s.kind==="stream"?` ${s.exportName}: (args${d}: ${c}) => Promise<AsyncIterable<${h}>>;`:` ${s.exportName}: (args${d}: ${c}) => Promise<${h}>;`}).join(`
|
|
362
|
+
`);return` ${j(A(o))}: {
|
|
363
363
|
${i}
|
|
364
364
|
};`}).join(`
|
|
365
|
-
`);return{implementation:t.map(([a
|
|
365
|
+
`);return{implementation:t.map(([o,a])=>{const i=A(o),s=a.map(c=>` ${Y(c.exportName)}: (args) => callRegistered(context, "${i}:${c.exportName}", args),`).join(`
|
|
366
366
|
`);return` ${Y(i)}: {
|
|
367
367
|
${s}
|
|
368
368
|
},`}).join(`
|
|
369
|
-
`),types:n}},
|
|
370
|
-
`:"",
|
|
369
|
+
`),types:n}},br=(e,t=[])=>{const n=new Set;for(const r of e.tables)for(const o of Object.values(r.shape)){const a=se(o);a.kind==="storage"&&typeof a.bucket=="string"&&a.bucket!==""&&n.add(a.bucket)}for(const r of t)r!==""&&r!=="default"&&n.add(r);return["default",...[...n].toSorted((r,o)=>r.localeCompare(o))]},wo=({agents:e=[],containers:t=[],env:n,hasAccessFacade:r=!1,hasAi:o=!1,hasAnalytics:a=!1,hasBrowser:i=!1,hasVectors:s=!0,hasFlags:c=!1,hasHyperdrive:d=!1,hasImages:h=!1,hasKv:g=!1,hasNotify:y=!1,hasPayments:u=!1,hasPipelines:l=!1,hasR2sql:b=!1,hasX402:R=!1,identity:x,queues:v=[],schema:$,storageRuleBuckets:T=[],useUmbrella:V=!1,workflows:O=[]}={})=>{const C=ae(V),k=br($??{tables:[]},T).map(p=>JSON.stringify(p)).join(" | "),M=o?`import type { LunoraAi } from "@lunora/ai";
|
|
370
|
+
`:"",F=o?`
|
|
371
371
|
readonly ai: LunoraAi;`:"",ie=u?`import type { LunoraPayment } from "@lunora/payment";
|
|
372
372
|
`:"",le=u?`
|
|
373
373
|
readonly payments: LunoraPayment;`:"",Z=R?`import type { X402Pay } from "@lunora/x402/pay";
|
|
374
|
-
`:"",
|
|
374
|
+
`:"",H=R?`
|
|
375
375
|
readonly x402: X402Pay;`:"",D=t.length>0?`import type { ContainerAccessor } from "@lunora/container";
|
|
376
376
|
`:"",ee=t.length>0?`
|
|
377
377
|
readonly containers: {${t.map(p=>`
|
|
378
378
|
readonly ${p.exportName}: ContainerAccessor;`).join("")}
|
|
379
|
-
};`:"",w=[...
|
|
379
|
+
};`:"",w=[...o?[" /** Workers AI binding (the conventional `env.AI`), narrowing `ctx.ai`. */\n readonly AI?: unknown;"]:[],...t.map(p=>(f(p.bindingName,`container binding "${p.bindingName}"`),` /** Durable Object namespace for the \`${p.exportName}\` container. */
|
|
380
380
|
readonly ${p.bindingName}?: unknown;`)),...O.map(p=>(f(p.bindingName,`workflow binding "${p.bindingName}"`),` /** Workflow binding for the \`${p.exportName}\` workflow. */
|
|
381
381
|
readonly ${p.bindingName}?: unknown;`)),...v.map(p=>(f(p.bindingName,`queue binding "${p.bindingName}"`),` /** Queue producer binding for the \`${p.exportName}\` queue. */
|
|
382
382
|
readonly ${p.bindingName}?: unknown;`)),...e.map(p=>(f(p.bindingName,`agent binding "${p.bindingName}"`),` /** Workflow binding for the \`${p.exportName}\` agent. */
|
|
@@ -399,21 +399,21 @@ ${w}`:""}
|
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
/** Alias for {@link CloudflareBindings} — the typed shape of \`env\`. */
|
|
402
|
-
export type Env = CloudflareBindings;`,
|
|
402
|
+
export type Env = CloudflareBindings;`,B=(p,We,Te)=>{const re=Ln.get(p);if(re!==void 0&&re.tier!==Te)throw new X("INTERNAL",`@lunora/codegen: capability "${p}" declares tier "${re.tier}" in SERVER_CTX_FIELDS but is emitted onto the "${Te}" context — update whichever is wrong.`);return We?re?.field??"":""},ce=B("kv",g,"every"),de=B("analytics",a,"every"),Oe=B("hyperdrive",d,"action"),Ie=B("browser",i,"action"),Ce=B("images",h,"action"),ue=B("pipelines",l,"action"),G=B("r2sql",b,"action"),_=s&&($?.vectorIndexes.length??0)>0,J=_?' | "vectors"':"",te=_?`
|
|
403
403
|
readonly vectors: VectorSearch<VectorIndexName>;`:"",he=_?`
|
|
404
404
|
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",z=_?`import type { VectorSearch, VectorSearchReader } from "${C.server}";
|
|
405
405
|
import type { VectorIndexName } from "./dataModel.js";
|
|
406
|
-
`:"",
|
|
406
|
+
`:"",W=r?`
|
|
407
407
|
/** Verified Cloudflare Access identity — a synchronous facade over the resolved claims (email / groups / hasGroup / claims). Anonymous when no Access token is present. */
|
|
408
|
-
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",
|
|
408
|
+
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",U=c?`
|
|
409
409
|
/** Feature-flag evaluation (OpenFeature). Reads are memoized per request; evaluations never throw — a provider error resolves to the supplied default. */
|
|
410
|
-
readonly flags: import("${C.flags}").LunoraFlags;`:"",
|
|
410
|
+
readonly flags: import("${C.flags}").LunoraFlags;`:"",K=y?`
|
|
411
411
|
/** 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. */
|
|
412
412
|
readonly notify: import("@lunora/notify").LunoraNotify;
|
|
413
413
|
/** Device push sub-facade — the same object as ctx.notify.push (register / send / broadcast). Sends belong in action handlers. */
|
|
414
|
-
readonly push: import("@lunora/notify").LunoraPush;`:"",
|
|
414
|
+
readonly push: import("@lunora/notify").LunoraPush;`:"",q=O.length>0,ne=q?`import type { WorkflowHandle } from "@lunora/workflow";
|
|
415
415
|
import type * as lunoraWorkflowDefinitions from "../workflows.js";
|
|
416
|
-
`:"",De=
|
|
416
|
+
`:"",De=q?`
|
|
417
417
|
|
|
418
418
|
/** Params type carried by a \`defineWorkflow\` definition (its phantom \`__params\`). */
|
|
419
419
|
type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params }
|
|
@@ -426,7 +426,7 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
426
426
|
export interface LunoraWorkflows {
|
|
427
427
|
${O.map(p=>` get(name: ${JSON.stringify(p.exportName)}): WorkflowHandle<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${p.exportName}>>;`).join(`
|
|
428
428
|
`)}
|
|
429
|
-
}`:"",ve=
|
|
429
|
+
}`:"",ve=q?' | "workflows"':"",Se=q?`
|
|
430
430
|
readonly workflows: LunoraWorkflows;`:"",pe=v.length>0,Le=pe?`import type { QueueProducer } from "@lunora/queue";
|
|
431
431
|
import type * as lunoraQueueDefinitions from "../queues.js";
|
|
432
432
|
`:"",Ee=pe?`
|
|
@@ -517,7 +517,7 @@ export type {
|
|
|
517
517
|
} from "${C.serverDataModel}";
|
|
518
518
|
|
|
519
519
|
import type { DataModel, Doc, GeoIndexNamesByTable, Id as IdOfTable, IndexNamesByTable, Insert, InsertModel, RankIndexNamesByTable, Relations, SearchIndexNamesByTable, TableName } from "./dataModel.js";
|
|
520
|
-
${z}${
|
|
520
|
+
${z}${M}${ie}${Z}${D}${ne}${Le}${_e}${Me}${qe}
|
|
521
521
|
export type { AppTableName, DataModel, Doc, Id, TableName } from "./dataModel.js";
|
|
522
522
|
|
|
523
523
|
/**
|
|
@@ -643,19 +643,19 @@ type TypedAsId = <T extends string>(tableName: AsIdTable<T>, id: string) => IdOf
|
|
|
643
643
|
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${J}${ge}${be}> {
|
|
644
644
|
readonly db: Omit<DatabaseReader, "asId" | "query" | "get"> & DatabaseReaderFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
645
645
|
readonly orm: OrmReader;
|
|
646
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${he}${
|
|
646
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${he}${W}${ce}${U}${K}${de}${ye}${fe}
|
|
647
647
|
}
|
|
648
648
|
|
|
649
649
|
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${J}${ve}${ge}${be}> {
|
|
650
650
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
651
651
|
readonly orm: OrmWriter;
|
|
652
|
-
readonly storage: MutationStorage<StorageBucketName>;${te}${
|
|
652
|
+
readonly storage: MutationStorage<StorageBucketName>;${te}${W}${ce}${U}${K}${de}${ye}${Se}${Re}${$e}${fe}
|
|
653
653
|
}
|
|
654
654
|
|
|
655
655
|
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${J}${ve}${ge}${be}> {
|
|
656
656
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
657
657
|
readonly orm: OrmWriter;
|
|
658
|
-
readonly storage: StorageBase<StorageBucketName>;${te}${
|
|
658
|
+
readonly storage: StorageBase<StorageBucketName>;${te}${W}${F}${le}${H}${ee}${ce}${U}${K}${Oe}${Ie}${Ce}${de}${ue}${G}${ye}${Se}${Re}${$e}${fe}
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
/**
|
|
@@ -730,13 +730,13 @@ export const definePolicy = createPolicyDsl<DataModel, Relations${Be}>();
|
|
|
730
730
|
export const v = vBase as unknown as Omit<typeof vBase, "id"> & {
|
|
731
731
|
id: <T extends TableName>(table: T) => ColumnValidator<IdOfTable<T>, IdOfTable<T>>;
|
|
732
732
|
};
|
|
733
|
-
`},
|
|
733
|
+
`},yr=e=>{const t={connect:[],disconnect:[],init:[],reactor:[],whisper:[]};for(const n of e)n.lifecycle&&t[n.lifecycle].push(`${A(n.filePath)}:${n.exportName}`);return t},ko=e=>{const{agents:t=[],functions:n,migrations:r=[],mutators:o=[],shapes:a=[],useUmbrella:i=!1,usesSandbox:s=!1}=e,c=n.length>0,d=ae(i),{dispatchBody:h,importBlock:g,installBlock:y,migrationBody:u,mutatorPaths:l,shapeBody:b}=gr(n,r,o,a),R=lr(t,n),x=cr(s,n),v=[R.lines,x.lines].filter(w=>w.length>0).join(`
|
|
734
734
|
`);let $=h;v.length>0&&($=h.length>0?`${h.trimEnd()}
|
|
735
735
|
${v}
|
|
736
736
|
`:`
|
|
737
737
|
${v}
|
|
738
|
-
`);const T=
|
|
739
|
-
`:"",O=
|
|
738
|
+
`);const T=yr(n),V=a.length>0?`import type { RegisteredShape } from "${d.server}";
|
|
739
|
+
`:"",O=a.length>0?`
|
|
740
740
|
/**
|
|
741
741
|
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
742
742
|
* The generated ShardDO's \`resolveShape\` override looks a shape up by name and
|
|
@@ -752,23 +752,23 @@ export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${b}};
|
|
|
752
752
|
*/
|
|
753
753
|
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${l.map(w=>JSON.stringify(w)).join(", ")}]);
|
|
754
754
|
`:"",k=y.length>0?`import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${d.values}";
|
|
755
|
-
`:"",
|
|
755
|
+
`:"",M=y.length>0?`
|
|
756
756
|
/**
|
|
757
757
|
* AOT-compiled argument validators (Worker-safe, no \`eval\`). Each is installed
|
|
758
758
|
* onto its function's live \`.args\` object and consulted by the interpreted
|
|
759
759
|
* parser as a zero-allocation fast path; anything it can't model is deferred.
|
|
760
760
|
*/
|
|
761
761
|
${y}
|
|
762
|
-
`:"",
|
|
763
|
-
${
|
|
764
|
-
`:"",le=
|
|
765
|
-
${
|
|
766
|
-
`:"",Z=ze(
|
|
767
|
-
`:"",D=c?"context":"_context",ee=c?`${
|
|
768
|
-
|
|
769
|
-
`:"";return
|
|
762
|
+
`:"",F=fr(n),ie=F.types?`
|
|
763
|
+
${F.types}
|
|
764
|
+
`:"",le=F.implementation?`
|
|
765
|
+
${F.implementation}
|
|
766
|
+
`:"",Z=ze(F.types),H=Z.length>0?`import type { ${Z.join(", ")} } from "./dataModel.js";
|
|
767
|
+
`:"",D=c?"context":"_context",ee=c?`${mr}
|
|
768
|
+
|
|
769
|
+
`:"";return $t(`${S}${g}${R.importLine}${x.importLine}${k}${V}import { LunoraError } from "${d.server}";
|
|
770
770
|
import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
771
|
-
${
|
|
771
|
+
${H}
|
|
772
772
|
/**
|
|
773
773
|
* Single registered function, narrowed to the shape \`handleRpc\` needs.
|
|
774
774
|
* The real argument validators / return types are checked elsewhere — at
|
|
@@ -820,7 +820,7 @@ ${R.prelude}${x.prelude}
|
|
|
820
820
|
* emits (\`api[namespace][fn].__lunoraRef === "namespace:fn"\`).
|
|
821
821
|
*/
|
|
822
822
|
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${$}};
|
|
823
|
-
${
|
|
823
|
+
${M}${O}${C}
|
|
824
824
|
/**
|
|
825
825
|
* Lifecycle manifest: the function paths the generated ShardDO dispatches when a
|
|
826
826
|
* client's WebSocket connects (\`connect\`) or disconnects (\`disconnect\`), once
|
|
@@ -896,7 +896,7 @@ export interface RegisteredDataMigration {
|
|
|
896
896
|
* shard DO's admin RPC and the CLI resolve migrations to run through this map.
|
|
897
897
|
*/
|
|
898
898
|
export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${u}};
|
|
899
|
-
`,i)},
|
|
899
|
+
`,i)},wr=e=>{const t={};for(const n of e.tables){const r={};for(const[o,a]of Object.entries(n.shape)){const i=se(a);i.kind==="id"&&i.tableName!==void 0&&(r[o]=i.tableName)}Object.keys(r).length>0&&(t[n.name]=r)}return t},kr=e=>{const t={};for(const n of e.tables){const r=[];for(const[o,a]of Object.entries(n.shape))se(a).kind==="storage"&&r.push(o);r.length>0&&(t[n.name]=r)}return t},xr=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(a=>a.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},vr=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},Sr=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},Rr=(e,t,n)=>{const r=se(t),o={name:e,optional:vt(t),type:r.kind};if(r.kind==="id"&&r.tableName!==void 0){o.ref=r.tableName;const i=n.get(e);i!==void 0&&(o.onDelete=i)}r.kind==="storage"&&(o.isStorage=!0,r.bucket!==void 0&&(o.bucket=r.bucket));const a=Sr(r);return a!==void 0&&(o.enumValues=a),r.column?.notNull===!1&&(o.nullable=!0),o},$r=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"}]:[]],o=new Map(n.relations.filter(a=>a.kind==="one").map(a=>[a.field,a.onDelete]));for(const[a,i]of Object.entries(n.shape))r.push(Rr(a,i,o));t[n.name]=r}return t},Tr=e=>e?{importFragment:"serveRelationFanout, ",override:`
|
|
900
900
|
protected override async runRelationFanoutRead(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
901
901
|
this.ensureMigrated();
|
|
902
902
|
|
|
@@ -904,7 +904,7 @@ export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${u}}
|
|
|
904
904
|
|
|
905
905
|
return serveRelationFanout(schema as unknown as SchemaLike, db, functionPath, args);
|
|
906
906
|
}
|
|
907
|
-
`}:{importFragment:"",override:""},
|
|
907
|
+
`}:{importFragment:"",override:""},Nr=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:`
|
|
908
908
|
const aiBinding = config.ai?.(env) ?? (env as Record<string, unknown>).AI;
|
|
909
909
|
// Correlate AI-Gateway-routed calls with the Lunora trace: thread the
|
|
910
910
|
// function path + trace id into createAi, which folds them into the
|
|
@@ -935,14 +935,14 @@ const aiStub: LunoraAi = {
|
|
|
935
935
|
${t}
|
|
936
936
|
}) as unknown as LunoraAi["workersai"],
|
|
937
937
|
};
|
|
938
|
-
`}},I=(e,t,n,{cast:r="",sync:
|
|
938
|
+
`}},I=(e,t,n,{cast:r="",sync:o=[]}={})=>{const a=n.map(i=>` ${i}: ${o.includes(i)?"":"async "}() => {
|
|
939
939
|
${t}
|
|
940
940
|
},`).join(`
|
|
941
941
|
`);return`
|
|
942
942
|
const ${e} = {
|
|
943
|
-
${
|
|
943
|
+
${a}
|
|
944
944
|
}${r};
|
|
945
|
-
`},E={build:"",configField:"",contextField:"",importLines:[],stub:""},
|
|
945
|
+
`},E={build:"",configField:"",contextField:"",importLines:[],stub:""},Ar=e=>e?{build:`
|
|
946
946
|
const kvBinding = config.kv?.(env) ?? (env as Record<string, unknown>).KV;
|
|
947
947
|
// KV is not this shard's SQLite, so nothing appends a \`__cdc_log\` entry
|
|
948
948
|
// when a value changes — a subscription that read one can never be proven
|
|
@@ -956,32 +956,32 @@ ${o}
|
|
|
956
956
|
]);
|
|
957
957
|
`,configField:`
|
|
958
958
|
kv?: (env: Record<string, unknown>) => KVNamespaceLike;`,contextField:`
|
|
959
|
-
kv,`,importLines:['import type { Kv, KVNamespaceLike } from "@lunora/bindings/kv";','import { createKv } from "@lunora/bindings/kv";'],stub:I("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"])}:E,
|
|
959
|
+
kv,`,importLines:['import type { Kv, KVNamespaceLike } from "@lunora/bindings/kv";','import { createKv } from "@lunora/bindings/kv";'],stub:I("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"])}:E,Or=(e,t)=>e?{build:`
|
|
960
960
|
const flags: import("${t}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
961
961
|
provider: () => config.flags?.(env),
|
|
962
962
|
targetingKey: () => flagsConfig.identify?.({ identity: identity ?? null, userId: userId ?? null }),
|
|
963
963
|
});
|
|
964
964
|
`,configField:`
|
|
965
965
|
flags?: (env: Record<string, unknown>) => import("${t}").Provider;`,contextField:`
|
|
966
|
-
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:E,
|
|
966
|
+
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:E,Ir=e=>e?{build:`
|
|
967
967
|
const { notify, push } = createNotify(notifyConfig, env, { log, metrics });
|
|
968
968
|
`,configField:"",contextField:`
|
|
969
969
|
notify,
|
|
970
|
-
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:E,
|
|
970
|
+
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:E,Cr=e=>e?{build:`
|
|
971
971
|
const envConfig = lunoraEnvContract.${e.exportName}(env);
|
|
972
972
|
`,configField:"",contextField:`
|
|
973
|
-
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:E,
|
|
973
|
+
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:E,Dr=e=>e?{build:`
|
|
974
974
|
const access = accessFacade(identity, userId);
|
|
975
975
|
`,configField:"",contextField:`
|
|
976
|
-
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:E,
|
|
976
|
+
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:E,Lr=(e,t,n)=>{if(!t)return{constant:"",evaluateOverride:"",subscriptionOverride:""};const r=s=>`
|
|
977
977
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
978
978
|
const flags: import("${n}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
979
979
|
provider: () => config.flags?.(env),
|
|
980
980
|
targetingKey: ${s},
|
|
981
|
-
});`,
|
|
981
|
+
});`,o=`
|
|
982
982
|
/** Statically-discovered feature flags (\`ctx.flags.<type>("key")\` reads) served via \`__lunora_admin__:listFlags\` + the reactive \`__lunora_flags__:\` channel. */
|
|
983
983
|
const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number" | "object" | "string" }> = ${JSON.stringify(e,void 0,4)};
|
|
984
|
-
`,
|
|
984
|
+
`,a=`
|
|
985
985
|
protected override async evaluateFlags(context?: Record<string, unknown>): Promise<FlagsResult> {${r("undefined")}
|
|
986
986
|
const evalContext = context as import("${n}").EvaluationContext | undefined;
|
|
987
987
|
const evaluations: FlagsResult["flags"] = [];
|
|
@@ -1035,25 +1035,25 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
1035
1035
|
|
|
1036
1036
|
return flags.boolean(key, typeof args.default === "boolean" ? args.default : false, context);
|
|
1037
1037
|
}
|
|
1038
|
-
`;return{constant:
|
|
1038
|
+
`;return{constant:o,evaluateOverride:a,subscriptionOverride:i}},Er=e=>e?{build:`
|
|
1039
1039
|
const analyticsBinding = config.analytics?.(env) ?? (env as Record<string, unknown>).ANALYTICS;
|
|
1040
1040
|
const analytics: AnalyticsClient = analyticsBinding ? createAnalytics(analyticsBinding as AnalyticsEngineDatasetLike) : analyticsStub;
|
|
1041
1041
|
`,configField:`
|
|
1042
1042
|
analytics?: (env: Record<string, unknown>) => AnalyticsEngineDatasetLike;`,contextField:`
|
|
1043
|
-
analytics,`,importLines:['import type { AnalyticsClient, AnalyticsEngineDatasetLike } from "@lunora/bindings/analytics";','import { createAnalytics } from "@lunora/bindings/analytics";'],stub:I("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"]})}:E,
|
|
1043
|
+
analytics,`,importLines:['import type { AnalyticsClient, AnalyticsEngineDatasetLike } from "@lunora/bindings/analytics";','import { createAnalytics } from "@lunora/bindings/analytics";'],stub:I("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"]})}:E,_r=e=>e?{build:`
|
|
1044
1044
|
const imagesBinding = config.images?.(env) ?? (env as Record<string, unknown>).IMAGES;
|
|
1045
1045
|
const images: Images = imagesBinding ? createImages({ binding: imagesBinding as ImagesBindingLike }) : imagesStub;
|
|
1046
1046
|
`,configField:`
|
|
1047
1047
|
images?: (env: Record<string, unknown>) => ImagesBindingLike;`,contextField:`
|
|
1048
|
-
images,`,importLines:['import type { Images, ImagesBindingLike } from "@lunora/bindings/images";','import { createImages } from "@lunora/bindings/images";'],stub:I("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"])}:E,
|
|
1048
|
+
images,`,importLines:['import type { Images, ImagesBindingLike } from "@lunora/bindings/images";','import { createImages } from "@lunora/bindings/images";'],stub:I("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"])}:E,Pr=e=>e?{build:`
|
|
1049
1049
|
const sql: SqlClient = config.sql ? config.sql(env) : sqlStub;
|
|
1050
1050
|
`,configField:`
|
|
1051
1051
|
sql?: (env: Record<string, unknown>) => SqlClient;`,contextField:`
|
|
1052
|
-
sql,`,importLines:['import type { SqlClient } from "@lunora/hyperdrive";'],stub:I("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"])}:E,
|
|
1052
|
+
sql,`,importLines:['import type { SqlClient } from "@lunora/hyperdrive";'],stub:I("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"])}:E,Mr=e=>e?{build:`
|
|
1053
1053
|
const browser: Browser = config.browser ? config.browser(env) : browserStub;
|
|
1054
1054
|
`,configField:`
|
|
1055
1055
|
browser?: (env: Record<string, unknown>) => Browser;`,contextField:`
|
|
1056
|
-
browser,`,importLines:['import type { Browser } from "@lunora/browser";'],stub:I("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"])}:E,
|
|
1056
|
+
browser,`,importLines:['import type { Browser } from "@lunora/browser";'],stub:I("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"])}:E,Fr=e=>e?{build:`
|
|
1057
1057
|
const r2sqlEnv = env as Record<string, unknown>;
|
|
1058
1058
|
const r2sqlAccountId = (r2sqlEnv.R2_SQL_ACCOUNT_ID ?? r2sqlEnv.CLOUDFLARE_ACCOUNT_ID) as string | undefined;
|
|
1059
1059
|
const r2sqlToken = r2sqlEnv.R2_SQL_TOKEN as string | undefined;
|
|
@@ -1064,18 +1064,18 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
1064
1064
|
? createR2Sql({ accountId: r2sqlAccountId, apiToken: r2sqlToken, bucket: r2sqlBucket })
|
|
1065
1065
|
: r2sqlStub;
|
|
1066
1066
|
`,configField:`
|
|
1067
|
-
r2sql?: (env: Record<string, unknown>) => R2SqlClient;`,contextField:"",importLines:['import type { R2SqlClient } from "@lunora/bindings/r2sql";','import { createR2Sql } from "@lunora/bindings/r2sql";'],stub:I("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"]})}:E,
|
|
1067
|
+
r2sql?: (env: Record<string, unknown>) => R2SqlClient;`,contextField:"",importLines:['import type { R2SqlClient } from "@lunora/bindings/r2sql";','import { createR2Sql } from "@lunora/bindings/r2sql";'],stub:I("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"]})}:E,Br=e=>e?{build:`
|
|
1068
1068
|
const pipelinesBinding = config.pipelines?.(env) ?? (env as Record<string, unknown>).PIPELINES;
|
|
1069
1069
|
const pipelines: PipelineClient = pipelinesBinding ? createPipelines({ binding: pipelinesBinding as PipelineBindingLike }) : pipelinesStub;
|
|
1070
1070
|
`,configField:`
|
|
1071
|
-
pipelines?: (env: Record<string, unknown>) => PipelineBindingLike;`,contextField:"",importLines:['import type { PipelineBindingLike, PipelineClient } from "@lunora/bindings/pipelines";','import { createPipelines } from "@lunora/bindings/pipelines";'],stub:I("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"])}:E,
|
|
1072
|
-
export class ${
|
|
1071
|
+
pipelines?: (env: Record<string, unknown>) => PipelineBindingLike;`,contextField:"",importLines:['import type { PipelineBindingLike, PipelineClient } from "@lunora/bindings/pipelines";','import { createPipelines } from "@lunora/bindings/pipelines";'],stub:I("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"])}:E,xo=(e,t)=>{if(e.length===0)return"";const n=t?`, ${JSON.stringify(t)}`:"",r=e.map(a=>(f(a.exportName,`container export "${a.exportName}"`),f(a.className,`container class "${a.className}"`),`/** Container DO for the \`${a.exportName}\` definition (binding \`${a.bindingName}\`). */
|
|
1072
|
+
export class ${a.className} extends LunoraContainer {
|
|
1073
1073
|
public constructor(ctx: ConstructorParameters<typeof LunoraContainer>[0], env: Record<string, unknown>) {
|
|
1074
|
-
super(ctx, env, ${
|
|
1074
|
+
super(ctx, env, ${a.exportName}, "${a.exportName}"${n});
|
|
1075
1075
|
}
|
|
1076
1076
|
}
|
|
1077
1077
|
`)).join(`
|
|
1078
|
-
`),
|
|
1078
|
+
`),o=e.map(a=>a.exportName).join(", ");return`${S}/**
|
|
1079
1079
|
* Container-enabled Durable Object classes for the containers declared in
|
|
1080
1080
|
* \`lunora/containers.ts\`. Re-export them from your worker entry — wrangler
|
|
1081
1081
|
* requires each \`containers[].class_name\` to be exported by the worker:
|
|
@@ -1089,11 +1089,11 @@ export class ${o.className} extends LunoraContainer {
|
|
|
1089
1089
|
*/
|
|
1090
1090
|
import { LunoraContainer } from "@lunora/container/do";
|
|
1091
1091
|
|
|
1092
|
-
import { ${
|
|
1092
|
+
import { ${o} } from "../containers.js";
|
|
1093
1093
|
|
|
1094
1094
|
export { ContainerProxy } from "@lunora/container/do";
|
|
1095
1095
|
|
|
1096
|
-
${r}`},
|
|
1096
|
+
${r}`},qr=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const r of e)f(r.exportName,`container export "${r.exportName}"`),f(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(`
|
|
1097
1097
|
`);return{build:`
|
|
1098
1098
|
const containers = createContainerContext(env, LUNORA_CONTAINERS, ${t?JSON.stringify(t):"undefined"}, this.getCurrentTraceparent(), this.getCurrentSampleErrors());
|
|
1099
1099
|
`,contextField:`
|
|
@@ -1102,7 +1102,7 @@ ${r}`},Br=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[]
|
|
|
1102
1102
|
const LUNORA_CONTAINERS: ReadonlyArray<ContainerBindingSpec> = [
|
|
1103
1103
|
${n}
|
|
1104
1104
|
];
|
|
1105
|
-
`}},
|
|
1105
|
+
`}},vo=e=>{if(e.length===0)return"";const t=e.map(r=>(f(r.exportName,`workflow export "${r.exportName}"`),f(r.className,`workflow class "${r.className}"`),`/** WorkflowEntrypoint for the \`${r.exportName}\` definition (binding \`${r.bindingName}\`). */
|
|
1106
1106
|
export class ${r.className} extends LunoraWorkflow<WorkflowParamsOf<typeof ${r.exportName}>, WorkflowOutputOf<typeof ${r.exportName}>> {
|
|
1107
1107
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1108
1108
|
super(ctx, env, ${r.exportName}, "${r.exportName}");
|
|
@@ -1130,7 +1130,7 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
1130
1130
|
/** Output type carried by a \`defineWorkflow\` definition (its phantom \`__output\`), so each entrypoint keeps the authored return type. */
|
|
1131
1131
|
type WorkflowOutputOf<Definition> = Definition extends { __output?: infer Output } ? Output : unknown;
|
|
1132
1132
|
|
|
1133
|
-
${t}`},
|
|
1133
|
+
${t}`},So=e=>{if(e.length===0)return"";const n=e.filter(s=>s.voice).length>0,r=e.map(s=>{f(s.exportName,`agent export "${s.exportName}"`),f(s.className,`agent class "${s.className}"`);const c=`/** WorkflowEntrypoint for the \`${s.exportName}\` agent (binding \`${s.bindingName}\`). */
|
|
1134
1134
|
export class ${s.className} extends LunoraWorkflow<AgentRunInput, AgentRunResult> {
|
|
1135
1135
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1136
1136
|
super(ctx, env, compileAgentWorkflow(${s.exportName}, "${s.exportName}"), "${s.exportName}");
|
|
@@ -1144,7 +1144,7 @@ export class ${d} extends VoiceSessionDO {
|
|
|
1144
1144
|
}
|
|
1145
1145
|
}
|
|
1146
1146
|
`;return`${c}${g}`}).join(`
|
|
1147
|
-
`),
|
|
1147
|
+
`),o=e.map(s=>s.exportName).join(", ");return`${S}/**
|
|
1148
1148
|
* WorkflowEntrypoint classes for the agents declared in \`lunora/agents.ts\`.
|
|
1149
1149
|
* Each \`defineAgent\` compiles a replay-safe tool-loop onto a Cloudflare
|
|
1150
1150
|
* Workflow. Re-export them from your worker entry — wrangler requires each
|
|
@@ -1156,9 +1156,9 @@ import LunoraWorkflow from "@lunora/workflow/do";
|
|
|
1156
1156
|
${n?'import { compileAgentWorkflow, VoiceSessionDO } from "@lunora/agent";':'import { compileAgentWorkflow } from "@lunora/agent";'}
|
|
1157
1157
|
import type { AgentRunInput, AgentRunResult } from "@lunora/agent";
|
|
1158
1158
|
|
|
1159
|
-
import { ${
|
|
1159
|
+
import { ${o} } from "../agents.js";
|
|
1160
1160
|
|
|
1161
|
-
${r}`},
|
|
1161
|
+
${r}`},Ro=e=>{const t=e.filter(o=>o.mode==="push");if(t.length===0)return"";for(const o of t)f(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(`
|
|
1162
1162
|
`);return`${S}/**
|
|
1163
1163
|
* Push-consumer registry for the queues declared in \`lunora/queues.ts\`. The
|
|
1164
1164
|
* composed worker's \`queue(batch, env, ctx)\` entry routes each delivered batch
|
|
@@ -1173,7 +1173,7 @@ import { ${n} } from "../queues.js";
|
|
|
1173
1173
|
export const LUNORA_QUEUE_REGISTRY: QueueRegistry = {
|
|
1174
1174
|
${r}
|
|
1175
1175
|
};
|
|
1176
|
-
`},
|
|
1176
|
+
`},jr=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)f(n.exportName,`workflow export "${n.exportName}"`),f(n.bindingName,`workflow binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}" },`).join(`
|
|
1177
1177
|
`);return{build:`
|
|
1178
1178
|
const workflows = createWorkflowContext(env, LUNORA_WORKFLOWS);
|
|
1179
1179
|
`,contextField:`
|
|
@@ -1182,7 +1182,7 @@ ${r}
|
|
|
1182
1182
|
const LUNORA_WORKFLOWS: ReadonlyArray<WorkflowBindingSpec> = [
|
|
1183
1183
|
${t}
|
|
1184
1184
|
];
|
|
1185
|
-
`}},
|
|
1185
|
+
`}},Wr=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)f(n.exportName,`queue export "${n.exportName}"`),f(n.bindingName,`queue binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}", name: ${JSON.stringify(n.name)} },`).join(`
|
|
1186
1186
|
`);return{build:`
|
|
1187
1187
|
const queues = createQueueContext(env, LUNORA_QUEUES);
|
|
1188
1188
|
`,contextField:`
|
|
@@ -1191,7 +1191,7 @@ ${t}
|
|
|
1191
1191
|
const LUNORA_QUEUES: ReadonlyArray<QueueBindingSpec> = [
|
|
1192
1192
|
${t}
|
|
1193
1193
|
];
|
|
1194
|
-
`}},
|
|
1194
|
+
`}},Ur=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)f(n.exportName,`agent export "${n.exportName}"`),f(n.bindingName,`agent binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}"${n.publicRun===!0?", publicRun: true":""} },`).join(`
|
|
1195
1195
|
`);return{build:`
|
|
1196
1196
|
const agents = createAgentContext(env, LUNORA_AGENTS);
|
|
1197
1197
|
`,contextField:`
|
|
@@ -1200,14 +1200,14 @@ ${t}
|
|
|
1200
1200
|
const LUNORA_AGENTS: ReadonlyArray<AgentBindingSpec> = [
|
|
1201
1201
|
${t}
|
|
1202
1202
|
];
|
|
1203
|
-
`}},
|
|
1204
|
-
${
|
|
1203
|
+
`}},At=(e,t,n,r,o)=>({constant:`
|
|
1204
|
+
${o}
|
|
1205
1205
|
const ${e}: ${t} = ${JSON.stringify(r,void 0,4)};
|
|
1206
1206
|
`,override:`
|
|
1207
1207
|
protected override ${n}(): ${t} {
|
|
1208
1208
|
return ${e};
|
|
1209
1209
|
}
|
|
1210
|
-
`}),
|
|
1210
|
+
`}),Kr=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 At("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. */")},Qr=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 At("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. */")},Vr=e=>e?{imports:['import type { LunoraDatabaseLike as LunoraPaymentDbLike, LunoraPayment, PaymentsFromContextOptions } from "@lunora/payment";','import { paymentsFromContext } from "@lunora/payment";'],build:`
|
|
1211
1211
|
const payments: LunoraPayment = config.payment
|
|
1212
1212
|
? paymentsFromContext({ auth: { userId: userId ?? null }, db: db as unknown as LunoraPaymentDbLike }, config.payment(env))
|
|
1213
1213
|
: paymentStub;
|
|
@@ -1218,10 +1218,10 @@ const ${e}: ${t} = ${JSON.stringify(r,void 0,4)};
|
|
|
1218
1218
|
? lazyX402Pay(config.x402(env), { getSecret: (name: string) => secrets.get(name) })
|
|
1219
1219
|
: x402Stub;
|
|
1220
1220
|
`,configField:`
|
|
1221
|
-
x402?: (env: Record<string, unknown>) => X402PayConfig;`,stub:I("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:""},
|
|
1221
|
+
x402?: (env: Record<string, unknown>) => X402PayConfig;`,stub:I("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:""},Gr=(e,t,n,r,o)=>["AdvisorProcedure","AdvisoryFinding","DatabaseWriterLike","DataMigrationLike","DispatchBookmark","ExportRow",...r?["FlagsResult"]:[],"ImportShardResult","KeyRange","MaskPoliciesResult","MigrationRunResult","QueryReadScope",...n?["QueuesResult"]:[],"RelatedPage","RunShardApplyCdcArgs","RunShardExportArgs","RunShardFindRelatedArgs","RunShardImportArgs","RunShardMigrationArgs","RlsPoliciesResult","RunShardRankBeforeArgs","RunShardRankPageArgs","RunShardWriteArgs","RunShardWriteResult","SchedulerLike",...o?["SearchBackfillProgress"]:[],"TransactionHeadroomTracker","SchemaLike","ShardDOState","ShardRankPageResult","SqlExec","StorageRulesResult","StudioFeaturesResult","SubscriptionIdentity","SystemReaderStorageLike","TelemetrySink",...e?["VectorBackfillProgress"]:[],...t?["WorkflowsResult"]:[],...e?["WriteHook"]:[]],$o=({advisories:e=[],advisorProcedures:t=[],agents:n=[],containers:r=[],env:o,flagKeys:a=[],hasAccessFacade:i=!1,hasAi:s=!1,hasAnalytics:c=!1,hasBrowser:d=!1,hasFlags:h=!1,hasHyperdrive:g=!1,hasImages:y=!1,hasKv:u=!1,hasNotify:l=!1,hasPayments:b=!1,hasPipelines:R=!1,hasR2sql:x=!1,hasVectors:v=!0,hasX402:$=!1,maskMetadata:T,mutators:V=[],queues:O=[],rlsMetadata:C,schema:k,schemaSnapshot:M,shapes:F=[],storageRules:ie,studioFeatures:le,useUmbrella:Z=!1,workflows:H=[]})=>{const D=ae(Z),ee=V.length>0,w=F.length>0,Ae=M===void 0?"":Tn(M),B=M===void 0?"":`
|
|
1222
1222
|
/** 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. */
|
|
1223
|
-
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(
|
|
1224
|
-
`,ce=
|
|
1223
|
+
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(Nn(M))}, json: ${JSON.stringify(Ae)} };
|
|
1224
|
+
`,ce=M===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:de,configField:Oe,contextField:Ie,stub:Ce}=Nr(s),ue=Dr(i),G=Ar(u),_=Or(h,D.flags),J=Lr(a,h,D.flags),te=Ir(l),he=Cr(o),z=Er(c),W=_r(y),U=Pr(g),K=Mr(d),q=Fr(x),ne=Br(R),{build:De,contextField:ve,importLines:Se,specs:pe}=Wr(O),{build:Le,contextField:Ee,importLines:Re,specs:me}=qr(r,k.jurisdiction),{build:_e,contextField:Pe,importLines:$e,specs:Me}=jr(H),{build:Fe,contextField:ge,importLines:fe,specs:Be}=Ur(n),{build:qe,configField:je,contextField:be,imports:ye,stub:Ze}=Vr(b),{build:p,configField:We,imports:Te,stub:re}=Hr($),It=e,Ct=t,et=C??{policies:[],roles:[]},Dt=T??{columns:[]},Lt=ie??{rules:[]},Et=le??{analytics:!1,auth:!1,containers:!1,flags:!1,kv:!1,mail:!1,notifications:!1,payments:!1,queues:!1,scheduler:!1,storage:!1,vectors:!1,workflows:!1},{constant:_t,override:Pt}=Kr(H),{constant:Mt,override:Ft}=Qr(O),P=v&&k.vectorIndexes.length>0,tt=new Set(k.tables.filter(m=>typeof m.shardMode=="object"&&m.shardMode.kind==="shardBy").map(m=>m.name)),Ne=P&&k.vectorIndexes.some(m=>tt.has(m.table)),we=k.tables.some(m=>m.shardMode==="global"),Ue=k.tables.some(m=>On(m)),nt=k.tables.some(m=>In(m)),oe=k.tables.some(m=>m.externalSource!==void 0),rt=k.tables.some(m=>m.memory===!0),Ke=k.tables.some(m=>m.shardMode!=="global"&&m.searchIndexes.length>0);if(nt&&Ue)throw new X("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=k.tables.length>0,Bt=wr(k),qt=xr(k),jt=$r(k),Wt=kr(k),ot=vr(k),at=Gr(P,H.length>0,O.length>0,h,Ke);w&&at.push("WhereInput");const st=Tr(we),Ut=w?`
|
|
1225
1225
|
protected override resolveShape(name: string, args: Record<string, unknown>, identity?: SubscriptionIdentity): { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string } | undefined {
|
|
1226
1226
|
const shape = LUNORA_SHAPES[name];
|
|
1227
1227
|
|
|
@@ -1285,40 +1285,62 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
|
|
|
1285
1285
|
|
|
1286
1286
|
return { columns: shape.columns, effectiveWhere, global: isGlobal, table: shape.table };
|
|
1287
1287
|
}
|
|
1288
|
-
`:"",it=w?[...new Set(et.policies.filter(m=>m.on==="read"&&m.table!=="").map(m=>m.table))].toSorted((m
|
|
1288
|
+
`:"",it=w?[...new Set(et.policies.filter(m=>m.on==="read"&&m.table!=="").map(m=>m.table))].toSorted((m,$n)=>m.localeCompare($n)):[],lt=it.length>0?`
|
|
1289
1289
|
/** Refuses to boot a shape that would replicate around the read policies its table is governed by (\`defineShape({ use })\` is how a shape opts in; \`use: []\` acknowledges an ungoverned one). */
|
|
1290
1290
|
assertShapesDeclareReadPolicies(LUNORA_SHAPES, ${JSON.stringify(it)}, (schema as unknown as { rlsMode?: string }).rlsMode === "required");
|
|
1291
|
-
`:"",
|
|
1291
|
+
`:"",Kt=ee?`
|
|
1292
1292
|
protected override isCustomMutator(functionPath: string): boolean {
|
|
1293
1293
|
return LUNORA_MUTATOR_PATHS.has(functionPath);
|
|
1294
1294
|
}
|
|
1295
|
-
`:"",
|
|
1296
|
-
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",
|
|
1297
|
-
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;`:"",
|
|
1298
|
-
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1299
|
-
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
let vectors: VectorSearchLike;
|
|
1303
|
-
let onWrite: WriteHook | undefined;
|
|
1304
|
-
|
|
1305
|
-
if (config.vectors) {
|
|
1306
|
-
const lunora = createVectors({ indexes: config.vectors(env) });
|
|
1307
|
-
${nn}
|
|
1308
|
-
vectors = createContextVectors(lunora${an});
|
|
1309
|
-
onWrite = createVectorSyncHook({ ${rn}schema: schema as unknown as VectorSchemaLike, vectors });
|
|
1310
|
-
} else {
|
|
1311
|
-
vectors = vectorsStub;
|
|
1312
|
-
onWrite = undefined;
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1295
|
+
`:"",Qt=w?"assertShapeShardable, ":"",Vt=lt===""?"":"assertShapesDeclareReadPolicies, ",ke=[`import type { ${at.join(", ")} } from "${D.do}";`,`import { applyCdcChanges, ${Ke?"backfillSearchIndexes, ":""}${P?"backfillVectorIndexes, ":""}buildReprojectionMigration, ${rt?"clearMemoryTables, ":""}${Qt}createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, ${oe?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}markUnvouchableReads, ${Ne?"ROOT_SHARD_NAME, ":""}runDataMigration, runShardMigrations, ${st.importFragment}ShardDO as ShardDOBase } from "${D.do}";`,...oe?[`import type { ExternalSourceLike, SourceClientLike, TraceRefLike } from "${D.do}";`]:[],w?`import { asBucketStorage, ${Vt}beginDeferredDeletes, beginDeferredSchedules, composeShapeReadWhere, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${D.server}";`:`import { asBucketStorage, beginDeferredDeletes, beginDeferredSchedules, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${D.server}";`];Qe&&ke.push(`import { bindOrm, bindTableFacade } from "${D.server}";`),P&&ke.push('import type { SchemaLike as VectorSchemaLike, VectorBackfillSync, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectorBackfillSync, createVectors, createVectorSyncHook, vectorBackfillTargets } from "@lunora/bindings/vectors";'),s&&ke.push('import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'),ke.push(...ue.importLines,...G.importLines,..._.importLines,...te.importLines,...he.importLines,...z.importLines,...W.importLines,...U.importLines,...K.importLines,...q.importLines,...ne.importLines,...Re,...$e,...Se,...fe,...ye,...Te,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...ee?["LUNORA_MUTATOR_PATHS"]:[],...w?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const Ht=P?`
|
|
1296
|
+
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",Gt=nt?`
|
|
1297
|
+
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;`:"",Jt=Ue?`
|
|
1298
|
+
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",zt=oe?`
|
|
1299
|
+
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",Yt='throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");',Xt='throw new Error("ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().");',Zt='throw new Error("ctx.scheduler: no scheduler configured. Pass `scheduler` to createShardDO().");',en='throw new Error("ctx.storage: no storage configured. Pass `storage` to createShardDO().");',tn=we?I("globalDbStub: DatabaseWriterLike",Yt,["aggregate","count","delete","findFirst","findFirstOrThrow","findMany","get","groupBy","insert","normalizeId","patch","query","rank","rankPage","replace"],{sync:["normalizeId","query"]}):"",nn=P?I("vectorsStub: VectorSearchLike",Xt,["deleteByIds","getByIds","query","upsert","upsertNow"]):"",rn=Ne?` const vectorShardKey = this.currentShardKey();
|
|
1300
|
+
`:"",ct=Ne?"namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, ":"",on=`, { ${["deferAfterCommit: (work) => this.deferAfterCommit(work)",...Ne?["namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey",`shardedIndexNames: [${k.vectorIndexes.filter(m=>tt.has(m.table)).map(m=>JSON.stringify(m.name)).join(", ")}]`]:[]].join(", ")} }`,an=P?`
|
|
1301
|
+
const vectorSync = this.vectorSync(env);
|
|
1315
1302
|
// Vectorize lives outside this shard's SQLite, so a query whose result
|
|
1316
1303
|
// depends on a similarity search cannot be proven current on reconnect —
|
|
1317
1304
|
// an unrelated upsert (or a re-index) moves the matches without touching
|
|
1318
|
-
// \`__cdc_log\`.
|
|
1305
|
+
// \`__cdc_log\`. Only \`ctx.vectors\` is wrapped: the write-through
|
|
1319
1306
|
// vector-sync hook keeps calling the bare facade.
|
|
1320
|
-
|
|
1321
|
-
|
|
1307
|
+
const bareVectors = vectorSync?.vectors ?? vectorsStub;
|
|
1308
|
+
const vectors = markUnvouchableReads(bareVectors, options.onRead, ["getByIds", "query"]);
|
|
1309
|
+
const onWrite = vectorSync?.onWrite;
|
|
1310
|
+
`:"",sn=P?`
|
|
1311
|
+
private vectorSync(env: Record<string, unknown>): { backfill: VectorBackfillSync; onWrite: WriteHook; vectors: VectorSearchLike } | undefined {
|
|
1312
|
+
if (!config.vectors) {
|
|
1313
|
+
return undefined;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
const lunora = createVectors({ indexes: config.vectors(env) });
|
|
1317
|
+
${rn} const vectors = createContextVectors(lunora${on});
|
|
1318
|
+
|
|
1319
|
+
return {
|
|
1320
|
+
backfill: createVectorBackfillSync({ ${ct}schema: schema as unknown as VectorSchemaLike, upsertMany: lunora.upsertMany, vectors }),
|
|
1321
|
+
onWrite: createVectorSyncHook({ ${ct}schema: schema as unknown as VectorSchemaLike, vectors }),
|
|
1322
|
+
vectors,
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// \`__lunora_admin__:backfillVectors\`: the rows that predate a vector index,
|
|
1327
|
+
// a page at a time, each page ordered on the after-commit chain so it
|
|
1328
|
+
// never lands over a newer write's vector.
|
|
1329
|
+
protected override async runShardVectorBackfill(options: { maxPages?: number; restart?: boolean }): Promise<VectorBackfillProgress> {
|
|
1330
|
+
this.ensureMigrated();
|
|
1331
|
+
|
|
1332
|
+
const vectorSync = this.vectorSync((this.env ?? {}) as Record<string, unknown>);
|
|
1333
|
+
|
|
1334
|
+
if (!vectorSync) {
|
|
1335
|
+
throw new LunoraError("NOT_IMPLEMENTED", "vector backfill is unavailable: no vectors configured. Pass \`vectors\` to createShardDO().");
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
return backfillVectorIndexes(this.sql as SqlExec, vectorBackfillTargets(schema as unknown as VectorSchemaLike), vectorSync.backfill, {
|
|
1339
|
+
...options,
|
|
1340
|
+
ordered: async (read, work) => this.runOrderedAfterWrites(read, work),
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
`:"",ln=`{
|
|
1322
1344
|
...this.ctxDbTuning(),
|
|
1323
1345
|
auth: { identity: identity ?? null, userId: userId ?? null },
|
|
1324
1346
|
broadcast: (delta) => {
|
|
@@ -1356,7 +1378,7 @@ ${nn}
|
|
|
1356
1378
|
// Left \`undefined\` when there is no scope so \`createShardCtxDb\`
|
|
1357
1379
|
// keeps its own "degrade a provable slice to a whole-table dep"
|
|
1358
1380
|
// fallback rather than reporting into a no-op.
|
|
1359
|
-
onReadRange: options.onReadRange ?? (options.scope === undefined ? undefined : this.getCtxDbReadRangeHook(options.scope)),${
|
|
1381
|
+
onReadRange: options.onReadRange ?? (options.scope === undefined ? undefined : this.getCtxDbReadRangeHook(options.scope)),${P?`
|
|
1360
1382
|
// Vectorize is outside this shard's SQLite and cannot roll back, so
|
|
1361
1383
|
// the sync is held until the mutation's transaction has COMMITTED
|
|
1362
1384
|
// (\`deferAfterCommit\`) instead of running inline. Inline, a write
|
|
@@ -1370,7 +1392,7 @@ ${nn}
|
|
|
1370
1392
|
sql: this.sql as SqlExec,
|
|
1371
1393
|
storage,${we?`
|
|
1372
1394
|
globalDb,`:""}
|
|
1373
|
-
}`,
|
|
1395
|
+
}`,cn=` /**
|
|
1374
1396
|
* The bare writer every admin/maintenance entry point writes through.
|
|
1375
1397
|
*
|
|
1376
1398
|
* Admin and maintenance writes go through the SAME reactive-cache hooks as a
|
|
@@ -1402,11 +1424,11 @@ ${nn}
|
|
|
1402
1424
|
schema: schema as unknown as SchemaLike,
|
|
1403
1425
|
sql: this.sql as SqlExec,
|
|
1404
1426
|
});
|
|
1405
|
-
}`,Q=(m="")=>` const writer = this.adminWriter(${m});`,
|
|
1406
|
-
vectors,`:"",
|
|
1407
|
-
orm: bindOrm(facade),`:"",
|
|
1408
|
-
const globalDb: DatabaseWriterLike = ${
|
|
1409
|
-
`:"",
|
|
1427
|
+
}`,Q=(m="")=>` const writer = this.adminWriter(${m});`,dn=P?`
|
|
1428
|
+
vectors,`:"",un=Qe?`
|
|
1429
|
+
orm: bindOrm(facade),`:"",Ve=Ue?"config.hyperdriveGlobal":"config.d1",hn=we?` const globalRequest = { ...this.globalCdcOptions(config.cdc ?? false), bookmark: this.getInboundBookmark(), identity, onBookmark: (bookmarkValue: string | undefined) => { if (options.bookmarks !== undefined) { options.bookmarks.value = bookmarkValue; } }, userId };
|
|
1430
|
+
const globalDb: DatabaseWriterLike = ${Ve}?.(env, globalRequest) ?? globalDbStub;
|
|
1431
|
+
`:"",pn=w&&we?`
|
|
1410
1432
|
protected override async readGlobalShapeRows(resolved: { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string }, identity?: SubscriptionIdentity): Promise<Array<{ doc: Record<string, unknown>; id: string }>> {
|
|
1411
1433
|
const env = this.env as Record<string, unknown>;
|
|
1412
1434
|
// A shape read performs no writes, so the widened request only needs
|
|
@@ -1420,7 +1442,7 @@ ${nn}
|
|
|
1420
1442
|
// keys must mean equal rows, so a field the writer can scope by has to
|
|
1421
1443
|
// be either in the key or out of the request; it is out.
|
|
1422
1444
|
const globalRequest = { ...this.globalCdcOptions(config.cdc ?? false), bookmark: this.getInboundBookmark(), identity: identity?.identity, userId: identity?.userId };
|
|
1423
|
-
const globalDb: DatabaseWriterLike = ${
|
|
1445
|
+
const globalDb: DatabaseWriterLike = ${Ve}?.(env, globalRequest) ?? globalDbStub;
|
|
1424
1446
|
const rows: Array<{ doc: Record<string, unknown>; id: string }> = [];
|
|
1425
1447
|
|
|
1426
1448
|
let cursor: null | string = null;
|
|
@@ -1461,21 +1483,21 @@ ${nn}
|
|
|
1461
1483
|
// emitted \`shard.ts\` uncompilable for every Hyperdrive-global app with
|
|
1462
1484
|
// a \`defineShape\`. The Hyperdrive factory simply never reads it.
|
|
1463
1485
|
const globalRequest = { ...this.globalCdcOptions(config.cdc ?? false), bookmark: this.getInboundBookmark() };
|
|
1464
|
-
const globalDb: DatabaseWriterLike = ${
|
|
1486
|
+
const globalDb: DatabaseWriterLike = ${Ve}?.(env, globalRequest) ?? globalDbStub;
|
|
1465
1487
|
|
|
1466
1488
|
return globalDb.cdcChangedTables?.(sinceSeq, { cursorOnly });
|
|
1467
1489
|
}
|
|
1468
|
-
`:"",
|
|
1490
|
+
`:"",mn=oe?`
|
|
1469
1491
|
const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
|
|
1470
1492
|
const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
1471
|
-
`:"",
|
|
1493
|
+
`:"",gn=`
|
|
1472
1494
|
protected override async runShardInit(): Promise<void> {
|
|
1473
1495
|
this.ensureMigrated();
|
|
1474
1496
|
${rt?` clearMemoryTables(this.sql as SqlExec, schema as unknown as SchemaLike);
|
|
1475
1497
|
`:""}
|
|
1476
1498
|
await this.dispatchShardInit();
|
|
1477
1499
|
}
|
|
1478
|
-
`,
|
|
1500
|
+
`,fn=oe?`
|
|
1479
1501
|
protected override async pollExternalSources(trace?: TraceRefLike): Promise<number | undefined> {
|
|
1480
1502
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1481
1503
|
const sourced = Object.entries((schema as unknown as SchemaLike).tables)
|
|
@@ -1615,7 +1637,7 @@ ${rt?` clearMemoryTables(this.sql as SqlExec, schema as unknown as Sc
|
|
|
1615
1637
|
|
|
1616
1638
|
return nextDueAt;
|
|
1617
1639
|
}
|
|
1618
|
-
`:"",
|
|
1640
|
+
`:"",bn=ot.length>0,yn=`
|
|
1619
1641
|
public constructor(state: ShardDOState, env: unknown) {
|
|
1620
1642
|
super(state, env, {
|
|
1621
1643
|
// Every writer this file builds spreads the ctxDbTuning() slice —
|
|
@@ -1628,7 +1650,7 @@ ${rt?` clearMemoryTables(this.sql as SqlExec, schema as unknown as Sc
|
|
|
1628
1650
|
...(config.reactiveCache ? { reactiveCache: config.reactiveCache === true ? {} : config.reactiveCache } : {}),
|
|
1629
1651
|
...(config.relationExistsPushDown === undefined ? {} : { relationExistsPushDown: config.relationExistsPushDown }),
|
|
1630
1652
|
});
|
|
1631
|
-
${
|
|
1653
|
+
${oe?`
|
|
1632
1654
|
const autoSourced = Object.values((schema as unknown as SchemaLike).tables).some((definition) => {
|
|
1633
1655
|
const source = (definition as { externalSource?: ExternalSourceLike }).externalSource;
|
|
1634
1656
|
|
|
@@ -1638,7 +1660,7 @@ ${ae?`
|
|
|
1638
1660
|
if (autoSourced) {
|
|
1639
1661
|
void this.scheduleSourcePoll();
|
|
1640
1662
|
}
|
|
1641
|
-
`:""}${
|
|
1663
|
+
`:""}${bn?`
|
|
1642
1664
|
if (LUNORA_TTL_SWEEPS.length > 0) {
|
|
1643
1665
|
void this.scheduleTtlSweep();
|
|
1644
1666
|
}
|
|
@@ -1666,21 +1688,21 @@ ${ae?`
|
|
|
1666
1688
|
protected override isPaidFunction(functionPath: string): boolean {
|
|
1667
1689
|
return LUNORA_FUNCTIONS[functionPath]?.x402 !== undefined;
|
|
1668
1690
|
}
|
|
1669
|
-
`,
|
|
1691
|
+
`,wn=Qe?`
|
|
1670
1692
|
const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
|
|
1671
1693
|
${k.tables.map(m=>` facade[${JSON.stringify(m.name)}] = bindTableFacade(db, ${JSON.stringify(m.name)});`).join(`
|
|
1672
1694
|
`)}
|
|
1673
|
-
`:"",
|
|
1695
|
+
`:"",kn=`${ue.build}${G.build}${_.build}${z.build}${he.build}
|
|
1674
1696
|
const secrets = createSecrets(env);
|
|
1675
|
-
`,
|
|
1676
|
-
secrets,`,
|
|
1697
|
+
`,xn=`${ue.contextField}${G.contextField}${_.contextField}${te.contextField}${z.contextField}${he.contextField}
|
|
1698
|
+
secrets,`,vn=te.build,dt=y||g||d||x||R||$,Sn=dt?`
|
|
1677
1699
|
// ActionCtx-only helpers (external, non-deterministic I/O): constructed
|
|
1678
1700
|
// and attached only for an \`action\` so query/mutation ctx never carry them.
|
|
1679
1701
|
if (isAction) {
|
|
1680
|
-
${
|
|
1702
|
+
${W.build}${U.build}${K.build}${q.build}${ne.build}${p}${[...y?[" ctx.images = images;"]:[],...g?[" ctx.sql = sql;"]:[],...d?[" ctx.browser = browser;"]:[],...x?[" ctx.r2sql = r2sql;"]:[],...R?[" ctx.pipelines = pipelines;"]:[],...$?[" ctx.x402 = x402;"]:[]].join(`
|
|
1681
1703
|
`)}
|
|
1682
1704
|
}
|
|
1683
|
-
`:"",
|
|
1705
|
+
`:"",Rn=dt?` const isAction = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind === "action";
|
|
1684
1706
|
`:"";return`${S}${ke.join(`
|
|
1685
1707
|
`)}
|
|
1686
1708
|
|
|
@@ -1691,10 +1713,10 @@ interface FunctionReference {
|
|
|
1691
1713
|
}
|
|
1692
1714
|
|
|
1693
1715
|
/** Foreign-key columns per table (\`v.id("target")\` fields) for the data browser. */
|
|
1694
|
-
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(
|
|
1716
|
+
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(Bt,void 0,4)};
|
|
1695
1717
|
|
|
1696
1718
|
/** Declared indexes per table (secondary, search, geo, rank, vector) for the schema viewer. */
|
|
1697
|
-
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(
|
|
1719
|
+
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(qt,void 0,4)};
|
|
1698
1720
|
|
|
1699
1721
|
/** Columns per table (typed, with PK/FK markers) for the studio's schema diagram, served via \`__lunora_admin__:describeTable\`. */
|
|
1700
1722
|
const LUNORA_TABLE_COLUMNS: Record<
|
|
@@ -1711,32 +1733,32 @@ const LUNORA_TABLE_COLUMNS: Record<
|
|
|
1711
1733
|
ref?: string;
|
|
1712
1734
|
type: string;
|
|
1713
1735
|
}>
|
|
1714
|
-
> = ${JSON.stringify(
|
|
1736
|
+
> = ${JSON.stringify(jt,void 0,4)};
|
|
1715
1737
|
|
|
1716
1738
|
/** Storage-key columns per table (\`v.storage(...)\` fields) for the file browser's records↔files join. */
|
|
1717
|
-
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(
|
|
1739
|
+
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(Wt,void 0,4)};
|
|
1718
1740
|
|
|
1719
1741
|
/** Declarative TTL policies (\`.ttl(field, { after? })\`) the DO alarm sweep auto-expires rows for. */
|
|
1720
|
-
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(
|
|
1742
|
+
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(ot,void 0,4)};
|
|
1721
1743
|
|
|
1722
1744
|
/** Static schema advisories (computed by @lunora/advisor at codegen time) served via \`__lunora_admin__:getAdvisories\`. */
|
|
1723
|
-
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(
|
|
1745
|
+
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(It,void 0,4)};
|
|
1724
1746
|
|
|
1725
1747
|
/** Every declared procedure (discovered by @lunora/codegen) served via \`__lunora_admin__:getAdvisorProcedures\` — the health map's denominator. */
|
|
1726
|
-
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(
|
|
1748
|
+
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(Ct,void 0,4)};
|
|
1727
1749
|
|
|
1728
1750
|
/** Read-only RLS metadata (policies + roles discovered from \`.use(rls(...))\` chains) served via \`__lunora_admin__:rlsPolicies\` for the studio's RLS inspector. */
|
|
1729
1751
|
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(et,void 0,4)};
|
|
1730
1752
|
${lt}
|
|
1731
1753
|
/** 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. */
|
|
1732
|
-
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(
|
|
1754
|
+
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(Dt,void 0,4)};
|
|
1733
1755
|
|
|
1734
1756
|
/** Read-only storage access-rule metadata (discovered from \`.use(storageRules(...))\` chains) served via \`__lunora_admin__:storageRules\` for the studio's access-rules view. */
|
|
1735
|
-
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(
|
|
1757
|
+
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(Lt,void 0,4)};
|
|
1736
1758
|
|
|
1737
1759
|
/** 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. */
|
|
1738
|
-
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(
|
|
1739
|
-
${
|
|
1760
|
+
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(Et,void 0,4)};
|
|
1761
|
+
${B}${J.constant}${_t}${Mt}${me}${Me}${pe}${Be}
|
|
1740
1762
|
export interface ShardDOConfig {
|
|
1741
1763
|
/** Opt into change-data-capture: records a post-image to \`__cdc_log\` on every write (backs streaming export + replay-PITR). */
|
|
1742
1764
|
cdc?: boolean;
|
|
@@ -1750,9 +1772,9 @@ export interface ShardDOConfig {
|
|
|
1750
1772
|
observability?: (env: Record<string, unknown>) => TelemetrySink | undefined;
|
|
1751
1773
|
/** \`unknown\` because \`@lunora/scheduler\`'s \`Scheduler\` is not assignable to \`SchedulerLike\`; the shard casts it. */
|
|
1752
1774
|
scheduler?: (env: Record<string, unknown>) => unknown;
|
|
1753
|
-
storage?: (env: Record<string, unknown>) => unknown;${Ht}${Oe}${G.configField}${_.configField}${z.configField}${
|
|
1775
|
+
storage?: (env: Record<string, unknown>) => unknown;${Ht}${Oe}${G.configField}${_.configField}${z.configField}${W.configField}${U.configField}${K.configField}${q.configField}${ne.configField}${je}${We}${Gt}${Jt}${zt}
|
|
1754
1776
|
}
|
|
1755
|
-
${I("schedulerStub",
|
|
1777
|
+
${I("schedulerStub",Zt,["cancel","runAfter","runAt"])}${I("storageStub",en,["delete","download","getMetadata","getSignedUrl","getUrl","head","list","upload"],{sync:["getUrl"]})}${tn}${mn}${nn}${Ce}${G.stub}${_.stub}${z.stub}${W.stub}${U.stub}${K.stub}${q.stub}${ne.stub}${Ze}${re}
|
|
1756
1778
|
// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
|
|
1757
1779
|
// referencing call fails loudly with a clear error instead of overflowing the
|
|
1758
1780
|
// stack. Tracked across the awaited handler chain (one DO invocation is
|
|
@@ -1826,7 +1848,7 @@ const dispatchRun = async (
|
|
|
1826
1848
|
* from the worker entry so wrangler binds it by name.
|
|
1827
1849
|
*/
|
|
1828
1850
|
export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOState, env: unknown) => ShardDOBase =>
|
|
1829
|
-
class extends ShardDOBase {${
|
|
1851
|
+
class extends ShardDOBase {${yn}
|
|
1830
1852
|
private migrated = false;
|
|
1831
1853
|
|
|
1832
1854
|
public override async handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker, scope?: QueryReadScope, bookmarks?: DispatchBookmark): Promise<unknown> {
|
|
@@ -2048,11 +2070,11 @@ ${st.override}
|
|
|
2048
2070
|
iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath, identity }), args, signal),
|
|
2049
2071
|
};
|
|
2050
2072
|
}
|
|
2051
|
-
${
|
|
2073
|
+
${Kt}${Ut}${pn}${fn}
|
|
2052
2074
|
protected override lifecycleHookPaths(event: "connect" | "disconnect" | "init" | "reactor" | "whisper"): readonly string[] {
|
|
2053
2075
|
return LUNORA_LIFECYCLE_HOOKS[event];
|
|
2054
2076
|
}
|
|
2055
|
-
${
|
|
2077
|
+
${gn}
|
|
2056
2078
|
// One \`onQueryChange\` dispatch. Mirrors \`executeSubscription\` — the
|
|
2057
2079
|
// socket-terminated half of the same reactivity — and differs only in who
|
|
2058
2080
|
// consumes the result: the base's \`dispatchReactors\` stores the digest as
|
|
@@ -2140,7 +2162,7 @@ ${mn}
|
|
|
2140
2162
|
protected override studioFeatures(): StudioFeaturesResult {
|
|
2141
2163
|
return LUNORA_STUDIO_FEATURES;
|
|
2142
2164
|
}
|
|
2143
|
-
${J.evaluateOverride}${J.subscriptionOverride}${
|
|
2165
|
+
${J.evaluateOverride}${J.subscriptionOverride}${Pt}${Ft}
|
|
2144
2166
|
protected override advisories(): AdvisoryFinding[] {
|
|
2145
2167
|
return LUNORA_ADVISORIES;
|
|
2146
2168
|
}
|
|
@@ -2149,7 +2171,7 @@ ${J.evaluateOverride}${J.subscriptionOverride}${_t}${Mt}
|
|
|
2149
2171
|
return LUNORA_ADVISOR_PROCEDURES;
|
|
2150
2172
|
}
|
|
2151
2173
|
|
|
2152
|
-
${
|
|
2174
|
+
${cn}
|
|
2153
2175
|
|
|
2154
2176
|
protected override async runShardDataMigration(args: RunShardMigrationArgs): Promise<MigrationRunResult> {
|
|
2155
2177
|
this.ensureMigrated();
|
|
@@ -2363,7 +2385,7 @@ ${Ke?`
|
|
|
2363
2385
|
|
|
2364
2386
|
return backfillSearchIndexes(this.sql as SqlExec, schema as unknown as SchemaLike, options);
|
|
2365
2387
|
}
|
|
2366
|
-
`:""}
|
|
2388
|
+
`:""}${sn}
|
|
2367
2389
|
private buildCtx(options: { bookmarks?: DispatchBookmark; functionPath?: string; headroom?: TransactionHeadroomTracker; identity?: SubscriptionIdentity; onRead?: (table: string, idOrScan?: string) => void; onReadRange?: (range: KeyRange) => void; scope?: QueryReadScope; trusted?: boolean } = {}): unknown {
|
|
2368
2390
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
2369
2391
|
// The caller context this ctx runs under, resolved ONCE on one
|
|
@@ -2385,7 +2407,7 @@ ${Ke?`
|
|
|
2385
2407
|
userId: this.getCurrentUserId(),
|
|
2386
2408
|
};
|
|
2387
2409
|
const { identity, ip, userId } = caller;
|
|
2388
|
-
${
|
|
2410
|
+
${an}${de}${kn}${Le}${_e}${De}${Fe}
|
|
2389
2411
|
// Which dispatch this ctx belongs to. Drives the two deferral facades
|
|
2390
2412
|
// below and the \`ctx.run*\` caller guard; a ctx built for an
|
|
2391
2413
|
// admin/lifecycle path has no registered function, and so no kind.
|
|
@@ -2481,13 +2503,13 @@ ${on}${de}${wn}${Le}${_e}${De}${Fe}
|
|
|
2481
2503
|
// so both write to the same trace.
|
|
2482
2504
|
const span = this.makeDispatchSpan(traceAnchor, observability);
|
|
2483
2505
|
|
|
2484
|
-
${
|
|
2506
|
+
${hn} // \`ctx.db\`, wrapped in automatic instrumentation: by default this
|
|
2485
2507
|
// adds aggregate counters (call count, total time, per-operation
|
|
2486
2508
|
// breakdown) to the wide event rather than a span per call, so a
|
|
2487
2509
|
// handler making hundreds of queries stays readable. See
|
|
2488
2510
|
// \`instrumentDatabase\` for the \`"spans"\` / \`"off"\` levels.
|
|
2489
|
-
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${
|
|
2490
|
-
${
|
|
2511
|
+
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${ln}), logFunctionPath, traceAnchor, observability);
|
|
2512
|
+
${wn}${qe}
|
|
2491
2513
|
|
|
2492
2514
|
// \`ctx.trace\` / \`ctx.metrics\`: spans and measurements to the same sink.
|
|
2493
2515
|
// The trace anchor is threaded explicitly for the same reason \`identity\`
|
|
@@ -2495,7 +2517,7 @@ ${yn}${qe}
|
|
|
2495
2517
|
// writing mutation's trace from the shared per-request field.
|
|
2496
2518
|
const trace = this.makeTracer(logFunctionPath, observability, traceAnchor);
|
|
2497
2519
|
const metrics = this.makeMetrics(logFunctionPath, observability);
|
|
2498
|
-
${
|
|
2520
|
+
${vn}
|
|
2499
2521
|
// \`ctx.now\`: the wall-clock instant (epoch ms) this function began,
|
|
2500
2522
|
// captured ONCE so the whole handler body sees a single stable value.
|
|
2501
2523
|
// A \`query\` handler is re-run by every live subscription that reads it,
|
|
@@ -2533,13 +2555,13 @@ ${xn}
|
|
|
2533
2555
|
},
|
|
2534
2556
|
log,
|
|
2535
2557
|
metrics,
|
|
2536
|
-
now,${
|
|
2558
|
+
now,${un}
|
|
2537
2559
|
scheduler,
|
|
2538
2560
|
span,
|
|
2539
2561
|
storage: contextStorage,
|
|
2540
|
-
trace,${
|
|
2562
|
+
trace,${dn}${Ie}${xn}${be}${Ee}${Pe}${ve}${ge}
|
|
2541
2563
|
};
|
|
2542
|
-
${
|
|
2564
|
+
${Rn}${Sn}
|
|
2543
2565
|
ctx.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, ctx, contextKind);
|
|
2544
2566
|
// The composed mutation runs under the SAME wrapper the top-level RPC
|
|
2545
2567
|
// uses, so "do the transactional work in a mutation and call it from the
|
|
@@ -2574,21 +2596,21 @@ ${Sn}${vn}
|
|
|
2574
2596
|
return ctx;
|
|
2575
2597
|
}
|
|
2576
2598
|
};
|
|
2577
|
-
`},Xe=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:N(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:N(e)};case"id":return{builder:"text",notNull:!0};case"literal":{const t=e.literalValue??"";return t.startsWith('"')||t.startsWith("'")?{builder:"text",notNull:!0}:t==="true"||t==="false"?{builder:"integer",mode:"boolean",notNull:!0}:t==="null"?{builder:"text",notNull:!0}:{builder:"real",notNull:!0}}case"null":return{builder:"text",notNull:!0};case"number":return{builder:"real",notNull:!0};case"optional":return{...e.inner?Xe(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},
|
|
2599
|
+
`},Xe=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:N(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:N(e)};case"id":return{builder:"text",notNull:!0};case"literal":{const t=e.literalValue??"";return t.startsWith('"')||t.startsWith("'")?{builder:"text",notNull:!0}:t==="true"||t==="false"?{builder:"integer",mode:"boolean",notNull:!0}:t==="null"?{builder:"text",notNull:!0}:{builder:"real",notNull:!0}}case"null":return{builder:"text",notNull:!0};case"number":return{builder:"real",notNull:!0};case"optional":return{...e.inner?Xe(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},Ot=(e,t)=>{const n=se(e);return n.kind==="id"&&n.tableName!==void 0&&t.has(n.tableName)?n.tableName:void 0},Jr=(e,t,n)=>{f(e,"drizzle column name");const r=Xe(t),o=r.mode?`, { mode: "${r.mode}" }`:"";let a=`${r.builder}("${e}"${o})`;r.typeAnnotation&&(a+=`.$type<${r.typeAnnotation}>()`);const i=Ot(t,n);return i!==void 0&&(a+=`.references((): AnySQLiteColumn => ${i}._id)`),r.notNull&&(a+=".notNull()"),a},zr=e=>{const t=e.unique?"uniqueIndex":"index",n=e.fields.map(r=>(f(r,"drizzle index field"),`t.${r}`)).join(", ");return` ${Y(e.name)}: ${t}(${JSON.stringify(e.name)}).on(${n}),`},Yr=(e,t)=>{f(e.name,"table name");const n=[' _id: text("_id").primaryKey(),',' _creationTime: integer("_creationTime").notNull(),',...Object.entries(e.shape).map(([o,a])=>` ${o}: ${Jr(o,a,t)},`)].join(`
|
|
2578
2600
|
`),r=e.indexes.length>0?`, (t) => ({
|
|
2579
|
-
${e.indexes.map(
|
|
2601
|
+
${e.indexes.map(o=>zr(o)).join(`
|
|
2580
2602
|
`)}
|
|
2581
2603
|
})`:"";return`export const ${e.name} = sqliteTable("${e.name}", {
|
|
2582
2604
|
${n}
|
|
2583
|
-
}${r});`},
|
|
2584
|
-
`;const n=
|
|
2605
|
+
}${r});`},Xr=e=>e.typeAnnotation?.includes('Id<"')??!1,Zr=(e,t)=>{const n=new Set(["integer","sqliteTable","text"]),r=new Set;let o=!1,a=!1;for(const i of e){for(const s of Object.values(i.shape)){const c=Xe(s);n.add(c.builder),a=a||Xr(c),o=o||Ot(s,t)!==void 0}for(const s of i.indexes)r.add(s.unique?"uniqueIndex":"index")}return{columns:[...n].toSorted((i,s)=>i.localeCompare(s)),indexes:[...r].toSorted((i,s)=>i.localeCompare(s)),needsAnyColumn:o,needsId:a}},pt=(e,t=!1)=>{if(e.length===0)return`${S}export {};
|
|
2606
|
+
`;const n=ae(t),r=new Set(e.map(g=>g.name)),{columns:o,indexes:a,needsAnyColumn:i,needsId:s}=Zr(e,r),c=[...a,...o].toSorted((g,y)=>g.localeCompare(y)),d=e.map(g=>Yr(g,r)).join(`
|
|
2585
2607
|
|
|
2586
2608
|
`),h=[i?`import type { AnySQLiteColumn } from "${n.serverDrizzle}";
|
|
2587
2609
|
`:"",s?`import type { Id } from "./dataModel.js";
|
|
2588
2610
|
`:""].join("");return`${S}import { ${c.join(", ")} } from "${n.serverDrizzle}";
|
|
2589
2611
|
${h}
|
|
2590
2612
|
${d}
|
|
2591
|
-
`},
|
|
2613
|
+
`},To=(e,t=!1)=>{const n=e.tables.filter(o=>o.shardMode==="global"),r=e.tables.filter(o=>o.shardMode!=="global");return{global:L(pt(n,t),Je),shard:L(pt(r,t),Je)}},No=e=>e?`${S}/**
|
|
2592
2614
|
* The \`SchedulerDO\` Durable Object class, re-exported so a worker entry can
|
|
2593
2615
|
* forward it — wrangler binds only what the entry exports:
|
|
2594
2616
|
*
|
|
@@ -2598,15 +2620,15 @@ ${d}
|
|
|
2598
2620
|
* forwards this module for you whenever it exists.
|
|
2599
2621
|
*/
|
|
2600
2622
|
export { SchedulerDO } from "@lunora/scheduler";
|
|
2601
|
-
`:"",
|
|
2623
|
+
`:"",Ao=e=>{const t=new Map;for(const i of e){const s=t.get(i.cron);s?s.push(i):t.set(i.cron,[i])}const n=[...t.keys()].map(i=>` ${JSON.stringify(i)},`).join(`
|
|
2602
2624
|
`),r=n.length>0?`
|
|
2603
2625
|
${n}
|
|
2604
|
-
`:"",
|
|
2626
|
+
`:"",o=[...t.entries()].map(([i,s])=>{const c=s.map(d=>{const h=d.workflow?`workflow: ${JSON.stringify(d.workflow.binding)}`:`functionPath: ${JSON.stringify(d.functionPath)}`;return` { name: ${JSON.stringify(d.name)}, ${h}, args: ${JSON.stringify(d.args)} },`}).join(`
|
|
2605
2627
|
`);return` ${JSON.stringify(i)}: [
|
|
2606
2628
|
${c}
|
|
2607
2629
|
],`}).join(`
|
|
2608
|
-
`),o
|
|
2609
|
-
${
|
|
2630
|
+
`),a=o.length>0?`
|
|
2631
|
+
${o}
|
|
2610
2632
|
`:"";return`${S}/**
|
|
2611
2633
|
* One scheduled cron invocation. Exactly one target is set: \`functionPath\` is
|
|
2612
2634
|
* the \`namespace:fn\` dispatch ref (matches \`__lunoraRef\`), invoked on the
|
|
@@ -2631,8 +2653,8 @@ export const LUNORA_CRON_TRIGGERS: ReadonlyArray<string> = [${r}];
|
|
|
2631
2653
|
* Dispatcher map keyed by cron expression. The Worker's \`scheduled()\` handler
|
|
2632
2654
|
* looks up \`event.cron\` here and dispatches every job in the list.
|
|
2633
2655
|
*/
|
|
2634
|
-
export const LUNORA_CRONS: Record<string, ReadonlyArray<LunoraCronJob>> = {${
|
|
2635
|
-
`},
|
|
2656
|
+
export const LUNORA_CRONS: Record<string, ReadonlyArray<LunoraCronJob>> = {${a}};
|
|
2657
|
+
`},Oo=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(`
|
|
2636
2658
|
`),n=t.length>0?`
|
|
2637
2659
|
${t}
|
|
2638
2660
|
`:"";return`${S}/**
|
|
@@ -2656,4 +2678,4 @@ export interface LunoraVectorIndex {
|
|
|
2656
2678
|
* \`createWorker({ vectorIntrospector })\` to back the studio's vector browser.
|
|
2657
2679
|
*/
|
|
2658
2680
|
export const LUNORA_VECTOR_INDEXES: ReadonlyArray<LunoraVectorIndex> = [${n}];
|
|
2659
|
-
`},
|
|
2681
|
+
`},Io=e=>[...new Set(e.map(t=>t.cron))];export{mo as A,Dn as C,S as G,nr as U,fo as a,yo as b,xo as c,Ao as d,So as e,go as f,To as g,ko as h,No as i,wo as j,$o as k,Oo as l,vo as m,Io as n,kr as o,Ro as p,bo as q};
|