@lunora/codegen 1.0.0-alpha.154 → 1.0.0-alpha.155
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 +29 -4
- package/dist/index.d.ts +29 -4
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/{GENERATED_HEADER-w7DB5GZI.mjs → GENERATED_HEADER-_apO4IVc.mjs} +1 -1
- package/dist/packem_shared/{OPENRPC_VERSION-BAgBIsQM.mjs → OPENRPC_VERSION-DWdTwXvO.mjs} +1 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-B9OxLwqq.mjs +9 -0
- package/dist/packem_shared/{buildOpenApiDocument-ZdoDQXmt.mjs → buildOpenApiDocument-DIboMAh6.mjs} +1 -1
- package/dist/packem_shared/{discoverSchema-D5XGH2wu.mjs → discoverSchema-C4znXEB-.mjs} +1 -1
- package/dist/packem_shared/{emit-Dsr5DNpc.mjs → emit-B6ud4F_z.mjs} +225 -225
- package/dist/packem_shared/{emitApp-kFg_xYlc.mjs → emitApp-BSxrIa6e.mjs} +29 -29
- package/package.json +10 -10
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-S3Ey8df4.mjs +0 -9
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{agentComponent as dt}from"@lunora/agent/component";import{LunoraError as
|
|
1
|
+
import{agentComponent as dt}from"@lunora/agent/component";import{LunoraError as X}from"@lunora/errors";import{serializeSchemaSnapshot as vn,hashSchemaSnapshot as Rn}from"./SCHEMA_SNAPSHOT_VERSION-CWESEYLi.mjs";import{s as T}from"./paths-C-9fwEgQ.mjs";const ut=[{contextProperty:"access",key:"access",moduleSpecifier:"@lunora/cloudflare-access"},{appMethod:{configKey:"ai",doc:"Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`).",method:"ai"},contextProperty:"ai",key:"ai",moduleSpecifier:"@lunora/ai"},{appMethod:{configKey:"analytics",doc:"Override the Analytics Engine dataset backing `ctx.analytics` (defaults to `env.ANALYTICS`).",method:"analytics"},contextProperty:"analytics",key:"analytics",moduleSpecifier:"@lunora/bindings/analytics",serverCtxField:{field:`
|
|
2
2
|
/** Analytics Engine telemetry sink. Fire-and-forget and sampled; do not read it back in-handler. */
|
|
3
3
|
readonly analytics: import("@lunora/bindings/analytics").AnalyticsClient;`,tier:"every"}},{appMethod:{configKey:"browser",doc:"Override the Browser Rendering binding backing `ctx.browser` (defaults to `env.BROWSER`).",method:"browser"},contextProperty:"browser",key:"browser",moduleSpecifier:"@lunora/browser",serverCtxField:{field:`
|
|
4
4
|
/** Browser Rendering (screenshots/PDF/scrape). Non-deterministic — available only in actions. */
|
|
@@ -15,61 +15,61 @@ import{agentComponent as dt}from"@lunora/agent/component";import{LunoraError as
|
|
|
15
15
|
/**
|
|
16
16
|
* R2 SQL over Apache Iceberg tables (window functions, DISTINCT, set operations). Non-deterministic — available only in actions. Reads here are NOT tracked by Lunora live queries.
|
|
17
17
|
*/
|
|
18
|
-
readonly r2sql: import("@lunora/bindings/r2sql").R2SqlClient;`,tier:"action"}},{contextProperty:"scheduler",key:"scheduler",moduleSpecifier:"@lunora/scheduler"},{contextProperty:"storage",key:"storage",moduleSpecifier:"@lunora/storage"},{appMethod:{configKey:"vectors",doc:"Wire the Vectorize index map backing `ctx.vectors`.",method:"vectors"},contextProperty:"vectors",key:"vectors",moduleSpecifier:"@lunora/bindings/vectors"},{contextProperty:"workflows",key:"workflows",moduleSpecifier:"@lunora/workflow"}],
|
|
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"}],Sn=ut,$n=new Map(Sn.flatMap(e=>e.serverCtxField?[[e.key,e.serverCtxField]]:[])),to=ut.flatMap(e=>"appMethod"in e?[{appMethod:e.appMethod,key:e.key}]:[]),pt=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,Tn=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),ht=e=>e.column!==void 0,Nn=(e,t)=>{switch(e){case"bigint":return`if (typeof ${t} !== "bigint") return DEFER;
|
|
19
19
|
`;case"boolean":return`if (typeof ${t} !== "boolean") return DEFER;
|
|
20
20
|
`;case"date":case"number":case"timestamp":return`if (typeof ${t} !== "number" || !Number.isFinite(${t})) return DEFER;
|
|
21
21
|
`;case"null":return`if (${t} !== null) return DEFER;
|
|
22
22
|
`;default:return`if (typeof ${t} !== "string") return DEFER;
|
|
23
|
-
`}},
|
|
24
|
-
`,
|
|
25
|
-
`}},Ge=(e,t,n)=>{if(!ht(e)&&!(e.unmodelledRefinement||e.sourceText!==void 0)){if(
|
|
23
|
+
`}},An=(e,t)=>e.stringMaxLength===void 0?"":`if (${t}.length > ${String(e.stringMaxLength)}) return DEFER;
|
|
24
|
+
`,On=(e,t)=>{const n=e.literalValue?.trim();if(!(n===void 0||!pt.test(n)))return{out:t,pre:`if (${t} !== ${n}) return DEFER;
|
|
25
|
+
`}},Ge=(e,t,n)=>{if(!ht(e)&&!(e.unmodelledRefinement||e.sourceText!==void 0)){if(Tn.has(e.kind))return e.kind==="any"?{out:t,pre:""}:{out:t,pre:Nn(e.kind,t)+An(e,t)};switch(e.kind){case"array":return In(e,t,n);case"literal":return On(e,t);case"object":return En(e,t,n);default:return}}},In=(e,t,n)=>{const{inner:r}=e;if(!r)return;const o=n.next(),s=`__arr${String(o)}`,i=`__i${String(o)}`,a=`__e${String(o)}`,c=Ge(r,a,n);if(!c)return;const d=`if (!Array.isArray(${t})) return DEFER;
|
|
26
26
|
const ${s} = new Array(${t}.length);
|
|
27
27
|
for (let ${i} = 0; ${i} < ${t}.length; ${i}++) {
|
|
28
28
|
const ${a} = ${t}[${i}];
|
|
29
29
|
${c.pre}${s}[${i}] = ${c.out};
|
|
30
30
|
}
|
|
31
|
-
`;return{out:s,pre:d}},
|
|
31
|
+
`;return{out:s,pre:d}},Cn=(e,t,n,r)=>{const o=JSON.stringify(e);if(t.kind==="optional"){if(t.hasRefinement||t.sourceText!==void 0||ht(t))return;const{inner:i}=t;if(!i)return;const a=Ge(i,n,r);if(!a)return;const c=r.next(),d=`__has${String(c)}`,p=`__val${String(c)}`,m=`let ${d} = false;
|
|
32
32
|
let ${p};
|
|
33
33
|
if (${n} !== undefined) {
|
|
34
34
|
${a.pre}${p} = ${a.out};
|
|
35
35
|
${d} = true;
|
|
36
36
|
}
|
|
37
|
-
`;return{entry:`...(${d} ? { ${o}: ${p} } : {})`,pre:m}}const s=Ge(t,n,r);if(s)return{entry:`${o}: ${s.out}`,pre:s.pre}},
|
|
38
|
-
`,c=p}const d=
|
|
39
|
-
`},
|
|
37
|
+
`;return{entry:`...(${d} ? { ${o}: ${p} } : {})`,pre:m}}const s=Ge(t,n,r);if(s)return{entry:`${o}: ${s.out}`,pre:s.pre}},Ln=new Set(Object.getOwnPropertyNames(Object.prototype)),mt=(e,t,n)=>{let r="";const o=[];for(const s of Object.keys(e)){const i=e[s];if(!i)return;const a=JSON.stringify(s);let c=`${t}[${a}]`;if(Ln.has(s)){const p=`__f${String(n.next())}`;r+=`const ${p} = Object.hasOwn(${t}, ${a}) ? ${t}[${a}] : undefined;
|
|
38
|
+
`,c=p}const d=Cn(s,i,c,n);if(!d)return;r+=d.pre,o.push(d.entry)}return{entries:o.join(", "),pre:r}},gt=e=>{const t=`Object.getPrototypeOf(${e})`;return`if (${t} !== Object.prototype && ${t} !== null) return DEFER;
|
|
39
|
+
`},En=(e,t,n)=>{const r=e.shape??{},o=mt(r,t,n);if(!o)return;const s=n.next(),i=`__obj${String(s)}`,a=`if (typeof ${t} !== "object" || ${t} === null || Array.isArray(${t})) return DEFER;
|
|
40
40
|
${gt(t)}${o.pre}const ${i} = { ${o.entries} };
|
|
41
|
-
`;return{out:i,pre:a}},
|
|
41
|
+
`;return{out:i,pre:a}},_n=e=>{let t=0;const r=mt(e,"source",{next:()=>(t+=1,t)});if(r)return`(source) => {
|
|
42
42
|
if (typeof source !== "object" || source === null || Array.isArray(source)) return DEFER;
|
|
43
43
|
${gt("source")}${r.pre}return { ${r.entries} };
|
|
44
|
-
}`}
|
|
44
|
+
}`},$=`// GENERATED by @lunora/codegen — do not edit.
|
|
45
45
|
// Run \`lunora codegen\` to regenerate.
|
|
46
46
|
|
|
47
|
-
`,ae=(e=!1)=>e?{client:"lunorash/client",do:"lunorash/do",flags:"lunorash/flags",server:"lunorash/server",serverDataModel:"lunorash/server/data-model",serverDrizzle:"lunorash/server/drizzle",serverTypes:"lunorash/server/types",values:"lunorash/values"}:{client:"@lunora/client",do:"@lunora/do",flags:"@lunora/flags",server:"@lunora/server",serverDataModel:"@lunora/server/data-model",serverDrizzle:"@lunora/server/drizzle",serverTypes:"@lunora/server/types",values:"@lunora/values"},ft=/^[A-Za-z_$][\w$]*$/u,
|
|
47
|
+
`,ae=(e=!1)=>e?{client:"lunorash/client",do:"lunorash/do",flags:"lunorash/flags",server:"lunorash/server",serverDataModel:"lunorash/server/data-model",serverDrizzle:"lunorash/server/drizzle",serverTypes:"lunorash/server/types",values:"lunorash/values"}:{client:"@lunora/client",do:"@lunora/do",flags:"@lunora/flags",server:"@lunora/server",serverDataModel:"@lunora/server/data-model",serverDrizzle:"@lunora/server/drizzle",serverTypes:"@lunora/server/types",values:"@lunora/values"},ft=/^[A-Za-z_$][\w$]*$/u,Dn=/^[\w./-]+$/u,f=(e,t)=>{if(!ft.test(e))throw new X("INTERNAL",`@lunora/codegen: ${t} is not a valid JS identifier: ${JSON.stringify(e)}`)},He=e=>e.charAt(0).toUpperCase()+e.slice(1),q=e=>ft.test(e)?e:JSON.stringify(e),Y=e=>e==="__proto__"?`[${JSON.stringify(e)}]`:q(e),Pn={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"},Mn=e=>{if(e===void 0)return"unknown";if(!pt.test(e))throw new X("INTERNAL",`@lunora/codegen: v.literal() argument is not a parseable string/number/boolean/null literal: ${JSON.stringify(e)}`);return e},O=e=>{const t=Pn[e.kind];if(t!==void 0)return t;switch(e.kind){case"array":return`Array<${e.inner?O(e.inner):"unknown"}>`;case"from":return e.tsType??"unknown";case"id":{const n=e.tableName??"_unknown_";return f(n,"v.id() table name"),`Id<"${n}">`}case"literal":return Mn(e.literalValue);case"object":return e.shape?`{ ${Object.entries(e.shape).map(([r,o])=>bt(r,o)).join("; ")} }`:"Record<string, unknown>";case"optional":return`${e.inner?O(e.inner):"unknown"} | undefined`;case"record":{const n=e.keyType?O(e.keyType):"string",r=e.valueType?O(e.valueType):"unknown";return`Record<${n}, ${r}>`}case"union":return e.members&&e.members.length>0?e.members.map(n=>O(n)).join(" | "):"never";default:return"unknown"}},bt=(e,t)=>{const n=q(e);if(t.kind==="optional"){const r=t.inner?O(t.inner):"unknown";return`${n}?: ${r}`}return`${n}: ${O(t)}`},xe=e=>{const t=Object.entries(e);return t.length===0?"{}":`{ ${t.map(([n,r])=>bt(n,r)).join("; ")} }`},yt=e=>e.kind==="optional"||!!e.column?.hasDefault,se=e=>e.kind==="optional"&&e.inner?e.inner:e,Fn=e=>{f(e.name,"table name");const t=Object.entries(e.shape).map(([r,o])=>{const s=se(o),i=O(s),a=q(r);return yt(o)?` ${a}?: ${i};`:` ${a}: ${i};`}).join(`
|
|
48
48
|
`),n=t?`
|
|
49
49
|
${t}
|
|
50
50
|
`:"";return`export interface Insert_${e.name} {
|
|
51
51
|
_id?: Id<"${e.name}">;
|
|
52
|
-
_creationTime?: number;${n}}`},Je="schema",
|
|
53
|
-
`),
|
|
52
|
+
_creationTime?: number;${n}}`},Je="schema",no=e=>{for(const u of e.tables)f(u.name,"table name");const t=e.tables.map(u=>`"${u.name}"`).join(" | ")||"never",n=e.tables.filter(u=>u.extensionKey===void 0).map(u=>`"${u.name}"`).join(" | ")||"never",r=e.tables.map(u=>{const l=Object.entries(u.shape).map(([x,v])=>{const S=q(x);if(v.kind==="optional"){const N=v.inner?O(v.inner):"unknown";return` ${S}?: ${N};`}return` ${S}: ${O(v)};`}).join(`
|
|
53
|
+
`),b=l?`
|
|
54
54
|
${l}
|
|
55
55
|
`:"",R=u.commitOrdered===!0?`
|
|
56
56
|
_commitSeq: number;`:"";return`export interface Doc_${u.name} {
|
|
57
57
|
_id: Id<"${u.name}">;
|
|
58
|
-
_creationTime: number;${R}${
|
|
58
|
+
_creationTime: number;${R}${b}}`}).join(`
|
|
59
59
|
|
|
60
60
|
`),o=e.tables.map(u=>` ${u.name}: Doc_${u.name};`).join(`
|
|
61
|
-
`),s=e.tables.map(u=>{const l=u.indexes.map(
|
|
62
|
-
`),i=e.tables.map(u=>{const l=u.searchIndexes.map(
|
|
63
|
-
`),a=e.tables.map(u=>{const l=u.rankIndexes.map(
|
|
64
|
-
`),c=e.tables.map(u=>{const l=u.shardMode==="global"?"":(u.geoIndexes??[]).map(
|
|
65
|
-
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",p=e.tables.map(u=>
|
|
61
|
+
`),s=e.tables.map(u=>{const l=u.indexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
62
|
+
`),i=e.tables.map(u=>{const l=u.searchIndexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
63
|
+
`),a=e.tables.map(u=>{const l=u.rankIndexes.map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
64
|
+
`),c=e.tables.map(u=>{const l=u.shardMode==="global"?"":(u.geoIndexes??[]).map(b=>JSON.stringify(b.name)).join(" | ");return` ${u.name}: ${l||"never"};`}).join(`
|
|
65
|
+
`),d=e.vectorIndexes.map(u=>JSON.stringify(u.name)).join(" | ")||"never",p=e.tables.map(u=>Fn(u)).join(`
|
|
66
66
|
|
|
67
67
|
`),m=e.tables.map(u=>` ${u.name}: Insert_${u.name};`).join(`
|
|
68
|
-
`),
|
|
68
|
+
`),y=e.tables.map(u=>{const l=u.relations.map(b=>(f(b.table,"relation target table"),` ${q(b.name)}: ${b.kind==="one"?"OneRelation":"ManyRelation"}<"${b.table}">;`)).join(`
|
|
69
69
|
`);return l?` ${u.name}: {
|
|
70
70
|
${l}
|
|
71
71
|
};`:` ${u.name}: {};`}).join(`
|
|
72
|
-
`);return E(`${
|
|
72
|
+
`);return E(`${$}export type TableName = ${t};
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* The tables **this app declared** — every {@link TableName} except those an add-on
|
|
@@ -158,14 +158,14 @@ export interface ManyRelation<Target extends keyof DataModel> {
|
|
|
158
158
|
|
|
159
159
|
/** Per-table relation map keyed by accessor name. \`{}\` for tables with none. */
|
|
160
160
|
export interface Relations {
|
|
161
|
-
${
|
|
161
|
+
${y}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
`,Je)},
|
|
165
|
-
`);return` ${q(
|
|
164
|
+
`,Je)},Bn=/import\("(?<spec>(?:\.\.?\/)*_generated\/[^"]+)"\)/gu,wt=/^(?:\.\.?\/)*_generated\//u,kt=/\.[A-Za-z]\w*$/u,qn=e=>e.replaceAll(Bn,(t,n)=>{const r=n.replace(wt,"./");return`import("${kt.test(r)?r:`${r}.js`}")`}),jn=/import\("(?<spec>[^"]+)"\)/gu,it="node_modules/",Wn=/^@types\//u,Un=e=>e.replaceAll(jn,(t,n)=>{const r=n.lastIndexOf(it);if(r===-1||r>0&&n[r-1]!=="/")return t;const o=n.slice(r+it.length);return o===""||Wn.test(o)?t:`import("${o}")`}),Kn=/import\("(?<spec>\.\.?\/[^"]+)"\)/gu,Qn=/^(?:\.\.?\/)+/u,Vn=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("/")},Hn=(e,t)=>e.replaceAll(Kn,(n,r)=>{if(wt.test(r.replace(Qn,"")))return n;const o=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",i=`../${Vn(`${o}/${r}`)}`;return`import("${kt.test(i)?i:`${i}.js`}")`}),E=(e,t)=>qn(Hn(Un(e),t)),Gn=["client","do","errors","flags","observability","platform","ratelimit","runtime","server","values"],Jn=new RegExp(String.raw`import\("@lunora/(?<pkg>${Gn.join("|")})(?<subpath>/[^"]*)?"\)`,"gu"),zn={flags:new Set(["/web"]),platform:new Set},xt=(e,t)=>t?e.replaceAll(Jn,(n,r,o)=>{const s=zn[r];return o&&s&&!s.has(o)?n:`import("lunorash/${r}${o??""}")`}):e,ze=e=>["Doc","Id"].filter(t=>new RegExp(String.raw`(?<![.$\w])${t}<`,"u").test(e)),vt=e=>e.output===void 0||e.output.kind==="any"||e.kind==="stream"?e.returnType:O(e.output),Ye=e=>{const t=new Map;for(const n of e){const r=t.get(n.filePath)??[];r.push(n),t.set(n.filePath,r)}return[...t.entries()].toSorted(([n],[r])=>n.localeCompare(r))},lt=e=>{const t=([n,r])=>{const o=r.toSorted((s,i)=>s.exportName.localeCompare(i.exportName)).map(s=>{const i=E(xe(s.args),s.filePath),a=E(vt(s),s.filePath);return` ${s.exportName}: FunctionReference<"${s.kind}", ${i}, ${a}>;`}).join(`
|
|
165
|
+
`);return` ${q(T(n))}: {
|
|
166
166
|
${o}
|
|
167
167
|
};`};return Ye(e).map(n=>t(n)).join(`
|
|
168
|
-
`)},
|
|
168
|
+
`)},Yn=(e,t)=>{if(e.length===0&&t.length===0)return{block:"",importLine:""};const n=[];let r="";if(e.length>0&&(r+="\n/** Params type carried by a `defineWorkflow` definition (its phantom `__params`). */\ntype WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params } ? (unknown extends Params ? Record<string, unknown> : Params) : Record<string, unknown>;\n"),r+=`
|
|
169
169
|
/** A typed reference to a durable workflow, addressable for \`cronJobs()\` targets. Mirrors \`@lunora/scheduler\`'s \`WorkflowReference\` structurally. */
|
|
170
170
|
export interface WorkflowReference<Params = Record<string, unknown>> {
|
|
171
171
|
readonly isLunoraWorkflow: true;
|
|
@@ -174,7 +174,7 @@ export interface WorkflowReference<Params = Record<string, unknown>> {
|
|
|
174
174
|
readonly name: string;
|
|
175
175
|
}
|
|
176
176
|
`,e.length>0){const o=[...e].toSorted((a,c)=>a.exportName.localeCompare(c.exportName)),s=o.map(a=>` ${a.exportName}: WorkflowReference<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${a.exportName}>>;`).join(`
|
|
177
|
-
`),i=o.map(a=>` ${
|
|
177
|
+
`),i=o.map(a=>` ${Y(a.exportName)}: { isLunoraWorkflow: true, binding: ${JSON.stringify(a.bindingName)}, name: ${JSON.stringify(a.exportName)} },`).join(`
|
|
178
178
|
`);r+=`
|
|
179
179
|
/** This project's durable workflows, addressable as typed references (e.g. \`crons.daily("digest", …, workflows.digestPipeline, params)\`). */
|
|
180
180
|
export interface WorkflowsRef {
|
|
@@ -186,7 +186,7 @@ ${i}
|
|
|
186
186
|
};
|
|
187
187
|
`,n.push(`import type * as lunoraWorkflowDefinitions from "../workflows.js";
|
|
188
188
|
`)}if(t.length>0){const o=[...t].toSorted((a,c)=>a.exportName.localeCompare(c.exportName)),s=o.map(a=>` ${a.exportName}: WorkflowReference<AgentRunInput>;`).join(`
|
|
189
|
-
`),i=o.map(a=>` ${
|
|
189
|
+
`),i=o.map(a=>` ${Y(a.exportName)}: { isLunoraWorkflow: true, binding: ${JSON.stringify(a.bindingName)}, name: ${JSON.stringify(a.name)} },`).join(`
|
|
190
190
|
`);r+=`
|
|
191
191
|
/** This project's durable agents, addressable as typed references for \`cronJobs()\` — each fire starts a fresh agent run (e.g. \`crons.daily("sweep", …, agents.support, { input, threadKey })\`). */
|
|
192
192
|
export interface AgentsRef {
|
|
@@ -197,7 +197,7 @@ export const agents: AgentsRef = {
|
|
|
197
197
|
${i}
|
|
198
198
|
};
|
|
199
199
|
`,n.push(`import type { AgentRunInput } from "@lunora/agent";
|
|
200
|
-
`)}return{block:r,importLine:n.join("")}},
|
|
200
|
+
`)}return{block:r,importLine:n.join("")}},Xn=()=>Object.keys(dt().functions).toSorted((e,t)=>e.localeCompare(t)),Rt=e=>new Set(e.filter(t=>T(t.filePath)==="agents").map(t=>t.exportName)),Zn=()=>new Set(Object.entries(dt().functions).filter(([,e])=>e.visibility==="internal").map(([e])=>e)),er=(e,t)=>{const n={importLine:"",lines:"",prelude:""};if(e.length===0)return n;const r=Rt(t),o=Zn(),s=t.find(a=>T(a.filePath)==="agents"&&o.has(a.exportName));if(s)throw new X("INTERNAL",`@lunora/codegen: "agents:${s.exportName}" is reserved for the durable agent loop's internal dispatch — rename the "${s.exportName}" export in ${s.filePath}`);const i=Xn().filter(a=>!r.has(a));return i.length===0?n:{importLine:`import { agentComponent } from "@lunora/agent/component";
|
|
201
201
|
`,lines:i.map(a=>` "agents:${a}": lunoraAgentRuntimeFunctions.${a} as unknown as RegisteredLunoraFunction,`).join(`
|
|
202
202
|
`),prelude:`
|
|
203
203
|
/**
|
|
@@ -206,13 +206,13 @@ ${i}
|
|
|
206
206
|
* subscribe to the public queries (\`agents:agentMessages\` is the live thread view).
|
|
207
207
|
*/
|
|
208
208
|
const lunoraAgentRuntimeFunctions = agentComponent().functions;
|
|
209
|
-
`}},
|
|
210
|
-
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},
|
|
211
|
-
`);return` ${q(
|
|
209
|
+
`}},tr=(e,t)=>{if(!e)return{importLine:"",lines:"",prelude:""};const n=t.find(r=>T(r.filePath)==="sandbox"&&r.exportName==="invoke");if(n)throw new X("INTERNAL",`@lunora/codegen: "sandbox:invoke" is reserved for the batteries-included sandbox tool dispatcher (browserTool/containerTool) — rename the "invoke" export in ${n.filePath}`);return{importLine:`import { sandboxComponent } from "@lunora/agent/component";
|
|
210
|
+
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},nr=(e,t)=>{if(e.length===0)return[];const n=Rt(t),r=[{args:{key:{kind:"string"},limit:{inner:{kind:"number"},kind:"optional"}},exportName:"agentMessages",filePath:"agents",kind:"query",returnType:"Record<string, unknown>[]"},{args:{decision:{kind:"union",members:[{kind:"literal",literalValue:'"approve"'},{kind:"literal",literalValue:'"reject"'}]},instanceId:{kind:"string"},note:{inner:{kind:"string"},kind:"optional"},threadKey:{kind:"string"},toolCallId:{kind:"string"}},exportName:"agentResolveApproval",filePath:"agents",kind:"mutation",returnType:"{ resolved: boolean }"},{args:{agent:{kind:"string"},input:{kind:"string"},threadKey:{kind:"string"},title:{inner:{kind:"string"},kind:"optional"}},exportName:"agentRun",filePath:"agents",kind:"mutation",returnType:"{ id: string; threadKey: string }"},{args:{key:{kind:"string"}},exportName:"agentState",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"},{args:{key:{kind:"string"}},exportName:"agentThread",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"}];for(const o of e)o.voice&&r.push({args:{threadKey:{kind:"string"}},exportName:`${o.exportName}Voice`,filePath:"agents",kind:"stream",returnType:"Record<string, unknown>"});return r.filter(o=>!n.has(o.exportName))},rr=(e,t)=>{if(e.length===0)return[];const n=new Set(t.filter(r=>T(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}))},or=e=>{const t=e.filter(i=>i.stream);if(t.length===0)return{block:"",body:""};const n=Ye(t),r=n.map(([i,a])=>{const c=a.map(d=>{const p=E(d.chunkType??"unknown",d.filePath),m=E(xe(d.searchParams),d.filePath),y=E(xe(d.params),d.filePath);return` ${q(d.exportName)}: HttpStreamRef<${p}, ${m}, ${y}>;`}).join(`
|
|
211
|
+
`);return` ${q(T(i))}: {
|
|
212
212
|
${c}
|
|
213
213
|
};`}).join(`
|
|
214
|
-
`),o=n.map(([i,a])=>{const c=a.map(d=>` ${
|
|
215
|
-
`);return` ${
|
|
214
|
+
`),o=n.map(([i,a])=>{const c=a.map(d=>` ${Y(d.exportName)}: { method: ${JSON.stringify(d.method)}, path: ${JSON.stringify(d.path)} },`).join(`
|
|
215
|
+
`);return` ${Y(T(i))}: {
|
|
216
216
|
${c}
|
|
217
217
|
},`}).join(`
|
|
218
218
|
`);return{block:`
|
|
@@ -224,15 +224,15 @@ ${r}
|
|
|
224
224
|
export const httpStreams: HttpStreamsRef = {
|
|
225
225
|
${o}
|
|
226
226
|
};
|
|
227
|
-
`,body:r}},
|
|
227
|
+
`,body:r}},ro=e=>{const{agents:t=[],functions:n,httpRoutes:r=[],mutators:o=[],useUmbrella:s=!1,workflows:i=[]}=e,a=ae(s),c=[...n.filter(A=>A.visibility!=="internal"),...nr(t,n),...rr(o,n)],d=n.filter(A=>A.visibility==="internal"),p=lt(c),m=lt(d),y=or(r),u=`${p}
|
|
228
228
|
${m}
|
|
229
|
-
${
|
|
229
|
+
${y.body}`,l=ze(u),b=l.length>0?`
|
|
230
230
|
import type { ${l.join(", ")} } from "./dataModel.js";
|
|
231
231
|
`:"",R=p?`
|
|
232
232
|
${p}
|
|
233
233
|
`:"",x=m?`
|
|
234
234
|
${m}
|
|
235
|
-
`:"",
|
|
235
|
+
`:"",v=Yn(i,t),S=`export interface ApiTypes {${R}}
|
|
236
236
|
|
|
237
237
|
export const api = anyApi as unknown as ApiTypes;
|
|
238
238
|
|
|
@@ -240,10 +240,10 @@ export const api = anyApi as unknown as ApiTypes;
|
|
|
240
240
|
export interface InternalApiTypes {${x}}
|
|
241
241
|
|
|
242
242
|
export const internal = anyApi as unknown as InternalApiTypes;
|
|
243
|
-
${
|
|
244
|
-
`:"";return xt(`${
|
|
245
|
-
${
|
|
246
|
-
${
|
|
243
|
+
${v.block}${y.block}`,N=[...S.includes("FunctionReference<")?["FunctionReference"]:[],...y.block===""?[]:["HttpStreamRef"]],Q=N.length>0?`import type { ${N.join(", ")} } from "${a.client}";
|
|
244
|
+
`:"";return xt(`${$}import { anyApi } from "${a.client}";
|
|
245
|
+
${Q}${v.importLine}${b}
|
|
246
|
+
${S}`,s)},oo=e=>e?`${$}import { createSeedClient as createSeedClientBase } from "@lunora/seed";
|
|
247
247
|
import type { SeedClient, SeedClientOptions } from "@lunora/seed";
|
|
248
248
|
|
|
249
249
|
import schema from "../schema.js";
|
|
@@ -260,9 +260,9 @@ import type { InsertModel } from "./dataModel.js";
|
|
|
260
260
|
* const { posts } = await seed.posts((x) => x([10, 20]));
|
|
261
261
|
*/
|
|
262
262
|
export const createSeedClient = (options?: SeedClientOptions): SeedClient<InsertModel> => createSeedClientBase<InsertModel>(schema, options);
|
|
263
|
-
`:"",
|
|
263
|
+
`:"",ao=(e,t,n=!1)=>{if(e.length===0||!t)return"";const r=ae(n),o=c=>c.table===void 0?"Row":`Doc<${JSON.stringify(c.table)}> & Row`,s=e.map(c=>{f(c.exportName,"shape export name");const d=o(c),p=E(xe(c.args),c.filePath),m=Object.keys(c.args).length>0,y=m?` args: ${p};`:` args?: ${p};`,u=m?`(args: ${p}) => void`:`(args?: ${p}) => void`,l=`${c.exportName}CollectionOptions`;return`/** Options for the \`${c.exportName}\` shape binding. */
|
|
264
264
|
export interface ${He(l)} {
|
|
265
|
-
${
|
|
265
|
+
${y}
|
|
266
266
|
/**
|
|
267
267
|
* Share the optimistic-overlay gate with other collections + mutators on this
|
|
268
268
|
* shard. Defaults to the shared per-shard registry, which is almost always what
|
|
@@ -307,14 +307,14 @@ export const ${c.exportName}Collection = (
|
|
|
307
307
|
};`}).join(`
|
|
308
308
|
|
|
309
309
|
`),i=ze(s),a=i.length>0?`import type { ${i.join(", ")} } from "./dataModel.js";
|
|
310
|
-
`:"";return`${
|
|
310
|
+
`:"";return`${$}import type { LunoraClient, SubscriptionError } from "${r.client}";
|
|
311
311
|
import { lunoraCollectionOptions } from "@lunora/db/collections";
|
|
312
312
|
import type { CheckpointRegistry, LunoraCollectionOptions, Row } from "@lunora/db";
|
|
313
313
|
import type { Collection } from "@tanstack/db";
|
|
314
314
|
import { createCollection } from "@tanstack/db";
|
|
315
315
|
${a}
|
|
316
316
|
${s}
|
|
317
|
-
`},
|
|
317
|
+
`},ar=(e,t)=>`lunora_${T(e)}_${String(t)}`,sr=`const callRegistered = async <R>(context: CallerCtx, functionPath: string, args: Record<string, unknown> | undefined): Promise<R> => {
|
|
318
318
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
319
319
|
|
|
320
320
|
if (!registered) {
|
|
@@ -343,43 +343,43 @@ ${s}
|
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
return (await registered.handler(context, args ?? {})) as R;
|
|
346
|
-
};`,
|
|
347
|
-
`),a=e.map(l=>` "${
|
|
346
|
+
};`,ir=(e,t,n=[],r=[])=>{const o=new Map,s=l=>{o.has(l)||o.set(l,ar(l,o.size))};for(const l of e)s(l.filePath);for(const l of t)s(l.filePath);for(const l of n)s(l.filePath);for(const l of r)s(l.filePath);const i=[...o.entries()].map(([l,b])=>{if(!Dn.test(l))throw new X("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(l)}`);return`import * as ${b} from "../${l}.js";`}).join(`
|
|
347
|
+
`),a=e.map(l=>` "${T(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
348
348
|
`),c=t.map(l=>` ${JSON.stringify(l.id)}: ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredDataMigration,`).join(`
|
|
349
|
-
`),d=n.map(l=>` "${
|
|
349
|
+
`),d=n.map(l=>` "${T(l.filePath)}:${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
350
350
|
`),p=r.map(l=>` "${l.exportName}": ${o.get(l.filePath)??""}.${l.exportName} as unknown as RegisteredShape,`).join(`
|
|
351
|
-
`),m=n.map(l=>`${
|
|
352
|
-
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const
|
|
353
|
-
`);return{dispatchBody:
|
|
354
|
-
${
|
|
351
|
+
`),m=n.map(l=>`${T(l.filePath)}:${l.exportName}`),y=[a,d].filter(l=>l.length>0).join(`
|
|
352
|
+
`),u=e.map(l=>{if(l.lifecycle||Object.keys(l.args).length===0)return;const b=_n(l.args);return b===void 0?void 0:`installCompiledValidatorMap(${o.get(l.filePath)??""}.${l.exportName}.args, ${b});`}).filter(l=>l!==void 0).join(`
|
|
353
|
+
`);return{dispatchBody:y.length>0?`
|
|
354
|
+
${y}
|
|
355
355
|
`:"",importBlock:i.length>0?`${i}
|
|
356
356
|
|
|
357
357
|
`:"",installBlock:u,migrationBody:c.length>0?`
|
|
358
358
|
${c}
|
|
359
359
|
`:"",mutatorPaths:m,shapeBody:p.length>0?`
|
|
360
360
|
${p}
|
|
361
|
-
`:""}},
|
|
362
|
-
`);return` ${q(
|
|
361
|
+
`:""}},lr=e=>{const t=Ye(e),n=t.map(([o,s])=>{const i=s.map(a=>{const c=E(xe(a.args),a.filePath),d=c==="{}"?"?":"",p=E(vt(a),a.filePath);return a.kind==="stream"?` ${a.exportName}: (args${d}: ${c}) => Promise<AsyncIterable<${p}>>;`:` ${a.exportName}: (args${d}: ${c}) => Promise<${p}>;`}).join(`
|
|
362
|
+
`);return` ${q(T(o))}: {
|
|
363
363
|
${i}
|
|
364
364
|
};`}).join(`
|
|
365
|
-
`);return{implementation:t.map(([o,s])=>{const i
|
|
366
|
-
`);return` ${
|
|
365
|
+
`);return{implementation:t.map(([o,s])=>{const i=T(o),a=s.map(c=>` ${Y(c.exportName)}: (args) => callRegistered(context, "${i}:${c.exportName}", args),`).join(`
|
|
366
|
+
`);return` ${Y(i)}: {
|
|
367
367
|
${a}
|
|
368
368
|
},`}).join(`
|
|
369
|
-
`),types:n}},
|
|
369
|
+
`),types:n}},cr=(e,t=[])=>{const n=new Set;for(const r of e.tables)for(const o of Object.values(r.shape)){const s=se(o);s.kind==="storage"&&typeof s.bucket=="string"&&s.bucket!==""&&n.add(s.bucket)}for(const r of t)r!==""&&r!=="default"&&n.add(r);return["default",...[...n].toSorted((r,o)=>r.localeCompare(o))]},so=({agents:e=[],containers:t=[],env:n,hasAccessFacade:r=!1,hasAi:o=!1,hasAnalytics:s=!1,hasBrowser:i=!1,hasVectors:a=!0,hasFlags:c=!1,hasHyperdrive:d=!1,hasImages:p=!1,hasKv:m=!1,hasNotify:y=!1,hasPayments:u=!1,hasPipelines:l=!1,hasR2sql:b=!1,hasX402:R=!1,identity:x,queues:v=[],schema:S,storageRuleBuckets:N=[],useUmbrella:Q=!1,workflows:A=[]}={})=>{const C=ae(Q),w=cr(S??{tables:[]},N).map(h=>JSON.stringify(h)).join(" | "),P=o?`import type { LunoraAi } from "@lunora/ai";
|
|
370
370
|
`:"",M=o?`
|
|
371
|
-
readonly ai: LunoraAi;`:"",
|
|
372
|
-
`:"",
|
|
373
|
-
readonly payments: LunoraPayment;`:"",
|
|
374
|
-
`:"",
|
|
375
|
-
readonly x402: X402Pay;`:"",
|
|
376
|
-
`:"",
|
|
371
|
+
readonly ai: LunoraAi;`:"",ie=u?`import type { LunoraPayment } from "@lunora/payment";
|
|
372
|
+
`:"",le=u?`
|
|
373
|
+
readonly payments: LunoraPayment;`:"",Z=R?`import type { X402Pay } from "@lunora/x402/pay";
|
|
374
|
+
`:"",V=R?`
|
|
375
|
+
readonly x402: X402Pay;`:"",L=t.length>0?`import type { ContainerAccessor } from "@lunora/container";
|
|
376
|
+
`:"",ee=t.length>0?`
|
|
377
377
|
readonly containers: {${t.map(h=>`
|
|
378
378
|
readonly ${h.exportName}: ContainerAccessor;`).join("")}
|
|
379
|
-
};`:"",
|
|
380
|
-
readonly ${h.bindingName}?: unknown;`)),...
|
|
381
|
-
readonly ${h.bindingName}?: unknown;`)),...
|
|
382
|
-
readonly ${h.bindingName}?: unknown;`)),...e.map(h=>(
|
|
379
|
+
};`:"",k=[...o?[" /** Workers AI binding (the conventional `env.AI`), narrowing `ctx.ai`. */\n readonly AI?: unknown;"]:[],...t.map(h=>(f(h.bindingName,`container binding "${h.bindingName}"`),` /** Durable Object namespace for the \`${h.exportName}\` container. */
|
|
380
|
+
readonly ${h.bindingName}?: unknown;`)),...A.map(h=>(f(h.bindingName,`workflow binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` workflow. */
|
|
381
|
+
readonly ${h.bindingName}?: unknown;`)),...v.map(h=>(f(h.bindingName,`queue binding "${h.bindingName}"`),` /** Queue producer binding for the \`${h.exportName}\` queue. */
|
|
382
|
+
readonly ${h.bindingName}?: unknown;`)),...e.map(h=>(f(h.bindingName,`agent binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` agent. */
|
|
383
383
|
readonly ${h.bindingName}?: unknown;`))].join(`
|
|
384
384
|
`),Ae=`
|
|
385
385
|
|
|
@@ -394,24 +394,24 @@ ${a}
|
|
|
394
394
|
* surface, so treat them as \`Fetcher\`/\`Service<unknown>\` and cast.
|
|
395
395
|
*/
|
|
396
396
|
export interface CloudflareBindings {
|
|
397
|
-
readonly [binding: string]: unknown;${
|
|
398
|
-
${
|
|
397
|
+
readonly [binding: string]: unknown;${k?`
|
|
398
|
+
${k}`:""}
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
/** Alias for {@link CloudflareBindings} — the typed shape of \`env\`. */
|
|
402
|
-
export type Env = CloudflareBindings;`,F=(h,We,Te)=>{const re
|
|
403
|
-
readonly vectors: VectorSearch<VectorIndexName>;`:"",
|
|
404
|
-
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",
|
|
402
|
+
export type Env = CloudflareBindings;`,F=(h,We,Te)=>{const re=$n.get(h);if(re!==void 0&&re.tier!==Te)throw new X("INTERNAL",`@lunora/codegen: capability "${h}" declares tier "${re.tier}" in SERVER_CTX_FIELDS but is emitted onto the "${Te}" context — update whichever is wrong.`);return We?re?.field??"":""},ce=F("kv",m,"every"),de=F("analytics",s,"every"),Oe=F("hyperdrive",d,"action"),Ie=F("browser",i,"action"),Ce=F("images",p,"action"),ue=F("pipelines",l,"action"),H=F("r2sql",b,"action"),D=a&&(S?.vectorIndexes.length??0)>0,G=D?' | "vectors"':"",te=D?`
|
|
403
|
+
readonly vectors: VectorSearch<VectorIndexName>;`:"",pe=D?`
|
|
404
|
+
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",J=D?`import type { VectorSearch, VectorSearchReader } from "${C.server}";
|
|
405
405
|
import type { VectorIndexName } from "./dataModel.js";
|
|
406
|
-
`:"",
|
|
406
|
+
`:"",j=r?`
|
|
407
407
|
/** Verified Cloudflare Access identity — a synchronous facade over the resolved claims (email / groups / hasGroup / claims). Anonymous when no Access token is present. */
|
|
408
|
-
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",
|
|
408
|
+
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",W=c?`
|
|
409
409
|
/** Feature-flag evaluation (OpenFeature). Reads are memoized per request; evaluations never throw — a provider error resolves to the supplied default. */
|
|
410
|
-
readonly flags: import("${
|
|
410
|
+
readonly flags: import("${C.flags}").LunoraFlags;`:"",U=y?`
|
|
411
411
|
/** Multi-channel notifications (@lunora/notify): send / chat / inApp / webhook plus the push device sub-facade. Sends are external I/O — confine them to action handlers. */
|
|
412
412
|
readonly notify: import("@lunora/notify").LunoraNotify;
|
|
413
413
|
/** Device push sub-facade — the same object as ctx.notify.push (register / send / broadcast). Sends belong in action handlers. */
|
|
414
|
-
readonly push: import("@lunora/notify").LunoraPush;`:"",B=
|
|
414
|
+
readonly push: import("@lunora/notify").LunoraPush;`:"",B=A.length>0,ne=B?`import type { WorkflowHandle } from "@lunora/workflow";
|
|
415
415
|
import type * as lunoraWorkflowDefinitions from "../workflows.js";
|
|
416
416
|
`:"",Le=B?`
|
|
417
417
|
|
|
@@ -424,10 +424,10 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
424
424
|
|
|
425
425
|
/** This project's declared workflows, addressable from \`ctx.workflows\` by their \`lunora/workflows.ts\` export name. */
|
|
426
426
|
export interface LunoraWorkflows {
|
|
427
|
-
${
|
|
427
|
+
${A.map(h=>` get(name: ${JSON.stringify(h.exportName)}): WorkflowHandle<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${h.exportName}>>;`).join(`
|
|
428
428
|
`)}
|
|
429
429
|
}`:"",ve=B?' | "workflows"':"",Re=B?`
|
|
430
|
-
readonly workflows: LunoraWorkflows;`:"",he=
|
|
430
|
+
readonly workflows: LunoraWorkflows;`:"",he=v.length>0,Ee=he?`import type { QueueProducer } from "@lunora/queue";
|
|
431
431
|
import type * as lunoraQueueDefinitions from "../queues.js";
|
|
432
432
|
`:"",_e=he?`
|
|
433
433
|
|
|
@@ -436,7 +436,7 @@ type QueueBodyOf<Definition> = Definition extends { __lunoraBody?: infer Body }
|
|
|
436
436
|
|
|
437
437
|
/** This project's declared queues, addressable from \`ctx.queues\` by their \`lunora/queues.ts\` export name. */
|
|
438
438
|
export interface LunoraQueues {
|
|
439
|
-
${
|
|
439
|
+
${v.map(h=>` readonly ${h.exportName}: QueueProducer<QueueBodyOf<typeof lunoraQueueDefinitions.${h.exportName}>>;`).join(`
|
|
440
440
|
`)}
|
|
441
441
|
}`:"",Se=he?`
|
|
442
442
|
readonly queues: LunoraQueues;`:"",me=e.length>0,De=me?`import type { AgentHandle } from "@lunora/agent";
|
|
@@ -444,10 +444,10 @@ ${k.map(h=>` readonly ${h.exportName}: QueueProducer<QueueBodyOf<typeof lunor
|
|
|
444
444
|
|
|
445
445
|
/** This project's declared agents, addressable from \`ctx.agents\` by their \`lunora/agents.ts\` export name. */
|
|
446
446
|
export interface LunoraAgents {
|
|
447
|
-
${e.map(h=>(
|
|
447
|
+
${e.map(h=>(f(h.exportName,`agent export "${h.exportName}"`),` readonly ${h.exportName}: AgentHandle;`)).join(`
|
|
448
448
|
`)}
|
|
449
449
|
}`:"",$e=me?`
|
|
450
|
-
readonly agents: LunoraAgents;`:"",Me=x?`import type { InferIdentity } from "${
|
|
450
|
+
readonly agents: LunoraAgents;`:"",Me=x?`import type { InferIdentity } from "${C.server}";
|
|
451
451
|
import type * as lunoraIdentityContract from "../identity.js";
|
|
452
452
|
`:"",Fe=x?`
|
|
453
453
|
|
|
@@ -460,7 +460,7 @@ type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: (
|
|
|
460
460
|
`:"",je=n?`
|
|
461
461
|
|
|
462
462
|
/** This app's declared env contract (\`defineEnv\` in \`lunora/env.ts\`) — the validated, coercion-aware shape of \`ctx.env\`. */
|
|
463
|
-
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",be=n?' | "env"':"",ye=n?"\n /** Validated, typed environment declared by `defineEnv` in `lunora/env.ts` — parsed & coercion-aware config values (`ctx.env.STRIPE_KEY`); a missing or invalid value throws at read time. */\n readonly env: LunoraEnv;":"";return`${
|
|
463
|
+
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",be=n?' | "env"':"",ye=n?"\n /** Validated, typed environment declared by `defineEnv` in `lunora/env.ts` — parsed & coercion-aware config values (`ctx.env.STRIPE_KEY`); a missing or invalid value throws at read time. */\n readonly env: LunoraEnv;":"";return`${$}import { createPolicyDsl, defineMutator as defineMutatorBase, initLunora, v as vBase } from "${C.server}";
|
|
464
464
|
import type {
|
|
465
465
|
ActionBuilder,
|
|
466
466
|
ActionCtx as ActionCtxBase,
|
|
@@ -482,7 +482,7 @@ import type {
|
|
|
482
482
|
Storage as StorageBase,
|
|
483
483
|
TableReader,
|
|
484
484
|
Validator,
|
|
485
|
-
} from "${
|
|
485
|
+
} from "${C.server}";
|
|
486
486
|
|
|
487
487
|
import type {
|
|
488
488
|
DatabaseReaderFacade as DatabaseReaderFacadeOf,
|
|
@@ -491,7 +491,7 @@ import type {
|
|
|
491
491
|
TableReaderFacade as TableReaderFacadeOf,
|
|
492
492
|
TableWriterFacade as TableWriterFacadeOf,
|
|
493
493
|
WithArg as WithArgOf,
|
|
494
|
-
} from "${
|
|
494
|
+
} from "${C.serverDataModel}";
|
|
495
495
|
|
|
496
496
|
export type {
|
|
497
497
|
AggregateOp,
|
|
@@ -514,10 +514,10 @@ export type {
|
|
|
514
514
|
Where,
|
|
515
515
|
WhereOf,
|
|
516
516
|
WhereOperators,
|
|
517
|
-
} from "${
|
|
517
|
+
} from "${C.serverDataModel}";
|
|
518
518
|
|
|
519
519
|
import type { DataModel, Doc, GeoIndexNamesByTable, Id as IdOfTable, IndexNamesByTable, Insert, InsertModel, RankIndexNamesByTable, Relations, SearchIndexNamesByTable, TableName } from "./dataModel.js";
|
|
520
|
-
${
|
|
520
|
+
${J}${P}${ie}${Z}${L}${ne}${Ee}${De}${Me}${qe}
|
|
521
521
|
export type { AppTableName, DataModel, Doc, Id, TableName } from "./dataModel.js";
|
|
522
522
|
|
|
523
523
|
/**
|
|
@@ -577,7 +577,7 @@ export interface OrmWriter extends OrmReader {
|
|
|
577
577
|
}
|
|
578
578
|
|
|
579
579
|
/** Storage buckets this schema declares (\`v.storage("name")\`), narrowing \`ctx.storage.bucket(name)\`. */
|
|
580
|
-
export type StorageBucketName = ${
|
|
580
|
+
export type StorageBucketName = ${w};${Ae}${Le}${_e}${Pe}${Fe}${je}
|
|
581
581
|
|
|
582
582
|
/**
|
|
583
583
|
* Project-typed contexts. The base contexts from \`@lunora/server\` are
|
|
@@ -643,19 +643,19 @@ type TypedAsId = <T extends string>(tableName: AsIdTable<T>, id: string) => IdOf
|
|
|
643
643
|
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${G}${ge}${be}> {
|
|
644
644
|
readonly db: Omit<DatabaseReader, "asId" | "query" | "get"> & DatabaseReaderFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
645
645
|
readonly orm: OrmReader;
|
|
646
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${
|
|
646
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${pe}${j}${ce}${W}${U}${de}${ye}${fe}
|
|
647
647
|
}
|
|
648
648
|
|
|
649
649
|
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${G}${ve}${ge}${be}> {
|
|
650
650
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
651
651
|
readonly orm: OrmWriter;
|
|
652
|
-
readonly storage: MutationStorage<StorageBucketName>;${te}${
|
|
652
|
+
readonly storage: MutationStorage<StorageBucketName>;${te}${j}${ce}${W}${U}${de}${ye}${Re}${Se}${$e}${fe}
|
|
653
653
|
}
|
|
654
654
|
|
|
655
655
|
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${G}${ve}${ge}${be}> {
|
|
656
656
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
657
657
|
readonly orm: OrmWriter;
|
|
658
|
-
readonly storage: StorageBase<StorageBucketName>;${te}${
|
|
658
|
+
readonly storage: StorageBase<StorageBucketName>;${te}${j}${M}${le}${V}${ee}${ce}${W}${U}${Oe}${Ie}${Ce}${de}${ue}${H}${ye}${Re}${Se}${$e}${fe}
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
/**
|
|
@@ -688,7 +688,7 @@ export const internalAction = lunoraBuilders.internalAction as unknown as Intern
|
|
|
688
688
|
/**
|
|
689
689
|
* \`defineMutator\` bound to this project's typed {@link MutationCtx} — declare
|
|
690
690
|
* custom mutators (\`lunora/mutators.ts\`) with it instead of importing from
|
|
691
|
-
* \`${
|
|
691
|
+
* \`${C.server}\`, and the authoritative \`server\` impl's \`ctx\` carries the
|
|
692
692
|
* schema-typed \`ctx.db\` (\`ctx.db.query("nodes")\` resolves \`Doc<"nodes">\`,
|
|
693
693
|
* \`ctx.db.patch(id, …)\` takes an \`Id<"nodes">\`) with no hand-written ctx type and
|
|
694
694
|
* no \`as unknown as\` cast. Runtime-identical to the package export; only the
|
|
@@ -730,45 +730,45 @@ export const definePolicy = createPolicyDsl<DataModel, Relations${Be}>();
|
|
|
730
730
|
export const v = vBase as unknown as Omit<typeof vBase, "id"> & {
|
|
731
731
|
id: <T extends TableName>(table: T) => ColumnValidator<IdOfTable<T>, IdOfTable<T>>;
|
|
732
732
|
};
|
|
733
|
-
`},
|
|
734
|
-
`);let
|
|
735
|
-
${
|
|
733
|
+
`},dr=e=>{const t={connect:[],disconnect:[],init:[],reactor:[]};for(const n of e)n.lifecycle&&t[n.lifecycle].push(`${T(n.filePath)}:${n.exportName}`);return t},io=e=>{const{agents:t=[],functions:n,migrations:r=[],mutators:o=[],shapes:s=[],useUmbrella:i=!1,usesSandbox:a=!1}=e,c=n.length>0,d=ae(i),{dispatchBody:p,importBlock:m,installBlock:y,migrationBody:u,mutatorPaths:l,shapeBody:b}=ir(n,r,o,s),R=er(t,n),x=tr(a,n),v=[R.lines,x.lines].filter(k=>k.length>0).join(`
|
|
734
|
+
`);let S=p;v.length>0&&(S=p.length>0?`${p.trimEnd()}
|
|
735
|
+
${v}
|
|
736
736
|
`:`
|
|
737
|
-
${
|
|
738
|
-
`);const N=
|
|
739
|
-
`:"",
|
|
737
|
+
${v}
|
|
738
|
+
`);const N=dr(n),Q=s.length>0?`import type { RegisteredShape } from "${d.server}";
|
|
739
|
+
`:"",A=s.length>0?`
|
|
740
740
|
/**
|
|
741
741
|
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
742
742
|
* The generated ShardDO's \`resolveShape\` override looks a shape up by name and
|
|
743
743
|
* evaluates its trusted \`compileWhere(ctx, args)\` to authorize + scope a
|
|
744
744
|
* \`shape_subscribe\` (reads-as-permissions).
|
|
745
745
|
*/
|
|
746
|
-
export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${
|
|
747
|
-
`:"",
|
|
746
|
+
export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${b}};
|
|
747
|
+
`:"",C=l.length>0?`
|
|
748
748
|
/**
|
|
749
749
|
* Custom-mutator function paths — the \`LUNORA_FUNCTIONS\` keys the generated
|
|
750
750
|
* ShardDO's \`isCustomMutator\` override routes through the client-watermark push
|
|
751
751
|
* protocol (\`x-lunora-client-id\`/\`x-lunora-client-seq\` ordering).
|
|
752
752
|
*/
|
|
753
|
-
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${l.map(
|
|
754
|
-
`:"",
|
|
755
|
-
`:"",
|
|
753
|
+
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${l.map(k=>JSON.stringify(k)).join(", ")}]);
|
|
754
|
+
`:"",w=y.length>0?`import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${d.values}";
|
|
755
|
+
`:"",P=y.length>0?`
|
|
756
756
|
/**
|
|
757
757
|
* AOT-compiled argument validators (Worker-safe, no \`eval\`). Each is installed
|
|
758
758
|
* onto its function's live \`.args\` object and consulted by the interpreted
|
|
759
759
|
* parser as a zero-allocation fast path; anything it can't model is deferred.
|
|
760
760
|
*/
|
|
761
|
-
${
|
|
762
|
-
`:"",M=
|
|
761
|
+
${y}
|
|
762
|
+
`:"",M=lr(n),ie=M.types?`
|
|
763
763
|
${M.types}
|
|
764
|
-
`:"",
|
|
764
|
+
`:"",le=M.implementation?`
|
|
765
765
|
${M.implementation}
|
|
766
|
-
`:"",
|
|
767
|
-
`:"",
|
|
766
|
+
`:"",Z=ze(M.types),V=Z.length>0?`import type { ${Z.join(", ")} } from "./dataModel.js";
|
|
767
|
+
`:"",L=c?"context":"_context",ee=c?`${sr}
|
|
768
768
|
|
|
769
|
-
`:"";return xt(`${
|
|
769
|
+
`:"";return xt(`${$}${m}${R.importLine}${x.importLine}${w}${Q}import { LunoraError } from "${d.server}";
|
|
770
770
|
import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
771
|
-
${
|
|
771
|
+
${V}
|
|
772
772
|
/**
|
|
773
773
|
* Single registered function, narrowed to the shape \`handleRpc\` needs.
|
|
774
774
|
* The real argument validators / return types are checked elsewhere — at
|
|
@@ -810,8 +810,8 @@ ${R.prelude}${x.prelude}
|
|
|
810
810
|
* Static dispatch table. The key matches the \`__lunoraRef\` the client
|
|
811
811
|
* emits (\`api[namespace][fn].__lunoraRef === "namespace:fn"\`).
|
|
812
812
|
*/
|
|
813
|
-
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${
|
|
814
|
-
${
|
|
813
|
+
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${S}};
|
|
814
|
+
${P}${A}${C}
|
|
815
815
|
/**
|
|
816
816
|
* Lifecycle manifest: the function paths the generated ShardDO dispatches when a
|
|
817
817
|
* client's WebSocket connects (\`connect\`) or disconnects (\`disconnect\`), once
|
|
@@ -822,10 +822,10 @@ ${ie}${C}${f}
|
|
|
822
822
|
* anonymous — all via system dispatch.
|
|
823
823
|
*/
|
|
824
824
|
export const LUNORA_LIFECYCLE_HOOKS: { connect: readonly string[]; disconnect: readonly string[]; init: readonly string[]; reactor: readonly string[] } = {
|
|
825
|
-
connect: [${N.connect.map(
|
|
826
|
-
disconnect: [${N.disconnect.map(
|
|
827
|
-
init: [${N.init.map(
|
|
828
|
-
reactor: [${N.reactor.map(
|
|
825
|
+
connect: [${N.connect.map(k=>JSON.stringify(k)).join(", ")}],
|
|
826
|
+
disconnect: [${N.disconnect.map(k=>JSON.stringify(k)).join(", ")}],
|
|
827
|
+
init: [${N.init.map(k=>JSON.stringify(k)).join(", ")}],
|
|
828
|
+
reactor: [${N.reactor.map(k=>JSON.stringify(k)).join(", ")}],
|
|
829
829
|
};
|
|
830
830
|
|
|
831
831
|
/**
|
|
@@ -856,10 +856,10 @@ export type CallerCtx = ActionCtx | MutationCtx | QueryCtx;
|
|
|
856
856
|
* with the supplied \`context\`, exactly like \`ctx.runQuery\`/\`runMutation\`/
|
|
857
857
|
* \`runAction\` but without re-stating the function path.
|
|
858
858
|
*/
|
|
859
|
-
export interface Caller {${
|
|
859
|
+
export interface Caller {${ie}}
|
|
860
860
|
|
|
861
|
-
${
|
|
862
|
-
export const createCaller = (${
|
|
861
|
+
${ee}/** Build a {@link Caller} bound to \`context\` (typically a handler's \`ctx\`). */
|
|
862
|
+
export const createCaller = (${L}: CallerCtx): Caller => ({${le}});
|
|
863
863
|
|
|
864
864
|
/**
|
|
865
865
|
* Single registered data migration, narrowed to the shape the per-shard runner
|
|
@@ -879,7 +879,7 @@ export interface RegisteredDataMigration {
|
|
|
879
879
|
* shard DO's admin RPC and the CLI resolve migrations to run through this map.
|
|
880
880
|
*/
|
|
881
881
|
export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${u}};
|
|
882
|
-
`,i)},
|
|
882
|
+
`,i)},ur=e=>{const t={};for(const n of e.tables){const r={};for(const[o,s]of Object.entries(n.shape)){const i=se(s);i.kind==="id"&&i.tableName!==void 0&&(r[o]=i.tableName)}Object.keys(r).length>0&&(t[n.name]=r)}return t},pr=e=>{const t={};for(const n of e.tables){const r=[];for(const[o,s]of Object.entries(n.shape))se(s).kind==="storage"&&r.push(o);r.length>0&&(t[n.name]=r)}return t},hr=e=>{const t={};for(const n of e.tables){const r=[...n.indexes.map(o=>({fields:[...o.fields],name:o.name,type:"index",...o.unique===!0?{unique:!0}:{}})),...n.searchIndexes.map(o=>({fields:[o.field,...o.filterFields??[]],name:o.name,type:"search"})),...(n.geoIndexes??[]).map(o=>({fields:[o.field],name:o.name,type:"geo"})),...n.rankIndexes.map(o=>({fields:o.sortBy.map(s=>s.field),name:o.name,type:"rank"})),...n.vectorIndexes.map(o=>({fields:o.field===void 0?[]:[o.field],name:o.name,type:"vector"}))];r.length>0&&(t[n.name]=r)}return t},mr=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},gr=e=>{if(e.kind!=="union"||e.members===void 0||e.members.length===0)return;const t=[];for(const n of e.members){if(n.kind!=="literal"||n.literalValue===void 0)return;try{const r=JSON.parse(n.literalValue);if(typeof r!="string")return;t.push(r)}catch{return}}return t},fr=(e,t)=>{const n=se(t),r={name:e,optional:yt(t),type:n.kind};n.kind==="id"&&n.tableName!==void 0&&(r.ref=n.tableName),n.kind==="storage"&&(r.isStorage=!0,n.bucket!==void 0&&(r.bucket=n.bucket));const o=gr(n);return o!==void 0&&(r.enumValues=o),n.column?.notNull===!1&&(r.nullable=!0),r},br=e=>{const t={};for(const n of e.tables){const r=[{name:"_id",optional:!1,pk:!0,type:"id"},{name:"_creationTime",optional:!1,type:"number"},...n.commitOrdered===!0?[{name:"_commitSeq",optional:!1,type:"number"}]:[]];for(const[o,s]of Object.entries(n.shape))r.push(fr(o,s));t[n.name]=r}return t},yr=e=>e?{importFragment:"serveRelationFanout, ",override:`
|
|
883
883
|
protected override async runRelationFanoutRead(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
884
884
|
this.ensureMigrated();
|
|
885
885
|
|
|
@@ -887,7 +887,7 @@ export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${u}}
|
|
|
887
887
|
|
|
888
888
|
return serveRelationFanout(schema as unknown as SchemaLike, db, functionPath, args);
|
|
889
889
|
}
|
|
890
|
-
`}:{importFragment:"",override:""},
|
|
890
|
+
`}:{importFragment:"",override:""},wr=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:`
|
|
891
891
|
const aiBinding = config.ai?.(env) ?? (env as Record<string, unknown>).AI;
|
|
892
892
|
// Correlate AI-Gateway-routed calls with the Lunora trace: thread the
|
|
893
893
|
// function path + trace id into createAi, which folds them into the
|
|
@@ -918,14 +918,14 @@ const aiStub: LunoraAi = {
|
|
|
918
918
|
${t}
|
|
919
919
|
}) as unknown as LunoraAi["workersai"],
|
|
920
920
|
};
|
|
921
|
-
`}},
|
|
921
|
+
`}},I=(e,t,n,{cast:r="",sync:o=[]}={})=>{const s=n.map(i=>` ${i}: ${o.includes(i)?"":"async "}() => {
|
|
922
922
|
${t}
|
|
923
923
|
},`).join(`
|
|
924
924
|
`);return`
|
|
925
925
|
const ${e} = {
|
|
926
926
|
${s}
|
|
927
927
|
}${r};
|
|
928
|
-
`},_={build:"",configField:"",contextField:"",importLines:[],stub:""},
|
|
928
|
+
`},_={build:"",configField:"",contextField:"",importLines:[],stub:""},kr=e=>e?{build:`
|
|
929
929
|
const kvBinding = config.kv?.(env) ?? (env as Record<string, unknown>).KV;
|
|
930
930
|
// KV is not this shard's SQLite, so nothing appends a \`__cdc_log\` entry
|
|
931
931
|
// when a value changes — a subscription that read one can never be proven
|
|
@@ -939,24 +939,24 @@ ${s}
|
|
|
939
939
|
]);
|
|
940
940
|
`,configField:`
|
|
941
941
|
kv?: (env: Record<string, unknown>) => KVNamespaceLike;`,contextField:`
|
|
942
|
-
kv,`,importLines:['import type { Kv, KVNamespaceLike } from "@lunora/bindings/kv";','import { createKv } from "@lunora/bindings/kv";'],stub:
|
|
942
|
+
kv,`,importLines:['import type { Kv, KVNamespaceLike } from "@lunora/bindings/kv";','import { createKv } from "@lunora/bindings/kv";'],stub:I("kvStub: Kv",'throw new Error("ctx.kv: no KV binding found. Add a \\`kv_namespaces\\` binding (env.KV) to wrangler.jsonc, or pass \\`kv\\` to createShardDO().");',["delete","get","getRaw","getWithMetadata","list","put"])}:_,xr=(e,t)=>e?{build:`
|
|
943
943
|
const flags: import("${t}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
944
944
|
provider: () => config.flags?.(env),
|
|
945
945
|
targetingKey: () => flagsConfig.identify?.({ identity: identity ?? null, userId: userId ?? null }),
|
|
946
946
|
});
|
|
947
947
|
`,configField:`
|
|
948
948
|
flags?: (env: Record<string, unknown>) => import("${t}").Provider;`,contextField:`
|
|
949
|
-
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:_,
|
|
949
|
+
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:_,vr=e=>e?{build:`
|
|
950
950
|
const { notify, push } = createNotify(notifyConfig, env, { log, metrics });
|
|
951
951
|
`,configField:"",contextField:`
|
|
952
952
|
notify,
|
|
953
|
-
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:_,
|
|
953
|
+
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:_,Rr=e=>e?{build:`
|
|
954
954
|
const envConfig = lunoraEnvContract.${e.exportName}(env);
|
|
955
955
|
`,configField:"",contextField:`
|
|
956
|
-
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:_,
|
|
956
|
+
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:_,Sr=e=>e?{build:`
|
|
957
957
|
const access = accessFacade(identity, userId);
|
|
958
958
|
`,configField:"",contextField:`
|
|
959
|
-
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:_
|
|
959
|
+
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:_,$r=(e,t,n)=>{if(!t)return{constant:"",evaluateOverride:"",subscriptionOverride:""};const r=a=>`
|
|
960
960
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
961
961
|
const flags: import("${n}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
962
962
|
provider: () => config.flags?.(env),
|
|
@@ -1018,25 +1018,25 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
1018
1018
|
|
|
1019
1019
|
return flags.boolean(key, typeof args.default === "boolean" ? args.default : false, context);
|
|
1020
1020
|
}
|
|
1021
|
-
`;return{constant:o,evaluateOverride:s,subscriptionOverride:i}}
|
|
1021
|
+
`;return{constant:o,evaluateOverride:s,subscriptionOverride:i}},Tr=e=>e?{build:`
|
|
1022
1022
|
const analyticsBinding = config.analytics?.(env) ?? (env as Record<string, unknown>).ANALYTICS;
|
|
1023
1023
|
const analytics: AnalyticsClient = analyticsBinding ? createAnalytics(analyticsBinding as AnalyticsEngineDatasetLike) : analyticsStub;
|
|
1024
1024
|
`,configField:`
|
|
1025
1025
|
analytics?: (env: Record<string, unknown>) => AnalyticsEngineDatasetLike;`,contextField:`
|
|
1026
|
-
analytics,`,importLines:['import type { AnalyticsClient, AnalyticsEngineDatasetLike } from "@lunora/bindings/analytics";','import { createAnalytics } from "@lunora/bindings/analytics";'],stub:
|
|
1026
|
+
analytics,`,importLines:['import type { AnalyticsClient, AnalyticsEngineDatasetLike } from "@lunora/bindings/analytics";','import { createAnalytics } from "@lunora/bindings/analytics";'],stub:I("analyticsStub: AnalyticsClient",'throw new Error("ctx.analytics: no Analytics Engine binding found. Add an \\`analytics_engine_datasets\\` binding (env.ANALYTICS) to wrangler.jsonc, or pass \\`analytics\\` to createShardDO().");',["track","writeDataPoint"],{sync:["track","writeDataPoint"]})}:_,Nr=e=>e?{build:`
|
|
1027
1027
|
const imagesBinding = config.images?.(env) ?? (env as Record<string, unknown>).IMAGES;
|
|
1028
1028
|
const images: Images = imagesBinding ? createImages({ binding: imagesBinding as ImagesBindingLike }) : imagesStub;
|
|
1029
1029
|
`,configField:`
|
|
1030
1030
|
images?: (env: Record<string, unknown>) => ImagesBindingLike;`,contextField:`
|
|
1031
|
-
images,`,importLines:['import type { Images, ImagesBindingLike } from "@lunora/bindings/images";','import { createImages } from "@lunora/bindings/images";'],stub:
|
|
1031
|
+
images,`,importLines:['import type { Images, ImagesBindingLike } from "@lunora/bindings/images";','import { createImages } from "@lunora/bindings/images";'],stub:I("imagesStub: Images",'throw new Error("ctx.images: no Images binding found. Add an \\`images\\` binding (env.IMAGES) to wrangler.jsonc, or pass \\`images\\` to createShardDO().");',["info","transform"])}:_,Ar=e=>e?{build:`
|
|
1032
1032
|
const sql: SqlClient = config.sql ? config.sql(env) : sqlStub;
|
|
1033
1033
|
`,configField:`
|
|
1034
1034
|
sql?: (env: Record<string, unknown>) => SqlClient;`,contextField:`
|
|
1035
|
-
sql,`,importLines:['import type { SqlClient } from "@lunora/hyperdrive";'],stub:
|
|
1035
|
+
sql,`,importLines:['import type { SqlClient } from "@lunora/hyperdrive";'],stub:I("sqlStub: SqlClient",'throw new Error("ctx.sql: provide a \\`sql\\` config thunk that builds a SqlClient from your driver, e.g. \\`sql: (env) => fromPostgresJs(postgres(env.HYPERDRIVE.connectionString))\\`.");',["query"])}:_,Or=e=>e?{build:`
|
|
1036
1036
|
const browser: Browser = config.browser ? config.browser(env) : browserStub;
|
|
1037
1037
|
`,configField:`
|
|
1038
1038
|
browser?: (env: Record<string, unknown>) => Browser;`,contextField:`
|
|
1039
|
-
browser,`,importLines:['import type { Browser } from "@lunora/browser";'],stub:
|
|
1039
|
+
browser,`,importLines:['import type { Browser } from "@lunora/browser";'],stub:I("browserStub: Browser","throw new Error(\"ctx.browser: provide a \\`browser\\` config thunk, e.g. \\`browser: (env) => createBrowser({ binding: env.BROWSER, launch })\\` with \\`import { launch } from '@cloudflare/playwright'\\`. Session reuse (connect/sessions) additionally needs those two exports passed the same way.\");",["connect","content","launch","pdf","scrape","screenshot","sessions"])}:_,Ir=e=>e?{build:`
|
|
1040
1040
|
const r2sqlEnv = env as Record<string, unknown>;
|
|
1041
1041
|
const r2sqlAccountId = (r2sqlEnv.R2_SQL_ACCOUNT_ID ?? r2sqlEnv.CLOUDFLARE_ACCOUNT_ID) as string | undefined;
|
|
1042
1042
|
const r2sqlToken = r2sqlEnv.R2_SQL_TOKEN as string | undefined;
|
|
@@ -1047,18 +1047,18 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
1047
1047
|
? createR2Sql({ accountId: r2sqlAccountId, apiToken: r2sqlToken, bucket: r2sqlBucket })
|
|
1048
1048
|
: r2sqlStub;
|
|
1049
1049
|
`,configField:`
|
|
1050
|
-
r2sql?: (env: Record<string, unknown>) => R2SqlClient;`,contextField:"",importLines:['import type { R2SqlClient } from "@lunora/bindings/r2sql";','import { createR2Sql } from "@lunora/bindings/r2sql";'],stub:
|
|
1050
|
+
r2sql?: (env: Record<string, unknown>) => R2SqlClient;`,contextField:"",importLines:['import type { R2SqlClient } from "@lunora/bindings/r2sql";','import { createR2Sql } from "@lunora/bindings/r2sql";'],stub:I("r2sqlStub: R2SqlClient",'throw new Error("ctx.r2sql: no R2 SQL credentials found. Set \\`R2_SQL_TOKEN\\`, \\`R2_SQL_ACCOUNT_ID\\` (or \\`CLOUDFLARE_ACCOUNT_ID\\`), and \\`R2_SQL_BUCKET\\` in your env/.dev.vars, or pass an \\`r2sql\\` config thunk to createShardDO().");',["describe","explain","from","query","showDatabases","showTables"],{sync:["from"]})}:_,Cr=e=>e?{build:`
|
|
1051
1051
|
const pipelinesBinding = config.pipelines?.(env) ?? (env as Record<string, unknown>).PIPELINES;
|
|
1052
1052
|
const pipelines: PipelineClient = pipelinesBinding ? createPipelines({ binding: pipelinesBinding as PipelineBindingLike }) : pipelinesStub;
|
|
1053
1053
|
`,configField:`
|
|
1054
|
-
pipelines?: (env: Record<string, unknown>) => PipelineBindingLike;`,contextField:"",importLines:['import type { PipelineBindingLike, PipelineClient } from "@lunora/bindings/pipelines";','import { createPipelines } from "@lunora/bindings/pipelines";'],stub:
|
|
1054
|
+
pipelines?: (env: Record<string, unknown>) => PipelineBindingLike;`,contextField:"",importLines:['import type { PipelineBindingLike, PipelineClient } from "@lunora/bindings/pipelines";','import { createPipelines } from "@lunora/bindings/pipelines";'],stub:I("pipelinesStub: PipelineClient",'throw new Error("ctx.pipelines: no Pipelines binding found. Add a \\`pipelines\\` binding (env.PIPELINES) to wrangler.jsonc, or pass \\`pipelines\\` to createShardDO().");',["send"])}:_,lo=(e,t)=>{if(e.length===0)return"";const n=t?`, ${JSON.stringify(t)}`:"",r=e.map(s=>(f(s.exportName,`container export "${s.exportName}"`),f(s.className,`container class "${s.className}"`),`/** Container DO for the \`${s.exportName}\` definition (binding \`${s.bindingName}\`). */
|
|
1055
1055
|
export class ${s.className} extends LunoraContainer {
|
|
1056
1056
|
public constructor(ctx: ConstructorParameters<typeof LunoraContainer>[0], env: Record<string, unknown>) {
|
|
1057
1057
|
super(ctx, env, ${s.exportName}, "${s.exportName}"${n});
|
|
1058
1058
|
}
|
|
1059
1059
|
}
|
|
1060
1060
|
`)).join(`
|
|
1061
|
-
`),o=e.map(s=>s.exportName).join(", ");return`${
|
|
1061
|
+
`),o=e.map(s=>s.exportName).join(", ");return`${$}/**
|
|
1062
1062
|
* Container-enabled Durable Object classes for the containers declared in
|
|
1063
1063
|
* \`lunora/containers.ts\`. Re-export them from your worker entry — wrangler
|
|
1064
1064
|
* requires each \`containers[].class_name\` to be exported by the worker:
|
|
@@ -1076,7 +1076,7 @@ import { ${o} } from "../containers.js";
|
|
|
1076
1076
|
|
|
1077
1077
|
export { ContainerProxy } from "@lunora/container/do";
|
|
1078
1078
|
|
|
1079
|
-
${r}`},
|
|
1079
|
+
${r}`},Lr=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const r of e)f(r.exportName,`container export "${r.exportName}"`),f(r.bindingName,`container binding "${r.bindingName}"`);const n=e.map(r=>{const o=r.maxInstances===void 0?"":`, maxInstances: ${String(r.maxInstances)}`;return` { binding: "${r.bindingName}", exportName: "${r.exportName}"${o} },`}).join(`
|
|
1080
1080
|
`);return{build:`
|
|
1081
1081
|
const containers = createContainerContext(env, LUNORA_CONTAINERS, ${t?JSON.stringify(t):"undefined"}, this.getCurrentTraceparent());
|
|
1082
1082
|
`,contextField:`
|
|
@@ -1085,14 +1085,14 @@ ${r}`},Cr=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[]
|
|
|
1085
1085
|
const LUNORA_CONTAINERS: ReadonlyArray<ContainerBindingSpec> = [
|
|
1086
1086
|
${n}
|
|
1087
1087
|
];
|
|
1088
|
-
`}},
|
|
1088
|
+
`}},co=e=>{if(e.length===0)return"";const t=e.map(r=>(f(r.exportName,`workflow export "${r.exportName}"`),f(r.className,`workflow class "${r.className}"`),`/** WorkflowEntrypoint for the \`${r.exportName}\` definition (binding \`${r.bindingName}\`). */
|
|
1089
1089
|
export class ${r.className} extends LunoraWorkflow<WorkflowParamsOf<typeof ${r.exportName}>, WorkflowOutputOf<typeof ${r.exportName}>> {
|
|
1090
1090
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1091
1091
|
super(ctx, env, ${r.exportName}, "${r.exportName}");
|
|
1092
1092
|
}
|
|
1093
1093
|
}
|
|
1094
1094
|
`)).join(`
|
|
1095
|
-
`),n=e.map(r=>r.exportName).join(", ");return`${
|
|
1095
|
+
`),n=e.map(r=>r.exportName).join(", ");return`${$}/**
|
|
1096
1096
|
* WorkflowEntrypoint classes for the workflows declared in
|
|
1097
1097
|
* \`lunora/workflows.ts\`. Re-export them from your worker entry — wrangler
|
|
1098
1098
|
* requires each \`workflows[].class_name\` to be exported by the worker:
|
|
@@ -1113,13 +1113,13 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
1113
1113
|
/** Output type carried by a \`defineWorkflow\` definition (its phantom \`__output\`), so each entrypoint keeps the authored return type. */
|
|
1114
1114
|
type WorkflowOutputOf<Definition> = Definition extends { __output?: infer Output } ? Output : unknown;
|
|
1115
1115
|
|
|
1116
|
-
${t}`},
|
|
1116
|
+
${t}`},uo=e=>{if(e.length===0)return"";const n=e.filter(a=>a.voice).length>0,r=e.map(a=>{f(a.exportName,`agent export "${a.exportName}"`),f(a.className,`agent class "${a.className}"`);const c=`/** WorkflowEntrypoint for the \`${a.exportName}\` agent (binding \`${a.bindingName}\`). */
|
|
1117
1117
|
export class ${a.className} extends LunoraWorkflow<AgentRunInput, AgentRunResult> {
|
|
1118
1118
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1119
1119
|
super(ctx, env, compileAgentWorkflow(${a.exportName}, "${a.exportName}"), "${a.exportName}");
|
|
1120
1120
|
}
|
|
1121
1121
|
}
|
|
1122
|
-
`;if(!a.voice)return c;const d=a.voiceClassName??"",p=a.voiceBindingName??"";
|
|
1122
|
+
`;if(!a.voice)return c;const d=a.voiceClassName??"",p=a.voiceBindingName??"";f(d,`agent voice class "${d}"`);const m=`
|
|
1123
1123
|
/** Voice-session Durable Object for the \`${a.exportName}\` agent (binding \`${p}\`). */
|
|
1124
1124
|
export class ${d} extends VoiceSessionDO {
|
|
1125
1125
|
public constructor(ctx: ConstructorParameters<typeof VoiceSessionDO>[0], env: Record<string, unknown>) {
|
|
@@ -1127,7 +1127,7 @@ export class ${d} extends VoiceSessionDO {
|
|
|
1127
1127
|
}
|
|
1128
1128
|
}
|
|
1129
1129
|
`;return`${c}${m}`}).join(`
|
|
1130
|
-
`),o=e.map(a=>a.exportName).join(", ");return`${
|
|
1130
|
+
`),o=e.map(a=>a.exportName).join(", ");return`${$}/**
|
|
1131
1131
|
* WorkflowEntrypoint classes for the agents declared in \`lunora/agents.ts\`.
|
|
1132
1132
|
* Each \`defineAgent\` compiles a replay-safe tool-loop onto a Cloudflare
|
|
1133
1133
|
* Workflow. Re-export them from your worker entry — wrangler requires each
|
|
@@ -1141,8 +1141,8 @@ import type { AgentRunInput, AgentRunResult } from "@lunora/agent";
|
|
|
1141
1141
|
|
|
1142
1142
|
import { ${o} } from "../agents.js";
|
|
1143
1143
|
|
|
1144
|
-
${r}`},
|
|
1145
|
-
`);return`${
|
|
1144
|
+
${r}`},po=e=>{const t=e.filter(o=>o.mode==="push");if(t.length===0)return"";for(const o of t)f(o.exportName,`queue export "${o.exportName}"`);const n=t.map(o=>o.exportName).join(", "),r=t.map(o=>` ${JSON.stringify(o.name)}: { definition: ${o.exportName}, exportName: ${JSON.stringify(o.exportName)} },`).join(`
|
|
1145
|
+
`);return`${$}/**
|
|
1146
1146
|
* Push-consumer registry for the queues declared in \`lunora/queues.ts\`. The
|
|
1147
1147
|
* composed worker's \`queue(batch, env, ctx)\` entry routes each delivered batch
|
|
1148
1148
|
* by \`batch.queue\` to the matching \`defineQueue\` handler. Wired automatically
|
|
@@ -1156,7 +1156,7 @@ import { ${n} } from "../queues.js";
|
|
|
1156
1156
|
export const LUNORA_QUEUE_REGISTRY: QueueRegistry = {
|
|
1157
1157
|
${r}
|
|
1158
1158
|
};
|
|
1159
|
-
`},
|
|
1159
|
+
`},Er=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)f(n.exportName,`workflow export "${n.exportName}"`),f(n.bindingName,`workflow binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}" },`).join(`
|
|
1160
1160
|
`);return{build:`
|
|
1161
1161
|
const workflows = createWorkflowContext(env, LUNORA_WORKFLOWS);
|
|
1162
1162
|
`,contextField:`
|
|
@@ -1165,7 +1165,7 @@ ${r}
|
|
|
1165
1165
|
const LUNORA_WORKFLOWS: ReadonlyArray<WorkflowBindingSpec> = [
|
|
1166
1166
|
${t}
|
|
1167
1167
|
];
|
|
1168
|
-
`}},
|
|
1168
|
+
`}},_r=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)f(n.exportName,`queue export "${n.exportName}"`),f(n.bindingName,`queue binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}", name: ${JSON.stringify(n.name)} },`).join(`
|
|
1169
1169
|
`);return{build:`
|
|
1170
1170
|
const queues = createQueueContext(env, LUNORA_QUEUES);
|
|
1171
1171
|
`,contextField:`
|
|
@@ -1174,7 +1174,7 @@ ${t}
|
|
|
1174
1174
|
const LUNORA_QUEUES: ReadonlyArray<QueueBindingSpec> = [
|
|
1175
1175
|
${t}
|
|
1176
1176
|
];
|
|
1177
|
-
`}},
|
|
1177
|
+
`}},Dr=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)f(n.exportName,`agent export "${n.exportName}"`),f(n.bindingName,`agent binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}"${n.publicRun===!0?", publicRun: true":""} },`).join(`
|
|
1178
1178
|
`);return{build:`
|
|
1179
1179
|
const agents = createAgentContext(env, LUNORA_AGENTS);
|
|
1180
1180
|
`,contextField:`
|
|
@@ -1190,21 +1190,21 @@ const ${e}: ${t} = ${JSON.stringify(r,void 0,4)};
|
|
|
1190
1190
|
protected override ${n}(): ${t} {
|
|
1191
1191
|
return ${e};
|
|
1192
1192
|
}
|
|
1193
|
-
`}),
|
|
1193
|
+
`}),Pr=e=>{if(e.length===0)return{constant:"",override:""};const t={workflows:e.map(n=>({binding:n.bindingName,className:n.className,exportName:n.exportName,name:n.name}))};return St("LUNORA_WORKFLOWS_INFO","WorkflowsResult","workflowsMetadata",t,"/** Read-only declared-workflow metadata (discovered from `lunora/workflows.ts`) served via `__lunora_admin__:listWorkflows` for the studio's workflows view. */")},Mr=e=>{if(e.length===0)return{constant:"",override:""};const t={queues:e.map(n=>({binding:n.bindingName,...n.tuning.deadLetterQueue===void 0?{}:{deadLetterQueue:n.tuning.deadLetterQueue},exportName:n.exportName,mode:n.mode,name:n.name}))};return St("LUNORA_QUEUES_INFO","QueuesResult","queuesMetadata",t,"/** Read-only declared-queue metadata (discovered from `lunora/queues.ts`) served via `__lunora_admin__:listQueues` for the studio's queues view. */")},Fr=e=>e?{imports:['import type { LunoraDatabaseLike as LunoraPaymentDbLike, LunoraPayment, PaymentsFromContextOptions } from "@lunora/payment";','import { paymentsFromContext } from "@lunora/payment";'],build:`
|
|
1194
1194
|
const payments: LunoraPayment = config.payment
|
|
1195
1195
|
? paymentsFromContext({ auth: { userId: userId ?? null }, db: db as unknown as LunoraPaymentDbLike }, config.payment(env))
|
|
1196
1196
|
: paymentStub;
|
|
1197
1197
|
`,configField:`
|
|
1198
1198
|
payment?: (env: Record<string, unknown>) => PaymentsFromContextOptions;`,contextField:`
|
|
1199
|
-
payments,`,stub:
|
|
1199
|
+
payments,`,stub:I("paymentStub: LunoraPayment",'throw new Error("ctx.payments: no payment configured. Pass \\`payment\\` to createShardDO().");',["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"],{cast:" as unknown as LunoraPayment",sync:["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"]})}:{build:"",configField:"",contextField:"",imports:[],stub:""},Br=e=>e?{imports:['import type { X402Pay, X402PayConfig } from "@lunora/x402/pay";','import { lazyX402Pay } from "@lunora/x402/pay";'],build:`
|
|
1200
1200
|
const x402: X402Pay = config.x402
|
|
1201
1201
|
? lazyX402Pay(config.x402(env), { getSecret: (name: string) => secrets.get(name) })
|
|
1202
1202
|
: x402Stub;
|
|
1203
1203
|
`,configField:`
|
|
1204
|
-
x402?: (env: Record<string, unknown>) => X402PayConfig;`,stub:
|
|
1204
|
+
x402?: (env: Record<string, unknown>) => X402PayConfig;`,stub:I("x402Stub: X402Pay",'throw new Error("ctx.x402: no pay rail configured. Pass \\`x402\\` to createShardDO().");',["fetch"],{cast:" as unknown as X402Pay",sync:["fetch"]})}:{build:"",configField:"",imports:[],stub:""},qr=(e,t,n,r,o)=>["AdvisorProcedure","AdvisoryFinding","DatabaseWriterLike","DataMigrationLike","ExportRow",...r?["FlagsResult"]:[],"ImportShardResult","KeyRange","MaskPoliciesResult","MigrationRunResult","QueryReadScope",...n?["QueuesResult"]:[],"RunShardApplyCdcArgs","RunShardExportArgs","RunShardImportArgs","RunShardMigrationArgs","RlsPoliciesResult","RunShardRankBeforeArgs","RunShardRankPageArgs","RunShardWriteArgs","RunShardWriteResult","SchedulerLike",...o?["SearchBackfillProgress"]:[],"TransactionHeadroomTracker","SchemaLike","ShardDOState","ShardRankPageResult","SqlExec","StorageRulesResult","StudioFeaturesResult","SystemReaderStorageLike","TelemetrySink",...t?["WorkflowsResult"]:[],...e?["WriteHook"]:[]],ho=({advisories:e=[],advisorProcedures:t=[],agents:n=[],containers:r=[],env:o,flagKeys:s=[],hasAccessFacade:i=!1,hasAi:a=!1,hasAnalytics:c=!1,hasBrowser:d=!1,hasFlags:p=!1,hasHyperdrive:m=!1,hasImages:y=!1,hasKv:u=!1,hasNotify:l=!1,hasPayments:b=!1,hasPipelines:R=!1,hasR2sql:x=!1,hasVectors:v=!0,hasX402:S=!1,maskMetadata:N,mutators:Q=[],queues:A=[],rlsMetadata:C,schema:w,schemaSnapshot:P,shapes:M=[],storageRules:ie,studioFeatures:le,useUmbrella:Z=!1,workflows:V=[]})=>{const L=ae(Z),ee=Q.length>0,k=M.length>0,Ae=P===void 0?"":vn(P),F=P===void 0?"":`
|
|
1205
1205
|
/** Structural schema snapshot + its content hash, recorded in the shard's \`__lunora_schema_history\` ledger on cold start so the studio can show a schema-version timeline and diff any two versions. */
|
|
1206
|
-
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(
|
|
1207
|
-
`,
|
|
1206
|
+
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(Rn(P))}, json: ${JSON.stringify(Ae)} };
|
|
1207
|
+
`,ce=P===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:de,configField:Oe,contextField:Ie,stub:Ce}=wr(a),ue=Sr(i),H=kr(u),D=xr(p,L.flags),G=$r(s,p,L.flags),te=vr(l),pe=Rr(o),J=Tr(c),j=Nr(y),W=Ar(m),U=Or(d),B=Ir(x),ne=Cr(R),{build:Le,contextField:ve,importLines:Re,specs:he}=_r(A),{build:Ee,contextField:_e,importLines:Se,specs:me}=Lr(r,w.jurisdiction),{build:De,contextField:Pe,importLines:$e,specs:Me}=Er(V),{build:Fe,contextField:ge,importLines:fe,specs:Be}=Dr(n),{build:qe,configField:je,contextField:be,imports:ye,stub:Ze}=Fr(b),{build:h,configField:We,imports:Te,stub:re}=Br(S),Tt=e,Nt=t,At=C??{policies:[],roles:[]},Ot=N??{columns:[]},It=ie??{rules:[]},Ct=le??{analytics:!1,auth:!1,containers:!1,flags:!1,kv:!1,mail:!1,notifications:!1,payments:!1,queues:!1,scheduler:!1,storage:!1,vectors:!1,workflows:!1},{constant:Lt,override:Et}=Pr(V),{constant:_t,override:Dt}=Mr(A),K=v&&w.vectorIndexes.length>0,et=new Set(w.tables.filter(g=>typeof g.shardMode=="object"&&g.shardMode.kind==="shardBy").map(g=>g.name)),Ne=K&&w.vectorIndexes.some(g=>et.has(g.table)),we=w.tables.some(g=>g.shardMode==="global"),Ue=w.tables.some(g=>g.shardMode==="global"&&g.globalBackend==="hyperdrive"),tt=w.tables.some(g=>g.shardMode==="global"&&g.globalBackend!=="hyperdrive"),oe=w.tables.some(g=>g.externalSource!==void 0),nt=w.tables.some(g=>g.memory===!0),Ke=w.tables.some(g=>g.shardMode!=="global"&&g.searchIndexes.length>0);if(tt&&Ue)throw new X("INTERNAL",'lunora codegen: mixing `.global()` (D1) and `.global({ backend: "hyperdrive" })` tables in one app is not supported yet — use a single global backend.');const Qe=w.tables.length>0,Pt=ur(w),Mt=hr(w),Ft=br(w),Bt=pr(w),rt=mr(w),ot=qr(K,V.length>0,A.length>0,p,Ke);k&&ot.push("WhereInput");const at=yr(we),qt=k?`
|
|
1208
1208
|
protected override resolveShape(name: string, args: Record<string, unknown>, identity?: { identity?: Record<string, unknown>; userId?: string }): { columns?: readonly string[]; effectiveWhere?: WhereInput; global?: boolean; table: string } | undefined {
|
|
1209
1209
|
const shape = LUNORA_SHAPES[name];
|
|
1210
1210
|
|
|
@@ -1256,25 +1256,25 @@ const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.st
|
|
|
1256
1256
|
|
|
1257
1257
|
return { columns: shape.columns, effectiveWhere, global: isGlobal, table: shape.table };
|
|
1258
1258
|
}
|
|
1259
|
-
`:"",
|
|
1259
|
+
`:"",jt=ee?`
|
|
1260
1260
|
protected override isCustomMutator(functionPath: string): boolean {
|
|
1261
1261
|
return LUNORA_MUTATOR_PATHS.has(functionPath);
|
|
1262
1262
|
}
|
|
1263
|
-
`:"",
|
|
1264
|
-
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",
|
|
1265
|
-
d1?: (env: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1266
|
-
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1267
|
-
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",
|
|
1263
|
+
`:"",Wt=k?"\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":"",Ut=k?"assertShapeShardable, ":"",ke=[`import type { ${ot.join(", ")} } from "${L.do}";`,`import { applyCdcChanges, ${Ke?"backfillSearchIndexes, ":""}buildReprojectionMigration, ${nt?"clearMemoryTables, ":""}${Ut}createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, ${oe?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}markUnvouchableReads, ${Ne?"ROOT_SHARD_NAME, ":""}runDataMigration, runShardMigrations, ${at.importFragment}ShardDO as ShardDOBase } from "${L.do}";`,...oe?[`import type { ExternalSourceLike, SourceClientLike, TraceRefLike } from "${L.do}";`]:[],k?`import { asBucketStorage, beginDeferredSchedules, buildRlsReadRegistry, composeShapeReadWhere, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${L.server}";`:`import { asBucketStorage, beginDeferredSchedules, createSecrets, flushDeferredDeletes, LunoraError, withDeferredDeletes, withDeferredSchedules } from "${L.server}";`];Qe&&ke.push(`import { bindOrm, bindTableFacade } from "${L.server}";`),K&&ke.push('import type { SchemaLike as VectorSchemaLike, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectors, createVectorSyncHook } from "@lunora/bindings/vectors";'),a&&ke.push('import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'),ke.push(...ue.importLines,...H.importLines,...D.importLines,...te.importLines,...pe.importLines,...J.importLines,...j.importLines,...W.importLines,...U.importLines,...B.importLines,...ne.importLines,...Se,...$e,...Re,...fe,...ye,...Te,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...ee?["LUNORA_MUTATOR_PATHS"]:[],...k?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const Kt=K?`
|
|
1264
|
+
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",Qt=tt?`
|
|
1265
|
+
d1?: (env: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string }) => DatabaseWriterLike | undefined;`:"",Vt=Ue?`
|
|
1266
|
+
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",Ht=oe?`
|
|
1267
|
+
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",Gt='throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");',Jt='throw new Error("ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().");',zt='throw new Error("ctx.scheduler: no scheduler configured. Pass `scheduler` to createShardDO().");',Yt='throw new Error("ctx.storage: no storage configured. Pass `storage` to createShardDO().");',Xt=we?I("globalDbStub: DatabaseWriterLike",Gt,["aggregate","count","delete","findFirst","findFirstOrThrow","findMany","get","groupBy","insert","normalizeId","patch","query","rank","rankPage","replace"],{sync:["normalizeId","query"]}):"",Zt=K?I("vectorsStub: VectorSearchLike",Jt,["deleteByIds","getByIds","query","upsert","upsertNow"]):"",en=Ne?`
|
|
1268
1268
|
const vectorShardKey = this.currentShardKey();
|
|
1269
|
-
`:"",
|
|
1269
|
+
`:"",tn=Ne?"namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, ":"",nn=Ne?`, { namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, shardedIndexNames: [${w.vectorIndexes.filter(g=>et.has(g.table)).map(g=>JSON.stringify(g.name)).join(", ")}] }`:"",rn=K?`
|
|
1270
1270
|
let vectors: VectorSearchLike;
|
|
1271
1271
|
let onWrite: WriteHook | undefined;
|
|
1272
1272
|
|
|
1273
1273
|
if (config.vectors) {
|
|
1274
1274
|
const lunora = createVectors({ indexes: config.vectors(env) });
|
|
1275
|
-
${
|
|
1276
|
-
vectors = createContextVectors(lunora${
|
|
1277
|
-
onWrite = createVectorSyncHook({ ${
|
|
1275
|
+
${en}
|
|
1276
|
+
vectors = createContextVectors(lunora${nn});
|
|
1277
|
+
onWrite = createVectorSyncHook({ ${tn}schema: schema as unknown as VectorSchemaLike, vectors });
|
|
1278
1278
|
} else {
|
|
1279
1279
|
vectors = vectorsStub;
|
|
1280
1280
|
onWrite = undefined;
|
|
@@ -1286,7 +1286,7 @@ ${Zt}
|
|
|
1286
1286
|
// \`__cdc_log\`. Wrapped AFTER \`onWrite\` is built so the write-through
|
|
1287
1287
|
// vector-sync hook keeps calling the bare facade.
|
|
1288
1288
|
vectors = markUnvouchableReads(vectors, options.onRead, ["getByIds", "query"]);
|
|
1289
|
-
`:"",
|
|
1289
|
+
`:"",on=`{
|
|
1290
1290
|
...this.ctxDbTuning(),
|
|
1291
1291
|
auth: { identity: identity ?? null, userId: userId ?? null },
|
|
1292
1292
|
broadcast: (delta) => {
|
|
@@ -1317,14 +1317,14 @@ ${Zt}
|
|
|
1317
1317
|
// Left \`undefined\` when there is no scope so \`createShardCtxDb\`
|
|
1318
1318
|
// keeps its own "degrade a provable slice to a whole-table dep"
|
|
1319
1319
|
// fallback rather than reporting into a no-op.
|
|
1320
|
-
onReadRange: options.onReadRange ?? (options.scope === undefined ? undefined : this.getCtxDbReadRangeHook(options.scope)),${
|
|
1320
|
+
onReadRange: options.onReadRange ?? (options.scope === undefined ? undefined : this.getCtxDbReadRangeHook(options.scope)),${K?`
|
|
1321
1321
|
onWrite,`:""}
|
|
1322
1322
|
scheduler,
|
|
1323
1323
|
schema: schema as unknown as SchemaLike,
|
|
1324
1324
|
sql: this.sql as SqlExec,
|
|
1325
1325
|
storage,${we?`
|
|
1326
1326
|
globalDb,`:""}
|
|
1327
|
-
}`,
|
|
1327
|
+
}`,an=` /**
|
|
1328
1328
|
* The bare writer every admin/maintenance entry point writes through.
|
|
1329
1329
|
*
|
|
1330
1330
|
* Admin and maintenance writes go through the SAME reactive-cache hooks as a
|
|
@@ -1356,11 +1356,11 @@ ${Zt}
|
|
|
1356
1356
|
schema: schema as unknown as SchemaLike,
|
|
1357
1357
|
sql: this.sql as SqlExec,
|
|
1358
1358
|
});
|
|
1359
|
-
}`,
|
|
1360
|
-
vectors,`:"",
|
|
1361
|
-
orm: bindOrm(facade),`:"",Ve=Ue?"config.hyperdriveGlobal":"config.d1",
|
|
1359
|
+
}`,z=(g="")=>` const writer = this.adminWriter(${g});`,sn=K?`
|
|
1360
|
+
vectors,`:"",ln=Qe?`
|
|
1361
|
+
orm: bindOrm(facade),`:"",Ve=Ue?"config.hyperdriveGlobal":"config.d1",cn=we?` const globalRequest = { ...this.globalCdcOptions(config.cdc ?? false), bookmark: this.getInboundBookmark(), identity, onBookmark: (bookmarkValue: string | undefined) => { this.setOutboundBookmark(bookmarkValue); }, userId };
|
|
1362
1362
|
const globalDb: DatabaseWriterLike = ${Ve}?.(env, globalRequest) ?? globalDbStub;
|
|
1363
|
-
`:"",
|
|
1363
|
+
`:"",dn=k&&we?`
|
|
1364
1364
|
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 }>> {
|
|
1365
1365
|
const env = this.env as Record<string, unknown>;
|
|
1366
1366
|
// A shape read performs no writes, so the widened request only needs
|
|
@@ -1405,17 +1405,17 @@ ${Zt}
|
|
|
1405
1405
|
|
|
1406
1406
|
return globalDb.cdcChangedTables?.(sinceSeq, { cursorOnly });
|
|
1407
1407
|
}
|
|
1408
|
-
`:"",
|
|
1408
|
+
`:"",un=oe?`
|
|
1409
1409
|
const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
|
|
1410
1410
|
const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
1411
|
-
`:"",
|
|
1411
|
+
`:"",pn=`
|
|
1412
1412
|
protected override async runShardInit(): Promise<void> {
|
|
1413
1413
|
this.ensureMigrated();
|
|
1414
1414
|
${nt?` clearMemoryTables(this.sql as SqlExec, schema as unknown as SchemaLike);
|
|
1415
1415
|
`:""}
|
|
1416
1416
|
await this.dispatchShardInit();
|
|
1417
1417
|
}
|
|
1418
|
-
`,
|
|
1418
|
+
`,hn=oe?`
|
|
1419
1419
|
protected override async pollExternalSources(trace?: TraceRefLike): Promise<number | undefined> {
|
|
1420
1420
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1421
1421
|
const sourced = Object.entries((schema as unknown as SchemaLike).tables)
|
|
@@ -1555,7 +1555,7 @@ ${nt?` clearMemoryTables(this.sql as SqlExec, schema as unknown as Sc
|
|
|
1555
1555
|
|
|
1556
1556
|
return nextDueAt;
|
|
1557
1557
|
}
|
|
1558
|
-
`:"",
|
|
1558
|
+
`:"",mn=rt.length>0,gn=`
|
|
1559
1559
|
public constructor(state: ShardDOState, env: unknown) {
|
|
1560
1560
|
super(state, env, {
|
|
1561
1561
|
// Every writer this file builds spreads the ctxDbTuning() slice —
|
|
@@ -1578,7 +1578,7 @@ ${oe?`
|
|
|
1578
1578
|
if (autoSourced) {
|
|
1579
1579
|
void this.scheduleSourcePoll();
|
|
1580
1580
|
}
|
|
1581
|
-
`:""}${
|
|
1581
|
+
`:""}${mn?`
|
|
1582
1582
|
if (LUNORA_TTL_SWEEPS.length > 0) {
|
|
1583
1583
|
void this.scheduleTtlSweep();
|
|
1584
1584
|
}
|
|
@@ -1591,22 +1591,22 @@ ${oe?`
|
|
|
1591
1591
|
protected override isPaidFunction(functionPath: string): boolean {
|
|
1592
1592
|
return LUNORA_FUNCTIONS[functionPath]?.x402 !== undefined;
|
|
1593
1593
|
}
|
|
1594
|
-
`,
|
|
1594
|
+
`,fn=Qe?`
|
|
1595
1595
|
const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
|
|
1596
|
-
${
|
|
1596
|
+
${w.tables.map(g=>` facade[${JSON.stringify(g.name)}] = bindTableFacade(db, ${JSON.stringify(g.name)});`).join(`
|
|
1597
1597
|
`)}
|
|
1598
|
-
`:"",
|
|
1598
|
+
`:"",bn=`${ue.build}${H.build}${D.build}${J.build}${pe.build}
|
|
1599
1599
|
const secrets = createSecrets(env);
|
|
1600
|
-
`,
|
|
1601
|
-
secrets,`,
|
|
1600
|
+
`,yn=`${ue.contextField}${H.contextField}${D.contextField}${te.contextField}${J.contextField}${pe.contextField}
|
|
1601
|
+
secrets,`,wn=te.build,st=y||m||d||x||R||S,kn=st?`
|
|
1602
1602
|
// ActionCtx-only helpers (external, non-deterministic I/O): constructed
|
|
1603
1603
|
// and attached only for an \`action\` so query/mutation ctx never carry them.
|
|
1604
1604
|
if (isAction) {
|
|
1605
|
-
${
|
|
1605
|
+
${j.build}${W.build}${U.build}${B.build}${ne.build}${h}${[...y?[" ctx.images = images;"]:[],...m?[" ctx.sql = sql;"]:[],...d?[" ctx.browser = browser;"]:[],...x?[" ctx.r2sql = r2sql;"]:[],...R?[" ctx.pipelines = pipelines;"]:[],...S?[" ctx.x402 = x402;"]:[]].join(`
|
|
1606
1606
|
`)}
|
|
1607
1607
|
}
|
|
1608
|
-
`:"",
|
|
1609
|
-
`:"";return`${
|
|
1608
|
+
`:"",xn=st?` const isAction = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind === "action";
|
|
1609
|
+
`:"";return`${$}${ke.join(`
|
|
1610
1610
|
`)}
|
|
1611
1611
|
|
|
1612
1612
|
type FunctionKind = "action" | "mutation" | "query";
|
|
@@ -1616,41 +1616,41 @@ interface FunctionReference {
|
|
|
1616
1616
|
}
|
|
1617
1617
|
|
|
1618
1618
|
/** Foreign-key columns per table (\`v.id("target")\` fields) for the data browser. */
|
|
1619
|
-
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(
|
|
1619
|
+
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(Pt,void 0,4)};
|
|
1620
1620
|
|
|
1621
1621
|
/** Declared indexes per table (secondary, search, geo, rank, vector) for the schema viewer. */
|
|
1622
|
-
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(
|
|
1622
|
+
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(Mt,void 0,4)};
|
|
1623
1623
|
|
|
1624
1624
|
/** Columns per table (typed, with PK/FK markers) for the studio's schema diagram, served via \`__lunora_admin__:describeTable\`. */
|
|
1625
1625
|
const LUNORA_TABLE_COLUMNS: Record<
|
|
1626
1626
|
string,
|
|
1627
1627
|
Array<{ bucket?: string; enumValues?: string[]; isStorage?: boolean; name: string; nullable?: boolean; optional: boolean; pk?: boolean; ref?: string; type: string }>
|
|
1628
|
-
> = ${JSON.stringify(
|
|
1628
|
+
> = ${JSON.stringify(Ft,void 0,4)};
|
|
1629
1629
|
|
|
1630
1630
|
/** Storage-key columns per table (\`v.storage(...)\` fields) for the file browser's records↔files join. */
|
|
1631
|
-
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(
|
|
1631
|
+
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(Bt,void 0,4)};
|
|
1632
1632
|
|
|
1633
1633
|
/** Declarative TTL policies (\`.ttl(field, { after? })\`) the DO alarm sweep auto-expires rows for. */
|
|
1634
1634
|
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(rt,void 0,4)};
|
|
1635
1635
|
|
|
1636
1636
|
/** Static schema advisories (computed by @lunora/advisor at codegen time) served via \`__lunora_admin__:getAdvisories\`. */
|
|
1637
|
-
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(
|
|
1637
|
+
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(Tt,void 0,4)};
|
|
1638
1638
|
|
|
1639
1639
|
/** Every declared procedure (discovered by @lunora/codegen) served via \`__lunora_admin__:getAdvisorProcedures\` — the health map's denominator. */
|
|
1640
|
-
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(
|
|
1640
|
+
const LUNORA_ADVISOR_PROCEDURES: AdvisorProcedure[] = ${JSON.stringify(Nt,void 0,4)};
|
|
1641
1641
|
|
|
1642
1642
|
/** Read-only RLS metadata (policies + roles discovered from \`.use(rls(...))\` chains) served via \`__lunora_admin__:rlsPolicies\` for the studio's RLS inspector. */
|
|
1643
|
-
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(
|
|
1643
|
+
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(At,void 0,4)};
|
|
1644
1644
|
|
|
1645
1645
|
/** Read-only masking metadata (table + column + strategy discovered from \`.use(mask(...))\` chains) served via \`__lunora_admin__:maskPolicies\` for the studio's data-browser mask preview. */
|
|
1646
|
-
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(
|
|
1646
|
+
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(Ot,void 0,4)};
|
|
1647
1647
|
|
|
1648
1648
|
/** Read-only storage access-rule metadata (discovered from \`.use(storageRules(...))\` chains) served via \`__lunora_admin__:storageRules\` for the studio's access-rules view. */
|
|
1649
|
-
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(
|
|
1649
|
+
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(It,void 0,4)};
|
|
1650
1650
|
|
|
1651
1651
|
/** Which optional package-backed features this app wires up (discovered from imports / \`ctx.*\` reads / schema signals) served via \`__lunora_admin__:studioFeatures\` so the studio hides nav pages whose package isn't enabled. */
|
|
1652
|
-
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(
|
|
1653
|
-
${
|
|
1652
|
+
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(Ct,void 0,4)};
|
|
1653
|
+
${F}${G.constant}${Wt}${Lt}${_t}${me}${Me}${he}${Be}
|
|
1654
1654
|
export interface ShardDOConfig {
|
|
1655
1655
|
/** Opt into change-data-capture: records a post-image to \`__cdc_log\` on every write (backs streaming export + replay-PITR). */
|
|
1656
1656
|
cdc?: boolean;
|
|
@@ -1664,9 +1664,9 @@ export interface ShardDOConfig {
|
|
|
1664
1664
|
observability?: (env: Record<string, unknown>) => TelemetrySink | undefined;
|
|
1665
1665
|
/** \`unknown\` because \`@lunora/scheduler\`'s \`Scheduler\` is not assignable to \`SchedulerLike\`; the shard casts it. */
|
|
1666
1666
|
scheduler?: (env: Record<string, unknown>) => unknown;
|
|
1667
|
-
storage?: (env: Record<string, unknown>) => unknown;${
|
|
1667
|
+
storage?: (env: Record<string, unknown>) => unknown;${Kt}${Oe}${H.configField}${D.configField}${J.configField}${j.configField}${W.configField}${U.configField}${B.configField}${ne.configField}${je}${We}${Qt}${Vt}${Ht}
|
|
1668
1668
|
}
|
|
1669
|
-
${
|
|
1669
|
+
${I("schedulerStub",zt,["cancel","runAfter","runAt"])}${I("storageStub",Yt,["delete","download","getMetadata","getSignedUrl","getUrl","head","list","upload"],{sync:["getUrl"]})}${Xt}${un}${Zt}${Ce}${H.stub}${D.stub}${J.stub}${j.stub}${W.stub}${U.stub}${B.stub}${ne.stub}${Ze}${re}
|
|
1670
1670
|
// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
|
|
1671
1671
|
// referencing call fails loudly with a clear error instead of overflowing the
|
|
1672
1672
|
// stack. Tracked across the awaited handler chain (one DO invocation is
|
|
@@ -1740,7 +1740,7 @@ const dispatchRun = async (
|
|
|
1740
1740
|
* from the worker entry so wrangler binds it by name.
|
|
1741
1741
|
*/
|
|
1742
1742
|
export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOState, env: unknown) => ShardDOBase =>
|
|
1743
|
-
class extends ShardDOBase {${
|
|
1743
|
+
class extends ShardDOBase {${gn}
|
|
1744
1744
|
private migrated = false;
|
|
1745
1745
|
|
|
1746
1746
|
public override async handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker, scope?: QueryReadScope): Promise<unknown> {
|
|
@@ -1932,11 +1932,11 @@ ${at.override}
|
|
|
1932
1932
|
iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath, identity }), args, signal),
|
|
1933
1933
|
};
|
|
1934
1934
|
}
|
|
1935
|
-
${
|
|
1935
|
+
${jt}${qt}${dn}${hn}
|
|
1936
1936
|
protected override lifecycleHookPaths(event: "connect" | "disconnect" | "init" | "reactor"): readonly string[] {
|
|
1937
1937
|
return LUNORA_LIFECYCLE_HOOKS[event];
|
|
1938
1938
|
}
|
|
1939
|
-
${
|
|
1939
|
+
${pn}
|
|
1940
1940
|
// One \`onQueryChange\` dispatch. Mirrors \`executeSubscription\` — the
|
|
1941
1941
|
// socket-terminated half of the same reactivity — and differs only in who
|
|
1942
1942
|
// consumes the result: the base's \`dispatchReactors\` stores the digest as
|
|
@@ -2015,7 +2015,7 @@ ${un}
|
|
|
2015
2015
|
protected override studioFeatures(): StudioFeaturesResult {
|
|
2016
2016
|
return LUNORA_STUDIO_FEATURES;
|
|
2017
2017
|
}
|
|
2018
|
-
${
|
|
2018
|
+
${G.evaluateOverride}${G.subscriptionOverride}${Et}${Dt}
|
|
2019
2019
|
protected override advisories(): AdvisoryFinding[] {
|
|
2020
2020
|
return LUNORA_ADVISORIES;
|
|
2021
2021
|
}
|
|
@@ -2024,7 +2024,7 @@ ${W.evaluateOverride}${W.subscriptionOverride}${Lt}${_t}
|
|
|
2024
2024
|
return LUNORA_ADVISOR_PROCEDURES;
|
|
2025
2025
|
}
|
|
2026
2026
|
|
|
2027
|
-
${
|
|
2027
|
+
${an}
|
|
2028
2028
|
|
|
2029
2029
|
protected override async runShardDataMigration(args: RunShardMigrationArgs): Promise<MigrationRunResult> {
|
|
2030
2030
|
this.ensureMigrated();
|
|
@@ -2041,7 +2041,7 @@ ${on}
|
|
|
2041
2041
|
throw new LunoraError("MIGRATION_NOT_FOUND", \`data migration "\${args.id}" is not registered\`, { status: 404 });
|
|
2042
2042
|
}
|
|
2043
2043
|
|
|
2044
|
-
${
|
|
2044
|
+
${z()}
|
|
2045
2045
|
|
|
2046
2046
|
return runDataMigration({
|
|
2047
2047
|
batchSize: args.batchSize,
|
|
@@ -2074,7 +2074,7 @@ ${Y()}
|
|
|
2074
2074
|
|
|
2075
2075
|
this.ensureMigrated();
|
|
2076
2076
|
|
|
2077
|
-
${
|
|
2077
|
+
${z("headroom ?? this.transactionHeadroom()")}
|
|
2078
2078
|
|
|
2079
2079
|
if (args.op === "insert") {
|
|
2080
2080
|
const id = await writer.insert(args.table, args.doc ?? {});
|
|
@@ -2125,7 +2125,7 @@ ${Y("headroom ?? this.transactionHeadroom()")}
|
|
|
2125
2125
|
protected override async runShardExport(args: RunShardExportArgs): Promise<ExportRow[]> {
|
|
2126
2126
|
this.ensureMigrated();
|
|
2127
2127
|
|
|
2128
|
-
${
|
|
2128
|
+
${z()}
|
|
2129
2129
|
|
|
2130
2130
|
const rows: ExportRow[] = [];
|
|
2131
2131
|
|
|
@@ -2142,7 +2142,7 @@ ${Y()}
|
|
|
2142
2142
|
protected override async runShardImport(args: RunShardImportArgs): Promise<ImportShardResult> {
|
|
2143
2143
|
this.ensureMigrated();
|
|
2144
2144
|
|
|
2145
|
-
${
|
|
2145
|
+
${z()}
|
|
2146
2146
|
|
|
2147
2147
|
// \`importShardRows\` inserts with \`allowExplicitId\`, so a source
|
|
2148
2148
|
// database's \`_id\`s carry across verbatim and every foreign key
|
|
@@ -2153,7 +2153,7 @@ ${Y()}
|
|
|
2153
2153
|
protected override async runShardRankBefore(args: RunShardRankBeforeArgs): Promise<{ before: number; total: number }> {
|
|
2154
2154
|
this.ensureMigrated();
|
|
2155
2155
|
|
|
2156
|
-
${
|
|
2156
|
+
${z()}
|
|
2157
2157
|
|
|
2158
2158
|
// \`rankBefore\` is optional on \`DatabaseWriterLike\` (the D1 twin omits it),
|
|
2159
2159
|
// but the shard writer from \`createShardCtxDb\` always defines it.
|
|
@@ -2171,7 +2171,7 @@ ${Y()}
|
|
|
2171
2171
|
protected override async runShardRankPage(args: RunShardRankPageArgs): Promise<ShardRankPageResult> {
|
|
2172
2172
|
this.ensureMigrated();
|
|
2173
2173
|
|
|
2174
|
-
${
|
|
2174
|
+
${z()}
|
|
2175
2175
|
|
|
2176
2176
|
// \`rankPageRows\` is optional on \`DatabaseWriterLike\` (the D1 twin omits it),
|
|
2177
2177
|
// but the shard writer from \`createShardCtxDb\` always defines it. The sort
|
|
@@ -2192,7 +2192,7 @@ ${Y()}
|
|
|
2192
2192
|
protected override async runShardApplyCdc(args: RunShardApplyCdcArgs): Promise<{ applied: number }> {
|
|
2193
2193
|
this.ensureMigrated();
|
|
2194
2194
|
|
|
2195
|
-
${
|
|
2195
|
+
${z()}
|
|
2196
2196
|
|
|
2197
2197
|
await applyCdcChanges(writer, args.changes);
|
|
2198
2198
|
|
|
@@ -2204,7 +2204,7 @@ ${Y()}
|
|
|
2204
2204
|
return;
|
|
2205
2205
|
}
|
|
2206
2206
|
|
|
2207
|
-
runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${
|
|
2207
|
+
runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${ce} });
|
|
2208
2208
|
this.migrated = true;
|
|
2209
2209
|
}
|
|
2210
2210
|
${Ke?`
|
|
@@ -2226,7 +2226,7 @@ ${Ke?`
|
|
|
2226
2226
|
// dispatch path) fall back to the per-request fields as before.
|
|
2227
2227
|
const userId = options.identity ? options.identity.userId : this.getCurrentUserId();
|
|
2228
2228
|
const identity = options.identity ? options.identity.identity : this.getCurrentIdentity();
|
|
2229
|
-
${
|
|
2229
|
+
${rn}${de}${bn}${Ee}${De}${Le}${Fe}
|
|
2230
2230
|
// Which dispatch this ctx belongs to. Drives the two deferral facades
|
|
2231
2231
|
// below and the \`ctx.run*\` caller guard; a ctx built for an
|
|
2232
2232
|
// admin/lifecycle path has no registered function, and so no kind.
|
|
@@ -2313,13 +2313,13 @@ ${nn}${de}${fn}${he}${me}${Ce}${Me}
|
|
|
2313
2313
|
// so both write to the same trace.
|
|
2314
2314
|
const span = this.makeDispatchSpan(traceAnchor, observability);
|
|
2315
2315
|
|
|
2316
|
-
${
|
|
2316
|
+
${cn} // \`ctx.db\`, wrapped in automatic instrumentation: by default this
|
|
2317
2317
|
// adds aggregate counters (call count, total time, per-operation
|
|
2318
2318
|
// breakdown) to the wide event rather than a span per call, so a
|
|
2319
2319
|
// handler making hundreds of queries stays readable. See
|
|
2320
2320
|
// \`instrumentDatabase\` for the \`"spans"\` / \`"off"\` levels.
|
|
2321
|
-
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${
|
|
2322
|
-
${
|
|
2321
|
+
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${on}), logFunctionPath, traceAnchor, observability);
|
|
2322
|
+
${fn}${qe}
|
|
2323
2323
|
|
|
2324
2324
|
// \`ctx.trace\` / \`ctx.metrics\`: spans and measurements to the same sink.
|
|
2325
2325
|
// The trace anchor is threaded explicitly for the same reason \`identity\`
|
|
@@ -2327,7 +2327,7 @@ ${gn}${Be}
|
|
|
2327
2327
|
// writing mutation's trace from the shared per-request field.
|
|
2328
2328
|
const trace = this.makeTracer(logFunctionPath, observability, traceAnchor);
|
|
2329
2329
|
const metrics = this.makeMetrics(logFunctionPath, observability);
|
|
2330
|
-
${
|
|
2330
|
+
${wn}
|
|
2331
2331
|
// \`ctx.now\`: the wall-clock instant (epoch ms) this function began,
|
|
2332
2332
|
// captured ONCE so the whole handler body sees a single stable value.
|
|
2333
2333
|
// Query/mutation handlers must be deterministic (they may be re-run on
|
|
@@ -2350,13 +2350,13 @@ ${yn}
|
|
|
2350
2350
|
ip: this.getCurrentIp(),
|
|
2351
2351
|
log,
|
|
2352
2352
|
metrics,
|
|
2353
|
-
now,${
|
|
2353
|
+
now,${ln}
|
|
2354
2354
|
scheduler,
|
|
2355
2355
|
span,
|
|
2356
2356
|
storage: contextStorage,
|
|
2357
|
-
trace,${
|
|
2357
|
+
trace,${sn}${Ie}${yn}${be}${_e}${Pe}${ve}${ge}
|
|
2358
2358
|
};
|
|
2359
|
-
${
|
|
2359
|
+
${xn}${kn}
|
|
2360
2360
|
ctx.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, ctx, contextKind);
|
|
2361
2361
|
// The composed mutation runs under the SAME wrapper the top-level RPC
|
|
2362
2362
|
// uses, so "do the transactional work in a mutation and call it from the
|
|
@@ -2389,21 +2389,21 @@ ${kn}${wn}
|
|
|
2389
2389
|
return ctx;
|
|
2390
2390
|
}
|
|
2391
2391
|
};
|
|
2392
|
-
`},Xe=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:
|
|
2392
|
+
`},Xe=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:O(e)};case"bigint":return{builder:"blob",mode:"bigint",notNull:!0};case"boolean":return{builder:"integer",mode:"boolean",notNull:!0};case"bytes":return{builder:"blob",mode:"buffer",notNull:!0};case"date":case"timestamp":return{builder:"integer",notNull:!0};case"from":return{builder:"text",notNull:!0,typeAnnotation:O(e)};case"id":return{builder:"text",notNull:!0};case"literal":{const t=e.literalValue??"";return t.startsWith('"')||t.startsWith("'")?{builder:"text",notNull:!0}:t==="true"||t==="false"?{builder:"integer",mode:"boolean",notNull:!0}:t==="null"?{builder:"text",notNull:!0}:{builder:"real",notNull:!0}}case"null":return{builder:"text",notNull:!0};case"number":return{builder:"real",notNull:!0};case"optional":return{...e.inner?Xe(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},$t=(e,t)=>{const n=se(e);return n.kind==="id"&&n.tableName!==void 0&&t.has(n.tableName)?n.tableName:void 0},jr=(e,t,n)=>{f(e,"drizzle column name");const r=Xe(t),o=r.mode?`, { mode: "${r.mode}" }`:"";let s=`${r.builder}("${e}"${o})`;r.typeAnnotation&&(s+=`.$type<${r.typeAnnotation}>()`);const i=$t(t,n);return i!==void 0&&(s+=`.references((): AnySQLiteColumn => ${i}._id)`),r.notNull&&(s+=".notNull()"),s},Wr=e=>{const t=e.unique?"uniqueIndex":"index",n=e.fields.map(r=>(f(r,"drizzle index field"),`t.${r}`)).join(", ");return` ${Y(e.name)}: ${t}(${JSON.stringify(e.name)}).on(${n}),`},Ur=(e,t)=>{f(e.name,"table name");const n=[' _id: text("_id").primaryKey(),',' _creationTime: integer("_creationTime").notNull(),',...Object.entries(e.shape).map(([o,s])=>` ${o}: ${jr(o,s,t)},`)].join(`
|
|
2393
2393
|
`),r=e.indexes.length>0?`, (t) => ({
|
|
2394
|
-
${e.indexes.map(o=>
|
|
2394
|
+
${e.indexes.map(o=>Wr(o)).join(`
|
|
2395
2395
|
`)}
|
|
2396
2396
|
})`:"";return`export const ${e.name} = sqliteTable("${e.name}", {
|
|
2397
2397
|
${n}
|
|
2398
|
-
}${r});`},
|
|
2399
|
-
`;const n=ae(t),r=new Set(e.map(m=>m.name)),{columns:o,indexes:s,needsAnyColumn:i,needsId:a}=
|
|
2398
|
+
}${r});`},Kr=e=>e.typeAnnotation?.includes('Id<"')??!1,Qr=(e,t)=>{const n=new Set(["integer","sqliteTable","text"]),r=new Set;let o=!1,s=!1;for(const i of e){for(const a of Object.values(i.shape)){const c=Xe(a);n.add(c.builder),s=s||Kr(c),o=o||$t(a,t)!==void 0}for(const a of i.indexes)r.add(a.unique?"uniqueIndex":"index")}return{columns:[...n].toSorted((i,a)=>i.localeCompare(a)),indexes:[...r].toSorted((i,a)=>i.localeCompare(a)),needsAnyColumn:o,needsId:s}},ct=(e,t=!1)=>{if(e.length===0)return`${$}export {};
|
|
2399
|
+
`;const n=ae(t),r=new Set(e.map(m=>m.name)),{columns:o,indexes:s,needsAnyColumn:i,needsId:a}=Qr(e,r),c=[...s,...o].toSorted((m,y)=>m.localeCompare(y)),d=e.map(m=>Ur(m,r)).join(`
|
|
2400
2400
|
|
|
2401
2401
|
`),p=[i?`import type { AnySQLiteColumn } from "${n.serverDrizzle}";
|
|
2402
2402
|
`:"",a?`import type { Id } from "./dataModel.js";
|
|
2403
|
-
`:""].join("");return`${
|
|
2403
|
+
`:""].join("");return`${$}import { ${c.join(", ")} } from "${n.serverDrizzle}";
|
|
2404
2404
|
${p}
|
|
2405
2405
|
${d}
|
|
2406
|
-
`},
|
|
2406
|
+
`},mo=(e,t=!1)=>{const n=e.tables.filter(o=>o.shardMode==="global"),r=e.tables.filter(o=>o.shardMode!=="global");return{global:E(ct(n,t),Je),shard:E(ct(r,t),Je)}},go=e=>{const t=new Map;for(const i of e){const a=t.get(i.cron);a?a.push(i):t.set(i.cron,[i])}const n=[...t.keys()].map(i=>` ${JSON.stringify(i)},`).join(`
|
|
2407
2407
|
`),r=n.length>0?`
|
|
2408
2408
|
${n}
|
|
2409
2409
|
`:"",o=[...t.entries()].map(([i,a])=>{const c=a.map(d=>{const p=d.workflow?`workflow: ${JSON.stringify(d.workflow.binding)}`:`functionPath: ${JSON.stringify(d.functionPath)}`;return` { name: ${JSON.stringify(d.name)}, ${p}, args: ${JSON.stringify(d.args)} },`}).join(`
|
|
@@ -2412,7 +2412,7 @@ ${c}
|
|
|
2412
2412
|
],`}).join(`
|
|
2413
2413
|
`),s=o.length>0?`
|
|
2414
2414
|
${o}
|
|
2415
|
-
`:"";return`${
|
|
2415
|
+
`:"";return`${$}/**
|
|
2416
2416
|
* One scheduled cron invocation. Exactly one target is set: \`functionPath\` is
|
|
2417
2417
|
* the \`namespace:fn\` dispatch ref (matches \`__lunoraRef\`), invoked on the
|
|
2418
2418
|
* shard; \`workflow\` is a \`WORKFLOW_*\` binding name whose durable workflow is
|
|
@@ -2437,10 +2437,10 @@ export const LUNORA_CRON_TRIGGERS: ReadonlyArray<string> = [${r}];
|
|
|
2437
2437
|
* looks up \`event.cron\` here and dispatches every job in the list.
|
|
2438
2438
|
*/
|
|
2439
2439
|
export const LUNORA_CRONS: Record<string, ReadonlyArray<LunoraCronJob>> = {${s}};
|
|
2440
|
-
`},
|
|
2440
|
+
`},fo=e=>{const t=[...e].toSorted((r,o)=>r.name.localeCompare(o.name)).map(r=>{const o=[`name: ${JSON.stringify(r.name)}`,`table: ${JSON.stringify(r.table)}`];return r.field!==void 0&&o.push(`field: ${JSON.stringify(r.field)}`),r.dimensions!==void 0&&o.push(`dimensions: ${JSON.stringify(r.dimensions)}`),r.metric!==void 0&&o.push(`metric: ${JSON.stringify(r.metric)}`),r.metadata!==void 0&&o.push(`metadata: ${JSON.stringify(r.metadata)}`),` { ${o.join(", ")} },`}).join(`
|
|
2441
2441
|
`),n=t.length>0?`
|
|
2442
2442
|
${t}
|
|
2443
|
-
`:"";return`${
|
|
2443
|
+
`:"";return`${$}/**
|
|
2444
2444
|
* One vector index declared in \`schema.ts\` — an inline \`.vectorize()\` column
|
|
2445
2445
|
* or a standalone \`defineVectorIndex()\`. \`field\` is the source column (absent
|
|
2446
2446
|
* for a \`select\`-derived Shape B index); \`metadata\` lists the row fields
|
|
@@ -2461,4 +2461,4 @@ export interface LunoraVectorIndex {
|
|
|
2461
2461
|
* \`createWorker({ vectorIntrospector })\` to back the studio's vector browser.
|
|
2462
2462
|
*/
|
|
2463
2463
|
export const LUNORA_VECTOR_INDEXES: ReadonlyArray<LunoraVectorIndex> = [${n}];
|
|
2464
|
-
`},
|
|
2464
|
+
`},bo=e=>[...new Set(e.map(t=>t.cron))];export{to as A,Sn as C,$ as G,Gn as U,ro as a,ao as b,lo as c,go as d,uo as e,no as f,mo as g,io as h,so as i,ho as j,fo as k,co as l,bo as m,pr as n,po as o,oo as p};
|