@lunora/config 1.0.0-alpha.13 → 1.0.0-alpha.131
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 +2 -2
- package/__assets__/package-og.svg +1 -1
- package/dist/cloudflare/index.d.mts +790 -0
- package/dist/cloudflare/index.d.ts +790 -0
- package/dist/cloudflare/index.mjs +1 -0
- package/dist/index.d.mts +702 -855
- package/dist/index.d.ts +702 -855
- package/dist/index.mjs +1 -22
- package/dist/packem_shared/ACCENT-CLeV5v0K.mjs +7 -0
- package/dist/packem_shared/AGENT_MODE_ENV-B54hVQ_w.mjs +1 -0
- package/dist/packem_shared/AGENT_RULES_DIR-hP9TiDNx.mjs +1 -0
- package/dist/packem_shared/ALLOW_FORWARDED_ENV-DGdbCDre.mjs +1 -0
- package/dist/packem_shared/BINDING_MANIFEST_VERSION-DOlqQgYt.mjs +1 -0
- package/dist/packem_shared/CLOUDFLARE_DRIVER-B_MaIVFz.mjs +1 -0
- package/dist/packem_shared/DEFAULT_DEPLOY_TARGET-cfA_ogWA.mjs +1 -0
- package/dist/packem_shared/DEV_DAEMON_ENV-D9Z83rlU.mjs +4 -0
- package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-BL0hrPx3.mjs +6 -0
- package/dist/packem_shared/LINKED_PROJECT_DIR-CMzUvj-1.mjs +2 -0
- package/dist/packem_shared/LUNORA_CONFIG_FILE-11ax8L-y.mjs +1 -0
- package/dist/packem_shared/LUNORA_EVENT_SOURCE-ZclWASXS.mjs +1 -0
- package/dist/packem_shared/LUNORA_IGNORED_PATHS-DIdyP0js.mjs +19 -0
- package/dist/packem_shared/LunoraReporter-BnXUqh8t.mjs +6 -0
- package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-BgmvEPA-.mjs +1 -0
- package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CUYWD0Mh.mjs +1 -0
- package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-ws6iE0y-.mjs +1 -0
- package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-BN97lRmC.mjs +1 -0
- package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-BNB1ogaj.mjs +1 -0
- package/dist/packem_shared/SEED_ENDPOINT-BaYShU8q.mjs +1 -0
- package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-B1h_wNDN.mjs +1 -0
- package/dist/packem_shared/WRANGLER_FILES-Bi_18Pj6.mjs +1 -0
- package/dist/packem_shared/applyAdditiveEdit-Cff30cSa.mjs +6 -0
- package/dist/packem_shared/assetContentType-DNZyUOuF.mjs +1 -0
- package/dist/packem_shared/buildPackageSecretsBlock-D2oDEMcf.mjs +18 -0
- package/dist/packem_shared/classifyPolicyEdit-BzC_MfYK.mjs +24 -0
- package/dist/packem_shared/cloudflare-driver-BHtz6vmK.mjs +1 -0
- package/dist/packem_shared/collectExportGaps-ajyIOfom.mjs +1 -0
- package/dist/packem_shared/collectWranglerSecretVariables-DZE0RIsW.mjs +1 -0
- package/dist/packem_shared/createConfirm-C5G4-dT6.mjs +7 -0
- package/dist/packem_shared/detectFramework-VTQfCNXy.mjs +1 -0
- package/dist/packem_shared/discover-info-DRQ0Ote0.mjs +1 -0
- package/dist/packem_shared/discoverAgentInfo-C8LTinx8.mjs +1 -0
- package/dist/packem_shared/discoverContainerInfo-C1zY2O8F.mjs +1 -0
- package/dist/packem_shared/discoverSchemaInfo-C8X9mo-i.mjs +1 -0
- package/dist/packem_shared/discoverWorkflowInfo-DHzCyLRj.mjs +1 -0
- package/dist/packem_shared/inferLunoraBindings-_ESCdL9P.mjs +1 -0
- package/dist/packem_shared/jsonc-edit-BZVpxVA0.mjs +1 -0
- package/dist/packem_shared/parseDevVariable-B193_28t.mjs +1 -0
- package/dist/packem_shared/parseSchema-BQjgz6bk.mjs +1 -0
- package/dist/packem_shared/{policy-scaffold.d-DCmwn7zQ.d.mts → policy-scaffold.d-fV3db0S_.d.mts} +23 -23
- package/dist/packem_shared/{policy-scaffold.d-DCmwn7zQ.d.ts → policy-scaffold.d-fV3db0S_.d.ts} +23 -23
- package/dist/packem_shared/reconcileWranglerCompatibilityDate-BXNiEQ7p.mjs +1 -0
- package/dist/packem_shared/reconcileWranglerCrons-BmQa_kGL.mjs +1 -0
- package/dist/packem_shared/renderStudioHtml-B2AkxcW1.mjs +15 -0
- package/dist/packem_shared/schema-info.d-DS0bUsWE.d.mts +375 -0
- package/dist/packem_shared/schema-info.d-DS0bUsWE.d.ts +375 -0
- package/dist/packem_shared/serveJsonHandler-DQ-Yqa4J.mjs +1 -0
- package/dist/packem_shared/streamContainerLogs-BPYBNrWS.mjs +2 -0
- package/dist/packem_shared/wranglerToAlchemy-BXagFk92.mjs +6 -0
- package/dist/packem_shared/write-atomic-Cdr2oQb-.mjs +1 -0
- package/dist/studio-host/index.d.mts +166 -92
- package/dist/studio-host/index.d.ts +166 -92
- package/dist/studio-host/index.mjs +1 -7
- package/package.json +15 -8
- package/dist/packem_shared/ACCENT-DW1XJn8i.mjs +0 -40
- package/dist/packem_shared/AGENT_RULES_DIR-lcgC08aE.mjs +0 -40
- package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs +0 -37
- package/dist/packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs +0 -52
- package/dist/packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs +0 -34
- package/dist/packem_shared/LUNORA_EVENT_SOURCE-D2fDeGB6.mjs +0 -86
- package/dist/packem_shared/LunoraReporter-Ci-bDCK9.mjs +0 -70
- package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs +0 -70
- package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CiC2IGKx.mjs +0 -103
- package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-BC7_e9Bz.mjs +0 -105
- package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-DRSNSOOp.mjs +0 -476
- package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-Df-Wrix-.mjs +0 -99
- package/dist/packem_shared/SEED_ENDPOINT-DVCjaGO-.mjs +0 -61
- package/dist/packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs +0 -25
- package/dist/packem_shared/applyAdditiveEdit-C-snTFEV.mjs +0 -228
- package/dist/packem_shared/buildPackageSecretsBlock-DWDKHViT.mjs +0 -243
- package/dist/packem_shared/classifyPolicyEdit-BHeAqF8P.mjs +0 -99
- package/dist/packem_shared/createConfirm-fvpdgJ9s.mjs +0 -100
- package/dist/packem_shared/detectFramework-Br-BcPBq.mjs +0 -41
- package/dist/packem_shared/discoverContainerInfo-BXFs6Wav.mjs +0 -19
- package/dist/packem_shared/discoverSchemaInfo-BB-CKlTK.mjs +0 -25
- package/dist/packem_shared/discoverWorkflowInfo-CedvR0mn.mjs +0 -19
- package/dist/packem_shared/inferLunoraBindings-DIku9mTN.mjs +0 -302
- package/dist/packem_shared/loadStudioAssets-Csk5RS4E.mjs +0 -28
- package/dist/packem_shared/parseDevVariable-CJiq2IwE.mjs +0 -30
- package/dist/packem_shared/parseSchema-DSeyktvG.mjs +0 -107
- package/dist/packem_shared/reconcileWranglerBindings-DTHmqTbL.mjs +0 -277
- package/dist/packem_shared/renderStudioHtml-449Ysn75.mjs +0 -37
- package/dist/packem_shared/serveJsonHandler-B4OLTGLS.mjs +0 -86
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
const FRAMEWORK_SIGNATURES = [
|
|
5
|
-
{ class: "A", dependency: "@tanstack/react-start", framework: "tanstack-start" },
|
|
6
|
-
{ class: "A", dependency: "@tanstack/solid-start", framework: "tanstack-start-solid" },
|
|
7
|
-
{ class: "A", dependency: "@react-router/dev", framework: "react-router" },
|
|
8
|
-
{ class: "A", dependency: "@solidjs/start", framework: "solid-start" },
|
|
9
|
-
{ class: "A", dependency: "solid-start", framework: "solid-start" },
|
|
10
|
-
{ class: "B", dependency: "@sveltejs/kit", framework: "sveltekit" },
|
|
11
|
-
{ class: "B", dependency: "nuxt", framework: "nuxt" },
|
|
12
|
-
{ class: "B", dependency: "astro", framework: "astro" }
|
|
13
|
-
];
|
|
14
|
-
const STANDALONE = { class: "C", framework: "none" };
|
|
15
|
-
const readDependencyNames = (root) => {
|
|
16
|
-
const packageJsonPath = join(root, "package.json");
|
|
17
|
-
if (!existsSync(packageJsonPath)) {
|
|
18
|
-
return /* @__PURE__ */ new Set();
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
const raw = readFileSync(packageJsonPath, "utf8");
|
|
22
|
-
const parsed = JSON.parse(raw);
|
|
23
|
-
return /* @__PURE__ */ new Set([...Object.keys(parsed.dependencies ?? {}), ...Object.keys(parsed.devDependencies ?? {})]);
|
|
24
|
-
} catch {
|
|
25
|
-
return /* @__PURE__ */ new Set();
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
const detectFramework = (root) => {
|
|
29
|
-
const dependencies = readDependencyNames(root);
|
|
30
|
-
if (dependencies.size === 0) {
|
|
31
|
-
return STANDALONE;
|
|
32
|
-
}
|
|
33
|
-
for (const signature of FRAMEWORK_SIGNATURES) {
|
|
34
|
-
if (dependencies.has(signature.dependency)) {
|
|
35
|
-
return { class: signature.class, framework: signature.framework };
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return STANDALONE;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export { detectFramework };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { CONTAINERS_FILENAME, discoverContainers } from '@lunora/codegen';
|
|
3
|
-
import { Project } from 'ts-morph';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
|
|
6
|
-
const discoverContainerInfo = (projectRoot, schemaDirectory) => {
|
|
7
|
-
const containersPath = join(projectRoot, schemaDirectory, CONTAINERS_FILENAME);
|
|
8
|
-
if (!existsSync(containersPath)) {
|
|
9
|
-
return { containers: [] };
|
|
10
|
-
}
|
|
11
|
-
try {
|
|
12
|
-
const project = new Project({ skipAddingFilesFromTsConfig: true, skipFileDependencyResolution: true, useInMemoryFileSystem: false });
|
|
13
|
-
return { containers: discoverContainers(project, join(projectRoot, schemaDirectory)) };
|
|
14
|
-
} catch (error) {
|
|
15
|
-
return { containers: [], error: error instanceof Error ? error.message : String(error) };
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export { discoverContainerInfo };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { discoverSchema } from '@lunora/codegen';
|
|
3
|
-
import { Project } from 'ts-morph';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
|
|
6
|
-
const discoverSchemaInfo = (projectRoot, schemaDirectory) => {
|
|
7
|
-
const schemaPath = join(projectRoot, schemaDirectory, "schema.ts");
|
|
8
|
-
if (!existsSync(schemaPath)) {
|
|
9
|
-
return { info: void 0 };
|
|
10
|
-
}
|
|
11
|
-
try {
|
|
12
|
-
const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
|
|
13
|
-
const schema = discoverSchema(project, schemaPath, projectRoot);
|
|
14
|
-
return {
|
|
15
|
-
info: {
|
|
16
|
-
hasGlobalTable: schema.tables.some((table) => table.shardMode === "global"),
|
|
17
|
-
vectorIndexNames: schema.vectorIndexes.map((index) => index.name)
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
} catch (error) {
|
|
21
|
-
return { error: error instanceof Error ? error.message : String(error), info: void 0 };
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export { discoverSchemaInfo };
|
|
@@ -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,302 +0,0 @@
|
|
|
1
|
-
import { existsSync, statSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { init, parse } from 'es-module-lexer';
|
|
3
|
-
import { discoverContainerInfo } from './discoverContainerInfo-BXFs6Wav.mjs';
|
|
4
|
-
import { discoverSchemaInfo } from './discoverSchemaInfo-BB-CKlTK.mjs';
|
|
5
|
-
import { discoverWorkflowInfo } from './discoverWorkflowInfo-CedvR0mn.mjs';
|
|
6
|
-
import { WRANGLER_FILES, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
7
|
-
import { join } from 'node:path';
|
|
8
|
-
|
|
9
|
-
const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".jsx", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
10
|
-
const IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([".git", ".lunora-cache", ".wrangler", "_generated", "dist", "node_modules"]);
|
|
11
|
-
const DEFAULT_SCAN_DIRECTORIES = ["lunora", "src"];
|
|
12
|
-
const WORKER_ENTRY_FALLBACKS = ["src/server/index.ts", "src/server/index.tsx", "src/index.ts", "src/worker.ts"];
|
|
13
|
-
const DURABLE_OBJECT_BINDINGS = {
|
|
14
|
-
SchedulerDO: "SCHEDULER",
|
|
15
|
-
SessionDO: "SESSION",
|
|
16
|
-
ShardDO: "SHARD"
|
|
17
|
-
};
|
|
18
|
-
const DURABLE_OBJECT_CLASSES = Object.keys(DURABLE_OBJECT_BINDINGS);
|
|
19
|
-
const TYPE_ONLY_EXPORT_PATTERNS = {
|
|
20
|
-
SchedulerDO: /\btype\s+SchedulerDO\b/,
|
|
21
|
-
SessionDO: /\btype\s+SessionDO\b/,
|
|
22
|
-
ShardDO: /\btype\s+ShardDO\b/
|
|
23
|
-
};
|
|
24
|
-
const ENV_DB_PATTERN = /\benv\s*\.\s*DB\b/;
|
|
25
|
-
const ENV_AI_PATTERN = /\benv\s*\.\s*AI\b/;
|
|
26
|
-
const TYPE_ONLY_IMPORT_PATTERN = /^\s*import\s+type\b/;
|
|
27
|
-
const CAPABILITY_SOURCES = {
|
|
28
|
-
usesAi: { pattern: /\bfrom\s+["']@lunora\/ai["']/, source: "@lunora/ai" },
|
|
29
|
-
usesAnalytics: { pattern: /\bfrom\s+["']@lunora\/analytics["']/, source: "@lunora/analytics" },
|
|
30
|
-
usesAuth: { pattern: /\bfrom\s+["']@lunora\/auth["']/, source: "@lunora/auth" },
|
|
31
|
-
usesBrowser: { pattern: /\bfrom\s+["']@lunora\/browser["']/, source: "@lunora/browser" },
|
|
32
|
-
usesHyperdrive: { pattern: /\bfrom\s+["']@lunora\/hyperdrive["']/, source: "@lunora/hyperdrive" },
|
|
33
|
-
usesImages: { pattern: /\bfrom\s+["']@lunora\/images["']/, source: "@lunora/images" },
|
|
34
|
-
usesKv: { pattern: /\bfrom\s+["']@lunora\/kv["']/, source: "@lunora/kv" },
|
|
35
|
-
usesMail: { pattern: /\bfrom\s+["']@lunora\/mail["']/, source: "@lunora/mail" },
|
|
36
|
-
usesPayment: { pattern: /\bfrom\s+["']@lunora\/payment["']/, source: "@lunora/payment" },
|
|
37
|
-
usesPipelines: { pattern: /\bfrom\s+["']@lunora\/pipelines["']/, source: "@lunora/pipelines" },
|
|
38
|
-
usesScheduler: { pattern: /\bfrom\s+["']@lunora\/scheduler["']/, source: "@lunora/scheduler" },
|
|
39
|
-
usesStorage: { pattern: /\bfrom\s+["']@lunora\/storage["']/, source: "@lunora/storage" }
|
|
40
|
-
};
|
|
41
|
-
const CAPABILITY_FLAGS = Object.keys(CAPABILITY_SOURCES);
|
|
42
|
-
const PAYMENT_PROVIDER_SECRETS = "STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET (Stripe) or POLAR_ACCESS_TOKEN + POLAR_WEBHOOK_SECRET (Polar)";
|
|
43
|
-
const ALL_CAPABILITY_KEYS = [...CAPABILITY_FLAGS, "needsD1"];
|
|
44
|
-
const emptyCapabilities = () => {
|
|
45
|
-
const base = {};
|
|
46
|
-
for (const key of ALL_CAPABILITY_KEYS) {
|
|
47
|
-
base[key] = false;
|
|
48
|
-
}
|
|
49
|
-
return base;
|
|
50
|
-
};
|
|
51
|
-
const NO_CAPABILITIES = Object.freeze(emptyCapabilities());
|
|
52
|
-
const mergeCapabilities = (a, b) => {
|
|
53
|
-
const merged = {};
|
|
54
|
-
for (const key of ALL_CAPABILITY_KEYS) {
|
|
55
|
-
merged[key] = a[key] || b[key];
|
|
56
|
-
}
|
|
57
|
-
return merged;
|
|
58
|
-
};
|
|
59
|
-
const capabilityForImportSource = (source) => {
|
|
60
|
-
for (const flag of CAPABILITY_FLAGS) {
|
|
61
|
-
if (CAPABILITY_SOURCES[flag].source === source) {
|
|
62
|
-
return { ...NO_CAPABILITIES, [flag]: true };
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return NO_CAPABILITIES;
|
|
66
|
-
};
|
|
67
|
-
const lexCapabilities = (code) => {
|
|
68
|
-
const [imports] = parse(code);
|
|
69
|
-
let capabilities = NO_CAPABILITIES;
|
|
70
|
-
for (const entry of imports) {
|
|
71
|
-
const source = entry.n;
|
|
72
|
-
if (!source || TYPE_ONLY_IMPORT_PATTERN.test(code.slice(entry.ss, entry.se))) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
capabilities = mergeCapabilities(capabilities, capabilityForImportSource(source));
|
|
76
|
-
}
|
|
77
|
-
return capabilities;
|
|
78
|
-
};
|
|
79
|
-
const regexCapabilities = (code) => {
|
|
80
|
-
const capabilities = { ...NO_CAPABILITIES };
|
|
81
|
-
for (const flag of CAPABILITY_FLAGS) {
|
|
82
|
-
capabilities[flag] = CAPABILITY_SOURCES[flag].pattern.test(code);
|
|
83
|
-
}
|
|
84
|
-
return capabilities;
|
|
85
|
-
};
|
|
86
|
-
const capabilitiesFromSource = (code) => {
|
|
87
|
-
let capabilities;
|
|
88
|
-
try {
|
|
89
|
-
capabilities = lexCapabilities(code);
|
|
90
|
-
} catch {
|
|
91
|
-
capabilities = regexCapabilities(code);
|
|
92
|
-
}
|
|
93
|
-
return mergeCapabilities(capabilities, { ...NO_CAPABILITIES, needsD1: ENV_DB_PATTERN.test(code), usesAi: ENV_AI_PATTERN.test(code) });
|
|
94
|
-
};
|
|
95
|
-
const collectSourceFiles = (directory, accumulator) => {
|
|
96
|
-
let entries;
|
|
97
|
-
try {
|
|
98
|
-
entries = readdirSync(directory, { withFileTypes: true });
|
|
99
|
-
} catch {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
for (const entry of entries) {
|
|
103
|
-
if (entry.isDirectory()) {
|
|
104
|
-
if (!IGNORED_DIRECTORIES.has(entry.name)) {
|
|
105
|
-
collectSourceFiles(join(directory, entry.name), accumulator);
|
|
106
|
-
}
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
const dotIndex = entry.name.lastIndexOf(".");
|
|
110
|
-
if (dotIndex !== -1 && SOURCE_EXTENSIONS.has(entry.name.slice(dotIndex))) {
|
|
111
|
-
accumulator.push(join(directory, entry.name));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
const resolveWorkerEntry = (projectRoot) => {
|
|
116
|
-
for (const candidate of WRANGLER_FILES) {
|
|
117
|
-
const wranglerPath = join(projectRoot, candidate);
|
|
118
|
-
if (!existsSync(wranglerPath)) {
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
const { parsed } = readWranglerJsonc(wranglerPath);
|
|
122
|
-
const main = parsed?.main;
|
|
123
|
-
if (typeof main === "string" && existsSync(join(projectRoot, main))) {
|
|
124
|
-
return join(projectRoot, main);
|
|
125
|
-
}
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
for (const fallback of WORKER_ENTRY_FALLBACKS) {
|
|
129
|
-
const fullPath = join(projectRoot, fallback);
|
|
130
|
-
if (existsSync(fullPath)) {
|
|
131
|
-
return fullPath;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return void 0;
|
|
135
|
-
};
|
|
136
|
-
const detectExportedDurableObjects = (entryPath) => {
|
|
137
|
-
const code = readFileSync(entryPath, "utf8");
|
|
138
|
-
let exportedNames;
|
|
139
|
-
try {
|
|
140
|
-
const [, exports] = parse(code);
|
|
141
|
-
exportedNames = new Set(exports.map((entry) => entry.n));
|
|
142
|
-
} catch {
|
|
143
|
-
exportedNames = new Set(DURABLE_OBJECT_CLASSES.filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code)));
|
|
144
|
-
}
|
|
145
|
-
return DURABLE_OBJECT_CLASSES.filter((className) => exportedNames.has(className) && !TYPE_ONLY_EXPORT_PATTERNS[className].test(code)).map((className) => {
|
|
146
|
-
return {
|
|
147
|
-
binding: DURABLE_OBJECT_BINDINGS[className],
|
|
148
|
-
className
|
|
149
|
-
};
|
|
150
|
-
});
|
|
151
|
-
};
|
|
152
|
-
const CONTAINERS_STAR_REEXPORT_PATTERN = /\bexport\s*\*\s*from\s*["'][^"']*_generated\/containers(?:\.js)?["']/;
|
|
153
|
-
const detectContainerExports = (entryPath, containers) => {
|
|
154
|
-
if (containers.length === 0) {
|
|
155
|
-
return [];
|
|
156
|
-
}
|
|
157
|
-
if (entryPath === void 0) {
|
|
158
|
-
return containers.map((container) => {
|
|
159
|
-
return { ...container, exported: false };
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
const code = readFileSync(entryPath, "utf8");
|
|
163
|
-
const starReexport = CONTAINERS_STAR_REEXPORT_PATTERN.test(code);
|
|
164
|
-
let exportedNames;
|
|
165
|
-
try {
|
|
166
|
-
const [, exports] = parse(code);
|
|
167
|
-
exportedNames = new Set(exports.map((entry) => entry.n));
|
|
168
|
-
} catch {
|
|
169
|
-
exportedNames = new Set(
|
|
170
|
-
containers.map((container) => container.className).filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code))
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
return containers.map((container) => {
|
|
174
|
-
return { ...container, exported: starReexport || exportedNames.has(container.className) };
|
|
175
|
-
});
|
|
176
|
-
};
|
|
177
|
-
const WORKFLOWS_STAR_REEXPORT_PATTERN = /\bexport\s*\*\s*from\s*["'][^"']*_generated\/workflows(?:\.js)?["']/;
|
|
178
|
-
const detectWorkflowExports = (entryPath, workflows) => {
|
|
179
|
-
if (workflows.length === 0) {
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
182
|
-
if (entryPath === void 0) {
|
|
183
|
-
return workflows.map((workflow) => {
|
|
184
|
-
return { ...workflow, exported: false };
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
const code = readFileSync(entryPath, "utf8");
|
|
188
|
-
const starReexport = WORKFLOWS_STAR_REEXPORT_PATTERN.test(code);
|
|
189
|
-
let exportedNames;
|
|
190
|
-
try {
|
|
191
|
-
const [, exports] = parse(code);
|
|
192
|
-
exportedNames = new Set(exports.map((entry) => entry.n));
|
|
193
|
-
} catch {
|
|
194
|
-
exportedNames = new Set(
|
|
195
|
-
workflows.map((workflow) => workflow.className).filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code))
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
return workflows.map((workflow) => {
|
|
199
|
-
return { ...workflow, exported: starReexport || exportedNames.has(workflow.className) };
|
|
200
|
-
});
|
|
201
|
-
};
|
|
202
|
-
const schemaNeedsD1 = (projectRoot, schemaDirectory) => discoverSchemaInfo(projectRoot, schemaDirectory).info?.hasGlobalTable ?? false;
|
|
203
|
-
const scanCapabilities = (projectRoot, scanDirectories) => {
|
|
204
|
-
let merged = NO_CAPABILITIES;
|
|
205
|
-
for (const relativeDirectory of scanDirectories) {
|
|
206
|
-
const absolute = join(projectRoot, relativeDirectory);
|
|
207
|
-
if (!existsSync(absolute) || !statSync(absolute).isDirectory()) {
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
const files = [];
|
|
211
|
-
collectSourceFiles(absolute, files);
|
|
212
|
-
for (const file of files) {
|
|
213
|
-
merged = mergeCapabilities(merged, capabilitiesFromSource(readFileSync(file, "utf8")));
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return merged;
|
|
217
|
-
};
|
|
218
|
-
const describeDeclaredExports = (containers, workflows) => [
|
|
219
|
-
...containers.map(
|
|
220
|
-
(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"\``
|
|
221
|
-
),
|
|
222
|
-
...workflows.map(
|
|
223
|
-
(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"\``
|
|
224
|
-
)
|
|
225
|
-
];
|
|
226
|
-
const describeCapabilitySignals = (capabilities, exported) => {
|
|
227
|
-
const rules = [
|
|
228
|
-
[capabilities.usesAi, "AI (@lunora/ai imported or env.AI used)"],
|
|
229
|
-
[
|
|
230
|
-
capabilities.usesAuth && !exported.has("SessionDO"),
|
|
231
|
-
"hint: @lunora/auth is imported but no SessionDO is exported (sessions are D1-backed, or export SessionDO for DO-backed sessions)"
|
|
232
|
-
],
|
|
233
|
-
[capabilities.usesScheduler && !exported.has("SchedulerDO"), "hint: @lunora/scheduler is imported but no SchedulerDO is exported by the worker entry"],
|
|
234
|
-
[capabilities.usesStorage, "hint: @lunora/storage is imported; add an r2_buckets binding (bucket binding names are user-defined)"],
|
|
235
|
-
[capabilities.usesMail, "hint: @lunora/mail is imported; set RESEND_API_KEY in .dev.vars (obtain at https://resend.com/api-keys)"],
|
|
236
|
-
[capabilities.usesPayment, `hint: @lunora/payment is imported; set the provider secrets in .dev.vars — ${PAYMENT_PROVIDER_SECRETS}`],
|
|
237
|
-
// Self-describing bindings: the binding name is the whole config (no remote
|
|
238
|
-
// id to mint), so reconcile auto-writes them like the DO/D1 bindings.
|
|
239
|
-
[capabilities.usesBrowser, "browser (@lunora/browser imported) — self-describing { binding: BROWSER }"],
|
|
240
|
-
[capabilities.usesImages, "images (@lunora/images imported) — self-describing { binding: IMAGES }"],
|
|
241
|
-
[capabilities.usesAnalytics, "analytics_engine_datasets (@lunora/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],
|
|
242
|
-
// Hint bindings: each needs a remote resource Lunora can't fabricate (a KV
|
|
243
|
-
// namespace id, a Hyperdrive id, a Pipelines pipeline name), so they surface
|
|
244
|
-
// as hints — never an auto-write — exactly like R2's user-defined bucket name.
|
|
245
|
-
[
|
|
246
|
-
capabilities.usesKv,
|
|
247
|
-
"hint: @lunora/kv is imported; add a kv_namespaces binding ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned"
|
|
248
|
-
],
|
|
249
|
-
[
|
|
250
|
-
capabilities.usesHyperdrive,
|
|
251
|
-
"hint: @lunora/hyperdrive is imported; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned"
|
|
252
|
-
],
|
|
253
|
-
[
|
|
254
|
-
capabilities.usesPipelines,
|
|
255
|
-
"hint: @lunora/pipelines is imported; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding, pipeline }) — the pipeline resource can't be auto-provisioned"
|
|
256
|
-
]
|
|
257
|
-
];
|
|
258
|
-
return rules.filter(([active]) => active).map(([, signal]) => signal);
|
|
259
|
-
};
|
|
260
|
-
const describeSignals = (durableObjects, needsD1, capabilities, containers = [], workflows = []) => {
|
|
261
|
-
const exported = new Set(durableObjects.map((object) => object.className));
|
|
262
|
-
const signals = durableObjects.map((object) => `${object.binding}/${object.className} (exported by worker entry)`);
|
|
263
|
-
if (needsD1) {
|
|
264
|
-
signals.push("DB (.global() table declared)");
|
|
265
|
-
}
|
|
266
|
-
signals.push(...describeDeclaredExports(containers, workflows), ...describeCapabilitySignals(capabilities, exported));
|
|
267
|
-
return signals;
|
|
268
|
-
};
|
|
269
|
-
const inferLunoraBindings = async (options) => {
|
|
270
|
-
await init;
|
|
271
|
-
const schemaDirectory = options.schemaDir ?? "lunora";
|
|
272
|
-
const scanDirectories = options.scanDirs ?? DEFAULT_SCAN_DIRECTORIES;
|
|
273
|
-
const capabilities = scanCapabilities(options.projectRoot, scanDirectories);
|
|
274
|
-
const entryPath = resolveWorkerEntry(options.projectRoot);
|
|
275
|
-
const durableObjects = entryPath ? detectExportedDurableObjects(entryPath) : [];
|
|
276
|
-
const needsD1 = capabilities.needsD1 || schemaNeedsD1(options.projectRoot, schemaDirectory);
|
|
277
|
-
const containers = detectContainerExports(entryPath, discoverContainerInfo(options.projectRoot, schemaDirectory).containers);
|
|
278
|
-
const workflows = detectWorkflowExports(entryPath, discoverWorkflowInfo(options.projectRoot, schemaDirectory).workflows);
|
|
279
|
-
const capabilityFlags = {};
|
|
280
|
-
for (const flag of CAPABILITY_FLAGS) {
|
|
281
|
-
capabilityFlags[flag] = capabilities[flag];
|
|
282
|
-
}
|
|
283
|
-
return {
|
|
284
|
-
containers,
|
|
285
|
-
durableObjects,
|
|
286
|
-
needsD1,
|
|
287
|
-
signals: describeSignals(durableObjects, needsD1, capabilities, containers, workflows),
|
|
288
|
-
workflows,
|
|
289
|
-
...capabilityFlags
|
|
290
|
-
};
|
|
291
|
-
};
|
|
292
|
-
const packageNamesFromBindings = (bindings) => {
|
|
293
|
-
const names = [];
|
|
294
|
-
for (const flag of CAPABILITY_FLAGS) {
|
|
295
|
-
if (bindings[flag]) {
|
|
296
|
-
names.push(CAPABILITY_SOURCES[flag].source);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return names;
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
export { inferLunoraBindings, packageNamesFromBindings };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { readFileSync, statSync } from 'node:fs';
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
|
|
4
|
-
const loadStudioAssets = (logger, resolveFrom = import.meta.url) => {
|
|
5
|
-
try {
|
|
6
|
-
const require = createRequire(resolveFrom);
|
|
7
|
-
return {
|
|
8
|
-
script: readFileSync(require.resolve("@lunora/studio/standalone/studio.js")),
|
|
9
|
-
styles: readFileSync(require.resolve("@lunora/studio/styles.css"))
|
|
10
|
-
};
|
|
11
|
-
} catch (error) {
|
|
12
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
13
|
-
logger?.warnOnce?.(`[lunora] studio assets unavailable (build @lunora/studio?): ${message}`);
|
|
14
|
-
return void 0;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const studioAssetsStamp = (resolveFrom = import.meta.url) => {
|
|
18
|
-
try {
|
|
19
|
-
const require = createRequire(resolveFrom);
|
|
20
|
-
const scriptMtime = statSync(require.resolve("@lunora/studio/standalone/studio.js")).mtimeMs;
|
|
21
|
-
const stylesMtime = statSync(require.resolve("@lunora/studio/styles.css")).mtimeMs;
|
|
22
|
-
return Math.max(scriptMtime, stylesMtime);
|
|
23
|
-
} catch {
|
|
24
|
-
return void 0;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export { loadStudioAssets as default, studioAssetsStamp };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
const LINE_BREAK = /\r?\n/u;
|
|
5
|
-
const parseDevVariable = (contents, key) => {
|
|
6
|
-
for (const raw of contents.split(LINE_BREAK)) {
|
|
7
|
-
const line = raw.trim();
|
|
8
|
-
const eq = line.indexOf("=");
|
|
9
|
-
if (line === "" || line.startsWith("#") || eq === -1 || line.slice(0, eq).trim() !== key) {
|
|
10
|
-
continue;
|
|
11
|
-
}
|
|
12
|
-
const value = line.slice(eq + 1).trim();
|
|
13
|
-
const unquoted = value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'") ? value.slice(1, -1) : value;
|
|
14
|
-
return unquoted === "" ? void 0 : unquoted;
|
|
15
|
-
}
|
|
16
|
-
return void 0;
|
|
17
|
-
};
|
|
18
|
-
const resolveAdminToken = (root) => {
|
|
19
|
-
const fromEnv = process.env["LUNORA_ADMIN_TOKEN"];
|
|
20
|
-
if (typeof fromEnv === "string" && fromEnv !== "") {
|
|
21
|
-
return fromEnv;
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
return parseDevVariable(readFileSync(join(root, ".dev.vars"), "utf8"), "LUNORA_ADMIN_TOKEN");
|
|
25
|
-
} catch {
|
|
26
|
-
return void 0;
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
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 };
|