@lunora/vite 1.0.0-alpha.8 → 1.0.0-alpha.81
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 +15 -0
- package/__assets__/package-og.svg +1 -1
- package/dist/index.d.mts +335 -248
- package/dist/index.d.ts +335 -248
- package/dist/index.mjs +44 -25
- package/dist/packem_shared/{CLASS_A_WIRING-CZVcjgKo.mjs → CLASS_A_WIRING-T1RohRZQ.mjs} +22 -8
- package/dist/packem_shared/LUNORA_API_UPDATED_EVENT-BrkWk3rr.mjs +3 -0
- package/dist/packem_shared/{STUDIO_PATH-5ppCdBHa.mjs → STUDIO_PATH-U0eIaW1t.mjs} +32 -6
- package/dist/packem_shared/codegenPlugin-B8c38rky.mjs +347 -0
- package/dist/packem_shared/containerLogsPlugin-DMssU3wb.mjs +50 -0
- package/dist/packem_shared/devStatePlugin-DdjfMrhx.mjs +84 -0
- package/dist/packem_shared/devVariablesPlugin-CDNSnvOP.mjs +19 -0
- package/dist/packem_shared/{logStreamPlugin-CqvZ17kd.mjs → logStreamPlugin-DeFzd_pC.mjs} +30 -10
- package/dist/packem_shared/lunoraSolutionFinder-BKEAiUJP.mjs +17 -0
- package/dist/packem_shared/{planViteRemoteBindings-QN5ncUS1.mjs → planViteRemoteBindings-CRU90Bip.mjs} +21 -5
- package/dist/packem_shared/server-close-DKDp7YTU.mjs +16 -0
- package/dist/packem_shared/{wranglerValidatorPlugin-CEoJEghS.mjs → wranglerValidatorPlugin-C5VWOD7N.mjs} +3 -1
- package/package.json +9 -8
- package/dist/packem_shared/codegenPlugin-MuvbqAP8.mjs +0 -218
- package/dist/packem_shared/devVariablesPlugin-CVjkQay7.mjs +0 -21
- package/dist/packem_shared/reconcileWranglerCrons-PxGwfCp_.mjs +0 -29
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { claimDevServerState, DEV_LOG_FILE_ENV, DEV_DAEMON_ENV, DEV_HANDOFF_ENV, clearDevServerState } from '@lunora/config';
|
|
2
|
+
import { l as lunoraLine } from './log-BjO9EWah.mjs';
|
|
3
|
+
import { r as runPendingClose, a as registerDevServerClose } from './server-close-DKDp7YTU.mjs';
|
|
4
|
+
|
|
5
|
+
const TRAILING_SLASH = /\/$/;
|
|
6
|
+
const resolveLocalUrl = (server) => {
|
|
7
|
+
const resolved = server.resolvedUrls?.local[0];
|
|
8
|
+
if (resolved !== void 0) {
|
|
9
|
+
return resolved.replace(TRAILING_SLASH, "");
|
|
10
|
+
}
|
|
11
|
+
const address = server.httpServer?.address();
|
|
12
|
+
if (address !== null && typeof address === "object") {
|
|
13
|
+
return `http://localhost:${String(address.port)}`;
|
|
14
|
+
}
|
|
15
|
+
return void 0;
|
|
16
|
+
};
|
|
17
|
+
const devStatePlugin = (options) => {
|
|
18
|
+
let recorded = false;
|
|
19
|
+
const pendingMiddlewareClears = /* @__PURE__ */ new Map();
|
|
20
|
+
return {
|
|
21
|
+
apply: "serve",
|
|
22
|
+
configureServer(server) {
|
|
23
|
+
const root = options.projectRoot;
|
|
24
|
+
const record = () => {
|
|
25
|
+
if (recorded) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const url = resolveLocalUrl(server);
|
|
29
|
+
if (url === void 0) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const handoffPid = Number(process.env[DEV_HANDOFF_ENV]);
|
|
33
|
+
const claim = claimDevServerState(
|
|
34
|
+
root,
|
|
35
|
+
{
|
|
36
|
+
background: process.env[DEV_DAEMON_ENV] === "1",
|
|
37
|
+
logFile: process.env[DEV_LOG_FILE_ENV],
|
|
38
|
+
mode: "vite",
|
|
39
|
+
pid: process.pid,
|
|
40
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41
|
+
url
|
|
42
|
+
},
|
|
43
|
+
Number.isInteger(handoffPid) && handoffPid > 0 ? { supersedePid: handoffPid } : void 0
|
|
44
|
+
);
|
|
45
|
+
if (!claim.ok) {
|
|
46
|
+
if (claim.existing !== void 0) {
|
|
47
|
+
server.config.logger.warn(
|
|
48
|
+
lunoraLine(
|
|
49
|
+
`another dev server is already recorded at ${claim.existing.url} (pid ${String(claim.existing.pid)}) — leaving .lunora/dev.json untouched`
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
recorded = true;
|
|
56
|
+
};
|
|
57
|
+
const clearOnClose = () => {
|
|
58
|
+
if (recorded) {
|
|
59
|
+
clearDevServerState(root, process.pid);
|
|
60
|
+
recorded = false;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
registerDevServerClose(server, pendingMiddlewareClears, clearOnClose);
|
|
64
|
+
return () => {
|
|
65
|
+
if (typeof server.printUrls === "function") {
|
|
66
|
+
const printUrls = server.printUrls.bind(server);
|
|
67
|
+
server.printUrls = () => {
|
|
68
|
+
printUrls();
|
|
69
|
+
record();
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
server.httpServer?.once("listening", () => {
|
|
73
|
+
setTimeout(record, 0);
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
buildEnd() {
|
|
78
|
+
runPendingClose(pendingMiddlewareClears, this.environment);
|
|
79
|
+
},
|
|
80
|
+
name: "lunora:dev-state"
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export { devStatePlugin as default };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ensureDevVariables, createConfirm, fillDevSecrets } from '@lunora/config';
|
|
2
|
+
import { l as lunoraLine } from './log-BjO9EWah.mjs';
|
|
3
|
+
|
|
4
|
+
const devVariablesPlugin = (options) => {
|
|
5
|
+
return {
|
|
6
|
+
apply: "serve",
|
|
7
|
+
async configResolved() {
|
|
8
|
+
const info = (message) => {
|
|
9
|
+
console.info(lunoraLine(message));
|
|
10
|
+
};
|
|
11
|
+
await ensureDevVariables({ confirm: createConfirm("[lunora] "), cwd: options.projectRoot, info });
|
|
12
|
+
fillDevSecrets({ cwd: options.projectRoot, info });
|
|
13
|
+
},
|
|
14
|
+
enforce: "pre",
|
|
15
|
+
name: "lunora:dev-vars"
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { devVariablesPlugin as default };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { LUNORA_EVENT_SOURCE, formatLunoraEvent } from '@lunora/config';
|
|
1
|
+
import { detectAiAgent, LUNORA_EVENT_SOURCE, formatLunoraEvent } from '@lunora/config';
|
|
2
|
+
import { a as registerDevServerClose, r as runPendingClose } from './server-close-DKDp7YTU.mjs';
|
|
2
3
|
|
|
3
4
|
const LUNORA_MARKER = `"source":"${LUNORA_EVENT_SOURCE}"`;
|
|
4
5
|
const ANSI = {
|
|
@@ -30,29 +31,48 @@ const wrapWrite = (original, colour) => (...args) => {
|
|
|
30
31
|
};
|
|
31
32
|
const patchStream = (stream) => {
|
|
32
33
|
const original = stream.write.bind(stream);
|
|
33
|
-
|
|
34
|
+
const wrapper = wrapWrite(original, stream.isTTY === true);
|
|
35
|
+
stream.write = wrapper;
|
|
34
36
|
return () => {
|
|
35
|
-
stream.write
|
|
37
|
+
if (stream.write === wrapper) {
|
|
38
|
+
stream.write = original;
|
|
39
|
+
}
|
|
36
40
|
};
|
|
37
41
|
};
|
|
42
|
+
const wantRawJsonLogs = () => {
|
|
43
|
+
const flag = process.env.LUNORA_LOG_JSON;
|
|
44
|
+
if (flag === "1" || flag === "true") {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (flag === "0" || flag === "false") {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return detectAiAgent() !== void 0;
|
|
51
|
+
};
|
|
38
52
|
const logStreamPlugin = () => {
|
|
39
|
-
|
|
53
|
+
const pendingMiddlewareTeardowns = /* @__PURE__ */ new Map();
|
|
54
|
+
let activeRestore;
|
|
40
55
|
return {
|
|
41
56
|
apply: "serve",
|
|
57
|
+
buildEnd() {
|
|
58
|
+
runPendingClose(pendingMiddlewareTeardowns, this.environment);
|
|
59
|
+
},
|
|
42
60
|
configureServer(server) {
|
|
43
|
-
if (
|
|
61
|
+
if (wantRawJsonLogs()) {
|
|
44
62
|
return;
|
|
45
63
|
}
|
|
64
|
+
activeRestore?.();
|
|
46
65
|
const restoreStdout = patchStream(process.stdout);
|
|
47
66
|
const restoreStderr = patchStream(process.stderr);
|
|
48
|
-
restore = () => {
|
|
67
|
+
const restore = () => {
|
|
49
68
|
restoreStdout();
|
|
50
69
|
restoreStderr();
|
|
51
|
-
|
|
70
|
+
if (activeRestore === restore) {
|
|
71
|
+
activeRestore = void 0;
|
|
72
|
+
}
|
|
52
73
|
};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
74
|
+
activeRestore = restore;
|
|
75
|
+
registerDevServerClose(server, pendingMiddlewareTeardowns, restore);
|
|
56
76
|
},
|
|
57
77
|
name: "lunora:log-stream"
|
|
58
78
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { findLunoraSolution } from '@lunora/codegen';
|
|
2
|
+
|
|
3
|
+
const lunoraSolutionFinder = {
|
|
4
|
+
// Synchronous body wrapped in `Promise.resolve` rather than `async`: the
|
|
5
|
+
// overlay's `handle` contract is promise-returning, but `require-await` is on
|
|
6
|
+
// for src and there's nothing to await here.
|
|
7
|
+
handle: (error) => {
|
|
8
|
+
const message = typeof error.message === "string" ? error.message : "";
|
|
9
|
+
const solution = findLunoraSolution(message);
|
|
10
|
+
return Promise.resolve(solution ? { body: solution.body, header: solution.header } : void 0);
|
|
11
|
+
},
|
|
12
|
+
name: "lunora",
|
|
13
|
+
priority: 100
|
|
14
|
+
};
|
|
15
|
+
const lunoraSolutionFinders = [lunoraSolutionFinder];
|
|
16
|
+
|
|
17
|
+
export { lunoraSolutionFinder, lunoraSolutionFinders };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveRemoteEnabled, readProjectRemotePreference, materializeRemoteWranglerConfig } from '@lunora/config';
|
|
2
|
+
import { l as lunoraLine } from './log-BjO9EWah.mjs';
|
|
2
3
|
|
|
3
4
|
const noopCleanup = () => {
|
|
4
5
|
};
|
|
@@ -21,7 +22,7 @@ const planViteRemoteBindings = (options) => {
|
|
|
21
22
|
reason: result.reason
|
|
22
23
|
};
|
|
23
24
|
};
|
|
24
|
-
const withRemoteBindings = (options,
|
|
25
|
+
const withRemoteBindings = (options, plan) => {
|
|
25
26
|
if (!plan.enabled || plan.configPath === void 0) {
|
|
26
27
|
return options;
|
|
27
28
|
}
|
|
@@ -29,11 +30,26 @@ const withRemoteBindings = (options, isServe, plan) => {
|
|
|
29
30
|
if (typeof existing.configPath === "string") {
|
|
30
31
|
return options;
|
|
31
32
|
}
|
|
32
|
-
if (!isServe()) {
|
|
33
|
-
return options;
|
|
34
|
-
}
|
|
35
33
|
return { ...options, configPath: plan.configPath };
|
|
36
34
|
};
|
|
35
|
+
const remoteBindingsConfigPlugin = (options, plan) => {
|
|
36
|
+
return {
|
|
37
|
+
config(_userConfig, env) {
|
|
38
|
+
if (env.command !== "serve") {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const merged = withRemoteBindings(options, plan);
|
|
42
|
+
const target = options;
|
|
43
|
+
if (merged.configPath !== void 0 && target.configPath === void 0) {
|
|
44
|
+
target.configPath = merged.configPath;
|
|
45
|
+
} else if (plan.enabled && plan.configPath === void 0 && plan.reason !== void 0) {
|
|
46
|
+
console.info(lunoraLine(`remote bindings requested but not applied: ${plan.reason}`));
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
enforce: "pre",
|
|
50
|
+
name: "lunora:remote-bindings-config"
|
|
51
|
+
};
|
|
52
|
+
};
|
|
37
53
|
const remoteBindingsCleanupPlugin = (cleanup) => {
|
|
38
54
|
return {
|
|
39
55
|
buildEnd() {
|
|
@@ -47,4 +63,4 @@ const remoteBindingsCleanupPlugin = (cleanup) => {
|
|
|
47
63
|
};
|
|
48
64
|
};
|
|
49
65
|
|
|
50
|
-
export { planViteRemoteBindings, remoteBindingsCleanupPlugin, withRemoteBindings };
|
|
66
|
+
export { planViteRemoteBindings, remoteBindingsCleanupPlugin, remoteBindingsConfigPlugin, withRemoteBindings };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const registerDevServerClose = (server, pending, onClose) => {
|
|
2
|
+
if (server.httpServer) {
|
|
3
|
+
server.httpServer.once("close", onClose);
|
|
4
|
+
} else {
|
|
5
|
+
pending.set(server.environments.client, onClose);
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
const runPendingClose = (pending, environment) => {
|
|
9
|
+
const onClose = pending.get(environment);
|
|
10
|
+
if (onClose !== void 0) {
|
|
11
|
+
pending.delete(environment);
|
|
12
|
+
onClose();
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { registerDevServerClose as a, runPendingClose as r };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import { validateWranglerProject, readWranglerJsonc } from '@lunora/config';
|
|
3
|
+
import { LunoraError } from '@lunora/errors';
|
|
3
4
|
import { l as lunoraLine } from './log-BjO9EWah.mjs';
|
|
4
5
|
|
|
5
6
|
const isLocalImagePath = (image) => image.startsWith("./") || image.startsWith("../") || image.startsWith("/") || image.includes("Dockerfile");
|
|
@@ -41,7 +42,8 @@ const wranglerValidatorPlugin = (options) => {
|
|
|
41
42
|
schemaDir: options.schemaDir
|
|
42
43
|
});
|
|
43
44
|
if (!result.wranglerPath) {
|
|
44
|
-
throw new
|
|
45
|
+
throw new LunoraError(
|
|
46
|
+
"INTERNAL",
|
|
45
47
|
[
|
|
46
48
|
"[lunora] wrangler.jsonc not found.",
|
|
47
49
|
` searched in: ${options.projectRoot}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/vite",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.81",
|
|
4
4
|
"description": "The Lunora Vite plugin: codegen, type sync, wrangler validation, and an error overlay over @cloudflare/vite-plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"directory": "packages/vite"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"dist",
|
|
28
|
+
"./dist",
|
|
29
29
|
"__assets__",
|
|
30
30
|
"README.md",
|
|
31
31
|
"LICENSE.md"
|
|
@@ -45,16 +45,17 @@
|
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@cloudflare/vite-plugin": "1.
|
|
49
|
-
"@lunora/codegen": "1.0.0-alpha.
|
|
50
|
-
"@lunora/config": "1.0.0-alpha.
|
|
51
|
-
"@
|
|
48
|
+
"@cloudflare/vite-plugin": "1.45.1",
|
|
49
|
+
"@lunora/codegen": "1.0.0-alpha.55",
|
|
50
|
+
"@lunora/config": "1.0.0-alpha.81",
|
|
51
|
+
"@lunora/errors": "1.0.0-alpha.8",
|
|
52
|
+
"@visulima/vite-overlay": "2.0.4",
|
|
52
53
|
"jsonc-parser": "^3.3.1",
|
|
53
54
|
"ts-morph": "^28.0.0"
|
|
54
55
|
},
|
|
55
56
|
"peerDependencies": {
|
|
56
|
-
"@lunora/studio": "1.0.0-alpha.
|
|
57
|
-
"vite": "^8.
|
|
57
|
+
"@lunora/studio": ">=1.0.0-alpha.50 <2.0.0-0",
|
|
58
|
+
"vite": "^8.1.5"
|
|
58
59
|
},
|
|
59
60
|
"peerDependenciesMeta": {
|
|
60
61
|
"@lunora/studio": {
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { resolve, sep, join } from 'node:path';
|
|
3
|
-
import { createCodegenProject, refreshCodegenProject, runCodegen, CodegenDiagnosticError } from '@lunora/codegen';
|
|
4
|
-
import { inferLunoraBindings, reconcileWranglerBindings } from '@lunora/config';
|
|
5
|
-
import { reconcileWranglerCrons } from './reconcileWranglerCrons-PxGwfCp_.mjs';
|
|
6
|
-
import { L as LUNORA_TAG, a as advisoryLine } from './log-BjO9EWah.mjs';
|
|
7
|
-
|
|
8
|
-
const DEBOUNCE_MS = 100;
|
|
9
|
-
const TSCONFIG_VARIANT_RE = /[/\\]tsconfig\..+\.json$/u;
|
|
10
|
-
const formatExportGapOverlay = (gaps) => {
|
|
11
|
-
const lines = gaps.map((gap) => ` • ${gap.kind} "${gap.exportName}" — class ${gap.className} is not exported by your worker entry.`);
|
|
12
|
-
const hints = [...new Set(gaps.map((gap) => gap.module))].map((module) => ` export * from "./lunora/_generated/${module}";`);
|
|
13
|
-
return [
|
|
14
|
-
`[lunora] ${String(gaps.length)} declared ${gaps.length === 1 ? "binding is" : "bindings are"} not exported by your worker entry — \`wrangler deploy\` will fail.`,
|
|
15
|
-
...lines,
|
|
16
|
-
"",
|
|
17
|
-
"Add to your worker entry:",
|
|
18
|
-
...hints
|
|
19
|
-
].join("\n");
|
|
20
|
-
};
|
|
21
|
-
const reconcileBindingsSafely = async (options, logger, onExportGaps) => {
|
|
22
|
-
try {
|
|
23
|
-
const inferred = await inferLunoraBindings({ projectRoot: options.projectRoot, schemaDir: options.schemaDir });
|
|
24
|
-
const reconciled = reconcileWranglerBindings(options.projectRoot, inferred);
|
|
25
|
-
if (reconciled.changed) {
|
|
26
|
-
logger.info?.(`${LUNORA_TAG} inferred bindings → ${reconciled.added.join(", ")} (written to ${reconciled.wranglerPath ?? "wrangler.jsonc"})`);
|
|
27
|
-
}
|
|
28
|
-
for (const warning of reconciled.warnings) {
|
|
29
|
-
logger.warn(`${LUNORA_TAG} ${warning}`);
|
|
30
|
-
}
|
|
31
|
-
if (reconciled.exportGaps.length > 0) {
|
|
32
|
-
onExportGaps?.(reconciled.exportGaps);
|
|
33
|
-
}
|
|
34
|
-
} catch (error) {
|
|
35
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
36
|
-
logger.warn(`${LUNORA_TAG} binding inference skipped: ${message}`);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const runCodegenSafely = (options, logger, overlay, project) => {
|
|
40
|
-
const schemaPath = join(options.projectRoot, options.schemaDir, "schema.ts");
|
|
41
|
-
if (!existsSync(schemaPath)) {
|
|
42
|
-
logger.warn(`${LUNORA_TAG} schema.ts not found at ${schemaPath} — codegen skipped`);
|
|
43
|
-
return void 0;
|
|
44
|
-
}
|
|
45
|
-
try {
|
|
46
|
-
const result = runCodegen({ apiSpec: options.apiSpec, lunoraDirectory: options.schemaDir, project, projectRoot: options.projectRoot });
|
|
47
|
-
try {
|
|
48
|
-
const reconciled = reconcileWranglerCrons(options.projectRoot, result.cronTriggers);
|
|
49
|
-
if (reconciled.changed) {
|
|
50
|
-
logger.info?.(
|
|
51
|
-
`${LUNORA_TAG} synced ${result.cronTriggers.length.toFixed(0)} cron trigger(s) into ${reconciled.wranglerPath ?? "wrangler.jsonc"}`
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
} catch (cronError) {
|
|
55
|
-
const message = cronError instanceof Error ? cronError.message : String(cronError);
|
|
56
|
-
logger.warn(`${LUNORA_TAG} cron trigger sync skipped: ${message}`);
|
|
57
|
-
}
|
|
58
|
-
for (const advisory of result.advisories) {
|
|
59
|
-
const line = advisoryLine(advisory.level, advisory.name, advisory.detail, advisory.remediation);
|
|
60
|
-
if (advisory.level === "ERROR") {
|
|
61
|
-
logger.error(line);
|
|
62
|
-
} else {
|
|
63
|
-
logger.warn(line);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return resolve(result.outputDirectory);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
69
|
-
logger.error(`${LUNORA_TAG} codegen failed: ${message}`);
|
|
70
|
-
overlay?.onError(error, message);
|
|
71
|
-
return void 0;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
const codegenPlugin = (options) => {
|
|
75
|
-
const absoluteSchemaDirectory = resolve(options.projectRoot, options.schemaDir);
|
|
76
|
-
let absoluteGeneratedDirectory = resolve(options.projectRoot, options.generatedDir);
|
|
77
|
-
let debounceTimer;
|
|
78
|
-
let devServer;
|
|
79
|
-
return {
|
|
80
|
-
async buildStart() {
|
|
81
|
-
const logger = {
|
|
82
|
-
error: (message) => {
|
|
83
|
-
console.error(message);
|
|
84
|
-
},
|
|
85
|
-
info: (message) => {
|
|
86
|
-
console.info(message);
|
|
87
|
-
},
|
|
88
|
-
warn: (message) => {
|
|
89
|
-
console.warn(message);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
const outputDirectory = runCodegenSafely(options, logger);
|
|
93
|
-
if (outputDirectory !== void 0) {
|
|
94
|
-
absoluteGeneratedDirectory = outputDirectory;
|
|
95
|
-
}
|
|
96
|
-
await reconcileBindingsSafely(options, logger, (gaps) => {
|
|
97
|
-
devServer?.hot.send({
|
|
98
|
-
err: { loc: void 0, message: formatExportGapOverlay(gaps), stack: "" },
|
|
99
|
-
type: "error"
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
},
|
|
103
|
-
configureServer(server) {
|
|
104
|
-
devServer = server;
|
|
105
|
-
server.watcher.add(absoluteSchemaDirectory);
|
|
106
|
-
const serverLogger = {
|
|
107
|
-
error: (message) => {
|
|
108
|
-
server.config.logger.error(message);
|
|
109
|
-
},
|
|
110
|
-
info: (message) => {
|
|
111
|
-
server.config.logger.info(message);
|
|
112
|
-
},
|
|
113
|
-
warn: (message) => {
|
|
114
|
-
server.config.logger.warn(message);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
const overlay = {
|
|
118
|
-
onError(error, message) {
|
|
119
|
-
const loc = error instanceof CodegenDiagnosticError ? { column: error.column, file: error.file, line: error.line } : void 0;
|
|
120
|
-
const overlayMessage = loc === void 0 ? `[lunora] codegen failed: ${message}
|
|
121
|
-
(see terminal for full stack trace and file location)` : `[lunora] codegen failed: ${message}`;
|
|
122
|
-
devServer?.hot.send({
|
|
123
|
-
err: {
|
|
124
|
-
loc,
|
|
125
|
-
message: overlayMessage,
|
|
126
|
-
stack: error instanceof Error ? error.stack ?? "" : ""
|
|
127
|
-
},
|
|
128
|
-
type: "error"
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
const isInside = (path, directory) => path === directory || path.startsWith(directory + sep);
|
|
133
|
-
let closed = false;
|
|
134
|
-
let cachedProject;
|
|
135
|
-
const invalidateGenerated = () => {
|
|
136
|
-
const environments = server.environments;
|
|
137
|
-
const graphs = [];
|
|
138
|
-
if (environments !== void 0) {
|
|
139
|
-
for (const environment of Object.values(environments)) {
|
|
140
|
-
if (environment.moduleGraph !== void 0) {
|
|
141
|
-
graphs.push(environment.moduleGraph);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (graphs.length === 0) {
|
|
146
|
-
graphs.push(server.moduleGraph);
|
|
147
|
-
}
|
|
148
|
-
for (const graph of graphs) {
|
|
149
|
-
for (const moduleEntry of graph.idToModuleMap.values()) {
|
|
150
|
-
if (moduleEntry.id && isInside(moduleEntry.id, absoluteGeneratedDirectory)) {
|
|
151
|
-
graph.invalidateModule(moduleEntry);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
const onChange = (file) => {
|
|
157
|
-
const normalized = resolve(file);
|
|
158
|
-
if (!isInside(normalized, absoluteSchemaDirectory)) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
if (isInside(normalized, absoluteGeneratedDirectory)) {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (normalized.endsWith(`${sep}tsconfig.json`) || TSCONFIG_VARIANT_RE.test(normalized)) {
|
|
165
|
-
cachedProject = void 0;
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (!normalized.endsWith(".ts")) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if (normalized.includes(`${sep}__tests__${sep}`) || normalized.endsWith(".test.ts") || normalized.endsWith(".spec.ts")) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if (debounceTimer) {
|
|
175
|
-
clearTimeout(debounceTimer);
|
|
176
|
-
}
|
|
177
|
-
debounceTimer = setTimeout(() => {
|
|
178
|
-
debounceTimer = void 0;
|
|
179
|
-
if (closed) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
if (cachedProject === void 0) {
|
|
183
|
-
cachedProject = createCodegenProject(absoluteSchemaDirectory);
|
|
184
|
-
} else {
|
|
185
|
-
refreshCodegenProject(cachedProject, absoluteSchemaDirectory);
|
|
186
|
-
}
|
|
187
|
-
const outputDirectory = runCodegenSafely(options, serverLogger, overlay, cachedProject);
|
|
188
|
-
if (outputDirectory === void 0) {
|
|
189
|
-
cachedProject = void 0;
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
absoluteGeneratedDirectory = outputDirectory;
|
|
193
|
-
invalidateGenerated();
|
|
194
|
-
server.hot.send({ type: "full-reload" });
|
|
195
|
-
}, DEBOUNCE_MS);
|
|
196
|
-
};
|
|
197
|
-
server.watcher.on("add", onChange);
|
|
198
|
-
server.watcher.on("change", onChange);
|
|
199
|
-
server.watcher.on("unlink", onChange);
|
|
200
|
-
return () => {
|
|
201
|
-
server.httpServer?.once("close", () => {
|
|
202
|
-
closed = true;
|
|
203
|
-
cachedProject = void 0;
|
|
204
|
-
if (debounceTimer) {
|
|
205
|
-
clearTimeout(debounceTimer);
|
|
206
|
-
debounceTimer = void 0;
|
|
207
|
-
}
|
|
208
|
-
server.watcher.off("add", onChange);
|
|
209
|
-
server.watcher.off("change", onChange);
|
|
210
|
-
server.watcher.off("unlink", onChange);
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
},
|
|
214
|
-
name: "lunora:codegen"
|
|
215
|
-
};
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
export { codegenPlugin as default };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { ensureDevVariables, createConfirm } from '@lunora/config';
|
|
2
|
-
import { l as lunoraLine } from './log-BjO9EWah.mjs';
|
|
3
|
-
|
|
4
|
-
const devVariablesPlugin = (options) => {
|
|
5
|
-
return {
|
|
6
|
-
apply: "serve",
|
|
7
|
-
async configResolved() {
|
|
8
|
-
await ensureDevVariables({
|
|
9
|
-
confirm: createConfirm("[lunora] "),
|
|
10
|
-
cwd: options.projectRoot,
|
|
11
|
-
info: (message) => {
|
|
12
|
-
console.info(lunoraLine(message));
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
},
|
|
16
|
-
enforce: "pre",
|
|
17
|
-
name: "lunora:dev-vars"
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export { devVariablesPlugin as default };
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from 'node:fs';
|
|
2
|
-
import { findWranglerFile, readWranglerJsonc } from '@lunora/config';
|
|
3
|
-
import { modify, applyEdits } from 'jsonc-parser';
|
|
4
|
-
|
|
5
|
-
const sameTriggers = (a, b) => a.length === b.length && a.every((value, index) => value === b[index]);
|
|
6
|
-
const reconcileWranglerCrons = (projectRoot, cronTriggers) => {
|
|
7
|
-
const wranglerPath = findWranglerFile(projectRoot);
|
|
8
|
-
if (!wranglerPath) {
|
|
9
|
-
return { changed: false, reason: "wrangler.jsonc not found" };
|
|
10
|
-
}
|
|
11
|
-
const { parsed, text } = readWranglerJsonc(wranglerPath);
|
|
12
|
-
if (parsed === void 0) {
|
|
13
|
-
return { changed: false, reason: `failed to parse ${wranglerPath} as JSONC`, wranglerPath };
|
|
14
|
-
}
|
|
15
|
-
const existing = Array.isArray(parsed.triggers?.crons) ? parsed.triggers.crons.filter((value) => typeof value === "string") : [];
|
|
16
|
-
if (sameTriggers(existing, cronTriggers)) {
|
|
17
|
-
return { changed: false, reason: "triggers.crons already in sync", wranglerPath };
|
|
18
|
-
}
|
|
19
|
-
const edits = modify(text, ["triggers", "crons"], [...cronTriggers], {
|
|
20
|
-
formattingOptions: { insertSpaces: true, tabSize: 4 }
|
|
21
|
-
});
|
|
22
|
-
if (edits.length === 0) {
|
|
23
|
-
return { changed: false, reason: "no structural edit produced", wranglerPath };
|
|
24
|
-
}
|
|
25
|
-
writeFileSync(wranglerPath, applyEdits(text, edits), "utf8");
|
|
26
|
-
return { changed: true, wranglerPath };
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export { reconcileWranglerCrons };
|