@lunora/codegen 1.0.0-alpha.320 → 1.0.0-alpha.322
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 +22 -4
- package/dist/index.d.ts +22 -4
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/DEFAULT_TARGET-DksDPUdg.mjs +1 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-BW62y2zs.mjs +11 -0
- package/dist/packem_shared/capabilitiesUsedBy-D3pvpeAt.mjs +1 -0
- package/dist/packem_shared/{emitApp-BEe4wd3R.mjs → emitApp-DphNN43J.mjs} +12 -11
- package/dist/packem_shared/{emitFunctions-rjyb7h7k.mjs → emitFunctions-CuZzKaU4.mjs} +37 -40
- package/dist/packem_shared/{emitShard-D3Po46nf.mjs → emitShard-BF--3qQv.mjs} +1 -1
- package/dist/packem_shared/{shard-CsOnD3Na.mjs → shard-ceGu_Fps.mjs} +81 -75
- package/package.json +9 -9
- package/dist/packem_shared/DEFAULT_TARGET-B0FkdiZq.mjs +0 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-Bo67h-3B.mjs +0 -11
- package/dist/packem_shared/capabilitiesUsedBy-QgSZyE0T.mjs +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{SyntaxKind as c,Node as r}from"ts-morph";import{CAPABILITIES as m}from"./CAPABILITY_PROBES-brcmKenl.mjs";import{bindingKeyName as p,listLunoraSourceFiles as g}from"./isTestPath-B81lOULB.mjs";import{scanImportDeclaration as u,noSandboxUsage as l}from"./discoverSandboxUsage-w6Q3RvxZ.mjs";const d="ctx",E=(e,t,o)=>{for(const n of e.getDescendantsOfKind(c.ElementAccessExpression)){const s=n.getArgumentExpression();t(n.getExpression())&&s!==void 0&&(r.isStringLiteral(s)||r.isNoSubstitutionTemplateLiteral(s))&&o.add(s.getLiteralValue())}},x=e=>{const t=new Set,o=new Set([d]),n=i=>{if(r.isObjectBindingPattern(i))for(const a of i.getElements()){const f=p(a);f&&t.add(f)}};for(const i of e.getDescendantsOfKind(c.BindingElement)){if(p(i)!==d)continue;const a=i.getNameNode();r.isIdentifier(a)?o.add(a.getText()):n(a)}const s=i=>r.isIdentifier(i)&&o.has(i.getText());for(const i of e.getDescendantsOfKind(c.PropertyAccessExpression))s(i.getExpression())&&t.add(i.getName());E(e,s,t);for(const i of e.getDescendantsOfKind(c.VariableDeclaration)){const a=i.getInitializer();a!==void 0&&s(a)&&n(i.getNameNode())}return t},y=e=>{if(e.isTypeOnly())return!0;if(r.isExportDeclaration(e)){const o=e.getNamedExports();return!e.isNamespaceExport()&&o.length>0&&o.every(n=>n.isTypeOnly())}const t=e.getNamedImports();return e.getDefaultImport()===void 0&&e.getNamespaceImport()===void 0&&t.length>0&&t.every(o=>o.isTypeOnly())},N=new Map(m.flatMap(({bindingFreeExports:e,moduleSpecifier:t})=>e===void 0?[]:[[t,new Set(e)]])),I=(e,t)=>{const o=N.get(t);if(o===void 0||r.isImportDeclaration(e)&&(e.getDefaultImport()!==void 0||e.getNamespaceImport()!==void 0))return!1;const n=r.isExportDeclaration(e)?e.getNamedExports():e.getNamedImports();return n.length>0&&n.every(s=>s.isTypeOnly()||o.has(s.getName()))},S=e=>{const t=new Set;for(const o of e.getDescendantsOfKind(c.CallExpression)){const[n]=o.getArguments();o.getExpression().getKind()===c.ImportKeyword&&(r.isStringLiteral(n)||r.isNoSubstitutionTemplateLiteral(n))&&t.add(n.getLiteralValue())}return t},T=e=>{const t=e.getImportDeclarations(),o=l();for(const n of t){const s=u(n);for(const i of Object.keys(o))o[i]||=s[i]}return{contextReads:x(e),dynamicImports:S(e),sandboxTools:o,valueImports:new Set([...t,...e.getExportDeclarations()].flatMap(n=>{const s=n.getModuleSpecifierValue();return s===void 0||y(n)||I(n,s)?[]:[s]}))}},b=e=>{const t=new Set,o=new Set,n=l(),s=new Set;for(const i of e){for(const a of i.contextReads)t.add(a);for(const a of i.dynamicImports)o.add(a);for(const a of i.valueImports)s.add(a);for(const a of Object.keys(n))n[a]||=i.sandboxTools[a]}return{contextReads:t,dynamicImports:o,sandboxTools:n,valueImports:s}},O=e=>new Set(m.filter(({contextProperty:t,moduleSpecifier:o})=>e.valueImports.has(o)||t!==void 0&&e.contextReads.has(t)).map(({key:t})=>t)),v=new RegExp(String.raw`\b${d}\b`,"u"),w=new RegExp(String.raw`\b(?:${m.flatMap(({contextProperty:e})=>e===void 0?[]:[e]).join("|")})\b`,"u"),K=e=>v.test(e)&&w.test(e),L=(e,t)=>{const o=b(g(t).map(s=>T(e.getSourceFile(s)??e.addSourceFileAtPath(s)))),n=O(o);return Object.fromEntries(m.map(({key:s})=>[s,n.has(s)]))};export{O as capabilitiesUsedBy,x as contextPropertiesRead,L as discoverFeatureUsage,b as foldCapabilitySignals,K as mayReadCapabilityContext,T as sourceCapabilitySignals};
|
|
@@ -361,8 +361,9 @@ const buildGlobalCdcApplier =
|
|
|
361
361
|
|
|
362
362
|
return this;
|
|
363
363
|
}`," /**\n * Route the shard's `ctx.log` lines, `ctx.trace` spans and `ctx.metrics` measurements to a telemetry sink.\n *\n * The DO half of observability: without it every in-handler signal stays in the shard's local ring buffer (the studio Logs panel) and reaches no collector. The worker half — one `onRpc` event per dispatched RPC — is a `createWorker` option; pass the SAME sink to both via `.extend((env) => ({ observability: sink(env) }))` to correlate them.\n */\n public observability(selector: NonNullable<ShardConfig[\"observability\"]>): this {\n this.observabilitySink = selector;\n\n return this;\n }",' /** Resolution policy for a relation-crossing `where` whose child is co-located in this shard: `"auto"` (cost-based, the engine default), `"always"` (inline correlated EXISTS) or `"never"` (universal semijoin). All three return identical rows. */\n public relationExistsPushDown(mode: NonNullable<ShardConfig["relationExistsPushDown"]>): this {\n this.relationExistsPushDownMode = mode;\n\n return this;\n }',` /** Authorize each RPC/subscription read and fence its eventual delivery against durable authority epochs. */
|
|
364
|
-
public deliveryAuthorization(selector: NonNullable<ShardConfig["deliveryAuthorization"]
|
|
365
|
-
this.deliveryAuthorizationSelector = selector
|
|
364
|
+
public deliveryAuthorization(selector: (env: Env) => ReturnType<NonNullable<ShardConfig["deliveryAuthorization"]>>): this {
|
|
365
|
+
this.deliveryAuthorizationSelector = selector as NonNullable<ShardConfig["deliveryAuthorization"]>;
|
|
366
|
+
|
|
366
367
|
return this;
|
|
367
368
|
}`,...e.hasAuth?[' /** Wire better-auth — the builder lazily builds the instance, runs `ensureMigrated`, and dispatches `/api/auth/*` inside the worker (instrumented for the auth-failure SLO). Pass `d1` for the D1-backed default, or `namespace` + `internalSecret` to host the auth tables in a Durable Object (what `@better-auth/scim` needs). */\n public auth(declaration: AuthDeclaration<Env>): this {\n // Reject the ambiguous and the empty shapes here rather than at the first\n // request: with neither storage set, auth would silently never answer, and\n // with both it is unclear which one owns the tables.\n if (declaration.d1 && declaration.namespace) {\n throw new Error(".auth(): pass either `d1` or `namespace`, not both — they are two different homes for the same tables.");\n }\n\n if (!declaration.d1 && !declaration.namespace) {\n throw new Error(".auth(): needs `d1` (D1-backed) or `namespace` (Durable-Object-backed) to know where the auth tables live.");\n }\n\n if (declaration.namespace && !declaration.internalSecret) {\n throw new Error(\n ".auth(): `namespace` requires `internalSecret` — the auth DO binding is reachable from any worker bound to it, so identity resolution is gated on a shared secret and would otherwise fail closed on every request.",\n );\n }\n\n this.authDeclaration = declaration;\n\n return this;\n }']:[]," /** Escape hatch — merge raw `WorkerOptions` (anything not yet sugared) over the derived options at build time. The second `derived` argument is a snapshot of the options assembled so far (after `.auth(...)` etc.), so you can compose rather than clobber — e.g. wrap `derived.resolveIdentity` instead of replacing it. */\n public extend(fn: (env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>): this {\n this.extendFns.push(fn);\n\n return this;\n }",...e.hasGlobal?[` /** Back \`.global()\` (cross-tenant) tables with D1 — wires \`ctx.db\` routing, the studio global browser, and reverse cross-shard relations. */
|
|
368
369
|
public global(declaration: GlobalDeclaration<Env>): this {
|
|
@@ -404,7 +405,7 @@ const buildGlobalCdcApplier =
|
|
|
404
405
|
this.storageDeclaration = declaration;
|
|
405
406
|
|
|
406
407
|
return this;
|
|
407
|
-
}`]:[],...T(e)],
|
|
408
|
+
}`]:[],...T(e)],q=e=>{const r=a=>e.hasScheduler?`
|
|
408
409
|
...(this.schedulerDeclaration ? { scheduler: this.resolveScheduler(env) as unknown as ${a}["scheduler"] } : {}),`:"",t=[" cdc: this.cdcEnabled,"," reactiveCache: this.reactiveCacheConfig,"," ...(this.maxRelationKeysLimit === undefined ? {} : { maxRelationKeys: this.maxRelationKeysLimit }),"," ...(this.observabilitySink === undefined ? {} : { observability: this.observabilitySink }),"," ...(this.deliveryAuthorizationSelector === undefined ? {} : { deliveryAuthorization: this.deliveryAuthorizationSelector }),"," ...(this.relationExistsPushDownMode === undefined ? {} : { relationExistsPushDown: this.relationExistsPushDownMode }),",...e.hasGlobal?[` ...(this.globalDeclaration
|
|
409
410
|
? {
|
|
410
411
|
d1: (rawEnv: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string | null }) => {
|
|
@@ -487,7 +488,7 @@ const buildGlobalCdcApplier =
|
|
|
487
488
|
: {}),`]:[],...d(e)?[" ...(this.shardRegistrySelector ? { shardRegistry: (rawEnv: Record<string, unknown>) => this.shardRegistrySelector?.(rawEnv as Env) } : {}),"]:[],...e.hasSourcedTables?[" ...(this.sourceClientFactory === undefined ? {} : { sourceClient: this.sourceClientFactory }),"]:[],...e.hasStorage?[" ...(this.storageDeclaration ? { storage: (rawEnv: Record<string, unknown>, origin?: string) => this.resolveStorage(rawEnv as Env, origin) } : {}),"]:[],...g(e)?[" ...this.shardExtras,"]:[]];return t.length>0?`
|
|
488
489
|
${t.join(`
|
|
489
490
|
`)}
|
|
490
|
-
`:""},
|
|
491
|
+
`:""},I=e=>e?['import * as lunoraIdentityContract from "../identity.js";']:[],L=(e,r)=>e?['import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";',`import { createAccessResolver${r?", composeResolvers":""} } from "@lunora/cloudflare-access";`]:[],j=e=>e?['import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";']:[],B=e=>e?['import { createVectorAdminIntrospector } from "@lunora/bindings/vectors";']:[],P=e=>e?['import type { D1CtxDbOptions, D1DatabaseLike, D1Exec } from "@lunora/d1";','import { applyCdcChanges, createD1CtxDb, emitD1QueryCost, exportGlobalRows, facetGlobalColumn, importGlobalRows, listGlobalTables, readD1CdcChanges, readGlobalTablePage, retryingExec } from "@lunora/d1";']:[],G=e=>e?['import notifyConfig from "../notify.js";']:[],_=e=>v(e)?['import { dispatchAgentEmail } from "@lunora/agent/inbound";']:[],W=e=>v(e)?['import * as lunoraAgentDefinitions from "../agents.js";']:[],M=e=>{const{hasFramework:r,hasGlobal:t,hasHyperdriveGlobal:a,hasQueue:s,useUmbrella:o}=e,i=o?"lunorash/runtime":"@lunora/runtime",c=["ExecutionContextLike","HttpRouterLike","LunoraWorker","Route","ScheduledControllerLike","ShardNamespaceLike","WorkerOptions",...s?["TriggerTrace"]:[],...t?["GlobalIntrospector"]:[],...e.tables.length>0?["ShardingInfo"]:[],...r?["FrameworkHostHandler"]:[]],l=[...t||a?["createCrossShardRelationCapabilities"]:[],...d(e)?["createDynamicShardRegistry","createQueryCoordinator"]:[],"createWorker",...e.jurisdiction?["declareAppJurisdiction"]:[],"resolveLogArchiveFromEnv",...e.hasAuth?["memoizeIdentity"]:[],...r?["withFrameworkWorker"]:[]].join(", ");return[`import type { ${[...c].toSorted((n,h)=>n.localeCompare(h)).join(", ")} } from "${i}";`,`import { ${l} } from "${i}";`]},H=e=>{const{hasAccess:r,hasAuth:t,hasGlobal:a,hasHyperdriveGlobal:s,hasKvIntrospector:o,hasQueue:i,hasScheduler:c,hasStorage:l,hasWorkflow:n,wantsOpenApi:h,wantsOpenRpc:u}=e;return[...t?['import type { AuthNamespaceLike, LunoraAuth, LunoraAuthOptions } from "@lunora/auth";','import { authDiscoveryPathsFor, createAuth, createAuthAdmin, createAuthAuditReader, createDoAuthWiring, d1Executor, handleAuthDiscoveryRequest, handleAuthRequest, lunoraD1Adapter } from "@lunora/auth";']:[],...L(r,t),...P(a),...s?['import type { HyperdriveEngine } from "@lunora/hyperdrive/global";','import { createHyperdriveGlobalCtxDb } from "@lunora/hyperdrive/global";','import type { SqlCtxDbOptions, SqlExec } from "@lunora/sql-store";']:[],...j(o),...B(e.hasVectors),...c?['import type { DurableObjectNamespaceLike } from "@lunora/scheduler";','import { createScheduler } from "@lunora/scheduler";']:[],...l?['import type { R2BucketLike, R2S3Credentials, Storage } from "@lunora/storage";','import { createBucketStorage, createStorage } from "@lunora/storage";']:[],...n?['import { createWorkflowsRestClient } from "@lunora/workflow";']:[],..._(e),...M(e),"",...I(e.identity),...W(e),...a||s?['import schema from "../schema.js";']:[],...G(e.hasNotify),'import { LUNORA_CRONS } from "./crons.js";','import { LUNORA_FUNCTIONS } from "./functions.js";',...i?['import { createQueueCaptureSink, dispatchQueueBatch, shouldCaptureQueue } from "@lunora/queue";','import { LUNORA_QUEUE_REGISTRY } from "./queues.js";']:[],...e.wantsArchitecture?['import { architecture } from "./architecture.js";']:[],...h?['import { openApiSpec } from "./openapi.js";']:[],...u?['import { openRpcSpec } from "./openrpc.js";']:[],'import { createShardDO } from "./shard.js";',...e.hasVectors?['import { LUNORA_VECTOR_INDEXES } from "./vectors.js";']:[]]},$=e=>e.jurisdiction&&e.jurisdictionPinsAuth===!0?`
|
|
491
492
|
// The schema's jurisdiction pins the auth object like every other DO.
|
|
492
493
|
jurisdiction: ${JSON.stringify(e.jurisdiction)},`:"",U=e=>typeof e=="string"?`{ mode: { kind: ${JSON.stringify(e)} } }`:`{ mode: { field: ${JSON.stringify(e.field)}, kind: "shardBy" } }`,F=e=>[...e.tables.length>0?[` const tableSharding = new Map<string, ShardingInfo>([
|
|
493
494
|
${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`).join(`
|
|
@@ -747,10 +748,10 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`)
|
|
|
747
748
|
}`]:[],...e.voiceAgents&&e.voiceAgents.length>0?[` options.voiceAgents = {
|
|
748
749
|
${e.voiceAgents.map(r=>` ${JSON.stringify(r.exportName)}: (env as Record<string, unknown>)[${JSON.stringify(r.bindingName)}] as ShardNamespaceLike,`).join(`
|
|
749
750
|
`)}
|
|
750
|
-
};`]:[]],z=e=>[" cronJobs: LUNORA_CRONS,"," functions: LUNORA_FUNCTIONS,",...e.identity?[` identity: lunoraIdentityContract.${e.identity.exportName},`]:[],...e.jurisdiction?[` jurisdiction: ${JSON.stringify(e.jurisdiction)},`]:[],...e.wantsArchitecture?[" architecture,"]:[],...e.wantsOpenApi?[" openApiSpec,"]:[],...e.wantsOpenRpc?[" openRpcSpec,"]:[],...e.hasQueue?[
|
|
751
|
+
};`]:[]],z=e=>[" cronJobs: LUNORA_CRONS,"," functions: LUNORA_FUNCTIONS,",...e.identity?[` identity: lunoraIdentityContract.${e.identity.exportName},`]:[],...e.jurisdiction?[` jurisdiction: ${JSON.stringify(e.jurisdiction)},`]:[],...e.wantsArchitecture?[" architecture,"]:[],...e.wantsOpenApi?[" openApiSpec,"]:[],...e.wantsOpenRpc?[" openRpcSpec,"]:[],...e.hasQueue?[` queue: (batch: unknown, queueEnv: unknown, _context: ExecutionContextLike, trigger: TriggerTrace, ${e.liveStreams?"queueLive":"_live"}: Parameters<typeof dispatchQueueBatch>[2]["live"], queueFetch: Parameters<typeof dispatchQueueBatch>[2]["fetchImpl"]): Promise<void> =>`," dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, {"," capture: shouldCaptureQueue(queueEnv as Record<string, unknown>)",` ? createQueueCaptureSink(queueEnv as Record<string, unknown>${e.jurisdiction?`, { jurisdiction: ${JSON.stringify(e.jurisdiction)} }`:""})`," : undefined,"," env: queueEnv as Record<string, unknown>,"," traceparent: trigger.traceparent,"," fetchImpl: queueFetch,",...e.liveStreams?[" live: queueLive,"]:[]," }),"]:[]," ...(this.httpRouterApp ? { httpRouter: this.httpRouterApp } : {}),"," routes: this.routeMap,",...e.liveStreamsWithheld?[" liveStreams: false,"]:[]," shardDO: this.shardSelector?.(env) ?? (undefined as unknown as ShardNamespaceLike),"],J=e=>e?`
|
|
751
752
|
/** The identity memo per \`env\` object, owned by one assembled worker. */
|
|
752
753
|
type IdentityMemoStore = WeakMap<object, ReturnType<typeof memoizeIdentity>>;
|
|
753
|
-
`:"",K=e=>[...e.hasAuth?["AuthDeclaration"]:[],"ComposedApp",...e.hasGlobal?["GlobalDeclaration"]:[],"LunoraConfig",...e.hasScheduler?["SchedulerDeclaration"]:[],"Selector",...e.hasStorage?["StorageDeclaration"]:[]].toSorted((r,t)=>r.localeCompare(t)).join(", "),Z=e=>{const r=(e.hasVectors??!0)&&(e.vectorIndexCount??0)>0,t={...e,hasVectors:r},{hasAuth:a}=t,
|
|
754
|
+
`:"",K=e=>[...e.hasAuth?["AuthDeclaration"]:[],"ComposedApp",...e.hasGlobal?["GlobalDeclaration"]:[],"LunoraConfig",...e.hasScheduler?["SchedulerDeclaration"]:[],"Selector",...e.hasStorage?["StorageDeclaration"]:[]].toSorted((r,t)=>r.localeCompare(t)).join(", "),Z=e=>{const r=(e.hasVectors??!0)&&(e.vectorIndexCount??0)>0,t={...e,hasVectors:r},{hasAuth:a}=t,s=C(t),o=Q(t),i=a?` let auth: LunoraAuth | null = null;
|
|
754
755
|
let authInit: Promise<void> | null = null;
|
|
755
756
|
// One memo per env for THIS assembled worker: a framework-hosted worker rebuilds its options per
|
|
756
757
|
// request and must reuse it, but a second \`assemble()\` has its own auth closure and must not share.
|
|
@@ -808,8 +809,8 @@ type IdentityMemoStore = WeakMap<object, ReturnType<typeof memoizeIdentity>>;
|
|
|
808
809
|
throw error;
|
|
809
810
|
}));
|
|
810
811
|
`:"",l=a?`
|
|
811
|
-
await ensureAuth(env);`:"",
|
|
812
|
-
host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${
|
|
812
|
+
await ensureAuth(env);`:"",n=a?"() => auth, identityMemos":"() => null",h=a?"getAuth: () => LunoraAuth | null, identityMemos: IdentityMemoStore":"_getAuth: () => null",u=t.hasFramework?` const buildWorker = (env: Env): LunoraWorker =>
|
|
813
|
+
host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${n})) : createWorker(this.buildWorkerOptions(env, ${n}));`:` const buildWorker = (env: Env): LunoraWorker => createWorker(this.buildWorkerOptions(env, ${n}));`,y=t.hasFramework?"host?: FrameworkHostHandler":"",p=t.emailAgents??[],f=p.length>0?` composed.email = dispatchAgentEmail([
|
|
813
814
|
${p.map(b=>` { agent: lunoraAgentDefinitions.${b.exportName}, className: ${JSON.stringify(b.className)} },`).join(`
|
|
814
815
|
`)}
|
|
815
816
|
]);
|
|
@@ -831,9 +832,9 @@ ${J(a)}${t.jurisdiction?`
|
|
|
831
832
|
// \`@lunora/mail\` reads it to pin its shard RPC like every other DO path.
|
|
832
833
|
declareAppJurisdiction(${JSON.stringify(t.jurisdiction)});
|
|
833
834
|
`:""}
|
|
834
|
-
${
|
|
835
|
+
${s.join(`
|
|
835
836
|
|
|
836
|
-
`)}${
|
|
837
|
+
`)}${s.length>0?`
|
|
837
838
|
|
|
838
839
|
`:""}/** The composed app: a Cloudflare module worker (\`fetch\` / \`scheduled\` / optional \`email\`) plus the \`ShardDO\` class binding. */
|
|
839
840
|
interface ComposedApp extends LunoraWorker {
|
|
@@ -863,7 +864,7 @@ ${w}
|
|
|
863
864
|
|
|
864
865
|
/** Build the shard DO + compose the worker (standalone or framework-hosted), wrapping the lazy per-isolate singletons + auth init. */
|
|
865
866
|
private assemble(${y}): ComposedApp {
|
|
866
|
-
const ShardDO = createShardDO({${
|
|
867
|
+
const ShardDO = createShardDO({${q(t)}});
|
|
867
868
|
|
|
868
869
|
// Per-isolate singletons: the worker (and auth instance) are expensive to
|
|
869
870
|
// build, so the first request constructs them and every later request on
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{LunoraError as P}from"@lunora/errors";import{L as oe,G as C,d as j,I as
|
|
1
|
+
import{LunoraError as P}from"@lunora/errors";import{L as oe,G as C,d as j,I as F,b as M,r as se,c as ae}from"./shared-DnCokNcE.mjs";import{renderAgentFunctionRegistry as ie,renderSandboxFunctionRegistry as ce}from"./emitApi-CDgIPAG2.mjs";import{b as le,a as de,r as _,c as ue}from"./qualifiers-DEdXn5wP.mjs";import{s as f}from"./dispatch-namespace-DwTjD7BU.mjs";const he=new Set(["any","bigint","boolean","date","id","null","number","storage","string","timestamp"]),D=r=>r.column!==void 0,me=(r,t)=>{switch(r){case"bigint":return`if (typeof ${t} !== "bigint") return DEFER;
|
|
2
2
|
`;case"boolean":return`if (typeof ${t} !== "boolean") return DEFER;
|
|
3
3
|
`;case"date":case"number":case"timestamp":return`if (typeof ${t} !== "number" || !Number.isFinite(${t})) return DEFER;
|
|
4
4
|
`;case"null":return`if (${t} !== null) return DEFER;
|
|
@@ -24,7 +24,7 @@ ${J(t)}${a.pre}const ${s} = { ${a.entries} };
|
|
|
24
24
|
`;return{out:s,pre:d}},B=r=>{let t=0;const o=U(r,"source",{next:()=>(t+=1,t)});if(o)return`(source) => {
|
|
25
25
|
if (typeof source !== "object" || source === null || Array.isArray(source)) return DEFER;
|
|
26
26
|
${J("source")}${o.pre}return { ${o.entries} };
|
|
27
|
-
}`},Re=(r,t)=>`lunora_${f(r)}_${String(t)}`,I=r=>JSON.stringify(Object.entries(r).toSorted(([t],[n])=>t.localeCompare(n)).map(([t,n])=>{const o=n.kind==="optional",a=o?n.inner??{kind:"unknown"}:n,i=a.kind==="array"?a.inner?.kind:void 0,s=a.kind==="id"?a.tableName:void 0;return{kind:a.kind,name:t,optional:o,...s===void 0?{}:{table:s},...i===void 0||i==="unknown"?{}:{element:i}}})),H=(r,t,n,o)=>{const a=new Map,i=s=>{a.has(s)||a.set(s,Re(s,a.size))};for(const s of r)i(s.filePath);for(const s of t)i(s.filePath);for(const s of n)i(s.filePath);for(const s of o)i(s.filePath);return a},q=(r,t,n)=>new Set([...r.map(o=>o.filePath),...t.map(o=>o.filePath),...n.map(o=>o.filePath)]),k=r=>`${r}[functionPath]`,
|
|
27
|
+
}`},Re=(r,t)=>`lunora_${f(r)}_${String(t)}`,I=r=>JSON.stringify(Object.entries(r).toSorted(([t],[n])=>t.localeCompare(n)).map(([t,n])=>{const o=n.kind==="optional",a=o?n.inner??{kind:"unknown"}:n,i=a.kind==="array"?a.inner?.kind:void 0,s=a.kind==="id"?a.tableName:void 0;return{kind:a.kind,name:t,optional:o,...s===void 0?{}:{table:s},...i===void 0||i==="unknown"?{}:{element:i}}})),H=(r,t,n,o)=>{const a=new Map,i=s=>{a.has(s)||a.set(s,Re(s,a.size))};for(const s of r)i(s.filePath);for(const s of t)i(s.filePath);for(const s of n)i(s.filePath);for(const s of o)i(s.filePath);return a},q=(r,t,n)=>new Set([...r.map(o=>o.filePath),...t.map(o=>o.filePath),...n.map(o=>o.filePath)]),k=r=>`${r}[functionPath]`,be=`const callRegistered = async <R>(context: CallerCtx, functionPath: string, args: Record<string, unknown> | undefined): Promise<R> => {
|
|
28
28
|
const registered = await loadFunction(functionPath);
|
|
29
29
|
|
|
30
30
|
if (!registered) {
|
|
@@ -57,7 +57,7 @@ ${J("source")}${o.pre}return { ${o.entries} };
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
return (await registered.handler(context, args ?? {})) as R;
|
|
60
|
-
};`,
|
|
60
|
+
};`,Ne=(r,t,n=[],o=[],a=!1)=>{const i=H(r,t,n,o),s=q(t,n,o),d=[...i.entries()].filter(([e])=>!a||s.has(e)?!0:r.some(m=>m.filePath===e&&m.channel?.kind==="room")).map(([e,m])=>{if(!F.test(e))throw new P("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(e)}`);return`import ${a&&!s.has(e)?"type ":""}* as ${m} from "../${e}.js";`}).join(`
|
|
61
61
|
`),u=r.map(e=>!a||s.has(e.filePath)?` "${f(e.filePath)}:${e.exportName}": ${i.get(e.filePath)??""}.${e.exportName} as unknown as RegisteredLunoraFunction,`:` "${f(e.filePath)}:${e.exportName}": { args: {}, handler: unloadedFunctionHandler, ...${JSON.stringify({argumentDescriptors:JSON.parse(I(e.args)),kind:e.kind,...e.channel?{channel:e.channel}:{},...e.expose?{expose:e.expose}:{},...e.lifecycle?{lifecycle:e.lifecycle}:{},...e.visibility?{visibility:e.visibility}:{},...e.x402?.price===void 0?{}:{x402:{price:e.x402.price}}})} } satisfies RegisteredLunoraFunction & Pick<FunctionManifestEntry, "argumentDescriptors" | "channel" | "expose">,`).join(`
|
|
62
62
|
`),c=t.map(e=>` ${JSON.stringify(e.id)}: ${i.get(e.filePath)??""}.${e.exportName} as unknown as RegisteredDataMigration,`).join(`
|
|
63
63
|
`),l=n.map(e=>` "${f(e.filePath)}:${e.exportName}": ${i.get(e.filePath)??""}.${e.exportName} as unknown as RegisteredLunoraFunction,`).join(`
|
|
@@ -65,21 +65,21 @@ ${J("source")}${o.pre}return { ${o.entries} };
|
|
|
65
65
|
`),y=n.map(e=>`${f(e.filePath)}:${e.exportName}`),$=[u,l].filter(e=>e.length>0).join(`
|
|
66
66
|
`),v=r.filter(e=>!a||s.has(e.filePath)).map(e=>{if(e.lifecycle||Object.keys(e.args).length===0)return;const m=B(e.args);return m===void 0?void 0:`installCompiledValidatorMap(${i.get(e.filePath)??""}.${e.exportName}.args, ${m});`}).filter(e=>e!==void 0).join(`
|
|
67
67
|
`),O=r.filter(e=>e.channel?.kind==="room").map(e=>` ${JSON.stringify(e.channel?.name??"")}: RoomMessageOf<typeof ${i.get(e.filePath)??""}[${JSON.stringify(e.exportName)}]>;`).join(`
|
|
68
|
-
`),
|
|
69
|
-
`):"",h=[...new Set(x.map(({definition:e})=>e.filePath))],w=a?h.map(e=>{if(!
|
|
68
|
+
`),b=[...r.map(e=>({args:e.args,definition:e,path:`${f(e.filePath)}:${e.exportName}`})),...n.map(e=>({args:e.args,definition:{...e,expose:void 0,kind:"mutation",lifecycle:void 0,visibility:void 0,x402:void 0},path:`${f(e.filePath)}:${e.exportName}`}))],x=a?b.filter(({definition:e})=>!s.has(e.filePath)):[];for(const{definition:e}of b)if(a&&e.x402&&e.x402.price===void 0)throw new P("INTERNAL",`@lunora/codegen: lazy function registry needs a literal \`.x402({ price })\` value in ${e.filePath}:${e.exportName}`);const N=a?x.map(({definition:e,path:m})=>{const R=i.get(e.filePath)??"",S="channel"in e?e.channel:void 0,A={argumentDescriptors:JSON.parse(I(e.args)),exportName:e.exportName,kind:e.kind,moduleId:R,...S?{channel:S}:{},...e.expose?{expose:e.expose}:{},...e.lifecycle?{lifecycle:e.lifecycle}:{},...e.visibility?{visibility:e.visibility}:{},...e.x402?.price===void 0?{}:{x402:{price:e.x402.price}}};return` ${JSON.stringify(m)}: ${JSON.stringify(A)},`}).join(`
|
|
69
|
+
`):"",h=[...new Set(x.map(({definition:e})=>e.filePath))],w=a?h.map(e=>{if(!F.test(e))throw new P("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(e)}`);const m=i.get(e)??"";return` ${JSON.stringify(m)}: () => import(${JSON.stringify(`./fn/${m}.js`)}),`}).join(`
|
|
70
70
|
`):"";return{dispatchBody:$.length>0?`
|
|
71
71
|
${$}
|
|
72
72
|
`:"",importBlock:d.length>0?`${d}
|
|
73
73
|
|
|
74
|
-
`:"",installBlock:v,manifestBody:
|
|
75
|
-
${
|
|
74
|
+
`:"",installBlock:v,manifestBody:N.length>0?`
|
|
75
|
+
${N}
|
|
76
76
|
`:"",migrationBody:c.length>0?`
|
|
77
77
|
${c}
|
|
78
78
|
`:"",moduleLoaders:w.length>0?`
|
|
79
79
|
${w}
|
|
80
80
|
`:"",mutatorPaths:y,roomMessagesBody:O,shapeBody:g.length>0?`
|
|
81
81
|
${g}
|
|
82
|
-
`:""}},ke=r=>{const t=
|
|
82
|
+
`:""}},ke=r=>{const t=M(r,o=>{const a=_(se(o.args),o.filePath),i=a==="{}"?"?":"",s=_(ue(o),o.filePath);return o.kind==="stream"?`${o.exportName}: (args${i}: ${a}) => Promise<AsyncIterable<${s}>>;`:`${o.exportName}: (args${i}: ${a}) => Promise<${s}>;`},"type");return{implementation:M(r,o=>`${ae(o.exportName)}: (args) => callRegistered(context, "${f(o.filePath)}:${o.exportName}", args),`,"value"),types:t}},ve=r=>{const t={connect:[],disconnect:[],init:[],reactor:[],whisper:[]};for(const n of r)n.lifecycle&&t[n.lifecycle].push(`${f(n.filePath)}:${n.exportName}`);return t},Oe=(r,t,n)=>r?{channelField:` /**
|
|
83
83
|
* Set on a \`defineRoom\` registration: the room's name (without the \`room:\`
|
|
84
84
|
* topic prefix). The generated \`LUNORA_ROOMS\` map keys it on the room's
|
|
85
85
|
* \`room:<name>\` whisper topic so the ShardDO resolves a room topic to this
|
|
@@ -159,9 +159,9 @@ ${n.types}
|
|
|
159
159
|
`:"",a=n.implementation?`
|
|
160
160
|
${n.implementation}
|
|
161
161
|
`:"",i=de(n.types),s=i.length>0?`import type { ${i.join(", ")} } from "./dataModel.js";
|
|
162
|
-
`:"",d=r.length>0?"context":"_context";let u="";if(r.length>0){let c=
|
|
162
|
+
`:"",d=r.length>0?"context":"_context";let u="";if(r.length>0){let c=be;t||(c=c.replace("await loadFunction(functionPath)",k("LUNORA_FUNCTIONS"))),u=`${c}
|
|
163
163
|
|
|
164
|
-
`}return{callRegisteredHelper:u,dataModelImport:s,implementation:a,parameter:d,types:o}},Ee=r=>{const{agents:t=[],functions:n,lazyFunctions:o=!1,migrations:a=[],mutators:i=[],shapes:s=[],useUmbrella:d=!1,usesSandbox:u=!1}=r,c=j(d),{dispatchBody:l,importBlock:g,installBlock:y,manifestBody:$,migrationBody:v,moduleLoaders:O,mutatorPaths:
|
|
164
|
+
`}return{callRegisteredHelper:u,dataModelImport:s,implementation:a,parameter:d,types:o}},Ee=r=>{const{agents:t=[],functions:n,lazyFunctions:o=!1,migrations:a=[],mutators:i=[],shapes:s=[],useUmbrella:d=!1,usesSandbox:u=!1}=r,c=j(d),{dispatchBody:l,importBlock:g,installBlock:y,manifestBody:$,migrationBody:v,moduleLoaders:O,mutatorPaths:b,roomMessagesBody:x,shapeBody:N}=Ne(n,a,i,s,o),h=ie(t,n),w=ce(u,n),e=[h.lines,w.lines].filter(p=>p.length>0).join(`
|
|
165
165
|
`);let m=l;e.length>0&&(m=l.length>0?`${l.trimEnd()}
|
|
166
166
|
${e}
|
|
167
167
|
`:`
|
|
@@ -170,31 +170,31 @@ ${e}
|
|
|
170
170
|
throw new LunoraError("FUNCTION_NOT_FOUND", \`function not registered: \${functionPath}\`);
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
`:"",
|
|
174
|
-
`:"",E=n.some(p=>p.channel?.kind==="room"),L=Oe(E,c.server,x),
|
|
173
|
+
`:"",z=s.length>0?`import type { RegisteredShape } from "${c.server}";
|
|
174
|
+
`:"",E=n.some(p=>p.channel?.kind==="room"),L=Oe(E,c.server,x),Q=s.length>0?`
|
|
175
175
|
/**
|
|
176
176
|
* Replication-shape registry — one entry per \`defineShape\` in \`lunora/shapes.ts\`.
|
|
177
177
|
* The generated ShardDO's \`resolveShape\` override looks a shape up by name and
|
|
178
178
|
* evaluates its trusted \`compileWhere(ctx, args)\` to authorize + scope a
|
|
179
179
|
* \`shape_subscribe\` (reads-as-permissions).
|
|
180
180
|
*/
|
|
181
|
-
export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${
|
|
182
|
-
`:"",
|
|
181
|
+
export const LUNORA_SHAPES: Record<string, RegisteredShape> = {${N}};
|
|
182
|
+
`:"",G=b.length>0?`
|
|
183
183
|
/**
|
|
184
184
|
* Custom-mutator function paths — the \`LUNORA_FUNCTIONS\` keys the generated
|
|
185
185
|
* ShardDO's \`isCustomMutator\` override routes through the client-watermark push
|
|
186
186
|
* protocol (\`x-lunora-client-id\`/\`x-lunora-client-seq\` ordering).
|
|
187
187
|
*/
|
|
188
|
-
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${
|
|
189
|
-
`:"",
|
|
190
|
-
`:"",
|
|
188
|
+
export const LUNORA_MUTATOR_PATHS: ReadonlySet<string> = new Set([${b.map(p=>JSON.stringify(p)).join(", ")}]);
|
|
189
|
+
`:"",V=xe(E,o,n),W=y.length>0?`import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${c.values}";
|
|
190
|
+
`:"",Y=y.length>0?`
|
|
191
191
|
/**
|
|
192
192
|
* AOT-compiled argument validators (Worker-safe, no \`eval\`). Each is installed
|
|
193
193
|
* onto its function's live \`.args\` object and consulted by the interpreted
|
|
194
194
|
* parser as a zero-allocation fast path; anything it can't model is deferred.
|
|
195
195
|
*/
|
|
196
196
|
${y}
|
|
197
|
-
`:"",
|
|
197
|
+
`:"",K=Se(n,o),{callRegisteredHelper:Z,dataModelImport:X,implementation:ee,parameter:te,types:re}=K,ne=o?`
|
|
198
198
|
export interface FunctionManifestEntry {
|
|
199
199
|
argumentDescriptors: ReadonlyArray<{ element?: string; kind: string; name: string; optional: boolean; table?: string }>;
|
|
200
200
|
channel?: { kind: "room"; name: string };
|
|
@@ -213,6 +213,7 @@ export const LUNORA_FUNCTION_MANIFEST: Readonly<Record<string, FunctionManifestE
|
|
|
213
213
|
const MODULE_LOADERS: Record<string, () => Promise<Record<string, unknown>>> = {${O}};
|
|
214
214
|
const loadedModules = new Map<string, Promise<Record<string, unknown>>>();
|
|
215
215
|
const resolvedModules = new Map<string, Record<string, unknown>>();
|
|
216
|
+
const boundFunctions = new Set<string>();
|
|
216
217
|
const unloadedFunctionHandler = (): never => {
|
|
217
218
|
throw new Error("a lazy function was invoked before it was prepared");
|
|
218
219
|
};
|
|
@@ -226,6 +227,10 @@ export const getLoadedFunction = (functionPath: string): RegisteredLunoraFunctio
|
|
|
226
227
|
return registered;
|
|
227
228
|
}
|
|
228
229
|
|
|
230
|
+
if (boundFunctions.has(functionPath)) {
|
|
231
|
+
return registered;
|
|
232
|
+
}
|
|
233
|
+
|
|
229
234
|
const module = resolvedModules.get(manifest.moduleId);
|
|
230
235
|
|
|
231
236
|
if (module === undefined) {
|
|
@@ -239,6 +244,7 @@ export const getLoadedFunction = (functionPath: string): RegisteredLunoraFunctio
|
|
|
239
244
|
}
|
|
240
245
|
|
|
241
246
|
Object.assign(registered, loaded);
|
|
247
|
+
boundFunctions.add(functionPath);
|
|
242
248
|
|
|
243
249
|
return registered;
|
|
244
250
|
};
|
|
@@ -265,25 +271,16 @@ export const loadFunction = async (functionPath: string): Promise<RegisteredLuno
|
|
|
265
271
|
loadedModules.set(manifest.moduleId, pending);
|
|
266
272
|
}
|
|
267
273
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
} catch (error: unknown) {
|
|
273
|
-
if (loadedModules.get(manifest.moduleId) === pending) {
|
|
274
|
-
loadedModules.delete(manifest.moduleId);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
resolvedModules.set(manifest.moduleId, module);
|
|
274
|
+
// A module that failed to evaluate stays failed for the isolate: the runtime has already cached
|
|
275
|
+
// the failed evaluation, and a bundler's lazy initializer can hand a retry a half-initialized
|
|
276
|
+
// namespace, so every later call rethrows the original error instead.
|
|
277
|
+
resolvedModules.set(manifest.moduleId, await pending);
|
|
281
278
|
|
|
282
279
|
return getLoadedFunction(functionPath);
|
|
283
280
|
};
|
|
284
|
-
`:"";return le(`${C}${g}${h.importLine}${w.importLine}${W}${
|
|
281
|
+
`:"";return le(`${C}${g}${h.importLine}${w.importLine}${W}${z}${L.typeImport}import { LunoraError } from "${c.server}";
|
|
285
282
|
import type { ActionCtx, MutationCtx, QueryCtx } from "./server.js";
|
|
286
|
-
${
|
|
283
|
+
${X}
|
|
287
284
|
/**
|
|
288
285
|
* Single registered function, narrowed to the shape \`handleRpc\` needs.
|
|
289
286
|
* The real argument validators / return types are checked elsewhere — at
|
|
@@ -335,7 +332,7 @@ ${h.prelude}${w.prelude}${ne}
|
|
|
335
332
|
* emits (\`api[namespace][fn].__lunoraRef === "namespace:fn"\`).
|
|
336
333
|
*/
|
|
337
334
|
export const LUNORA_FUNCTIONS: Record<string, RegisteredLunoraFunction> = {${m}};
|
|
338
|
-
${
|
|
335
|
+
${Y}${Q}${G}${V}${L.messagesBlock}
|
|
339
336
|
/**
|
|
340
337
|
* Lifecycle manifest: the function paths the generated ShardDO dispatches when a
|
|
341
338
|
* client's WebSocket connects (\`connect\`) or disconnects (\`disconnect\`), once
|
|
@@ -390,7 +387,7 @@ export type CallerCtx = ActionCtx | MutationCtx | QueryCtx;
|
|
|
390
387
|
*/
|
|
391
388
|
export interface Caller {${re}}
|
|
392
389
|
|
|
393
|
-
${
|
|
390
|
+
${Z}/** Build a {@link Caller} bound to \`context\` (typically a handler's \`ctx\`). */
|
|
394
391
|
export const createCaller = (${te}: CallerCtx): Caller => ({${ee}});
|
|
395
392
|
|
|
396
393
|
/**
|
|
@@ -411,12 +408,12 @@ export interface RegisteredDataMigration {
|
|
|
411
408
|
* shard DO's admin RPC and the CLI resolve migrations to run through this map.
|
|
412
409
|
*/
|
|
413
410
|
export const LUNORA_MIGRATIONS: Record<string, RegisteredDataMigration> = {${v}};
|
|
414
|
-
`,d)},
|
|
411
|
+
`,d)},Me="fn",_e=r=>{if(r.lazyFunctions!==!0)return{};const{functions:t}=r,n=r.migrations??[],o=r.mutators??[],a=r.shapes??[],i=H(t,n,o,a),s=q(n,o,a),d=[...new Set(t.filter(l=>!s.has(l.filePath)).map(l=>l.filePath))],u=j(r.useUmbrella??!1),c={};for(const l of d){if(!F.test(l))throw new P("INTERNAL",`@lunora/codegen: refusing to emit import for unsafe file path: ${JSON.stringify(l)}`);const g=i.get(l)??"",y=`../../${l}.js`,$=t.filter(h=>h.filePath===l&&!h.lifecycle&&Object.keys(h.args).length>0).flatMap(h=>{const w=B(h.args);return w===void 0?[]:[`installCompiledValidatorMap(${g}.${h.exportName}.args, ${w});`]}),v=$.length>0?`import { DEFER_VALIDATION as DEFER, installCompiledValidatorMap } from "${u.values}";
|
|
415
412
|
`:"",O=$.length>0?`import * as ${g} from "${y}";
|
|
416
|
-
`:"",
|
|
413
|
+
`:"",b=$.length>0?`
|
|
417
414
|
/** Install the precompiled argument parsers before the module is dispatched. */
|
|
418
415
|
${$.join(`
|
|
419
416
|
`)}
|
|
420
|
-
`:"",
|
|
421
|
-
`:"";c[
|
|
422
|
-
${
|
|
417
|
+
`:"",N=t.some(h=>h.filePath===l&&h.exportName==="default")||n.some(h=>h.filePath===l&&h.exportName==="default")?`export { default } from "${y}";
|
|
418
|
+
`:"";c[`${g}.ts`]=`${C}${v}${O}${b}export * from "${y}";
|
|
419
|
+
${N}`}return c};export{Me as LAZY_FUNCTION_DIRECTORY,Ee as emitFunctions,_e as emitLazyFunctionModules};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import"./isD1GlobalTable-udvHAAzD.mjs";import"./json-data-Chfs2Cz5.mjs";import{e as d}from"./shard-
|
|
1
|
+
import"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import"./isD1GlobalTable-udvHAAzD.mjs";import"./json-data-Chfs2Cz5.mjs";import{e as d}from"./shard-ceGu_Fps.mjs";import"./shard-runtime-BpoCV-aM.mjs";import"./shared-DnCokNcE.mjs";import"./platform-8oj7iXQy.mjs";import"./schema-BgM8A3XV.mjs";export{d as default};
|