@lunora/codegen 1.0.0-alpha.26 → 1.0.0-alpha.261
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/LICENSE.md +6 -0
- package/README.md +1 -1
- package/dist/index.d.mts +3851 -1254
- package/dist/index.d.ts +3851 -1254
- package/dist/index.mjs +1 -34
- package/dist/packem_shared/AGENTS_FILENAME-UhIaG4BZ.mjs +1 -0
- package/dist/packem_shared/CAPABILITY_PROBES-DFsutD7g.mjs +25 -0
- package/dist/packem_shared/CONTAINERS_FILENAME-DhUL5rDc.mjs +1 -0
- package/dist/packem_shared/CodegenDiagnosticError-BUXlG3P-.mjs +1 -0
- package/dist/packem_shared/DEFAULT_TARGET-7sHexLjO.mjs +1 -0
- package/dist/packem_shared/FLAGS_FILENAME-BINQ51Zq.mjs +1 -0
- package/dist/packem_shared/GENERATED_HEADER-dFyrHgQ0.mjs +1 -0
- package/dist/packem_shared/LUNORA_ERROR_CODES-C2s0xWQD.mjs +1 -0
- package/dist/packem_shared/MUTATORS_FILENAME-D1Q6EUII.mjs +1 -0
- package/dist/packem_shared/NOTIFY_FILENAME-bbHHFQ_t.mjs +1 -0
- package/dist/packem_shared/OPENRPC_VERSION-CGu1_YK7.mjs +3 -0
- package/dist/packem_shared/PROJECT_CONFIG_FILENAMES-DzOu-lSc.mjs +1 -0
- package/dist/packem_shared/QUEUES_FILENAME-CSLmXUQA.mjs +1 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-BVhRHIbS.mjs +11 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs +2 -0
- package/dist/packem_shared/SDK_LANGUAGES-Df_CnJx5.mjs +372 -0
- package/dist/packem_shared/SHAPES_FILENAME-DuR5hLW1.mjs +1 -0
- package/dist/packem_shared/SchemaSnapshotParseError-CPOXlFhI.mjs +18 -0
- package/dist/packem_shared/WORKFLOWS_FILENAME-IqUyMQgM.mjs +1 -0
- package/dist/packem_shared/attribution-sW_DHmLO.mjs +1 -0
- package/dist/packem_shared/buildOpenApiDocument-DOsv1HEF.mjs +3 -0
- package/dist/packem_shared/capabilitiesUsedBy-CzqyN9dX.mjs +1 -0
- package/dist/packem_shared/chain-BTbLDrrU.mjs +1 -0
- package/dist/packem_shared/classify-procedure-call-OnJoKgqu.mjs +1 -0
- package/dist/packem_shared/context-property-calls-BEBjylgc.mjs +1 -0
- package/dist/packem_shared/context-root-KWXRWlv6.mjs +1 -0
- package/dist/packem_shared/database-calls-rLPCL3-U.mjs +1 -0
- package/dist/packem_shared/declared-output-Iaar469J.mjs +1 -0
- package/dist/packem_shared/describeErrorLevelFindings-vzaGS9KL.mjs +1 -0
- package/dist/packem_shared/discoverAuthApiCalls-CNj9-Jch.mjs +1 -0
- package/dist/packem_shared/discoverCrons-BqTY53L5.mjs +1 -0
- package/dist/packem_shared/discoverFunctions-DPH4drkg.mjs +1 -0
- package/dist/packem_shared/discoverHttpRoutes-MRFziTCb.mjs +1 -0
- package/dist/packem_shared/discoverHyperdriveCalls-BcVkR6nw.mjs +1 -0
- package/dist/packem_shared/discoverInserts-Duz40u-s.mjs +1 -0
- package/dist/packem_shared/discoverMaskProcedures-DYJhbHF3.mjs +1 -0
- package/dist/packem_shared/discoverMigrations-D2P2n7JE.mjs +1 -0
- package/dist/packem_shared/discoverNondeterministicCalls-Cxf6T2Oi.mjs +1 -0
- package/dist/packem_shared/discoverQueries-CWmNPVHm.mjs +1 -0
- package/dist/packem_shared/discoverR2sqlCalls-DnKwop5c.mjs +1 -0
- package/dist/packem_shared/discoverRlsMetadata-BXXEFXjf.mjs +1 -0
- package/dist/packem_shared/discoverRlsProcedures-Des596JU.mjs +1 -0
- package/dist/packem_shared/discoverSandboxUsage-Bjl8A_hj.mjs +1 -0
- package/dist/packem_shared/discoverSchema-Cd3iH6q5.mjs +1 -0
- package/dist/packem_shared/discoverStorageRulesMetadata-DGFonj0I.mjs +1 -0
- package/dist/packem_shared/emitAgents-Dotqck8w.mjs +1 -0
- package/dist/packem_shared/emitApi-xDIHPRPH.mjs +154 -0
- package/dist/packem_shared/emitApp-RNU41dtm.mjs +860 -0
- package/dist/packem_shared/emitCrons-DsXsg1uG.mjs +83 -0
- package/dist/packem_shared/emitDataModel-DSk9AkJe.mjs +113 -0
- package/dist/packem_shared/emitDrizzleSchema-DohtnI8c.mjs +15 -0
- package/dist/packem_shared/emitFunctions-evl8Mx1a.mjs +249 -0
- package/dist/packem_shared/emitServer-DymRagL2.mjs +368 -0
- package/dist/packem_shared/emitShard-DHMYSP4m.mjs +1 -0
- package/dist/packem_shared/exported-procedure-chains-58yS9zc8.mjs +1 -0
- package/dist/packem_shared/fingerprintSchemaSources-BzFVnBfa.mjs +1 -0
- package/dist/packem_shared/formatAdvisories-DwmUKYuc.mjs +2 -0
- package/dist/packem_shared/handler-reference-C1oBljnl.mjs +1 -0
- package/dist/packem_shared/index-BusOvbeQ.mjs +1 -0
- package/dist/packem_shared/ir-DBSvhNa-.mjs +1 -0
- package/dist/packem_shared/isD1GlobalTable-udvHAAzD.mjs +1 -0
- package/dist/packem_shared/isTypedSchema-CKzc3ioR.mjs +4 -0
- package/dist/packem_shared/json-data-Chfs2Cz5.mjs +1 -0
- package/dist/packem_shared/listLunoraSourceFiles-DRes9d5p.mjs +1 -0
- package/dist/packem_shared/loadProjectConfig-CuGQsqYS.mjs +1 -0
- package/dist/packem_shared/module-specifiers-WF8iAydP.mjs +1 -0
- package/dist/packem_shared/modules-CsA-QVJ6.mjs +1 -0
- package/dist/packem_shared/parse-validator-B4mFs19C.mjs +1 -0
- package/dist/packem_shared/paths-C-9fwEgQ.mjs +1 -0
- package/dist/packem_shared/qualifiers-Cw8dEDbh.mjs +1 -0
- package/dist/packem_shared/readPackageDependencies-C6h6FZuP.mjs +1 -0
- package/dist/packem_shared/readServiceBindings-CnvEGOir.mjs +1 -0
- package/dist/packem_shared/redact-Cy14LEnc.mjs +1 -0
- package/dist/packem_shared/reserved-words-CW1QFbTd.mjs +1 -0
- package/dist/packem_shared/schemaFromIr-BWFnvCVg.mjs +1 -0
- package/dist/packem_shared/shard-WXSIZRpD.mjs +1438 -0
- package/dist/packem_shared/shard-runtime-B1nU9CRa.mjs +321 -0
- package/dist/packem_shared/shared-BXUKWh7t.mjs +9 -0
- package/dist/packem_shared/unwrap-handler-return-D7E2TKkS.mjs +1 -0
- package/package.json +16 -7
- package/dist/packem_shared/CONTAINERS_FILENAME-DlP6YM_Q.mjs +0 -224
- package/dist/packem_shared/CodegenDiagnosticError-DeblMkzO.mjs +0 -23
- package/dist/packem_shared/FLAGS_FILENAME-B1vE0LIo.mjs +0 -139
- package/dist/packem_shared/GENERATED_HEADER-CYaSI_qY.mjs +0 -3268
- package/dist/packem_shared/LUNORA_ERROR_CODES-CySpQPD3.mjs +0 -61
- package/dist/packem_shared/LUNORA_SOLUTION_RULES-BTejmZp-.mjs +0 -131
- package/dist/packem_shared/MUTATORS_FILENAME-BhqdPtKp.mjs +0 -81
- package/dist/packem_shared/OPENRPC_VERSION-CRe5l79E.mjs +0 -60
- package/dist/packem_shared/QUEUES_FILENAME-B5_eWCRe.mjs +0 -119
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-cgOjZTVY.mjs +0 -1137
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-wWGP2_5E.mjs +0 -245
- package/dist/packem_shared/SHAPES_FILENAME-ChV7MqgE.mjs +0 -94
- package/dist/packem_shared/WORKFLOWS_FILENAME-CCisG0Vy.mjs +0 -124
- package/dist/packem_shared/buildOpenApiDocument-BlpXQe2K.mjs +0 -183
- package/dist/packem_shared/discover-ast-CT6BgBr4.mjs +0 -13
- package/dist/packem_shared/discoverAuthApiCalls-CoirYbg6.mjs +0 -62
- package/dist/packem_shared/discoverCrons-Cev7RRAf.mjs +0 -257
- package/dist/packem_shared/discoverFunctions-BWMczzBx.mjs +0 -465
- package/dist/packem_shared/discoverHttpRoutes-CfP6cMzt.mjs +0 -131
- package/dist/packem_shared/discoverInserts-C7zxXkUf.mjs +0 -61
- package/dist/packem_shared/discoverMaskProcedures-Cm81kwrb.mjs +0 -217
- package/dist/packem_shared/discoverMigrations-Bi5nJ0mJ.mjs +0 -97
- package/dist/packem_shared/discoverNondeterministicCalls-C4M8AXmQ.mjs +0 -122
- package/dist/packem_shared/discoverQueries-B0wGT-xe.mjs +0 -62
- package/dist/packem_shared/discoverR2sqlCalls-BVNMd428.mjs +0 -80
- package/dist/packem_shared/discoverRlsMetadata-BS9GOGC5.mjs +0 -280
- package/dist/packem_shared/discoverSchema-KYq55qu3.mjs +0 -864
- package/dist/packem_shared/discoverStorageRulesMetadata-Da8BKXcI.mjs +0 -97
- package/dist/packem_shared/emitApp-C38fHt_1.mjs +0 -675
- package/dist/packem_shared/formatAdvisories-DdjK7sgh.mjs +0 -81
- package/dist/packem_shared/parse-validator-Cabb60UV.mjs +0 -133
- package/dist/packem_shared/paths-BRd6JHuF.mjs +0 -11
- package/dist/packem_shared/schemaFromIr-DTYsLBaA.mjs +0 -57
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import{s as b}from"./ir-DBSvhNa-.mjs";import{r as y}from"./json-data-Chfs2Cz5.mjs";import{CAPABILITIES as $}from"./CAPABILITY_PROBES-DFsutD7g.mjs";import{a as c,G as p}from"./shared-BXUKWh7t.mjs";const W=e=>e?{importFragment:"serveRelationFanout, ",override:`
|
|
2
|
+
protected override async runRelationFanoutRead(functionPath: string, args: Record<string, unknown>): Promise<unknown> {
|
|
3
|
+
this.ensureMigrated();
|
|
4
|
+
|
|
5
|
+
const { db } = this.buildCtx({ functionPath }) as { db: DatabaseWriterLike };
|
|
6
|
+
|
|
7
|
+
return serveRelationFanout(schema as unknown as SchemaLike, db, functionPath, args);
|
|
8
|
+
}
|
|
9
|
+
`}:{importFragment:"",override:""},g=(e,r,t,{cast:n="",sync:o=[]}={})=>{const i=`throw new Error(${JSON.stringify(r)});`,u=t.map(a=>` ${a}: ${o.includes(a)?"":"async "}() => {
|
|
10
|
+
${i}
|
|
11
|
+
},`).join(`
|
|
12
|
+
`);return`
|
|
13
|
+
const ${e} = {
|
|
14
|
+
${u}
|
|
15
|
+
}${n};
|
|
16
|
+
`},f={build:"",configField:"",contextField:"",importLines:[],stub:""},I=e=>e.size===0?{configField:"",constant:"",override:""}:{configField:"\n /** The `ShardRegistryDO` namespace (typically `env.SHARD_REGISTRY`). This shard registers its key for each `.shardBy()` table it writes, so cross-shard export, sync and migrations reach it. */\n shardRegistry?: (env: Record<string, unknown>) => unknown;",constant:`
|
|
17
|
+
/** The \`.shardBy()\` tables this shard registers with the shard registry when it writes them. */
|
|
18
|
+
const SHARDED_TABLES: ReadonlySet<string> = new Set([${[...e].map(r=>JSON.stringify(r)).join(", ")}]);
|
|
19
|
+
`,override:`
|
|
20
|
+
protected override shardRegistry(): undefined | { namespace: unknown; shardedTables: ReadonlySet<string> } {
|
|
21
|
+
const namespace = config.shardRegistry?.((this.env ?? {}) as Record<string, unknown>);
|
|
22
|
+
|
|
23
|
+
return namespace === undefined ? undefined : { namespace, shardedTables: SHARDED_TABLES };
|
|
24
|
+
}
|
|
25
|
+
`},T=(e,r)=>e?{build:`
|
|
26
|
+
const flags: import("${r}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
27
|
+
provider: () => config.flags?.(env),
|
|
28
|
+
targetingKey: () => flagsConfig.identify?.({ identity: identity ?? null, userId: userId ?? null }),
|
|
29
|
+
});
|
|
30
|
+
`,configField:`
|
|
31
|
+
flags?: (env: Record<string, unknown>) => import("${r}").Provider;`,contextField:`
|
|
32
|
+
flags,`,importLines:[`import { createFlags } from "${r}";`,'import flagsConfig from "../flags.js";'],stub:""}:f,q=e=>e?{build:`
|
|
33
|
+
const { notify, push } = createNotify(notifyConfig, env, { log, metrics });
|
|
34
|
+
`,configField:"",contextField:`
|
|
35
|
+
notify,
|
|
36
|
+
push,`,importLines:['import { createNotify } from "@lunora/notify";','import notifyConfig from "../notify.js";'],stub:""}:f,B=e=>e?{build:`
|
|
37
|
+
const envConfig = lunoraEnvContract.${e.exportName}(env);
|
|
38
|
+
`,configField:"",contextField:`
|
|
39
|
+
env: envConfig,`,importLines:['import * as lunoraEnvContract from "../env.js";'],stub:""}:f,D=(e,r,t)=>{if(!r)return{constant:"",evaluateOverride:"",subscriptionOverride:""};const n=a=>`
|
|
40
|
+
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
41
|
+
const flags: import("${t}").LunoraFlags = createFlags(flagsConfig, env, {
|
|
42
|
+
provider: () => config.flags?.(env),
|
|
43
|
+
targetingKey: ${a},
|
|
44
|
+
});`,o=`
|
|
45
|
+
/** Statically-discovered feature flags (\`ctx.flags.<type>("key")\` reads) served via \`__lunora_admin__:listFlags\` + the reactive \`__lunora_flags__:\` channel. */
|
|
46
|
+
const LUNORA_FLAG_KEYS = ${y(e,'ReadonlyArray<{ key: string; type: "boolean" | "number" | "object" | "string" }>')};
|
|
47
|
+
`,i=`
|
|
48
|
+
protected override async evaluateFlags(context?: Record<string, unknown>): Promise<FlagsResult> {${n("undefined")}
|
|
49
|
+
const evalContext = context as import("${t}").EvaluationContext | undefined;
|
|
50
|
+
const evaluations: FlagsResult["flags"] = [];
|
|
51
|
+
|
|
52
|
+
for (const entry of LUNORA_FLAG_KEYS) {
|
|
53
|
+
// eslint-disable-next-line no-await-in-loop -- flags evaluate sequentially; each shares the single memoized provider client
|
|
54
|
+
const details =
|
|
55
|
+
entry.type === "boolean"
|
|
56
|
+
? await flags.details.boolean(entry.key, false, evalContext)
|
|
57
|
+
: entry.type === "number"
|
|
58
|
+
? await flags.details.number(entry.key, 0, evalContext)
|
|
59
|
+
: entry.type === "string"
|
|
60
|
+
? await flags.details.string(entry.key, "", evalContext)
|
|
61
|
+
: await flags.details.object(entry.key, {}, evalContext);
|
|
62
|
+
|
|
63
|
+
evaluations.push({ errorCode: details.errorCode, key: entry.key, reason: details.reason, type: entry.type, value: details.value, variant: details.variant });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { configured: true, flags: evaluations };
|
|
67
|
+
}
|
|
68
|
+
`,u=`
|
|
69
|
+
protected override runFlagSubscriptionRead(_functionPath: string, args: Record<string, unknown>, identity?: SubscriptionIdentity): Promise<unknown> {${n("() => flagsConfig.identify?.({ identity: identity?.identity ?? null, userId: identity?.userId ?? null })")}
|
|
70
|
+
const key = typeof args.key === "string" ? args.key : "";
|
|
71
|
+
|
|
72
|
+
// SECURITY: the reactive channel is public (any socket, no auth). Serve
|
|
73
|
+
// ONLY statically-discovered flag keys — an arbitrary client-supplied key
|
|
74
|
+
// would let a subscriber probe the value of internal/unreleased flags the
|
|
75
|
+
// app never exposes. Unknown key ⇒ the "nothing to deliver" sentinel.
|
|
76
|
+
// eslint-disable-next-line unicorn/no-null -- the base hook's "nothing to deliver" sentinel
|
|
77
|
+
if (key.length === 0 || !LUNORA_FLAG_KEYS.some((entry) => entry.key === key)) {
|
|
78
|
+
return Promise.resolve(null);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// SECURITY: evaluate under the socket's server-verified identity ONLY
|
|
82
|
+
// (the targetingKey resolved above). Client-supplied targeting context is
|
|
83
|
+
// NOT honored on this public channel — otherwise a subscriber could spoof
|
|
84
|
+
// targeting attributes (e.g. plan/role) to unlock a flag gated on them.
|
|
85
|
+
const context = undefined;
|
|
86
|
+
|
|
87
|
+
if (args.type === "number") {
|
|
88
|
+
return flags.number(key, typeof args.default === "number" ? args.default : 0, context);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (args.type === "string") {
|
|
92
|
+
return flags.string(key, typeof args.default === "string" ? args.default : "", context);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (args.type === "object") {
|
|
96
|
+
return flags.object(key, (args.default ?? {}) as import("${t}").JsonValue, context);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return flags.boolean(key, typeof args.default === "boolean" ? args.default : false, context);
|
|
100
|
+
}
|
|
101
|
+
`;return{constant:o,evaluateOverride:i,subscriptionOverride:u}},v=()=>({build:`
|
|
102
|
+
const aiBinding = config.ai?.(env) ?? (env as Record<string, unknown>).AI;
|
|
103
|
+
// Correlate AI-Gateway-routed calls with the Lunora trace: thread the
|
|
104
|
+
// function path + trace id into createAi, which folds them into the
|
|
105
|
+
// gateway's \`metadata\`. Mirror the tracer's anchor guard — a deferred
|
|
106
|
+
// subscription re-run must not borrow a concurrent dispatch's trace, so
|
|
107
|
+
// read \`getCurrentTrace()\` only on the synchronous (non-threaded-identity) path.
|
|
108
|
+
const aiTrace = options.identity ? undefined : this.getCurrentTrace();
|
|
109
|
+
// \`telemetry\` gives every model call an \`ai.generate\` / \`ai.stream\` span
|
|
110
|
+
// and \`gen_ai.usage.*\` token + cost counters attributed to this function.
|
|
111
|
+
const ai: LunoraAi = createAi({
|
|
112
|
+
binding: aiBinding as AiBindingLike | undefined,
|
|
113
|
+
env: env as Record<string, unknown>,
|
|
114
|
+
metadata: { functionPath: options.functionPath, traceId: aiTrace?.traceId },
|
|
115
|
+
telemetry: { metrics, trace },
|
|
116
|
+
});
|
|
117
|
+
`,configField:`
|
|
118
|
+
ai?: (env: Record<string, unknown>) => AiBindingLike;`,importLines:['import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'],stub:""}),k=()=>({build:`
|
|
119
|
+
const access = accessFacade(identity, userId);
|
|
120
|
+
`,configField:"",importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}),R=()=>({build:`
|
|
121
|
+
const r2sqlEnv = env as Record<string, unknown>;
|
|
122
|
+
const r2sqlAccountId = (r2sqlEnv.R2_SQL_ACCOUNT_ID ?? r2sqlEnv.CLOUDFLARE_ACCOUNT_ID) as string | undefined;
|
|
123
|
+
const r2sqlToken = r2sqlEnv.R2_SQL_TOKEN as string | undefined;
|
|
124
|
+
const r2sqlBucket = r2sqlEnv.R2_SQL_BUCKET as string | undefined;
|
|
125
|
+
const r2sql: R2SqlClient = config.r2sql
|
|
126
|
+
? config.r2sql(env)
|
|
127
|
+
: r2sqlAccountId && r2sqlToken && r2sqlBucket
|
|
128
|
+
? createR2Sql({ accountId: r2sqlAccountId, apiToken: r2sqlToken, bucket: r2sqlBucket })
|
|
129
|
+
: r2sqlStub;
|
|
130
|
+
`,configField:`
|
|
131
|
+
r2sql?: (env: Record<string, unknown>) => R2SqlClient;`,importLines:['import type { R2SqlClient } from "@lunora/bindings/r2sql";','import { createR2Sql } from "@lunora/bindings/r2sql";'],stub:g("r2sqlStub: R2SqlClient","ctx.r2sql: no R2 SQL credentials found. Set `R2_SQL_TOKEN`, `R2_SQL_ACCOUNT_ID` (or `CLOUDFLARE_ACCOUNT_ID`), and `R2_SQL_BUCKET` in your env/.dev.vars, or pass an `r2sql` config thunk to createShardDO().",["describe","explain","from","query","showDatabases","showTables"],{sync:["from"]})}),N=()=>({build:`
|
|
132
|
+
const x402: X402Pay = config.x402
|
|
133
|
+
? lazyX402Pay(config.x402(env), { getSecret: (name: string) => secrets.get(name) })
|
|
134
|
+
: x402Stub;
|
|
135
|
+
`,configField:`
|
|
136
|
+
x402?: (env: Record<string, unknown>) => X402PayConfig;`,importLines:['import type { X402Pay, X402PayConfig } from "@lunora/x402/pay";','import { lazyX402Pay } from "@lunora/x402/pay";'],stub:g("x402Stub: X402Pay","ctx.x402: no pay rail configured. Pass `x402` to createShardDO().",["fetch"],{cast:" as unknown as X402Pay",sync:["fetch"]})}),S={access:k,ai:v,r2sql:R,x402:N},w=e=>e.shardBinding==="bespoke",L=e=>typeof e.shardBinding=="object",d=" ",A=(e,r,t)=>{const n=`${e}Binding`,{factory:o}=t;let i=`(${n} as ${r})`;if(o!==void 0){const u=`${n} as ${t.bindingType??r}`;i=o.option===void 0?`${o.name}(${u})`:`${o.name}({ ${o.option}: ${u} })`}return`${n} ? ${i} : ${e}Stub`},C=(e,r,t)=>{const n=A(e,r,t),o=`${d}const ${e}Binding = config.${e}?.(env) ?? (env as Record<string, unknown>).${t.envName};
|
|
137
|
+
`,i=t.unvouchableReads??[];return i.length===0?`
|
|
138
|
+
${o}${d}const ${e}: ${r} = ${n};
|
|
139
|
+
`:`
|
|
140
|
+
${o}${d}// ${t.envName} is not this shard's SQLite, so nothing appends a \`__cdc_log\` entry
|
|
141
|
+
${d}// when a value changes — a subscription that read one can never be proven
|
|
142
|
+
${d}// current on reconnect and must re-snapshot. Reads only; writes stay unstamped.
|
|
143
|
+
${d}const ${e}: ${r} = markUnvouchableReads(${n}, options.onRead, [
|
|
144
|
+
${i.map(u=>`${d} ${JSON.stringify(u)},`).join(`
|
|
145
|
+
`)}
|
|
146
|
+
${d}]);
|
|
147
|
+
`},F=(e,r,t)=>{const{binding:n,clientType:o}=t,i=g(`${e}Stub: ${o}`,t.missingMessage,t.stubMethods,{sync:t.syncStubMethods});if(n===void 0){const l=t.instrument===void 0?`config.${e}(env)`:`this.${t.instrument}(config.${e}(env), logFunctionPath, traceAnchor, observability)`;return{build:`
|
|
148
|
+
${d}const ${e}: ${o} = config.${e} ? ${l} : ${e}Stub;
|
|
149
|
+
`,configField:`
|
|
150
|
+
${e}?: (env: Record<string, unknown>) => ${o};`,importLines:[`import type { ${o} } from "${r}";`],stub:i}}const u=n.bindingType??o,a=[...new Set([u,o])].toSorted((l,s)=>l.localeCompare(s));return{build:C(e,o,n),configField:`
|
|
151
|
+
${e}?: (env: Record<string, unknown>) => ${u};`,importLines:[`import type { ${a.join(", ")} } from "${r}";`,...n.factory===void 0?[]:[`import { ${n.factory.name} } from "${r}";`]],stub:i}},U=e=>{const r=[],t=[];let n="",o="",i="",u="",a="";for(const l of $.filter(({key:s})=>e.has(s))){let s;if(w(l))s=S[l.key]();else if(L(l))s=F(l.contextProperty,l.moduleSpecifier,l.shardBinding);else continue;const m=l.contextProperty;t.push(...s.importLines),o+=s.configField,a+=s.stub,l.tier==="every"?(i+=s.build,u+=`
|
|
152
|
+
${m},`):(n+=s.build,r.push(m))}return{actionBuild:n,actionFields:r,configFields:o,everyBuild:i,everyFields:u,importLines:t,stubs:a}},j=(e,r)=>{if(e.length===0)return"";const t=r?`, ${JSON.stringify(r)}`:"",n=e.map(s=>{c(s.exportName,`container export "${s.exportName}"`),c(s.className,`container class "${s.className}"`);const m=s.sandbox===!0?"LunoraSandboxContainer":"LunoraContainer";return`/** Container DO for the \`${s.exportName}\` definition (binding \`${s.bindingName}\`). */
|
|
153
|
+
export class ${s.className} extends ${m} {
|
|
154
|
+
public constructor(ctx: ConstructorParameters<typeof ${m}>[0], env: Record<string, unknown>) {
|
|
155
|
+
super(ctx, env, ${s.exportName}, "${s.exportName}"${t});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
`}).join(`
|
|
159
|
+
`),o=e.map(s=>s.exportName).join(", "),i=e.some(s=>s.sandbox===!0),u=e.some(s=>s.sandbox!==!0)?`import { LunoraContainer } from "@lunora/container/do";
|
|
160
|
+
`:"";return`${p}/**
|
|
161
|
+
* Container-enabled Durable Object classes for the containers declared in
|
|
162
|
+
* \`lunora/containers.ts\`. Re-export them from your worker entry — wrangler
|
|
163
|
+
* requires each \`containers[].class_name\` to be exported by the worker:
|
|
164
|
+
*
|
|
165
|
+
* \`export * from "./lunora/_generated/containers.js";\`
|
|
166
|
+
*
|
|
167
|
+
* \`ContainerProxy\` is re-exported alongside them: the egress-interception path
|
|
168
|
+
* (\`allowedHosts\`/\`deniedHosts\`/\`interceptHttps\` and the runtime
|
|
169
|
+
* \`handle.egress\` controls) routes container outbound traffic through this
|
|
170
|
+
* WorkerEntrypoint, so it too must be exported by the deployed worker.
|
|
171
|
+
*/
|
|
172
|
+
${u}${i?`import { LunoraSandboxContainer } from "@lunora/container/sandbox";
|
|
173
|
+
`:""}
|
|
174
|
+
import { ${o} } from "../containers.js";
|
|
175
|
+
|
|
176
|
+
export { ContainerProxy } from "@lunora/container/do";
|
|
177
|
+
${i?`
|
|
178
|
+
/**
|
|
179
|
+
* \`DirectoryBackup\` and \`S3Mount\` route a \`sandbox: true\` container's storage
|
|
180
|
+
* traffic through these WorkerEntrypoints, so the deployed worker must export them.
|
|
181
|
+
*/
|
|
182
|
+
export { DirectoryBackupGateway, S3Gateway } from "@lunora/container/sandbox";
|
|
183
|
+
`:""}
|
|
184
|
+
${n}`},Q=(e,r)=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const n of e)c(n.exportName,`container export "${n.exportName}"`),c(n.bindingName,`container binding "${n.bindingName}"`);const t=e.map(n=>{const o=n.schedulingPolicy!==void 0||n.maxInstances===void 0?"":`, maxInstances: ${String(n.maxInstances)}`;return` { binding: "${n.bindingName}", exportName: "${n.exportName}"${o} },`}).join(`
|
|
185
|
+
`);return{build:`
|
|
186
|
+
const containers = createContainerContext(env, LUNORA_CONTAINERS, ${r?JSON.stringify(r):"undefined"}, this.getCurrentTraceparent(), this.getCurrentSampleErrors());
|
|
187
|
+
`,contextField:`
|
|
188
|
+
containers,`,importLines:['import type { ContainerBindingSpec } from "@lunora/container";','import { createContainerContext } from "@lunora/container";'],specs:`
|
|
189
|
+
/** Wiring specs for \`ctx.containers\` (codegen-derived from \`lunora/containers.ts\`). */
|
|
190
|
+
const LUNORA_CONTAINERS: ReadonlyArray<ContainerBindingSpec> = [
|
|
191
|
+
${t}
|
|
192
|
+
];
|
|
193
|
+
`}},M=e=>{if(e.length===0)return"";const r=e.map(n=>(c(n.exportName,`workflow export "${n.exportName}"`),c(n.className,`workflow class "${n.className}"`),`/** WorkflowEntrypoint for the \`${n.exportName}\` definition, reached as \`ctx.exports.${n.className}\`. */
|
|
194
|
+
export class ${n.className} extends LunoraWorkflow<WorkflowParamsOf<typeof ${n.exportName}>, WorkflowOutputOf<typeof ${n.exportName}>> {
|
|
195
|
+
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
196
|
+
super(ctx, env, ${n.exportName}, "${n.exportName}");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
`)).join(`
|
|
200
|
+
`),t=e.map(n=>n.exportName).join(", ");return`${p}/**
|
|
201
|
+
* WorkflowEntrypoint classes for the workflows declared in
|
|
202
|
+
* \`lunora/workflows.ts\`. Re-export them from your worker entry — wrangler
|
|
203
|
+
* requires each \`workflows[].class_name\` to be exported by the worker:
|
|
204
|
+
*
|
|
205
|
+
* \`export * from "./lunora/_generated/workflows.js";\`
|
|
206
|
+
*/
|
|
207
|
+
import LunoraWorkflow from "@lunora/workflow/do";
|
|
208
|
+
|
|
209
|
+
import { ${t} } from "../workflows.js";
|
|
210
|
+
|
|
211
|
+
/** Params type carried by a \`defineWorkflow\` definition (its phantom \`__params\`), so each entrypoint keeps the authored \`ctx.params\` type. */
|
|
212
|
+
type WorkflowParamsOf<Definition> = Definition extends { __params?: infer Params }
|
|
213
|
+
? unknown extends Params
|
|
214
|
+
? Record<string, unknown>
|
|
215
|
+
: NonNullable<Params>
|
|
216
|
+
: Record<string, unknown>;
|
|
217
|
+
|
|
218
|
+
/** Output type carried by a \`defineWorkflow\` definition (its phantom \`__output\`), so each entrypoint keeps the authored return type. */
|
|
219
|
+
type WorkflowOutputOf<Definition> = Definition extends { __output?: infer Output } ? Output : unknown;
|
|
220
|
+
|
|
221
|
+
${r}`},K=e=>{if(e.length===0)return"";const t=e.filter(a=>a.voice).length>0,n=e.map(a=>{c(a.exportName,`agent export "${a.exportName}"`),c(a.className,`agent class "${a.className}"`);const l=`/** WorkflowEntrypoint for the \`${a.exportName}\` agent, reached as \`ctx.exports.${a.className}\`. */
|
|
222
|
+
export class ${a.className} extends LunoraWorkflow<AgentRunInput, AgentRunResult> {
|
|
223
|
+
public constructor(ctx: ConstructorParameters<typeof LunoraWorkflow>[0], env: Record<string, unknown>) {
|
|
224
|
+
super(ctx, env, compileAgentWorkflow(${a.exportName}, "${a.exportName}"), "${a.exportName}");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
`;if(!a.voice)return l;const s=a.voiceClassName??"",m=a.voiceBindingName??"";c(s,`agent voice class "${s}"`);const x=`
|
|
228
|
+
/** Voice-session Durable Object for the \`${a.exportName}\` agent (binding \`${m}\`). */
|
|
229
|
+
export class ${s} extends VoiceSessionDO {
|
|
230
|
+
public constructor(ctx: ConstructorParameters<typeof VoiceSessionDO>[0], env: Record<string, unknown>) {
|
|
231
|
+
super(ctx, env, ${a.exportName}, "${a.exportName}");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
`;return`${l}${x}`}).join(`
|
|
235
|
+
`),o=e.map(a=>a.exportName).join(", ");return`${p}/**
|
|
236
|
+
* WorkflowEntrypoint classes for the agents declared in \`lunora/agents.ts\`.
|
|
237
|
+
* Each \`defineAgent\` compiles a replay-safe tool-loop onto a Cloudflare
|
|
238
|
+
* Workflow. Re-export them from your worker entry — wrangler requires each
|
|
239
|
+
* \`workflows[].class_name\` to be exported by the worker:
|
|
240
|
+
*
|
|
241
|
+
* \`export * from "./lunora/_generated/agents.js";\`${t?"\n *\n * Voice-enabled agents ALSO get a `VoiceSessionDO` subclass here — a real\n * Durable Object (unlike the Workflow), so wrangler needs both its\n * `durable_objects` binding and its `class_name` export (the same re-export\n * line covers it).":""}
|
|
242
|
+
*/
|
|
243
|
+
import LunoraWorkflow from "@lunora/workflow/do";
|
|
244
|
+
${t?'import { compileAgentWorkflow, VoiceSessionDO } from "@lunora/agent";':'import { compileAgentWorkflow } from "@lunora/agent";'}
|
|
245
|
+
import type { AgentRunInput, AgentRunResult } from "@lunora/agent";
|
|
246
|
+
|
|
247
|
+
import { ${o} } from "../agents.js";
|
|
248
|
+
|
|
249
|
+
${n}`},G=e=>{const r=e.filter(o=>o.mode==="push");if(r.length===0)return"";for(const o of r)c(o.exportName,`queue export "${o.exportName}"`);const t=r.map(o=>o.exportName).join(", "),n=r.map(o=>` ${JSON.stringify(o.name)}: { binding: ${JSON.stringify(o.bindingName)}, definition: ${o.exportName}, exportName: ${JSON.stringify(o.exportName)} },`).join(`
|
|
250
|
+
`);return`${p}/**
|
|
251
|
+
* Push-consumer registry for the queues declared in \`lunora/queues.ts\`. The
|
|
252
|
+
* composed worker's \`queue(batch, env, ctx)\` entry routes each delivered batch
|
|
253
|
+
* by \`batch.queue\` to the matching \`defineQueue\` handler. Wired automatically
|
|
254
|
+
* by \`defineApp\` — you don't import this directly.
|
|
255
|
+
*/
|
|
256
|
+
import type { QueueRegistry } from "@lunora/queue";
|
|
257
|
+
|
|
258
|
+
import { ${t} } from "../queues.js";
|
|
259
|
+
|
|
260
|
+
/** Stable wrangler queue name → { binding, definition, exportName } for batch routing. */
|
|
261
|
+
export const LUNORA_QUEUE_REGISTRY: QueueRegistry = {
|
|
262
|
+
${n}
|
|
263
|
+
};
|
|
264
|
+
`},H=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const t of e)c(t.exportName,`workflow export "${t.exportName}"`),c(t.className,`workflow class "${t.className}"`);const r=e.map(t=>` { className: "${t.className}", exportName: "${t.exportName}" },`).join(`
|
|
265
|
+
`);return{build:`
|
|
266
|
+
const workflows = createWorkflowContext(env, LUNORA_WORKFLOWS, this.state.exports);
|
|
267
|
+
`,contextField:`
|
|
268
|
+
workflows,`,importLines:['import type { WorkflowBindingSpec } from "@lunora/workflow";','import { createWorkflowContext } from "@lunora/workflow";'],specs:`
|
|
269
|
+
/** Wiring specs for \`ctx.workflows\` (codegen-derived from \`lunora/workflows.ts\`). */
|
|
270
|
+
const LUNORA_WORKFLOWS: ReadonlyArray<WorkflowBindingSpec> = [
|
|
271
|
+
${r}
|
|
272
|
+
];
|
|
273
|
+
`}},J=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const t of e)c(t.exportName,`queue export "${t.exportName}"`),c(t.bindingName,`queue binding "${t.bindingName}"`);const r=e.map(t=>` { binding: "${t.bindingName}", exportName: "${t.exportName}", name: ${JSON.stringify(t.name)} },`).join(`
|
|
274
|
+
`);return{build:`
|
|
275
|
+
const queues = createQueueContext(env, LUNORA_QUEUES);
|
|
276
|
+
`,contextField:`
|
|
277
|
+
queues,`,importLines:['import type { QueueBindingSpec } from "@lunora/queue";','import { createQueueContext } from "@lunora/queue";'],specs:`
|
|
278
|
+
/** Wiring specs for \`ctx.queues\` (codegen-derived from \`lunora/queues.ts\`). */
|
|
279
|
+
const LUNORA_QUEUES: ReadonlyArray<QueueBindingSpec> = [
|
|
280
|
+
${r}
|
|
281
|
+
];
|
|
282
|
+
`}},V=(e,r)=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};const t=e.map(n=>{c(n.exportName,`topic export "${n.exportName}"`);const o=b(r,n.exportName).map(i=>`{ binding: "${i.bindingName}", exportName: "${i.exportName}" }`).join(", ");return` { exportName: "${n.exportName}", subscriptions: [${o}] },`}).join(`
|
|
283
|
+
`);return{build:`
|
|
284
|
+
const topics = createTopicContext(env, LUNORA_TOPICS);
|
|
285
|
+
`,contextField:`
|
|
286
|
+
topics,`,importLines:['import type { TopicBindingSpec } from "@lunora/queue";','import { createTopicContext } from "@lunora/queue";'],specs:`
|
|
287
|
+
/** Wiring specs for \`ctx.topics\` (codegen-derived from \`lunora/queues.ts\`): each topic's subscription queues. */
|
|
288
|
+
const LUNORA_TOPICS: ReadonlyArray<TopicBindingSpec> = [
|
|
289
|
+
${t}
|
|
290
|
+
];
|
|
291
|
+
`}},Y=(e,r)=>{if(e.length===0)return{build:"",importLines:[],specs:""};const t=e.map(n=>(c(n.name,`service "${n.name}"`),c(n.binding,`service binding "${n.binding}"`),` { binding: "${n.binding}", name: "${n.name}"${n.rpcEntrypoint===void 0?"":", rpc: true"} },`)).join(`
|
|
292
|
+
`);return{build:`
|
|
293
|
+
const services = createServices(env, LUNORA_SERVICES);
|
|
294
|
+
`,importLines:[`import type { ServiceBindingSpec } from "${r}";`,`import { createServices } from "${r}";`],specs:`
|
|
295
|
+
/** Wiring specs for \`ctx.services\` (codegen-derived from \`lunora.config\` \`services\`). */
|
|
296
|
+
const LUNORA_SERVICES: ReadonlyArray<ServiceBindingSpec> = [
|
|
297
|
+
${t}
|
|
298
|
+
];
|
|
299
|
+
`}},X=e=>{if(e.length===0)return{build:"",contextField:"",importLines:[],specs:""};for(const t of e)c(t.exportName,`agent export "${t.exportName}"`),c(t.className,`agent class "${t.className}"`);const r=e.map(t=>` { className: "${t.className}", exportName: "${t.exportName}"${t.publicRun===!0?", publicRun: true":""} },`).join(`
|
|
300
|
+
`);return{build:`
|
|
301
|
+
const agents = createAgentContext(env, LUNORA_AGENTS, { exports: this.state.exports });
|
|
302
|
+
`,contextField:`
|
|
303
|
+
agents,`,importLines:['import { createAgentContext } from "@lunora/agent";','import type { AgentBindingSpec } from "@lunora/agent";'],specs:`
|
|
304
|
+
/** Wiring specs for \`ctx.agents\` (codegen-derived from \`lunora/agents.ts\`). */
|
|
305
|
+
const LUNORA_AGENTS: ReadonlyArray<AgentBindingSpec> = [
|
|
306
|
+
${r}
|
|
307
|
+
];
|
|
308
|
+
`}},h=(e,r,t,n,o)=>({constant:`
|
|
309
|
+
${o}
|
|
310
|
+
const ${e} = ${y(n,r)};
|
|
311
|
+
`,override:`
|
|
312
|
+
protected override ${t}(): ${r} {
|
|
313
|
+
return ${e};
|
|
314
|
+
}
|
|
315
|
+
`}),z=e=>{if(e.length===0)return{constant:"",override:""};const r={workflows:e.map(t=>({className:t.className,exportName:t.exportName,name:t.name}))};return h("LUNORA_WORKFLOWS_INFO","WorkflowsResult","workflowsMetadata",r,"/** Read-only declared-workflow metadata (discovered from `lunora/workflows.ts`) served via `__lunora_admin__:listWorkflows` for the studio's workflows view. */")},Z=e=>{if(e.length===0)return{constant:"",override:""};const r={queues:e.map(t=>({binding:t.bindingName,...t.tuning.deadLetterQueue===void 0?{}:{deadLetterQueue:t.tuning.deadLetterQueue},exportName:t.exportName,mode:t.mode,name:t.name,...t.topic===void 0?{}:{topic:t.topic}}))};return h("LUNORA_QUEUES_INFO","QueuesResult","queuesMetadata",r,"/** Read-only declared-queue metadata (discovered from `lunora/queues.ts`) served via `__lunora_admin__:listQueues` for the studio's queues view. */")},ee=e=>e?{imports:['import type { LunoraDatabaseLike as LunoraPaymentDbLike, LunoraPayment, PaymentsFromContextOptions } from "@lunora/payment";','import { paymentsFromContext } from "@lunora/payment";'],build:`
|
|
316
|
+
const payments: LunoraPayment = config.payment
|
|
317
|
+
? paymentsFromContext({ auth: { userId: userId ?? null }, db: db as unknown as LunoraPaymentDbLike }, config.payment(env))
|
|
318
|
+
: paymentStub;
|
|
319
|
+
`,configField:`
|
|
320
|
+
payment?: (env: Record<string, unknown>) => PaymentsFromContextOptions;`,contextField:`
|
|
321
|
+
payments,`,stub:g("paymentStub: LunoraPayment","ctx.payments: no payment configured. Pass `payment` to createShardDO().",["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"],{cast:" as unknown as LunoraPayment",sync:["attach","cancelSubscription","check","createCheckout","createPortalSession","handleWebhook","listBalances","listSubscriptions","track"]})}:{build:"",configField:"",contextField:"",imports:[],stub:""},te=(e,r,t,n,o)=>["AdvisorProcedure","AdvisoryFinding","DatabaseWriterLike","DataMigrationLike","DispatchBookmark","ExportRow",...n?["FlagsResult"]:[],"ImportShardResult","KeyRange","MaskPoliciesResult","MigrationRunResult","QueryReadScope",...t?["QueuesResult"]:[],"RelatedPage","RunShardApplyCdcArgs","RunShardExportArgs","RunShardFindRelatedArgs","RunShardImportArgs","RunShardMigrationArgs","RlsPoliciesResult","RunShardRankBeforeArgs","RunShardRankPageArgs","RunShardWriteArgs","RunShardWriteResult","SchedulerLike",...o?["SearchBackfillProgress"]:[],"TransactionHeadroomTracker","SchemaLike","ShardDOState","ShardRankPageResult","SqlExec","StorageRulesResult","StudioFeaturesResult","SubscriptionIdentity","SystemReaderStorageLike","TelemetrySink",...e?["VectorBackfillProgress"]:[],...r?["WorkflowsResult"]:[],...e?["WriteHook"]:[]];export{T as a,D as b,B as c,J as d,U as e,V as f,Y as g,Q as h,H as i,X as j,ee as k,z as l,Z as m,I as n,te as o,W as p,q,g as r,K as s,j as t,M as u,G as v};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{LunoraError as u}from"@lunora/errors";import{R as $}from"./reserved-words-CW1QFbTd.mjs";import{acceptsAbsentIr as b}from"./LUNORA_ERROR_CODES-C2s0xWQD.mjs";const g=/^(?:"(?:[^"\\]|\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4}))*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u,k=`// GENERATED by @lunora/codegen — do not edit.
|
|
2
|
+
// Run \`lunora codegen\` to regenerate.
|
|
3
|
+
|
|
4
|
+
`,I=(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"},i=/^[A-Za-z_$][\w$]*$/u,A=/^[\w./-]+$/u,f=(e,n)=>{if(!i.test(e)||$.has(e))throw new u("INTERNAL",`@lunora/codegen: ${n} is not a valid JS identifier: ${JSON.stringify(e)}`)},N=(e,n)=>{if(!i.test(e))throw new u("INTERNAL",`@lunora/codegen: ${n} is not a valid JS identifier: ${JSON.stringify(e)}`)},O=e=>e.charAt(0).toUpperCase()+e.slice(1),a=e=>i.test(e)?e:JSON.stringify(e),S=e=>e==="__proto__"?`[${JSON.stringify(e)}]`:a(e),d={any:"unknown",bigint:"bigint",boolean:"boolean",bytes:"ArrayBuffer",date:"number",geoPoint:"{ lat: number; lng: number }",null:"null",number:"number",storage:"string",string:"string",timestamp:"number"},T=e=>{if(e===void 0)return"unknown";if(!g.test(e))throw new u("INTERNAL",`@lunora/codegen: v.literal() argument is not a parseable string/number/boolean/null literal: ${JSON.stringify(e)}`);return e},t=e=>e.column?.notNull===!1?`${p(e)} | null`:p(e),p=e=>{const n=d[e.kind];if(n!==void 0)return n;switch(e.kind){case"array":return`Array<${e.inner?t(e.inner):"unknown"}>`;case"from":return e.tsType??"unknown";case"id":{const r=e.tableName??"_unknown_";return f(r,"v.id() table name"),`Id<"${r}">`}case"literal":return T(e.literalValue);case"object":return e.shape?`{ ${Object.entries(e.shape).map(([s,o])=>y(s,o)).join("; ")} }`:"Record<string, unknown>";case"optional":return`${e.inner?t(e.inner):"unknown"} | undefined`;case"record":{const r=e.keyType?t(e.keyType):"string",s=e.valueType?t(e.valueType):"unknown";return`Record<${r}, ${s}>`}case"union":return e.members&&e.members.length>0?e.members.map(r=>t(r)).join(" | "):"never";default:return"unknown"}},y=(e,n)=>{const r=a(e);if(n.kind==="optional"){const s=n.inner?t(n.inner):"unknown";return`${r}?: ${s}`}return b(n)?`${r}?: ${t(n)}`:`${r}: ${t(n)}`},D=e=>{const n=Object.entries(e);return n.length===0?"{}":`{ ${n.map(([r,s])=>y(r,s)).join("; ")} }`},E=e=>e.kind==="optional"||!!e.column?.hasDefault,h=e=>e.kind==="optional"&&e.inner?e.inner:e,j=e=>{f(e.name,"table name");const n=Object.entries(e.shape).map(([s,o])=>{const m=h(o),c=t(m),l=a(s);return E(o)?` ${l}?: ${c};`:` ${l}: ${c};`}).join(`
|
|
5
|
+
`),r=n?`
|
|
6
|
+
${n}
|
|
7
|
+
`:"";return`export interface Insert_${e.name} {
|
|
8
|
+
_id?: Id<"${e.name}">;
|
|
9
|
+
_creationTime?: number;${r}}`};export{k as G,A as I,g as L,f as a,a as b,S as c,I as d,j as e,N as f,E as i,O as p,D as r,h as u,t as v};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Node as l,SyntaxKind as g}from"ts-morph";import{lunoraRelativePath as L}from"./listLunoraSourceFiles-DRes9d5p.mjs";import{posix as D}from"node:path";let S,v;const Ae=e=>{const t=S,n=[];S=n;try{return{erased:n,value:e()}}finally{S=t}},Te=e=>{S?.push(...e)},j=e=>{for(const t of e.getAncestors())if(l.isVariableDeclaration(t))return t.getName()},w=(e,t)=>{S?.push({exportName:j(e),filePath:e.getSourceFile().getFilePath(),line:e.getStartLineNumber(),rendered:t})},Ne=e=>{v!==void 0&&w(v,e)},xe=(e,t)=>{const n=v;v=e;try{return t()}finally{v=n}},k=(e,t)=>{const n=e.exportName??`line ${e.line.toString()}`;return{cacheKey:`procedure_return_type_erased:${t}:${n}`,categories:["SCHEMA"],description:"Codegen renders a procedure's return type into `_generated/`, where only names that resolve from that directory may appear. A type it can neither name nor reproduce structurally — a class instance, a call or index signature, a recursive or very deeply nested shape — is emitted as `unknown` instead, so callers lose the shape while the runtime still returns it.",detail:`\`${n}\` in \`${t}\` (line ${e.line.toString()}) returns \`${e.rendered}\`, which codegen could not reproduce — its generated type is \`unknown\`.`,facing:"INTERNAL",level:"WARN",metadata:{exportName:e.exportName,filePath:t,line:e.line,rendered:e.rendered},name:"procedure_return_type_erased",remediation:"Declare the shape explicitly with `.output(...)`, or export the type from the module that declares it so codegen can name it. A class instance cannot cross the wire at all — return a plain object.",title:"Procedure return type is missing from the generated type"}},De=(e,t)=>{const n=new Map;for(const r of e){const s=k(r,L(t,r.filePath));n.set(s.cacheKey,s)}return[...n.values()].toSorted((r,s)=>r.cacheKey.localeCompare(s.cacheKey))},P=/\bany\b(?!\s*(?:\?\s*)?:)/u,U=/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`/gu,O=e=>P.test(e.replaceAll(U,"")),K="/_generated/",B=e=>{const t=[e.getSymbol(),e.getAliasSymbol()].flatMap(n=>n?.getDeclarations()??[]);return t.length>0&&t.every(n=>n.getSourceFile().getSymbol()===void 0)},F=/^(?<quote>["'])(?<specifier>.*)\k<quote>$/su,T=e=>{for(const t of e.getAncestors())if(l.isModuleDeclaration(t)){const n=F.exec(t.getName());if(n?.groups?.specifier!==void 0)return n.groups.specifier}},h=new WeakMap,V=(e,t)=>{const n=e.getSymbol();if(n===void 0)return;let r=h.get(n.compilerSymbol);return r===void 0&&(r=new Map,h.set(n.compilerSymbol,r)),r.has(t)||r.set(t,n.getExport(t)??e.getExportSymbols().find(s=>s.getName()===t)),r.get(t)},_=(e,t)=>e.getNamespaceImport()!==void 0||e.getNamedImports().some(n=>n.getName()===t),W=(e,t,n)=>e.getModuleSpecifierValue()===t&&_(e,n)?n:void 0,q=(e,t)=>{const n=e.getDefaultImport();if(n===void 0)return;const r=n.getSymbol();return(r?.getAliasedSymbol()??r)?.getDeclarations().includes(t)===!0?"default":void 0},G=(e,t,n)=>{if(!_(e,n))return;const r=e.getModuleSpecifierSourceFile(),s=r===void 0?void 0:V(r,n);return(s?.getAliasedSymbol()??s)?.getDeclarations().includes(t)===!0?n:void 0},X=/^\.\.?(?:$|\/)/u,H=new Map([[".cjs",".cjs"],[".cts",".cjs"],[".d.ts",".js"],[".js",".js"],[".jsx",".jsx"],[".mjs",".mjs"],[".mts",".mjs"],[".ts",".js"],[".tsx",".js"]]),Y=(e,t)=>{const n=t.getModuleSpecifierValue();if(!X.test(n))return;const r=t.getModuleSpecifierSourceFile(),s=r===void 0?void 0:H.get(r.getExtension());if(r===void 0||s===void 0)return;const i=`${D.join(r.getDirectoryPath(),r.getBaseNameWithoutExtension())}${s}`,o=D.relative(e.getDirectoryPath(),i);return o.startsWith(".")?o:`./${o}`},J=(e,t,n)=>{const r=T(t);for(const s of e.getImportDeclarations()){const i=r===void 0?q(s,t)??G(s,t,n):W(s,r,n);if(i!==void 0)return{exportName:i,specifier:Y(e,s)??s.getModuleSpecifierValue()}}},z=(e,t)=>Object.keys(t.getProject().getCompilerOptions().paths??{}).some(n=>{const r=n.indexOf("*");return r===-1?e===n:e.startsWith(n.slice(0,r))&&e.endsWith(n.slice(r+1))}),m={kind:"verbatim"},p={kind:"expand"},Q=new Set([g.ClassDeclaration,g.EnumDeclaration,g.EnumMember,g.InterfaceDeclaration,g.TypeAliasDeclaration]),Z=e=>T(e)!==void 0||l.isExportable(e)&&e.isExported(),ee=(e,t)=>new RegExp(String.raw`(?<![$\w])${t.replaceAll(/[$()*+.?[\\\]^{|}]/gu,String.raw`\$&`)}(?![$\w])`,"u").test(e),M=(e,t,n,r)=>{const s=e.getSourceFile();if(s.getSymbol()===void 0&&T(e)===void 0||!Q.has(e.getKind()))return m;const i=s.getFilePath();if(i.includes(K))return m;if(i===n)return p;const o=l.isEnumMember(e)?e.getParent():e;if(!l.hasName(o))return p;const a=J(t.getSourceFile(),o,o.getName());return a===void 0?Z(o)||!ee(r(),o.getName())?m:p:z(a.specifier,t)?p:{kind:"qualify",qualified:a}},te=new Set([g.ClassDeclaration,g.EnumDeclaration,g.FunctionDeclaration,g.ModuleDeclaration]),I=e=>{const t=e?.getDeclarations()??[];return t.length>0&&t.every(n=>n.getSourceFile().getSymbol()===void 0)},ne=e=>{for(const t of e.getDeclarations()){const n=t.getFirstChildByKind(g.ComputedPropertyName);if(n!==void 0){let r=n.getExpression();for(;l.isPropertyAccessExpression(r);)r=r.getExpression();return r}}},re=(e,t)=>{if(e.getProperties().some(s=>{if(!s.getName().startsWith("__@"))return!1;const i=ne(s);return i===void 0||!I(i.getSymbol())}))return!0;const r=e.getSymbol();return r!==void 0&&r.getDeclarations().some(s=>te.has(s.getKind()))&&!I(r)&&t().startsWith("typeof ")},R=(e,t,n)=>{const r=e.getAliasSymbol(),s=e.getSymbol(),i=new Set((r??s)?.getDeclarations());let o=!1,a;const c=()=>(a??=e.getText(t),a);for(const u of[s,r].flatMap(d=>d?.getDeclarations()??[])){const d=M(u,t,n,c);if(d.kind==="qualify"&&i.has(u))return d;o||=d.kind!=="verbatim"}return o||re(e,c)?p:m},se=(e,t,n)=>{const r=l.isPropertySignature(e)||l.isPropertyDeclaration(e)?e.getTypeNode():void 0;if(r===void 0)return m;let s=!1;for(const i of[r,...r.getDescendantsOfKind(g.TypeReference)].filter(o=>l.isTypeReference(o))){const o=i.getTypeName().getSymbol();for(const a of(o?.getAliasedSymbol()??o)?.getDeclarations()??[]){const c=M(a,t,n,()=>i.getText());if(c.kind==="qualify")return c;s||=c.kind!=="verbatim"}}return s?p:m},oe=/^[A-Za-z_$][\w$]*$/u,ie=e=>oe.test(e)?e:JSON.stringify(e),$=e=>{const t=[...e.getTypeArguments()];return e.isUnion()&&t.push(...e.getUnionTypes()),e.isIntersection()&&t.push(...e.getIntersectionTypes()),t},y=e=>!e.isObject()||e.isArray()||e.isTuple()||e.getCallSignatures().length>0||e.getConstructSignatures().length>0?!1:e.getStringIndexType()===void 0&&e.getNumberIndexType()===void 0&&!e.getProperties().some(t=>t.getName().startsWith("__@")),E=(e,t,n,r=new Set)=>r.has(e)?!1:(r.add(e),R(e,t,n).kind!=="verbatim"||$(e).some(s=>E(s,t,n,r))?!0:y(e)?e.getProperties().some(s=>s.getDeclarations().some(i=>se(i,t,n).kind!=="verbatim")?!0:E(s.getTypeAtLocation(t),t,n,r)):!1),ae=(e,t)=>{const n=e.getValueDeclaration()??e.getDeclarations()[0];return n&&(l.isPropertySignature(n)||l.isPropertyDeclaration(n))&&n.hasQuestionToken()?!0:t.isUnion()&&t.getUnionTypes().some(r=>r.isUndefined())},C=(e,t)=>e!==void 0&&(y(e)||e.isString()||e.isNumber()||e.isBigInt()||e.isBoolean()||e.isLiteral()||e.isBooleanLiteral()||e.isEnumLiteral()||e.isTemplateLiteral()||e.isNull()||e.isUndefined()||e.isAny()||e.isUnknown()||e.isNever()||e.isVoid())?t:`(${t})`,ce=32,ue=8,le=(e,t,n,r,s,i)=>{const o=e.getArrayElementType(),a=o?i(o,t,n,r,s):void 0;if(a!==void 0)return`${C(o,a)}[]`},ge=(e,t,n,r,s,i)=>{const o=[];for(const a of e.getUnionTypes()){const c=i(a,t,n,r,s);if(c===void 0)return;o.push(c)}return o.join(" | ")},de=(e,t,n,r,s,i)=>{const o=[];for(const a of e.getIntersectionTypes()){const c=i(a,t,n,r,s);if(c===void 0)return;o.push(C(a,c))}return o.join(" & ")},me=(e,t,n,r,s,i)=>{if(!y(e))return;const o=[];for(const a of e.getProperties()){const c=a.getTypeAtLocation(t),u=ae(a,c),d=u&&c.isUnion()?c.getUnionTypes().filter(A=>!A.isUndefined()):[c],N=[];for(const A of d){const x=i(A,t,n,r+1,s);if(x===void 0)return;N.push(x)}o.push(`${ie(a.getName())}${u?"?":""}: ${N.join(" | ")}`)}return o.length>0?`{ ${o.join("; ")} }`:"{}"},fe=e=>{const t=e.getLiteralValue();return typeof t=="string"?JSON.stringify(t):typeof t=="number"?String(t):void 0},pe=e=>[e.getSymbol(),e.getAliasSymbol()].flatMap(t=>t?.getDeclarations()??[]).some(t=>l.isClassDeclaration(t)||l.isClassExpression(t)),b=(e,t,n,r,s=new Set)=>{if(r.has(e)||s.has(e))return!1;if(n>ce)return!0;const i=new Set(r).add(e);if($(e).some(u=>b(u,t,n+1,i,s)))return!0;const o=e.getArrayElementType();if(o!==void 0)return b(o,t,n+1,i,s);if(B(e))return s.add(e),!1;if(e.getCallSignatures().length>0||e.getConstructSignatures().length>0||[e.getSymbol(),e.getAliasSymbol()].flatMap(u=>u?.getDeclarations()??[]).some(u=>l.isClassDeclaration(u)||l.isClassExpression(u)))return!0;const c=y(e)&&e.getProperties().some(u=>b(u.getTypeAtLocation(t),t,n+1,i,s));return c||s.add(e),c},Se=(e,t,n,r,s,i,o)=>{const a=[];for(const c of t.getAliasSymbol()===void 0?t.getTypeArguments():t.getAliasTypeArguments()){const u=o(c,n,r,s+1,i);if(u===void 0)return;a.push(u)}return`import("${e.specifier}").${e.exportName}${a.length>0?`<${a.join(", ")}>`:""}`},ve=e=>[e.getSymbol(),e.getAliasSymbol()].flatMap(t=>t?.getDeclarations()??[]).some(t=>l.isEnumDeclaration(t)||l.isEnumMember(t)),f=(e,t,n,r,s)=>{if(r>ue||s.has(e))return;const i=R(e,t,n);if(i.kind==="verbatim"&&!E(e,t,n))return e.getText(t);const o=new Set(s).add(e);if(!pe(e)){if(e.isEnumLiteral())return fe(e);if(i.kind==="qualify"&&!ve(e)){const a=Se(i.qualified,e,t,n,r,o,f);if(a!==void 0)return a}return e.isArray()?le(e,t,n,r,o,f):e.isUnion()?ge(e,t,n,r,o,f):e.isIntersection()?de(e,t,n,r,o,f):me(e,t,n,r,o,f)}},he=e=>{const t=e.getType().getCallSignatures()[0];if(!t)return"unknown";let n=t.getReturnType();const s=(n.getSymbol()??n.getAliasSymbol())?.getName();if(s==="Promise"||s==="AsyncIterable"||s==="AsyncIterableIterator"||s==="AsyncGenerator"){const a=n.getTypeArguments()[0];a&&(n=a)}const i=n.getText(e);if(!i||i==="any"||i==="never"||O(i)||b(n,e,0,new Set))return"unknown";const o=e.getSourceFile().getFilePath();if(E(n,e,o)){const a=f(n,e,o,0,new Set);return a===void 0&&w(e,i),a??"unknown"}return i};export{E as a,Ne as b,Ae as c,De as d,f as e,O as i,xe as p,Te as r,he as u};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/codegen",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.261",
|
|
4
4
|
"description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,14 +46,23 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/advisor": "1.0.0-alpha.
|
|
50
|
-
"@lunora/
|
|
51
|
-
"@lunora/
|
|
52
|
-
"@lunora/
|
|
53
|
-
"@lunora/
|
|
54
|
-
"@lunora/
|
|
49
|
+
"@lunora/advisor": "1.0.0-alpha.189",
|
|
50
|
+
"@lunora/agent": "1.0.0-alpha.175",
|
|
51
|
+
"@lunora/container": "1.0.0-alpha.69",
|
|
52
|
+
"@lunora/errors": "1.0.0-alpha.50",
|
|
53
|
+
"@lunora/platform": "1.0.0-alpha.55",
|
|
54
|
+
"@lunora/queue": "1.0.0-alpha.91",
|
|
55
|
+
"@lunora/scheduler": "1.0.0-alpha.109",
|
|
56
|
+
"@lunora/values": "1.0.0-alpha.60",
|
|
57
|
+
"@lunora/workflow": "1.0.0-alpha.71",
|
|
58
|
+
"jiti": "^2.7.0",
|
|
59
|
+
"quicktype-core": "^26.0.0",
|
|
55
60
|
"ts-morph": "^28.0.0"
|
|
56
61
|
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@lunora/server": ">=1.0.0-alpha.91 <2.0.0-0",
|
|
64
|
+
"@lunora/shard-engine": ">=1.0.0-alpha.45 <2.0.0-0"
|
|
65
|
+
},
|
|
57
66
|
"engines": {
|
|
58
67
|
"node": "^22.15.0 || >=24.11.0"
|
|
59
68
|
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { containerClassName, containerBindingName, normalizeContainerImage } from '@lunora/container';
|
|
4
|
-
import { SyntaxKind, Node } from 'ts-morph';
|
|
5
|
-
import { diagnosticAt } from './CodegenDiagnosticError-DeblMkzO.mjs';
|
|
6
|
-
|
|
7
|
-
const CONTAINERS_FILENAME = "containers.ts";
|
|
8
|
-
const isDefineContainer = (identifier) => {
|
|
9
|
-
const symbol = identifier.getSymbol();
|
|
10
|
-
if (!symbol) {
|
|
11
|
-
return identifier.getText() === "defineContainer";
|
|
12
|
-
}
|
|
13
|
-
for (const declaration of symbol.getDeclarations()) {
|
|
14
|
-
if (!Node.isImportSpecifier(declaration)) {
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
if (declaration.getImportDeclaration().getModuleSpecifierValue() !== "@lunora/container") {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
return declaration.getNameNode().getText() === "defineContainer";
|
|
21
|
-
}
|
|
22
|
-
return false;
|
|
23
|
-
};
|
|
24
|
-
const stringProperty = (expression, exportName, property) => {
|
|
25
|
-
if (Node.isStringLiteral(expression) || Node.isNoSubstitutionTemplateLiteral(expression)) {
|
|
26
|
-
return expression.getLiteralValue();
|
|
27
|
-
}
|
|
28
|
-
throw diagnosticAt(
|
|
29
|
-
expression,
|
|
30
|
-
`container "${exportName}": \`${property}\` must be a static string literal — it is deploy configuration codegen writes into wrangler.jsonc`
|
|
31
|
-
);
|
|
32
|
-
};
|
|
33
|
-
const numberProperty = (expression, exportName, property) => {
|
|
34
|
-
if (Node.isNumericLiteral(expression)) {
|
|
35
|
-
return expression.getLiteralValue();
|
|
36
|
-
}
|
|
37
|
-
throw diagnosticAt(
|
|
38
|
-
expression,
|
|
39
|
-
`container "${exportName}": \`${property}\` must be a static number literal — it is deploy configuration codegen writes into wrangler.jsonc`
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
const imageFromExpression = (expression, exportName) => {
|
|
43
|
-
if (Node.isStringLiteral(expression) || Node.isNoSubstitutionTemplateLiteral(expression)) {
|
|
44
|
-
return normalizeContainerImage(expression.getLiteralValue());
|
|
45
|
-
}
|
|
46
|
-
if (Node.isObjectLiteralExpression(expression)) {
|
|
47
|
-
const registry = expression.getProperty("registry");
|
|
48
|
-
if (registry && Node.isPropertyAssignment(registry)) {
|
|
49
|
-
const initializer = registry.getInitializerOrThrow();
|
|
50
|
-
return normalizeContainerImage({ registry: stringProperty(initializer, exportName, "image.registry") });
|
|
51
|
-
}
|
|
52
|
-
const build = expression.getProperty("build");
|
|
53
|
-
if (build && Node.isPropertyAssignment(build)) {
|
|
54
|
-
const initializer = build.getInitializerOrThrow();
|
|
55
|
-
return normalizeContainerImage({ build: stringProperty(initializer, exportName, "image.build") });
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
throw diagnosticAt(expression, `container "${exportName}": \`image\` must be a static string path, { registry: "…" }, or { build: "…" } literal`);
|
|
59
|
-
};
|
|
60
|
-
const stringRecordLiteral = (expression) => {
|
|
61
|
-
if (!Node.isObjectLiteralExpression(expression)) {
|
|
62
|
-
return void 0;
|
|
63
|
-
}
|
|
64
|
-
const record = {};
|
|
65
|
-
for (const property of expression.getProperties()) {
|
|
66
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const value = property.getInitializerOrThrow();
|
|
70
|
-
if (Node.isStringLiteral(value) || Node.isNoSubstitutionTemplateLiteral(value)) {
|
|
71
|
-
record[property.getName()] = value.getLiteralValue();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return Object.keys(record).length > 0 ? record : void 0;
|
|
75
|
-
};
|
|
76
|
-
const rolloutLiteral = (expression) => {
|
|
77
|
-
if (!Node.isObjectLiteralExpression(expression)) {
|
|
78
|
-
return void 0;
|
|
79
|
-
}
|
|
80
|
-
const rollout = {};
|
|
81
|
-
for (const property of expression.getProperties()) {
|
|
82
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
const key = property.getName();
|
|
86
|
-
const value = property.getInitializerOrThrow();
|
|
87
|
-
if (Node.isNumericLiteral(value) && (key === "gracePeriodSeconds" || key === "stepPercentage")) {
|
|
88
|
-
rollout[key] = value.getLiteralValue();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return rollout.gracePeriodSeconds === void 0 && rollout.stepPercentage === void 0 ? void 0 : rollout;
|
|
92
|
-
};
|
|
93
|
-
const booleanLiteral = (expression) => {
|
|
94
|
-
if (Node.isTrueLiteral(expression)) {
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
if (Node.isFalseLiteral(expression)) {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
return void 0;
|
|
101
|
-
};
|
|
102
|
-
const stringOrNumberLiteral = (expression) => {
|
|
103
|
-
if (Node.isStringLiteral(expression) || Node.isNoSubstitutionTemplateLiteral(expression)) {
|
|
104
|
-
return expression.getLiteralValue();
|
|
105
|
-
}
|
|
106
|
-
if (Node.isNumericLiteral(expression)) {
|
|
107
|
-
return expression.getLiteralValue();
|
|
108
|
-
}
|
|
109
|
-
return void 0;
|
|
110
|
-
};
|
|
111
|
-
const instanceTypeFromExpression = (expression, exportName) => {
|
|
112
|
-
if (Node.isStringLiteral(expression)) {
|
|
113
|
-
return expression.getLiteralValue();
|
|
114
|
-
}
|
|
115
|
-
if (Node.isObjectLiteralExpression(expression)) {
|
|
116
|
-
const custom = {};
|
|
117
|
-
for (const property of expression.getProperties()) {
|
|
118
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
119
|
-
throw diagnosticAt(property, `container "${exportName}": \`instanceType\` must be an object of static number literals`);
|
|
120
|
-
}
|
|
121
|
-
const key = property.getName();
|
|
122
|
-
if (key !== "diskMb" && key !== "memoryMib" && key !== "vcpu") {
|
|
123
|
-
throw diagnosticAt(property, `container "${exportName}": unknown \`instanceType\` field "${key}" — expected vcpu, memoryMib, or diskMb`);
|
|
124
|
-
}
|
|
125
|
-
custom[key] = numberProperty(property.getInitializerOrThrow(), exportName, `instanceType.${key}`);
|
|
126
|
-
}
|
|
127
|
-
return custom;
|
|
128
|
-
}
|
|
129
|
-
throw diagnosticAt(expression, `container "${exportName}": \`instanceType\` must be a static string or { vcpu, memoryMib, diskMb } literal`);
|
|
130
|
-
};
|
|
131
|
-
const containerFromCall = (call, exportName) => {
|
|
132
|
-
const argument = call.getArguments()[0];
|
|
133
|
-
if (!argument || !Node.isObjectLiteralExpression(argument)) {
|
|
134
|
-
throw diagnosticAt(call, `container "${exportName}": defineContainer must be passed an inline object literal`);
|
|
135
|
-
}
|
|
136
|
-
const ir = {
|
|
137
|
-
bindingName: containerBindingName(exportName),
|
|
138
|
-
className: containerClassName(exportName),
|
|
139
|
-
exportName,
|
|
140
|
-
image: { buildContext: ".", dockerfilePath: "./Dockerfile", kind: "dockerfile" }
|
|
141
|
-
};
|
|
142
|
-
let sawImage = false;
|
|
143
|
-
for (const property of argument.getProperties()) {
|
|
144
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
const key = property.getName();
|
|
148
|
-
const initializer = property.getInitializerOrThrow();
|
|
149
|
-
switch (key) {
|
|
150
|
-
case "buildArgs": {
|
|
151
|
-
ir.buildArgs = stringRecordLiteral(initializer);
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
case "enableInternet": {
|
|
155
|
-
ir.enableInternet = booleanLiteral(initializer);
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
case "image": {
|
|
159
|
-
ir.image = imageFromExpression(initializer, exportName);
|
|
160
|
-
sawImage = true;
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
case "instanceType": {
|
|
164
|
-
ir.instanceType = instanceTypeFromExpression(initializer, exportName);
|
|
165
|
-
break;
|
|
166
|
-
}
|
|
167
|
-
case "maxInstances": {
|
|
168
|
-
ir.maxInstances = numberProperty(initializer, exportName, "maxInstances");
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
case "name": {
|
|
172
|
-
ir.name = stringProperty(initializer, exportName, "name");
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
case "rollout": {
|
|
176
|
-
ir.rollout = rolloutLiteral(initializer);
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
case "sleepAfter": {
|
|
180
|
-
ir.sleepAfter = stringOrNumberLiteral(initializer);
|
|
181
|
-
break;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (!sawImage) {
|
|
186
|
-
throw diagnosticAt(argument, `container "${exportName}": defineContainer requires a static \`image\` property`);
|
|
187
|
-
}
|
|
188
|
-
return ir;
|
|
189
|
-
};
|
|
190
|
-
const containersFromSource = (source) => {
|
|
191
|
-
const containers = [];
|
|
192
|
-
for (const declaration of source.getVariableDeclarations()) {
|
|
193
|
-
if (!declaration.isExported()) {
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
const initializer = declaration.getInitializer();
|
|
197
|
-
if (initializer?.getKind() !== SyntaxKind.CallExpression) {
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
const call = initializer;
|
|
201
|
-
const callee = call.getExpression();
|
|
202
|
-
if (!Node.isIdentifier(callee) || !isDefineContainer(callee)) {
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
const nameNode = declaration.getNameNode();
|
|
206
|
-
if (!Node.isIdentifier(nameNode)) {
|
|
207
|
-
throw diagnosticAt(nameNode, "defineContainer exports must be plain named exports (no destructuring)");
|
|
208
|
-
}
|
|
209
|
-
containers.push(containerFromCall(call, nameNode.getText()));
|
|
210
|
-
}
|
|
211
|
-
return containers;
|
|
212
|
-
};
|
|
213
|
-
const discoverContainers = (project, lunoraDirectory) => {
|
|
214
|
-
const containersPath = join(lunoraDirectory, CONTAINERS_FILENAME);
|
|
215
|
-
if (!existsSync(containersPath)) {
|
|
216
|
-
return [];
|
|
217
|
-
}
|
|
218
|
-
const source = project.getSourceFile(containersPath) ?? project.addSourceFileAtPath(containersPath);
|
|
219
|
-
const containers = containersFromSource(source);
|
|
220
|
-
containers.sort((a, b) => a.exportName.localeCompare(b.exportName));
|
|
221
|
-
return containers;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
export { CONTAINERS_FILENAME, discoverContainers };
|