@reticlehq/vite-plugin 2.5.0 → 2.6.0

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.ts CHANGED
@@ -95,9 +95,9 @@ export interface ReticleVitePlugin {
95
95
  config?: (config: {
96
96
  optimizeDeps?: {
97
97
  include?: string[];
98
- esbuildOptions?: {
99
- define?: Record<string, string>;
100
- };
98
+ /** Whichever key the app used — the plugin reads both and writes the one this Vite wants. */
99
+ esbuildOptions?: Record<string, unknown>;
100
+ rolldownOptions?: Record<string, unknown>;
101
101
  };
102
102
  define?: Record<string, string>;
103
103
  root?: string;
@@ -123,11 +123,28 @@ export interface ReticleVitePlugin {
123
123
  root?: string;
124
124
  command?: string;
125
125
  }) => void;
126
+ /** Dev-server hook: keeps the served connect module from outliving the token it was built without. */
127
+ configureServer?: (server: ViteDevServerLike) => void;
126
128
  /** Build-time post-condition: desktop injection must have happened. */
127
129
  buildEnd?: () => void;
128
130
  /** Runs the dev-mode injection check immediately. Test seam for the deferred timer. */
129
131
  checkInjectedForTest?: () => void;
130
132
  }
133
+ /**
134
+ * The slice of Vite's dev server this plugin touches, structurally — so `vite` stays a peer the
135
+ * plugin never imports, the same way the Svelte compiler and Playwright are handled elsewhere.
136
+ */
137
+ export interface ViteDevServerLike {
138
+ middlewares: {
139
+ use: (handler: (req: {
140
+ url?: string;
141
+ }, res: unknown, next: () => void) => void) => void;
142
+ };
143
+ moduleGraph: {
144
+ getModuleById: (id: string) => object | undefined;
145
+ invalidateModule: (mod: object) => void;
146
+ };
147
+ }
131
148
  interface HtmlTag {
132
149
  tag: string;
133
150
  /** Absent on an inline script, which carries its source in `children` instead. */
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { RETICLE_DEFAULT_PORT, RETICLE_RENDER_PREHOOK, bridgeWsUrl, ReticleDir,
9
9
  import { resolveProjectId } from './project-id.js';
10
10
  import { discoverDaemonPort } from './discover-port.js';
11
11
  import { SVELTE_FILE, stampSvelte } from './svelte-source.js';
12
- import { resolvableChain, sdkPackageVersion, sdkBuildFingerprint, viteMajor, optimizerOptionsKey, } from './installed.js';
12
+ import { resolvableChain, sdkPackageVersion, sdkBuildFingerprint, viteMajor, optimizerOptionsKey, optimizerOptions, } from './installed.js';
13
13
  export const RETICLE_VITE_PLUGIN_NAME = 'reticle';
14
14
  // The React kit the host app imports the SDK from. It re-exports the browser sensor, so a single
15
15
  // specifier yields both `reticle` (connect) and `install` (the React adapter). NOT `@reticlehq/core`
@@ -367,6 +367,7 @@ export function reticle(options = {}) {
367
367
  // Everything below asks what the APP has installed, so every lookup is rooted here and never
368
368
  // at the plugin's own location. Vite defaults an omitted root to the cwd; so do we.
369
369
  const appRoot = config.root ?? process.cwd();
370
+ const optimizerKey = optimizerOptionsKey(viteMajor(appRoot));
370
371
  return {
371
372
  // Expose the daemon's pairing token to hand-written connects in the same Vite app. The
372
373
  // plugin's own injected connect gets the token directly, but a connect the USER writes —
@@ -391,13 +392,12 @@ export function reticle(options = {}) {
391
392
  // Under the key THIS Vite wants. Vite 7 moved the optimizer to rolldown and deprecated
392
393
  // `esbuildOptions`, warning on every boot — a warning attributed to the plugin that set
393
394
  // it, which is us.
394
- [optimizerOptionsKey(viteMajor(appRoot))]: {
395
+ // Inherited from whichever key the app used, and `define` placed where this bundler will
396
+ // take it — rolldown refuses it at the top level. See optimizerOptions.
397
+ [optimizerKey]: optimizerOptions(optimizerKey, {
395
398
  ...(config.optimizeDeps?.esbuildOptions ?? {}),
396
- define: {
397
- ...(config.optimizeDeps?.esbuildOptions?.define ?? {}),
398
- __RETICLE_SDK_BUILD__: JSON.stringify(sdkBuildFingerprint(appRoot)),
399
- },
400
- },
399
+ ...(config.optimizeDeps?.rolldownOptions ?? {}),
400
+ }, { __RETICLE_SDK_BUILD__: JSON.stringify(sdkBuildFingerprint(appRoot)) }),
401
401
  include: [
402
402
  ...(config.optimizeDeps?.include ?? []),
403
403
  // The SDK ITSELF. Without this, Vite does not learn about @reticlehq/react until the
@@ -463,6 +463,33 @@ export function reticle(options = {}) {
463
463
  root = config.root;
464
464
  command = config.command;
465
465
  },
466
+ /**
467
+ * Serve the connect module fresh, every time.
468
+ *
469
+ * `load` reads the daemon's pairing token at serve time precisely because the daemon may start
470
+ * after the dev server — but Vite caches the module it produced, and answers every later request
471
+ * from that cache, INCLUDING after a full page reload. So a dev server started first served a
472
+ * tokenless connect module once and then kept serving it: the SDK got a 1008 `authentication
473
+ * failed`, stopped retrying (correctly — a wrong token does not fix itself), and `reticle status`
474
+ * showed no session while the page demonstrably contained `/@reticle-connect`. Only restarting
475
+ * the dev server cleared it, which is not a step anybody guesses.
476
+ *
477
+ * Dropping the cached module before it is served makes `load` re-read the token, so starting the
478
+ * daemon and reloading the page is enough. Costs one string compare per request and re-runs a
479
+ * three-line module — no reason to be cleverer about when to invalidate.
480
+ */
481
+ configureServer(server) {
482
+ if (!inject)
483
+ return;
484
+ server.middlewares.use((req, _res, next) => {
485
+ if ((req.url ?? '').split('?')[0] === RETICLE_CONNECT_MODULE) {
486
+ const mod = server.moduleGraph.getModuleById(RETICLE_CONNECT_MODULE);
487
+ if (mod !== undefined)
488
+ server.moduleGraph.invalidateModule(mod);
489
+ }
490
+ next();
491
+ });
492
+ },
466
493
  /**
467
494
  * Desktop injection is silent when it misses — the bundle simply has no connect() in it and the
468
495
  * app looks wired while reporting nothing. That happened twice while this was being built. A
@@ -68,3 +68,21 @@ export type OptimizerOptionsKey = (typeof OPTIMIZER_OPTIONS_KEY)[keyof typeof OP
68
68
  * than an option the installed Vite has never heard of.
69
69
  */
70
70
  export declare function optimizerOptionsKey(major: number | null): OptimizerOptionsKey;
71
+ /**
72
+ * The optimizer options object, with `define` where THIS bundler will accept it.
73
+ *
74
+ * esbuild reads `define` from the top level of its options. Rolldown does not — it rejects the key
75
+ * outright and reads defines from `transform.define` instead. Vite 8 surfaces that as a warning on
76
+ * every dev boot, attributed to whichever plugin set the option:
77
+ *
78
+ * Warning: Invalid input options (1 issue found)
79
+ * - For the "define". Invalid key: Expected never but received "define".
80
+ *
81
+ * The app still ran, which is why this survived: the option was dropped, `__RETICLE_SDK_BUILD__`
82
+ * stopped participating in the optimizer cache key, and the only visible symptom was a warning with
83
+ * Reticle's name on it. Reported by a user on vite@8.0.16.
84
+ *
85
+ * An inherited top-level `define` is MOVED rather than dropped on the rolldown path — it is the
86
+ * app's own, it meant something, and passing it through unchanged is what produced the warning.
87
+ */
88
+ export declare function optimizerOptions(key: OptimizerOptionsKey, inherited: Record<string, unknown>, add: Record<string, string>): Record<string, unknown>;
package/dist/installed.js CHANGED
@@ -182,3 +182,33 @@ export function optimizerOptionsKey(major) {
182
182
  ? OPTIMIZER_OPTIONS_KEY.ROLLDOWN
183
183
  : OPTIMIZER_OPTIONS_KEY.ESBUILD;
184
184
  }
185
+ /**
186
+ * The optimizer options object, with `define` where THIS bundler will accept it.
187
+ *
188
+ * esbuild reads `define` from the top level of its options. Rolldown does not — it rejects the key
189
+ * outright and reads defines from `transform.define` instead. Vite 8 surfaces that as a warning on
190
+ * every dev boot, attributed to whichever plugin set the option:
191
+ *
192
+ * Warning: Invalid input options (1 issue found)
193
+ * - For the "define". Invalid key: Expected never but received "define".
194
+ *
195
+ * The app still ran, which is why this survived: the option was dropped, `__RETICLE_SDK_BUILD__`
196
+ * stopped participating in the optimizer cache key, and the only visible symptom was a warning with
197
+ * Reticle's name on it. Reported by a user on vite@8.0.16.
198
+ *
199
+ * An inherited top-level `define` is MOVED rather than dropped on the rolldown path — it is the
200
+ * app's own, it meant something, and passing it through unchanged is what produced the warning.
201
+ */
202
+ export function optimizerOptions(key, inherited, add) {
203
+ const inheritedDefine = (inherited['define'] ?? {});
204
+ if (OPTIMIZER_OPTIONS_KEY.ROLLDOWN !== key) {
205
+ return { ...inherited, define: { ...inheritedDefine, ...add } };
206
+ }
207
+ const { define: _moved, ...rest } = inherited;
208
+ const transform = (inherited['transform'] ?? {});
209
+ const transformDefine = (transform['define'] ?? {});
210
+ return {
211
+ ...rest,
212
+ transform: { ...transform, define: { ...inheritedDefine, ...transformDefine, ...add } },
213
+ };
214
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reticlehq/vite-plugin",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "Vite plugin for Reticle: dev-only source-map stamping plus auto-injected reticle.connect(). apply:'serve' guarantees it never ships to production.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -35,8 +35,8 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@babel/core": "^7.26.0",
38
- "@reticlehq/babel-plugin": "2.5.0",
39
- "@reticlehq/core": "2.5.0"
38
+ "@reticlehq/babel-plugin": "2.6.0",
39
+ "@reticlehq/core": "2.6.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/babel__core": "^7.20.5",