@lunora/config 1.0.0-alpha.80 → 1.0.0-alpha.82

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.
Files changed (81) hide show
  1. package/dist/index.mjs +1 -30
  2. package/dist/packem_shared/ACCENT-CLeV5v0K.mjs +7 -0
  3. package/dist/packem_shared/AGENT_MODE_ENV-B54hVQ_w.mjs +1 -0
  4. package/dist/packem_shared/AGENT_RULES_DIR-hP9TiDNx.mjs +1 -0
  5. package/dist/packem_shared/DEV_DAEMON_ENV-D9Z83rlU.mjs +4 -0
  6. package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-DX6xGbpr.mjs +1 -0
  7. package/dist/packem_shared/LINKED_PROJECT_DIR-CMzUvj-1.mjs +2 -0
  8. package/dist/packem_shared/LUNORA_CONFIG_FILE-3bpx6TZN.mjs +1 -0
  9. package/dist/packem_shared/LUNORA_EVENT_SOURCE-ZclWASXS.mjs +1 -0
  10. package/dist/packem_shared/LunoraReporter-BnXUqh8t.mjs +6 -0
  11. package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-BgmvEPA-.mjs +1 -0
  12. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CUYWD0Mh.mjs +1 -0
  13. package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-ws6iE0y-.mjs +1 -0
  14. package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-DPcRuAhj.mjs +1 -0
  15. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-CZ8rSh2k.mjs +1 -0
  16. package/dist/packem_shared/SEED_ENDPOINT-BaYShU8q.mjs +1 -0
  17. package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-B1h_wNDN.mjs +1 -0
  18. package/dist/packem_shared/WRANGLER_FILES-Bi_18Pj6.mjs +1 -0
  19. package/dist/packem_shared/applyAdditiveEdit-BdcnSa-j.mjs +6 -0
  20. package/dist/packem_shared/assetContentType-DNZyUOuF.mjs +1 -0
  21. package/dist/packem_shared/buildPackageSecretsBlock-BpvaZzQ8.mjs +18 -0
  22. package/dist/packem_shared/classifyPolicyEdit-BzC_MfYK.mjs +24 -0
  23. package/dist/packem_shared/collectWranglerSecretVariables-OacEwPmL.mjs +1 -0
  24. package/dist/packem_shared/createConfirm-7IL0kZyE.mjs +7 -0
  25. package/dist/packem_shared/detectFramework-VTQfCNXy.mjs +1 -0
  26. package/dist/packem_shared/discoverAgentInfo-BJm0QtoI.mjs +1 -0
  27. package/dist/packem_shared/discoverContainerInfo-CYG9j2LY.mjs +1 -0
  28. package/dist/packem_shared/discoverSchemaInfo-B2W3VrcT.mjs +1 -0
  29. package/dist/packem_shared/discoverWorkflowInfo-Bbc0u2gE.mjs +1 -0
  30. package/dist/packem_shared/inferLunoraBindings-DWSabh1j.mjs +1 -0
  31. package/dist/packem_shared/jsonc-edit-BZVpxVA0.mjs +1 -0
  32. package/dist/packem_shared/parseDevVariable-NAVJ8tgA.mjs +1 -0
  33. package/dist/packem_shared/parseSchema-BPmtMgmb.mjs +1 -0
  34. package/dist/packem_shared/reconcileWranglerBindings-Dd3tLauZ.mjs +1 -0
  35. package/dist/packem_shared/reconcileWranglerCompatibilityDate-BXNiEQ7p.mjs +1 -0
  36. package/dist/packem_shared/reconcileWranglerCrons-BmQa_kGL.mjs +1 -0
  37. package/dist/packem_shared/renderStudioHtml-B2AkxcW1.mjs +15 -0
  38. package/dist/packem_shared/serveJsonHandler-C5GWlWJF.mjs +1 -0
  39. package/dist/packem_shared/streamContainerLogs-BPYBNrWS.mjs +2 -0
  40. package/dist/packem_shared/write-atomic-Cdr2oQb-.mjs +1 -0
  41. package/dist/studio-host/index.mjs +1 -7
  42. package/package.json +3 -3
  43. package/dist/packem_shared/ACCENT-DW1XJn8i.mjs +0 -40
  44. package/dist/packem_shared/AGENT_MODE_ENV-B5R7jpY7.mjs +0 -17
  45. package/dist/packem_shared/AGENT_RULES_DIR-lcgC08aE.mjs +0 -40
  46. package/dist/packem_shared/DEV_DAEMON_ENV-FIEtW7Fz.mjs +0 -163
  47. package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs +0 -37
  48. package/dist/packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs +0 -52
  49. package/dist/packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs +0 -34
  50. package/dist/packem_shared/LUNORA_EVENT_SOURCE-M1KM9_pR.mjs +0 -112
  51. package/dist/packem_shared/LunoraReporter-Ci-bDCK9.mjs +0 -70
  52. package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-NCTSphDk.mjs +0 -138
  53. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CvTZpaZF.mjs +0 -100
  54. package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-C-F_Flgy.mjs +0 -100
  55. package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-DP0SFVy9.mjs +0 -607
  56. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-Bt2SNkpV.mjs +0 -95
  57. package/dist/packem_shared/SEED_ENDPOINT-7izz_Jao.mjs +0 -61
  58. package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-CaXbS7CX.mjs +0 -11
  59. package/dist/packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs +0 -25
  60. package/dist/packem_shared/applyAdditiveEdit-C-snTFEV.mjs +0 -228
  61. package/dist/packem_shared/assetContentType-ByZjeV3D.mjs +0 -72
  62. package/dist/packem_shared/buildPackageSecretsBlock-BxOcyaAY.mjs +0 -281
  63. package/dist/packem_shared/classifyPolicyEdit-BHeAqF8P.mjs +0 -99
  64. package/dist/packem_shared/collectWranglerSecretVariables-BRWIvT-e.mjs +0 -56
  65. package/dist/packem_shared/createConfirm-BMikeJC9.mjs +0 -117
  66. package/dist/packem_shared/detectFramework-U08038Yp.mjs +0 -41
  67. package/dist/packem_shared/discoverAgentInfo-eXA3hF4v.mjs +0 -19
  68. package/dist/packem_shared/discoverContainerInfo-BXFs6Wav.mjs +0 -19
  69. package/dist/packem_shared/discoverSchemaInfo-BB-CKlTK.mjs +0 -25
  70. package/dist/packem_shared/discoverWorkflowInfo-CedvR0mn.mjs +0 -19
  71. package/dist/packem_shared/inferLunoraBindings-BcvvtpSG.mjs +0 -397
  72. package/dist/packem_shared/jsonc-edit-SbcD7MAe.mjs +0 -9
  73. package/dist/packem_shared/parseDevVariable-B0FEvfHC.mjs +0 -21
  74. package/dist/packem_shared/parseSchema-DSeyktvG.mjs +0 -107
  75. package/dist/packem_shared/reconcileWranglerBindings-2Cww5VLa.mjs +0 -362
  76. package/dist/packem_shared/reconcileWranglerCompatibilityDate-C8c497ag.mjs +0 -31
  77. package/dist/packem_shared/reconcileWranglerCrons-DvsceVFz.mjs +0 -29
  78. package/dist/packem_shared/renderStudioHtml-449Ysn75.mjs +0 -37
  79. package/dist/packem_shared/serveJsonHandler-Cl2Wqkv8.mjs +0 -86
  80. package/dist/packem_shared/streamContainerLogs-BZ4cOZwH.mjs +0 -157
  81. package/dist/packem_shared/write-atomic-B2REqapi.mjs +0 -14
@@ -1,19 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
- import { WORKFLOWS_FILENAME, discoverWorkflows } from '@lunora/codegen';
3
- import { Project } from 'ts-morph';
4
- import { join } from 'node:path';
5
-
6
- const discoverWorkflowInfo = (projectRoot, schemaDirectory) => {
7
- const workflowsPath = join(projectRoot, schemaDirectory, WORKFLOWS_FILENAME);
8
- if (!existsSync(workflowsPath)) {
9
- return { workflows: [] };
10
- }
11
- try {
12
- const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
13
- return { workflows: discoverWorkflows(project, join(projectRoot, schemaDirectory)) };
14
- } catch (error) {
15
- return { error: error instanceof Error ? error.message : String(error), workflows: [] };
16
- }
17
- };
18
-
19
- export { discoverWorkflowInfo };
@@ -1,397 +0,0 @@
1
- import { existsSync, statSync, readFileSync, readdirSync } from 'node:fs';
2
- import { init, parse } from 'es-module-lexer';
3
- import { discoverAgentInfo } from './discoverAgentInfo-eXA3hF4v.mjs';
4
- import { discoverContainerInfo } from './discoverContainerInfo-BXFs6Wav.mjs';
5
- import { FLAGS_FILENAME, discoverFlags, QUEUES_FILENAME, discoverQueues } from '@lunora/codegen';
6
- import { Project } from 'ts-morph';
7
- import { join } from 'node:path';
8
- import { discoverSchemaInfo } from './discoverSchemaInfo-BB-CKlTK.mjs';
9
- import { discoverWorkflowInfo } from './discoverWorkflowInfo-CedvR0mn.mjs';
10
- import { WRANGLER_FILES, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
11
-
12
- const discoverFlagsInfo = (projectRoot, schemaDirectory) => {
13
- const flagsPath = join(projectRoot, schemaDirectory, FLAGS_FILENAME);
14
- if (!existsSync(flagsPath)) {
15
- return {};
16
- }
17
- try {
18
- const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
19
- return { flags: discoverFlags(project, join(projectRoot, schemaDirectory)) };
20
- } catch (error) {
21
- return { error: error instanceof Error ? error.message : String(error) };
22
- }
23
- };
24
-
25
- const discoverQueueInfo = (projectRoot, schemaDirectory) => {
26
- const queuesPath = join(projectRoot, schemaDirectory, QUEUES_FILENAME);
27
- if (!existsSync(queuesPath)) {
28
- return { queues: [] };
29
- }
30
- try {
31
- const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
32
- return { queues: discoverQueues(project, join(projectRoot, schemaDirectory)) };
33
- } catch (error) {
34
- return { error: error instanceof Error ? error.message : String(error), queues: [] };
35
- }
36
- };
37
-
38
- const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".jsx", ".mjs", ".mts", ".ts", ".tsx"]);
39
- const IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([".git", ".lunora-cache", ".wrangler", "_generated", "dist", "node_modules"]);
40
- const DEFAULT_SCAN_DIRECTORIES = ["lunora", "src"];
41
- const WORKER_ENTRY_FALLBACKS = ["src/server/index.ts", "src/server/index.tsx", "src/index.ts", "src/worker.ts"];
42
- const DURABLE_OBJECT_BINDINGS = {
43
- SchedulerDO: "SCHEDULER",
44
- SessionDO: "SESSION",
45
- ShardDO: "SHARD"
46
- };
47
- const DURABLE_OBJECT_CLASSES = Object.keys(DURABLE_OBJECT_BINDINGS);
48
- const TYPE_ONLY_EXPORT_PATTERNS = {
49
- SchedulerDO: /\btype\s+SchedulerDO\b/,
50
- SessionDO: /\btype\s+SessionDO\b/,
51
- ShardDO: /\btype\s+ShardDO\b/
52
- };
53
- const ENV_DB_PATTERN = /\benv\s*\.\s*DB\b/;
54
- const ENV_AI_PATTERN = /\benv\s*\.\s*AI\b/;
55
- const CTX_PIPELINES_PATTERN = /\bctx\s*\.\s*pipelines\b/;
56
- const TYPE_ONLY_IMPORT_PATTERN = /^\s*import\s+type\b/;
57
- const SANDBOX_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["@lunora/agent", "@lunora/agent/sandbox"]);
58
- const extractImportSpecifierList = (statementText) => {
59
- const openBraceIndex = statementText.indexOf("{");
60
- if (openBraceIndex === -1) {
61
- return "";
62
- }
63
- const closeBraceIndex = statementText.indexOf("}", openBraceIndex + 1);
64
- return closeBraceIndex === -1 ? statementText.slice(openBraceIndex + 1) : statementText.slice(openBraceIndex + 1, closeBraceIndex);
65
- };
66
- const TYPE_BROWSER_TOOL_SPECIFIER_PATTERN = /\btype\s+browserTool\b/;
67
- const BROWSER_TOOL_NAME_PATTERN = /\bbrowserTool\b/;
68
- const SANDBOX_BROWSER_TOOL_FALLBACK_PATTERN = /import\s+\{[^}]*\bbrowserTool\b[^}]*\}\s+from\s+["']@lunora\/agent(?:\/sandbox)?["']/;
69
- const isValueBrowserToolImport = (statementText) => {
70
- if (TYPE_ONLY_IMPORT_PATTERN.test(statementText)) {
71
- return false;
72
- }
73
- const specifierList = extractImportSpecifierList(statementText);
74
- return BROWSER_TOOL_NAME_PATTERN.test(specifierList) && !TYPE_BROWSER_TOOL_SPECIFIER_PATTERN.test(specifierList);
75
- };
76
- const hasSandboxBrowserToolImport = (code) => {
77
- try {
78
- const [imports] = parse(code);
79
- return imports.some(
80
- (entry) => entry.n !== void 0 && SANDBOX_MODULE_SPECIFIERS.has(entry.n) && isValueBrowserToolImport(code.slice(entry.ss, entry.se))
81
- );
82
- } catch {
83
- return SANDBOX_BROWSER_TOOL_FALLBACK_PATTERN.test(code);
84
- }
85
- };
86
- const CAPABILITY_SOURCES = {
87
- usesAi: { pattern: /\bfrom\s+["']@lunora\/ai["']/, source: "@lunora/ai" },
88
- usesAnalytics: { pattern: /\bfrom\s+["']@lunora\/bindings\/analytics["']/, source: "@lunora/bindings/analytics" },
89
- usesAuth: { pattern: /\bfrom\s+["']@lunora\/auth["']/, source: "@lunora/auth" },
90
- usesBrowser: { pattern: /\bfrom\s+["']@lunora\/browser["']/, source: "@lunora/browser" },
91
- usesHyperdrive: { pattern: /\bfrom\s+["']@lunora\/hyperdrive["']/, source: "@lunora/hyperdrive" },
92
- usesImages: { pattern: /\bfrom\s+["']@lunora\/bindings\/images["']/, source: "@lunora/bindings/images" },
93
- usesKv: { pattern: /\bfrom\s+["']@lunora\/bindings\/kv["']/, source: "@lunora/bindings/kv" },
94
- usesMail: { pattern: /\bfrom\s+["']@lunora\/mail["']/, source: "@lunora/mail" },
95
- usesPayment: { pattern: /\bfrom\s+["']@lunora\/payment["']/, source: "@lunora/payment" },
96
- // Keyed off the `ctx.pipelines` access (not an import) — see CTX_PIPELINES_PATTERN.
97
- // Pipelines is codegen-wired onto ActionCtx, so apps reach it via `ctx.pipelines`
98
- // rather than importing `@lunora/bindings/pipelines`; `source` names that subpath
99
- // for the hint message.
100
- usesPipelines: { pattern: CTX_PIPELINES_PATTERN, source: "@lunora/bindings/pipelines" },
101
- usesScheduler: { pattern: /\bfrom\s+["']@lunora\/scheduler["']/, source: "@lunora/scheduler" },
102
- usesStorage: { pattern: /\bfrom\s+["']@lunora\/storage["']/, source: "@lunora/storage" },
103
- // x402 rails are opt-in add-on subpaths (not part of the `lunorash` umbrella),
104
- // so they key off the exact `@lunora/x402/{charge,pay}` specifiers. Neither
105
- // implies a `.dev.vars` secret: the charge recipient is a user-named `[vars]`
106
- // entry and the pay wallet key is a Secrets Store binding — both hint-only.
107
- usesX402Charge: { pattern: /\bfrom\s+["']@lunora\/x402\/charge["']/, source: "@lunora/x402/charge" },
108
- usesX402Pay: { pattern: /\bfrom\s+["']@lunora\/x402\/pay["']/, source: "@lunora/x402/pay" }
109
- };
110
- const CAPABILITY_FLAGS = Object.keys(CAPABILITY_SOURCES);
111
- const PAYMENT_PROVIDER_SECRETS = "STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET (Stripe) or POLAR_ACCESS_TOKEN + POLAR_WEBHOOK_SECRET (Polar)";
112
- const ALL_CAPABILITY_KEYS = [...CAPABILITY_FLAGS, "needsD1"];
113
- const emptyCapabilities = () => {
114
- const base = {};
115
- for (const key of ALL_CAPABILITY_KEYS) {
116
- base[key] = false;
117
- }
118
- return base;
119
- };
120
- const NO_CAPABILITIES = Object.freeze(emptyCapabilities());
121
- const mergeCapabilities = (a, b) => {
122
- const merged = {};
123
- for (const key of ALL_CAPABILITY_KEYS) {
124
- merged[key] = a[key] || b[key];
125
- }
126
- return merged;
127
- };
128
- const capabilityForImportSource = (source) => {
129
- for (const flag of CAPABILITY_FLAGS) {
130
- if (CAPABILITY_SOURCES[flag].source === source) {
131
- return { ...NO_CAPABILITIES, [flag]: true };
132
- }
133
- }
134
- return NO_CAPABILITIES;
135
- };
136
- const lexCapabilities = (code) => {
137
- const [imports] = parse(code);
138
- let capabilities = NO_CAPABILITIES;
139
- for (const entry of imports) {
140
- const source = entry.n;
141
- if (!source || TYPE_ONLY_IMPORT_PATTERN.test(code.slice(entry.ss, entry.se))) {
142
- continue;
143
- }
144
- capabilities = mergeCapabilities(capabilities, capabilityForImportSource(source));
145
- }
146
- return capabilities;
147
- };
148
- const regexCapabilities = (code) => {
149
- const capabilities = { ...NO_CAPABILITIES };
150
- for (const flag of CAPABILITY_FLAGS) {
151
- capabilities[flag] = CAPABILITY_SOURCES[flag].pattern.test(code);
152
- }
153
- return capabilities;
154
- };
155
- const capabilitiesFromSource = (code) => {
156
- let capabilities;
157
- try {
158
- capabilities = lexCapabilities(code);
159
- } catch {
160
- capabilities = regexCapabilities(code);
161
- }
162
- return mergeCapabilities(capabilities, {
163
- ...NO_CAPABILITIES,
164
- needsD1: ENV_DB_PATTERN.test(code),
165
- usesAi: ENV_AI_PATTERN.test(code),
166
- usesPipelines: CTX_PIPELINES_PATTERN.test(code)
167
- });
168
- };
169
- const collectSourceFiles = (directory, accumulator) => {
170
- let entries;
171
- try {
172
- entries = readdirSync(directory, { withFileTypes: true });
173
- } catch {
174
- return;
175
- }
176
- for (const entry of entries) {
177
- if (entry.isDirectory()) {
178
- if (!IGNORED_DIRECTORIES.has(entry.name)) {
179
- collectSourceFiles(join(directory, entry.name), accumulator);
180
- }
181
- continue;
182
- }
183
- const dotIndex = entry.name.lastIndexOf(".");
184
- if (dotIndex !== -1 && SOURCE_EXTENSIONS.has(entry.name.slice(dotIndex))) {
185
- accumulator.push(join(directory, entry.name));
186
- }
187
- }
188
- };
189
- const resolveWorkerEntry = (projectRoot) => {
190
- for (const candidate of WRANGLER_FILES) {
191
- const wranglerPath = join(projectRoot, candidate);
192
- if (!existsSync(wranglerPath)) {
193
- continue;
194
- }
195
- const { parsed } = readWranglerJsonc(wranglerPath);
196
- const main = parsed?.main;
197
- if (typeof main === "string" && existsSync(join(projectRoot, main))) {
198
- return join(projectRoot, main);
199
- }
200
- break;
201
- }
202
- for (const fallback of WORKER_ENTRY_FALLBACKS) {
203
- const fullPath = join(projectRoot, fallback);
204
- if (existsSync(fullPath)) {
205
- return fullPath;
206
- }
207
- }
208
- return void 0;
209
- };
210
- const detectExportedDurableObjects = (entryPath) => {
211
- const code = readFileSync(entryPath, "utf8");
212
- let exportedNames;
213
- try {
214
- const [, exports] = parse(code);
215
- exportedNames = new Set(exports.map((entry) => entry.n));
216
- } catch {
217
- exportedNames = new Set(DURABLE_OBJECT_CLASSES.filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code)));
218
- }
219
- return DURABLE_OBJECT_CLASSES.filter((className) => exportedNames.has(className) && !TYPE_ONLY_EXPORT_PATTERNS[className].test(code)).map((className) => {
220
- return {
221
- binding: DURABLE_OBJECT_BINDINGS[className],
222
- className
223
- };
224
- });
225
- };
226
- const isTypeOnlyClassExport = (code, className) => (
227
- // `export type Foo` / `export type { … Foo … }` / `export { type Foo }` — all
228
- // three type-only forms list the name via the lexer but compile away.
229
- new RegExp(String.raw`\bexport\s+type\s+${className}\b`).test(code) || new RegExp(String.raw`\bexport\s+type\s*\{[^}]*\b${className}\b`).test(code) || new RegExp(String.raw`\bexport\s+\{[^}]*\btype\s+${className}\b`).test(code)
230
- );
231
- const detectClassExports = (entryPath, definitions, generatedModule) => {
232
- if (definitions.length === 0) {
233
- return [];
234
- }
235
- if (entryPath === void 0) {
236
- return definitions.map((definition) => {
237
- return { ...definition, exported: false };
238
- });
239
- }
240
- const code = readFileSync(entryPath, "utf8");
241
- const starReexport = new RegExp(String.raw`\bexport\s*\*\s*from\s*["'][^"']*_generated\/${generatedModule}(?:\.js)?["']`).test(code);
242
- let exportedNames;
243
- try {
244
- const [, exports] = parse(code);
245
- exportedNames = new Set(exports.map((entry) => entry.n));
246
- } catch {
247
- exportedNames = new Set(
248
- definitions.map((definition) => definition.className).filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code))
249
- );
250
- }
251
- return definitions.map((definition) => {
252
- const exported = starReexport || exportedNames.has(definition.className) && !isTypeOnlyClassExport(code, definition.className);
253
- return { ...definition, exported };
254
- });
255
- };
256
- const detectContainerExports = (entryPath, containers) => detectClassExports(entryPath, containers, "containers");
257
- const detectWorkflowExports = (entryPath, workflows) => detectClassExports(entryPath, workflows, "workflows");
258
- const detectAgentExports = (entryPath, agents) => detectClassExports(entryPath, agents, "agents");
259
- const schemaNeedsD1 = (projectRoot, schemaDirectory) => discoverSchemaInfo(projectRoot, schemaDirectory).info?.hasGlobalTable ?? false;
260
- const scanCapabilities = (projectRoot, scanDirectories) => {
261
- let merged = NO_CAPABILITIES;
262
- for (const relativeDirectory of scanDirectories) {
263
- const absolute = join(projectRoot, relativeDirectory);
264
- if (!existsSync(absolute) || !statSync(absolute).isDirectory()) {
265
- continue;
266
- }
267
- const files = [];
268
- collectSourceFiles(absolute, files);
269
- for (const file of files) {
270
- merged = mergeCapabilities(merged, capabilitiesFromSource(readFileSync(file, "utf8")));
271
- }
272
- }
273
- return merged;
274
- };
275
- const scanSandboxBrowserToolUsage = (projectRoot, lunoraDirectory) => {
276
- const absolute = join(projectRoot, lunoraDirectory);
277
- if (!existsSync(absolute) || !statSync(absolute).isDirectory()) {
278
- return false;
279
- }
280
- const files = [];
281
- collectSourceFiles(absolute, files);
282
- return files.some((file) => hasSandboxBrowserToolImport(readFileSync(file, "utf8")));
283
- };
284
- const describeDeclaredExports = (containers, workflows, agents) => [
285
- ...containers.map(
286
- (container) => container.exported ? `${container.bindingName}/${container.className} (container "${container.exportName}" declared and exported)` : `hint: container "${container.exportName}" is declared but ${container.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/containers"\``
287
- ),
288
- ...workflows.map(
289
- (workflow) => workflow.exported ? `${workflow.bindingName}/${workflow.className} (workflow "${workflow.exportName}" declared and exported)` : `hint: workflow "${workflow.exportName}" is declared but ${workflow.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/workflows"\``
290
- ),
291
- ...agents.map(
292
- (agent) => agent.exported ? `${agent.bindingName}/${agent.className} (agent "${agent.exportName}" declared and exported)` : `hint: agent "${agent.exportName}" is declared but ${agent.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/agents"\``
293
- )
294
- ];
295
- const describeCapabilitySignals = (capabilities, exported) => {
296
- const rules = [
297
- [capabilities.usesAi, "AI (@lunora/ai imported or env.AI used)"],
298
- [
299
- capabilities.usesAuth && !exported.has("SessionDO"),
300
- "hint: @lunora/auth is imported but no SessionDO is exported (sessions are D1-backed, or export SessionDO for DO-backed sessions)"
301
- ],
302
- [capabilities.usesScheduler && !exported.has("SchedulerDO"), "hint: @lunora/scheduler is imported but no SchedulerDO is exported by the worker entry"],
303
- [capabilities.usesStorage, "hint: @lunora/storage is imported; add an r2_buckets binding (bucket binding names are user-defined)"],
304
- [capabilities.usesMail, "hint: @lunora/mail is imported; set RESEND_API_KEY in .dev.vars (obtain at https://resend.com/api-keys)"],
305
- [capabilities.usesPayment, `hint: @lunora/payment is imported; set the provider secrets in .dev.vars — ${PAYMENT_PROVIDER_SECRETS}`],
306
- // Self-describing bindings: the binding name is the whole config (no remote
307
- // id to mint), so reconcile auto-writes them like the DO/D1 bindings.
308
- [capabilities.usesBrowser, "browser (@lunora/browser imported) — self-describing { binding: BROWSER }"],
309
- [capabilities.usesImages, "images (@lunora/bindings/images imported) — self-describing { binding: IMAGES }"],
310
- [capabilities.usesAnalytics, "analytics_engine_datasets (@lunora/bindings/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],
311
- // Hint bindings: each needs a remote resource Lunora can't fabricate (a KV
312
- // namespace id, a Hyperdrive id, a Pipelines pipeline name), so they surface
313
- // as hints — never an auto-write — exactly like R2's user-defined bucket name.
314
- [
315
- capabilities.usesKv,
316
- "hint: @lunora/bindings/kv is imported; add a kv_namespaces binding ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned"
317
- ],
318
- [
319
- capabilities.usesHyperdrive,
320
- "hint: @lunora/hyperdrive is imported; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned"
321
- ],
322
- [
323
- capabilities.usesPipelines,
324
- "hint: ctx.pipelines is used; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding, pipeline }) — the pipeline resource can't be auto-provisioned"
325
- ],
326
- [
327
- capabilities.usesX402Charge,
328
- "hint: @lunora/x402/charge is imported; set the recipient wallet address as a [vars] entry (the var name is yours to choose) and pass it to the charge config — the x402 facilitator settles USDC to that address"
329
- ],
330
- [
331
- capabilities.usesX402Pay,
332
- "hint: @lunora/x402/pay is imported (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding for the agent wallet key (name it to match signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars, so the key can't be auto-provisioned"
333
- ]
334
- ];
335
- return rules.filter(([active]) => active).map(([, signal]) => signal);
336
- };
337
- const describeSignals = (durableObjects, needsD1, capabilities, containers = [], workflows = [], agents = []) => {
338
- const exported = new Set(durableObjects.map((object) => object.className));
339
- const signals = durableObjects.map((object) => `${object.binding}/${object.className} (exported by worker entry)`);
340
- if (needsD1) {
341
- signals.push("DB (.global() table declared)");
342
- }
343
- signals.push(...describeDeclaredExports(containers, workflows, agents), ...describeCapabilitySignals(capabilities, exported));
344
- return signals;
345
- };
346
- const inferLunoraBindings = async (options) => {
347
- await init;
348
- const schemaDirectory = options.schemaDir ?? "lunora";
349
- const scanDirectories = options.scanDirs ?? DEFAULT_SCAN_DIRECTORIES;
350
- const scannedCapabilities = scanCapabilities(options.projectRoot, scanDirectories);
351
- const capabilities = {
352
- ...scannedCapabilities,
353
- usesBrowser: scannedCapabilities.usesBrowser || scanSandboxBrowserToolUsage(options.projectRoot, schemaDirectory)
354
- };
355
- const entryPath = resolveWorkerEntry(options.projectRoot);
356
- const durableObjects = entryPath ? detectExportedDurableObjects(entryPath) : [];
357
- const needsD1 = capabilities.needsD1 || schemaNeedsD1(options.projectRoot, schemaDirectory);
358
- const containers = detectContainerExports(entryPath, discoverContainerInfo(options.projectRoot, schemaDirectory).containers);
359
- const workflows = detectWorkflowExports(entryPath, discoverWorkflowInfo(options.projectRoot, schemaDirectory).workflows);
360
- const agents = detectAgentExports(entryPath, discoverAgentInfo(options.projectRoot, schemaDirectory).agents);
361
- const queues = [...discoverQueueInfo(options.projectRoot, schemaDirectory).queues];
362
- const { flags } = discoverFlagsInfo(options.projectRoot, schemaDirectory);
363
- const flagshipBinding = flags?.provider === "flagship" && flags.mode === "binding" ? flags.bindingName : void 0;
364
- const capabilityFlags = {};
365
- for (const flag of CAPABILITY_FLAGS) {
366
- capabilityFlags[flag] = capabilities[flag];
367
- }
368
- const signals = describeSignals(durableObjects, needsD1, capabilities, containers, workflows, agents);
369
- if (flagshipBinding !== void 0) {
370
- signals.push(
371
- `hint: lunora/flags.ts uses Flagship in binding mode; add a flagship binding ({ binding: "${flagshipBinding}", app_id }) — the app_id can't be auto-provisioned`
372
- );
373
- }
374
- return {
375
- agents,
376
- containers,
377
- durableObjects,
378
- flagshipBinding,
379
- needsD1,
380
- queues,
381
- signals,
382
- usesFlags: flags !== void 0,
383
- workflows,
384
- ...capabilityFlags
385
- };
386
- };
387
- const packageNamesFromBindings = (bindings) => {
388
- const names = [];
389
- for (const flag of CAPABILITY_FLAGS) {
390
- if (bindings[flag]) {
391
- names.push(CAPABILITY_SOURCES[flag].source);
392
- }
393
- }
394
- return names;
395
- };
396
-
397
- export { inferLunoraBindings, packageNamesFromBindings };
@@ -1,9 +0,0 @@
1
- import { modify, applyEdits } from 'jsonc-parser';
2
-
3
- const FORMATTING = { formattingOptions: { insertSpaces: true, tabSize: 4 } };
4
- const applyModify = (text, path, value) => {
5
- const edits = modify(text, [...path], value, FORMATTING);
6
- return edits.length > 0 ? applyEdits(text, edits) : text;
7
- };
8
-
9
- export { FORMATTING as F, applyModify as a };
@@ -1,21 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { parseDevVariableEntries } from './DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs';
4
-
5
- const parseDevVariable = (contents, key) => {
6
- const entry = parseDevVariableEntries(contents).find((candidate) => candidate.key === key);
7
- return entry === void 0 || entry.value === "" ? void 0 : entry.value;
8
- };
9
- const resolveAdminToken = (root) => {
10
- const fromEnv = process.env["LUNORA_ADMIN_TOKEN"];
11
- if (typeof fromEnv === "string" && fromEnv !== "") {
12
- return fromEnv;
13
- }
14
- try {
15
- return parseDevVariable(readFileSync(join(root, ".dev.vars"), "utf8"), "LUNORA_ADMIN_TOKEN");
16
- } catch {
17
- return void 0;
18
- }
19
- };
20
-
21
- export { parseDevVariable, resolveAdminToken };
@@ -1,107 +0,0 @@
1
- import { Project, SyntaxKind } from 'ts-morph';
2
-
3
- const OPTIONAL_VALIDATOR_PATTERN = /^v\s*\.\s*optional\s*\(/u;
4
- const SHARD_BY_PATTERN = /\.shardBy\(\s*["']([^"']+)["']\s*\)/u;
5
- const GLOBAL_PATTERN = /\.global\(\s*\)/u;
6
- const QUOTE_PATTERN = /["']/gu;
7
- const collectCalls = (node) => {
8
- const calls = node.getDescendantsOfKind(SyntaxKind.CallExpression);
9
- if (node.getKind() === SyntaxKind.CallExpression) {
10
- calls.push(node.asKindOrThrow(SyntaxKind.CallExpression));
11
- }
12
- return calls;
13
- };
14
- const isOptionalValidator = (validatorText) => OPTIONAL_VALIDATOR_PATTERN.test(validatorText.trim());
15
- const readStringArray = (node) => {
16
- if (node?.getKind() !== SyntaxKind.ArrayLiteralExpression) {
17
- return [];
18
- }
19
- return node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression).getElements().filter((element) => element.getKind() === SyntaxKind.StringLiteral).map((element) => element.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralText());
20
- };
21
- const readUnique = (node) => {
22
- if (node?.getKind() !== SyntaxKind.ObjectLiteralExpression) {
23
- return false;
24
- }
25
- const property = node.asKindOrThrow(SyntaxKind.ObjectLiteralExpression).getProperty("unique");
26
- return property?.getKind() === SyntaxKind.PropertyAssignment && property.getInitializer()?.getText() === "true";
27
- };
28
- const parseIndexCall = (call) => {
29
- const expression = call.getExpression();
30
- if (expression.getKind() !== SyntaxKind.PropertyAccessExpression || expression.asKindOrThrow(SyntaxKind.PropertyAccessExpression).getName() !== "index") {
31
- return void 0;
32
- }
33
- const [nameArgument, fieldsArgument, optionsArgument] = call.getArguments();
34
- if (nameArgument?.getKind() !== SyntaxKind.StringLiteral) {
35
- return void 0;
36
- }
37
- return {
38
- fields: readStringArray(fieldsArgument),
39
- name: nameArgument.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralText(),
40
- unique: readUnique(optionsArgument)
41
- };
42
- };
43
- const parseIndexes = (initializer) => {
44
- const initializerNode = initializer.getInitializer();
45
- if (initializerNode === void 0) {
46
- return [];
47
- }
48
- const indexes = [];
49
- for (const call of collectCalls(initializerNode)) {
50
- const index = parseIndexCall(call);
51
- if (index !== void 0) {
52
- indexes.push(index);
53
- }
54
- }
55
- return indexes;
56
- };
57
- const parseColumns = (initializer) => {
58
- const columns = [];
59
- const defineTableCall = initializer.getInitializer()?.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => call.getExpression().getText() === "defineTable");
60
- const tableShape = defineTableCall?.getArguments()[0];
61
- if (tableShape?.getKind() !== SyntaxKind.ObjectLiteralExpression) {
62
- return columns;
63
- }
64
- for (const property of tableShape.getProperties()) {
65
- if (property.getKind() !== SyntaxKind.PropertyAssignment) {
66
- continue;
67
- }
68
- const assignment = property;
69
- const name = assignment.getName().replaceAll(QUOTE_PATTERN, "");
70
- const validator = assignment.getInitializer()?.getText() ?? "";
71
- columns.push({ name, optional: isOptionalValidator(validator), validator });
72
- }
73
- return columns;
74
- };
75
- const parseSchema = (source) => {
76
- const project = new Project({ compilerOptions: { allowJs: true }, useInMemoryFileSystem: true });
77
- const sourceFile = project.createSourceFile("schema.ts", source, { overwrite: true });
78
- const defineSchemaCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => call.getExpression().getText() === "defineSchema");
79
- if (defineSchemaCall === void 0) {
80
- const aliased = sourceFile.getImportDeclarations().some((declaration) => declaration.getNamedImports().some((named) => named.getName() === "defineSchema" && named.getAliasNode() !== void 0));
81
- return { ok: false, reason: aliased ? "aliased-define-schema" : "no-define-schema" };
82
- }
83
- const tablesArgument = defineSchemaCall.getArguments()[0];
84
- if (tablesArgument?.getKind() !== SyntaxKind.ObjectLiteralExpression) {
85
- return { ok: false, reason: "non-object-argument" };
86
- }
87
- const tables = [];
88
- for (const property of tablesArgument.getProperties()) {
89
- if (property.getKind() !== SyntaxKind.PropertyAssignment) {
90
- continue;
91
- }
92
- const assignment = property;
93
- const name = assignment.getName().replaceAll(QUOTE_PATTERN, "");
94
- const initializerText = assignment.getInitializer()?.getText() ?? "";
95
- const shardMatch = SHARD_BY_PATTERN.exec(initializerText);
96
- tables.push({
97
- columns: parseColumns(assignment),
98
- global: GLOBAL_PATTERN.test(initializerText),
99
- indexes: parseIndexes(assignment),
100
- name,
101
- ...shardMatch?.[1] === void 0 ? {} : { shardBy: shardMatch[1] }
102
- });
103
- }
104
- return { ok: true, tables };
105
- };
106
-
107
- export { collectCalls, parseSchema };