@lunora/codegen 1.0.0-alpha.45 → 1.0.0-alpha.47
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 +1217 -1297
- package/dist/index.d.ts +1217 -1297
- package/dist/index.mjs +9 -8
- package/dist/packem_shared/{AGENTS_FILENAME-BksnAJgx.mjs → AGENTS_FILENAME-Cxx7wiSs.mjs} +46 -4
- package/dist/packem_shared/{GENERATED_HEADER-CBFi_PqS.mjs → GENERATED_HEADER-81zst6_8.mjs} +1 -1
- package/dist/packem_shared/{OPENRPC_VERSION-BdFITigK.mjs → OPENRPC_VERSION-5mpS55nb.mjs} +1 -1
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_FILENAME-CCsVXrsN.mjs → SCHEMA_SNAPSHOT_FILENAME-Dx31MtBY.mjs} +47 -42
- package/dist/packem_shared/{WORKFLOWS_FILENAME-B2By8S4s.mjs → WORKFLOWS_FILENAME-Dtuzvluc.mjs} +10 -4
- package/dist/packem_shared/{buildOpenApiDocument-D0MBRHyR.mjs → buildOpenApiDocument-Cv4Mg1kd.mjs} +1 -1
- package/dist/packem_shared/{discoverCrons-_aosTRLr.mjs → discoverCrons-DvqkEWdx.mjs} +17 -2
- package/dist/packem_shared/discoverSandboxUsage-BUM2r90k.mjs +38 -0
- package/dist/packem_shared/{emit-Dyzron8Q.mjs → emit-CpcoK10Y.mjs} +64 -53
- package/dist/packem_shared/{emitApp-D5-NY844.mjs → emitApp-DknqEU1p.mjs} +1 -1
- package/package.json +9 -9
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { formatAdvisories, lintSchema } from './packem_shared/formatAdvisories-BmF7Mplc.mjs';
|
|
2
2
|
export { CodegenDiagnosticError, diagnosticAt } from './packem_shared/CodegenDiagnosticError-DyQ5FwkM.mjs';
|
|
3
|
-
export { AGENTS_FILENAME, discoverAgents } from './packem_shared/AGENTS_FILENAME-
|
|
3
|
+
export { AGENTS_FILENAME, discoverAgents } from './packem_shared/AGENTS_FILENAME-Cxx7wiSs.mjs';
|
|
4
4
|
export { default as discoverAuthApiCalls } from './packem_shared/discoverAuthApiCalls-Dx3K42rk.mjs';
|
|
5
5
|
export { CONTAINERS_FILENAME, discoverContainers } from './packem_shared/CONTAINERS_FILENAME-DjpXMqhp.mjs';
|
|
6
|
-
export { default as discoverCrons } from './packem_shared/discoverCrons-
|
|
6
|
+
export { default as discoverCrons } from './packem_shared/discoverCrons-DvqkEWdx.mjs';
|
|
7
7
|
export { FLAGS_FILENAME, discoverFlags } from './packem_shared/FLAGS_FILENAME-Dg4mKUuz.mjs';
|
|
8
8
|
export { discoverFunctions } from './packem_shared/discoverFunctions-BJ-qR7Rg.mjs';
|
|
9
9
|
export { default as discoverHttpRoutes } from './packem_shared/discoverHttpRoutes-daCzuTe8.mjs';
|
|
@@ -16,15 +16,16 @@ export { default as discoverQueries } from './packem_shared/discoverQueries-CJnn
|
|
|
16
16
|
export { QUEUES_FILENAME, discoverQueues } from './packem_shared/QUEUES_FILENAME-Xv6Vy-Ku.mjs';
|
|
17
17
|
export { default as discoverR2sqlCalls } from './packem_shared/discoverR2sqlCalls-pnpicWfz.mjs';
|
|
18
18
|
export { discoverRlsMetadata, default as discoverRlsProcedures } from './packem_shared/discoverRlsMetadata-DppniPUH.mjs';
|
|
19
|
+
export { discoverSandboxUsage } from './packem_shared/discoverSandboxUsage-BUM2r90k.mjs';
|
|
19
20
|
export { default as discoverSchema } from './packem_shared/discoverSchema-BaSAvooG.mjs';
|
|
20
21
|
export { SHAPES_FILENAME, discoverShapes } from './packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs';
|
|
21
22
|
export { default as discoverStorageRulesMetadata } from './packem_shared/discoverStorageRulesMetadata-CnHl2rXD.mjs';
|
|
22
|
-
export { WORKFLOWS_FILENAME, discoverWorkflows } from './packem_shared/WORKFLOWS_FILENAME-
|
|
23
|
-
export { G as GENERATED_HEADER, e as emitAgents, a as emitApi, b as emitCollections, c as emitContainers, d as emitCrons, f as emitDataModel, g as emitDrizzleSchema, h as emitFunctions, i as emitServer, j as emitShard, k as emitVectors, l as emitWorkflows, m as emitWranglerCronTriggers } from './packem_shared/emit-
|
|
24
|
-
export { emitApp } from './packem_shared/emitApp-
|
|
25
|
-
export { buildOpenApiDocument, emitOpenApi, emitOpenApiModule } from './packem_shared/buildOpenApiDocument-
|
|
26
|
-
export { OPENRPC_VERSION, buildOpenRpcDocument, emitOpenRpc, emitOpenRpcModule } from './packem_shared/OPENRPC_VERSION-
|
|
27
|
-
export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-
|
|
23
|
+
export { WORKFLOWS_FILENAME, discoverWorkflows } from './packem_shared/WORKFLOWS_FILENAME-Dtuzvluc.mjs';
|
|
24
|
+
export { G as GENERATED_HEADER, e as emitAgents, a as emitApi, b as emitCollections, c as emitContainers, d as emitCrons, f as emitDataModel, g as emitDrizzleSchema, h as emitFunctions, i as emitServer, j as emitShard, k as emitVectors, l as emitWorkflows, m as emitWranglerCronTriggers } from './packem_shared/emit-CpcoK10Y.mjs';
|
|
25
|
+
export { emitApp } from './packem_shared/emitApp-DknqEU1p.mjs';
|
|
26
|
+
export { buildOpenApiDocument, emitOpenApi, emitOpenApiModule } from './packem_shared/buildOpenApiDocument-Cv4Mg1kd.mjs';
|
|
27
|
+
export { OPENRPC_VERSION, buildOpenRpcDocument, emitOpenRpc, emitOpenRpcModule } from './packem_shared/OPENRPC_VERSION-5mpS55nb.mjs';
|
|
28
|
+
export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-Dx31MtBY.mjs';
|
|
28
29
|
export { SCHEMA_SNAPSHOT_VERSION, SchemaSnapshotParseError, buildSchemaSnapshot, diffSchemaSnapshots, evaluateSchemaDrift, parseSchemaSnapshot, serializeSchemaSnapshot } from './packem_shared/SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs';
|
|
29
30
|
export { schemaFromIr } from './packem_shared/schemaFromIr-DTYsLBaA.mjs';
|
|
30
31
|
export { LUNORA_ERROR_CODES, validatorIrToJsonSchema } from './packem_shared/LUNORA_ERROR_CODES-DvTLozCu.mjs';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { agentDefaultName, agentClassName, agentBindingName, voiceBindingName, voiceClassName } from '@lunora/agent/naming';
|
|
4
|
-
import {
|
|
4
|
+
import { LunoraError } from '@lunora/errors';
|
|
5
|
+
import { Node, SyntaxKind } from 'ts-morph';
|
|
5
6
|
import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
|
|
6
7
|
|
|
7
8
|
const AGENTS_FILENAME = "agents.ts";
|
|
@@ -79,17 +80,23 @@ const agentFromCall = (call, exportName) => {
|
|
|
79
80
|
}
|
|
80
81
|
return ir;
|
|
81
82
|
};
|
|
83
|
+
const unwrapToCallExpression = (node) => {
|
|
84
|
+
let current = node;
|
|
85
|
+
while (current && (Node.isAsExpression(current) || Node.isSatisfiesExpression(current) || Node.isParenthesizedExpression(current))) {
|
|
86
|
+
current = current.getExpression();
|
|
87
|
+
}
|
|
88
|
+
return current && Node.isCallExpression(current) ? current : void 0;
|
|
89
|
+
};
|
|
82
90
|
const agentsFromSource = (source) => {
|
|
83
91
|
const agents = [];
|
|
84
92
|
for (const declaration of source.getVariableDeclarations()) {
|
|
85
93
|
if (!declaration.isExported()) {
|
|
86
94
|
continue;
|
|
87
95
|
}
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
96
|
+
const call = unwrapToCallExpression(declaration.getInitializer());
|
|
97
|
+
if (!call) {
|
|
90
98
|
continue;
|
|
91
99
|
}
|
|
92
|
-
const call = initializer;
|
|
93
100
|
const callee = call.getExpression();
|
|
94
101
|
if (!Node.isIdentifier(callee) || !isDefineAgent(callee)) {
|
|
95
102
|
continue;
|
|
@@ -102,6 +109,40 @@ const agentsFromSource = (source) => {
|
|
|
102
109
|
}
|
|
103
110
|
return agents;
|
|
104
111
|
};
|
|
112
|
+
const assertUniqueNames = (agents) => {
|
|
113
|
+
const seenNames = /* @__PURE__ */ new Map();
|
|
114
|
+
const seenBindings = /* @__PURE__ */ new Map();
|
|
115
|
+
const seenClasses = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const agent of agents) {
|
|
117
|
+
const priorName = seenNames.get(agent.name);
|
|
118
|
+
if (priorName !== void 0) {
|
|
119
|
+
throw new LunoraError(
|
|
120
|
+
"DUPLICATE_AGENT_NAME",
|
|
121
|
+
`Duplicate agent name "${agent.name}": produced by both "${priorName}" and "${agent.exportName}". Deployed agent names must be unique across the project.`,
|
|
122
|
+
{ status: 500 }
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
seenNames.set(agent.name, agent.exportName);
|
|
126
|
+
const priorBinding = seenBindings.get(agent.bindingName);
|
|
127
|
+
if (priorBinding !== void 0) {
|
|
128
|
+
throw new LunoraError(
|
|
129
|
+
"DUPLICATE_AGENT_BINDING",
|
|
130
|
+
`Duplicate agent binding "${agent.bindingName}": produced by both "${priorBinding}" and "${agent.exportName}". Agent export names must yield unique binding names.`,
|
|
131
|
+
{ status: 500 }
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
seenBindings.set(agent.bindingName, agent.exportName);
|
|
135
|
+
const priorClass = seenClasses.get(agent.className);
|
|
136
|
+
if (priorClass !== void 0) {
|
|
137
|
+
throw new LunoraError(
|
|
138
|
+
"DUPLICATE_AGENT_CLASS",
|
|
139
|
+
`Duplicate agent class "${agent.className}": produced by both "${priorClass}" and "${agent.exportName}". Agent export names must yield unique generated class names.`,
|
|
140
|
+
{ status: 500 }
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
seenClasses.set(agent.className, agent.exportName);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
105
146
|
const discoverAgents = (project, lunoraDirectory) => {
|
|
106
147
|
const agentsPath = join(lunoraDirectory, AGENTS_FILENAME);
|
|
107
148
|
if (!existsSync(agentsPath)) {
|
|
@@ -110,6 +151,7 @@ const discoverAgents = (project, lunoraDirectory) => {
|
|
|
110
151
|
const source = project.getSourceFile(agentsPath) ?? project.addSourceFileAtPath(agentsPath);
|
|
111
152
|
const agents = agentsFromSource(source);
|
|
112
153
|
agents.sort((a, b) => a.exportName.localeCompare(b.exportName));
|
|
154
|
+
assertUniqueNames(agents);
|
|
113
155
|
return agents;
|
|
114
156
|
};
|
|
115
157
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import '@lunora/agent/component';
|
|
2
2
|
import '@lunora/errors';
|
|
3
|
-
export { G as GENERATED_HEADER, n as buildStorageColumns, e as emitAgents, a as emitApi, b as emitCollections, c as emitContainers, d as emitCrons, f as emitDataModel, g as emitDrizzleSchema, h as emitFunctions, o as emitQueues, p as emitSeed, i as emitServer, j as emitShard, k as emitVectors, l as emitWorkflows, m as emitWranglerCronTriggers } from './emit-
|
|
3
|
+
export { G as GENERATED_HEADER, n as buildStorageColumns, e as emitAgents, a as emitApi, b as emitCollections, c as emitContainers, d as emitCrons, f as emitDataModel, g as emitDrizzleSchema, h as emitFunctions, o as emitQueues, p as emitSeed, i as emitServer, j as emitShard, k as emitVectors, l as emitWorkflows, m as emitWranglerCronTriggers } from './emit-CpcoK10Y.mjs';
|
|
4
4
|
import './paths-BRd6JHuF.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GENERATED_HEADER } from './emit-
|
|
1
|
+
import { G as GENERATED_HEADER } from './emit-CpcoK10Y.mjs';
|
|
2
2
|
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
3
3
|
import { argsObjectSchema, LUNORA_ERROR_CODES } from './LUNORA_ERROR_CODES-DvTLozCu.mjs';
|
|
4
4
|
|
|
@@ -5,12 +5,12 @@ import { LunoraError } from '@lunora/errors';
|
|
|
5
5
|
import { Node, SyntaxKind, Project } from 'ts-morph';
|
|
6
6
|
import { lintSchema } from './formatAdvisories-BmF7Mplc.mjs';
|
|
7
7
|
import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall, inlineHandler as inlineHandler$1, procedureHandler, chainUsesWrappedCall, isDatabaseAccessor, chainHasStep, discoverFunctions } from './discoverFunctions-BJ-qR7Rg.mjs';
|
|
8
|
-
import { discoverAgents } from './AGENTS_FILENAME-
|
|
8
|
+
import { discoverAgents } from './AGENTS_FILENAME-Cxx7wiSs.mjs';
|
|
9
9
|
import discoverAuthApiCalls from './discoverAuthApiCalls-Dx3K42rk.mjs';
|
|
10
10
|
import { discoverContainers } from './CONTAINERS_FILENAME-DjpXMqhp.mjs';
|
|
11
|
-
import discoverCrons from './discoverCrons-
|
|
11
|
+
import discoverCrons from './discoverCrons-DvqkEWdx.mjs';
|
|
12
12
|
import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
|
|
13
|
-
import { C as CAPABILITIES, n as buildStorageColumns, f as emitDataModel, a as emitApi, i as emitServer, h as emitFunctions, j as emitShard, b as emitCollections, c as emitContainers, l as emitWorkflows, e as emitAgents, o as emitQueues, d as emitCrons, k as emitVectors, g as emitDrizzleSchema, p as emitSeed, m as emitWranglerCronTriggers } from './emit-
|
|
13
|
+
import { C as CAPABILITIES, n as buildStorageColumns, f as emitDataModel, a as emitApi, i as emitServer, h as emitFunctions, j as emitShard, b as emitCollections, c as emitContainers, l as emitWorkflows, e as emitAgents, o as emitQueues, d as emitCrons, k as emitVectors, g as emitDrizzleSchema, p as emitSeed, m as emitWranglerCronTriggers } from './emit-CpcoK10Y.mjs';
|
|
14
14
|
import { discoverFlagKeys } from './FLAGS_FILENAME-Dg4mKUuz.mjs';
|
|
15
15
|
import discoverHttpRoutes from './discoverHttpRoutes-daCzuTe8.mjs';
|
|
16
16
|
import discoverInserts from './discoverInserts-DI4q5NxE.mjs';
|
|
@@ -22,15 +22,16 @@ import discoverQueries from './discoverQueries-CJnnnLpd.mjs';
|
|
|
22
22
|
import { discoverQueues } from './QUEUES_FILENAME-Xv6Vy-Ku.mjs';
|
|
23
23
|
import discoverR2sqlCalls from './discoverR2sqlCalls-pnpicWfz.mjs';
|
|
24
24
|
import discoverRlsProcedures, { discoverRlsMetadata } from './discoverRlsMetadata-DppniPUH.mjs';
|
|
25
|
+
import { discoverSandboxUsage } from './discoverSandboxUsage-BUM2r90k.mjs';
|
|
25
26
|
import discoverSchema from './discoverSchema-BaSAvooG.mjs';
|
|
26
27
|
import { secretKindOf, redact } from './redact-oTmsol5A.mjs';
|
|
27
28
|
import { discoverShapes } from './SHAPES_FILENAME-DOhPGi-6.mjs';
|
|
28
29
|
import discoverStorageRulesMetadata from './discoverStorageRulesMetadata-CnHl2rXD.mjs';
|
|
29
30
|
import { e as enclosingExportName$2 } from './discover-ast-CT6BgBr4.mjs';
|
|
30
|
-
import { discoverWorkflows } from './WORKFLOWS_FILENAME-
|
|
31
|
-
import { emitApp } from './emitApp-
|
|
32
|
-
import { buildOpenApiDocument, emitOpenApiModule } from './buildOpenApiDocument-
|
|
33
|
-
import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-
|
|
31
|
+
import { discoverWorkflows } from './WORKFLOWS_FILENAME-Dtuzvluc.mjs';
|
|
32
|
+
import { emitApp } from './emitApp-DknqEU1p.mjs';
|
|
33
|
+
import { buildOpenApiDocument, emitOpenApiModule } from './buildOpenApiDocument-Cv4Mg1kd.mjs';
|
|
34
|
+
import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-5mpS55nb.mjs';
|
|
34
35
|
import { buildSchemaSnapshot, serializeSchemaSnapshot } from './SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs';
|
|
35
36
|
|
|
36
37
|
const HTTP_VERBS$1 = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put"]);
|
|
@@ -2699,41 +2700,6 @@ const discoverRelationLoads = (project, lunoraDirectory) => {
|
|
|
2699
2700
|
return rows;
|
|
2700
2701
|
};
|
|
2701
2702
|
|
|
2702
|
-
const SANDBOX_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["@lunora/agent", "@lunora/agent/sandbox"]);
|
|
2703
|
-
const scanImportDeclaration = (declaration) => {
|
|
2704
|
-
const found = { usesSandboxBrowser: false, usesSandboxContainer: false };
|
|
2705
|
-
if (!SANDBOX_MODULE_SPECIFIERS.has(declaration.getModuleSpecifierValue()) || declaration.isTypeOnly()) {
|
|
2706
|
-
return found;
|
|
2707
|
-
}
|
|
2708
|
-
for (const named of declaration.getNamedImports()) {
|
|
2709
|
-
if (named.isTypeOnly()) {
|
|
2710
|
-
continue;
|
|
2711
|
-
}
|
|
2712
|
-
const name = named.getNameNode().getText();
|
|
2713
|
-
if (name === "browserTool") {
|
|
2714
|
-
found.usesSandboxBrowser = true;
|
|
2715
|
-
} else if (name === "containerTool") {
|
|
2716
|
-
found.usesSandboxContainer = true;
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
return found;
|
|
2720
|
-
};
|
|
2721
|
-
const discoverSandboxUsage = (project, lunoraDirectory) => {
|
|
2722
|
-
const usage = { usesSandboxBrowser: false, usesSandboxContainer: false };
|
|
2723
|
-
for (const filePath of listLunoraSourceFiles(lunoraDirectory)) {
|
|
2724
|
-
const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
|
|
2725
|
-
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
2726
|
-
const found = scanImportDeclaration(declaration);
|
|
2727
|
-
usage.usesSandboxBrowser ||= found.usesSandboxBrowser;
|
|
2728
|
-
usage.usesSandboxContainer ||= found.usesSandboxContainer;
|
|
2729
|
-
}
|
|
2730
|
-
if (usage.usesSandboxBrowser && usage.usesSandboxContainer) {
|
|
2731
|
-
break;
|
|
2732
|
-
}
|
|
2733
|
-
}
|
|
2734
|
-
return usage;
|
|
2735
|
-
};
|
|
2736
|
-
|
|
2737
2703
|
const literalValueOf = (node) => {
|
|
2738
2704
|
if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) {
|
|
2739
2705
|
return node.getLiteralText();
|
|
@@ -3155,6 +3121,44 @@ const findTsconfig = (startPath) => {
|
|
|
3155
3121
|
return void 0;
|
|
3156
3122
|
};
|
|
3157
3123
|
const toPosixPath = (path) => path.replaceAll("\\", "/");
|
|
3124
|
+
const assertNoWorkflowAgentCollision = (workflows, agents) => {
|
|
3125
|
+
const namesByLabel = /* @__PURE__ */ new Map();
|
|
3126
|
+
const bindingsByLabel = /* @__PURE__ */ new Map();
|
|
3127
|
+
const classesByLabel = /* @__PURE__ */ new Map();
|
|
3128
|
+
for (const workflow of workflows) {
|
|
3129
|
+
namesByLabel.set(workflow.name, `workflow "${workflow.exportName}"`);
|
|
3130
|
+
bindingsByLabel.set(workflow.bindingName, `workflow "${workflow.exportName}"`);
|
|
3131
|
+
classesByLabel.set(workflow.className, `workflow "${workflow.exportName}"`);
|
|
3132
|
+
}
|
|
3133
|
+
for (const agent of agents) {
|
|
3134
|
+
const priorName = namesByLabel.get(agent.name);
|
|
3135
|
+
if (priorName !== void 0) {
|
|
3136
|
+
throw new LunoraError(
|
|
3137
|
+
// eslint-disable-next-line no-secrets/no-secrets -- an error code, not a secret
|
|
3138
|
+
"DUPLICATE_WORKFLOW_NAME",
|
|
3139
|
+
`Duplicate deployed name "${agent.name}": produced by both ${priorName} and agent "${agent.exportName}". Workflow and agent names share the same wrangler workflows[] array and must be unique together.`,
|
|
3140
|
+
{ status: 500 }
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
3143
|
+
const priorBinding = bindingsByLabel.get(agent.bindingName);
|
|
3144
|
+
if (priorBinding !== void 0) {
|
|
3145
|
+
throw new LunoraError(
|
|
3146
|
+
// eslint-disable-next-line no-secrets/no-secrets -- an error code, not a secret
|
|
3147
|
+
"DUPLICATE_WORKFLOW_BINDING",
|
|
3148
|
+
`Duplicate binding "${agent.bindingName}": produced by both ${priorBinding} and agent "${agent.exportName}". Workflow and agent bindings share the same wrangler workflows[] array and must be unique together.`,
|
|
3149
|
+
{ status: 500 }
|
|
3150
|
+
);
|
|
3151
|
+
}
|
|
3152
|
+
const priorClass = classesByLabel.get(agent.className);
|
|
3153
|
+
if (priorClass !== void 0) {
|
|
3154
|
+
throw new LunoraError(
|
|
3155
|
+
"DUPLICATE_WORKFLOW_CLASS",
|
|
3156
|
+
`Duplicate generated class "${agent.className}": produced by both ${priorClass} and agent "${agent.exportName}". Workflow and agent export names must yield unique generated class names.`,
|
|
3157
|
+
{ status: 500 }
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
};
|
|
3158
3162
|
const createCodegenProject = (lunoraDirectory) => {
|
|
3159
3163
|
const tsconfigPath = findTsconfig(lunoraDirectory);
|
|
3160
3164
|
return tsconfigPath ? new Project({ skipAddingFilesFromTsConfig: false, tsConfigFilePath: tsconfigPath, useInMemoryFileSystem: false }) : new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
|
|
@@ -3203,6 +3207,7 @@ const runCodegen = (options) => {
|
|
|
3203
3207
|
const workflows = discoverWorkflows(project, lunoraDirectory);
|
|
3204
3208
|
const queues = discoverQueues(project, lunoraDirectory);
|
|
3205
3209
|
const agents = discoverAgents(project, lunoraDirectory);
|
|
3210
|
+
assertNoWorkflowAgentCollision(workflows, agents);
|
|
3206
3211
|
const crons = discoverCrons(project, lunoraDirectory, workflows, agents);
|
|
3207
3212
|
const containers = discoverContainers(project, lunoraDirectory);
|
|
3208
3213
|
const advisories = options.lint === false ? [] : lintSchema({
|
package/dist/packem_shared/{WORKFLOWS_FILENAME-B2By8S4s.mjs → WORKFLOWS_FILENAME-Dtuzvluc.mjs}
RENAMED
|
@@ -2,7 +2,7 @@ import { existsSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { LunoraError } from '@lunora/errors';
|
|
4
4
|
import { workflowDefaultName, workflowClassName, workflowBindingName } from '@lunora/workflow';
|
|
5
|
-
import {
|
|
5
|
+
import { Node, SyntaxKind } from 'ts-morph';
|
|
6
6
|
import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
|
|
7
7
|
|
|
8
8
|
const WORKFLOWS_FILENAME = "workflows.ts";
|
|
@@ -88,17 +88,23 @@ const workflowFromCall = (call, exportName) => {
|
|
|
88
88
|
}
|
|
89
89
|
return ir;
|
|
90
90
|
};
|
|
91
|
+
const unwrapToCallExpression = (node) => {
|
|
92
|
+
let current = node;
|
|
93
|
+
while (current && (Node.isAsExpression(current) || Node.isSatisfiesExpression(current) || Node.isParenthesizedExpression(current))) {
|
|
94
|
+
current = current.getExpression();
|
|
95
|
+
}
|
|
96
|
+
return current && Node.isCallExpression(current) ? current : void 0;
|
|
97
|
+
};
|
|
91
98
|
const workflowsFromSource = (source) => {
|
|
92
99
|
const workflows = [];
|
|
93
100
|
for (const declaration of source.getVariableDeclarations()) {
|
|
94
101
|
if (!declaration.isExported()) {
|
|
95
102
|
continue;
|
|
96
103
|
}
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
104
|
+
const call = unwrapToCallExpression(declaration.getInitializer());
|
|
105
|
+
if (!call) {
|
|
99
106
|
continue;
|
|
100
107
|
}
|
|
101
|
-
const call = initializer;
|
|
102
108
|
const callee = call.getExpression();
|
|
103
109
|
if (!Node.isIdentifier(callee) || !isDefineWorkflow(callee)) {
|
|
104
110
|
continue;
|
package/dist/packem_shared/{buildOpenApiDocument-D0MBRHyR.mjs → buildOpenApiDocument-Cv4Mg1kd.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GENERATED_HEADER } from './emit-
|
|
1
|
+
import { G as GENERATED_HEADER } from './emit-CpcoK10Y.mjs';
|
|
2
2
|
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
3
3
|
import { LUNORA_ERROR_CODES, objectSchema, argsObjectSchema, validatorIrToJsonSchema } from './LUNORA_ERROR_CODES-DvTLozCu.mjs';
|
|
4
4
|
|
|
@@ -46,7 +46,7 @@ const rootIdentifierOf = (node) => {
|
|
|
46
46
|
};
|
|
47
47
|
const stringArgument = (call, index) => {
|
|
48
48
|
const argument = call.getArguments()[index];
|
|
49
|
-
return argument && Node.isStringLiteral(argument) ? argument.getLiteralValue() : void 0;
|
|
49
|
+
return argument && (Node.isStringLiteral(argument) || Node.isNoSubstitutionTemplateLiteral(argument)) ? argument.getLiteralValue() : void 0;
|
|
50
50
|
};
|
|
51
51
|
const literalValue = (node, jobName) => {
|
|
52
52
|
if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) {
|
|
@@ -165,12 +165,27 @@ const resolveTarget = (call, index, jobName, workflowsByName, agentsByName) => {
|
|
|
165
165
|
}
|
|
166
166
|
if (argument && Node.isIdentifier(argument)) {
|
|
167
167
|
const workflow = workflowsByName.get(argument.getText());
|
|
168
|
+
const agent = agentsByName.get(argument.getText());
|
|
169
|
+
if (workflow && agent) {
|
|
170
|
+
throw diagnosticAt(
|
|
171
|
+
argument,
|
|
172
|
+
`Cron job "${jobName}" references "${argument.getText()}", which is ambiguous: a workflow and an agent are both declared under that name.`,
|
|
173
|
+
{
|
|
174
|
+
code: "CRON_NON_STATIC_FN",
|
|
175
|
+
name: "LunoraError",
|
|
176
|
+
status: 500
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
}
|
|
168
180
|
if (workflow) {
|
|
169
181
|
return workflowTarget(workflow);
|
|
170
182
|
}
|
|
183
|
+
if (agent) {
|
|
184
|
+
return agentTarget(agent);
|
|
185
|
+
}
|
|
171
186
|
throw diagnosticAt(
|
|
172
187
|
argument,
|
|
173
|
-
`Cron job "${jobName}" references "${argument.getText()}", which is neither a function (internal.file.fn / api.file.fn) nor a declared workflow in lunora/workflows.ts.`,
|
|
188
|
+
`Cron job "${jobName}" references "${argument.getText()}", which is neither a function (internal.file.fn / api.file.fn) nor a declared workflow in lunora/workflows.ts nor a declared agent in lunora/agents.ts.`,
|
|
174
189
|
{
|
|
175
190
|
code: "CRON_NON_STATIC_FN",
|
|
176
191
|
name: "LunoraError",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { listLunoraSourceFiles } from './discoverFunctions-BJ-qR7Rg.mjs';
|
|
2
|
+
|
|
3
|
+
const SANDBOX_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["@lunora/agent", "@lunora/agent/sandbox"]);
|
|
4
|
+
const scanImportDeclaration = (declaration) => {
|
|
5
|
+
const found = { usesSandboxBrowser: false, usesSandboxContainer: false };
|
|
6
|
+
if (!SANDBOX_MODULE_SPECIFIERS.has(declaration.getModuleSpecifierValue()) || declaration.isTypeOnly()) {
|
|
7
|
+
return found;
|
|
8
|
+
}
|
|
9
|
+
for (const named of declaration.getNamedImports()) {
|
|
10
|
+
if (named.isTypeOnly()) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const name = named.getNameNode().getText();
|
|
14
|
+
if (name === "browserTool") {
|
|
15
|
+
found.usesSandboxBrowser = true;
|
|
16
|
+
} else if (name === "containerTool") {
|
|
17
|
+
found.usesSandboxContainer = true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return found;
|
|
21
|
+
};
|
|
22
|
+
const discoverSandboxUsage = (project, lunoraDirectory) => {
|
|
23
|
+
const usage = { usesSandboxBrowser: false, usesSandboxContainer: false };
|
|
24
|
+
for (const filePath of listLunoraSourceFiles(lunoraDirectory)) {
|
|
25
|
+
const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
|
|
26
|
+
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
27
|
+
const found = scanImportDeclaration(declaration);
|
|
28
|
+
usage.usesSandboxBrowser ||= found.usesSandboxBrowser;
|
|
29
|
+
usage.usesSandboxContainer ||= found.usesSandboxContainer;
|
|
30
|
+
}
|
|
31
|
+
if (usage.usesSandboxBrowser && usage.usesSandboxContainer) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return usage;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export { discoverSandboxUsage };
|
|
@@ -760,12 +760,23 @@ ${objectMembers}
|
|
|
760
760
|
};
|
|
761
761
|
const agentRuntimeFunctionNames = () => Object.keys(agentComponent().functions).toSorted((a, b) => a.localeCompare(b));
|
|
762
762
|
const takenAgentFunctionNames = (functions) => new Set(functions.filter((definition) => sanitizeNamespace(definition.filePath) === "agents").map((definition) => definition.exportName));
|
|
763
|
+
const internalAgentRuntimeFunctionNames = () => new Set(
|
|
764
|
+
Object.entries(agentComponent().functions).filter(([, definition]) => definition.visibility === "internal").map(([name]) => name)
|
|
765
|
+
);
|
|
763
766
|
const renderAgentFunctionRegistry = (agents, functions) => {
|
|
764
767
|
const empty = { importLine: "", lines: "", prelude: "" };
|
|
765
768
|
if (agents.length === 0) {
|
|
766
769
|
return empty;
|
|
767
770
|
}
|
|
768
771
|
const taken = takenAgentFunctionNames(functions);
|
|
772
|
+
const internal = internalAgentRuntimeFunctionNames();
|
|
773
|
+
const shadowedInternal = functions.find((definition) => sanitizeNamespace(definition.filePath) === "agents" && internal.has(definition.exportName));
|
|
774
|
+
if (shadowedInternal) {
|
|
775
|
+
throw new LunoraError(
|
|
776
|
+
"INTERNAL",
|
|
777
|
+
`@lunora/codegen: "agents:${shadowedInternal.exportName}" is reserved for the durable agent loop's internal dispatch — rename the "${shadowedInternal.exportName}" export in ${shadowedInternal.filePath}`
|
|
778
|
+
);
|
|
779
|
+
}
|
|
769
780
|
const names = agentRuntimeFunctionNames().filter((name) => !taken.has(name));
|
|
770
781
|
if (names.length === 0) {
|
|
771
782
|
return empty;
|
|
@@ -2875,14 +2886,14 @@ const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
|
|
|
2875
2886
|
const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
2876
2887
|
` : "";
|
|
2877
2888
|
const externalSourceOverride = hasSourcedTables ? `
|
|
2878
|
-
protected override async pollExternalSources(): Promise<number> {
|
|
2889
|
+
protected override async pollExternalSources(): Promise<number | undefined> {
|
|
2879
2890
|
const env = (this.env ?? {}) as Record<string, unknown>;
|
|
2880
2891
|
const sourced = Object.entries((schema as unknown as SchemaLike).tables)
|
|
2881
2892
|
.map(([table, definition]) => [table, (definition as { externalSource?: ExternalSourceLike }).externalSource] as const)
|
|
2882
2893
|
.filter((entry): entry is [string, ExternalSourceLike] => entry[1] !== undefined);
|
|
2883
2894
|
|
|
2884
2895
|
if (sourced.length === 0) {
|
|
2885
|
-
return
|
|
2896
|
+
return undefined;
|
|
2886
2897
|
}
|
|
2887
2898
|
|
|
2888
2899
|
const shardKey = this.currentShardKey();
|
|
@@ -2912,62 +2923,68 @@ const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
|
2912
2923
|
}
|
|
2913
2924
|
|
|
2914
2925
|
const now = Date.now();
|
|
2915
|
-
// \`
|
|
2916
|
-
// manual
|
|
2917
|
-
|
|
2926
|
+
// \`nextDueAt\` tracks the EARLIEST next-due timestamp across every
|
|
2927
|
+
// non-manual source; the shared alarm re-arms there instead of the
|
|
2928
|
+
// fixed 2 s global-shape floor, so a large \`refresh.everyMs\` actually
|
|
2929
|
+
// sleeps until it's due. Stays \`undefined\` when every source is
|
|
2930
|
+
// \`refresh: "manual"\`, so the shared alarm goes idle for this tier.
|
|
2931
|
+
let nextDueAt: number | undefined;
|
|
2918
2932
|
|
|
2919
2933
|
for (const [table, source] of sourced) {
|
|
2920
2934
|
if (source.refresh === "manual") {
|
|
2921
2935
|
continue;
|
|
2922
2936
|
}
|
|
2923
2937
|
|
|
2924
|
-
|
|
2938
|
+
if (isSourceDue(source.refresh, polledAt.get(table), now)) {
|
|
2939
|
+
try {
|
|
2940
|
+
let client = clients.get(source.binding);
|
|
2925
2941
|
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
}
|
|
2942
|
+
if (client === undefined) {
|
|
2943
|
+
client = config.sourceClient?.(env, source.binding);
|
|
2929
2944
|
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
client = config.sourceClient?.(env, source.binding);
|
|
2945
|
+
if (client !== undefined) {
|
|
2946
|
+
clients.set(source.binding, client);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2935
2949
|
|
|
2936
|
-
if (client
|
|
2937
|
-
|
|
2950
|
+
if (client === undefined) {
|
|
2951
|
+
// No SqlClient resolved for this binding (host never wired
|
|
2952
|
+
// \`config.sourceClient\`, or wired it wrong). Surface it in the
|
|
2953
|
+
// Logs panel and stamp \`polledAt\` so a persistent misconfig backs
|
|
2954
|
+
// off to \`refresh.everyMs\` instead of retrying every alarm tick.
|
|
2955
|
+
this.recordExternalSourceError(table, new Error(\`external-source: no sourceClient resolved for binding "\${source.binding}"\`));
|
|
2956
|
+
} else if (source.mode === "incremental") {
|
|
2957
|
+
// Incremental (plan 136): pull only rows past the durable
|
|
2958
|
+
// watermark (or a full-pull seed/reconcile), upsert-only.
|
|
2959
|
+
// eslint-disable-next-line no-await-in-loop -- one sourced table at a time; sequential keeps the writer transaction simple
|
|
2960
|
+
await pullExternalSourceIncrementalTick(this.sql as SqlExec, writer, client, table, source, shardKey, now);
|
|
2961
|
+
} else {
|
|
2962
|
+
// eslint-disable-next-line no-await-in-loop -- one sourced table at a time; slices are independent but small and sequential keeps the writer transaction simple
|
|
2963
|
+
await pullExternalSourceTick(this.sql as SqlExec, writer, client, table, source, shardKey);
|
|
2938
2964
|
}
|
|
2939
|
-
}
|
|
2940
2965
|
|
|
2941
|
-
|
|
2942
|
-
//
|
|
2943
|
-
//
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
this.recordExternalSourceError(table,
|
|
2947
|
-
|
|
2948
|
-
|
|
2966
|
+
// Timestamp AFTER the poll finishes, not the batch-start \`now\` — a
|
|
2967
|
+
// poll that outruns \`everyMs\` must not make \`nextDueAt\` (below)
|
|
2968
|
+
// stale-immediate and re-arm the alarm in a hammering loop.
|
|
2969
|
+
polledAt.set(table, Date.now());
|
|
2970
|
+
} catch (error) {
|
|
2971
|
+
this.recordExternalSourceError(table, error);
|
|
2972
|
+
// Stamp on failure too, so a persistently failing source throttles
|
|
2973
|
+
// to \`refresh.everyMs\` rather than being hammered every tick.
|
|
2974
|
+
polledAt.set(table, Date.now());
|
|
2949
2975
|
}
|
|
2976
|
+
}
|
|
2950
2977
|
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
} else {
|
|
2957
|
-
// eslint-disable-next-line no-await-in-loop -- one sourced table at a time; slices are independent but small and sequential keeps the writer transaction simple
|
|
2958
|
-
await pullExternalSourceTick(this.sql as SqlExec, writer, client, table, source, shardKey);
|
|
2959
|
-
}
|
|
2978
|
+
// This source's own next-due time, read AFTER the poll-or-skip above
|
|
2979
|
+
// so a just-polled source reports \`now + everyMs\` (its FRESH due
|
|
2980
|
+
// time), not the stale pre-poll one. An omitted \`refresh\` (poll
|
|
2981
|
+
// every tick) is due again immediately.
|
|
2982
|
+
const sourceNextDueAt = source.refresh === undefined ? now : (polledAt.get(table) ?? now) + source.refresh.everyMs;
|
|
2960
2983
|
|
|
2961
|
-
|
|
2962
|
-
} catch (error) {
|
|
2963
|
-
this.recordExternalSourceError(table, error);
|
|
2964
|
-
// Stamp on failure too, so a persistently failing source throttles
|
|
2965
|
-
// to \`refresh.everyMs\` rather than being hammered every tick.
|
|
2966
|
-
polledAt.set(table, now);
|
|
2967
|
-
}
|
|
2984
|
+
nextDueAt = nextDueAt === undefined ? sourceNextDueAt : Math.min(nextDueAt, sourceNextDueAt);
|
|
2968
2985
|
}
|
|
2969
2986
|
|
|
2970
|
-
return
|
|
2987
|
+
return nextDueAt;
|
|
2971
2988
|
}
|
|
2972
2989
|
` : "";
|
|
2973
2990
|
const sourceConstructorOverride = hasSourcedTables ? `
|
|
@@ -3479,19 +3496,13 @@ ${vectorsBuild}${aiBuild}${everyContextBuild}${containersBuild}${workflowsBuild}
|
|
|
3479
3496
|
const storage = asBucketStorage(config.storage?.(env) ?? storageStub) as unknown as SystemReaderStorageLike;
|
|
3480
3497
|
${globalDatabaseLine} const db: DatabaseWriterLike = createShardCtxDb(${databaseOptions});
|
|
3481
3498
|
${facadeBlock}${paymentsBuild}
|
|
3482
|
-
// \`ctx.log\`:
|
|
3483
|
-
//
|
|
3484
|
-
//
|
|
3485
|
-
// event the dev-server formats
|
|
3499
|
+
// \`ctx.log\`: the DO base builds the attributed logger (structured
|
|
3500
|
+
// fields + \`.with(...)\` child + trace correlation) and routes each call
|
|
3501
|
+
// to the optional \`observability\` sink. It also buffers the line (studio
|
|
3502
|
+
// Logs panel) and emits a structured console event the dev-server formats.
|
|
3486
3503
|
const observability = config.observability?.(env);
|
|
3487
3504
|
const logFunctionPath = options.functionPath ?? "";
|
|
3488
|
-
const log =
|
|
3489
|
-
debug: (...args: unknown[]) => { this.recordUserLog(logFunctionPath, "debug", args, observability); },
|
|
3490
|
-
error: (...args: unknown[]) => { this.recordUserLog(logFunctionPath, "error", args, observability); },
|
|
3491
|
-
info: (...args: unknown[]) => { this.recordUserLog(logFunctionPath, "info", args, observability); },
|
|
3492
|
-
log: (...args: unknown[]) => { this.recordUserLog(logFunctionPath, "log", args, observability); },
|
|
3493
|
-
warn: (...args: unknown[]) => { this.recordUserLog(logFunctionPath, "warn", args, observability); },
|
|
3494
|
-
};
|
|
3505
|
+
const log = this.makeLogger(logFunctionPath, observability);
|
|
3495
3506
|
|
|
3496
3507
|
// \`ctx.now\`: the wall-clock instant (epoch ms) this function began,
|
|
3497
3508
|
// captured ONCE so the whole handler body sees a single stable value.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as APP_METHOD_CAPABILITIES, G as GENERATED_HEADER } from './emit-
|
|
1
|
+
import { A as APP_METHOD_CAPABILITIES, G as GENERATED_HEADER } from './emit-CpcoK10Y.mjs';
|
|
2
2
|
|
|
3
3
|
const hasFlagKey = (key) => `has${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
4
4
|
const LONG_TAIL = APP_METHOD_CAPABILITIES.map(
|
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.47",
|
|
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,14 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/advisor": "1.0.0-alpha.
|
|
50
|
-
"@lunora/agent": "1.0.0-alpha.
|
|
51
|
-
"@lunora/container": "1.0.0-alpha.
|
|
52
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
53
|
-
"@lunora/queue": "1.0.0-alpha.
|
|
54
|
-
"@lunora/scheduler": "1.0.0-alpha.
|
|
55
|
-
"@lunora/values": "1.0.0-alpha.
|
|
56
|
-
"@lunora/workflow": "1.0.0-alpha.
|
|
49
|
+
"@lunora/advisor": "1.0.0-alpha.31",
|
|
50
|
+
"@lunora/agent": "1.0.0-alpha.5",
|
|
51
|
+
"@lunora/container": "1.0.0-alpha.13",
|
|
52
|
+
"@lunora/errors": "1.0.0-alpha.6",
|
|
53
|
+
"@lunora/queue": "1.0.0-alpha.9",
|
|
54
|
+
"@lunora/scheduler": "1.0.0-alpha.11",
|
|
55
|
+
"@lunora/values": "1.0.0-alpha.9",
|
|
56
|
+
"@lunora/workflow": "1.0.0-alpha.11",
|
|
57
57
|
"ts-morph": "^28.0.0"
|
|
58
58
|
},
|
|
59
59
|
"engines": {
|