@lunora/codegen 1.0.0-alpha.75 → 1.0.0-alpha.76
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 +190 -136
- package/dist/index.d.ts +190 -136
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/GENERATED_HEADER-CQRdzwf9.mjs +1 -0
- package/dist/packem_shared/{OPENRPC_VERSION-CvVFqUlq.mjs → OPENRPC_VERSION-67sJ7JrS.mjs} +1 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-x_pw6Agi.mjs +3 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-CFhF_hmg.mjs +2 -0
- package/dist/packem_shared/SchemaSnapshotParseError-0KRzSjo4.mjs +14 -0
- package/dist/packem_shared/{buildOpenApiDocument-xYxqrlj1.mjs → buildOpenApiDocument-DeMEuKaw.mjs} +1 -1
- package/dist/packem_shared/{emit-D7VIjvlm.mjs → emit-sQzv_a8t.mjs} +165 -162
- package/dist/packem_shared/{emitApp-CAeIj6e_.mjs → emitApp-D5X1S54W.mjs} +1 -1
- package/package.json +1 -1
- package/dist/packem_shared/GENERATED_HEADER-DV-sQj-R.mjs +0 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-Bj7EusPY.mjs +0 -3
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-Bpf1FGMG.mjs +0 -15
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{agentComponent as Ye}from"@lunora/agent/component";import{LunoraError as
|
|
1
|
+
import{agentComponent as Ye}from"@lunora/agent/component";import{LunoraError as ee}from"@lunora/errors";import{serializeSchemaSnapshot as Vt,hashSchemaSnapshot as Gt}from"./SCHEMA_SNAPSHOT_VERSION-CFhF_hmg.mjs";import{n as v}from"./paths-BmX5O1sG.mjs";const Ze=[{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. */
|
|
@@ -9,44 +9,44 @@ import{agentComponent as Ye}from"@lunora/agent/component";import{LunoraError as
|
|
|
9
9
|
readonly sql: import("@lunora/hyperdrive").SqlClient;`,tier:"action"}},{appMethod:{configKey:"images",doc:"Override the Images binding backing `ctx.images` (defaults to `env.IMAGES`).",method:"images"},contextProperty:"images",key:"images",moduleSpecifier:"@lunora/bindings/images",serverCtxField:{field:`
|
|
10
10
|
/** Cloudflare Images transforms (resize/format/optimize). Non-deterministic — available only in actions. */
|
|
11
11
|
readonly images: import("@lunora/bindings/images").Images;`,tier:"action"}},{appMethod:{configKey:"kv",doc:"Override the Workers KV binding backing `ctx.kv` (defaults to `env.KV`).",method:"kv"},contextProperty:"kv",key:"kv",moduleSpecifier:"@lunora/bindings/kv",serverCtxField:{field:`
|
|
12
|
-
readonly kv: import("@lunora/bindings/kv").Kv;`,tier:"every"}},{key:"mail",moduleSpecifier:"@lunora/mail"},{appMethod:{configKey:"payment",doc:"Wire the payment options backing `ctx.payments`.",method:"payment"},contextProperty:"payments",key:"payments",moduleSpecifier:"@lunora/payment"},{appMethod:{configKey:"x402",doc:"Wire the x402 agent-wallet pay rail backing `ctx.x402` — a payment-enabled `fetch` that answers `402` challenges under a mandatory spend policy (ActionCtx-only; spends real funds).",method:"x402"},contextProperty:"x402",key:"x402",moduleSpecifier:"@lunora/x402/pay"},{contextProperty:"pipelines",key:"pipelines",moduleSpecifier:"@lunora/bindings/pipelines",serverCtxField:{field:`
|
|
12
|
+
readonly kv: import("@lunora/bindings/kv").Kv;`,tier:"every"}},{key:"mail",moduleSpecifier:"@lunora/mail"},{contextProperty:"notify",key:"notify",moduleSpecifier:"@lunora/notify"},{appMethod:{configKey:"payment",doc:"Wire the payment options backing `ctx.payments`.",method:"payment"},contextProperty:"payments",key:"payments",moduleSpecifier:"@lunora/payment"},{appMethod:{configKey:"x402",doc:"Wire the x402 agent-wallet pay rail backing `ctx.x402` — a payment-enabled `fetch` that answers `402` challenges under a mandatory spend policy (ActionCtx-only; spends real funds).",method:"x402"},contextProperty:"x402",key:"x402",moduleSpecifier:"@lunora/x402/pay"},{contextProperty:"pipelines",key:"pipelines",moduleSpecifier:"@lunora/bindings/pipelines",serverCtxField:{field:`
|
|
13
13
|
/** Pipelines ingestion sink (durable, R2-backed). Fire-and-forget and batched; do not read it back in-handler. */
|
|
14
14
|
readonly pipelines: import("@lunora/bindings/pipelines").PipelineClient;`,tier:"action"}},{appMethod:{configKey:"r2sql",doc:"Wire the R2 SQL client backing `ctx.r2sql` — build it with `createR2Sql({ accountId, apiToken, bucket })` (defaults to env `R2_SQL_TOKEN` / `R2_SQL_ACCOUNT_ID` / `R2_SQL_BUCKET`).",method:"r2sql"},contextProperty:"r2sql",key:"r2sql",moduleSpecifier:"@lunora/bindings/r2sql",serverCtxField:{field:`
|
|
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"}],Ht=Ze,zt=new Map(Ht.flatMap(e=>e.serverCtxField?[[e.key,e.serverCtxField]]:[])),cr=Ze.flatMap(e=>"appMethod"in e?[{appMethod:e.appMethod,key:e.key}]:[]),et=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,Xt=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),tt=e=>e.column!==void 0,Yt=(e,t)=>{switch(e){case"bigint":return`if (typeof ${t} !== "bigint") return DEFER;
|
|
19
19
|
`;case"boolean":return`if (typeof ${t} !== "boolean") return DEFER;
|
|
20
20
|
`;case"date":case"number":case"timestamp":return`if (typeof ${t} !== "number" || !Number.isFinite(${t})) return DEFER;
|
|
21
21
|
`;case"null":return`if (${t} !== null) return DEFER;
|
|
22
22
|
`;default:return`if (typeof ${t} !== "string") return DEFER;
|
|
23
|
-
`}},
|
|
24
|
-
`}},Fe=(e,t,n)=>{if(!tt(e)&&!(e.hasRefinement||e.sourceText!==void 0)){if(
|
|
23
|
+
`}},Zt=(e,t)=>{const n=e.literalValue?.trim();if(!(n===void 0||!et.test(n)))return{out:t,pre:`if (${t} !== ${n}) return DEFER;
|
|
24
|
+
`}},Fe=(e,t,n)=>{if(!tt(e)&&!(e.hasRefinement||e.sourceText!==void 0)){if(Xt.has(e.kind))return e.kind==="any"?{out:t,pre:""}:{out:t,pre:Yt(e.kind,t)};switch(e.kind){case"array":return en(e,t,n);case"literal":return Zt(e,t);case"object":return nn(e,t,n);default:return}}},en=(e,t,n)=>{const{inner:r}=e;if(!r)return;const a=n.next(),o=`__arr${String(a)}`,s=`__i${String(a)}`,i=`__e${String(a)}`,l=Fe(r,i,n);if(!l)return;const u=`if (!Array.isArray(${t})) return DEFER;
|
|
25
25
|
const ${o} = new Array(${t}.length);
|
|
26
26
|
for (let ${s} = 0; ${s} < ${t}.length; ${s}++) {
|
|
27
27
|
const ${i} = ${t}[${s}];
|
|
28
28
|
${l.pre}${o}[${s}] = ${l.out};
|
|
29
29
|
}
|
|
30
|
-
`;return{out:o,pre:u}},
|
|
30
|
+
`;return{out:o,pre:u}},tn=(e,t,n,r)=>{const a=JSON.stringify(e);if(t.kind==="optional"){if(t.hasRefinement||t.sourceText!==void 0||tt(t))return;const{inner:s}=t;if(!s)return;const i=Fe(s,n,r);if(!i)return;const l=r.next(),u=`__has${String(l)}`,p=`__val${String(l)}`,b=`let ${u} = false;
|
|
31
31
|
let ${p};
|
|
32
32
|
if (${n} !== undefined) {
|
|
33
33
|
${i.pre}${p} = ${i.out};
|
|
34
34
|
${u} = true;
|
|
35
35
|
}
|
|
36
|
-
`;return{entry:`...(${u} ? { ${a}: ${p} } : {})`,pre:b}}const o=Fe(t,n,r);if(o)return{entry:`${a}: ${o.out}`,pre:o.pre}},nt=(e,t,n)=>{let r="";const a=[];for(const o of Object.keys(e)){const s=e[o];if(!s)return;const i=
|
|
36
|
+
`;return{entry:`...(${u} ? { ${a}: ${p} } : {})`,pre:b}}const o=Fe(t,n,r);if(o)return{entry:`${a}: ${o.out}`,pre:o.pre}},nt=(e,t,n)=>{let r="";const a=[];for(const o of Object.keys(e)){const s=e[o];if(!s)return;const i=tn(o,s,t(o),n);if(!i)return;r+=i.pre,a.push(i.entry)}return{entries:a.join(", "),pre:r}},nn=(e,t,n)=>{const r=e.shape??{},a=nt(r,l=>`${t}[${JSON.stringify(l)}]`,n);if(!a)return;const o=n.next(),s=`__obj${String(o)}`,i=`if (typeof ${t} !== "object" || ${t} === null || Array.isArray(${t})) return DEFER;
|
|
37
37
|
${a.pre}const ${s} = { ${a.entries} };
|
|
38
|
-
`;return{out:s,pre:i}},
|
|
38
|
+
`;return{out:s,pre:i}},rn=e=>{let t=0;const n=nt(e,r=>`source[${JSON.stringify(r)}]`,{next:()=>(t+=1,t)});if(n)return`(source) => {
|
|
39
39
|
if (typeof source !== "object" || source === null || Array.isArray(source)) return DEFER;
|
|
40
40
|
${n.pre}return { ${n.entries} };
|
|
41
41
|
}`},k=`// GENERATED by @lunora/codegen — do not edit.
|
|
42
42
|
// Run \`lunora codegen\` to regenerate.
|
|
43
43
|
|
|
44
|
-
`,
|
|
44
|
+
`,H=(e=!1)=>e?{client:"lunorash/client",do:"lunorash/do",flags:"lunorash/flags",server:"lunorash/server",serverDataModel:"lunorash/server/data-model",serverDrizzle:"lunorash/server/drizzle",serverTypes:"lunorash/server/types",values:"lunorash/values"}:{client:"@lunora/client",do:"@lunora/do",flags:"@lunora/flags",server:"@lunora/server",serverDataModel:"@lunora/server/data-model",serverDrizzle:"@lunora/server/drizzle",serverTypes:"@lunora/server/types",values:"@lunora/values"},rt=/^[A-Za-z_$][\w$]*$/u,an=/^[\w./-]+$/u,m=(e,t)=>{if(!rt.test(e))throw new ee("INTERNAL",`@lunora/codegen: ${t} is not a valid JS identifier: ${JSON.stringify(e)}`)},Ee=e=>e.charAt(0).toUpperCase()+e.slice(1),A=e=>rt.test(e)?e:JSON.stringify(e),on={any:"unknown",bigint:"bigint",boolean:"boolean",bytes:"ArrayBuffer",date:"number",from:"unknown",geoPoint:"{ lat: number; lng: number }",null:"null",number:"number",storage:"string",string:"string",timestamp:"number"},sn=e=>{if(e===void 0)return"unknown";if(!et.test(e))throw new ee("INTERNAL",`@lunora/codegen: v.literal() argument is not a parseable string/number/boolean/null literal: ${JSON.stringify(e)}`);return e},T=e=>{const t=on[e.kind];if(t!==void 0)return t;switch(e.kind){case"array":return`Array<${e.inner?T(e.inner):"unknown"}>`;case"id":{const n=e.tableName??"_unknown_";return m(n,"v.id() table name"),`Id<"${n}">`}case"literal":return sn(e.literalValue);case"object":return e.shape?`{ ${Object.entries(e.shape).map(([n,r])=>`${A(n)}: ${T(r)}`).join("; ")} }`:"Record<string, unknown>";case"optional":return`${e.inner?T(e.inner):"unknown"} | undefined`;case"record":{const n=e.keyType?T(e.keyType):"string",r=e.valueType?T(e.valueType):"unknown";return`Record<${n}, ${r}>`}case"union":return e.members&&e.members.length>0?e.members.map(n=>T(n)).join(" | "):"never";default:return"unknown"}},me=e=>{const t=Object.entries(e);return t.length===0?"{}":`{ ${t.map(([n,r])=>{const a=A(n);if(r.kind==="optional"){const o=r.inner?T(r.inner):"unknown";return`${a}?: ${o}`}return`${a}: ${T(r)}`}).join("; ")} }`},ln=e=>e.kind==="optional"||!!e.column?.hasDefault,dn=e=>{m(e.name,"table name");const t=Object.entries(e.shape).map(([r,a])=>{const o=a.kind==="optional"&&a.inner?a.inner:a,s=T(o),i=A(r);return ln(a)?` ${i}?: ${s};`:` ${i}: ${s};`}).join(`
|
|
45
45
|
`),n=t?`
|
|
46
46
|
${t}
|
|
47
47
|
`:"";return`export interface Insert_${e.name} {
|
|
48
48
|
_id?: Id<"${e.name}">;
|
|
49
|
-
_creationTime?: number;${n}}`},
|
|
49
|
+
_creationTime?: number;${n}}`},ur=(e,t=!1)=>{const n=H(t);for(const c of e.tables)m(c.name,"table name");const r=e.tables.map(c=>`"${c.name}"`).join(" | ")||"never",a=e.tables.filter(c=>c.extensionKey===void 0).map(c=>`"${c.name}"`).join(" | ")||"never",o=e.tables.map(c=>{const g=Object.entries(c.shape).map(([S,R])=>{const x=A(S);if(R.kind==="optional"){const _=R.inner?T(R.inner):"unknown";return` ${x}?: ${_};`}return` ${x}: ${T(R)};`}).join(`
|
|
50
50
|
`),f=g?`
|
|
51
51
|
${g}
|
|
52
52
|
`:"";return`export interface Doc_${c.name} {
|
|
@@ -58,7 +58,7 @@ ${g}
|
|
|
58
58
|
`),l=e.tables.map(c=>{const g=c.searchIndexes.map(f=>JSON.stringify(f.name)).join(" | ");return` ${c.name}: ${g||"never"};`}).join(`
|
|
59
59
|
`),u=e.tables.map(c=>{const g=c.rankIndexes.map(f=>JSON.stringify(f.name)).join(" | ");return` ${c.name}: ${g||"never"};`}).join(`
|
|
60
60
|
`),p=e.tables.map(c=>{const g=c.shardMode==="global"?"":(c.geoIndexes??[]).map(f=>JSON.stringify(f.name)).join(" | ");return` ${c.name}: ${g||"never"};`}).join(`
|
|
61
|
-
`),b=e.vectorIndexes.map(c=>JSON.stringify(c.name)).join(" | ")||"never",w=e.tables.map(c=>
|
|
61
|
+
`),b=e.vectorIndexes.map(c=>JSON.stringify(c.name)).join(" | ")||"never",w=e.tables.map(c=>dn(c)).join(`
|
|
62
62
|
|
|
63
63
|
`),$=e.tables.map(c=>` ${c.name}: Insert_${c.name};`).join(`
|
|
64
64
|
`),d=e.tables.map(c=>{const g=c.relations.map(f=>(m(f.table,"relation target table"),` ${A(f.name)}: ${f.kind==="one"?"OneRelation":"ManyRelation"}<"${f.table}">;`)).join(`
|
|
@@ -234,11 +234,11 @@ export interface OrmWriter extends OrmReader {
|
|
|
234
234
|
replace: <T extends keyof DataModel>(table: T, id: Id<T>) => OrmReplaceBuilder<T>;
|
|
235
235
|
update: <T extends keyof DataModel>(table: T, id: Id<T>) => OrmUpdateBuilder<T>;
|
|
236
236
|
}
|
|
237
|
-
`},
|
|
237
|
+
`},cn=/import\("(?<spec>(?:\.\.?\/)*_generated\/[^"]+)"\)/gu,un=/^(?:\.\.?\/)*_generated\//u,pn=/\.[A-Za-z]\w*$/u,Me=e=>e.replaceAll(cn,(t,n)=>{const r=n.replace(un,"./");return`import("${pn.test(r)?r:`${r}.js`}")`}),hn=/import\("@lunora\/(?<pkg>client|do|runtime|server|values)(?<subpath>\/[^"]*)?"\)/gu,at=(e,t)=>t?e.replaceAll(hn,(n,r,a)=>`import("lunorash/${r}${a??""}")`):e,qe=e=>["Doc","Id"].filter(t=>new RegExp(String.raw`\b${t}<`,"u").test(e)),ze=e=>{const t=new Map;for(const r of e){const a=t.get(r.filePath)??[];a.push(r),t.set(r.filePath,a)}const n=([r,a])=>{const o=a.toSorted((s,i)=>s.exportName.localeCompare(i.exportName)).map(s=>{const i=me(s.args),l=Me(s.returnType);return` ${s.exportName}: FunctionReference<"${s.kind}", ${i}, ${l}>;`}).join(`
|
|
238
238
|
`);return` ${A(v(r))}: {
|
|
239
239
|
${o}
|
|
240
240
|
};`};return[...t.entries()].toSorted(([r],[a])=>r.localeCompare(a)).map(r=>n(r)).join(`
|
|
241
|
-
`)},
|
|
241
|
+
`)},gn=(e,t)=>{if(e.length===0&&t.length===0)return{block:"",importLine:""};const n=[];let r="";if(e.length>0&&(r+="\n/** Params type carried by a `defineWorkflow` definition (its phantom `__params`). */\ntype WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params } ? (unknown extends Params ? Record<string, unknown> : Params) : Record<string, unknown>;\n"),r+=`
|
|
242
242
|
/** A typed reference to a durable workflow, addressable for \`cronJobs()\` targets. Mirrors \`@lunora/scheduler\`'s \`WorkflowReference\` structurally. */
|
|
243
243
|
export interface WorkflowReference<Params = Record<string, unknown>> {
|
|
244
244
|
readonly isLunoraWorkflow: true;
|
|
@@ -270,7 +270,7 @@ export const agents: AgentsRef = {
|
|
|
270
270
|
${s}
|
|
271
271
|
};
|
|
272
272
|
`,n.push(`import type { AgentRunInput } from "@lunora/agent";
|
|
273
|
-
`)}return{block:r,importLine:n.join("")}},
|
|
273
|
+
`)}return{block:r,importLine:n.join("")}},mn=()=>Object.keys(Ye().functions).toSorted((e,t)=>e.localeCompare(t)),ot=e=>new Set(e.filter(t=>v(t.filePath)==="agents").map(t=>t.exportName)),fn=()=>new Set(Object.entries(Ye().functions).filter(([,e])=>e.visibility==="internal").map(([e])=>e)),bn=(e,t)=>{const n={importLine:"",lines:"",prelude:""};if(e.length===0)return n;const r=ot(t),a=fn(),o=t.find(i=>v(i.filePath)==="agents"&&a.has(i.exportName));if(o)throw new ee("INTERNAL",`@lunora/codegen: "agents:${o.exportName}" is reserved for the durable agent loop's internal dispatch — rename the "${o.exportName}" export in ${o.filePath}`);const s=mn().filter(i=>!r.has(i));return s.length===0?n:{importLine:`import { agentComponent } from "@lunora/agent/component";
|
|
274
274
|
`,lines:s.map(i=>` "agents:${i}": lunoraAgentRuntimeFunctions.${i} as unknown as RegisteredLunoraFunction,`).join(`
|
|
275
275
|
`),prelude:`
|
|
276
276
|
/**
|
|
@@ -279,8 +279,8 @@ ${s}
|
|
|
279
279
|
* subscribe to the public queries (\`agents:agentMessages\` is the live thread view).
|
|
280
280
|
*/
|
|
281
281
|
const lunoraAgentRuntimeFunctions = agentComponent().functions;
|
|
282
|
-
`}},
|
|
283
|
-
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},
|
|
282
|
+
`}},yn=(e,t)=>{if(!e)return{importLine:"",lines:"",prelude:""};const n=t.find(r=>v(r.filePath)==="sandbox"&&r.exportName==="invoke");if(n)throw new ee("INTERNAL",`@lunora/codegen: "sandbox:invoke" is reserved for the batteries-included sandbox tool dispatcher (browserTool/containerTool) — rename the "invoke" export in ${n.filePath}`);return{importLine:`import { sandboxComponent } from "@lunora/agent/component";
|
|
283
|
+
`,lines:' "sandbox:invoke": lunoraSandbox.invoke as unknown as RegisteredLunoraFunction,',prelude:"\n/**\n * The `@lunora/agent` sandbox dispatcher — auto-registered because `lunora/`\n * imports a sandbox tool (`browserTool`/`containerTool`). The batteries-included\n * tools dispatch to this internal action, which runs on an action ctx carrying\n * `ctx.browser` + `ctx.containers` (the durable tool step itself has neither).\n */\nconst lunoraSandbox = sandboxComponent();\n"}},wn=(e,t)=>{if(e.length===0)return[];const n=ot(t),r=[{args:{key:{kind:"string"},limit:{inner:{kind:"number"},kind:"optional"}},exportName:"agentMessages",filePath:"agents",kind:"query",returnType:"Record<string, unknown>[]"},{args:{decision:{kind:"union",members:[{kind:"literal",literalValue:'"approve"'},{kind:"literal",literalValue:'"reject"'}]},instanceId:{kind:"string"},note:{inner:{kind:"string"},kind:"optional"},threadKey:{kind:"string"},toolCallId:{kind:"string"}},exportName:"agentResolveApproval",filePath:"agents",kind:"mutation",returnType:"{ resolved: boolean }"},{args:{agent:{kind:"string"},input:{kind:"string"},threadKey:{kind:"string"},title:{inner:{kind:"string"},kind:"optional"}},exportName:"agentRun",filePath:"agents",kind:"mutation",returnType:"{ id: string; threadKey: string }"},{args:{key:{kind:"string"}},exportName:"agentState",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"},{args:{key:{kind:"string"}},exportName:"agentThread",filePath:"agents",kind:"query",returnType:"Record<string, unknown> | undefined"}];for(const a of e)a.voice&&r.push({args:{threadKey:{kind:"string"}},exportName:`${a.exportName}Voice`,filePath:"agents",kind:"stream",returnType:"Record<string, unknown>"});return r.filter(a=>!n.has(a.exportName))},xn=(e,t)=>{if(e.length===0)return[];const n=new Set(t.filter(r=>v(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}))},kn=e=>{const t=e.filter(s=>s.stream);if(t.length===0)return{block:"",body:""};const n=new Map;for(const s of t){const i=n.get(s.filePath)??[];i.push(s),n.set(s.filePath,i)}const r=[...n.entries()].toSorted(([s],[i])=>s.localeCompare(i)),a=r.map(([s,i])=>{const l=i.map(u=>{const p=Me(u.chunkType??"unknown");return` ${A(u.exportName)}: HttpStreamRef<${p}, ${me(u.searchParams)}, ${me(u.params)}>;`}).join(`
|
|
284
284
|
`);return` ${A(v(s))}: {
|
|
285
285
|
${l}
|
|
286
286
|
};`}).join(`
|
|
@@ -297,7 +297,7 @@ ${a}
|
|
|
297
297
|
export const httpStreams: HttpStreamsRef = {
|
|
298
298
|
${o}
|
|
299
299
|
};
|
|
300
|
-
`,body:a}},
|
|
300
|
+
`,body:a}},pr=e=>{const{agents:t=[],functions:n,httpRoutes:r=[],mutators:a=[],useUmbrella:o=!1,workflows:s=[]}=e,i=H(o),l=[...n.filter(x=>x.visibility!=="internal"),...wn(t,n),...xn(a,n)],u=n.filter(x=>x.visibility==="internal"),p=ze(l),b=ze(u),w=kn(r),$=`${p}
|
|
301
301
|
${b}
|
|
302
302
|
${w.body}`,d=qe($),c=d.length>0?`
|
|
303
303
|
import type { ${d.join(", ")} } from "./dataModel.js";
|
|
@@ -305,7 +305,7 @@ import type { ${d.join(", ")} } from "./dataModel.js";
|
|
|
305
305
|
${p}
|
|
306
306
|
`:"",f=b?`
|
|
307
307
|
${b}
|
|
308
|
-
`:"",S=
|
|
308
|
+
`:"",S=gn(s,t),R=w.block===""?"FunctionReference":"FunctionReference, HttpStreamRef";return at(`${k}import { anyApi } from "${i.serverTypes}";
|
|
309
309
|
import type { ${R} } from "${i.client}";
|
|
310
310
|
${S.importLine}${c}
|
|
311
311
|
export interface ApiTypes {${g}}
|
|
@@ -316,7 +316,7 @@ export const api = anyApi as unknown as ApiTypes;
|
|
|
316
316
|
export interface InternalApiTypes {${f}}
|
|
317
317
|
|
|
318
318
|
export const internal = anyApi as unknown as InternalApiTypes;
|
|
319
|
-
${S.block}${w.block}`,o)},
|
|
319
|
+
${S.block}${w.block}`,o)},hr=e=>e?`${k}import { createSeedClient as createSeedClientBase } from "@lunora/seed";
|
|
320
320
|
import type { SeedClient, SeedClientOptions } from "@lunora/seed";
|
|
321
321
|
|
|
322
322
|
import schema from "../schema.js";
|
|
@@ -333,7 +333,7 @@ import type { InsertModel } from "./dataModel.js";
|
|
|
333
333
|
* const { posts } = await seed.posts((x) => x([10, 20]));
|
|
334
334
|
*/
|
|
335
335
|
export const createSeedClient = (options?: SeedClientOptions): SeedClient<InsertModel> => createSeedClientBase<InsertModel>(schema, options);
|
|
336
|
-
`:"",
|
|
336
|
+
`:"",gr=(e,t,n=!1)=>{if(e.length===0||!t)return"";const r=H(n),a=l=>l.table===void 0?"Row":`Doc<${JSON.stringify(l.table)}> & Row`,o=e.map(l=>{m(l.exportName,"shape export name");const u=a(l),p=me(l.args),b=Object.keys(l.args).length>0,w=b?` args: ${p};`:` args?: ${p};`,$=b?`(args: ${p}) => void`:`(args?: ${p}) => void`,d=`${l.exportName}CollectionOptions`;return`/** Options for the \`${l.exportName}\` shape binding. */
|
|
337
337
|
export interface ${Ee(d)} {
|
|
338
338
|
${w}
|
|
339
339
|
/**
|
|
@@ -387,7 +387,7 @@ import type { Collection } from "@tanstack/db";
|
|
|
387
387
|
import { createCollection } from "@tanstack/db";
|
|
388
388
|
${i}
|
|
389
389
|
${o}
|
|
390
|
-
`},
|
|
390
|
+
`},vn=(e,t)=>`lunora_${v(e)}_${String(t)}`,$n=`const callRegistered = async <R>(context: CallerCtx, functionPath: string, args: Record<string, unknown> | undefined): Promise<R> => {
|
|
391
391
|
const registered = LUNORA_FUNCTIONS[functionPath];
|
|
392
392
|
|
|
393
393
|
if (!registered) {
|
|
@@ -395,13 +395,13 @@ ${o}
|
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
return (await registered.handler(context, args ?? {})) as R;
|
|
398
|
-
};`,
|
|
398
|
+
};`,Sn=(e,t,n=[],r=[])=>{const a=new Map,o=d=>{a.has(d)||a.set(d,vn(d,a.size))};for(const d of e)o(d.filePath);for(const d of t)o(d.filePath);for(const d of n)o(d.filePath);for(const d of r)o(d.filePath);const s=[...a.entries()].map(([d,c])=>{if(!an.test(d))throw new ee("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(d)}`);return`import * as ${c} from "../${d}.js";`}).join(`
|
|
399
399
|
`),i=e.map(d=>` "${v(d.filePath)}:${d.exportName}": ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
400
400
|
`),l=t.map(d=>` ${JSON.stringify(d.id)}: ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredDataMigration,`).join(`
|
|
401
401
|
`),u=n.map(d=>` "${v(d.filePath)}:${d.exportName}": ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
402
402
|
`),p=r.map(d=>` "${d.exportName}": ${a.get(d.filePath)??""}.${d.exportName} as unknown as RegisteredShape,`).join(`
|
|
403
403
|
`),b=n.map(d=>`${v(d.filePath)}:${d.exportName}`),w=[i,u].filter(d=>d.length>0).join(`
|
|
404
|
-
`),$=e.map(d=>{if(d.lifecycle||Object.keys(d.args).length===0)return;const c=
|
|
404
|
+
`),$=e.map(d=>{if(d.lifecycle||Object.keys(d.args).length===0)return;const c=rn(d.args);return c===void 0?void 0:`installCompiledValidatorMap(${a.get(d.filePath)??""}.${d.exportName}.args, ${c});`}).filter(d=>d!==void 0).join(`
|
|
405
405
|
`);return{dispatchBody:w.length>0?`
|
|
406
406
|
${w}
|
|
407
407
|
`:"",importBlock:s.length>0?`${s}
|
|
@@ -410,7 +410,7 @@ ${w}
|
|
|
410
410
|
${l}
|
|
411
411
|
`:"",mutatorPaths:b,shapeBody:p.length>0?`
|
|
412
412
|
${p}
|
|
413
|
-
`:""}},
|
|
413
|
+
`:""}},Rn=e=>{const t=new Map;for(const a of e){const o=t.get(a.filePath)??[];o.push(a),t.set(a.filePath,o)}const n=[...t.entries()].toSorted(([a],[o])=>a.localeCompare(o)),r=n.map(([a,o])=>{const s=o.map(i=>{const l=me(i.args),u=l==="{}"?"?":"",p=Me(i.returnType);return i.kind==="stream"?` ${i.exportName}: (args${u}: ${l}) => Promise<AsyncIterable<${p}>>;`:` ${i.exportName}: (args${u}: ${l}) => Promise<${p}>;`}).join(`
|
|
414
414
|
`);return` ${A(v(a))}: {
|
|
415
415
|
${s}
|
|
416
416
|
};`}).join(`
|
|
@@ -418,18 +418,18 @@ ${s}
|
|
|
418
418
|
`);return` ${A(s)}: {
|
|
419
419
|
${i}
|
|
420
420
|
},`}).join(`
|
|
421
|
-
`),types:r}},
|
|
422
|
-
`:"",
|
|
423
|
-
readonly ai: LunoraAi;`:"",
|
|
424
|
-
`:"",
|
|
425
|
-
readonly payments: LunoraPayment;`:"",
|
|
426
|
-
`:"",
|
|
427
|
-
readonly x402: X402Pay;`:"",
|
|
428
|
-
`:"",
|
|
421
|
+
`),types:r}},Nn=(e,t=[])=>{const n=new Set;for(const r of e.tables)for(const a of Object.values(r.shape)){const o=a.kind==="optional"&&a.inner?a.inner:a;o.kind==="storage"&&typeof o.bucket=="string"&&o.bucket!==""&&n.add(o.bucket)}for(const r of t)r!==""&&r!=="default"&&n.add(r);return["default",...[...n].toSorted((r,a)=>r.localeCompare(a))]},mr=({agents:e=[],containers:t=[],env:n,hasAccessFacade:r=!1,hasAi:a=!1,hasAnalytics:o=!1,hasBrowser:s=!1,hasFlags:i=!1,hasHyperdrive:l=!1,hasImages:u=!1,hasKv:p=!1,hasNotify:b=!1,hasPayments:w=!1,hasPipelines:$=!1,hasR2sql:d=!1,hasX402:c=!1,identity:g,queues:f=[],schema:S,storageRuleBuckets:R=[],useUmbrella:x=!1,workflows:_=[]}={})=>{const y=H(x),I=Nn(S??{tables:[]},R).map(h=>JSON.stringify(h)).join(" | "),te=a?`import type { LunoraAi } from "@lunora/ai";
|
|
422
|
+
`:"",ne=a?`
|
|
423
|
+
readonly ai: LunoraAi;`:"",P=w?`import type { LunoraPayment } from "@lunora/payment";
|
|
424
|
+
`:"",re=w?`
|
|
425
|
+
readonly payments: LunoraPayment;`:"",W=c?`import type { X402Pay } from "@lunora/x402/pay";
|
|
426
|
+
`:"",N=c?`
|
|
427
|
+
readonly x402: X402Pay;`:"",z=t.length>0?`import type { ContainerAccessor } from "@lunora/container";
|
|
428
|
+
`:"",L=t.length>0?`
|
|
429
429
|
readonly containers: {${t.map(h=>`
|
|
430
430
|
readonly ${h.exportName}: ContainerAccessor;`).join("")}
|
|
431
|
-
};`:"",
|
|
432
|
-
readonly ${h.bindingName}?: unknown;`)),...
|
|
431
|
+
};`:"",X=[...a?[" /** Workers AI binding (the conventional `env.AI`), narrowing `ctx.ai`. */\n readonly AI?: unknown;"]:[],...t.map(h=>(m(h.bindingName,`container binding "${h.bindingName}"`),` /** Durable Object namespace for the \`${h.exportName}\` container. */
|
|
432
|
+
readonly ${h.bindingName}?: unknown;`)),..._.map(h=>(m(h.bindingName,`workflow binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` workflow. */
|
|
433
433
|
readonly ${h.bindingName}?: unknown;`)),...f.map(h=>(m(h.bindingName,`queue binding "${h.bindingName}"`),` /** Queue producer binding for the \`${h.exportName}\` queue. */
|
|
434
434
|
readonly ${h.bindingName}?: unknown;`)),...e.map(h=>(m(h.bindingName,`agent binding "${h.bindingName}"`),` /** Workflow binding for the \`${h.exportName}\` agent. */
|
|
435
435
|
readonly ${h.bindingName}?: unknown;`))].join(`
|
|
@@ -446,26 +446,26 @@ ${i}
|
|
|
446
446
|
* surface, so treat them as \`Fetcher\`/\`Service<unknown>\` and cast.
|
|
447
447
|
*/
|
|
448
448
|
export interface CloudflareBindings {
|
|
449
|
-
readonly [binding: string]: unknown;${
|
|
450
|
-
${
|
|
449
|
+
readonly [binding: string]: unknown;${X?`
|
|
450
|
+
${X}`:""}
|
|
451
451
|
}
|
|
452
452
|
|
|
453
453
|
/** Alias for {@link CloudflareBindings} — the typed shape of \`env\`. */
|
|
454
|
-
export type Env = CloudflareBindings;`,
|
|
455
|
-
readonly vectors: VectorSearch<VectorIndexName>;`:"",
|
|
456
|
-
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",
|
|
454
|
+
export type Env = CloudflareBindings;`,E=(h,_e)=>_e?zt.get(h)?.field??"":"",ae=E("kv",p),oe=E("analytics",o),xe=E("hyperdrive",l),ke=E("browser",s),ie=E("images",u),U=E("pipelines",$),K=E("r2sql",d),M=(S?.vectorIndexes.length??0)>0,Q=M?' | "vectors"':"",Y=M?`
|
|
455
|
+
readonly vectors: VectorSearch<VectorIndexName>;`:"",J=M?`
|
|
456
|
+
readonly vectors: VectorSearchReader<VectorIndexName>;`:"",Z=M?`import type { VectorSearch, VectorSearchReader } from "${y.server}";
|
|
457
457
|
import type { VectorIndexName } from "./dataModel.js";
|
|
458
|
-
`:"",
|
|
458
|
+
`:"",q=r?`
|
|
459
459
|
/** Verified Cloudflare Access identity — a synchronous facade over the resolved claims (email / groups / hasGroup / claims). Anonymous when no Access token is present. */
|
|
460
|
-
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",
|
|
460
|
+
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;`:"",B=i?`
|
|
461
461
|
/** Feature-flag evaluation (OpenFeature). Reads are memoized per request; evaluations never throw — a provider error resolves to the supplied default. */
|
|
462
|
-
readonly flags: import("${y.flags}").LunoraFlags;`:"",
|
|
462
|
+
readonly flags: import("${y.flags}").LunoraFlags;`:"",j=b?`
|
|
463
463
|
/** Multi-channel notifications (@lunora/notify): send / chat / inApp / webhook plus the push device sub-facade. Sends are external I/O — confine them to action handlers. */
|
|
464
464
|
readonly notify: import("@lunora/notify").LunoraNotify;
|
|
465
465
|
/** Device push sub-facade — the same object as ctx.notify.push (register / send / broadcast). Sends belong in action handlers. */
|
|
466
|
-
readonly push: import("@lunora/notify").LunoraPush;`:"",
|
|
466
|
+
readonly push: import("@lunora/notify").LunoraPush;`:"",F=_.length>0,ve=F?`import type { WorkflowHandle } from "@lunora/workflow";
|
|
467
467
|
import type * as lunoraWorkflowDefinitions from "../workflows.js";
|
|
468
|
-
`:"",$e=
|
|
468
|
+
`:"",$e=F?`
|
|
469
469
|
|
|
470
470
|
/** Params type carried by a \`defineWorkflow\` definition (its phantom \`__params\`). */
|
|
471
471
|
type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params }
|
|
@@ -476,12 +476,12 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
476
476
|
|
|
477
477
|
/** This project's declared workflows, addressable from \`ctx.workflows\` by their \`lunora/workflows.ts\` export name. */
|
|
478
478
|
export interface LunoraWorkflows {
|
|
479
|
-
${
|
|
479
|
+
${_.map(h=>` get(name: ${JSON.stringify(h.exportName)}): WorkflowHandle<WorkflowParamsOf<typeof lunoraWorkflowDefinitions.${h.exportName}>>;`).join(`
|
|
480
480
|
`)}
|
|
481
|
-
}`:"",
|
|
482
|
-
readonly workflows: LunoraWorkflows;`:"",
|
|
481
|
+
}`:"",fe=F?' | "workflows"':"",be=F?`
|
|
482
|
+
readonly workflows: LunoraWorkflows;`:"",se=f.length>0,Se=se?`import type { QueueProducer } from "@lunora/queue";
|
|
483
483
|
import type * as lunoraQueueDefinitions from "../queues.js";
|
|
484
|
-
`:"",Re=
|
|
484
|
+
`:"",Re=se?`
|
|
485
485
|
|
|
486
486
|
/** Message body type carried by a \`defineQueue\` definition (its phantom \`__lunoraBody\`). */
|
|
487
487
|
type QueueBodyOf<Definition> = Definition extends { __lunoraBody?: infer Body } ? (unknown extends Body ? unknown : NonNullable<Body>) : unknown;
|
|
@@ -490,15 +490,15 @@ type QueueBodyOf<Definition> = Definition extends { __lunoraBody?: infer Body }
|
|
|
490
490
|
export interface LunoraQueues {
|
|
491
491
|
${f.map(h=>` readonly ${h.exportName}: QueueProducer<QueueBodyOf<typeof lunoraQueueDefinitions.${h.exportName}>>;`).join(`
|
|
492
492
|
`)}
|
|
493
|
-
}`:"",
|
|
494
|
-
readonly queues: LunoraQueues;`:"",
|
|
495
|
-
`:"",Oe=
|
|
493
|
+
}`:"",ye=se?`
|
|
494
|
+
readonly queues: LunoraQueues;`:"",le=e.length>0,Ne=le?`import type { AgentHandle } from "@lunora/agent";
|
|
495
|
+
`:"",Oe=le?`
|
|
496
496
|
|
|
497
497
|
/** This project's declared agents, addressable from \`ctx.agents\` by their \`lunora/agents.ts\` export name. */
|
|
498
498
|
export interface LunoraAgents {
|
|
499
499
|
${e.map(h=>(m(h.exportName,`agent export "${h.exportName}"`),` readonly ${h.exportName}: AgentHandle;`)).join(`
|
|
500
500
|
`)}
|
|
501
|
-
}`:"",
|
|
501
|
+
}`:"",we=le?`
|
|
502
502
|
readonly agents: LunoraAgents;`:"",Te=g?`import type { InferIdentity } from "${y.server}";
|
|
503
503
|
import type * as lunoraIdentityContract from "../identity.js";
|
|
504
504
|
`:"",Ae=g?`
|
|
@@ -507,12 +507,12 @@ import type * as lunoraIdentityContract from "../identity.js";
|
|
|
507
507
|
export type Identity = InferIdentity<typeof lunoraIdentityContract.${g.exportName}>;
|
|
508
508
|
|
|
509
509
|
/** \`ctx.auth\` narrowed so \`getIdentity()\` resolves the declared {@link Identity} contract instead of the untyped claim bag. */
|
|
510
|
-
type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: () => Promise<Identity | null> };`:"",
|
|
510
|
+
type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: () => Promise<Identity | null> };`:"",de=g?' | "auth"':"",ce=g?`
|
|
511
511
|
readonly auth: NarrowedAuth;`:"",Le=g?", Identity":"",Ce=n?`import type * as lunoraEnvContract from "../env.js";
|
|
512
512
|
`:"",De=n?`
|
|
513
513
|
|
|
514
514
|
/** This app's declared env contract (\`defineEnv\` in \`lunora/env.ts\`) — the validated, coercion-aware shape of \`ctx.env\`. */
|
|
515
|
-
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",
|
|
515
|
+
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${n.exportName}>;`:"",ue=n?' | "env"':"",pe=n?"\n /** Validated, typed environment declared by `defineEnv` in `lunora/env.ts` — parsed & coercion-aware config values (`ctx.env.STRIPE_KEY`); a missing or invalid value throws at read time. */\n readonly env: LunoraEnv;":"";return`${k}import { createPolicyDsl, defineMutator as defineMutatorBase, initLunora, v as vBase } from "${y.server}";
|
|
516
516
|
import type {
|
|
517
517
|
ActionBuilder,
|
|
518
518
|
ActionCtx as ActionCtxBase,
|
|
@@ -536,11 +536,11 @@ import type {
|
|
|
536
536
|
} from "${y.server}";
|
|
537
537
|
|
|
538
538
|
import type { DataModel, DatabaseReaderFacade, DatabaseWriterFacade, Doc, Id as IdOfTable, OrmReader, OrmWriter, Relations, TableName } from "./dataModel.js";
|
|
539
|
-
${
|
|
539
|
+
${Z}${te}${P}${W}${z}${ve}${Se}${Ne}${Te}${Ce}
|
|
540
540
|
export type { AppTableName, DataModel, Doc, Id, TableName } from "./dataModel.js";
|
|
541
541
|
|
|
542
542
|
/** Storage buckets this schema declares (\`v.storage("name")\`), narrowing \`ctx.storage.bucket(name)\`. */
|
|
543
|
-
export type StorageBucketName = ${
|
|
543
|
+
export type StorageBucketName = ${I};${C}${$e}${Re}${Oe}${Ae}${De}
|
|
544
544
|
|
|
545
545
|
/**
|
|
546
546
|
* Project-typed contexts. The base contexts from \`@lunora/server\` are
|
|
@@ -594,22 +594,22 @@ type AsIdTable<T extends string> = T extends TableName ? T : string extends T ?
|
|
|
594
594
|
*/
|
|
595
595
|
type TypedAsId = <T extends string>(tableName: AsIdTable<T>, id: string) => IdOfTable<T & TableName>;
|
|
596
596
|
|
|
597
|
-
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${
|
|
597
|
+
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${Q}${de}${ue}> {
|
|
598
598
|
readonly db: Omit<DatabaseReader, "asId" | "query" | "get"> & DatabaseReaderFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
599
599
|
readonly orm: OrmReader;
|
|
600
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${
|
|
600
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${J}${q}${ae}${B}${j}${oe}${pe}${ce}
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
-
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${
|
|
603
|
+
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${Q}${fe}${de}${ue}> {
|
|
604
604
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
605
605
|
readonly orm: OrmWriter;
|
|
606
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${
|
|
606
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${Y}${q}${ae}${B}${j}${oe}${pe}${be}${ye}${we}${ce}
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
-
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${
|
|
609
|
+
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${Q}${fe}${de}${ue}> {
|
|
610
610
|
readonly db: Omit<DatabaseWriter, "asId" | "query" | "get"> & DatabaseWriterFacade & { asId: TypedAsId; query: TypedTableQuery; get: TypedTableGet };
|
|
611
611
|
readonly orm: OrmWriter;
|
|
612
|
-
readonly storage: StorageBase<StorageBucketName>;${
|
|
612
|
+
readonly storage: StorageBase<StorageBucketName>;${Y}${q}${ne}${re}${N}${L}${ae}${B}${j}${xe}${ke}${ie}${oe}${U}${K}${pe}${be}${ye}${we}${ce}
|
|
613
613
|
}
|
|
614
614
|
|
|
615
615
|
/**
|
|
@@ -684,12 +684,12 @@ export const definePolicy = createPolicyDsl<DataModel, Relations${Le}>();
|
|
|
684
684
|
export const v = vBase as unknown as Omit<typeof vBase, "id"> & {
|
|
685
685
|
id: <T extends TableName>(table: T) => ColumnValidator<IdOfTable<T>, IdOfTable<T>>;
|
|
686
686
|
};
|
|
687
|
-
`},
|
|
687
|
+
`},On=e=>{const t={connect:[],disconnect:[]};for(const n of e)n.lifecycle&&t[n.lifecycle].push(`${v(n.filePath)}:${n.exportName}`);return t},fr=e=>{const{agents:t=[],functions:n,migrations:r=[],mutators:a=[],shapes:o=[],useUmbrella:s=!1,usesSandbox:i=!1}=e,l=n.length>0,u=H(s),{dispatchBody:p,importBlock:b,installBlock:w,migrationBody:$,mutatorPaths:d,shapeBody:c}=Sn(n,r,a,o),g=bn(t,n),f=yn(i,n),S=[g.lines,f.lines].filter(C=>C.length>0).join(`
|
|
688
688
|
`);let R=p;S.length>0&&(R=p.length>0?`${p.trimEnd()}
|
|
689
689
|
${S}
|
|
690
690
|
`:`
|
|
691
691
|
${S}
|
|
692
|
-
`);const x=
|
|
692
|
+
`);const x=On(n),_=o.length>0?`import type { RegisteredShape } from "${u.server}";
|
|
693
693
|
`:"",y=o.length>0?`
|
|
694
694
|
/**
|
|
695
695
|
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
@@ -698,31 +698,31 @@ ${S}
|
|
|
698
698
|
* \`shape_subscribe\` (reads-as-permissions).
|
|
699
699
|
*/
|
|
700
700
|
export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${c}};
|
|
701
|
-
`:"",
|
|
701
|
+
`:"",I=d.length>0?`
|
|
702
702
|
/**
|
|
703
703
|
* Custom-mutator function paths — the \`LUNORA_FUNCTIONS\` keys the generated
|
|
704
704
|
* ShardDO's \`isCustomMutator\` override routes through the client-watermark push
|
|
705
705
|
* protocol (\`x-lunora-client-id\`/\`x-lunora-client-seq\` ordering).
|
|
706
706
|
*/
|
|
707
707
|
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${d.map(C=>JSON.stringify(C)).join(", ")}]);
|
|
708
|
-
`:"",
|
|
709
|
-
`:"",
|
|
708
|
+
`:"",te=w.length>0?`import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${u.values}";
|
|
709
|
+
`:"",ne=w.length>0?`
|
|
710
710
|
/**
|
|
711
711
|
* AOT-compiled argument validators (Worker-safe, no \`eval\`). Each is installed
|
|
712
712
|
* onto its function's live \`.args\` object and consulted by the interpreted
|
|
713
713
|
* parser as a zero-allocation fast path; anything it can't model is deferred.
|
|
714
714
|
*/
|
|
715
715
|
${w}
|
|
716
|
-
`:"",
|
|
717
|
-
${
|
|
718
|
-
`:"",
|
|
719
|
-
${
|
|
720
|
-
`:"",
|
|
721
|
-
`:"",
|
|
722
|
-
|
|
723
|
-
`:"";return at(`${k}${b}${g.importLine}${f.importLine}${
|
|
716
|
+
`:"",P=Rn(n),re=P.types?`
|
|
717
|
+
${P.types}
|
|
718
|
+
`:"",W=P.implementation?`
|
|
719
|
+
${P.implementation}
|
|
720
|
+
`:"",N=qe(P.types),z=N.length>0?`import type { ${N.join(", ")} } from "./dataModel.js";
|
|
721
|
+
`:"",L=l?"context":"_context",X=l?`${$n}
|
|
722
|
+
|
|
723
|
+
`:"";return at(`${k}${b}${g.importLine}${f.importLine}${te}${_}import { LunoraError } from "${u.server}";
|
|
724
724
|
import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
725
|
-
${
|
|
725
|
+
${z}
|
|
726
726
|
/**
|
|
727
727
|
* Single registered function, narrowed to the shape \`handleRpc\` needs.
|
|
728
728
|
* The real argument validators / return types are checked elsewhere — at
|
|
@@ -747,7 +747,7 @@ ${g.prelude}${f.prelude}
|
|
|
747
747
|
* emits (\`api[namespace][fn].__lunoraRef === "namespace:fn"\`).
|
|
748
748
|
*/
|
|
749
749
|
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${R}};
|
|
750
|
-
${
|
|
750
|
+
${ne}${y}${I}
|
|
751
751
|
/**
|
|
752
752
|
* Connection-lifecycle manifest: the function paths the generated ShardDO
|
|
753
753
|
* dispatches when a client's WebSocket connects (\`connect\`) or disconnects
|
|
@@ -787,10 +787,10 @@ export type CallerCtx = ActionCtx | MutationCtx | QueryCtx;
|
|
|
787
787
|
* with the supplied \`context\`, exactly like \`ctx.runQuery\`/\`runMutation\`/
|
|
788
788
|
* \`runAction\` but without re-stating the function path.
|
|
789
789
|
*/
|
|
790
|
-
export interface Caller {${
|
|
790
|
+
export interface Caller {${re}}
|
|
791
791
|
|
|
792
|
-
${
|
|
793
|
-
export const createCaller = (${
|
|
792
|
+
${X}/** Build a {@link Caller} bound to \`context\` (typically a handler's \`ctx\`). */
|
|
793
|
+
export const createCaller = (${L}: CallerCtx): Caller => ({${W}});
|
|
794
794
|
|
|
795
795
|
/**
|
|
796
796
|
* Single registered data migration, narrowed to the shape the per-shard runner
|
|
@@ -810,7 +810,7 @@ export interface RegisteredDataMigration {
|
|
|
810
810
|
* shard DO's admin RPC and the CLI resolve migrations to run through this map.
|
|
811
811
|
*/
|
|
812
812
|
export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${$}};
|
|
813
|
-
`,s)},
|
|
813
|
+
`,s)},Tn=e=>{const t={};for(const n of e.tables){const r={};for(const[a,o]of Object.entries(n.shape)){const s=o.kind==="optional"&&o.inner?o.inner:o;s.kind==="id"&&s.tableName!==void 0&&(r[a]=s.tableName)}Object.keys(r).length>0&&(t[n.name]=r)}return t},An=e=>{const t={};for(const n of e.tables){const r=[];for(const[a,o]of Object.entries(n.shape))(o.kind==="optional"&&o.inner?o.inner:o).kind==="storage"&&r.push(a);r.length>0&&(t[n.name]=r)}return t},Ln=e=>{const t={};for(const n of e.tables){const r=[...n.indexes.map(a=>({fields:[...a.fields],name:a.name,type:"index",...a.unique===!0?{unique:!0}:{}})),...n.searchIndexes.map(a=>({fields:[a.field,...a.filterFields??[]],name:a.name,type:"search"})),...(n.geoIndexes??[]).map(a=>({fields:[a.field],name:a.name,type:"geo"})),...n.rankIndexes.map(a=>({fields:a.sortBy.map(o=>o.field),name:a.name,type:"rank"})),...n.vectorIndexes.map(a=>({fields:a.field===void 0?[]:[a.field],name:a.name,type:"vector"}))];r.length>0&&(t[n.name]=r)}return t},Cn=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},Dn=e=>{const t={};for(const n of e.tables){const r=[{name:"_id",optional:!1,pk:!0,type:"id"},{name:"_creationTime",optional:!1,type:"number"}];for(const[a,o]of Object.entries(n.shape)){const s=o.kind==="optional"||!!o.column?.hasDefault,i=o.kind==="optional"&&o.inner?o.inner:o,l={name:a,optional:s,type:i.kind};i.kind==="id"&&i.tableName!==void 0&&(l.ref=i.tableName),i.kind==="storage"&&(l.isStorage=!0),r.push(l)}t[n.name]=r}return t},_n=e=>e?{importFragment:"serveRelationFanout, ",override:`
|
|
814
814
|
protected override async runRelationFanoutRead(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
815
815
|
this.ensureMigrated();
|
|
816
816
|
|
|
@@ -818,7 +818,7 @@ export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${$}}
|
|
|
818
818
|
|
|
819
819
|
return serveRelationFanout(schema as unknown as SchemaLike, db, functionPath, args);
|
|
820
820
|
}
|
|
821
|
-
`}:{importFragment:"",override:""},
|
|
821
|
+
`}:{importFragment:"",override:""},In=e=>{if(!e)return{build:"",configField:"",contextField:"",stub:""};const t='throw new Error("ctx.ai: no AI binding found. Add an \\`ai\\` binding (env.AI) to wrangler.jsonc, or pass \\`ai\\` to createShardDO().");';return{build:`
|
|
822
822
|
const aiBinding = config.ai?.(env) ?? (env as Record<string, unknown>).AI;
|
|
823
823
|
// Correlate AI-Gateway-routed calls with the Lunora trace: thread the
|
|
824
824
|
// function path + trace id into createAi, which folds them into the
|
|
@@ -849,7 +849,7 @@ const aiStub: LunoraAi = {
|
|
|
849
849
|
${t}
|
|
850
850
|
}) as unknown as LunoraAi["workersai"],
|
|
851
851
|
};
|
|
852
|
-
`}},D={build:"",configField:"",contextField:"",importLines:[],stub:""},
|
|
852
|
+
`}},D={build:"",configField:"",contextField:"",importLines:[],stub:""},Pn=e=>{if(!e)return D;const t='throw new Error("ctx.kv: no KV binding found. Add a \\`kv_namespaces\\` binding (env.KV) to wrangler.jsonc, or pass \\`kv\\` to createShardDO().");';return{build:`
|
|
853
853
|
const kvBinding = config.kv?.(env) ?? (env as Record<string, unknown>).KV;
|
|
854
854
|
const kv: Kv = kvBinding ? createKv({ namespace: kvBinding as KVNamespaceLike }) : kvStub;
|
|
855
855
|
`,configField:`
|
|
@@ -875,7 +875,7 @@ const kvStub: Kv = {
|
|
|
875
875
|
${t}
|
|
876
876
|
},
|
|
877
877
|
};
|
|
878
|
-
`}},
|
|
878
|
+
`}},En=(e,t)=>e?{build:`
|
|
879
879
|
const flags: import("${t}").LunoraFlags = createFlags({
|
|
880
880
|
hooks: flagsConfig.hooks,
|
|
881
881
|
logger: flagsConfig.logger,
|
|
@@ -884,17 +884,17 @@ const kvStub: Kv = {
|
|
|
884
884
|
});
|
|
885
885
|
`,configField:`
|
|
886
886
|
flags?: (env: Record<string, unknown>) => import("${t}").Provider;`,contextField:`
|
|
887
|
-
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:D,
|
|
887
|
+
flags,`,importLines:[`import { createFlags } from "${t}";`,'import flagsConfig from "../flags.js";'],stub:""}:D,Fn=e=>e?{build:`
|
|
888
888
|
const { notify, push } = createNotify(notifyConfig, env, { log, metrics });
|
|
889
889
|
`,configField:"",contextField:`
|
|
890
890
|
notify,
|
|
891
|
-
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:D,
|
|
891
|
+
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:D,Mn=e=>e?{build:`
|
|
892
892
|
const envConfig = lunoraEnvContract.${e.exportName}(env);
|
|
893
893
|
`,configField:"",contextField:`
|
|
894
|
-
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:D,
|
|
894
|
+
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:D,qn=e=>e?{build:`
|
|
895
895
|
const access = accessFacade(identity, userId);
|
|
896
896
|
`,configField:"",contextField:`
|
|
897
|
-
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:D,
|
|
897
|
+
access,`,importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}:D,Bn=(e,t,n)=>{if(!t)return{constant:"",evaluateOverride:"",subscriptionOverride:""};const r=i=>`
|
|
898
898
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
899
899
|
const flags: import("${n}").LunoraFlags = createFlags({
|
|
900
900
|
hooks: flagsConfig.hooks,
|
|
@@ -958,7 +958,7 @@ const LUNORA_FLAG_KEYS: ReadonlyArray<{ key: string; type: "boolean" | "number"
|
|
|
958
958
|
|
|
959
959
|
return flags.boolean(key, typeof args.default === "boolean" ? args.default : false, context);
|
|
960
960
|
}
|
|
961
|
-
`;return{constant:a,evaluateOverride:o,subscriptionOverride:s}},
|
|
961
|
+
`;return{constant:a,evaluateOverride:o,subscriptionOverride:s}},jn=e=>{if(!e)return D;const t='throw new Error("ctx.analytics: no Analytics Engine binding found. Add an \\`analytics_engine_datasets\\` binding (env.ANALYTICS) to wrangler.jsonc, or pass \\`analytics\\` to createShardDO().");';return{build:`
|
|
962
962
|
const analyticsBinding = config.analytics?.(env) ?? (env as Record<string, unknown>).ANALYTICS;
|
|
963
963
|
const analytics: AnalyticsClient = analyticsBinding ? createAnalytics(analyticsBinding as AnalyticsEngineDatasetLike) : analyticsStub;
|
|
964
964
|
`,configField:`
|
|
@@ -972,7 +972,7 @@ const analyticsStub: AnalyticsClient = {
|
|
|
972
972
|
${t}
|
|
973
973
|
},
|
|
974
974
|
};
|
|
975
|
-
`}},
|
|
975
|
+
`}},Wn=e=>{if(!e)return D;const t='throw new Error("ctx.images: no Images binding found. Add an \\`images\\` binding (env.IMAGES) to wrangler.jsonc, or pass \\`images\\` to createShardDO().");';return{build:`
|
|
976
976
|
const imagesBinding = config.images?.(env) ?? (env as Record<string, unknown>).IMAGES;
|
|
977
977
|
const images: Images = imagesBinding ? createImages({ binding: imagesBinding as ImagesBindingLike }) : imagesStub;
|
|
978
978
|
`,configField:`
|
|
@@ -986,7 +986,7 @@ const imagesStub: Images = {
|
|
|
986
986
|
${t}
|
|
987
987
|
},
|
|
988
988
|
};
|
|
989
|
-
`}},
|
|
989
|
+
`}},Un=e=>e?{build:`
|
|
990
990
|
const sql: SqlClient = config.sql ? config.sql(env) : sqlStub;
|
|
991
991
|
`,configField:`
|
|
992
992
|
sql?: (env: Record<string, unknown>) => SqlClient;`,contextField:`
|
|
@@ -996,7 +996,7 @@ const sqlStub: SqlClient = {
|
|
|
996
996
|
throw new Error("ctx.sql: provide a \\\`sql\\\` config thunk that builds a SqlClient from your driver, e.g. \\\`sql: (env) => fromPostgresJs(postgres(env.HYPERDRIVE.connectionString))\\\`.");
|
|
997
997
|
},
|
|
998
998
|
};
|
|
999
|
-
`}:D,
|
|
999
|
+
`}:D,Kn=e=>{if(!e)return D;const t="throw new Error(\"ctx.browser: provide a \\`browser\\` config thunk, e.g. \\`browser: (env) => createBrowser({ binding: env.BROWSER, launch })\\` with \\`import { launch } from '@cloudflare/playwright'\\`.\");";return{build:`
|
|
1000
1000
|
const browser: Browser = config.browser ? config.browser(env) : browserStub;
|
|
1001
1001
|
`,configField:`
|
|
1002
1002
|
browser?: (env: Record<string, unknown>) => Browser;`,contextField:`
|
|
@@ -1018,7 +1018,7 @@ const browserStub: Browser = {
|
|
|
1018
1018
|
${t}
|
|
1019
1019
|
},
|
|
1020
1020
|
};
|
|
1021
|
-
`}},
|
|
1021
|
+
`}},Qn=e=>{if(!e)return D;const t='throw new Error("ctx.r2sql: no R2 SQL credentials found. Set \\`R2_SQL_TOKEN\\`, \\`R2_SQL_ACCOUNT_ID\\` (or \\`CLOUDFLARE_ACCOUNT_ID\\`), and \\`R2_SQL_BUCKET\\` in your env/.dev.vars, or pass an \\`r2sql\\` config thunk to createShardDO().");';return{build:`
|
|
1022
1022
|
const r2sqlEnv = env as Record<string, unknown>;
|
|
1023
1023
|
const r2sqlAccountId = (r2sqlEnv.R2_SQL_ACCOUNT_ID ?? r2sqlEnv.CLOUDFLARE_ACCOUNT_ID) as string | undefined;
|
|
1024
1024
|
const r2sqlToken = r2sqlEnv.R2_SQL_TOKEN as string | undefined;
|
|
@@ -1050,7 +1050,7 @@ const r2sqlStub: R2SqlClient = {
|
|
|
1050
1050
|
${t}
|
|
1051
1051
|
},
|
|
1052
1052
|
};
|
|
1053
|
-
`}},
|
|
1053
|
+
`}},Jn=e=>e?{build:`
|
|
1054
1054
|
const pipelinesBinding = config.pipelines?.(env) ?? (env as Record<string, unknown>).PIPELINES;
|
|
1055
1055
|
const pipelines: PipelineClient = pipelinesBinding ? createPipelines({ binding: pipelinesBinding as PipelineBindingLike }) : pipelinesStub;
|
|
1056
1056
|
`,configField:`
|
|
@@ -1060,7 +1060,7 @@ const pipelinesStub: PipelineClient = {
|
|
|
1060
1060
|
throw new Error("ctx.pipelines: no Pipelines binding found. Add a \\\`pipelines\\\` binding (env.PIPELINES) to wrangler.jsonc, or pass \\\`pipelines\\\` to createShardDO().");
|
|
1061
1061
|
},
|
|
1062
1062
|
};
|
|
1063
|
-
`}:D,
|
|
1063
|
+
`}:D,br=(e,t)=>{if(e.length===0)return"";const n=t?`, ${JSON.stringify(t)}`:"",r=e.map(o=>(m(o.exportName,`container export "${o.exportName}"`),m(o.className,`container class "${o.className}"`),`/** Container DO for the \`${o.exportName}\` definition (binding \`${o.bindingName}\`). */
|
|
1064
1064
|
export class ${o.className} extends LunoraContainer {
|
|
1065
1065
|
public constructor(ctx: ConstructorParameters<typeof LunoraContainer>[0], env: Record<string, unknown>) {
|
|
1066
1066
|
super(ctx, env, ${o.exportName}, "${o.exportName}"${n});
|
|
@@ -1085,7 +1085,7 @@ import { ${a} } from "../containers.js";
|
|
|
1085
1085
|
|
|
1086
1086
|
export { ContainerProxy } from "@lunora/container/do";
|
|
1087
1087
|
|
|
1088
|
-
${r}`},
|
|
1088
|
+
${r}`},Vn=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const r of e)m(r.exportName,`container export "${r.exportName}"`),m(r.bindingName,`container binding "${r.bindingName}"`);const n=e.map(r=>{const a=r.maxInstances===void 0?"":`, maxInstances: ${String(r.maxInstances)}`;return` { binding: "${r.bindingName}", exportName: "${r.exportName}"${a} },`}).join(`
|
|
1089
1089
|
`);return{build:`
|
|
1090
1090
|
const containers = createContainerContext(env, LUNORA_CONTAINERS, ${t?JSON.stringify(t):"undefined"}, this.getCurrentTraceparent());
|
|
1091
1091
|
`,contextField:`
|
|
@@ -1094,7 +1094,7 @@ ${r}`},jn=(e,t)=>{if(e.length===0)return{build:"",contextField:"",importLines:[]
|
|
|
1094
1094
|
const LUNORA_CONTAINERS: ReadonlyArray<ContainerBindingSpec> = [
|
|
1095
1095
|
${n}
|
|
1096
1096
|
];
|
|
1097
|
-
`}},
|
|
1097
|
+
`}},yr=e=>{if(e.length===0)return"";const t=e.map(r=>(m(r.exportName,`workflow export "${r.exportName}"`),m(r.className,`workflow class "${r.className}"`),`/** WorkflowEntrypoint for the \`${r.exportName}\` definition (binding \`${r.bindingName}\`). */
|
|
1098
1098
|
export class ${r.className} extends LunoraWorkflow<WorkflowParamsOf<typeof ${r.exportName}>, WorkflowOutputOf<typeof ${r.exportName}>> {
|
|
1099
1099
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1100
1100
|
super(ctx, env, ${r.exportName}, "${r.exportName}");
|
|
@@ -1122,7 +1122,7 @@ type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params
|
|
|
1122
1122
|
/** Output type carried by a \`defineWorkflow\` definition (its phantom \`__output\`), so each entrypoint keeps the authored return type. */
|
|
1123
1123
|
type WorkflowOutputOf<Definition> = Definition extends { __output?: infer Output } ? Output : unknown;
|
|
1124
1124
|
|
|
1125
|
-
${t}`},
|
|
1125
|
+
${t}`},wr=e=>{if(e.length===0)return"";const t=e.filter(a=>a.voice).length>0,n=e.map(a=>{m(a.exportName,`agent export "${a.exportName}"`),m(a.className,`agent class "${a.className}"`);const o=`/** WorkflowEntrypoint for the \`${a.exportName}\` agent (binding \`${a.bindingName}\`). */
|
|
1126
1126
|
export class ${a.className} extends LunoraWorkflow<AgentRunInput, AgentRunResult> {
|
|
1127
1127
|
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
1128
1128
|
super(ctx, env, compileAgentWorkflow(${a.exportName}, "${a.exportName}"), "${a.exportName}");
|
|
@@ -1150,7 +1150,7 @@ import type { AgentRunInput, AgentRunResult } from "@lunora/agent";
|
|
|
1150
1150
|
|
|
1151
1151
|
import { ${r} } from "../agents.js";
|
|
1152
1152
|
|
|
1153
|
-
${n}`},
|
|
1153
|
+
${n}`},xr=e=>{const t=e.filter(a=>a.mode==="push");if(t.length===0)return"";for(const a of t)m(a.exportName,`queue export "${a.exportName}"`);const n=t.map(a=>a.exportName).join(", "),r=t.map(a=>` ${JSON.stringify(a.name)}: { definition: ${a.exportName}, exportName: ${JSON.stringify(a.exportName)} },`).join(`
|
|
1154
1154
|
`);return`${k}/**
|
|
1155
1155
|
* Push-consumer registry for the queues declared in \`lunora/queues.ts\`. The
|
|
1156
1156
|
* composed worker's \`queue(batch, env, ctx)\` entry routes each delivered batch
|
|
@@ -1165,7 +1165,7 @@ import { ${n} } from "../queues.js";
|
|
|
1165
1165
|
export const LUNORA_QUEUE_REGISTRY: QueueRegistry = {
|
|
1166
1166
|
${r}
|
|
1167
1167
|
};
|
|
1168
|
-
`},
|
|
1168
|
+
`},Gn=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)m(n.exportName,`workflow export "${n.exportName}"`),m(n.bindingName,`workflow binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}" },`).join(`
|
|
1169
1169
|
`);return{build:`
|
|
1170
1170
|
const workflows = createWorkflowContext(env, LUNORA_WORKFLOWS);
|
|
1171
1171
|
`,contextField:`
|
|
@@ -1174,7 +1174,7 @@ ${r}
|
|
|
1174
1174
|
const LUNORA_WORKFLOWS: ReadonlyArray<WorkflowBindingSpec> = [
|
|
1175
1175
|
${t}
|
|
1176
1176
|
];
|
|
1177
|
-
`}},
|
|
1177
|
+
`}},Hn=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)m(n.exportName,`queue export "${n.exportName}"`),m(n.bindingName,`queue binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}", name: ${JSON.stringify(n.name)} },`).join(`
|
|
1178
1178
|
`);return{build:`
|
|
1179
1179
|
const queues = createQueueContext(env, LUNORA_QUEUES);
|
|
1180
1180
|
`,contextField:`
|
|
@@ -1183,7 +1183,7 @@ ${t}
|
|
|
1183
1183
|
const LUNORA_QUEUES: ReadonlyArray<QueueBindingSpec> = [
|
|
1184
1184
|
${t}
|
|
1185
1185
|
];
|
|
1186
|
-
`}},
|
|
1186
|
+
`}},zn=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)m(n.exportName,`agent export "${n.exportName}"`),m(n.bindingName,`agent binding "${n.bindingName}"`);const t=e.map(n=>` { binding: "${n.bindingName}", exportName: "${n.exportName}"${n.publicRun===!0?", publicRun: true":""} },`).join(`
|
|
1187
1187
|
`);return{build:`
|
|
1188
1188
|
const agents = createAgentContext(env, LUNORA_AGENTS);
|
|
1189
1189
|
`,contextField:`
|
|
@@ -1192,21 +1192,21 @@ ${t}
|
|
|
1192
1192
|
const LUNORA_AGENTS: ReadonlyArray<AgentBindingSpec> = [
|
|
1193
1193
|
${t}
|
|
1194
1194
|
];
|
|
1195
|
-
`}},
|
|
1195
|
+
`}},Xn=e=>{if(e.length===0)return{constant:"",override:""};const t={workflows:e.map(n=>({binding:n.bindingName,className:n.className,exportName:n.exportName,name:n.name}))};return{constant:`
|
|
1196
1196
|
/** Read-only declared-workflow metadata (discovered from \`lunora/workflows.ts\`) served via \`__lunora_admin__:listWorkflows\` for the studio's workflows view. */
|
|
1197
1197
|
const LUNORA_WORKFLOWS_INFO: WorkflowsResult = ${JSON.stringify(t,void 0,4)};
|
|
1198
1198
|
`,override:`
|
|
1199
1199
|
protected override workflowsMetadata(): WorkflowsResult {
|
|
1200
1200
|
return LUNORA_WORKFLOWS_INFO;
|
|
1201
1201
|
}
|
|
1202
|
-
`}},
|
|
1202
|
+
`}},Yn=e=>{if(e.length===0)return{constant:"",override:""};const t={queues:e.map(n=>({binding:n.bindingName,...n.tuning.deadLetterQueue===void 0?{}:{deadLetterQueue:n.tuning.deadLetterQueue},exportName:n.exportName,mode:n.mode,name:n.name}))};return{constant:`
|
|
1203
1203
|
/** Read-only declared-queue metadata (discovered from \`lunora/queues.ts\`) served via \`__lunora_admin__:listQueues\` for the studio's queues view. */
|
|
1204
1204
|
const LUNORA_QUEUES_INFO: QueuesResult = ${JSON.stringify(t,void 0,4)};
|
|
1205
1205
|
`,override:`
|
|
1206
1206
|
protected override queuesMetadata(): QueuesResult {
|
|
1207
1207
|
return LUNORA_QUEUES_INFO;
|
|
1208
1208
|
}
|
|
1209
|
-
`}},
|
|
1209
|
+
`}},Zn=e=>{if(!e)return{build:"",configField:"",contextField:"",imports:[],stub:""};const t='throw new Error("ctx.payments: no payment configured. Pass \\`payment\\` to createShardDO().");';return{imports:['import type { LunoraDatabaseLike as LunoraPaymentDbLike, LunoraPayment, PaymentsFromContextOptions } from "@lunora/payment";','import { paymentsFromContext } from "@lunora/payment";'],build:`
|
|
1210
1210
|
const payments: LunoraPayment = config.payment
|
|
1211
1211
|
? paymentsFromContext({ auth: { userId: userId ?? null }, db: db as unknown as LunoraPaymentDbLike }, config.payment(env))
|
|
1212
1212
|
: paymentStub;
|
|
@@ -1242,7 +1242,7 @@ const paymentStub: LunoraPayment = {
|
|
|
1242
1242
|
${t}
|
|
1243
1243
|
},
|
|
1244
1244
|
} as unknown as LunoraPayment;
|
|
1245
|
-
`}},
|
|
1245
|
+
`}},er=e=>e?{imports:['import type { X402Pay, X402PayConfig } from "@lunora/x402/pay";','import { lazyX402Pay } from "@lunora/x402/pay";'],build:`
|
|
1246
1246
|
const x402: X402Pay = config.x402
|
|
1247
1247
|
? lazyX402Pay(config.x402(env), { getSecret: (name: string) => secrets.get(name) })
|
|
1248
1248
|
: x402Stub;
|
|
@@ -1254,7 +1254,10 @@ const x402Stub: X402Pay = {
|
|
|
1254
1254
|
throw new Error("ctx.x402: no pay rail configured. Pass \\\`x402\\\` to createShardDO().");
|
|
1255
1255
|
},
|
|
1256
1256
|
} as unknown as X402Pay;
|
|
1257
|
-
`}:{build:"",configField:"",contextField:"",imports:[],stub:""},
|
|
1257
|
+
`}:{build:"",configField:"",contextField:"",imports:[],stub:""},tr=(e,t,n,r)=>["AdvisoryFinding","DatabaseWriterLike","DataMigrationLike",...r?["FlagsResult"]:[],"MaskPoliciesResult","MigrationRunResult",...n?["QueuesResult"]:[],"RunShardApplyCdcArgs","RunShardMigrationArgs","RlsPoliciesResult","RunShardRankBeforeArgs","RunShardRankPageArgs","RunShardWriteArgs","RunShardWriteResult","SchedulerLike","SchemaLike","ShardDOState","ShardRankPageResult","SqlExec","StorageRulesResult","StudioFeaturesResult","SystemReaderStorageLike","TelemetrySink",...t?["WorkflowsResult"]:[],...e?["WriteHook"]:[]],kr=({advisories:e=[],agents:t=[],containers:n=[],env:r,flagKeys:a=[],hasAccessFacade:o=!1,hasAi:s=!1,hasAnalytics:i=!1,hasBrowser:l=!1,hasFlags:u=!1,hasHyperdrive:p=!1,hasImages:b=!1,hasKv:w=!1,hasNotify:$=!1,hasPayments:d=!1,hasPipelines:c=!1,hasR2sql:g=!1,hasX402:f=!1,maskMetadata:S,mutators:R=[],queues:x=[],rlsMetadata:_,schema:y,schemaSnapshot:I,shapes:te=[],storageRules:ne,studioFeatures:P,useUmbrella:re=!1,workflows:W=[]})=>{const N=H(re),z=R.length>0,L=te.length>0,X=I===void 0?"":Vt(I),C=I===void 0?"":`
|
|
1258
|
+
/** 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. */
|
|
1259
|
+
const LUNORA_SCHEMA_SNAPSHOT: { hash: string; json: string } = { hash: ${JSON.stringify(Gt(I))}, json: ${JSON.stringify(X)} };
|
|
1260
|
+
`,E=I===void 0?"":", schemaSnapshot: LUNORA_SCHEMA_SNAPSHOT",{build:ae,configField:oe,contextField:xe,stub:ke}=In(s),ie=qn(o),U=Pn(w),K=En(u,N.flags),M=Bn(a,u,N.flags),Q=Fn($),Y=Mn(r),J=jn(i),Z=Wn(b),q=Un(p),B=Kn(l),j=Qn(g),F=Jn(c),{build:ve,contextField:$e,importLines:fe,specs:be}=Hn(x),{build:se,contextField:Se,importLines:Re,specs:ye}=Vn(n,y.jurisdiction),{build:le,contextField:Ne,importLines:Oe,specs:we}=Gn(W),{build:Te,contextField:Ae,importLines:de,specs:ce}=zn(t),{build:Le,configField:Ce,contextField:De,imports:ue,stub:pe}=Zn(d),{build:h,configField:_e,imports:it,stub:st}=er(f),lt=e,dt=_??{policies:[],roles:[]},ct=S??{columns:[]},ut=ne??{rules:[]},pt=P??{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:ht,override:gt}=Xn(W),{constant:mt,override:ft}=Yn(x),V=y.vectorIndexes.length>0,he=y.tables.some(O=>O.shardMode==="global"),Ie=y.tables.some(O=>O.shardMode==="global"&&O.globalBackend==="hyperdrive"),je=y.tables.some(O=>O.shardMode==="global"&&O.globalBackend!=="hyperdrive"),G=y.tables.some(O=>O.externalSource!==void 0);if(je&&Ie)throw new ee("INTERNAL",'lunora codegen: mixing `.global()` (D1) and `.global({ backend: "hyperdrive" })` tables in one app is not supported yet — use a single global backend.');const Pe=y.tables.length>0,bt=Tn(y),yt=Ln(y),wt=Dn(y),xt=An(y),We=Cn(y),Ue=tr(V,W.length>0,x.length>0,u);L&&Ue.push("WhereInput");const Ke=_n(he),kt=L?`
|
|
1258
1261
|
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 {
|
|
1259
1262
|
const shape = LUNORA_SHAPES[name];
|
|
1260
1263
|
|
|
@@ -1307,15 +1310,15 @@ const x402Stub: X402Pay = {
|
|
|
1307
1310
|
|
|
1308
1311
|
return { columns: shape.columns, effectiveWhere, global: isGlobal, table: shape.table };
|
|
1309
1312
|
}
|
|
1310
|
-
`:"",
|
|
1313
|
+
`:"",vt=z?`
|
|
1311
1314
|
protected override isCustomMutator(functionPath: string): boolean {
|
|
1312
1315
|
return LUNORA_MUTATOR_PATHS.has(functionPath);
|
|
1313
1316
|
}
|
|
1314
|
-
`:""
|
|
1315
|
-
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",
|
|
1316
|
-
d1?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:""
|
|
1317
|
-
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",
|
|
1318
|
-
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",
|
|
1317
|
+
`:"",$t=L?"\n/** Per-table RLS read policies (hoisted from `.use(rls(...))` chains) the shape resolver AND-merges into each `defineShape` predicate so partial replication honours read policies. */\nconst LUNORA_RLS_READ_REGISTRY = buildRlsReadRegistry(Object.values(LUNORA_FUNCTIONS));\n":"",St=L?"assertShapeShardable, ":"",ge=[`import type { ${Ue.join(", ")} } from "${N.do}";`,`import { applyCdcChanges, ${St}createShardCtxDb, ${G?"isSourceDue, pullExternalSourceIncrementalTick, pullExternalSourceTick, ":""}runDataMigration, runShardMigrations, ${Ke.importFragment}ShardDO as ShardDOBase } from "${N.do}";`,...G?[`import type { ExternalSourceLike, SourceClientLike } from "${N.do}";`]:[],L?`import { asBucketStorage, buildRlsReadRegistry, composeShapeReadWhere, createSecrets, LunoraError } from "${N.server}";`:`import { asBucketStorage, createSecrets, LunoraError } from "${N.server}";`];Pe&&ge.push(`import { bindOrm, bindTableFacade } from "${N.server}";`),V&&ge.push('import type { SchemaLike as VectorSchemaLike, VectorizeIndexLike, VectorSearchLike } from "@lunora/bindings/vectors";','import { createContextVectors, createVectors, createVectorSyncHook } from "@lunora/bindings/vectors";'),s&&ge.push('import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'),ge.push(...ie.importLines,...U.importLines,...K.importLines,...Q.importLines,...Y.importLines,...J.importLines,...Z.importLines,...q.importLines,...B.importLines,...j.importLines,...F.importLines,...Re,...Oe,...fe,...de,...ue,...it,"",'import schema from "../schema.js";',`import { ${["LUNORA_FUNCTIONS","LUNORA_LIFECYCLE_HOOKS","LUNORA_MIGRATIONS",...z?["LUNORA_MUTATOR_PATHS"]:[],...L?["LUNORA_SHAPES"]:[]].join(", ")} } from "./functions.js";`);const Rt=V?`
|
|
1318
|
+
vectors?: (env: Record<string, unknown>) => Record<string, VectorizeIndexLike>;`:"",Nt=je?`
|
|
1319
|
+
d1?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",Ot=Ie?`
|
|
1320
|
+
hyperdriveGlobal?: (env: Record<string, unknown>, request?: { identity?: Record<string, unknown>; userId?: string }) => DatabaseWriterLike | undefined;`:"",Tt=G?`
|
|
1321
|
+
sourceClient?: (env: Record<string, unknown>, binding: string) => { query: <Row = Record<string, unknown>>(text: string, params?: readonly unknown[]) => Promise<Row[]> } | undefined;`:"",At=he?'\nconst globalDbStub: DatabaseWriterLike = {\n aggregate: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n count: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n delete: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n findFirst: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n findFirstOrThrow: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n findMany: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n get: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n groupBy: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n insert: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n normalizeId: () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n patch: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n query: () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n rank: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n rankPage: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n replace: async () => {\n throw new Error("ctx.db.<globalTable>: no global backend configured. Pass `d1` or `hyperdriveGlobal` to createShardDO().");\n },\n};\n':"",Lt=V?`
|
|
1319
1322
|
const vectorsStub: VectorSearchLike = {
|
|
1320
1323
|
deleteByIds: async () => {
|
|
1321
1324
|
throw new Error("ctx.vectors: no vectors configured. Pass \`vectors\` to createShardDO().");
|
|
@@ -1333,7 +1336,7 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1333
1336
|
throw new Error("ctx.vectors: no vectors configured. Pass \`vectors\` to createShardDO().");
|
|
1334
1337
|
},
|
|
1335
1338
|
};
|
|
1336
|
-
`:"",
|
|
1339
|
+
`:"",Ct=V?`
|
|
1337
1340
|
let vectors: VectorSearchLike;
|
|
1338
1341
|
let onWrite: WriteHook | undefined;
|
|
1339
1342
|
|
|
@@ -1346,9 +1349,9 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1346
1349
|
vectors = vectorsStub;
|
|
1347
1350
|
onWrite = undefined;
|
|
1348
1351
|
}
|
|
1349
|
-
`:"",Qe=
|
|
1352
|
+
`:"",Qe=he?`
|
|
1350
1353
|
globalDb,`:"",Je=`
|
|
1351
|
-
auth: { identity: identity ?? null, userId: userId ?? null },`,
|
|
1354
|
+
auth: { identity: identity ?? null, userId: userId ?? null },`,Dt=V?`{${Je}
|
|
1352
1355
|
broadcast: (delta) => {
|
|
1353
1356
|
this.recordChangedTable(delta.table);
|
|
1354
1357
|
},
|
|
@@ -1373,10 +1376,10 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1373
1376
|
schema: schema as unknown as SchemaLike,
|
|
1374
1377
|
sql: this.sql as SqlExec,
|
|
1375
1378
|
storage,${Qe}
|
|
1376
|
-
}`,
|
|
1377
|
-
vectors,`:"",
|
|
1378
|
-
orm: bindOrm(facade),`:"",
|
|
1379
|
-
`:"",
|
|
1379
|
+
}`,_t=V?`
|
|
1380
|
+
vectors,`:"",It=Pe?`
|
|
1381
|
+
orm: bindOrm(facade),`:"",Pt="",Ve=Ie?"config.hyperdriveGlobal":"config.d1",Et=he?` const globalDb: DatabaseWriterLike = ${Ve}?.(env, { identity, userId }) ?? globalDbStub;
|
|
1382
|
+
`:"",Ft=L&&he?`
|
|
1380
1383
|
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 }>> {
|
|
1381
1384
|
const env = this.env as Record<string, unknown>;
|
|
1382
1385
|
const globalDb: DatabaseWriterLike = ${Ve}?.(env, identity) ?? globalDbStub;
|
|
@@ -1406,10 +1409,10 @@ const vectorsStub: VectorSearchLike = {
|
|
|
1406
1409
|
|
|
1407
1410
|
return rows;
|
|
1408
1411
|
}
|
|
1409
|
-
`:"",
|
|
1412
|
+
`:"",Mt=G?`
|
|
1410
1413
|
const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
|
|
1411
1414
|
const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
1412
|
-
`:"",
|
|
1415
|
+
`:"",qt=G?`
|
|
1413
1416
|
protected override async pollExternalSources(): Promise<number | undefined> {
|
|
1414
1417
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
1415
1418
|
const sourced = Object.entries((schema as unknown as SchemaLike).tables)
|
|
@@ -1510,10 +1513,10 @@ const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
|
1510
1513
|
|
|
1511
1514
|
return nextDueAt;
|
|
1512
1515
|
}
|
|
1513
|
-
`:"",Ge=We.length>0,
|
|
1516
|
+
`:"",Ge=We.length>0,Bt=G||Ge?`
|
|
1514
1517
|
public constructor(state: ShardDOState, env: unknown) {
|
|
1515
1518
|
super(state, env);
|
|
1516
|
-
${
|
|
1519
|
+
${G?`
|
|
1517
1520
|
const autoSourced = Object.values((schema as unknown as SchemaLike).tables).some((definition) => {
|
|
1518
1521
|
const source = (definition as { externalSource?: ExternalSourceLike }).externalSource;
|
|
1519
1522
|
|
|
@@ -1528,22 +1531,22 @@ ${J?`
|
|
|
1528
1531
|
void this.scheduleTtlSweep();
|
|
1529
1532
|
}
|
|
1530
1533
|
`:""} }
|
|
1531
|
-
`:"",
|
|
1534
|
+
`:"",jt=Pe?`
|
|
1532
1535
|
const facade = db as unknown as Record<string, ReturnType<typeof bindTableFacade>>;
|
|
1533
1536
|
${y.tables.map(O=>` facade[${JSON.stringify(O.name)}] = bindTableFacade(db, ${JSON.stringify(O.name)});`).join(`
|
|
1534
1537
|
`)}
|
|
1535
|
-
`:"",
|
|
1538
|
+
`:"",Wt=`${ie.build}${U.build}${K.build}${J.build}${Y.build}
|
|
1536
1539
|
const secrets = createSecrets(env);
|
|
1537
|
-
`,
|
|
1538
|
-
secrets,`,
|
|
1540
|
+
`,Ut=`${ie.contextField}${U.contextField}${K.contextField}${Q.contextField}${J.contextField}${Y.contextField}
|
|
1541
|
+
secrets,`,Kt=Q.build,He=b||p||l||g||c||f,Qt=He?`
|
|
1539
1542
|
// ActionCtx-only helpers (external, non-deterministic I/O): constructed
|
|
1540
1543
|
// and attached only for an \`action\` so query/mutation ctx never carry them.
|
|
1541
1544
|
if (isAction) {
|
|
1542
|
-
${
|
|
1545
|
+
${Z.build}${q.build}${B.build}${j.build}${F.build}${h}${[...b?[" ctx.images = images;"]:[],...p?[" ctx.sql = sql;"]:[],...l?[" ctx.browser = browser;"]:[],...g?[" ctx.r2sql = r2sql;"]:[],...c?[" ctx.pipelines = pipelines;"]:[],...f?[" ctx.x402 = x402;"]:[]].join(`
|
|
1543
1546
|
`)}
|
|
1544
1547
|
}
|
|
1545
|
-
`:"",
|
|
1546
|
-
`:"";return`${k}${
|
|
1548
|
+
`:"",Jt=He?` const isAction = LUNORA_FUNCTIONS[options.functionPath ?? ""]?.kind === "action";
|
|
1549
|
+
`:"";return`${k}${ge.join(`
|
|
1547
1550
|
`)}
|
|
1548
1551
|
|
|
1549
1552
|
type FunctionKind = "action" | "mutation" | "query";
|
|
@@ -1553,42 +1556,42 @@ interface FunctionReference {
|
|
|
1553
1556
|
}
|
|
1554
1557
|
|
|
1555
1558
|
/** Foreign-key columns per table (\`v.id("target")\` fields) for the data browser. */
|
|
1556
|
-
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(
|
|
1559
|
+
const LUNORA_TABLE_REFS: Record<string, Record<string, string>> = ${JSON.stringify(bt,void 0,4)};
|
|
1557
1560
|
|
|
1558
1561
|
/** Declared indexes per table (secondary, search, geo, rank, vector) for the schema viewer. */
|
|
1559
|
-
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(
|
|
1562
|
+
const LUNORA_TABLE_INDEXES: Record<string, Array<{ fields: string[]; name: string; type: "geo" | "index" | "rank" | "search" | "vector"; unique?: boolean }>> = ${JSON.stringify(yt,void 0,4)};
|
|
1560
1563
|
|
|
1561
1564
|
/** Columns per table (typed, with PK/FK markers) for the studio's schema diagram, served via \`__lunora_admin__:describeTable\`. */
|
|
1562
|
-
const LUNORA_TABLE_COLUMNS: Record<string, Array<{ isStorage?: boolean; name: string; optional: boolean; pk?: boolean; ref?: string; type: string }>> = ${JSON.stringify(
|
|
1565
|
+
const LUNORA_TABLE_COLUMNS: Record<string, Array<{ isStorage?: boolean; name: string; optional: boolean; pk?: boolean; ref?: string; type: string }>> = ${JSON.stringify(wt,void 0,4)};
|
|
1563
1566
|
|
|
1564
1567
|
/** Storage-key columns per table (\`v.storage(...)\` fields) for the file browser's records↔files join. */
|
|
1565
|
-
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(
|
|
1568
|
+
const LUNORA_STORAGE_COLUMNS: Record<string, string[]> = ${JSON.stringify(xt,void 0,4)};
|
|
1566
1569
|
|
|
1567
1570
|
/** Declarative TTL policies (\`.ttl(field, { after? })\`) the DO alarm sweep auto-expires rows for. */
|
|
1568
1571
|
const LUNORA_TTL_SWEEPS: Array<{ after?: number; field: string; softDeleteField?: string; table: string }> = ${JSON.stringify(We,void 0,4)};
|
|
1569
1572
|
|
|
1570
1573
|
/** Static schema advisories (computed by @lunora/advisor at codegen time) served via \`__lunora_admin__:getAdvisories\`. */
|
|
1571
|
-
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(
|
|
1574
|
+
const LUNORA_ADVISORIES: AdvisoryFinding[] = ${JSON.stringify(lt,void 0,4)};
|
|
1572
1575
|
|
|
1573
1576
|
/** Read-only RLS metadata (policies + roles discovered from \`.use(rls(...))\` chains) served via \`__lunora_admin__:rlsPolicies\` for the studio's RLS inspector. */
|
|
1574
|
-
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(
|
|
1577
|
+
const LUNORA_RLS_METADATA: RlsPoliciesResult = ${JSON.stringify(dt,void 0,4)};
|
|
1575
1578
|
|
|
1576
1579
|
/** 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. */
|
|
1577
|
-
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(
|
|
1580
|
+
const LUNORA_MASK_METADATA: MaskPoliciesResult = ${JSON.stringify(ct,void 0,4)};
|
|
1578
1581
|
|
|
1579
1582
|
/** Read-only storage access-rule metadata (discovered from \`.use(storageRules(...))\` chains) served via \`__lunora_admin__:storageRules\` for the studio's access-rules view. */
|
|
1580
|
-
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(
|
|
1583
|
+
const LUNORA_STORAGE_RULES: StorageRulesResult = ${JSON.stringify(ut,void 0,4)};
|
|
1581
1584
|
|
|
1582
1585
|
/** 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. */
|
|
1583
|
-
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(
|
|
1584
|
-
${
|
|
1586
|
+
const LUNORA_STUDIO_FEATURES: StudioFeaturesResult = ${JSON.stringify(pt,void 0,4)};
|
|
1587
|
+
${C}${M.constant}${$t}${ht}${mt}${ye}${we}${be}${ce}
|
|
1585
1588
|
export interface ShardDOConfig {
|
|
1586
1589
|
/** Opt into change-data-capture: records a post-image to \`__cdc_log\` on every write (backs streaming export + replay-PITR). */
|
|
1587
1590
|
cdc?: boolean;
|
|
1588
1591
|
/** Optional telemetry sink. When supplied, each \`ctx.log.*\` call is forwarded to \`sink.onLog\`. Pass the SAME sink you give \`createWorker({ observability })\` (which drives \`onRpc\`) to route both RPC and log events. */
|
|
1589
1592
|
observability?: (env: Record<string, unknown>) => TelemetrySink | undefined;
|
|
1590
1593
|
scheduler?: (env: Record<string, unknown>) => unknown;
|
|
1591
|
-
storage?: (env: Record<string, unknown>) => unknown;${
|
|
1594
|
+
storage?: (env: Record<string, unknown>) => unknown;${Rt}${oe}${U.configField}${K.configField}${J.configField}${Z.configField}${q.configField}${B.configField}${j.configField}${F.configField}${Ce}${_e}${Nt}${Ot}${Tt}
|
|
1592
1595
|
}
|
|
1593
1596
|
|
|
1594
1597
|
const schedulerStub = {
|
|
@@ -1626,7 +1629,7 @@ const storageStub = {
|
|
|
1626
1629
|
throw new Error("ctx.storage: no storage configured. Pass \`storage\` to createShardDO().");
|
|
1627
1630
|
},
|
|
1628
1631
|
};
|
|
1629
|
-
${
|
|
1632
|
+
${At}${Mt}${Lt}${ke}${U.stub}${K.stub}${J.stub}${Z.stub}${q.stub}${B.stub}${j.stub}${F.stub}${pe}${st}${Pt}
|
|
1630
1633
|
// Bound in-process \`ctx.run*\` composition depth so a self- or cyclically-
|
|
1631
1634
|
// referencing call fails loudly with a clear error instead of overflowing the
|
|
1632
1635
|
// stack. Tracked across the awaited handler chain (one DO invocation is
|
|
@@ -1663,7 +1666,7 @@ const dispatchRun = async (expected: FunctionKind, functionPath: string, args: R
|
|
|
1663
1666
|
* from the worker entry so wrangler binds it by name.
|
|
1664
1667
|
*/
|
|
1665
1668
|
export const createShardDO = (config: ShardDOConfig = {}): new (state: ShardDOState, env: unknown) => ShardDOBase =>
|
|
1666
|
-
class extends ShardDOBase {${
|
|
1669
|
+
class extends ShardDOBase {${Bt}
|
|
1667
1670
|
private migrated = false;
|
|
1668
1671
|
|
|
1669
1672
|
public override async handleRpc(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
@@ -1739,7 +1742,7 @@ ${Ke.override}
|
|
|
1739
1742
|
iterator: (signal) => (registered.handler as (context: unknown, args: Record<string, unknown>, signal: AbortSignal) => AsyncIterable<unknown>)(this.buildCtx({ functionPath }), args, signal),
|
|
1740
1743
|
};
|
|
1741
1744
|
}
|
|
1742
|
-
${
|
|
1745
|
+
${vt}${kt}${Ft}${qt}
|
|
1743
1746
|
protected override lifecycleHookPaths(event: "connect" | "disconnect"): readonly string[] {
|
|
1744
1747
|
return LUNORA_LIFECYCLE_HOOKS[event];
|
|
1745
1748
|
}
|
|
@@ -1779,7 +1782,7 @@ ${yt}${bt}${It}${Pt}
|
|
|
1779
1782
|
protected override studioFeatures(): StudioFeaturesResult {
|
|
1780
1783
|
return LUNORA_STUDIO_FEATURES;
|
|
1781
1784
|
}
|
|
1782
|
-
${
|
|
1785
|
+
${M.evaluateOverride}${M.subscriptionOverride}${gt}${ft}
|
|
1783
1786
|
protected override advisories(): AdvisoryFinding[] {
|
|
1784
1787
|
return LUNORA_ADVISORIES;
|
|
1785
1788
|
}
|
|
@@ -1988,7 +1991,7 @@ ${re.evaluateOverride}${re.subscriptionOverride}${ct}${pt}
|
|
|
1988
1991
|
return;
|
|
1989
1992
|
}
|
|
1990
1993
|
|
|
1991
|
-
runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false });
|
|
1994
|
+
runShardMigrations(this.sql as SqlExec, schema as unknown as SchemaLike, { cdc: config.cdc ?? false${E} });
|
|
1992
1995
|
this.migrated = true;
|
|
1993
1996
|
}
|
|
1994
1997
|
|
|
@@ -2001,7 +2004,7 @@ ${re.evaluateOverride}${re.subscriptionOverride}${ct}${pt}
|
|
|
2001
2004
|
// dispatch path) fall back to the per-request fields as before.
|
|
2002
2005
|
const userId = options.identity ? options.identity.userId : this.getCurrentUserId();
|
|
2003
2006
|
const identity = options.identity ? options.identity.identity : this.getCurrentIdentity();
|
|
2004
|
-
${
|
|
2007
|
+
${Ct}${ae}${Wt}${se}${le}${ve}${Te}
|
|
2005
2008
|
const scheduler = (config.scheduler?.(env) ?? schedulerStub) as SchedulerLike;
|
|
2006
2009
|
// Build the storage adapter once and share it between \`ctx.storage\`
|
|
2007
2010
|
// and \`ctx.db.system._storage\` so both read the same R2 binding. The
|
|
@@ -2028,13 +2031,13 @@ ${Ot}${ne}${Mt}${ve}${de}${ie}${ce}
|
|
|
2028
2031
|
// so both write to the same trace.
|
|
2029
2032
|
const span = this.makeDispatchSpan(traceAnchor, observability);
|
|
2030
2033
|
|
|
2031
|
-
${
|
|
2034
|
+
${Et} // \`ctx.db\`, wrapped in automatic instrumentation: by default this
|
|
2032
2035
|
// adds aggregate counters (call count, total time, per-operation
|
|
2033
2036
|
// breakdown) to the wide event rather than a span per call, so a
|
|
2034
2037
|
// handler making hundreds of queries stays readable. See
|
|
2035
2038
|
// \`instrumentDatabase\` for the \`"spans"\` / \`"off"\` levels.
|
|
2036
|
-
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${
|
|
2037
|
-
${
|
|
2039
|
+
const db: DatabaseWriterLike = this.instrumentDb(createShardCtxDb(${Dt}), logFunctionPath, traceAnchor, observability);
|
|
2040
|
+
${jt}${Le}
|
|
2038
2041
|
|
|
2039
2042
|
// \`ctx.trace\` / \`ctx.metrics\`: spans and measurements to the same sink.
|
|
2040
2043
|
// The trace anchor is threaded explicitly for the same reason \`identity\`
|
|
@@ -2042,7 +2045,7 @@ ${Ft}${Te}
|
|
|
2042
2045
|
// writing mutation's trace from the shared per-request field.
|
|
2043
2046
|
const trace = this.makeTracer(logFunctionPath, observability, traceAnchor);
|
|
2044
2047
|
const metrics = this.makeMetrics(logFunctionPath, observability);
|
|
2045
|
-
${
|
|
2048
|
+
${Kt}
|
|
2046
2049
|
// \`ctx.now\`: the wall-clock instant (epoch ms) this function began,
|
|
2047
2050
|
// captured ONCE so the whole handler body sees a single stable value.
|
|
2048
2051
|
// Query/mutation handlers must be deterministic (they may be re-run on
|
|
@@ -2065,13 +2068,13 @@ ${Bt}
|
|
|
2065
2068
|
ip: this.getCurrentIp(),
|
|
2066
2069
|
log,
|
|
2067
2070
|
metrics,
|
|
2068
|
-
now,${
|
|
2071
|
+
now,${It}
|
|
2069
2072
|
scheduler,
|
|
2070
2073
|
span,
|
|
2071
2074
|
storage,
|
|
2072
|
-
trace,${
|
|
2075
|
+
trace,${_t}${xe}${Ut}${De}${Se}${Ne}${$e}${Ae}
|
|
2073
2076
|
};
|
|
2074
|
-
${
|
|
2077
|
+
${Jt}${Qt}
|
|
2075
2078
|
ctx.runAction = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("action", reference.__lunoraRef, fnArgs, ctx);
|
|
2076
2079
|
ctx.runMutation = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("mutation", reference.__lunoraRef, fnArgs, ctx);
|
|
2077
2080
|
ctx.runQuery = (reference: FunctionReference, fnArgs: Record<string, unknown>) => dispatchRun("query", reference.__lunoraRef, fnArgs, ctx);
|
|
@@ -2079,19 +2082,19 @@ ${Wt}${jt}
|
|
|
2079
2082
|
return ctx;
|
|
2080
2083
|
}
|
|
2081
2084
|
};
|
|
2082
|
-
`},Be=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:T(e)};case"bigint":return{builder:"blob",mode:"bigint",notNull:!0};case"boolean":return{builder:"integer",mode:"boolean",notNull:!0};case"bytes":return{builder:"blob",mode:"buffer",notNull:!0};case"date":case"timestamp":return{builder:"integer",notNull:!0};case"id":return{builder:"text",notNull:!0};case"literal":{const t=e.literalValue??"";return t.startsWith('"')||t.startsWith("'")?{builder:"text",notNull:!0}:t==="true"||t==="false"?{builder:"integer",mode:"boolean",notNull:!0}:t==="null"?{builder:"text",notNull:!0}:{builder:"real",notNull:!0}}case"null":return{builder:"text",notNull:!0};case"number":return{builder:"real",notNull:!0};case"optional":return{...e.inner?Be(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},
|
|
2085
|
+
`},Be=e=>{switch(e.kind){case"array":case"object":case"record":case"union":return{builder:"text",mode:"json",notNull:!0,typeAnnotation:T(e)};case"bigint":return{builder:"blob",mode:"bigint",notNull:!0};case"boolean":return{builder:"integer",mode:"boolean",notNull:!0};case"bytes":return{builder:"blob",mode:"buffer",notNull:!0};case"date":case"timestamp":return{builder:"integer",notNull:!0};case"id":return{builder:"text",notNull:!0};case"literal":{const t=e.literalValue??"";return t.startsWith('"')||t.startsWith("'")?{builder:"text",notNull:!0}:t==="true"||t==="false"?{builder:"integer",mode:"boolean",notNull:!0}:t==="null"?{builder:"text",notNull:!0}:{builder:"real",notNull:!0}}case"null":return{builder:"text",notNull:!0};case"number":return{builder:"real",notNull:!0};case"optional":return{...e.inner?Be(e.inner):{builder:"text",notNull:!1},notNull:!1};case"storage":case"string":return{builder:"text",notNull:!0};default:return{builder:"text",notNull:!0}}},nr=(e,t,n)=>{m(e,"drizzle column name");const r=Be(t),a=t.kind==="optional"&&t.inner?t.inner:t,o=r.mode?`, { mode: "${r.mode}" }`:"";let s=`${r.builder}("${e}"${o})`;return r.typeAnnotation&&(s+=`.$type<${r.typeAnnotation}>()`),a.kind==="id"&&a.tableName&&n.has(a.tableName)&&(s+=`.references(() => ${a.tableName}._id)`),r.notNull&&(s+=".notNull()"),s},rr=e=>{m(e.name,"drizzle index name");const t=e.unique?"uniqueIndex":"index",n=e.fields.map(r=>(m(r,"drizzle index field"),`t.${r}`)).join(", ");return` ${e.name}: ${t}("${e.name}").on(${n}),`},ar=(e,t)=>{m(e.name,"table name");const n=[' _id: text("_id").primaryKey(),',' _creationTime: integer("_creationTime").notNull(),',...Object.entries(e.shape).map(([a,o])=>` ${a}: ${nr(a,o,t)},`)].join(`
|
|
2083
2086
|
`),r=e.indexes.length>0?`, (t) => ({
|
|
2084
|
-
${e.indexes.map(a=>
|
|
2087
|
+
${e.indexes.map(a=>rr(a)).join(`
|
|
2085
2088
|
`)}
|
|
2086
2089
|
})`:"";return`export const ${e.name} = sqliteTable("${e.name}", {
|
|
2087
2090
|
${n}
|
|
2088
|
-
}${r});`},
|
|
2089
|
-
`;const n=
|
|
2091
|
+
}${r});`},or=e=>{const t=new Set,n=new Set;t.add("text"),t.add("integer"),t.add("sqliteTable");for(const r of e){for(const a of Object.values(r.shape)){const o=Be(a);t.add(o.builder)}for(const a of r.indexes)n.add(a.unique?"uniqueIndex":"index")}return{columns:[...t].toSorted((r,a)=>r.localeCompare(a)),indexes:[...n].toSorted((r,a)=>r.localeCompare(a))}},Xe=(e,t=!1)=>{if(e.length===0)return`${k}export {};
|
|
2092
|
+
`;const n=H(t),{columns:r,indexes:a}=or(e),o=[...a,...r].toSorted((l,u)=>l.localeCompare(u)),s=new Set(e.map(l=>l.name)),i=e.map(l=>ar(l,s)).join(`
|
|
2090
2093
|
|
|
2091
2094
|
`);return`${k}import { ${o.join(", ")} } from "${n.serverDrizzle}";
|
|
2092
2095
|
|
|
2093
2096
|
${i}
|
|
2094
|
-
`},
|
|
2097
|
+
`},vr=(e,t=!1)=>{const n=e.tables.filter(a=>a.shardMode==="global"),r=e.tables.filter(a=>a.shardMode!=="global");return{global:Xe(n,t),shard:Xe(r,t)}},$r=e=>{const t=[],n=new Map;for(const i of e){const l=n.get(i.cron);l?l.push(i):(n.set(i.cron,[i]),t.push(i.cron))}const r=t.map(i=>` ${JSON.stringify(i)},`).join(`
|
|
2095
2098
|
`),a=r.length>0?`
|
|
2096
2099
|
${r}
|
|
2097
2100
|
`:"",o=[...n.entries()].map(([i,l])=>{const u=l.map(p=>{const b=p.workflow?`workflow: ${JSON.stringify(p.workflow.binding)}`:`functionPath: ${JSON.stringify(p.functionPath)}`;return` { name: ${JSON.stringify(p.name)}, ${b}, args: ${JSON.stringify(p.args)} },`}).join(`
|
|
@@ -2125,7 +2128,7 @@ export const LUNORA_CRON_TRIGGERS: ReadonlyArray<string> = [${a}];
|
|
|
2125
2128
|
* looks up \`event.cron\` here and dispatches every job in the list.
|
|
2126
2129
|
*/
|
|
2127
2130
|
export const LUNORA_CRONS: Record<string, ReadonlyArray<LunoraCronJob>> = {${s}};
|
|
2128
|
-
`},
|
|
2131
|
+
`},Sr=e=>{const t=[...e].toSorted((r,a)=>r.name.localeCompare(a.name)).map(r=>{const a=[`name: ${JSON.stringify(r.name)}`,`table: ${JSON.stringify(r.table)}`];return r.field!==void 0&&a.push(`field: ${JSON.stringify(r.field)}`),r.dimensions!==void 0&&a.push(`dimensions: ${JSON.stringify(r.dimensions)}`),r.metric!==void 0&&a.push(`metric: ${JSON.stringify(r.metric)}`),r.metadata!==void 0&&a.push(`metadata: ${JSON.stringify(r.metadata)}`),` { ${a.join(", ")} },`}).join(`
|
|
2129
2132
|
`),n=t.length>0?`
|
|
2130
2133
|
${t}
|
|
2131
2134
|
`:"";return`${k}/**
|
|
@@ -2149,4 +2152,4 @@ export interface LunoraVectorIndex {
|
|
|
2149
2152
|
* \`createWorker({ vectorIntrospector })\` to back the studio's vector browser.
|
|
2150
2153
|
*/
|
|
2151
2154
|
export const LUNORA_VECTOR_INDEXES: ReadonlyArray<LunoraVectorIndex> = [${n}];
|
|
2152
|
-
`},
|
|
2155
|
+
`},Rr=e=>{const t=new Set,n=[];for(const r of e)t.has(r.cron)||(t.add(r.cron),n.push(r.cron));return n};export{wr as K,yr as Q,xr as V,br as W,ur as Z,cr as a,Rr as c,pr as g,gr as h,$r as i,mr as k,Sr as l,hr as m,An as n,Ht as r,vr as s,kr as t,fr as v,k as w};
|