@lunora/vite 1.0.0-alpha.49 → 1.0.0-alpha.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -257,6 +257,27 @@ declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedIm
257
257
  */
258
258
  declare const frameworkComposePlugin: (options: ResolvedLunoraPluginOptions, context: LunoraPluginContext) => Plugin;
259
259
  /**
260
+ * The custom HMR event the Lunora Vite plugin sends on the client environment's
261
+ * hot channel after a successful codegen run, in place of the old blanket
262
+ * browser `full-reload`. The generated `api`/`server` modules are just
263
+ * `FunctionReference` metadata, so Vite's granular module HMR re-imports the
264
+ * changed `_generated/*` in place; this event is a non-destructive nudge that
265
+ * lets open WebSocket subscriptions, optimistic state, the offline queue, and
266
+ * form state survive a schema save.
267
+ *
268
+ * Kept in its own module (a single source of truth) so the codegen plugin —
269
+ * whose sole export is the plugin factory — can reference it without becoming a
270
+ * mixed default+named module, and so any future client-side listener can agree
271
+ * on the exact string.
272
+ *
273
+ * There is no first-party client listener yet: `@lunora/client` / `@lunora/react`
274
+ * ship as pre-bundled, side-effect-free dependencies where `import.meta.hot` is
275
+ * `undefined` at runtime (Vite's dep optimizer), so a listener there would be
276
+ * dead (and tree-shaken) code. A future app-local or codegen-emitted listener
277
+ * can import this constant to re-validate active queries over the live socket.
278
+ */
279
+ declare const LUNORA_API_UPDATED_EVENT = "lunora:api-updated";
280
+ /**
260
281
  * Vite plugin (serve-only) that formats Lunora worker logs in the terminal.
261
282
  * Patches `process.stdout`/`process.stderr` once the dev server is configured
262
283
  * and restores them when it closes.
@@ -447,4 +468,4 @@ declare const resolveOverlayOption: (overlay: LunoraPluginOptions["overlay"]) =>
447
468
  */
448
469
  declare const lunora: (options?: LunoraPluginOptions) => LunoraPlugins;
449
470
  declare const VERSION = "0.0.0";
450
- export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR, LUNORA_WORKER_VIRTUAL_ID, type LunoraPluginOptions, type LunoraPlugins, type OverlayPluginOptions, type PlanViteRemoteOptions, type ReconcileResult, type ResolvedLunoraPluginOptions, STUDIO_PATH, type Solution, type SolutionFinder, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, codegenPlugin, containerLogsPlugin, createCommandProbe, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
471
+ export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR, LUNORA_API_UPDATED_EVENT, LUNORA_WORKER_VIRTUAL_ID, type LunoraPluginOptions, type LunoraPlugins, type OverlayPluginOptions, type PlanViteRemoteOptions, type ReconcileResult, type ResolvedLunoraPluginOptions, STUDIO_PATH, type Solution, type SolutionFinder, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, codegenPlugin, containerLogsPlugin, createCommandProbe, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
package/dist/index.d.ts CHANGED
@@ -257,6 +257,27 @@ declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedIm
257
257
  */
258
258
  declare const frameworkComposePlugin: (options: ResolvedLunoraPluginOptions, context: LunoraPluginContext) => Plugin;
259
259
  /**
260
+ * The custom HMR event the Lunora Vite plugin sends on the client environment's
261
+ * hot channel after a successful codegen run, in place of the old blanket
262
+ * browser `full-reload`. The generated `api`/`server` modules are just
263
+ * `FunctionReference` metadata, so Vite's granular module HMR re-imports the
264
+ * changed `_generated/*` in place; this event is a non-destructive nudge that
265
+ * lets open WebSocket subscriptions, optimistic state, the offline queue, and
266
+ * form state survive a schema save.
267
+ *
268
+ * Kept in its own module (a single source of truth) so the codegen plugin —
269
+ * whose sole export is the plugin factory — can reference it without becoming a
270
+ * mixed default+named module, and so any future client-side listener can agree
271
+ * on the exact string.
272
+ *
273
+ * There is no first-party client listener yet: `@lunora/client` / `@lunora/react`
274
+ * ship as pre-bundled, side-effect-free dependencies where `import.meta.hot` is
275
+ * `undefined` at runtime (Vite's dep optimizer), so a listener there would be
276
+ * dead (and tree-shaken) code. A future app-local or codegen-emitted listener
277
+ * can import this constant to re-validate active queries over the live socket.
278
+ */
279
+ declare const LUNORA_API_UPDATED_EVENT = "lunora:api-updated";
280
+ /**
260
281
  * Vite plugin (serve-only) that formats Lunora worker logs in the terminal.
261
282
  * Patches `process.stdout`/`process.stderr` once the dev server is configured
262
283
  * and restores them when it closes.
@@ -447,4 +468,4 @@ declare const resolveOverlayOption: (overlay: LunoraPluginOptions["overlay"]) =>
447
468
  */
448
469
  declare const lunora: (options?: LunoraPluginOptions) => LunoraPlugins;
449
470
  declare const VERSION = "0.0.0";
450
- export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR, LUNORA_WORKER_VIRTUAL_ID, type LunoraPluginOptions, type LunoraPlugins, type OverlayPluginOptions, type PlanViteRemoteOptions, type ReconcileResult, type ResolvedLunoraPluginOptions, STUDIO_PATH, type Solution, type SolutionFinder, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, codegenPlugin, containerLogsPlugin, createCommandProbe, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
471
+ export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR, LUNORA_API_UPDATED_EVENT, LUNORA_WORKER_VIRTUAL_ID, type LunoraPluginOptions, type LunoraPlugins, type OverlayPluginOptions, type PlanViteRemoteOptions, type ReconcileResult, type ResolvedLunoraPluginOptions, STUDIO_PATH, type Solution, type SolutionFinder, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, codegenPlugin, containerLogsPlugin, createCommandProbe, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import errorOverlayPlugin from '@visulima/vite-overlay';
3
3
  import { detectAgentRules, claimAgentRulesHint, AGENT_RULES_HINT, detectFramework } from '@lunora/config';
4
4
  export { detectFramework } from '@lunora/config';
5
5
  import { l as lunoraLine } from './packem_shared/log-BjO9EWah.mjs';
6
- import codegenPlugin from './packem_shared/codegenPlugin-CC4MeBmj.mjs';
6
+ import codegenPlugin from './packem_shared/codegenPlugin-3AqQzOq0.mjs';
7
7
  import containerLogsPlugin from './packem_shared/containerLogsPlugin-DMssU3wb.mjs';
8
8
  import devStatePlugin from './packem_shared/devStatePlugin-D7Qc2gKr.mjs';
9
9
  import devVariablesPlugin from './packem_shared/devVariablesPlugin-CDNSnvOP.mjs';
@@ -21,6 +21,7 @@ import { withWorkerStartupHint } from './packem_shared/WORKER_STARTUP_HINT-DhsXU
21
21
  export { WORKER_STARTUP_HINT, augmentWorkerStartupError, isWorkerEntryEvalError } from './packem_shared/WORKER_STARTUP_HINT-DhsXUW8k.mjs';
22
22
  import { wranglerValidatorPlugin } from './packem_shared/wranglerValidatorPlugin-C5VWOD7N.mjs';
23
23
  export { reconcileWranglerCrons } from './packem_shared/reconcileWranglerCrons-PxGwfCp_.mjs';
24
+ export { default as LUNORA_API_UPDATED_EVENT } from './packem_shared/LUNORA_API_UPDATED_EVENT-BrkWk3rr.mjs';
24
25
 
25
26
  const agentRulesHintPlugin = (options) => {
26
27
  return {
@@ -0,0 +1,3 @@
1
+ const LUNORA_API_UPDATED_EVENT = "lunora:api-updated";
2
+
3
+ export { LUNORA_API_UPDATED_EVENT as default };
@@ -1,10 +1,45 @@
1
1
  import { existsSync } from 'node:fs';
2
- import { resolve, sep, join } from 'node:path';
2
+ import { join, resolve, sep, basename } from 'node:path';
3
3
  import { createCodegenProject, refreshCodegenProject, runCodegen, CodegenDiagnosticError } from '@lunora/codegen';
4
- import { collectWranglerSecretVariables, inferLunoraBindings, reconcileWranglerBindings } from '@lunora/config';
4
+ import { findWranglerFile, LUNORA_CONFIG_FILE, readWranglerJsonc, WRANGLER_FILES, collectWranglerSecretVariables, inferLunoraBindings, reconcileWranglerBindings } from '@lunora/config';
5
+ import { isRunnableDevEnvironment } from 'vite';
5
6
  import { reconcileWranglerCrons } from './reconcileWranglerCrons-PxGwfCp_.mjs';
7
+ import LUNORA_API_UPDATED_EVENT from './LUNORA_API_UPDATED_EVENT-BrkWk3rr.mjs';
6
8
  import { L as LUNORA_TAG, a as advisoryLine } from './log-BjO9EWah.mjs';
7
9
 
10
+ const fingerprintJsonc = (filePath, normalize) => {
11
+ try {
12
+ const { parsed, text } = readWranglerJsonc(filePath);
13
+ if (parsed === void 0) {
14
+ return `raw:${text}`;
15
+ }
16
+ return JSON.stringify(normalize ? normalize(parsed) : parsed);
17
+ } catch {
18
+ return "unreadable";
19
+ }
20
+ };
21
+ const stripCodegenOwnedCrons = (parsed) => {
22
+ const clone = { ...parsed };
23
+ const { triggers } = clone;
24
+ if (triggers !== null && typeof triggers === "object") {
25
+ const restTriggers = { ...triggers };
26
+ delete restTriggers.crons;
27
+ if (Object.keys(restTriggers).length > 0) {
28
+ clone.triggers = restTriggers;
29
+ } else {
30
+ delete clone.triggers;
31
+ }
32
+ }
33
+ return clone;
34
+ };
35
+ const computeConfigFingerprint = (projectRoot) => {
36
+ const wranglerFile = findWranglerFile(projectRoot);
37
+ const wranglerPart = wranglerFile === void 0 ? "absent" : fingerprintJsonc(wranglerFile, stripCodegenOwnedCrons);
38
+ const lunoraConfigPath = join(projectRoot, LUNORA_CONFIG_FILE);
39
+ const lunoraPart = existsSync(lunoraConfigPath) ? fingerprintJsonc(lunoraConfigPath) : "absent";
40
+ return `${wranglerPart}\0${lunoraPart}`;
41
+ };
42
+
8
43
  const DEBOUNCE_MS = 100;
9
44
  const TSCONFIG_VARIANT_RE = /[/\\]tsconfig\..+\.json$/u;
10
45
  const formatExportGapOverlay = (gaps) => {
@@ -77,11 +112,36 @@ const runCodegenSafely = (options, logger, overlay, project) => {
77
112
  return void 0;
78
113
  }
79
114
  };
115
+ const notifyEnvironmentsAfterCodegen = (server, changedFile, clearErrorOverlay) => {
116
+ let clientEnvironment;
117
+ for (const [name, environment] of Object.entries(server.environments)) {
118
+ if (name === "client") {
119
+ clientEnvironment = environment;
120
+ continue;
121
+ }
122
+ if (isRunnableDevEnvironment(environment)) {
123
+ continue;
124
+ }
125
+ environment.hot.send({ path: "*", triggeredBy: changedFile, type: "full-reload" });
126
+ }
127
+ if (clientEnvironment === void 0) {
128
+ server.hot.send({ type: "full-reload" });
129
+ return;
130
+ }
131
+ if (clearErrorOverlay) {
132
+ clientEnvironment.hot.send({ type: "full-reload" });
133
+ return;
134
+ }
135
+ clientEnvironment.hot.send({ event: LUNORA_API_UPDATED_EVENT, type: "custom" });
136
+ };
80
137
  const codegenPlugin = (options) => {
81
138
  const absoluteSchemaDirectory = resolve(options.projectRoot, options.schemaDir);
82
139
  let absoluteGeneratedDirectory = resolve(options.projectRoot, options.generatedDir);
83
140
  let debounceTimer;
84
141
  let devServer;
142
+ let configFingerprint;
143
+ let configBaselineSettled = false;
144
+ let restartInFlight = false;
85
145
  return {
86
146
  async buildStart() {
87
147
  const logger = {
@@ -105,10 +165,16 @@ const codegenPlugin = (options) => {
105
165
  type: "error"
106
166
  });
107
167
  });
168
+ if (devServer !== void 0) {
169
+ configFingerprint = computeConfigFingerprint(options.projectRoot);
170
+ configBaselineSettled = true;
171
+ }
108
172
  },
109
173
  configureServer(server) {
110
174
  devServer = server;
111
175
  server.watcher.add(absoluteSchemaDirectory);
176
+ configFingerprint = computeConfigFingerprint(options.projectRoot);
177
+ configBaselineSettled = false;
112
178
  const serverLogger = {
113
179
  error: (message) => {
114
180
  server.config.logger.error(message);
@@ -120,8 +186,10 @@ const codegenPlugin = (options) => {
120
186
  server.config.logger.warn(message);
121
187
  }
122
188
  };
189
+ let hadErrorOverlay = false;
123
190
  const overlay = {
124
191
  onError(error, message) {
192
+ hadErrorOverlay = true;
125
193
  const loc = error instanceof CodegenDiagnosticError ? { column: error.column, file: error.file, line: error.line } : void 0;
126
194
  const overlayMessage = loc === void 0 ? `[lunora] codegen failed: ${message}
127
195
  (see terminal for full stack trace and file location)` : `[lunora] codegen failed: ${message}`;
@@ -186,12 +254,55 @@ const codegenPlugin = (options) => {
186
254
  }
187
255
  absoluteGeneratedDirectory = outputDirectory;
188
256
  invalidateGenerated();
189
- server.hot.send({ type: "full-reload" });
257
+ notifyEnvironmentsAfterCodegen(server, normalized, hadErrorOverlay);
258
+ hadErrorOverlay = false;
190
259
  }, DEBOUNCE_MS);
191
260
  };
192
261
  server.watcher.on("add", onChange);
193
262
  server.watcher.on("change", onChange);
194
263
  server.watcher.on("unlink", onChange);
264
+ const configWatchPaths = /* @__PURE__ */ new Set([
265
+ ...WRANGLER_FILES.map((name) => resolve(options.projectRoot, name)),
266
+ resolve(options.projectRoot, LUNORA_CONFIG_FILE)
267
+ ]);
268
+ for (const configPath of configWatchPaths) {
269
+ server.watcher.add(configPath);
270
+ }
271
+ const onConfigChange = (file) => {
272
+ if (!configWatchPaths.has(resolve(file))) {
273
+ return;
274
+ }
275
+ if (restartInFlight) {
276
+ return;
277
+ }
278
+ const nextFingerprint = computeConfigFingerprint(options.projectRoot);
279
+ if (!configBaselineSettled) {
280
+ configFingerprint = nextFingerprint;
281
+ return;
282
+ }
283
+ if (configFingerprint === void 0) {
284
+ configFingerprint = nextFingerprint;
285
+ return;
286
+ }
287
+ if (nextFingerprint === configFingerprint) {
288
+ return;
289
+ }
290
+ configFingerprint = nextFingerprint;
291
+ restartInFlight = true;
292
+ server.config.logger.info(`${LUNORA_TAG} ${basename(resolve(file))} changed — restarting dev server`);
293
+ Promise.resolve(server.restart()).finally(() => {
294
+ restartInFlight = false;
295
+ }).catch((error) => {
296
+ const message = error instanceof Error ? error.message : String(error);
297
+ server.config.logger.error(
298
+ `${LUNORA_TAG} dev server restart failed: ${message} — keeping the running server; re-save your config to retry.`
299
+ );
300
+ server.hot.send({ err: { loc: void 0, message: `[lunora] dev server restart failed: ${message}`, stack: "" }, type: "error" });
301
+ });
302
+ };
303
+ server.watcher.on("add", onConfigChange);
304
+ server.watcher.on("change", onConfigChange);
305
+ server.watcher.on("unlink", onConfigChange);
195
306
  return () => {
196
307
  server.httpServer?.once("close", () => {
197
308
  closed = true;
@@ -203,6 +314,9 @@ const codegenPlugin = (options) => {
203
314
  server.watcher.off("add", onChange);
204
315
  server.watcher.off("change", onChange);
205
316
  server.watcher.off("unlink", onChange);
317
+ server.watcher.off("add", onConfigChange);
318
+ server.watcher.off("change", onConfigChange);
319
+ server.watcher.off("unlink", onConfigChange);
206
320
  });
207
321
  };
208
322
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/vite",
3
- "version": "1.0.0-alpha.49",
3
+ "version": "1.0.0-alpha.50",
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",
@@ -46,15 +46,15 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "@cloudflare/vite-plugin": "1.42.3",
49
- "@lunora/codegen": "1.0.0-alpha.30",
50
- "@lunora/config": "1.0.0-alpha.49",
49
+ "@lunora/codegen": "1.0.0-alpha.32",
50
+ "@lunora/config": "1.0.0-alpha.50",
51
51
  "@lunora/errors": "1.0.0-alpha.1",
52
52
  "@visulima/vite-overlay": "2.0.0-alpha.35",
53
53
  "jsonc-parser": "^3.3.1",
54
54
  "ts-morph": "^28.0.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "@lunora/studio": "1.0.0-alpha.34",
57
+ "@lunora/studio": "1.0.0-alpha.35",
58
58
  "vite": "^8.1.0"
59
59
  },
60
60
  "peerDependenciesMeta": {