@reticlehq/vite-plugin 3.9.0 → 3.10.1

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
@@ -6019,6 +6019,16 @@ var EventType = {
6019
6019
  DOM_TEXT: "dom.text",
6020
6020
  NET_REQUEST: "net.request",
6021
6021
  NET_PENDING: "net.pending",
6022
+ /**
6023
+ * A fetch or XHR that the browser recorded in resource timing, and that no patched transport saw.
6024
+ *
6025
+ * The app sent it through a `fetch` reference it saved before Reticle patched `fetch`. It is NOT a
6026
+ * `net.request`: it has no method, and its status is only a hint (0 cross-origin without
6027
+ * `Timing-Allow-Origin`). A second record for one call would also raise a false duplicate. It
6028
+ * exists so a `net` miss over its URL reads `unknown`, not `no`.
6029
+ * `data: { url, urlRaw?, initiator, status? }`.
6030
+ */
6031
+ NET_UNPATCHED: "net.unpatched",
6022
6032
  /** An SSE (EventSource) or WebSocket frame — a message on a long-lived streaming connection. */
6023
6033
  NET_STREAM: "net.stream",
6024
6034
  /** A web-perf metric a screenshot can't verify: LCP, cumulative layout shift, or a long task. */
@@ -6347,6 +6357,7 @@ var RING_BUFFER_DEFAULTS = {
6347
6357
  MAX_BYTES: TRANSPORT_LIMITS.MAX_BUFFER_BYTES
6348
6358
  };
6349
6359
  var RETICLE_RENDER_PREHOOK = "__reticleRenderPreHook";
6360
+ var RETICLE_EARLY_CAPTURE = "__reticleEarlyCapture";
6350
6361
  var CONSOLE_LEVEL_PREFIX = "console.";
6351
6362
  var CONSOLE_LEVELS = [
6352
6363
  EventType.CONSOLE_LOG,
@@ -6355,6 +6366,9 @@ var CONSOLE_LEVELS = [
6355
6366
  EventType.CONSOLE_INFO
6356
6367
  ].map((type) => type.slice(CONSOLE_LEVEL_PREFIX.length));
6357
6368
 
6369
+ // ../../../core/dist/wire/constants/console-event.js
6370
+ var RETICLE_PRE_ATTACH_ERRORS = "__reticlePreAttach";
6371
+
6358
6372
  // ../../../core/dist/identity/source-constants.js
6359
6373
  var DATA_RETICLE_SOURCE_ATTR = "data-reticle-source";
6360
6374
  var RETICLE_ROOT_GLOBAL = "__RETICLE_ROOT__";
@@ -7260,6 +7274,27 @@ function isVitestBrowserServer(config2) {
7260
7274
  return true === browser.enabled;
7261
7275
  }
7262
7276
 
7277
+ // src/pre-attach-errors.ts
7278
+ var PRE_ATTACH_ERRORS_LIMIT = 50;
7279
+ var PRE_ATTACH_ERRORS_SOURCE = `(function(){try{
7280
+ var P='${RETICLE_PRE_ATTACH_ERRORS}',D='${RETICLE_EARLY_CAPTURE}',g=globalThis;
7281
+ if(g[P]!==undefined||g[D]!==undefined||typeof g.addEventListener!=='function')return;
7282
+ var B={open:true},q=[],n=0;
7283
+ g[P]=B;
7284
+ var keep=function(item){if(!B.open)return;if(q.length<${String(PRE_ATTACH_ERRORS_LIMIT)}){q.push(item);}else{n++;}};
7285
+ var onEvent=function(e){keep({event:e});};
7286
+ g.addEventListener('error',onEvent,true);
7287
+ g.addEventListener('unhandledrejection',onEvent,true);
7288
+ var c=g.console,ne=c&&c.error;
7289
+ if(typeof ne==='function'){c.error=function(){keep({args:Array.prototype.slice.call(arguments)});return ne.apply(this,arguments);};}
7290
+ B.drain=function(onError,onRejection,onConsole,dropped){
7291
+ if(!B.open)return;
7292
+ var kept=q,i,it;B.open=false;q=[];
7293
+ g.removeEventListener('error',onEvent,true);g.removeEventListener('unhandledrejection',onEvent,true);
7294
+ for(i=0;i<kept.length;i++){it=kept[i];try{dropped(i===0?n:0);
7295
+ if(it.args){onConsole('error',it.args);}else if(it.event.type==='unhandledrejection'){onRejection(it.event);}else{onError(it.event);}}catch(e){}}};
7296
+ }catch(e){}})();`;
7297
+
7263
7298
  // src/index.ts
7264
7299
  var RETICLE_PACKAGE2 = "@reticlehq/react";
7265
7300
  var RETICLE_SENSOR = "@reticlehq/browser";
@@ -7637,6 +7672,10 @@ ${code}`;
7637
7672
  if (!inject || desktop) return [];
7638
7673
  if (true !== options.inject && vitestBrowser) return [];
7639
7674
  return [
7675
+ // Classic and inline for the same reason as the render pre-hook below, and first: it has to
7676
+ // be listening before anything else on the page can load, fail or throw. See
7677
+ // PRE_ATTACH_ERRORS_SOURCE.
7678
+ { tag: "script", children: PRE_ATTACH_ERRORS_SOURCE, injectTo: "head-prepend" },
7640
7679
  // A CLASSIC inline script in <head>, and it has to be both.
7641
7680
  //
7642
7681
  // React reads `__REACT_DEVTOOLS_GLOBAL_HOOK__` when its renderer injects — which happens as
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ export const RETICLE_CONNECT_MODULE = '/@reticle-connect';
49
49
  */
50
50
  import { mergeIgnored } from './watch-ignore.js';
51
51
  import { isVitestBrowserServer } from './vitest-browser.js';
52
+ import { PRE_ATTACH_ERRORS_SOURCE } from './pre-attach-errors.js';
52
53
  export function connectModuleUrl(base) {
53
54
  if (undefined === base || !base.startsWith('/'))
54
55
  return RETICLE_CONNECT_MODULE;
@@ -657,6 +658,10 @@ export function reticle(options = {}) {
657
658
  if (true !== options.inject && vitestBrowser)
658
659
  return [];
659
660
  return [
661
+ // Classic and inline for the same reason as the render pre-hook below, and first: it has to
662
+ // be listening before anything else on the page can load, fail or throw. See
663
+ // PRE_ATTACH_ERRORS_SOURCE.
664
+ { tag: 'script', children: PRE_ATTACH_ERRORS_SOURCE, injectTo: 'head-prepend' },
660
665
  // A CLASSIC inline script in <head>, and it has to be both.
661
666
  //
662
667
  // React reads `__REACT_DEVTOOLS_GLOBAL_HOOK__` when its renderer injects — which happens as
@@ -0,0 +1,26 @@
1
+ /** How many errors the pre-attach buffer keeps. The first ones name the cause; later ones are counted. */
2
+ export declare const PRE_ATTACH_ERRORS_LIMIT = 50;
3
+ /**
4
+ * The pre-attach error buffer, as source for an inline <head> script (#1540).
5
+ *
6
+ * The SDK installs its console observer in `connect()`, and the connect module runs after the app's
7
+ * entry module. So an entry module that 404s, is served as HTML or throws, a rejection, or a
8
+ * `console.error` during start-up all happened while nothing was listening: the agent saw an empty
9
+ * page and an empty console, and could not tell a blank page from an app that crashed on load.
10
+ *
11
+ * This runs during parse, before any module. It keeps the raw `error` events (capture phase, because
12
+ * a failed `<script>` dispatches on the element and does not bubble), the unhandled rejections and
13
+ * the `console.error` arguments. When the SDK's console observer installs, it calls
14
+ * `drain(onError, onRejection, onConsole, dropped)` once. The buffer stops keeping and removes its
15
+ * listeners, then hands each entry to the SDK's own handler. Before each one it calls `dropped`:
16
+ * with the count of the entries it did not keep before the first, and with 0 after that. The SDK
17
+ * marks what it gets during this call as pre-attach itself. The handling code lives here and not
18
+ * in the SDK, so a page pays nothing for it in the SDK bundle.
19
+ * The `console.error` wrapper stays in the chain after that and only calls through.
20
+ *
21
+ * It does not install on a page Reticle drives: that page already has the pool's early capture
22
+ * (RETICLE_EARLY_CAPTURE), which hands the same errors to the SDK.
23
+ *
24
+ * The same rules as the render pre-hook: dependency-free ES5 in a try/catch.
25
+ */
26
+ export declare const PRE_ATTACH_ERRORS_SOURCE: string;
@@ -0,0 +1,44 @@
1
+ import { RETICLE_EARLY_CAPTURE, RETICLE_PRE_ATTACH_ERRORS } from '@reticlehq/core';
2
+ /** How many errors the pre-attach buffer keeps. The first ones name the cause; later ones are counted. */
3
+ export const PRE_ATTACH_ERRORS_LIMIT = 50;
4
+ /**
5
+ * The pre-attach error buffer, as source for an inline <head> script (#1540).
6
+ *
7
+ * The SDK installs its console observer in `connect()`, and the connect module runs after the app's
8
+ * entry module. So an entry module that 404s, is served as HTML or throws, a rejection, or a
9
+ * `console.error` during start-up all happened while nothing was listening: the agent saw an empty
10
+ * page and an empty console, and could not tell a blank page from an app that crashed on load.
11
+ *
12
+ * This runs during parse, before any module. It keeps the raw `error` events (capture phase, because
13
+ * a failed `<script>` dispatches on the element and does not bubble), the unhandled rejections and
14
+ * the `console.error` arguments. When the SDK's console observer installs, it calls
15
+ * `drain(onError, onRejection, onConsole, dropped)` once. The buffer stops keeping and removes its
16
+ * listeners, then hands each entry to the SDK's own handler. Before each one it calls `dropped`:
17
+ * with the count of the entries it did not keep before the first, and with 0 after that. The SDK
18
+ * marks what it gets during this call as pre-attach itself. The handling code lives here and not
19
+ * in the SDK, so a page pays nothing for it in the SDK bundle.
20
+ * The `console.error` wrapper stays in the chain after that and only calls through.
21
+ *
22
+ * It does not install on a page Reticle drives: that page already has the pool's early capture
23
+ * (RETICLE_EARLY_CAPTURE), which hands the same errors to the SDK.
24
+ *
25
+ * The same rules as the render pre-hook: dependency-free ES5 in a try/catch.
26
+ */
27
+ export const PRE_ATTACH_ERRORS_SOURCE = `(function(){try{
28
+ var P='${RETICLE_PRE_ATTACH_ERRORS}',D='${RETICLE_EARLY_CAPTURE}',g=globalThis;
29
+ if(g[P]!==undefined||g[D]!==undefined||typeof g.addEventListener!=='function')return;
30
+ var B={open:true},q=[],n=0;
31
+ g[P]=B;
32
+ var keep=function(item){if(!B.open)return;if(q.length<${String(PRE_ATTACH_ERRORS_LIMIT)}){q.push(item);}else{n++;}};
33
+ var onEvent=function(e){keep({event:e});};
34
+ g.addEventListener('error',onEvent,true);
35
+ g.addEventListener('unhandledrejection',onEvent,true);
36
+ var c=g.console,ne=c&&c.error;
37
+ if(typeof ne==='function'){c.error=function(){keep({args:Array.prototype.slice.call(arguments)});return ne.apply(this,arguments);};}
38
+ B.drain=function(onError,onRejection,onConsole,dropped){
39
+ if(!B.open)return;
40
+ var kept=q,i,it;B.open=false;q=[];
41
+ g.removeEventListener('error',onEvent,true);g.removeEventListener('unhandledrejection',onEvent,true);
42
+ for(i=0;i<kept.length;i++){it=kept[i];try{dropped(i===0?n:0);
43
+ if(it.args){onConsole('error',it.args);}else if(it.event.type==='unhandledrejection'){onRejection(it.event);}else{onError(it.event);}}catch(e){}}};
44
+ }catch(e){}})();`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reticlehq/vite-plugin",
3
- "version": "3.9.0",
3
+ "version": "3.10.1",
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,15 +41,15 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@babel/core": "^7.26.0",
44
- "@reticlehq/babel-plugin": "3.9.0",
45
- "@reticlehq/core": "3.9.0"
44
+ "@reticlehq/babel-plugin": "3.10.1",
45
+ "@reticlehq/core": "3.10.1"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/babel__core": "^7.20.5",
49
49
  "esbuild": "^0.28.2",
50
- "svelte": "^5.57.1",
50
+ "svelte": "^5.57.3",
51
51
  "vite": "^8",
52
- "@reticlehq/react": "3.9.0"
52
+ "@reticlehq/react": "3.10.1"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "vite": ">=4"