@lunora/codegen 1.0.0-alpha.81 → 1.0.0-alpha.82
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 +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/GENERATED_HEADER-Cphn03Kf.mjs +1 -0
- package/dist/packem_shared/{OPENRPC_VERSION-DfKtsdPS.mjs → OPENRPC_VERSION-IKkrtXye.mjs} +1 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-DBD0oti8.mjs +12 -0
- package/dist/packem_shared/SchemaSnapshotParseError-BJkhTEpi.mjs +16 -0
- package/dist/packem_shared/{buildOpenApiDocument-D46nZ7D_.mjs → buildOpenApiDocument-XeZ1ycwi.mjs} +1 -1
- package/dist/packem_shared/discoverSchema-CaTD2Sdx.mjs +1 -0
- package/dist/packem_shared/{emit-CCw5fiXq.mjs → emit-05q6XTbd.mjs} +258 -185
- package/dist/packem_shared/{emitApp-DEHN578T.mjs → emitApp-C2DhPKWE.mjs} +7 -6
- package/dist/packem_shared/readPackageDependencies-CogJX1Ia.mjs +1 -0
- package/package.json +3 -3
- package/dist/packem_shared/GENERATED_HEADER-CR3xA8yO.mjs +0 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-DjpfF4p7.mjs +0 -12
- package/dist/packem_shared/SchemaSnapshotParseError-0KRzSjo4.mjs +0 -14
- package/dist/packem_shared/discoverSchema-DUl8rbP3.mjs +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{agentComponent as
|
|
1
|
+
import{agentComponent as Ze}from"@lunora/agent/component";import{LunoraError as Z}from"@lunora/errors";import{serializeSchemaSnapshot as en,hashSchemaSnapshot as tn}from"./SCHEMA_SNAPSHOT_VERSION-CFhF_hmg.mjs";import{n as S}from"./paths-BmX5O1sG.mjs";const et=[{contextProperty:"access",key:"access",moduleSpecifier:"@lunora/cloudflare-access"},{appMethod:{configKey:"ai",doc:"Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`).",method:"ai"},contextProperty:"ai",key:"ai",moduleSpecifier:"@lunora/ai"},{appMethod:{configKey:"analytics",doc:"Override the Analytics Engine dataset backing `ctx.analytics` (defaults to `env.ANALYTICS`).",method:"analytics"},contextProperty:"analytics",key:"analytics",moduleSpecifier:"@lunora/bindings/analytics",serverCtxField:{field:`
|
|
2
2
|
/** Analytics Engine telemetry sink. Fire-and-forget and sampled; do not read it back in-handler. */
|
|
3
3
|
readonly analytics: import("@lunora/bindings/analytics").AnalyticsClient;`,tier:"every"}},{appMethod:{configKey:"browser",doc:"Override the Browser Rendering binding backing `ctx.browser` (defaults to `env.BROWSER`).",method:"browser"},contextProperty:"browser",key:"browser",moduleSpecifier:"@lunora/browser",serverCtxField:{field:`
|
|
4
4
|
/** Browser Rendering (screenshots/PDF/scrape). Non-deterministic — available only in actions. */
|
|
@@ -15,50 +15,50 @@ import{agentComponent as Ye}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"}],nn=et,rn=new Map(nn.flatMap(e=>e.serverCtxField?[[e.key,e.serverCtxField]]:[])),xr=et.flatMap(e=>"appMethod"in e?[{appMethod:e.appMethod,key:e.key}]:[]),tt=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,an=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),nt=e=>e.column!==void 0,on=(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
|
-
`}},Fe=(e,t,n)=>{if(!
|
|
23
|
+
`}},sn=(e,t)=>{const n=e.literalValue?.trim();if(!(n===void 0||!tt.test(n)))return{out:t,pre:`if (${t} !== ${n}) return DEFER;
|
|
24
|
+
`}},Fe=(e,t,n)=>{if(!nt(e)&&!(e.hasRefinement||e.sourceText!==void 0)){if(an.has(e.kind))return e.kind==="any"?{out:t,pre:""}:{out:t,pre:on(e.kind,t)};switch(e.kind){case"array":return ln(e,t,n);case"literal":return sn(e,t);case"object":return cn(e,t,n);default:return}}},ln=(e,t,n)=>{const{inner:r}=e;if(!r)return;const a=n.next(),o=`__arr${String(a)}`,i=`__i${String(a)}`,s=`__e${String(a)}`,l=Fe(r,s,n);if(!l)return;const u=`if (!Array.isArray(${t})) return DEFER;
|
|
25
25
|
const ${o} = new Array(${t}.length);
|
|
26
|
-
for (let ${
|
|
27
|
-
const ${
|
|
28
|
-
${l.pre}${o}[${
|
|
26
|
+
for (let ${i} = 0; ${i} < ${t}.length; ${i}++) {
|
|
27
|
+
const ${s} = ${t}[${i}];
|
|
28
|
+
${l.pre}${o}[${i}] = ${l.out};
|
|
29
29
|
}
|
|
30
|
-
`;return{out:o,pre:u}},
|
|
30
|
+
`;return{out:o,pre:u}},dn=(e,t,n,r)=>{const a=JSON.stringify(e);if(t.kind==="optional"){if(t.hasRefinement||t.sourceText!==void 0||nt(t))return;const{inner:i}=t;if(!i)return;const s=Fe(i,n,r);if(!s)return;const l=r.next(),u=`__has${String(l)}`,p=`__val${String(l)}`,f=`let ${u} = false;
|
|
31
31
|
let ${p};
|
|
32
32
|
if (${n} !== undefined) {
|
|
33
|
-
${
|
|
33
|
+
${s.pre}${p} = ${s.out};
|
|
34
34
|
${u} = true;
|
|
35
35
|
}
|
|
36
|
-
`;return{entry:`...(${u} ? { ${a}: ${p} } : {})`,pre:f}}const o=Fe(t,n,r);if(o)return{entry:`${a}: ${o.out}`,pre:o.pre}},
|
|
37
|
-
${a.pre}const ${
|
|
38
|
-
`;return{out:
|
|
36
|
+
`;return{entry:`...(${u} ? { ${a}: ${p} } : {})`,pre:f}}const o=Fe(t,n,r);if(o)return{entry:`${a}: ${o.out}`,pre:o.pre}},rt=(e,t,n)=>{let r="";const a=[];for(const o of Object.keys(e)){const i=e[o];if(!i)return;const s=dn(o,i,t(o),n);if(!s)return;r+=s.pre,a.push(s.entry)}return{entries:a.join(", "),pre:r}},cn=(e,t,n)=>{const r=e.shape??{},a=rt(r,l=>`${t}[${JSON.stringify(l)}]`,n);if(!a)return;const o=n.next(),i=`__obj${String(o)}`,s=`if (typeof ${t} !== "object" || ${t} === null || Array.isArray(${t})) return DEFER;
|
|
37
|
+
${a.pre}const ${i} = { ${a.entries} };
|
|
38
|
+
`;return{out:i,pre:s}},un=e=>{let t=0;const n=rt(e,r=>`source[${JSON.stringify(r)}]`,{next:()=>(t+=1,t)});if(n)return`(source) => {
|
|
39
39
|
if (typeof source !== "object" || source === null || Array.isArray(source)) return DEFER;
|
|
40
40
|
${n.pre}return { ${n.entries} };
|
|
41
41
|
}`},k=`// GENERATED by @lunora/codegen — do not edit.
|
|
42
42
|
// Run \`lunora codegen\` to regenerate.
|
|
43
43
|
|
|
44
|
-
`,H=(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"},
|
|
44
|
+
`,H=(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"},at=/^[A-Za-z_$][\w$]*$/u,pn=/^[\w./-]+$/u,m=(e,t)=>{if(!at.test(e))throw new Z("INTERNAL",`@lunora/codegen: ${t} is not a valid JS identifier: ${JSON.stringify(e)}`)},Ee=e=>e.charAt(0).toUpperCase()+e.slice(1),D=e=>at.test(e)?e:JSON.stringify(e),hn={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"},gn=e=>{if(e===void 0)return"unknown";if(!tt.test(e))throw new Z("INTERNAL",`@lunora/codegen: v.literal() argument is not a parseable string/number/boolean/null literal: ${JSON.stringify(e)}`);return e},C=e=>{const t=hn[e.kind];if(t!==void 0)return t;switch(e.kind){case"array":return`Array<${e.inner?C(e.inner):"unknown"}>`;case"from":return e.tsType??"unknown";case"id":{const n=e.tableName??"_unknown_";return m(n,"v.id() table name"),`Id<"${n}">`}case"literal":return gn(e.literalValue);case"object":return e.shape?`{ ${Object.entries(e.shape).map(([n,r])=>ot(n,r)).join("; ")} }`:"Record<string, unknown>";case"optional":return`${e.inner?C(e.inner):"unknown"} | undefined`;case"record":{const n=e.keyType?C(e.keyType):"string",r=e.valueType?C(e.valueType):"unknown";return`Record<${n}, ${r}>`}case"union":return e.members&&e.members.length>0?e.members.map(n=>C(n)).join(" | "):"never";default:return"unknown"}},ot=(e,t)=>{const n=D(e);if(t.kind==="optional"){const r=t.inner?C(t.inner):"unknown";return`${n}?: ${r}`}return`${n}: ${C(t)}`},me=e=>{const t=Object.entries(e);return t.length===0?"{}":`{ ${t.map(([n,r])=>ot(n,r)).join("; ")} }`},mn=e=>e.kind==="optional"||!!e.column?.hasDefault,fn=e=>{m(e.name,"table name");const t=Object.entries(e.shape).map(([r,a])=>{const o=a.kind==="optional"&&a.inner?a.inner:a,i=C(o),s=D(r);return mn(a)?` ${s}?: ${i};`:` ${s}: ${i};`}).join(`
|
|
45
45
|
`),n=t?`
|
|
46
46
|
${t}
|
|
47
47
|
`:"";return`export interface Insert_${e.name} {
|
|
48
48
|
_id?: Id<"${e.name}">;
|
|
49
|
-
_creationTime?: number;${n}}`},
|
|
49
|
+
_creationTime?: number;${n}}`},kr=(e,t=!1)=>{const n=H(t);for(const c of e.tables)m(c.name,"table name");const r=e.tables.map(c=>`"${c.name}"`).join(" | ")||"never",a=e.tables.filter(c=>c.extensionKey===void 0).map(c=>`"${c.name}"`).join(" | ")||"never",o=e.tables.map(c=>{const g=Object.entries(c.shape).map(([x,v])=>{const O=D(x);if(v.kind==="optional"){const N=v.inner?C(v.inner):"unknown";return` ${O}?: ${N};`}return` ${O}: ${C(v)};`}).join(`
|
|
50
50
|
`),b=g?`
|
|
51
51
|
${g}
|
|
52
52
|
`:"";return`export interface Doc_${c.name} {
|
|
53
53
|
_id: Id<"${c.name}">;
|
|
54
54
|
_creationTime: number;${b}}`}).join(`
|
|
55
55
|
|
|
56
|
-
`),
|
|
57
|
-
`),
|
|
56
|
+
`),i=e.tables.map(c=>` ${c.name}: Doc_${c.name};`).join(`
|
|
57
|
+
`),s=e.tables.map(c=>{const g=c.indexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${c.name}: ${g||"never"};`}).join(`
|
|
58
58
|
`),l=e.tables.map(c=>{const g=c.searchIndexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${c.name}: ${g||"never"};`}).join(`
|
|
59
59
|
`),u=e.tables.map(c=>{const g=c.rankIndexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${c.name}: ${g||"never"};`}).join(`
|
|
60
60
|
`),p=e.tables.map(c=>{const g=c.shardMode==="global"?"":(c.geoIndexes??[]).map(b=>JSON.stringify(b.name)).join(" | ");return` ${c.name}: ${g||"never"};`}).join(`
|
|
61
|
-
`),f=e.vectorIndexes.map(c=>JSON.stringify(c.name)).join(" | ")||"never",y=e.tables.map(c=>
|
|
61
|
+
`),f=e.vectorIndexes.map(c=>JSON.stringify(c.name)).join(" | ")||"never",y=e.tables.map(c=>fn(c)).join(`
|
|
62
62
|
|
|
63
63
|
`),R=e.tables.map(c=>` ${c.name}: Insert_${c.name};`).join(`
|
|
64
64
|
`),d=e.tables.map(c=>{const g=c.relations.map(b=>(m(b.table,"relation target table"),` ${D(b.name)}: ${b.kind==="one"?"OneRelation":"ManyRelation"}<"${b.table}">;`)).join(`
|
|
@@ -121,7 +121,7 @@ export type Id<TName extends string> = string & { readonly __table: TName };
|
|
|
121
121
|
${o}
|
|
122
122
|
|
|
123
123
|
export interface DataModel {
|
|
124
|
-
${
|
|
124
|
+
${i}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export type Doc<T extends keyof DataModel> = DataModel[T];
|
|
@@ -131,7 +131,7 @@ export type Doc<T extends keyof DataModel> = DataModel[T];
|
|
|
131
131
|
* Used by \`TableReader.withIndex()\` to constrain callers to declared names.
|
|
132
132
|
*/
|
|
133
133
|
export interface IndexNamesByTable {
|
|
134
|
-
${
|
|
134
|
+
${s}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
export type IndexName<T extends keyof DataModel> = IndexNamesByTable[T];
|
|
@@ -234,11 +234,11 @@ export interface OrmWriter extends OrmReader {
|
|
|
234
234
|
replace: <T extends keyof DataModel>(table: T, id: Id<T>) => OrmReplaceBuilder<T>;
|
|
235
235
|
update: <T extends keyof DataModel>(table: T, id: Id<T>) => OrmUpdateBuilder<T>;
|
|
236
236
|
}
|
|
237
|
-
`},
|
|
237
|
+
`},bn=/import\("(?<spec>(?:\.\.?\/)*_generated\/[^"]+)"\)/gu,st=/^(?:\.\.?\/)*_generated\//u,it=/\.[A-Za-z]\w*$/u,Me=e=>e.replaceAll(bn,(t,n)=>{const r=n.replace(st,"./");return`import("${it.test(r)?r:`${r}.js`}")`}),yn=/import\("(?<spec>\.\.?\/[^"]+)"\)/gu,wn=/^(?:\.\.?\/)+/u,xn=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("/")},qe=(e,t)=>e.replaceAll(yn,(n,r)=>{if(st.test(r.replace(wn,"")))return n;const a=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",o=`../${xn(`${a}/${r}`)}`;return`import("${it.test(o)?o:`${o}.js`}")`}),kn=/import\("@lunora\/(?<pkg>client|do|runtime|server|values)(?<subpath>\/[^"]*)?"\)/gu,lt=(e,t)=>t?e.replaceAll(kn,(n,r,a)=>`import("lunorash/${r}${a??""}")`):e,Be=e=>["Doc","Id"].filter(t=>new RegExp(String.raw`\b${t}<`,"u").test(e)),vn=e=>e.output===void 0||e.output.kind==="any"?e.returnType:C(e.output),Xe=e=>{const t=new Map;for(const r of e){const a=t.get(r.filePath)??[];a.push(r),t.set(r.filePath,a)}const n=([r,a])=>{const o=a.toSorted((i,s)=>i.exportName.localeCompare(s.exportName)).map(i=>{const s=me(i.args),l=Me(qe(vn(i),i.filePath));return` ${i.exportName}: FunctionReference<"${i.kind}", ${s}, ${l}>;`}).join(`
|
|
238
238
|
`);return` ${D(S(r))}: {
|
|
239
239
|
${o}
|
|
240
240
|
};`};return[...t.entries()].toSorted(([r],[a])=>r.localeCompare(a)).map(r=>n(r)).join(`
|
|
241
|
-
`)}
|
|
241
|
+
`)},$n=(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+=`
|
|
242
242
|
/** A typed reference to a durable workflow, addressable for \`cronJobs()\` targets. Mirrors \`@lunora/scheduler\`'s \`WorkflowReference\` structurally. */
|
|
243
243
|
export interface WorkflowReference<Params = Record<string, unknown>> {
|
|
244
244
|
readonly isLunoraWorkflow: true;
|
|
@@ -246,8 +246,8 @@ export interface WorkflowReference<Params = Record<string, unknown>> {
|
|
|
246
246
|
readonly binding: string;
|
|
247
247
|
readonly name: string;
|
|
248
248
|
}
|
|
249
|
-
`,e.length>0){const a=[...e].toSorted((
|
|
250
|
-
`),
|
|
249
|
+
`,e.length>0){const a=[...e].toSorted((s,l)=>s.exportName.localeCompare(l.exportName)),o=a.map(s=>` ${s.exportName}: WorkflowReference<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${s.exportName}>>;`).join(`
|
|
250
|
+
`),i=a.map(s=>` ${s.exportName}: { isLunoraWorkflow: true, binding: ${JSON.stringify(s.bindingName)}, name: ${JSON.stringify(s.exportName)} },`).join(`
|
|
251
251
|
`);r+=`
|
|
252
252
|
/** This project's durable workflows, addressable as typed references (e.g. \`crons.daily("digest", …, workflows.digestPipeline, params)\`). */
|
|
253
253
|
export interface WorkflowsRef {
|
|
@@ -255,11 +255,11 @@ ${o}
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
export const workflows: WorkflowsRef = {
|
|
258
|
-
${
|
|
258
|
+
${i}
|
|
259
259
|
};
|
|
260
260
|
`,n.push(`import type * as lunoraWorkflowDefinitions from "../workflows.js";
|
|
261
|
-
`)}if(t.length>0){const a=[...t].toSorted((
|
|
262
|
-
`),
|
|
261
|
+
`)}if(t.length>0){const a=[...t].toSorted((s,l)=>s.exportName.localeCompare(l.exportName)),o=a.map(s=>` ${s.exportName}: WorkflowReference<AgentRunInput>;`).join(`
|
|
262
|
+
`),i=a.map(s=>` ${s.exportName}: { isLunoraWorkflow: true, binding: ${JSON.stringify(s.bindingName)}, name: ${JSON.stringify(s.name)} },`).join(`
|
|
263
263
|
`);r+=`
|
|
264
264
|
/** 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 })\`). */
|
|
265
265
|
export interface AgentsRef {
|
|
@@ -267,11 +267,11 @@ ${o}
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
export const agents: AgentsRef = {
|
|
270
|
-
${
|
|
270
|
+
${i}
|
|
271
271
|
};
|
|
272
272
|
`,n.push(`import type { AgentRunInput } from "@lunora/agent";
|
|
273
|
-
`)}return{block:r,importLine:n.join("")}},
|
|
274
|
-
`,lines:
|
|
273
|
+
`)}return{block:r,importLine:n.join("")}},Sn=()=>Object.keys(Ze().functions).toSorted((e,t)=>e.localeCompare(t)),dt=e=>new Set(e.filter(t=>S(t.filePath)==="agents").map(t=>t.exportName)),Rn=()=>new Set(Object.entries(Ze().functions).filter(([,e])=>e.visibility==="internal").map(([e])=>e)),Nn=(e,t)=>{const n={importLine:"",lines:"",prelude:""};if(e.length===0)return n;const r=dt(t),a=Rn(),o=t.find(s=>S(s.filePath)==="agents"&&a.has(s.exportName));if(o)throw new Z("INTERNAL",`@lunora/codegen: "agents:${o.exportName}" is reserved for the durable agent loop's internal dispatch — rename the "${o.exportName}" export in ${o.filePath}`);const i=Sn().filter(s=>!r.has(s));return i.length===0?n:{importLine:`import { agentComponent } from "@lunora/agent/component";
|
|
274
|
+
`,lines:i.map(s=>` "agents:${s}": lunoraAgentRuntimeFunctions.${s} as unknown as RegisteredLunoraFunction,`).join(`
|
|
275
275
|
`),prelude:`
|
|
276
276
|
/**
|
|
277
277
|
* The \`@lunora/agent\` runtime component — auto-registered because \`lunora/agents.ts\`
|
|
@@ -279,13 +279,13 @@ ${s}
|
|
|
279
279
|
* subscribe to the public queries (\`agents:agentMessages\` is the live thread view).
|
|
280
280
|
*/
|
|
281
281
|
const lunoraAgentRuntimeFunctions = agentComponent().functions;
|
|
282
|
-
`}},
|
|
283
|
-
`,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"}}
|
|
284
|
-
`);return` ${D(S(
|
|
282
|
+
`}},On=(e,t)=>{if(!e)return{importLine:"",lines:"",prelude:""};const n=t.find(r=>S(r.filePath)==="sandbox"&&r.exportName==="invoke");if(n)throw new Z("INTERNAL",`@lunora/codegen: "sandbox:invoke" is reserved for the batteries-included sandbox tool dispatcher (browserTool/containerTool) — rename the "invoke" export in ${n.filePath}`);return{importLine:`import { sandboxComponent } from "@lunora/agent/component";
|
|
283
|
+
`,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"}},Tn=(e,t)=>{if(e.length===0)return[];const n=dt(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 a of e)a.voice&&r.push({args:{threadKey:{kind:"string"}},exportName:`${a.exportName}Voice`,filePath:"agents",kind:"stream",returnType:"Record<string, unknown>"});return r.filter(a=>!n.has(a.exportName))},An=(e,t)=>{if(e.length===0)return[];const n=new Set(t.filter(r=>S(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}))},Ln=e=>{const t=e.filter(i=>i.stream);if(t.length===0)return{block:"",body:""};const n=new Map;for(const i of t){const s=n.get(i.filePath)??[];s.push(i),n.set(i.filePath,s)}const r=[...n.entries()].toSorted(([i],[s])=>i.localeCompare(s)),a=r.map(([i,s])=>{const l=s.map(u=>{const p=Me(qe(u.chunkType??"unknown",u.filePath));return` ${D(u.exportName)}: HttpStreamRef<${p}, ${me(u.searchParams)}, ${me(u.params)}>;`}).join(`
|
|
284
|
+
`);return` ${D(S(i))}: {
|
|
285
285
|
${l}
|
|
286
286
|
};`}).join(`
|
|
287
|
-
`),o=r.map(([s
|
|
288
|
-
`);return` ${D(S(
|
|
287
|
+
`),o=r.map(([i,s])=>{const l=s.map(u=>` ${D(u.exportName)}: { method: ${JSON.stringify(u.method)}, path: ${JSON.stringify(u.path)} },`).join(`
|
|
288
|
+
`);return` ${D(S(i))}: {
|
|
289
289
|
${l}
|
|
290
290
|
},`}).join(`
|
|
291
291
|
`);return{block:`
|
|
@@ -297,15 +297,15 @@ ${a}
|
|
|
297
297
|
export const httpStreams: HttpStreamsRef = {
|
|
298
298
|
${o}
|
|
299
299
|
};
|
|
300
|
-
`,body:a}},
|
|
300
|
+
`,body:a}},vr=e=>{const{agents:t=[],functions:n,httpRoutes:r=[],mutators:a=[],useUmbrella:o=!1,workflows:i=[]}=e,s=H(o),l=[...n.filter($=>$.visibility!=="internal"),...Tn(t,n),...An(a,n)],u=n.filter($=>$.visibility==="internal"),p=Xe(l),f=Xe(u),y=Ln(r),R=`${p}
|
|
301
301
|
${f}
|
|
302
|
-
${y.body}`,d=
|
|
302
|
+
${y.body}`,d=Be(R),c=d.length>0?`
|
|
303
303
|
import type { ${d.join(", ")} } from "./dataModel.js";
|
|
304
304
|
`:"",g=p?`
|
|
305
305
|
${p}
|
|
306
306
|
`:"",b=f?`
|
|
307
307
|
${f}
|
|
308
|
-
`:"",x
|
|
308
|
+
`:"",x=$n(i,t),v=`export interface ApiTypes {${g}}
|
|
309
309
|
|
|
310
310
|
export const api = anyApi as unknown as ApiTypes;
|
|
311
311
|
|
|
@@ -313,10 +313,10 @@ export const api = anyApi as unknown as ApiTypes;
|
|
|
313
313
|
export interface InternalApiTypes {${b}}
|
|
314
314
|
|
|
315
315
|
export const internal = anyApi as unknown as InternalApiTypes;
|
|
316
|
-
${x.block}${y.block}`,
|
|
317
|
-
`:"";return
|
|
316
|
+
${x.block}${y.block}`,O=[...v.includes("FunctionReference<")?["FunctionReference"]:[],...y.block===""?[]:["HttpStreamRef"]],N=O.length>0?`import type { ${O.join(", ")} } from "${s.client}";
|
|
317
|
+
`:"";return lt(`${k}import { anyApi } from "${s.client}";
|
|
318
318
|
${N}${x.importLine}${c}
|
|
319
|
-
${v}`,o)}
|
|
319
|
+
${v}`,o)},$r=e=>e?`${k}import { createSeedClient as createSeedClientBase } from "@lunora/seed";
|
|
320
320
|
import type { SeedClient, SeedClientOptions } from "@lunora/seed";
|
|
321
321
|
|
|
322
322
|
import schema from "../schema.js";
|
|
@@ -333,7 +333,7 @@ import type { InsertModel } from "./dataModel.js";
|
|
|
333
333
|
* const { posts } = await seed.posts((x) => x([10, 20]));
|
|
334
334
|
*/
|
|
335
335
|
export const createSeedClient = (options?: SeedClientOptions): SeedClient<InsertModel> => createSeedClientBase<InsertModel>(schema, options);
|
|
336
|
-
`:"",
|
|
336
|
+
`:"",Sr=(e,t,n=!1)=>{if(e.length===0||!t)return"";const r=H(n),a=l=>l.table===void 0?"Row":`Doc<${JSON.stringify(l.table)}> & Row`,o=e.map(l=>{m(l.exportName,"shape export name");const u=a(l),p=me(l.args),f=Object.keys(l.args).length>0,y=f?` args: ${p};`:` args?: ${p};`,R=f?`(args: ${p}) => void`:`(args?: ${p}) => void`,d=`${l.exportName}CollectionOptions`;return`/** Options for the \`${l.exportName}\` shape binding. */
|
|
337
337
|
export interface ${Ee(d)} {
|
|
338
338
|
${y}
|
|
339
339
|
/**
|
|
@@ -379,15 +379,15 @@ export const ${l.exportName}Collection = (
|
|
|
379
379
|
return { checkpoints, collection: createCollection(config), scope };
|
|
380
380
|
};`}).join(`
|
|
381
381
|
|
|
382
|
-
`),
|
|
382
|
+
`),i=Be(o),s=i.length>0?`import type { ${i.join(", ")} } from "./dataModel.js";
|
|
383
383
|
`:"";return`${k}import type { LunoraClient, SubscriptionError } from "${r.client}";
|
|
384
384
|
import { lunoraCollectionOptions } from "@lunora/db/collections";
|
|
385
385
|
import type { CheckpointRegistry, LunoraCollectionOptions, Row } from "@lunora/db";
|
|
386
386
|
import type { Collection } from "@tanstack/db";
|
|
387
387
|
import { createCollection } from "@tanstack/db";
|
|
388
|
-
${
|
|
388
|
+
${s}
|
|
389
389
|
${o}
|
|
390
|
-
`},
|
|
390
|
+
`},Cn=(e,t)=>`lunora_${S(e)}_${String(t)}`,In=`const callRegistered = async <R>(context: CallerCtx, functionPath: string, args: Record<string, unknown> | undefined): Promise<R> => {
|
|
391
391
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
392
392
|
|
|
393
393
|
if (!registered) {
|
|
@@ -395,45 +395,45 @@ ${o}
|
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
return (await registered.handler(context, args ?? {})) as R;
|
|
398
|
-
};`,
|
|
399
|
-
`),
|
|
398
|
+
};`,Dn=(e,t,n=[],r=[])=>{const a=new Map,o=d=>{a.has(d)||a.set(d,Cn(d,a.size))};for(const d of e)o(d.filePath);for(const d of t)o(d.filePath);for(const d of n)o(d.filePath);for(const d of r)o(d.filePath);const i=[...a.entries()].map(([d,c])=>{if(!pn.test(d))throw new Z("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(d)}`);return`import * as ${c} from "../${d}.js";`}).join(`
|
|
399
|
+
`),s=e.map(d=>` "${S(d.filePath)}:${d.exportName}": ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
400
400
|
`),l=t.map(d=>` ${JSON.stringify(d.id)}: ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredDataMigration,`).join(`
|
|
401
401
|
`),u=n.map(d=>` "${S(d.filePath)}:${d.exportName}": ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
402
402
|
`),p=r.map(d=>` "${d.exportName}": ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredShape,`).join(`
|
|
403
|
-
`),f=n.map(d=>`${S(d.filePath)}:${d.exportName}`),y=[
|
|
404
|
-
`),R=e.map(d=>{if(d.lifecycle||Object.keys(d.args).length===0)return;const c=
|
|
403
|
+
`),f=n.map(d=>`${S(d.filePath)}:${d.exportName}`),y=[s,u].filter(d=>d.length>0).join(`
|
|
404
|
+
`),R=e.map(d=>{if(d.lifecycle||Object.keys(d.args).length===0)return;const c=un(d.args);return c===void 0?void 0:`installCompiledValidatorMap(${a.get(d.filePath)??""}.${d.exportName}.args, ${c});`}).filter(d=>d!==void 0).join(`
|
|
405
405
|
`);return{dispatchBody:y.length>0?`
|
|
406
406
|
${y}
|
|
407
|
-
`:"",importBlock:
|
|
407
|
+
`:"",importBlock:i.length>0?`${i}
|
|
408
408
|
|
|
409
409
|
`:"",installBlock:R,migrationBody:l.length>0?`
|
|
410
410
|
${l}
|
|
411
411
|
`:"",mutatorPaths:f,shapeBody:p.length>0?`
|
|
412
412
|
${p}
|
|
413
|
-
`:""}},
|
|
413
|
+
`:""}},_n=e=>{const t=new Map;for(const a of e){const o=t.get(a.filePath)??[];o.push(a),t.set(a.filePath,o)}const n=[...t.entries()].toSorted(([a],[o])=>a.localeCompare(o)),r=n.map(([a,o])=>{const i=o.map(s=>{const l=me(s.args),u=l==="{}"?"?":"",p=Me(qe(s.returnType,s.filePath));return s.kind==="stream"?` ${s.exportName}: (args${u}: ${l}) => Promise<AsyncIterable<${p}>>;`:` ${s.exportName}: (args${u}: ${l}) => Promise<${p}>;`}).join(`
|
|
414
414
|
`);return` ${D(S(a))}: {
|
|
415
|
-
${s}
|
|
416
|
-
};`}).join(`
|
|
417
|
-
`);return{implementation:n.map(([a,o])=>{const s=S(a),i=o.map(l=>` ${l.exportName}: (args) => callRegistered(context, "${s}:${l.exportName}", args),`).join(`
|
|
418
|
-
`);return` ${D(s)}: {
|
|
419
415
|
${i}
|
|
416
|
+
};`}).join(`
|
|
417
|
+
`);return{implementation:n.map(([a,o])=>{const i=S(a),s=o.map(l=>` ${l.exportName}: (args) => callRegistered(context, "${i}:${l.exportName}", args),`).join(`
|
|
418
|
+
`);return` ${D(i)}: {
|
|
419
|
+
${s}
|
|
420
420
|
},`}).join(`
|
|
421
|
-
`),types:r}},
|
|
421
|
+
`),types:r}},Pn=(e,t=[])=>{const n=new Set;for(const r of e.tables)for(const a of Object.values(r.shape)){const o=a.kind==="optional"&&a.inner?a.inner:a;o.kind==="storage"&&typeof o.bucket=="string"&&o.bucket!==""&&n.add(o.bucket)}for(const r of t)r!==""&&r!=="default"&&n.add(r);return["default",...[...n].toSorted((r,a)=>r.localeCompare(a))]},Rr=({agents:e=[],containers:t=[],env:n,hasAccessFacade:r=!1,hasAi:a=!1,hasAnalytics:o=!1,hasBrowser:i=!1,hasFlags:s=!1,hasHyperdrive:l=!1,hasImages:u=!1,hasKv:p=!1,hasNotify:f=!1,hasPayments:y=!1,hasPipelines:R=!1,hasR2sql:d=!1,hasX402:c=!1,identity:g,queues:b=[],schema:x,storageRuleBuckets:v=[],useUmbrella:O=!1,workflows:N=[]}={})=>{const $=H(O),w=Pn(x??{tables:[]},v).map(h=>JSON.stringify(h)).join(" | "),E=a?`import type { LunoraAi } from "@lunora/ai";
|
|
422
422
|
`:"",ee=a?`
|
|
423
423
|
readonly ai: LunoraAi;`:"",F=y?`import type { LunoraPayment } from "@lunora/payment";
|
|
424
424
|
`:"",te=y?`
|
|
425
425
|
readonly payments: LunoraPayment;`:"",ne=c?`import type { X402Pay } from "@lunora/x402/pay";
|
|
426
426
|
`:"",B=c?`
|
|
427
|
-
readonly x402: X402Pay;`:"",
|
|
427
|
+
readonly x402: X402Pay;`:"",T=t.length>0?`import type { ContainerAccessor } from "@lunora/container";
|
|
428
428
|
`:"",z=t.length>0?`
|
|
429
429
|
readonly containers: {${t.map(h=>`
|
|
430
430
|
readonly ${h.exportName}: ContainerAccessor;`).join("")}
|
|
431
|
-
};`:"",
|
|
431
|
+
};`:"",A=[...a?[" /** Workers AI binding (the conventional `env.AI`), narrowing `ctx.ai`. */\n readonly AI?: unknown;"]:[],...t.map(h=>(m(h.bindingName,`container binding "${h.bindingName}"`),` /** Durable Object namespace for the \`${h.exportName}\` container. */
|
|
432
432
|
readonly ${h.bindingName}?: unknown;`)),...N.map(h=>(m(h.bindingName,`workflow binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` workflow. */
|
|
433
433
|
readonly ${h.bindingName}?: unknown;`)),...b.map(h=>(m(h.bindingName,`queue binding "${h.bindingName}"`),` /** Queue producer binding for the \`${h.exportName}\` queue. */
|
|
434
434
|
readonly ${h.bindingName}?: unknown;`)),...e.map(h=>(m(h.bindingName,`agent binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` agent. */
|
|
435
435
|
readonly ${h.bindingName}?: unknown;`))].join(`
|
|
436
|
-
`),
|
|
436
|
+
`),I=`
|
|
437
437
|
|
|
438
438
|
/**
|
|
439
439
|
* This project's Cloudflare bindings, as far as codegen can discover them from
|
|
@@ -446,18 +446,18 @@ ${i}
|
|
|
446
446
|
* surface, so treat them as \`Fetcher\`/\`Service<unknown>\` and cast.
|
|
447
447
|
*/
|
|
448
448
|
export interface CloudflareBindings {
|
|
449
|
-
readonly [binding: string]: unknown;${
|
|
450
|
-
${
|
|
449
|
+
readonly [binding: string]: unknown;${A?`
|
|
450
|
+
${A}`:""}
|
|
451
451
|
}
|
|
452
452
|
|
|
453
453
|
/** Alias for {@link CloudflareBindings} — the typed shape of \`env\`. */
|
|
454
|
-
export type Env = CloudflareBindings;`,M=(h,
|
|
455
|
-
readonly vectors: VectorSearch<VectorIndexName>;`:"",
|
|
454
|
+
export type Env = CloudflareBindings;`,M=(h,De)=>De?rn.get(h)?.field??"":"",re=M("kv",p),ae=M("analytics",o),xe=M("hyperdrive",l),ke=M("browser",i),ve=M("images",u),oe=M("pipelines",R),K=M("r2sql",d),P=(x?.vectorIndexes.length??0)>0,Q=P?' | "vectors"':"",X=P?`
|
|
455
|
+
readonly vectors: VectorSearch<VectorIndexName>;`:"",se=P?`
|
|
456
456
|
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",J=P?`import type { VectorSearch, VectorSearchReader } from "${$.server}";
|
|
457
457
|
import type { VectorIndexName } from "./dataModel.js";
|
|
458
458
|
`:"",j=r?`
|
|
459
459
|
/** Verified Cloudflare Access identity — a synchronous facade over the resolved claims (email / groups / hasGroup / claims). Anonymous when no Access token is present. */
|
|
460
|
-
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",W=
|
|
460
|
+
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",W=s?`
|
|
461
461
|
/** Feature-flag evaluation (OpenFeature). Reads are memoized per request; evaluations never throw — a provider error resolves to the supplied default. */
|
|
462
462
|
readonly flags: import("${$.flags}").LunoraFlags;`:"",U=f?`
|
|
463
463
|
/** 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. */
|
|
@@ -479,9 +479,9 @@ export interface LunoraWorkflows {
|
|
|
479
479
|
${N.map(h=>` get(name: ${JSON.stringify(h.exportName)}): WorkflowHandle<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${h.exportName}>>;`).join(`
|
|
480
480
|
`)}
|
|
481
481
|
}`:"",fe=q?' | "workflows"':"",be=q?`
|
|
482
|
-
readonly workflows: LunoraWorkflows;`:"",
|
|
482
|
+
readonly workflows: LunoraWorkflows;`:"",ie=b.length>0,Se=ie?`import type { QueueProducer } from "@lunora/queue";
|
|
483
483
|
import type * as lunoraQueueDefinitions from "../queues.js";
|
|
484
|
-
`:"",Re=
|
|
484
|
+
`:"",Re=ie?`
|
|
485
485
|
|
|
486
486
|
/** Message body type carried by a \`defineQueue\` definition (its phantom \`__lunoraBody\`). */
|
|
487
487
|
type QueueBodyOf<Definition> = Definition extends { __lunoraBody?: infer Body } ? (unknown extends Body ? unknown : NonNullable<Body>) : unknown;
|
|
@@ -490,7 +490,7 @@ type QueueBodyOf<Definition> = Definition extends { __lunoraBody?: infer Body }
|
|
|
490
490
|
export interface LunoraQueues {
|
|
491
491
|
${b.map(h=>` readonly ${h.exportName}: QueueProducer<QueueBodyOf<typeof lunoraQueueDefinitions.${h.exportName}>>;`).join(`
|
|
492
492
|
`)}
|
|
493
|
-
}`:"",ye=
|
|
493
|
+
}`:"",ye=ie?`
|
|
494
494
|
readonly queues: LunoraQueues;`:"",le=e.length>0,Ne=le?`import type { AgentHandle } from "@lunora/agent";
|
|
495
495
|
`:"",Oe=le?`
|
|
496
496
|
|
|
@@ -509,7 +509,7 @@ export type Identity = InferIdentity<typeof lunoraIdentityContract.${g.exportNam
|
|
|
509
509
|
/** \`ctx.auth\` narrowed so \`getIdentity()\` resolves the declared {@link Identity} contract instead of the untyped claim bag. */
|
|
510
510
|
type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: () => Promise<Identity | null> };`:"",de=g?' | "auth"':"",ce=g?`
|
|
511
511
|
readonly auth: NarrowedAuth;`:"",Le=g?", Identity":"",Ce=n?`import type * as lunoraEnvContract from "../env.js";
|
|
512
|
-
`:"",
|
|
512
|
+
`:"",Ie=n?`
|
|
513
513
|
|
|
514
514
|
/** This app's declared env contract (\`defineEnv\` in \`lunora/env.ts\`) — the validated, coercion-aware shape of \`ctx.env\`. */
|
|
515
515
|
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",ue=n?' | "env"':"",pe=n?"\n /** Validated, typed environment declared by `defineEnv` in `lunora/env.ts` — parsed & coercion-aware config values (`ctx.env.STRIPE_KEY`); a missing or invalid value throws at read time. */\n readonly env: LunoraEnv;":"";return`${k}import { createPolicyDsl, defineMutator as defineMutatorBase, initLunora, v as vBase } from "${$.server}";
|
|
@@ -535,12 +535,12 @@ import type {
|
|
|
535
535
|
Validator,
|
|
536
536
|
} from "${$.server}";
|
|
537
537
|
|
|
538
|
-
import type { DataModel, DatabaseReaderFacade, DatabaseWriterFacade, Doc, Id as IdOfTable, OrmReader, OrmWriter, Relations, TableName } from "./dataModel.js";
|
|
539
|
-
${J}${E}${F}${ne}${
|
|
538
|
+
import type { DataModel, DatabaseReaderFacade, DatabaseWriterFacade, Doc, GeoIndexNamesByTable, Id as IdOfTable, IndexNamesByTable, OrmReader, OrmWriter, Relations, SearchIndexNamesByTable, TableName } from "./dataModel.js";
|
|
539
|
+
${J}${E}${F}${ne}${T}${Y}${Se}${Ne}${Te}${Ce}
|
|
540
540
|
export type { AppTableName, DataModel, Doc, Id, TableName } from "./dataModel.js";
|
|
541
541
|
|
|
542
542
|
/** Storage buckets this schema declares (\`v.storage("name")\`), narrowing \`ctx.storage.bucket(name)\`. */
|
|
543
|
-
export type StorageBucketName = ${w};${
|
|
543
|
+
export type StorageBucketName = ${w};${I}${$e}${Re}${Oe}${Ae}${Ie}
|
|
544
544
|
|
|
545
545
|
/**
|
|
546
546
|
* Project-typed contexts. The base contexts from \`@lunora/server\` are
|
|
@@ -559,8 +559,17 @@ export type StorageBucketName = ${w};${_}${$e}${Re}${Oe}${Ae}${De}
|
|
|
559
559
|
* Intersected with the wide \`(string) => TableReader\` signature so the bound
|
|
560
560
|
* \`ctx.db\` is still structurally assignable to schema-agnostic consumers that
|
|
561
561
|
* call \`db.query(someString)\` (e.g. \`@lunora/ratelimit\`'s \`createDbStore\`).
|
|
562
|
+
*
|
|
563
|
+
* The three index-name unions are what make \`.withIndex("by_TYPO")\` a compile
|
|
564
|
+
* error: each resolves to the table's declared names, or \`never\` when it
|
|
565
|
+
* declares none of that kind. Without them a renamed or dropped index left
|
|
566
|
+
* every call site typechecking, and the query either threw at runtime or
|
|
567
|
+
* degraded silently to a full table scan.
|
|
562
568
|
*/
|
|
563
|
-
type TypedTableQuery = (<T extends TableName>(
|
|
569
|
+
type TypedTableQuery = (<T extends TableName>(
|
|
570
|
+
table: T,
|
|
571
|
+
) => TableReader<Doc<T>, IndexNamesByTable[T], SearchIndexNamesByTable[T], GeoIndexNamesByTable[T]>) &
|
|
572
|
+
((table: string) => TableReader);
|
|
564
573
|
|
|
565
574
|
/**
|
|
566
575
|
* The point read \`ctx.db.get(id)\`, bound to this schema: an \`Id<"table">\`
|
|
@@ -597,7 +606,7 @@ type TypedAsId = <T extends string>(tableName: AsIdTable<T>, id: string) => IdOf
|
|
|
597
606
|
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${Q}${de}${ue}> {
|
|
598
607
|
readonly db: Omit<DatabaseReader, "asId" | "query" | "get"> & DatabaseReaderFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
599
608
|
readonly orm: OrmReader;
|
|
600
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${
|
|
609
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${se}${j}${re}${W}${U}${ae}${pe}${ce}
|
|
601
610
|
}
|
|
602
611
|
|
|
603
612
|
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${Q}${fe}${de}${ue}> {
|
|
@@ -684,12 +693,12 @@ export const definePolicy = createPolicyDsl<DataModel, Relations${Le}>();
|
|
|
684
693
|
export const v = vBase as unknown as Omit<typeof vBase, "id"> & {
|
|
685
694
|
id: <T extends TableName>(table: T) => ColumnValidator<IdOfTable<T>, IdOfTable<T>>;
|
|
686
695
|
};
|
|
687
|
-
`},
|
|
696
|
+
`},En=e=>{const t={connect:[],disconnect:[]};for(const n of e)n.lifecycle&&t[n.lifecycle].push(`${S(n.filePath)}:${n.exportName}`);return t},Nr=e=>{const{agents:t=[],functions:n,migrations:r=[],mutators:a=[],shapes:o=[],useUmbrella:i=!1,usesSandbox:s=!1}=e,l=n.length>0,u=H(i),{dispatchBody:p,importBlock:f,installBlock:y,migrationBody:R,mutatorPaths:d,shapeBody:c}=Dn(n,r,a,o),g=Nn(t,n),b=On(s,n),x=[g.lines,b.lines].filter(I=>I.length>0).join(`
|
|
688
697
|
`);let v=p;x.length>0&&(v=p.length>0?`${p.trimEnd()}
|
|
689
698
|
${x}
|
|
690
699
|
`:`
|
|
691
700
|
${x}
|
|
692
|
-
`);const
|
|
701
|
+
`);const O=En(n),N=o.length>0?`import type { RegisteredShape } from "${u.server}";
|
|
693
702
|
`:"",$=o.length>0?`
|
|
694
703
|
/**
|
|
695
704
|
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
@@ -704,7 +713,7 @@ export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${c}};
|
|
|
704
713
|
* ShardDO's \`isCustomMutator\` override routes through the client-watermark push
|
|
705
714
|
* protocol (\`x-lunora-client-id\`/\`x-lunora-client-seq\` ordering).
|
|
706
715
|
*/
|
|
707
|
-
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${d.map(
|
|
716
|
+
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${d.map(I=>JSON.stringify(I)).join(", ")}]);
|
|
708
717
|
`:"",E=y.length>0?`import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${u.values}";
|
|
709
718
|
`:"",ee=y.length>0?`
|
|
710
719
|
/**
|
|
@@ -713,16 +722,16 @@ export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${d.map(_=>JSO
|
|
|
713
722
|
* parser as a zero-allocation fast path; anything it can't model is deferred.
|
|
714
723
|
*/
|
|
715
724
|
${y}
|
|
716
|
-
`:"",F=
|
|
725
|
+
`:"",F=_n(n),te=F.types?`
|
|
717
726
|
${F.types}
|
|
718
727
|
`:"",ne=F.implementation?`
|
|
719
728
|
${F.implementation}
|
|
720
|
-
`:"",B=
|
|
721
|
-
`:"",z=l?"context":"_context",
|
|
729
|
+
`:"",B=Be(F.types),T=B.length>0?`import type { ${B.join(", ")} } from "./dataModel.js";
|
|
730
|
+
`:"",z=l?"context":"_context",A=l?`${In}
|
|
722
731
|
|
|
723
|
-
`:"";return
|
|
732
|
+
`:"";return lt(`${k}${f}${g.importLine}${b.importLine}${E}${N}import { LunoraError } from "${u.server}";
|
|
724
733
|
import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
725
|
-
${
|
|
734
|
+
${T}
|
|
726
735
|
/**
|
|
727
736
|
* Single registered function, narrowed to the shape \`handleRpc\` needs.
|
|
728
737
|
* The real argument validators / return types are checked elsewhere — at
|
|
@@ -755,8 +764,8 @@ ${ee}${$}${w}
|
|
|
755
764
|
* DO runs every hook under the socket's verified identity via system dispatch.
|
|
756
765
|
*/
|
|
757
766
|
export const LUNORA_LIFECYCLE_HOOKS: { connect: readonly string[]; disconnect: readonly string[] } = {
|
|
758
|
-
connect: [${
|
|
759
|
-
disconnect: [${
|
|
767
|
+
connect: [${O.connect.map(I=>JSON.stringify(I)).join(", ")}],
|
|
768
|
+
disconnect: [${O.disconnect.map(I=>JSON.stringify(I)).join(", ")}],
|
|
760
769
|
};
|
|
761
770
|
|
|
762
771
|
/**
|
|
@@ -789,7 +798,7 @@ export type CallerCtx = ActionCtx | MutationCtx | QueryCtx;
|
|
|
789
798
|
*/
|
|
790
799
|
export interface Caller {${te}}
|
|
791
800
|
|
|
792
|
-
${
|
|
801
|
+
${A}/** Build a {@link Caller} bound to \`context\` (typically a handler's \`ctx\`). */
|
|
793
802
|
export const createCaller = (${z}: CallerCtx): Caller => ({${ne}});
|
|
794
803
|
|
|
795
804
|
/**
|
|
@@ -810,7 +819,7 @@ export interface RegisteredDataMigration {
|
|
|
810
819
|
* shard DO's admin RPC and the CLI resolve migrations to run through this map.
|
|
811
820
|
*/
|
|
812
821
|
export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${R}};
|
|
813
|
-
`,
|
|
822
|
+
`,i)},Fn=e=>{const t={};for(const n of e.tables){const r={};for(const[a,o]of Object.entries(n.shape)){const i=o.kind==="optional"&&o.inner?o.inner:o;i.kind==="id"&&i.tableName!==void 0&&(r[a]=i.tableName)}Object.keys(r).length>0&&(t[n.name]=r)}return t},Mn=e=>{const t={};for(const n of e.tables){const r=[];for(const[a,o]of Object.entries(n.shape))(o.kind==="optional"&&o.inner?o.inner:o).kind==="storage"&&r.push(a);r.length>0&&(t[n.name]=r)}return t},qn=e=>{const t={};for(const n of e.tables){const r=[...n.indexes.map(a=>({fields:[...a.fields],name:a.name,type:"index",...a.unique===!0?{unique:!0}:{}})),...n.searchIndexes.map(a=>({fields:[a.field,...a.filterFields??[]],name:a.name,type:"search"})),...(n.geoIndexes??[]).map(a=>({fields:[a.field],name:a.name,type:"geo"})),...n.rankIndexes.map(a=>({fields:a.sortBy.map(o=>o.field),name:a.name,type:"rank"})),...n.vectorIndexes.map(a=>({fields:a.field===void 0?[]:[a.field],name:a.name,type:"vector"}))];r.length>0&&(t[n.name]=r)}return t},Bn=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},jn=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"}];for(const[a,o]of Object.entries(n.shape)){const i=o.kind==="optional"||!!o.column?.hasDefault,s=o.kind==="optional"&&o.inner?o.inner:o,l={name:a,optional:i,type:s.kind};s.kind==="id"&&s.tableName!==void 0&&(l.ref=s.tableName),s.kind==="storage"&&(l.isStorage=!0),r.push(l)}t[n.name]=r}return t},Wn=e=>e?{importFragment:"serveRelationFanout, ",override:`
|
|
814
823
|
protected override async runRelationFanoutRead(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
815
824
|
this.ensureMigrated();
|
|
816
825
|
|
|
@@ -818,7 +827,7 @@ export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${R}}
|
|
|
818
827
|
|
|
819
828
|
return serveRelationFanout(schema as unknown as SchemaLike, db, functionPath, args);
|
|
820
829
|
}
|
|
821
|
-
`}:{importFragment:"",override:""},
|
|
830
|
+
`}:{importFragment:"",override:""},Un=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:`
|
|
822
831
|
const aiBinding = config.ai?.(env) ?? (env as Record<string, unknown>).AI;
|
|
823
832
|
// Correlate AI-Gateway-routed calls with the Lunora trace: thread the
|
|
824
833
|
// function path + trace id into createAi, which folds them into the
|
|
@@ -849,7 +858,7 @@ const aiStub: LunoraAi = {
|
|
|
849
858
|
${t}
|
|
850
859
|
}) as unknown as LunoraAi["workersai"],
|
|
851
860
|
};
|
|
852
|
-
`}},
|
|
861
|
+
`}},_={build:"",configField:"",contextField:"",importLines:[],stub:""},Kn=e=>{if(!e)return _;const t='throw new Error("ctx.kv: no KV binding found. Add a \\`kv_namespaces\\` binding (env.KV) to wrangler.jsonc, or pass \\`kv\\` to createShardDO().");';return{build:`
|
|
853
862
|
const kvBinding = config.kv?.(env) ?? (env as Record<string, unknown>).KV;
|
|
854
863
|
const kv: Kv = kvBinding ? createKv({ namespace: kvBinding as KVNamespaceLike }) : kvStub;
|
|
855
864
|
`,configField:`
|
|
@@ -875,7 +884,7 @@ const kvStub: Kv = {
|
|
|
875
884
|
${t}
|
|
876
885
|
},
|
|
877
886
|
};
|
|
878
|
-
`}},
|
|
887
|
+
`}},Qn=(e,t)=>e?{build:`
|
|
879
888
|
const flags: import("${t}").LunoraFlags = createFlags({
|
|
880
889
|
hooks: flagsConfig.hooks,
|
|
881
890
|
logger: flagsConfig.logger,
|
|
@@ -884,23 +893,23 @@ const kvStub: Kv = {
|
|
|
884
893
|
});
|
|
885
894
|
`,configField:`
|
|
886
895
|
flags?: (env: Record<string, unknown>) => import("${t}").Provider;`,contextField:`
|
|
887
|
-
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:
|
|
896
|
+
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:_,Jn=e=>e?{build:`
|
|
888
897
|
const { notify, push } = createNotify(notifyConfig, env, { log, metrics });
|
|
889
898
|
`,configField:"",contextField:`
|
|
890
899
|
notify,
|
|
891
|
-
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:
|
|
900
|
+
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:_,Vn=e=>e?{build:`
|
|
892
901
|
const envConfig = lunoraEnvContract.${e.exportName}(env);
|
|
893
902
|
`,configField:"",contextField:`
|
|
894
|
-
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:
|
|
903
|
+
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:_,Gn=e=>e?{build:`
|
|
895
904
|
const access = accessFacade(identity, userId);
|
|
896
905
|
`,configField:"",contextField:`
|
|
897
|
-
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:
|
|
906
|
+
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:_,Hn=(e,t,n)=>{if(!t)return{constant:"",evaluateOverride:"",subscriptionOverride:""};const r=s=>`
|
|
898
907
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
899
908
|
const flags: import("${n}").LunoraFlags = createFlags({
|
|
900
909
|
hooks: flagsConfig.hooks,
|
|
901
910
|
logger: flagsConfig.logger,
|
|
902
911
|
provider: () => config.flags?.(env) ?? flagsConfig.provider(env),
|
|
903
|
-
targetingKey: ${
|
|
912
|
+
targetingKey: ${s},
|
|
904
913
|
});`,a=`
|
|
905
914
|
/** Statically-discovered feature flags (\`ctx.flags.<type>("key")\` reads) served via \`__lunora_admin__:listFlags\` + the reactive \`__lunora_flags__:\` channel. */
|
|
906
915
|
const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number" | "object" | "string" }> = ${JSON.stringify(e,void 0,4)};
|
|
@@ -925,7 +934,7 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
925
934
|
|
|
926
935
|
return { configured: true, flags: evaluations };
|
|
927
936
|
}
|
|
928
|
-
`,
|
|
937
|
+
`,i=`
|
|
929
938
|
protected override runFlagSubscriptionRead(_functionPath: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): Promise<unknown> {${r("() => flagsConfig.identify?.({ identity: identity?.identity ?? null, userId: identity?.userId ?? null })")}
|
|
930
939
|
const key = typeof args.key === "string" ? args.key : "";
|
|
931
940
|
|
|
@@ -958,7 +967,7 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
958
967
|
|
|
959
968
|
return flags.boolean(key, typeof args.default === "boolean" ? args.default : false, context);
|
|
960
969
|
}
|
|
961
|
-
`;return{constant:a,evaluateOverride:o,subscriptionOverride:
|
|
970
|
+
`;return{constant:a,evaluateOverride:o,subscriptionOverride:i}},zn=e=>{if(!e)return _;const t='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().");';return{build:`
|
|
962
971
|
const analyticsBinding = config.analytics?.(env) ?? (env as Record<string, unknown>).ANALYTICS;
|
|
963
972
|
const analytics: AnalyticsClient = analyticsBinding ? createAnalytics(analyticsBinding as AnalyticsEngineDatasetLike) : analyticsStub;
|
|
964
973
|
`,configField:`
|
|
@@ -972,7 +981,7 @@ const analyticsStub: AnalyticsClient = {
|
|
|
972
981
|
${t}
|
|
973
982
|
},
|
|
974
983
|
};
|
|
975
|
-
`}},
|
|
984
|
+
`}},Xn=e=>{if(!e)return _;const t='throw new Error("ctx.images: no Images binding found. Add an \\`images\\` binding (env.IMAGES) to wrangler.jsonc, or pass \\`images\\` to createShardDO().");';return{build:`
|
|
976
985
|
const imagesBinding = config.images?.(env) ?? (env as Record<string, unknown>).IMAGES;
|
|
977
986
|
const images: Images = imagesBinding ? createImages({ binding: imagesBinding as ImagesBindingLike }) : imagesStub;
|
|
978
987
|
`,configField:`
|
|
@@ -986,7 +995,7 @@ const imagesStub: Images = {
|
|
|
986
995
|
${t}
|
|
987
996
|
},
|
|
988
997
|
};
|
|
989
|
-
`}},
|
|
998
|
+
`}},Yn=e=>e?{build:`
|
|
990
999
|
const sql: SqlClient = config.sql ? config.sql(env) : sqlStub;
|
|
991
1000
|
`,configField:`
|
|
992
1001
|
sql?: (env: Record<string, unknown>) => SqlClient;`,contextField:`
|
|
@@ -996,7 +1005,7 @@ const sqlStub: SqlClient = {
|
|
|
996
1005
|
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))\\\`.");
|
|
997
1006
|
},
|
|
998
1007
|
};
|
|
999
|
-
`}:
|
|
1008
|
+
`}:_,Zn=e=>{if(!e)return _;const t="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.\");";return{build:`
|
|
1000
1009
|
const browser: Browser = config.browser ? config.browser(env) : browserStub;
|
|
1001
1010
|
`,configField:`
|
|
1002
1011
|
browser?: (env: Record<string, unknown>) => Browser;`,contextField:`
|
|
@@ -1024,7 +1033,7 @@ const browserStub: Browser = {
|
|
|
1024
1033
|
${t}
|
|
1025
1034
|
},
|
|
1026
1035
|
};
|
|
1027
|
-
`}},
|
|
1036
|
+
`}},er=e=>{if(!e)return _;const t='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().");';return{build:`
|
|
1028
1037
|
const r2sqlEnv = env as Record<string, unknown>;
|
|
1029
1038
|
const r2sqlAccountId = (r2sqlEnv.R2_SQL_ACCOUNT_ID ?? r2sqlEnv.CLOUDFLARE_ACCOUNT_ID) as string | undefined;
|
|
1030
1039
|
const r2sqlToken = r2sqlEnv.R2_SQL_TOKEN as string | undefined;
|
|
@@ -1056,7 +1065,7 @@ const r2sqlStub: R2SqlClient = {
|
|
|
1056
1065
|
${t}
|
|
1057
1066
|
},
|
|
1058
1067
|
};
|
|
1059
|
-
`}},
|
|
1068
|
+
`}},tr=e=>e?{build:`
|
|
1060
1069
|
const pipelinesBinding = config.pipelines?.(env) ?? (env as Record<string, unknown>).PIPELINES;
|
|
1061
1070
|
const pipelines: PipelineClient = pipelinesBinding ? createPipelines({ binding: pipelinesBinding as PipelineBindingLike }) : pipelinesStub;
|
|
1062
1071
|
`,configField:`
|
|
@@ -1066,7 +1075,7 @@ const pipelinesStub: PipelineClient = {
|
|
|
1066
1075
|
throw new Error("ctx.pipelines: no Pipelines binding found. Add a \\\`pipelines\\\` binding (env.PIPELINES) to wrangler.jsonc, or pass \\\`pipelines\\\` to createShardDO().");
|
|
1067
1076
|
},
|
|
1068
1077
|
};
|
|
1069
|
-
`}:
|
|
1078
|
+
`}:_,Or=(e,t)=>{if(e.length===0)return"";const n=t?`, ${JSON.stringify(t)}`:"",r=e.map(o=>(m(o.exportName,`container export "${o.exportName}"`),m(o.className,`container class "${o.className}"`),`/** Container DO for the \`${o.exportName}\` definition (binding \`${o.bindingName}\`). */
|
|
1070
1079
|
export class ${o.className} extends LunoraContainer {
|
|
1071
1080
|
public constructor(ctx: ConstructorParameters<typeof LunoraContainer>[0], env: Record<string, unknown>) {
|
|
1072
1081
|
super(ctx, env, ${o.exportName}, "${o.exportName}"${n});
|
|
@@ -1091,7 +1100,7 @@ import { ${a} } from "../containers.js";
|
|
|
1091
1100
|
|
|
1092
1101
|
export { ContainerProxy } from "@lunora/container/do";
|
|
1093
1102
|
|
|
1094
|
-
${r}`},
|
|
1103
|
+
${r}`},nr=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const r of e)m(r.exportName,`container export "${r.exportName}"`),m(r.bindingName,`container binding "${r.bindingName}"`);const n=e.map(r=>{const a=r.maxInstances===void 0?"":`, maxInstances: ${String(r.maxInstances)}`;return` { binding: "${r.bindingName}", exportName: "${r.exportName}"${a} },`}).join(`
|
|
1095
1104
|
`);return{build:`
|
|
1096
1105
|
const containers = createContainerContext(env, LUNORA_CONTAINERS, ${t?JSON.stringify(t):"undefined"}, this.getCurrentTraceparent());
|
|
1097
1106
|
`,contextField:`
|
|
@@ -1100,7 +1109,7 @@ ${r}`},Xn=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[]
|
|
|
1100
1109
|
const LUNORA_CONTAINERS: ReadonlyArray<ContainerBindingSpec> = [
|
|
1101
1110
|
${n}
|
|
1102
1111
|
];
|
|
1103
|
-
`}}
|
|
1112
|
+
`}},Tr=e=>{if(e.length===0)return"";const t=e.map(r=>(m(r.exportName,`workflow export "${r.exportName}"`),m(r.className,`workflow class "${r.className}"`),`/** WorkflowEntrypoint for the \`${r.exportName}\` definition (binding \`${r.bindingName}\`). */
|
|
1104
1113
|
export class ${r.className} extends LunoraWorkflow<WorkflowParamsOf<typeof ${r.exportName}>, WorkflowOutputOf<typeof ${r.exportName}>> {
|
|
1105
1114
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1106
1115
|
super(ctx, env, ${r.exportName}, "${r.exportName}");
|
|
@@ -1128,15 +1137,15 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
1128
1137
|
/** Output type carried by a \`defineWorkflow\` definition (its phantom \`__output\`), so each entrypoint keeps the authored return type. */
|
|
1129
1138
|
type WorkflowOutputOf<Definition> = Definition extends { __output?: infer Output } ? Output : unknown;
|
|
1130
1139
|
|
|
1131
|
-
${t}`},
|
|
1140
|
+
${t}`},Ar=e=>{if(e.length===0)return"";const t=e.filter(a=>a.voice).length>0,n=e.map(a=>{m(a.exportName,`agent export "${a.exportName}"`),m(a.className,`agent class "${a.className}"`);const o=`/** WorkflowEntrypoint for the \`${a.exportName}\` agent (binding \`${a.bindingName}\`). */
|
|
1132
1141
|
export class ${a.className} extends LunoraWorkflow<AgentRunInput, AgentRunResult> {
|
|
1133
1142
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1134
1143
|
super(ctx, env, compileAgentWorkflow(${a.exportName}, "${a.exportName}"), "${a.exportName}");
|
|
1135
1144
|
}
|
|
1136
1145
|
}
|
|
1137
|
-
`;if(!a.voice)return o;const
|
|
1138
|
-
/** Voice-session Durable Object for the \`${a.exportName}\` agent (binding \`${
|
|
1139
|
-
export class ${
|
|
1146
|
+
`;if(!a.voice)return o;const i=a.voiceClassName??"",s=a.voiceBindingName??"";m(i,`agent voice class "${i}"`);const l=`
|
|
1147
|
+
/** Voice-session Durable Object for the \`${a.exportName}\` agent (binding \`${s}\`). */
|
|
1148
|
+
export class ${i} extends VoiceSessionDO {
|
|
1140
1149
|
public constructor(ctx: ConstructorParameters<typeof VoiceSessionDO>[0], env: Record<string, unknown>) {
|
|
1141
1150
|
super(ctx, env, ${a.exportName}, "${a.exportName}");
|
|
1142
1151
|
}
|
|
@@ -1156,7 +1165,7 @@ import type { AgentRunInput, AgentRunResult } from "@lunora/agent";
|
|
|
1156
1165
|
|
|
1157
1166
|
import { ${r} } from "../agents.js";
|
|
1158
1167
|
|
|
1159
|
-
${n}`},
|
|
1168
|
+
${n}`},Lr=e=>{const t=e.filter(a=>a.mode==="push");if(t.length===0)return"";for(const a of t)m(a.exportName,`queue export "${a.exportName}"`);const n=t.map(a=>a.exportName).join(", "),r=t.map(a=>` ${JSON.stringify(a.name)}: { definition: ${a.exportName}, exportName: ${JSON.stringify(a.exportName)} },`).join(`
|
|
1160
1169
|
`);return`${k}/**
|
|
1161
1170
|
* Push-consumer registry for the queues declared in \`lunora/queues.ts\`. The
|
|
1162
1171
|
* composed worker's \`queue(batch, env, ctx)\` entry routes each delivered batch
|
|
@@ -1171,7 +1180,7 @@ import { ${n} } from "../queues.js";
|
|
|
1171
1180
|
export const LUNORA_QUEUE_REGISTRY: QueueRegistry = {
|
|
1172
1181
|
${r}
|
|
1173
1182
|
};
|
|
1174
|
-
`},
|
|
1183
|
+
`},rr=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)m(n.exportName,`workflow export "${n.exportName}"`),m(n.bindingName,`workflow binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}" },`).join(`
|
|
1175
1184
|
`);return{build:`
|
|
1176
1185
|
const workflows = createWorkflowContext(env, LUNORA_WORKFLOWS);
|
|
1177
1186
|
`,contextField:`
|
|
@@ -1180,7 +1189,7 @@ ${r}
|
|
|
1180
1189
|
const LUNORA_WORKFLOWS: ReadonlyArray<WorkflowBindingSpec> = [
|
|
1181
1190
|
${t}
|
|
1182
1191
|
];
|
|
1183
|
-
`}},
|
|
1192
|
+
`}},ar=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)m(n.exportName,`queue export "${n.exportName}"`),m(n.bindingName,`queue binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}", name: ${JSON.stringify(n.name)} },`).join(`
|
|
1184
1193
|
`);return{build:`
|
|
1185
1194
|
const queues = createQueueContext(env, LUNORA_QUEUES);
|
|
1186
1195
|
`,contextField:`
|
|
@@ -1189,7 +1198,7 @@ ${t}
|
|
|
1189
1198
|
const LUNORA_QUEUES: ReadonlyArray<QueueBindingSpec> = [
|
|
1190
1199
|
${t}
|
|
1191
1200
|
];
|
|
1192
|
-
`}},
|
|
1201
|
+
`}},or=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)m(n.exportName,`agent export "${n.exportName}"`),m(n.bindingName,`agent binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}"${n.publicRun===!0?", publicRun: true":""} },`).join(`
|
|
1193
1202
|
`);return{build:`
|
|
1194
1203
|
const agents = createAgentContext(env, LUNORA_AGENTS);
|
|
1195
1204
|
`,contextField:`
|
|
@@ -1198,21 +1207,21 @@ ${t}
|
|
|
1198
1207
|
const LUNORA_AGENTS: ReadonlyArray<AgentBindingSpec> = [
|
|
1199
1208
|
${t}
|
|
1200
1209
|
];
|
|
1201
|
-
`}},
|
|
1210
|
+
`}},sr=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{constant:`
|
|
1202
1211
|
/** Read-only declared-workflow metadata (discovered from \`lunora/workflows.ts\`) served via \`__lunora_admin__:listWorkflows\` for the studio's workflows view. */
|
|
1203
1212
|
const LUNORA_WORKFLOWS_INFO: WorkflowsResult = ${JSON.stringify(t,void 0,4)};
|
|
1204
1213
|
`,override:`
|
|
1205
1214
|
protected override workflowsMetadata(): WorkflowsResult {
|
|
1206
1215
|
return LUNORA_WORKFLOWS_INFO;
|
|
1207
1216
|
}
|
|
1208
|
-
`}},
|
|
1217
|
+
`}},ir=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{constant:`
|
|
1209
1218
|
/** Read-only declared-queue metadata (discovered from \`lunora/queues.ts\`) served via \`__lunora_admin__:listQueues\` for the studio's queues view. */
|
|
1210
1219
|
const LUNORA_QUEUES_INFO: QueuesResult = ${JSON.stringify(t,void 0,4)};
|
|
1211
1220
|
`,override:`
|
|
1212
1221
|
protected override queuesMetadata(): QueuesResult {
|
|
1213
1222
|
return LUNORA_QUEUES_INFO;
|
|
1214
1223
|
}
|
|
1215
|
-
`}},
|
|
1224
|
+
`}},lr=e=>{if(!e)return{build:"",configField:"",contextField:"",imports:[],stub:""};const t='throw new Error("ctx.payments: no payment configured. Pass \\`payment\\` to createShardDO().");';return{imports:['import type { LunoraDatabaseLike as LunoraPaymentDbLike, LunoraPayment, PaymentsFromContextOptions } from "@lunora/payment";','import { paymentsFromContext } from "@lunora/payment";'],build:`
|
|
1216
1225
|
const payments: LunoraPayment = config.payment
|
|
1217
1226
|
? paymentsFromContext({ auth: { userId: userId ?? null }, db: db as unknown as LunoraPaymentDbLike }, config.payment(env))
|
|
1218
1227
|
: paymentStub;
|
|
@@ -1248,7 +1257,7 @@ const paymentStub: LunoraPayment = {
|
|
|
1248
1257
|
${t}
|
|
1249
1258
|
},
|
|
1250
1259
|
} as unknown as LunoraPayment;
|
|
1251
|
-
`}},
|
|
1260
|
+
`}},dr=e=>e?{imports:['import type { X402Pay, X402PayConfig } from "@lunora/x402/pay";','import { lazyX402Pay } from "@lunora/x402/pay";'],build:`
|
|
1252
1261
|
const x402: X402Pay = config.x402
|
|
1253
1262
|
? lazyX402Pay(config.x402(env), { getSecret: (name: string) => secrets.get(name) })
|
|
1254
1263
|
: x402Stub;
|
|
@@ -1260,10 +1269,10 @@ const x402Stub: X402Pay = {
|
|
|
1260
1269
|
throw new Error("ctx.x402: no pay rail configured. Pass \\\`x402\\\` to createShardDO().");
|
|
1261
1270
|
},
|
|
1262
1271
|
} as unknown as X402Pay;
|
|
1263
|
-
`}:{build:"",configField:"",contextField:"",imports:[],stub:""},
|
|
1272
|
+
`}:{build:"",configField:"",contextField:"",imports:[],stub:""},cr=(e,t,n,r)=>["AdvisorProcedure","AdvisoryFinding","DatabaseWriterLike","DataMigrationLike","ExportRow",...r?["FlagsResult"]:[],"ImportShardResult","KeyRange","MaskPoliciesResult","MigrationRunResult",...n?["QueuesResult"]:[],"RunShardApplyCdcArgs","RunShardExportArgs","RunShardImportArgs","RunShardMigrationArgs","RlsPoliciesResult","RunShardRankBeforeArgs","RunShardRankPageArgs","RunShardWriteArgs","RunShardWriteResult","SchedulerLike","TransactionHeadroomTracker","SchemaLike","ShardDOState","ShardRankPageResult","SqlExec","StorageRulesResult","StudioFeaturesResult","SystemReaderStorageLike","TelemetrySink",...t?["WorkflowsResult"]:[],...e?["WriteHook"]:[]],Cr=({advisories:e=[],advisorProcedures:t=[],agents:n=[],containers:r=[],env:a,flagKeys:o=[],hasAccessFacade:i=!1,hasAi:s=!1,hasAnalytics:l=!1,hasBrowser:u=!1,hasFlags:p=!1,hasHyperdrive:f=!1,hasImages:y=!1,hasKv:R=!1,hasNotify:d=!1,hasPayments:c=!1,hasPipelines:g=!1,hasR2sql:b=!1,hasX402:x=!1,maskMetadata:v,mutators:O=[],queues:N=[],rlsMetadata:$,schema:w,schemaSnapshot:E,shapes:ee=[],storageRules:F,studioFeatures:te,useUmbrella:ne=!1,workflows:B=[]})=>{const T=H(ne),z=O.length>0,A=ee.length>0,I=E===void 0?"":en(E),M=E===void 0?"":`
|
|
1264
1273
|
/** 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. */
|
|
1265
|
-
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(
|
|
1266
|
-
`,re=E===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:ae,configField:xe,contextField:ke,stub:ve}=
|
|
1274
|
+
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(tn(E))}, json: ${JSON.stringify(I)} };
|
|
1275
|
+
`,re=E===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:ae,configField:xe,contextField:ke,stub:ve}=Un(s),oe=Gn(i),K=Kn(R),P=Qn(p,T.flags),Q=Hn(o,p,T.flags),X=Jn(d),se=Vn(a),J=zn(l),j=Xn(y),W=Yn(f),U=Zn(u),q=er(b),Y=tr(g),{build:$e,contextField:fe,importLines:be,specs:ie}=ar(N),{build:Se,contextField:Re,importLines:ye,specs:le}=nr(r,w.jurisdiction),{build:Ne,contextField:Oe,importLines:we,specs:Te}=rr(B),{build:Ae,contextField:de,importLines:ce,specs:Le}=or(n),{build:Ce,configField:Ie,contextField:ue,imports:pe,stub:h}=lr(c),{build:De,configField:ut,imports:pt,stub:ht}=dr(x),gt=e,mt=t,ft=$??{policies:[],roles:[]},bt=v??{columns:[]},yt=F??{rules:[]},wt=te??{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:xt,override:kt}=sr(B),{constant:vt,override:$t}=ir(N),V=w.vectorIndexes.length>0,he=w.tables.some(L=>L.shardMode==="global"),_e=w.tables.some(L=>L.shardMode==="global"&&L.globalBackend==="hyperdrive"),We=w.tables.some(L=>L.shardMode==="global"&&L.globalBackend!=="hyperdrive"),G=w.tables.some(L=>L.externalSource!==void 0);if(We&&_e)throw new Z("INTERNAL",'lunora codegen: mixing `.global()` (D1) and `.global({ backend: "hyperdrive" })` tables in one app is not supported yet — use a single global backend.');const Pe=w.tables.length>0,St=Fn(w),Rt=qn(w),Nt=jn(w),Ot=Mn(w),Ue=Bn(w),Ke=cr(V,B.length>0,N.length>0,p);A&&Ke.push("WhereInput");const Qe=Wn(he),Tt=A?`
|
|
1267
1276
|
protected override resolveShape(name: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string } | undefined {
|
|
1268
1277
|
const shape = LUNORA_SHAPES[name];
|
|
1269
1278
|
|
|
@@ -1316,15 +1325,15 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
|
|
|
1316
1325
|
|
|
1317
1326
|
return { columns: shape.columns, effectiveWhere, global: isGlobal, table: shape.table };
|
|
1318
1327
|
}
|
|
1319
|
-
`:"",
|
|
1328
|
+
`:"",At=z?`
|
|
1320
1329
|
protected override isCustomMutator(functionPath: string): boolean {
|
|
1321
1330
|
return LUNORA_MUTATOR_PATHS.has(functionPath);
|
|
1322
1331
|
}
|
|
1323
|
-
`:"",
|
|
1324
|
-
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",
|
|
1325
|
-
d1?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1326
|
-
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1327
|
-
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",
|
|
1332
|
+
`:"",Lt=A?"\n/** Per-table RLS read policies (hoisted from `.use(rls(...))` chains) the shape resolver AND-merges into each `defineShape` predicate so partial replication honours read policies. */\nconst LUNORA_RLS_READ_REGISTRY = buildRlsReadRegistry(Object.values(LUNORA_FUNCTIONS));\n":"",Ct=A?"assertShapeShardable, ":"",ge=[`import type { ${Ke.join(", ")} } from "${T.do}";`,`import { applyCdcChanges, ${Ct}createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, ${G?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}runDataMigration, runShardMigrations, ${Qe.importFragment}ShardDO as ShardDOBase } from "${T.do}";`,...G?[`import type { ExternalSourceLike, SourceClientLike } from "${T.do}";`]:[],A?`import { asBucketStorage, buildRlsReadRegistry, composeShapeReadWhere, createSecrets, LunoraError } from "${T.server}";`:`import { asBucketStorage, createSecrets, LunoraError } from "${T.server}";`];Pe&&ge.push(`import { bindOrm, bindTableFacade } from "${T.server}";`),V&&ge.push('import type { SchemaLike as VectorSchemaLike, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectors, createVectorSyncHook } from "@lunora/bindings/vectors";'),s&&ge.push('import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'),ge.push(...oe.importLines,...K.importLines,...P.importLines,...X.importLines,...se.importLines,...J.importLines,...j.importLines,...W.importLines,...U.importLines,...q.importLines,...Y.importLines,...ye,...we,...be,...ce,...pe,...pt,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...z?["LUNORA_MUTATOR_PATHS"]:[],...A?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const It=V?`
|
|
1333
|
+
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",Dt=We?`
|
|
1334
|
+
d1?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",_t=_e?`
|
|
1335
|
+
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",Pt=G?`
|
|
1336
|
+
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",Et=he?'\nconst globalDbStub: DatabaseWriterLike = {\n aggregate: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n count: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n delete: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n findFirst: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n findFirstOrThrow: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n findMany: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n get: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n groupBy: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n insert: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n normalizeId: () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n patch: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n query: () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n rank: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n rankPage: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n replace: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n};\n':"",Ft=V?`
|
|
1328
1337
|
const vectorsStub: VectorSearchLike = {
|
|
1329
1338
|
deleteByIds: async () => {
|
|
1330
1339
|
throw new Error("ctx.vectors: no vectors configured. Pass \`vectors\` to createShardDO().");
|
|
@@ -1342,7 +1351,7 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1342
1351
|
throw new Error("ctx.vectors: no vectors configured. Pass \`vectors\` to createShardDO().");
|
|
1343
1352
|
},
|
|
1344
1353
|
};
|
|
1345
|
-
`:"",
|
|
1354
|
+
`:"",Mt=V?`
|
|
1346
1355
|
let vectors: VectorSearchLike;
|
|
1347
1356
|
let onWrite: WriteHook | undefined;
|
|
1348
1357
|
|
|
@@ -1355,9 +1364,9 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1355
1364
|
vectors = vectorsStub;
|
|
1356
1365
|
onWrite = undefined;
|
|
1357
1366
|
}
|
|
1358
|
-
`:"",
|
|
1359
|
-
globalDb,`:"",
|
|
1360
|
-
auth: { identity: identity ?? null, userId: userId ?? null },`,
|
|
1367
|
+
`:"",Je=he?`
|
|
1368
|
+
globalDb,`:"",Ve=`
|
|
1369
|
+
auth: { identity: identity ?? null, userId: userId ?? null },`,qt=V?`{${Ve}
|
|
1361
1370
|
broadcast: (delta) => {
|
|
1362
1371
|
this.recordChangedTable(delta.table, delta.indexKeys);
|
|
1363
1372
|
},
|
|
@@ -1371,8 +1380,8 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1371
1380
|
scheduler,
|
|
1372
1381
|
schema: schema as unknown as SchemaLike,
|
|
1373
1382
|
sql: this.sql as SqlExec,
|
|
1374
|
-
storage,${
|
|
1375
|
-
}`:`{${
|
|
1383
|
+
storage,${Je}
|
|
1384
|
+
}`:`{${Ve}
|
|
1376
1385
|
broadcast: (delta) => {
|
|
1377
1386
|
this.recordChangedTable(delta.table, delta.indexKeys);
|
|
1378
1387
|
},
|
|
@@ -1385,14 +1394,14 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1385
1394
|
scheduler,
|
|
1386
1395
|
schema: schema as unknown as SchemaLike,
|
|
1387
1396
|
sql: this.sql as SqlExec,
|
|
1388
|
-
storage,${
|
|
1389
|
-
}`,
|
|
1390
|
-
vectors,`:"",
|
|
1391
|
-
orm: bindOrm(facade),`:"",
|
|
1392
|
-
`:"",
|
|
1397
|
+
storage,${Je}
|
|
1398
|
+
}`,Bt=V?`
|
|
1399
|
+
vectors,`:"",jt=Pe?`
|
|
1400
|
+
orm: bindOrm(facade),`:"",Wt="",Ge=_e?"config.hyperdriveGlobal":"config.d1",Ut=he?` const globalDb: DatabaseWriterLike = ${Ge}?.(env, { identity, userId }) ?? globalDbStub;
|
|
1401
|
+
`:"",Kt=A&&he?`
|
|
1393
1402
|
protected override async readGlobalShapeRows(resolved: { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string }, identity?: { identity?: Record<string, unknown>; userId?: string }): Promise<Array<{ doc: Record<string, unknown>; id: string }>> {
|
|
1394
1403
|
const env = this.env as Record<string, unknown>;
|
|
1395
|
-
const globalDb: DatabaseWriterLike = ${
|
|
1404
|
+
const globalDb: DatabaseWriterLike = ${Ge}?.(env, identity) ?? globalDbStub;
|
|
1396
1405
|
const rows: Array<{ doc: Record<string, unknown>; id: string }> = [];
|
|
1397
1406
|
|
|
1398
1407
|
let cursor: null | string = null;
|
|
@@ -1419,10 +1428,10 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1419
1428
|
|
|
1420
1429
|
return rows;
|
|
1421
1430
|
}
|
|
1422
|
-
`:"",
|
|
1431
|
+
`:"",Qt=G?`
|
|
1423
1432
|
const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
|
|
1424
1433
|
const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
1425
|
-
`:"",
|
|
1434
|
+
`:"",Jt=G?`
|
|
1426
1435
|
protected override async pollExternalSources(): Promise<number | undefined> {
|
|
1427
1436
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1428
1437
|
const sourced = Object.entries((schema as unknown as SchemaLike).tables)
|
|
@@ -1523,7 +1532,7 @@ const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
|
1523
1532
|
|
|
1524
1533
|
return nextDueAt;
|
|
1525
1534
|
}
|
|
1526
|
-
`:"",
|
|
1535
|
+
`:"",He=Ue.length>0,Vt=G||He?`
|
|
1527
1536
|
public constructor(state: ShardDOState, env: unknown) {
|
|
1528
1537
|
super(state, env);
|
|
1529
1538
|
${G?`
|
|
@@ -1536,26 +1545,26 @@ ${G?`
|
|
|
1536
1545
|
if (autoSourced) {
|
|
1537
1546
|
void this.scheduleSourcePoll();
|
|
1538
1547
|
}
|
|
1539
|
-
`:""}${
|
|
1548
|
+
`:""}${He?`
|
|
1540
1549
|
if (LUNORA_TTL_SWEEPS.length > 0) {
|
|
1541
1550
|
void this.scheduleTtlSweep();
|
|
1542
1551
|
}
|
|
1543
1552
|
`:""} }
|
|
1544
|
-
`:"",
|
|
1553
|
+
`:"",Gt=Pe?`
|
|
1545
1554
|
const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
|
|
1546
|
-
${w.tables.map(
|
|
1555
|
+
${w.tables.map(L=>` facade[${JSON.stringify(L.name)}] = bindTableFacade(db, ${JSON.stringify(L.name)});`).join(`
|
|
1547
1556
|
`)}
|
|
1548
|
-
`:"",
|
|
1557
|
+
`:"",Ht=`${oe.build}${K.build}${P.build}${J.build}${se.build}
|
|
1549
1558
|
const secrets = createSecrets(env);
|
|
1550
|
-
`,
|
|
1551
|
-
secrets,`,
|
|
1559
|
+
`,zt=`${oe.contextField}${K.contextField}${P.contextField}${X.contextField}${J.contextField}${se.contextField}
|
|
1560
|
+
secrets,`,Xt=X.build,ze=y||f||u||b||g||x,Yt=ze?`
|
|
1552
1561
|
// ActionCtx-only helpers (external, non-deterministic I/O): constructed
|
|
1553
1562
|
// and attached only for an \`action\` so query/mutation ctx never carry them.
|
|
1554
1563
|
if (isAction) {
|
|
1555
|
-
${j.build}${W.build}${U.build}${q.build}${Y.build}${
|
|
1564
|
+
${j.build}${W.build}${U.build}${q.build}${Y.build}${De}${[...y?[" ctx.images = images;"]:[],...f?[" ctx.sql = sql;"]:[],...u?[" ctx.browser = browser;"]:[],...b?[" ctx.r2sql = r2sql;"]:[],...g?[" ctx.pipelines = pipelines;"]:[],...x?[" ctx.x402 = x402;"]:[]].join(`
|
|
1556
1565
|
`)}
|
|
1557
1566
|
}
|
|
1558
|
-
`:"",
|
|
1567
|
+
`:"",Zt=ze?` const isAction = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind === "action";
|
|
1559
1568
|
`:"";return`${k}${ge.join(`
|
|
1560
1569
|
`)}
|
|
1561
1570
|
|
|
@@ -1566,45 +1575,45 @@ interface FunctionReference {
|
|
|
1566
1575
|
}
|
|
1567
1576
|
|
|
1568
1577
|
/** Foreign-key columns per table (\`v.id("target")\` fields) for the data browser. */
|
|
1569
|
-
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(
|
|
1578
|
+
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(St,void 0,4)};
|
|
1570
1579
|
|
|
1571
1580
|
/** Declared indexes per table (secondary, search, geo, rank, vector) for the schema viewer. */
|
|
1572
|
-
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(
|
|
1581
|
+
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(Rt,void 0,4)};
|
|
1573
1582
|
|
|
1574
1583
|
/** Columns per table (typed, with PK/FK markers) for the studio's schema diagram, served via \`__lunora_admin__:describeTable\`. */
|
|
1575
|
-
const LUNORA_TABLE_COLUMNS: Record<string, Array<{ isStorage?: boolean; name: string; optional: boolean; pk?: boolean; ref?: string; type: string }>> = ${JSON.stringify(
|
|
1584
|
+
const LUNORA_TABLE_COLUMNS: Record<string, Array<{ isStorage?: boolean; name: string; optional: boolean; pk?: boolean; ref?: string; type: string }>> = ${JSON.stringify(Nt,void 0,4)};
|
|
1576
1585
|
|
|
1577
1586
|
/** Storage-key columns per table (\`v.storage(...)\` fields) for the file browser's records↔files join. */
|
|
1578
|
-
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(
|
|
1587
|
+
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(Ot,void 0,4)};
|
|
1579
1588
|
|
|
1580
1589
|
/** Declarative TTL policies (\`.ttl(field, { after? })\`) the DO alarm sweep auto-expires rows for. */
|
|
1581
|
-
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(
|
|
1590
|
+
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(Ue,void 0,4)};
|
|
1582
1591
|
|
|
1583
1592
|
/** Static schema advisories (computed by @lunora/advisor at codegen time) served via \`__lunora_admin__:getAdvisories\`. */
|
|
1584
|
-
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(
|
|
1593
|
+
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(gt,void 0,4)};
|
|
1585
1594
|
|
|
1586
1595
|
/** Every declared procedure (discovered by @lunora/codegen) served via \`__lunora_admin__:getAdvisorProcedures\` — the health map's denominator. */
|
|
1587
|
-
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(
|
|
1596
|
+
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(mt,void 0,4)};
|
|
1588
1597
|
|
|
1589
1598
|
/** Read-only RLS metadata (policies + roles discovered from \`.use(rls(...))\` chains) served via \`__lunora_admin__:rlsPolicies\` for the studio's RLS inspector. */
|
|
1590
|
-
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(
|
|
1599
|
+
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(ft,void 0,4)};
|
|
1591
1600
|
|
|
1592
1601
|
/** 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. */
|
|
1593
|
-
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(
|
|
1602
|
+
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(bt,void 0,4)};
|
|
1594
1603
|
|
|
1595
1604
|
/** Read-only storage access-rule metadata (discovered from \`.use(storageRules(...))\` chains) served via \`__lunora_admin__:storageRules\` for the studio's access-rules view. */
|
|
1596
|
-
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(
|
|
1605
|
+
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(yt,void 0,4)};
|
|
1597
1606
|
|
|
1598
1607
|
/** 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. */
|
|
1599
|
-
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(
|
|
1600
|
-
${M}${Q.constant}${
|
|
1608
|
+
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(wt,void 0,4)};
|
|
1609
|
+
${M}${Q.constant}${Lt}${xt}${vt}${le}${Te}${ie}${Le}
|
|
1601
1610
|
export interface ShardDOConfig {
|
|
1602
1611
|
/** Opt into change-data-capture: records a post-image to \`__cdc_log\` on every write (backs streaming export + replay-PITR). */
|
|
1603
1612
|
cdc?: boolean;
|
|
1604
1613
|
/** Optional telemetry sink. When supplied, each \`ctx.log.*\` call is forwarded to \`sink.onLog\`. Pass the SAME sink you give \`createWorker({ observability })\` (which drives \`onRpc\`) to route both RPC and log events. */
|
|
1605
1614
|
observability?: (env: Record<string, unknown>) => TelemetrySink | undefined;
|
|
1606
1615
|
scheduler?: (env: Record<string, unknown>) => unknown;
|
|
1607
|
-
storage?: (env: Record<string, unknown>) => unknown;${
|
|
1616
|
+
storage?: (env: Record<string, unknown>) => unknown;${It}${xe}${K.configField}${P.configField}${J.configField}${j.configField}${W.configField}${U.configField}${q.configField}${Y.configField}${Ie}${ut}${Dt}${_t}${Pt}
|
|
1608
1617
|
}
|
|
1609
1618
|
|
|
1610
1619
|
const schedulerStub = {
|
|
@@ -1642,7 +1651,7 @@ const storageStub = {
|
|
|
1642
1651
|
throw new Error("ctx.storage: no storage configured. Pass \`storage\` to createShardDO().");
|
|
1643
1652
|
},
|
|
1644
1653
|
};
|
|
1645
|
-
${
|
|
1654
|
+
${Et}${Qt}${Ft}${ve}${K.stub}${P.stub}${J.stub}${j.stub}${W.stub}${U.stub}${q.stub}${Y.stub}${h}${ht}${Wt}
|
|
1646
1655
|
// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
|
|
1647
1656
|
// referencing call fails loudly with a clear error instead of overflowing the
|
|
1648
1657
|
// stack. Tracked across the awaited handler chain (one DO invocation is
|
|
@@ -1679,7 +1688,7 @@ const dispatchRun = async (expected: FunctionKind, functionPath: string, args: R
|
|
|
1679
1688
|
* from the worker entry so wrangler binds it by name.
|
|
1680
1689
|
*/
|
|
1681
1690
|
export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOState, env: unknown) => ShardDOBase =>
|
|
1682
|
-
class extends ShardDOBase {${
|
|
1691
|
+
class extends ShardDOBase {${Vt}
|
|
1683
1692
|
private migrated = false;
|
|
1684
1693
|
|
|
1685
1694
|
public override async handleRpc(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
@@ -1722,7 +1731,7 @@ export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOSt
|
|
|
1722
1731
|
|
|
1723
1732
|
return registered.handler(ctx, args);
|
|
1724
1733
|
}
|
|
1725
|
-
${
|
|
1734
|
+
${Qe.override}
|
|
1726
1735
|
protected override async executeSubscription(functionPath: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): Promise<{ ranges?: Map<string, KeyRange[]>; result: unknown; tables: Set<string> } | null> {
|
|
1727
1736
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
1728
1737
|
|
|
@@ -1757,7 +1766,7 @@ ${Ke.override}
|
|
|
1757
1766
|
iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath }), args, signal),
|
|
1758
1767
|
};
|
|
1759
1768
|
}
|
|
1760
|
-
${
|
|
1769
|
+
${At}${Tt}${Kt}${Jt}
|
|
1761
1770
|
protected override lifecycleHookPaths(event: "connect" | "disconnect"): readonly string[] {
|
|
1762
1771
|
return LUNORA_LIFECYCLE_HOOKS[event];
|
|
1763
1772
|
}
|
|
@@ -1797,7 +1806,7 @@ ${Rt}${St}${Bt}${Wt}
|
|
|
1797
1806
|
protected override studioFeatures(): StudioFeaturesResult {
|
|
1798
1807
|
return LUNORA_STUDIO_FEATURES;
|
|
1799
1808
|
}
|
|
1800
|
-
${Q.evaluateOverride}${Q.subscriptionOverride}${
|
|
1809
|
+
${Q.evaluateOverride}${Q.subscriptionOverride}${kt}${$t}
|
|
1801
1810
|
protected override advisories(): AdvisoryFinding[] {
|
|
1802
1811
|
return LUNORA_ADVISORIES;
|
|
1803
1812
|
}
|
|
@@ -1893,6 +1902,70 @@ ${Q.evaluateOverride}${Q.subscriptionOverride}${bt}${wt}
|
|
|
1893
1902
|
return { id: args.id ?? null, op: "patch" };
|
|
1894
1903
|
}
|
|
1895
1904
|
|
|
1905
|
+
// The base \`ShardDO\` cannot build a schema-aware writer, so its
|
|
1906
|
+
// \`runShardExport\`/\`runShardImport\` return \`[]\` and \`{inserted:{}}\`.
|
|
1907
|
+
// Those are success-shaped: an empty export is what a correct export of
|
|
1908
|
+
// an empty shard looks like, so a backup of a populated sharded schema
|
|
1909
|
+
// reported success and wrote nothing, and an import reported success and
|
|
1910
|
+
// dropped every row. Overriding both here is what makes the two admin
|
|
1911
|
+
// RPCs real for a \`.shardBy()\` table.
|
|
1912
|
+
//
|
|
1913
|
+
// NOTE: the admin export RPC is not paginated — \`parseExportShardArgs\`
|
|
1914
|
+
// takes \`tables\`/\`batchSize\` but no cursor, and the coordinator issues
|
|
1915
|
+
// one call per shard — so the rows are collected into a single response.
|
|
1916
|
+
// \`batchSize\` bounds the SQLite scan page, not the reply. A shard holding
|
|
1917
|
+
// more rows than fit in the DO's memory budget will therefore fail the
|
|
1918
|
+
// export rather than stream it. That is a loud failure where the bug this
|
|
1919
|
+
// replaces was a silent empty one, but a cursor on the RPC is what makes
|
|
1920
|
+
// this a complete backup path for large shards.
|
|
1921
|
+
protected override async runShardExport(args: RunShardExportArgs): Promise<ExportRow[]> {
|
|
1922
|
+
this.ensureMigrated();
|
|
1923
|
+
|
|
1924
|
+
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1925
|
+
const scheduler = (config.scheduler?.(env) ?? schedulerStub) as SchedulerLike;
|
|
1926
|
+
const writer = createShardCtxDb({
|
|
1927
|
+
broadcast: (delta) => {
|
|
1928
|
+
this.recordChangedTable(delta.table, delta.indexKeys);
|
|
1929
|
+
},
|
|
1930
|
+
cdc: config.cdc ?? false,
|
|
1931
|
+
scheduler,
|
|
1932
|
+
schema: schema as unknown as SchemaLike,
|
|
1933
|
+
sql: this.sql as SqlExec,
|
|
1934
|
+
});
|
|
1935
|
+
|
|
1936
|
+
const rows: ExportRow[] = [];
|
|
1937
|
+
|
|
1938
|
+
// \`exportShardRows\` walks in keyset batches so a large table does not
|
|
1939
|
+
// materialize at once inside the generator; the admin RPC's response
|
|
1940
|
+
// is a single array, so it is collected here rather than streamed.
|
|
1941
|
+
for await (const row of exportShardRows(writer, schema as unknown as SchemaLike, { batchSize: args.batchSize, tables: args.tables })) {
|
|
1942
|
+
rows.push(row);
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
return rows;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
protected override async runShardImport(args: RunShardImportArgs): Promise<ImportShardResult> {
|
|
1949
|
+
this.ensureMigrated();
|
|
1950
|
+
|
|
1951
|
+
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1952
|
+
const scheduler = (config.scheduler?.(env) ?? schedulerStub) as SchedulerLike;
|
|
1953
|
+
const writer = createShardCtxDb({
|
|
1954
|
+
broadcast: (delta) => {
|
|
1955
|
+
this.recordChangedTable(delta.table, delta.indexKeys);
|
|
1956
|
+
},
|
|
1957
|
+
cdc: config.cdc ?? false,
|
|
1958
|
+
scheduler,
|
|
1959
|
+
schema: schema as unknown as SchemaLike,
|
|
1960
|
+
sql: this.sql as SqlExec,
|
|
1961
|
+
});
|
|
1962
|
+
|
|
1963
|
+
// \`importShardRows\` inserts with \`allowExplicitId\`, so a source
|
|
1964
|
+
// database's \`_id\`s carry across verbatim and every foreign key
|
|
1965
|
+
// referencing them stays valid without a second remapping pass.
|
|
1966
|
+
return importShardRows(writer, schema as unknown as SchemaLike, { rows: args.rows, startLine: args.startLine });
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1896
1969
|
protected override async deleteRowThroughWriter(table: string, id: string): Promise<void> {
|
|
1897
1970
|
const definition = (schema as unknown as SchemaLike).tables[table];
|
|
1898
1971
|
|
|
@@ -2023,7 +2096,7 @@ ${Q.evaluateOverride}${Q.subscriptionOverride}${bt}${wt}
|
|
|
2023
2096
|
// dispatch path) fall back to the per-request fields as before.
|
|
2024
2097
|
const userId = options.identity ? options.identity.userId : this.getCurrentUserId();
|
|
2025
2098
|
const identity = options.identity ? options.identity.identity : this.getCurrentIdentity();
|
|
2026
|
-
${
|
|
2099
|
+
${Mt}${ae}${Ht}${Se}${Ne}${$e}${Ae}
|
|
2027
2100
|
const scheduler = (config.scheduler?.(env) ?? schedulerStub) as SchedulerLike;
|
|
2028
2101
|
// Build the storage adapter once and share it between \`ctx.storage\`
|
|
2029
2102
|
// and \`ctx.db.system._storage\` so both read the same R2 binding. The
|
|
@@ -2050,13 +2123,13 @@ ${It}${ae}${Qt}${Se}${Ne}${$e}${Ae}
|
|
|
2050
2123
|
// so both write to the same trace.
|
|
2051
2124
|
const span = this.makeDispatchSpan(traceAnchor, observability);
|
|
2052
2125
|
|
|
2053
|
-
${
|
|
2126
|
+
${Ut} // \`ctx.db\`, wrapped in automatic instrumentation: by default this
|
|
2054
2127
|
// adds aggregate counters (call count, total time, per-operation
|
|
2055
2128
|
// breakdown) to the wide event rather than a span per call, so a
|
|
2056
2129
|
// handler making hundreds of queries stays readable. See
|
|
2057
2130
|
// \`instrumentDatabase\` for the \`"spans"\` / \`"off"\` levels.
|
|
2058
|
-
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${
|
|
2059
|
-
${
|
|
2131
|
+
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${qt}), logFunctionPath, traceAnchor, observability);
|
|
2132
|
+
${Gt}${Ce}
|
|
2060
2133
|
|
|
2061
2134
|
// \`ctx.trace\` / \`ctx.metrics\`: spans and measurements to the same sink.
|
|
2062
2135
|
// The trace anchor is threaded explicitly for the same reason \`identity\`
|
|
@@ -2064,7 +2137,7 @@ ${Kt}${Ce}
|
|
|
2064
2137
|
// writing mutation's trace from the shared per-request field.
|
|
2065
2138
|
const trace = this.makeTracer(logFunctionPath, observability, traceAnchor);
|
|
2066
2139
|
const metrics = this.makeMetrics(logFunctionPath, observability);
|
|
2067
|
-
${
|
|
2140
|
+
${Xt}
|
|
2068
2141
|
// \`ctx.now\`: the wall-clock instant (epoch ms) this function began,
|
|
2069
2142
|
// captured ONCE so the whole handler body sees a single stable value.
|
|
2070
2143
|
// Query/mutation handlers must be deterministic (they may be re-run on
|
|
@@ -2087,13 +2160,13 @@ ${Vt}
|
|
|
2087
2160
|
ip: this.getCurrentIp(),
|
|
2088
2161
|
log,
|
|
2089
2162
|
metrics,
|
|
2090
|
-
now,${
|
|
2163
|
+
now,${jt}
|
|
2091
2164
|
scheduler,
|
|
2092
2165
|
span,
|
|
2093
2166
|
storage,
|
|
2094
|
-
trace,${
|
|
2167
|
+
trace,${Bt}${ke}${zt}${ue}${Re}${Oe}${fe}${de}
|
|
2095
2168
|
};
|
|
2096
|
-
${
|
|
2169
|
+
${Zt}${Yt}
|
|
2097
2170
|
ctx.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, ctx);
|
|
2098
2171
|
ctx.runMutation = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("mutation", reference.__lunoraRef, fnArgs, ctx);
|
|
2099
2172
|
ctx.runQuery = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("query", reference.__lunoraRef, fnArgs, ctx);
|
|
@@ -2101,28 +2174,28 @@ ${Ht}${Gt}
|
|
|
2101
2174
|
return ctx;
|
|
2102
2175
|
}
|
|
2103
2176
|
};
|
|
2104
|
-
`},
|
|
2177
|
+
`},je=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:C(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"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?je(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},ct=(e,t)=>{const n=e.kind==="optional"&&e.inner?e.inner:e;return n.kind==="id"&&n.tableName!==void 0&&t.has(n.tableName)?n.tableName:void 0},ur=(e,t,n)=>{m(e,"drizzle column name");const r=je(t),a=r.mode?`, { mode: "${r.mode}" }`:"";let o=`${r.builder}("${e}"${a})`;r.typeAnnotation&&(o+=`.$type<${r.typeAnnotation}>()`);const i=ct(t,n);return i!==void 0&&(o+=`.references((): AnySQLiteColumn => ${i}._id)`),r.notNull&&(o+=".notNull()"),o},pr=e=>{m(e.name,"drizzle index name");const t=e.unique?"uniqueIndex":"index",n=e.fields.map(r=>(m(r,"drizzle index field"),`t.${r}`)).join(", ");return` ${e.name}: ${t}("${e.name}").on(${n}),`},hr=(e,t)=>{m(e.name,"table name");const n=[' _id: text("_id").primaryKey(),',' _creationTime: integer("_creationTime").notNull(),',...Object.entries(e.shape).map(([a,o])=>` ${a}: ${ur(a,o,t)},`)].join(`
|
|
2105
2178
|
`),r=e.indexes.length>0?`, (t) => ({
|
|
2106
|
-
${e.indexes.map(a=>
|
|
2179
|
+
${e.indexes.map(a=>pr(a)).join(`
|
|
2107
2180
|
`)}
|
|
2108
2181
|
})`:"";return`export const ${e.name} = sqliteTable("${e.name}", {
|
|
2109
2182
|
${n}
|
|
2110
|
-
}${r});`},
|
|
2111
|
-
`;const n=H(t),r=new Set(e.map(f=>f.name)),{columns:a,indexes:o,needsAnyColumn:
|
|
2183
|
+
}${r});`},gr=e=>e.typeAnnotation?.includes('Id<"')??!1,mr=(e,t)=>{const n=new Set(["integer","sqliteTable","text"]),r=new Set;let a=!1,o=!1;for(const i of e){for(const s of Object.values(i.shape)){const l=je(s);n.add(l.builder),o=o||gr(l),a=a||ct(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:a,needsId:o}},Ye=(e,t=!1)=>{if(e.length===0)return`${k}export {};
|
|
2184
|
+
`;const n=H(t),r=new Set(e.map(f=>f.name)),{columns:a,indexes:o,needsAnyColumn:i,needsId:s}=mr(e,r),l=[...o,...a].toSorted((f,y)=>f.localeCompare(y)),u=e.map(f=>hr(f,r)).join(`
|
|
2112
2185
|
|
|
2113
|
-
`),p=[
|
|
2114
|
-
`:"",
|
|
2186
|
+
`),p=[i?`import type { AnySQLiteColumn } from "${n.serverDrizzle}";
|
|
2187
|
+
`:"",s?`import type { Id } from "./dataModel.js";
|
|
2115
2188
|
`:""].join("");return`${k}import { ${l.join(", ")} } from "${n.serverDrizzle}";
|
|
2116
2189
|
${p}
|
|
2117
2190
|
${u}
|
|
2118
|
-
`},
|
|
2191
|
+
`},Ir=(e,t=!1)=>{const n=e.tables.filter(a=>a.shardMode==="global"),r=e.tables.filter(a=>a.shardMode!=="global");return{global:Ye(n,t),shard:Ye(r,t)}},Dr=e=>{const t=[],n=new Map;for(const s of e){const l=n.get(s.cron);l?l.push(s):(n.set(s.cron,[s]),t.push(s.cron))}const r=t.map(s=>` ${JSON.stringify(s)},`).join(`
|
|
2119
2192
|
`),a=r.length>0?`
|
|
2120
2193
|
${r}
|
|
2121
|
-
`:"",o=[...n.entries()].map(([
|
|
2122
|
-
`);return` ${JSON.stringify(
|
|
2194
|
+
`:"",o=[...n.entries()].map(([s,l])=>{const u=l.map(p=>{const f=p.workflow?`workflow: ${JSON.stringify(p.workflow.binding)}`:`functionPath: ${JSON.stringify(p.functionPath)}`;return` { name: ${JSON.stringify(p.name)}, ${f}, args: ${JSON.stringify(p.args)} },`}).join(`
|
|
2195
|
+
`);return` ${JSON.stringify(s)}: [
|
|
2123
2196
|
${u}
|
|
2124
2197
|
],`}).join(`
|
|
2125
|
-
`),
|
|
2198
|
+
`),i=o.length>0?`
|
|
2126
2199
|
${o}
|
|
2127
2200
|
`:"";return`${k}/**
|
|
2128
2201
|
* One scheduled cron invocation. Exactly one target is set: \`functionPath\` is
|
|
@@ -2148,8 +2221,8 @@ export const LUNORA_CRON_TRIGGERS: ReadonlyArray<string> = [${a}];
|
|
|
2148
2221
|
* Dispatcher map keyed by cron expression. The Worker's \`scheduled()\` handler
|
|
2149
2222
|
* looks up \`event.cron\` here and dispatches every job in the list.
|
|
2150
2223
|
*/
|
|
2151
|
-
export const LUNORA_CRONS: Record<string, ReadonlyArray<LunoraCronJob>> = {${
|
|
2152
|
-
`},
|
|
2224
|
+
export const LUNORA_CRONS: Record<string, ReadonlyArray<LunoraCronJob>> = {${i}};
|
|
2225
|
+
`},_r=e=>{const t=[...e].toSorted((r,a)=>r.name.localeCompare(a.name)).map(r=>{const a=[`name: ${JSON.stringify(r.name)}`,`table: ${JSON.stringify(r.table)}`];return r.field!==void 0&&a.push(`field: ${JSON.stringify(r.field)}`),r.dimensions!==void 0&&a.push(`dimensions: ${JSON.stringify(r.dimensions)}`),r.metric!==void 0&&a.push(`metric: ${JSON.stringify(r.metric)}`),r.metadata!==void 0&&a.push(`metadata: ${JSON.stringify(r.metadata)}`),` { ${a.join(", ")} },`}).join(`
|
|
2153
2226
|
`),n=t.length>0?`
|
|
2154
2227
|
${t}
|
|
2155
2228
|
`:"";return`${k}/**
|
|
@@ -2173,4 +2246,4 @@ export interface LunoraVectorIndex {
|
|
|
2173
2246
|
* \`createWorker({ vectorIntrospector })\` to back the studio's vector browser.
|
|
2174
2247
|
*/
|
|
2175
2248
|
export const LUNORA_VECTOR_INDEXES: ReadonlyArray<LunoraVectorIndex> = [${n}];
|
|
2176
|
-
`},
|
|
2249
|
+
`},Pr=e=>{const t=new Set,n=[];for(const r of e)t.has(r.cron)||(t.add(r.cron),n.push(r.cron));return n};export{Nr as L,Rr as O,Sr as S,Or as X,Tr as Z,Mn as a,Dr as b,Cr as d,Ar as e,Ir as f,vr as k,xr as n,nn as r,kr as s,Lr as t,$r as v,k as w,Pr as x,_r as y};
|