@reticlehq/vite-plugin 2.10.0 → 2.12.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.cjs CHANGED
@@ -36,7 +36,6 @@ __export(index_exports, {
36
36
  RETICLE_DEV_MODULE_CANDIDATES: () => RETICLE_DEV_MODULE_CANDIDATES,
37
37
  RETICLE_TOKEN_GLOBAL: () => RETICLE_TOKEN_GLOBAL,
38
38
  RETICLE_VITE_PLUGIN_NAME: () => RETICLE_VITE_PLUGIN_NAME,
39
- cjsDepIncludes: () => cjsDepIncludes,
40
39
  connectChurnWarning: () => connectChurnWarning,
41
40
  connectModuleSource: () => connectModuleSource,
42
41
  findDevModule: () => findDevModule,
@@ -86,7 +85,8 @@ var import_babel_plugin = __toESM(require("@reticlehq/babel-plugin"), 1);
86
85
  // ../core/dist/constants.js
87
86
  var RETICLE_DEFAULT_PORT = 4400;
88
87
  var RETICLE_WS_PATH = "/reticle";
89
- function bridgeWsUrl(port = RETICLE_DEFAULT_PORT, host = "localhost") {
88
+ var RETICLE_CLIENT_HOST = "localhost";
89
+ function bridgeWsUrl(port = RETICLE_DEFAULT_PORT, host = RETICLE_CLIENT_HOST) {
90
90
  return `ws://${host}:${String(port)}${RETICLE_WS_PATH}`;
91
91
  }
92
92
  var ReticleEnv = {
@@ -223,6 +223,8 @@ var ReticleDir = {
223
223
  * questions about the product; this answers the user's question about their own work.
224
224
  */
225
225
  IMPACT_FILE: "impact.json",
226
+ /** what changes were SUPPOSED to make true —.reticle/intent.json (git-checked, reviewed) */
227
+ INTENT_FILE: "intent.json",
226
228
  /** opt-in pixel baselines —.reticle/visual/<name>.png + <name>.diff.png. */
227
229
  VISUAL_SUBDIR: "visual",
228
230
  /** verification-run artifacts —.reticle/runs/<runId>.json (the OEM/CI-consumable verdict). */
@@ -285,6 +287,12 @@ var EventType = {
285
287
  STORAGE_CHANGE: "storage.change",
286
288
  /** page-level visibility/focus health (distinct from element-level VISIBLE_*). */
287
289
  PAGE_HEALTH: "page.health",
290
+ /**
291
+ * synthetic: the page called window.open, so the consequence of what was just clicked may live in
292
+ * another browsing context this one cannot observe (an OAuth popup is the archetype).
293
+ * `data: { href }` — the URL the page asked to open, when it named one.
294
+ */
295
+ CONTEXT_OPENED: "context.opened",
288
296
  /** aggregated React commits over a throttle window (dev builds) — `data: { commits }`. Commit storms /
289
297
  * wasted re-renders show up here without a per-render flood. */
290
298
  RENDER_COMMIT: "render.commit",
@@ -4604,7 +4612,8 @@ var import_node_module2 = require("node:module");
4604
4612
  var RETICLE_PACKAGE = "@reticlehq/react";
4605
4613
  var MANIFEST_SEARCH_DEPTH = 5;
4606
4614
  function requireFromApp(from) {
4607
- return (0, import_node_module2.createRequire)((0, import_node_path5.join)(from, "package.json"));
4615
+ const absoluteFrom = (0, import_node_path5.isAbsolute)(from) ? from : (0, import_node_path5.resolve)(process.cwd(), from);
4616
+ return (0, import_node_module2.createRequire)((0, import_node_path5.join)(absoluteFrom, "package.json"));
4608
4617
  }
4609
4618
  function packageDirOf(specifier, from) {
4610
4619
  try {
@@ -4758,13 +4767,6 @@ function stamp(code, id) {
4758
4767
  map: out.map === void 0 || null === out.map ? null : JSON.stringify(out.map)
4759
4768
  };
4760
4769
  }
4761
- var SDK_CJS_DEPS = {
4762
- TESTING_LIBRARY: "@testing-library/dom",
4763
- ARIA_QUERY: "aria-query"
4764
- };
4765
- function cjsDepIncludes(appRoot, canResolve = (dep) => null !== resolvableChain([dep], appRoot)) {
4766
- return [SDK_CJS_DEPS.TESTING_LIBRARY, SDK_CJS_DEPS.ARIA_QUERY].filter(canResolve);
4767
- }
4768
4770
  function readPairingToken() {
4769
4771
  const override = process.env[ReticleEnv.PAIRING_TOKEN_DIR];
4770
4772
  const dir = override !== void 0 && override.length > 0 ? override : (0, import_node_path6.join)((0, import_node_os2.homedir)(), ReticleDir.ROOT);
@@ -4812,6 +4814,20 @@ function findDevModule(root, exists) {
4812
4814
  return null;
4813
4815
  }
4814
4816
  function installedSdk(appRoot, canResolve = (dep) => null !== resolvableChain([dep], appRoot)) {
4817
+ try {
4818
+ const pkgPath = (0, import_node_path6.join)(appRoot, "package.json");
4819
+ if ((0, import_node_fs5.existsSync)(pkgPath)) {
4820
+ const pkg = JSON.parse((0, import_node_fs5.readFileSync)(pkgPath, "utf8"));
4821
+ const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
4822
+ if (deps[RETICLE_SENSOR] !== void 0 && deps[RETICLE_PACKAGE2] === void 0) {
4823
+ return { specifier: RETICLE_SENSOR, usesInstall: false };
4824
+ }
4825
+ if (deps[RETICLE_PACKAGE2] !== void 0) {
4826
+ return { specifier: RETICLE_PACKAGE2, usesInstall: true };
4827
+ }
4828
+ }
4829
+ } catch {
4830
+ }
4815
4831
  if (canResolve(RETICLE_PACKAGE2)) return { specifier: RETICLE_PACKAGE2, usesInstall: true };
4816
4832
  if (canResolve(RETICLE_SENSOR)) return { specifier: RETICLE_SENSOR, usesInstall: false };
4817
4833
  return { specifier: RETICLE_PACKAGE2, usesInstall: true };
@@ -4821,9 +4837,11 @@ function connectModuleSource(options, devModule = null) {
4821
4837
  const sdk = installedSdk(options.root ?? process.cwd());
4822
4838
  const named = sdk.usesInstall ? "reticle, install" : "reticle";
4823
4839
  const call = sdk.usesInstall ? "install();\n" : "";
4840
+ const hot = `if (import.meta.hot) reticle.observeHotUpdates(import.meta.hot);
4841
+ `;
4824
4842
  const base = `import { ${named} } from '${sdk.specifier}';
4825
4843
  ${call}reticle.connect(${args});
4826
- `;
4844
+ ${hot}`;
4827
4845
  return null === devModule ? base : `${base}import('${devModule}');
4828
4846
  `;
4829
4847
  }
@@ -4869,21 +4887,11 @@ function reticle(options = {}) {
4869
4887
  ...true === options.desktop ? {} : { apply: "serve" },
4870
4888
  enforce: "pre",
4871
4889
  /**
4872
- * Declare the SDK's CJS runtime deps so Vite pre-bundles them.
4873
- *
4874
- * `@testing-library/dom` is what `by: role` matching runs on, and it pulls CJS `aria-query`. When
4875
- * the SDK resolves from OUTSIDE the app's root — a linked package, a pnpm workspace, `npm link`,
4876
- * a monorepo alias — Vite skips pre-bundling and the named import dies with "does not provide an
4877
- * export named 'elementRoles'". That takes the WHOLE SDK down before connect() runs, so there is
4878
- * no session, no Reticle-side error, and only a console SyntaxError naming a package the
4879
- * developer has never heard of. Measured on the react-admin demo with the SDK aliased to a local
4880
- * checkout: zero sessions, and it looked like the app was failing to render.
4890
+ * Declare the SDK itself and the optimizer cache fingerprint.
4881
4891
  *
4882
- * Declaring them is free when Vite would have found them anyway but only when they are
4883
- * actually installed. Naming a package that is not there makes Vite log `Failed to resolve
4884
- * dependency: …, present in optimizeDeps.include` on every boot, which is a scary line pointing
4885
- * at Reticle for a problem that does not exist. SvelteKit apps hit exactly that: nothing in that
4886
- * tree depends on @testing-library/dom.
4892
+ * The browser SDK used to need extra CJS query-engine deps here. It no longer imports that
4893
+ * second accessibility engine, so keeping those names would make Vite pre-bundle packages the
4894
+ * app may not have and blame Reticle for a false `Failed to resolve dependency` warning.
4887
4895
  */
4888
4896
  config(config) {
4889
4897
  const appRoot = config.root ?? process.cwd();
@@ -4965,10 +4973,7 @@ function reticle(options = {}) {
4965
4973
  // Whichever SDK this app actually has: naming `@reticlehq/react` in a Vue app that was
4966
4974
  // given the sensor produces the exact boot warning the note below is about, for a
4967
4975
  // package that is correctly absent.
4968
- installedSdk(appRoot).specifier,
4969
- // Only in a form that resolves — see above; a name Vite cannot resolve produces a boot
4970
- // warning that blames Reticle, and a forced re-optimization on every cold start.
4971
- ...cjsDepIncludes(appRoot)
4976
+ installedSdk(appRoot).specifier
4972
4977
  ]
4973
4978
  }
4974
4979
  };
@@ -5082,7 +5087,6 @@ ${code}`;
5082
5087
  RETICLE_DEV_MODULE_CANDIDATES,
5083
5088
  RETICLE_TOKEN_GLOBAL,
5084
5089
  RETICLE_VITE_PLUGIN_NAME,
5085
- cjsDepIncludes,
5086
5090
  connectChurnWarning,
5087
5091
  connectModuleSource,
5088
5092
  findDevModule,
package/dist/index.d.cts CHANGED
@@ -191,28 +191,11 @@ interface HtmlTag {
191
191
  injectTo: 'body' | 'head-prepend';
192
192
  }
193
193
  /**
194
- * Name each CJS dep ONLY in the bare form, and only when the app root can resolve it.
195
- *
196
- * This used to try three layouts and emit Vite's nested `a > b > c` form when a hoisted lookup
197
- * failed. The guard asked the wrong question: it tested NODE resolvability, walking the chain
198
- * segment by segment, and under pnpm that succeeds exactly where Vite fails. Measured on the
199
- * sveltekit fixture:
200
- *
201
- * ['@testing-library/dom'] -> null
202
- * ['@reticlehq/browser', '@testing-library/dom'] -> null
203
- * ['@reticlehq/react', '@reticlehq/browser', '@testing-library/dom'] -> emitted
204
- *
205
- * So we emitted the three-segment chain, Vite could not follow it, and the boot warning this
206
- * function exists to prevent appeared anyway — `Failed to resolve dependency: …, present in
207
- * optimizeDeps.include`, pointing at Reticle, naming a package the developer has never heard of,
208
- * and forcing a full re-optimization on every cold start. The comment stated the rule correctly and
209
- * the code broke it.
210
- *
211
- * Dropping the nested form loses nothing that matters: the SDK itself is still pre-bundled, and Vite
212
- * follows its imports when it does that, so these deps are handled as part of it. Naming them
213
- * separately was belt-and-braces for a locally-aliased SDK, where the bare form resolves anyway.
194
+ * Read the daemon's auto-provisioned pairing token (~/.reticle/pairing-token, or the
195
+ * RETICLE_PAIRING_TOKEN_DIR override) so the served app can present it. Node-side only — a browser
196
+ * sandbox can't read the file, which is exactly why a rogue localhost app can't forge it. Best-effort:
197
+ * undefined if the daemon hasn't started yet (the page reloads once it has). Exported for testing.
214
198
  */
215
- export declare function cjsDepIncludes(appRoot: string, canResolve?: (dep: string) => boolean): string[];
216
199
  export declare function readPairingToken(): string | undefined;
217
200
  /** The body of the connect module — real imports, resolved by Vite when the module is served. */
218
201
  /**
package/dist/index.d.ts CHANGED
@@ -191,28 +191,11 @@ interface HtmlTag {
191
191
  injectTo: 'body' | 'head-prepend';
192
192
  }
193
193
  /**
194
- * Name each CJS dep ONLY in the bare form, and only when the app root can resolve it.
195
- *
196
- * This used to try three layouts and emit Vite's nested `a > b > c` form when a hoisted lookup
197
- * failed. The guard asked the wrong question: it tested NODE resolvability, walking the chain
198
- * segment by segment, and under pnpm that succeeds exactly where Vite fails. Measured on the
199
- * sveltekit fixture:
200
- *
201
- * ['@testing-library/dom'] -> null
202
- * ['@reticlehq/browser', '@testing-library/dom'] -> null
203
- * ['@reticlehq/react', '@reticlehq/browser', '@testing-library/dom'] -> emitted
204
- *
205
- * So we emitted the three-segment chain, Vite could not follow it, and the boot warning this
206
- * function exists to prevent appeared anyway — `Failed to resolve dependency: …, present in
207
- * optimizeDeps.include`, pointing at Reticle, naming a package the developer has never heard of,
208
- * and forcing a full re-optimization on every cold start. The comment stated the rule correctly and
209
- * the code broke it.
210
- *
211
- * Dropping the nested form loses nothing that matters: the SDK itself is still pre-bundled, and Vite
212
- * follows its imports when it does that, so these deps are handled as part of it. Naming them
213
- * separately was belt-and-braces for a locally-aliased SDK, where the bare form resolves anyway.
194
+ * Read the daemon's auto-provisioned pairing token (~/.reticle/pairing-token, or the
195
+ * RETICLE_PAIRING_TOKEN_DIR override) so the served app can present it. Node-side only — a browser
196
+ * sandbox can't read the file, which is exactly why a rogue localhost app can't forge it. Best-effort:
197
+ * undefined if the daemon hasn't started yet (the page reloads once it has). Exported for testing.
214
198
  */
215
- export declare function cjsDepIncludes(appRoot: string, canResolve?: (dep: string) => boolean): string[];
216
199
  export declare function readPairingToken(): string | undefined;
217
200
  /** The body of the connect module — real imports, resolved by Vite when the module is served. */
218
201
  /**
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync } from 'node:fs';
1
+ import { existsSync, readFileSync } from 'node:fs';
2
2
  import { missingTokenWarning } from './missing-token.js';
3
3
  import { ensurePairingToken } from './ensure-token.js';
4
4
  import { homedir } from 'node:os';
@@ -150,43 +150,6 @@ function stamp(code, id) {
150
150
  * sandbox can't read the file, which is exactly why a rogue localhost app can't forge it. Best-effort:
151
151
  * undefined if the daemon hasn't started yet (the page reloads once it has). Exported for testing.
152
152
  */
153
- /**
154
- * CJS packages the browser SDK needs at runtime. Named, because a bare string here is exactly the
155
- * kind of thing that silently rots when a dependency is renamed.
156
- */
157
- const SDK_CJS_DEPS = {
158
- TESTING_LIBRARY: '@testing-library/dom',
159
- ARIA_QUERY: 'aria-query',
160
- };
161
- /**
162
- * Name each CJS dep ONLY in the bare form, and only when the app root can resolve it.
163
- *
164
- * This used to try three layouts and emit Vite's nested `a > b > c` form when a hoisted lookup
165
- * failed. The guard asked the wrong question: it tested NODE resolvability, walking the chain
166
- * segment by segment, and under pnpm that succeeds exactly where Vite fails. Measured on the
167
- * sveltekit fixture:
168
- *
169
- * ['@testing-library/dom'] -> null
170
- * ['@reticlehq/browser', '@testing-library/dom'] -> null
171
- * ['@reticlehq/react', '@reticlehq/browser', '@testing-library/dom'] -> emitted
172
- *
173
- * So we emitted the three-segment chain, Vite could not follow it, and the boot warning this
174
- * function exists to prevent appeared anyway — `Failed to resolve dependency: …, present in
175
- * optimizeDeps.include`, pointing at Reticle, naming a package the developer has never heard of,
176
- * and forcing a full re-optimization on every cold start. The comment stated the rule correctly and
177
- * the code broke it.
178
- *
179
- * Dropping the nested form loses nothing that matters: the SDK itself is still pre-bundled, and Vite
180
- * follows its imports when it does that, so these deps are handled as part of it. Naming them
181
- * separately was belt-and-braces for a locally-aliased SDK, where the bare form resolves anyway.
182
- */
183
- export function cjsDepIncludes(appRoot,
184
- // Injected so the rule can be tested hermetically. Real module resolution is not: under vitest,
185
- // `createRequire` from a directory that does not exist still resolves packages out of the runner's
186
- // own graph, so a filesystem-based test of "nothing is reachable here" silently asserts nothing.
187
- canResolve = (dep) => null !== resolvableChain([dep], appRoot)) {
188
- return [SDK_CJS_DEPS.TESTING_LIBRARY, SDK_CJS_DEPS.ARIA_QUERY].filter(canResolve);
189
- }
190
153
  export function readPairingToken() {
191
154
  const override = process.env[ReticleEnv.PAIRING_TOKEN_DIR];
192
155
  const dir = override !== undefined && override.length > 0 ? override : join(homedir(), ReticleDir.ROOT);
@@ -292,6 +255,22 @@ export function findDevModule(root, exists) {
292
255
  * missing export.
293
256
  */
294
257
  export function installedSdk(appRoot, canResolve = (dep) => null !== resolvableChain([dep], appRoot)) {
258
+ try {
259
+ const pkgPath = join(appRoot, 'package.json');
260
+ if (existsSync(pkgPath)) {
261
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
262
+ const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
263
+ if (deps[RETICLE_SENSOR] !== undefined && deps[RETICLE_PACKAGE] === undefined) {
264
+ return { specifier: RETICLE_SENSOR, usesInstall: false };
265
+ }
266
+ if (deps[RETICLE_PACKAGE] !== undefined) {
267
+ return { specifier: RETICLE_PACKAGE, usesInstall: true };
268
+ }
269
+ }
270
+ }
271
+ catch {
272
+ // Ignore read or parse failures when checking dependencies
273
+ }
295
274
  if (canResolve(RETICLE_PACKAGE))
296
275
  return { specifier: RETICLE_PACKAGE, usesInstall: true };
297
276
  if (canResolve(RETICLE_SENSOR))
@@ -305,7 +284,13 @@ export function connectModuleSource(options, devModule = null) {
305
284
  const sdk = installedSdk(options.root ?? process.cwd());
306
285
  const named = sdk.usesInstall ? 'reticle, install' : 'reticle';
307
286
  const call = sdk.usesInstall ? 'install();\n' : '';
308
- const base = `import { ${named} } from '${sdk.specifier}';\n${call}reticle.connect(${args});\n`;
287
+ // The only place in a Vite app that can see hot updates. `import.meta.hot` exists per module and
288
+ // only for modules Vite serves through its own transform; the SDK is a dependency, pre-bundled by
289
+ // the optimizer, and gets no hot context however it is written — so the channel is handed to it
290
+ // from here and the SDK owns everything after that (including which events it cares about).
291
+ // Guarded, because a desktop build has no dev server and therefore no hot context at all.
292
+ const hot = `if (import.meta.hot) reticle.observeHotUpdates(import.meta.hot);\n`;
293
+ const base = `import { ${named} } from '${sdk.specifier}';\n${call}reticle.connect(${args});\n${hot}`;
309
294
  // AFTER connect: registerStore subscribes through the live SDK, and registering before there is a
310
295
  // session to report into drops the first diffs.
311
296
  return null === devModule ? base : `${base}import('${devModule}');\n`;
@@ -422,21 +407,11 @@ export function reticle(options = {}) {
422
407
  ...(true === options.desktop ? {} : { apply: 'serve' }),
423
408
  enforce: 'pre',
424
409
  /**
425
- * Declare the SDK's CJS runtime deps so Vite pre-bundles them.
426
- *
427
- * `@testing-library/dom` is what `by: role` matching runs on, and it pulls CJS `aria-query`. When
428
- * the SDK resolves from OUTSIDE the app's root — a linked package, a pnpm workspace, `npm link`,
429
- * a monorepo alias — Vite skips pre-bundling and the named import dies with "does not provide an
430
- * export named 'elementRoles'". That takes the WHOLE SDK down before connect() runs, so there is
431
- * no session, no Reticle-side error, and only a console SyntaxError naming a package the
432
- * developer has never heard of. Measured on the react-admin demo with the SDK aliased to a local
433
- * checkout: zero sessions, and it looked like the app was failing to render.
410
+ * Declare the SDK itself and the optimizer cache fingerprint.
434
411
  *
435
- * Declaring them is free when Vite would have found them anyway but only when they are
436
- * actually installed. Naming a package that is not there makes Vite log `Failed to resolve
437
- * dependency: …, present in optimizeDeps.include` on every boot, which is a scary line pointing
438
- * at Reticle for a problem that does not exist. SvelteKit apps hit exactly that: nothing in that
439
- * tree depends on @testing-library/dom.
412
+ * The browser SDK used to need extra CJS query-engine deps here. It no longer imports that
413
+ * second accessibility engine, so keeping those names would make Vite pre-bundle packages the
414
+ * app may not have and blame Reticle for a false `Failed to resolve dependency` warning.
440
415
  */
441
416
  config(config) {
442
417
  // Everything below asks what the APP has installed, so every lookup is rooted here and never
@@ -517,9 +492,6 @@ export function reticle(options = {}) {
517
492
  // given the sensor produces the exact boot warning the note below is about, for a
518
493
  // package that is correctly absent.
519
494
  installedSdk(appRoot).specifier,
520
- // Only in a form that resolves — see above; a name Vite cannot resolve produces a boot
521
- // warning that blames Reticle, and a forced re-optimization on every cold start.
522
- ...cjsDepIncludes(appRoot),
523
495
  ],
524
496
  },
525
497
  };
@@ -24,10 +24,8 @@ export declare function isResolvable(specifier: string, from?: string): boolean;
24
24
  *
25
25
  * A single-segment chain is just the bare specifier, so this also answers "can the app see it
26
26
  * itself". Each further segment is resolved from the PREVIOUS package's directory, which is what
27
- * Vite does with the `>` form and the only way to name a dependency the app root cannot see: under
28
- * pnpm (and npm's nested layout) `@testing-library/dom` belongs to `@reticlehq/browser`, not to the
29
- * user's app. Naming it bare made Vite fail to resolve it and force a re-optimization on every cold
30
- * boot. SvelteKit ships `svelte > clsx` for the same reason.
27
+ * Vite does with the `>` form and the only way to name a dependency the app root cannot see under
28
+ * pnpm or npm's nested layout. SvelteKit ships `svelte > clsx` for the same reason.
31
29
  */
32
30
  export declare function resolvableChain(chain: readonly string[], from: string): string | null;
33
31
  /** The installed SDK's package version, for the HELLO's `sdkVersion`. Node-side only. */
package/dist/installed.js CHANGED
@@ -15,7 +15,7 @@
15
15
  * Silently, for every pnpm user, with no error anywhere.
16
16
  */
17
17
  import { existsSync, readFileSync, statSync } from 'node:fs';
18
- import { dirname, join } from 'node:path';
18
+ import { dirname, join, isAbsolute, resolve } from 'node:path';
19
19
  import { createRequire } from 'node:module';
20
20
  /** The React kit the host app imports the SDK from. Mirrors the constant in index.ts. */
21
21
  const RETICLE_PACKAGE = '@reticlehq/react';
@@ -26,7 +26,8 @@ const MANIFEST_SEARCH_DEPTH = 5;
26
26
  * `process.cwd()` default matches how Vite itself defaults the root when the config omits it.
27
27
  */
28
28
  function requireFromApp(from) {
29
- return createRequire(join(from, 'package.json'));
29
+ const absoluteFrom = isAbsolute(from) ? from : resolve(process.cwd(), from);
30
+ return createRequire(join(absoluteFrom, 'package.json'));
30
31
  }
31
32
  /**
32
33
  * Whether a package can be resolved from the app. Used to avoid declaring an optimizeDeps entry for
@@ -74,10 +75,8 @@ function packageDirOf(specifier, from) {
74
75
  *
75
76
  * A single-segment chain is just the bare specifier, so this also answers "can the app see it
76
77
  * itself". Each further segment is resolved from the PREVIOUS package's directory, which is what
77
- * Vite does with the `>` form and the only way to name a dependency the app root cannot see: under
78
- * pnpm (and npm's nested layout) `@testing-library/dom` belongs to `@reticlehq/browser`, not to the
79
- * user's app. Naming it bare made Vite fail to resolve it and force a re-optimization on every cold
80
- * boot. SvelteKit ships `svelte > clsx` for the same reason.
78
+ * Vite does with the `>` form and the only way to name a dependency the app root cannot see under
79
+ * pnpm or npm's nested layout. SvelteKit ships `svelte > clsx` for the same reason.
81
80
  */
82
81
  export function resolvableChain(chain, from) {
83
82
  let base = from;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reticlehq/vite-plugin",
3
- "version": "2.10.0",
3
+ "version": "2.12.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",
@@ -41,8 +41,8 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@babel/core": "^7.26.0",
44
- "@reticlehq/babel-plugin": "2.10.0",
45
- "@reticlehq/core": "2.10.0"
44
+ "@reticlehq/babel-plugin": "2.12.0",
45
+ "@reticlehq/core": "2.12.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/babel__core": "^7.20.5",