@taiga-ai/monitor-web 0.1.0-rc.3 → 0.2.0-dev.9

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A tiny, self-contained **Real User Monitoring (RUM) beacon** for web apps built with [Taiga](https://tai.ga). It reports how your app behaves in real browsers — Core Web Vitals, JavaScript errors, and client-observed API health — back to your Taiga project's Monitoring surface.
4
4
 
5
- - **~3.7 KiB gzipped**, zero runtime dependencies (Google's [`web-vitals`](https://github.com/GoogleChrome/web-vitals) is inlined at build time).
5
+ - **~4.8 KiB gzipped**, zero runtime dependencies (Google's [`web-vitals`](https://github.com/GoogleChrome/web-vitals) is inlined at build time).
6
6
  - **No cloud credentials, no server code.** Runs entirely in the browser using standard web APIs.
7
7
  - **Observe-only.** It never alters your responses, swallows your errors, or blocks the page — telemetry is strictly fire-and-forget and never throws into your app.
8
8
 
@@ -12,15 +12,20 @@ A tiny, self-contained **Real User Monitoring (RUM) beacon** for web apps built
12
12
  npm install @taiga-ai/monitor-web
13
13
  ```
14
14
 
15
- Then call `init()` once, as early as possible in your app's entry point:
15
+ Then call `init()` once, as early as possible in your app's entry point, with the **DSN** Taiga gives you for the environment:
16
16
 
17
17
  ```ts
18
18
  import { init } from '@taiga-ai/monitor-web';
19
19
 
20
- init({
21
- key: import.meta.env.VITE_TAIGA_MONITOR_KEY, // per-environment write-only ingest key
22
- url: import.meta.env.VITE_TAIGA_MONITOR_URL, // your Taiga /beacon endpoint
23
- });
20
+ init({ dsn: import.meta.env.VITE_TAIGA_MONITOR_DSN });
21
+ ```
22
+
23
+ The DSN is a single token — `https://<key>@<host>/beacon` — that carries both the ingest endpoint and a per-environment write-only key. Because Taiga mints it per environment, it always points at the right place; you only ever configure one value.
24
+
25
+ Prefer not to use a DSN? You can pass the endpoint and key separately instead:
26
+
27
+ ```ts
28
+ init({ key: import.meta.env.VITE_TAIGA_MONITOR_KEY, url: import.meta.env.VITE_TAIGA_MONITOR_URL });
24
29
  ```
25
30
 
26
31
  ### No build step? Use the global script
@@ -30,25 +35,26 @@ For static sites or apps without a bundler, load the IIFE global and call `Taiga
30
35
  ```html
31
36
  <script src="https://unpkg.com/@taiga-ai/monitor-web/dist/monitor-web.global.js"></script>
32
37
  <script>
33
- TaigaMonitor.init({ key: 'taiga_ing_…', url: 'https://…/beacon' });
38
+ TaigaMonitor.init({ dsn: 'https://taiga_ing_…@…/beacon' });
34
39
  </script>
35
40
  ```
36
41
 
37
42
  ## Configuration
38
43
 
39
- `init(config)` takes one object. Only `key` and `url` are required.
44
+ `init(config)` takes one object. Provide **either** a `dsn` (preferred) **or** a `key` + `url` pair.
40
45
 
41
- | Option | Type | Default | Description |
42
- | ----------------- | -------------------------- | ------- | --------------------------------------------------------------------------------------------------- |
43
- | `key` | `string` | — | Per-environment **write-only** ingest key (`taiga_ing_…`). Safe to ship in the client bundle. |
44
- | `url` | `string` | — | The Taiga `/beacon` ingest endpoint for this environment. |
45
- | `sampleRate` | `number` (0–1) | `1` | Fraction of sessions to instrument. Decided once per page load. |
46
- | `captureVitals` | `boolean` | `true` | Collect Core Web Vitals (LCP, INP, CLS, FCP, TTFB). |
47
- | `captureErrors` | `boolean` | `true` | Collect uncaught errors and unhandled promise rejections. |
48
- | `captureRequests` | `boolean` | `true` | Collect client-observed API calls (`fetch` + `XHR`): status and latency. |
49
- | `beforeSend` | `(event) => event \| null` | — | Transform each event before it is queued, or return `null` to drop it. Use for extra PII scrubbing. |
46
+ | Option | Type | Default | Description |
47
+ | ----------------- | -------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
48
+ | `dsn` | `string` | — | Per-environment ingest DSN, `https://<key>@<host>/beacon`. Encodes the endpoint + write-only key in one env-correct token. **Preferred.** |
49
+ | `key` | `string` | — | Per-environment **write-only** ingest key (`taiga_ing_…`). Safe to ship in the client bundle. Use with `url`, or prefer `dsn`. |
50
+ | `url` | `string` | — | The Taiga `/beacon` ingest endpoint for this environment. Use with `key`, or prefer `dsn`. |
51
+ | `sampleRate` | `number` (0–1) | `1` | Fraction of sessions to instrument. Decided once per page load. |
52
+ | `captureVitals` | `boolean` | `true` | Collect Core Web Vitals (LCP, INP, CLS, FCP, TTFB). |
53
+ | `captureErrors` | `boolean` | `true` | Collect uncaught errors and unhandled promise rejections. |
54
+ | `captureRequests` | `boolean` | `true` | Collect client-observed API calls (`fetch` + `XHR`): status and latency. |
55
+ | `beforeSend` | `(event) => event \| null` | — | Transform each event before it is queued, or return `null` to drop it. Use for extra PII scrubbing. |
50
56
 
51
- The `key`, `url`, and any of the flags are the _only_ configuration — there is nothing to set up inside the package itself.
57
+ The `dsn` (or `key` + `url`) and any of the flags are the _only_ configuration — there is nothing to set up inside the package itself.
52
58
 
53
59
  ## What it collects
54
60
 
@@ -62,7 +68,7 @@ Every measurement is sent as a small, self-describing event `{ kind, name?, valu
62
68
 
63
69
  URLs are scrubbed client-side before anything leaves the page — the query string and fragment (which routinely carry tokens, ids, and PII) are dropped, keeping only origin + path. Request and response bodies are never read. Use `beforeSend` to redact or drop anything else specific to your app.
64
70
 
65
- The `key` is **write-only**: it can submit telemetry to your environment's ingest but cannot read anything back, which is why it is safe to embed in a public client bundle.
71
+ The ingest key (whether passed directly or embedded in the `dsn`) is **write-only**: it can submit telemetry to your environment's ingest but cannot read anything back, which is why it is safe to embed in a public client bundle.
66
72
 
67
73
  ## Batching & delivery
68
74
 
package/dist/dsn.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { MonitorConfig, ResolvedConfig } from './types.js';
2
+ /**
3
+ * Parse a Taiga monitor DSN into its ingest key and endpoint URL.
4
+ *
5
+ * Format (Sentry-style): `https://<key>@<host>/<beacon-path>`, e.g.
6
+ * `https://taiga_ing_abc123@api.eu.tai.ga/beacon`. The key is the URL userinfo;
7
+ * the endpoint is origin + pathname (which carries any per-environment stage
8
+ * prefix, e.g. `/prod/beacon`). Query and fragment are dropped. On the wire the
9
+ * beacon still POSTs to `<endpoint>?k=<key>`, so this is a client-side wrapper
10
+ * only. Returns null for anything unparseable or missing a key.
11
+ */
12
+ export declare function parseDsn(dsn: string): {
13
+ key: string;
14
+ url: string;
15
+ } | null;
16
+ /**
17
+ * Resolve the ingest target from user config: a parseable `dsn` wins; otherwise
18
+ * fall back to an explicit `key` + `url` pair (so a mis-set DSN alongside a valid
19
+ * pair still works). Returns null when neither yields a usable target, so a
20
+ * misconfigured `init()` is a no-op rather than an error.
21
+ */
22
+ export declare function resolveTarget(config: MonitorConfig): ResolvedConfig | null;
package/dist/index.d.ts CHANGED
@@ -1,16 +1,18 @@
1
1
  import type { BeaconEvent, MonitorConfig } from './types.js';
2
2
  import { SDK_NAME, SDK_VERSION } from './version.js';
3
3
  export type { BeaconEvent, MonitorConfig };
4
+ export { parseDsn } from './dsn.js';
4
5
  export { SDK_NAME, SDK_VERSION };
5
6
  /**
6
7
  * Start the Taiga monitoring beacon. Safe to call once; extra calls are no-ops.
7
8
  * Collects Core Web Vitals, JS errors, and client-observed API calls, batches
8
- * them, and sends them to the ingest keyed by the write-only `key`. Everything is
9
- * fire-and-forget — the beacon never throws into the host app.
9
+ * them, and sends them to the ingest. Configure with a `dsn` (preferred) or an
10
+ * explicit `key` + `url`. Everything is fire-and-forget — the beacon never
11
+ * throws into the host app.
10
12
  *
11
13
  * ```ts
12
14
  * import { init } from '@taiga-ai/monitor-web';
13
- * init({ key: import.meta.env.VITE_TAIGA_MONITOR_KEY, url: import.meta.env.VITE_TAIGA_MONITOR_URL });
15
+ * init({ dsn: import.meta.env.VITE_TAIGA_MONITOR_DSN });
14
16
  * ```
15
17
  */
16
18
  export declare function init(config: MonitorConfig): void;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- const e=`@taiga-ai/monitor-web`,t=`0.1.0`;function n(){let e=globalThis.crypto;return e&&typeof e.randomUUID==`function`?e.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function r(e,t){return`${e}${e.includes(`?`)?`&`:`?`}k=${encodeURIComponent(t)}`}var i=class{constructor(e){this.config=e,this.queue=[],this.fetchImpl=globalThis.fetch?globalThis.fetch.bind(globalThis):void 0}enqueue(e){let t=e;if(this.config.beforeSend)try{t=this.config.beforeSend(e)}catch{return}t&&(this.queue.push(t),this.queue.length>=50?this.flush():this.scheduleFlush())}flush(){for(this.timer!==void 0&&(clearTimeout(this.timer),this.timer=void 0);this.queue.length>0;){let e=this.queue.splice(0,50);this.send(e)}}scheduleFlush(){this.timer===void 0&&(this.timer=setTimeout(()=>this.flush(),5e3))}send(i){let a;try{a=JSON.stringify({batchId:n(),meta:{sdk:e,sdkVersion:t,sentAt:new Date().toISOString()},events:i})}catch{return}let o=r(this.config.url,this.config.key);try{let e=globalThis.navigator;if(e&&typeof e.sendBeacon==`function`&&e.sendBeacon(o,new Blob([a],{type:`text/plain`})))return}catch{}try{this.fetchImpl?.(o,{method:`POST`,body:a,keepalive:!0,headers:{"content-type":`text/plain`},mode:`cors`})}catch{}}};let a=-1;const o=e=>{addEventListener(`pageshow`,t=>{t.persisted&&(a=t.timeStamp,e(t))},!0)},s=(e,t,n,r)=>{let i,a;return o=>{t.value>=0&&(o||r)&&(a=t.value-(i??0),(a||i===void 0)&&(i=t.value,t.delta=a,t.rating=((e,t)=>e>t[1]?`poor`:e>t[0]?`needs-improvement`:`good`)(t.value,n),e(t)))}},c=e=>{requestAnimationFrame(()=>requestAnimationFrame(e))},l=()=>{let e=performance.getEntriesByType(`navigation`)[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},u=()=>l()?.activationStart??0,d=(e,t=-1)=>{let n=l(),r=`navigate`;return a>=0?r=`back-forward-cache`:n&&(document.prerendering||u()>0?r=`prerender`:document.wasDiscarded?r=`restore`:n.type&&(r=n.type.replace(/_/g,`-`))),{name:e,value:t,rating:`good`,delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+0xe8d4a51000}`,navigationType:r}},f=new WeakMap;function p(e,t){return f.get(e)||f.set(e,new t),f.get(e)}var m=class{t;i=0;o=[];h(e){if(e.hadRecentInput)return;let t=this.o[0],n=this.o.at(-1);this.i&&t&&n&&e.startTime-n.startTime<1e3&&e.startTime-t.startTime<5e3?(this.i+=e.value,this.o.push(e)):(this.i=e.value,this.o=[e]),this.t?.(e)}};const h=(e,t,n={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let r=new PerformanceObserver(e=>{queueMicrotask(()=>{t(e.getEntries())})});return r.observe({type:e,buffered:!0,...n}),r}}catch{}},g=e=>{let t=!1;return()=>{t||=(e(),!0)}};let _=-1;const v=new Set,y=()=>document.visibilityState!==`hidden`||document.prerendering?1/0:0,b=e=>{if(document.visibilityState===`hidden`){if(e.type===`visibilitychange`)for(let e of v)e();isFinite(_)||(_=e.type===`visibilitychange`?e.timeStamp:0,removeEventListener(`prerenderingchange`,b,!0))}},x=()=>{if(_<0){let e=u();_=(document.prerendering?void 0:globalThis.performance.getEntriesByType(`visibility-state`).find(t=>t.name===`hidden`&&t.startTime>=e)?.startTime)??y(),addEventListener(`visibilitychange`,b,!0),addEventListener(`prerenderingchange`,b,!0),o(()=>{setTimeout(()=>{_=y()})})}return{get firstHiddenTime(){return _},onHidden(e){v.add(e)}}},S=e=>{document.prerendering?addEventListener(`prerenderingchange`,e,!0):e()},C=[1800,3e3],w=(e,t={})=>{S(()=>{let n=x(),r,i=d(`FCP`),a=h(`paint`,e=>{for(let t of e)t.name===`first-contentful-paint`&&(a.disconnect(),t.startTime<n.firstHiddenTime&&(i.value=Math.max(t.startTime-u(),0),i.entries.push(t),r(!0)))});a&&(r=s(e,i,C,t.reportAllChanges),o(n=>{i=d(`FCP`),r=s(e,i,C,t.reportAllChanges),c(()=>{i.value=performance.now()-n.timeStamp,r(!0)})}))})},T=[.1,.25],E=(e,t={})=>{let n=x();w(g(()=>{let r,i=d(`CLS`,0),a=p(t,m),l=e=>{for(let t of e)a.h(t);a.i>i.value&&(i.value=a.i,i.entries=a.o,r())},u=h(`layout-shift`,l);u&&(r=s(e,i,T,t.reportAllChanges),n.onHidden(()=>{l(u.takeRecords()),r(!0)}),o(()=>{a.i=0,i=d(`CLS`,0),r=s(e,i,T,t.reportAllChanges),c(r)}),setTimeout(r))}))};let D=0,O=1/0,k=0;const ee=e=>{for(let t of e)t.interactionId&&(O=Math.min(O,t.interactionId),k=Math.max(k,t.interactionId),D=k?(k-O)/7+1:0)};let A;const j=()=>A?D:performance.interactionCount??0,M=()=>{`interactionCount`in performance||A||(A=h(`event`,ee,{durationThreshold:0}))};let N=0;var P=class{l=[];u=new Map;m;p;v(){N=j(),this.l.length=0,this.u.clear()}T(){let e=Math.min(this.l.length-1,Math.floor((j()-N)/50));return this.l[e]}h(e){if(this.m?.(e),!e.interactionId&&e.entryType!==`first-input`)return;let t=this.l.at(-1),n=this.u.get(e.interactionId);if(n||this.l.length<10||e.duration>t.L){if(n?e.duration>n.L?(n.entries=[e],n.L=e.duration):e.duration===n.L&&e.startTime===n.entries[0].startTime&&n.entries.push(e):(n={id:e.interactionId,entries:[e],L:e.duration},this.u.set(n.id,n),this.l.push(n)),this.l.sort((e,t)=>t.L-e.L),this.l.length>10){let e=this.l.splice(10);for(let t of e)this.u.delete(t.id)}this.p?.(n)}}};const F=e=>{let t=globalThis.requestIdleCallback||setTimeout,n=globalThis.cancelIdleCallback||clearTimeout;if(document.visibilityState===`hidden`)e();else{let r=g(e),i=-1,a=()=>{n(i),r()};addEventListener(`visibilitychange`,a,{once:!0,capture:!0}),i=t(()=>{removeEventListener(`visibilitychange`,a,{capture:!0}),r()})}},I=[200,500],L=(e,t={})=>{if(!globalThis.PerformanceEventTiming||!(`interactionId`in PerformanceEventTiming.prototype))return;let n=x();S(()=>{M();let r,i=d(`INP`),a=p(t,P),c=e=>{F(()=>{for(let t of e)a.h(t);let t=a.T();t&&t.L!==i.value&&(i.value=t.L,i.entries=t.entries,r())})},l=h(`event`,c,{durationThreshold:t.durationThreshold??40});r=s(e,i,I,t.reportAllChanges),l&&(l.observe({type:`first-input`,buffered:!0}),n.onHidden(()=>{c(l.takeRecords()),r(!0)}),o(()=>{a.v(),i=d(`INP`),r=s(e,i,I,t.reportAllChanges)}))})};var R=class{m;h(e){this.m?.(e)}};const z=[2500,4e3],B=(e,t={})=>{S(()=>{let n=x(),r,i=d(`LCP`),a=p(t,R),l=e=>{t.reportAllChanges||(e=e.slice(-1));for(let t of e)a.h(t),t.startTime<n.firstHiddenTime&&(i.value=Math.max(t.startTime-u(),0),i.entries=[t],r())},f=h(`largest-contentful-paint`,l);if(f){r=s(e,i,z,t.reportAllChanges);let n=g(()=>{l(f.takeRecords()),f.disconnect(),r(!0)}),a=e=>{e.isTrusted&&(F(n),removeEventListener(e.type,a,{capture:!0}))};for(let e of[`keydown`,`click`,`visibilitychange`])addEventListener(e,a,{capture:!0});o(n=>{i=d(`LCP`),r=s(e,i,z,t.reportAllChanges),c(()=>{i.value=performance.now()-n.timeStamp,r(!0)})})}})},V=[800,1800],H=e=>{document.prerendering?S(()=>H(e)):document.readyState===`complete`?setTimeout(e):addEventListener(`load`,()=>H(e),!0)},U=(e,t={})=>{let n=d(`TTFB`),r=s(e,n,V,t.reportAllChanges);H(()=>{let i=l();i&&(n.value=Math.max(i.responseStart-u(),0),n.entries=[i],r(!0),o(()=>{n=d(`TTFB`,0),r=s(e,n,V,t.reportAllChanges),r(!0)}))})},W={LCP:`ms`,INP:`ms`,FCP:`ms`,TTFB:`ms`,CLS:`score`};function G(e){let t=t=>{e({kind:`web_vital`,name:t.name,value:t.value,unit:W[t.name]??`ms`,attributes:{rating:t.rating,id:t.id,navigationType:t.navigationType},occurredAt:new Date().toISOString()})};B(t),L(t),E(t),w(t),U(t)}function K(e,t=2048){let n=globalThis.location?.href;try{let r=new URL(e,n);return`${r.origin}${r.pathname}`.slice(0,t)}catch{return(e??``).split(`?`)[0].split(`#`)[0].slice(0,t)}}function q(e,t){return String(e??``).slice(0,t)}function J(e){globalThis.addEventListener(`error`,t=>{let n=t.error;e({kind:`error`,name:n?.name??`Error`,attributes:{message:q(t.message,1e3),stack:n?.stack?q(n.stack,4e3):void 0,url:K(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})}),globalThis.addEventListener(`unhandledrejection`,t=>{let n=t.reason;e({kind:`error`,name:`unhandledrejection`,attributes:{message:q(n?.message??n,1e3),stack:n?.stack?q(n.stack,4e3):void 0,url:K(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})})}const Y=Symbol.for(`taiga.monitor.fetch`),X=Symbol.for(`taiga.monitor.xhr`);function Z(){return globalThis.performance?.now?.()??Date.now()}function Q(e,t,n,r){let i=K(t);return{kind:`api_call`,name:`${e} ${i}`.slice(0,120),value:Math.round(r),unit:`ms`,attributes:{method:e,url:i,statusCode:n},occurredAt:new Date().toISOString()}}function te(e,t){return(t?.method??(typeof e==`object`&&`method`in e?e.method:void 0)??`GET`).toUpperCase()}function ne(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function re(e){let t=globalThis,n=t.fetch;typeof n!=`function`||t[Y]||(t[Y]=!0,t.fetch=function(...t){let r=Z(),i=te(t[0],t[1]),a=ne(t[0]);return Reflect.apply(n,this,t).then(t=>{try{e(Q(i,a,t.status,Z()-r))}catch{}return t},t=>{try{e(Q(i,a,0,Z()-r))}catch{}throw t})})}function ie(e){let t=globalThis.XMLHttpRequest,n=t?.prototype;if(!t||!n||n[X])return;let r=n.open,i=n.send,a=Symbol.for(`taiga.monitor.xhrctx`);n.open=function(e,t,...n){return this[a]={method:String(e).toUpperCase(),url:String(t),start:0},r.apply(this,[e,t,...n])},n.send=function(...t){let n=this[a];return n&&(n.start=Z(),this.addEventListener(`loadend`,()=>{try{e(Q(n.method,n.url,this.status,Z()-n.start))}catch{}},{once:!0})),i.apply(this,t)},n[X]=!0}let $=!1;function ae(e){if($||!e?.key||!e?.url||globalThis.window===void 0)return;$=!0;let t=e.sampleRate??1;if(!(t<1&&Math.random()>=t))try{let t=new i(e),n=e=>t.enqueue(e);e.captureVitals!==!1&&G(n),e.captureErrors!==!1&&J(n),e.captureRequests!==!1&&(re(n),ie(n));let r=()=>t.flush();globalThis.addEventListener(`visibilitychange`,()=>{globalThis.document?.visibilityState===`hidden`&&r()}),globalThis.addEventListener(`pagehide`,r)}catch{$=!1}}function oe(){$=!1}export{e as SDK_NAME,t as SDK_VERSION,oe as __resetForTests,ae as init};
1
+ const e=`@taiga-ai/monitor-web`,t=`0.2.0`;function n(){let e=globalThis.crypto;return e&&typeof e.randomUUID==`function`?e.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function r(e,t){return`${e}${e.includes(`?`)?`&`:`?`}k=${encodeURIComponent(t)}`}var i=class{constructor(e){this.config=e,this.queue=[],this.fetchImpl=globalThis.fetch?globalThis.fetch.bind(globalThis):void 0}enqueue(e){let t=e;if(this.config.beforeSend)try{t=this.config.beforeSend(e)}catch{return}t&&(this.queue.push(t),this.queue.length>=50?this.flush():this.scheduleFlush())}flush(){for(this.timer!==void 0&&(clearTimeout(this.timer),this.timer=void 0);this.queue.length>0;){let e=this.queue.splice(0,50);this.send(e)}}scheduleFlush(){this.timer===void 0&&(this.timer=setTimeout(()=>this.flush(),5e3))}send(i){let a;try{a=JSON.stringify({batchId:n(),meta:{sdk:e,sdkVersion:t,sentAt:new Date().toISOString()},events:i})}catch{return}let o=r(this.config.url,this.config.key);try{let e=globalThis.navigator;if(e&&typeof e.sendBeacon==`function`&&e.sendBeacon(o,new Blob([a],{type:`text/plain`})))return}catch{}try{this.fetchImpl?.(o,{method:`POST`,body:a,keepalive:!0,headers:{"content-type":`text/plain`},mode:`cors`})}catch{}}};function a(e){try{let t=new URL(e);if(t.protocol!==`https:`&&t.protocol!==`http:`)return null;let n=decodeURIComponent(t.username);return n?(t.username=``,t.password=``,{key:n,url:`${t.origin}${t.pathname}`}):null}catch{return null}}function o(e){let t=(e.dsn?a(e.dsn):null)??(e.key&&e.url?{key:e.key,url:e.url}:null);return t?{...t,beforeSend:e.beforeSend}:null}let s=-1;const c=()=>s,l=e=>{addEventListener(`pageshow`,t=>{t.persisted&&(s=t.timeStamp,e(t))},!0)},u=(e,t,n,r)=>{let i,a;return o=>{t.value>=0&&(o||r)&&(a=t.value-(i??0),(a||i===void 0)&&(i=t.value,t.delta=a,t.rating=((e,t)=>e>t[1]?`poor`:e>t[0]?`needs-improvement`:`good`)(t.value,n),e(t)))}},d=e=>{requestAnimationFrame(()=>requestAnimationFrame(e))},f=()=>{let e=performance.getEntriesByType(`navigation`)[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},p=()=>f()?.activationStart??0;let m=-1;const h=new Set,g=()=>document.visibilityState!==`hidden`||document.prerendering?1/0:0,_=e=>{if(document.visibilityState===`hidden`){if(e.type===`visibilitychange`)for(let e of h)e();isFinite(m)||(m=e.type===`visibilitychange`?e.timeStamp:0,removeEventListener(`prerenderingchange`,_,!0))}},v=(e=!1)=>{if(e&&(m=1/0),m<0){let e=p();m=(document.prerendering?void 0:globalThis.performance.getEntriesByType(`visibility-state`).find(t=>t.name===`hidden`&&t.startTime>=e)?.startTime)??g(),addEventListener(`visibilitychange`,_,!0),addEventListener(`prerenderingchange`,_,!0),l(()=>{setTimeout(()=>{m=g()})})}return{get firstHiddenTime(){return m},onHidden(e){h.add(e)}}},y=(e,t=-1,n,r=0,i,a,o)=>{let s=f(),l=s?.navigationId||0,u=`navigate`;return n?u=n:c()>=0?u=`back-forward-cache`:s&&(document.prerendering||p()>0?u=`prerender`:document.wasDiscarded?u=`restore`:s.type&&(u=s.type.replace(/_/g,`-`))),{name:e,value:t,rating:`good`,delta:0,entries:[],id:`v6-${Date.now()}-${Math.floor(8999999999999*Math.random())+0xe8d4a51000}`,navigationType:u,navigationId:r||l,navigationInteractionId:i,navigationURL:a||s?.name,navigationStartTime:o||0}},b=new WeakMap;function x(e,t){let n=b.get(t);return n||(n=new WeakMap,b.set(t,n)),n.get(e)||n.set(e,new t),n.get(e)}var ee=class{t;i=0;o=[];h(e){if(e.hadRecentInput)return;let t=this.o[0],n=this.o.at(-1);this.i&&t&&n&&e.startTime-n.startTime<1e3&&e.startTime-t.startTime<5e3?(this.i+=e.value,this.o.push(e)):(this.i=e.value,this.o=[e]),this.t?.(e)}};const S=(e,t,n={})=>{try{let r=e.filter(e=>PerformanceObserver.supportedEntryTypes.includes(e));if(r.length>0){let e=new PerformanceObserver(e=>{queueMicrotask(()=>{let n=e.getEntries();r.length>1&&n.sort((e,t)=>e.startTime+e.duration-(t.startTime+t.duration)),t(n)})});for(let t of r)e.observe({type:t,buffered:!0,...n});return e}}catch{}},C=e=>globalThis.PerformanceObserver?.supportedEntryTypes.includes(`soft-navigation`)&&typeof globalThis.PerformanceSoftNavigation?.prototype?.getLargestInteractionContentfulPaint==`function`&&e&&e.reportSoftNavs,w=(e,t)=>{if(e.set(t.navigationId,t),e.size>2){let t=e.keys().next().value;t!==void 0&&e.delete(t)}},T=e=>{let t=!1;return()=>{t||=(e(),!0)}};var te=class{l};const E=e=>{document.prerendering?addEventListener(`prerenderingchange`,e,!0):e()},D=[1800,3e3],O=(e,t={})=>{let n=C(t);E(()=>{let r=x(t,te),i=v(),a,o=y(`FCP`),s=S([`paint`],e=>{for(let t of e)t.name===`first-contentful-paint`&&(s.disconnect(),t.startTime<i.firstHiddenTime&&(o.value=Math.max(t.startTime-p(),0),o.entries.push(t),o.navigationId=t.navigationId||o.navigationId,a(!0)))});s&&(a=u(e,o,D,t.reportAllChanges),l(n=>{o=y(`FCP`,-1,`back-forward-cache`,o.navigationId,o.navigationInteractionId,o.navigationURL,c()),a=u(e,o,D,t.reportAllChanges),d(()=>{o.value=performance.now()-n.timeStamp,a(!0)})})),n&&S([`soft-navigation`],n=>{n.forEach(n=>{r.l&&n.navigationId&&w(r.l,n);let i=Math.max((n.presentationTime||n.paintTime||0)-n.startTime,0);o=y(`FCP`,i,`soft-navigation`,n.navigationId,n.interactionId,n.name,n.startTime),a=u(e,o,D,t.reportAllChanges),a(!0)})},t)})},k=[.1,.25],A=(e,t={})=>{let n=v();O(T(()=>{let r,i=y(`CLS`,0),a=x(t,ee),o=(n,o,s,c,l)=>{i=y(`CLS`,0,n,o,s,c,l),a.i=0,r=u(e,i,k,t.reportAllChanges)},s=(e=!1)=>{a.i>i.value&&(i.value=a.i,i.entries=a.o),r(e)},f=e=>{s(!0),o(`soft-navigation`,e.navigationId,e.interactionId,e.name,e.startTime)},p=e=>{for(let t of e)t.entryType===`soft-navigation`?f(t):a.h(t);s()},m=[`layout-shift`];C(t)&&m.push(`soft-navigation`);let h=S(m,p);h&&(r=u(e,i,k,t.reportAllChanges),n.onHidden(()=>{p(h.takeRecords()),r(!0)}),l(()=>{o(`back-forward-cache`,i.navigationId,i.navigationInteractionId,i.navigationURL,c()),d(r)}),setTimeout(r))}))};let j=0,M=1/0,N=0;const ne=e=>{for(let t of e)t.interactionId&&(M=Math.min(M,t.interactionId),N=Math.max(N,t.interactionId),j=N?(N-M)/7+1:0)};let P;const F=()=>P?j:performance.interactionCount??0,re=()=>{`interactionCount`in performance||P||(P=S([`event`],ne,{durationThreshold:0}))};let I=0;var L=class{u=[];v=new Map;m;p;T(){I=F(),this.u.length=0,this.v.clear()}M(e){let t=F()-I,n=Math.min(this.u.length-1,Math.floor(t/50));return!t||n!==-1||e!==`soft-navigation`&&e!==`back-forward-cache`?this.u[n]:{_:8,id:-1,entries:[]}}h(e){if(this.m?.(e),!e.interactionId&&e.entryType!==`first-input`)return;let t=this.u.at(-1),n=this.v.get(e.interactionId);if(n||this.u.length<10||e.duration>t._){if(n?e.duration>n._?(n.entries=[e],n._=e.duration):e.duration===n._&&e.startTime===n.entries[0].startTime&&n.entries.push(e):(n={id:e.interactionId,entries:[e],_:e.duration},this.v.set(n.id,n),this.u.push(n)),this.u.sort((e,t)=>t._-e._),this.u.length>10){let e=this.u.splice(10);for(let t of e)this.v.delete(t.id)}this.p?.(n)}}};const R=e=>{let t=`requestIdleCallback`in globalThis?1e3:0,n=globalThis.requestIdleCallback||setTimeout,r=globalThis.cancelIdleCallback||clearTimeout;if(document.visibilityState===`hidden`)e();else{let i=T(e),a=-1,o=()=>{r(a),i()};addEventListener(`visibilitychange`,o,{once:!0,capture:!0}),a=n(()=>{removeEventListener(`visibilitychange`,o,{capture:!0}),i()},{timeout:t})}},z=[200,500],ie=(e,t={})=>{if(!globalThis.PerformanceEventTiming||!(`interactionId`in PerformanceEventTiming.prototype))return;let n=v();E(()=>{re();let r,i=y(`INP`),a=x(t,L),o=(n,o,s,c,l)=>{a.T(),i=y(`INP`,-1,n,o,s,c,l),r=u(e,i,z,t.reportAllChanges)},s=()=>{let e=a.M(i.navigationType);e&&e._!==i.value&&(i.value=e._,i.entries=e.entries,r())},d=e=>{s(),r(!0),o(`soft-navigation`,e.navigationId,e.interactionId,e.name,e.startTime)},f=(e,t=!1)=>{R(()=>{for(let t of e)t.entryType===`soft-navigation`?d(t):a.h(t);s(),t&&r(!0)})},p=[`event`,`first-input`];C(t)&&p.push(`soft-navigation`);let m=S(p,f,{...t,durationThreshold:t.durationThreshold??40});r=u(e,i,z,t.reportAllChanges),m&&(n.onHidden(()=>{f(m.takeRecords(),!0)}),l(()=>{o(`back-forward-cache`,i.navigationId,i.navigationInteractionId,i.navigationURL,c())}))})};var ae=class{m;l;h(e){this.m?.(e)}};const B=[2500,4e3],oe=(e,t={})=>{let n=!1,r=C(t);E(()=>{let i,a=v(),o=y(`LCP`),s=x(t,ae),f=(r,s,c,l,d)=>{o=y(`LCP`,-1,r,s,c,l,d),i=u(e,o,B,t.reportAllChanges),n=!1,r===`soft-navigation`&&(a=v(!0))},m=e=>{s.l&&e.navigationId&&w(s.l,e),n||i(!0),f(`soft-navigation`,e.navigationId,e.interactionId,e.name,e.startTime);let t=e.getLargestInteractionContentfulPaint?.();t&&h([t])},h=e=>{t.reportAllChanges||r||(e=e.slice(-1));for(let t of e){if(!t)continue;if(t.entryType===`soft-navigation`){m(t);continue}let e=0,n=[],r=t.startTime;if(t.entryType===`largest-contentful-paint`)e=Math.max(t.startTime-p(),0),s.h(t),n=[t];else if(t.entryType===`interaction-contentful-paint`){let i=t;if(!o.navigationId||`interactionId`in i&&i.interactionId!=o.navigationInteractionId)continue;r=i.largestContentfulPaint?.renderTime||0,e=Math.max(r-t.startTime,0),i.largestContentfulPaint&&(s.h(i.largestContentfulPaint),n=[i.largestContentfulPaint])}r<a.firstHiddenTime&&(o.value=e,o.entries=n,i())}},g=[`largest-contentful-paint`];r&&g.push(`interaction-contentful-paint`,`soft-navigation`);let _=S(g,h);if(_){i=u(e,o,B,t.reportAllChanges);let a=[`keydown`,`click`,`visibilitychange`],s=e=>{if(e.isTrusted&&!n){let e=o.id;R(()=>{if(!n){if(!r){_.disconnect();for(let e of a)removeEventListener(e,s,{capture:!0})}e===o.id&&(n=!0,i(!0))}})}};for(let e of a)addEventListener(e,s,{capture:!0});l(r=>{f(`back-forward-cache`,o.navigationId,o.navigationInteractionId,o.navigationURL,c()),i=u(e,o,B,t.reportAllChanges),d(()=>{o.value=performance.now()-r.timeStamp,n=!0,i(!0)})})}})},V=[800,1800],H=e=>{document.prerendering?E(()=>H(e)):document.readyState===`complete`?setTimeout(e):addEventListener(`load`,()=>H(e),!0)},U=(e,t={})=>{let n=C(t),r=y(`TTFB`),i=u(e,r,V,t.reportAllChanges);H(()=>{let a=f();if(a){let o=a.responseStart;r.value=Math.max(o-p(),0),r.entries=[a],i(!0),l(()=>{r=y(`TTFB`,0,`back-forward-cache`,r.navigationId,r.navigationInteractionId,r.navigationURL,c()),i=u(e,r,V,t.reportAllChanges),i(!0)}),n&&S([`soft-navigation`],n=>{n.forEach(n=>{n.navigationId&&(r=y(`TTFB`,0,`soft-navigation`,n.navigationId,n.interactionId,n.name,n.startTime),r.entries=[n],i=u(e,r,V,t.reportAllChanges),i(!0))})},t)}})},W={LCP:`ms`,INP:`ms`,FCP:`ms`,TTFB:`ms`,CLS:`score`};function G(e){let t=t=>{e({kind:`web_vital`,name:t.name,value:t.value,unit:W[t.name]??`ms`,attributes:{rating:t.rating,id:t.id,navigationType:t.navigationType},occurredAt:new Date().toISOString()})};oe(t),ie(t),A(t),O(t),U(t)}function K(e,t=2048){let n=globalThis.location?.href;try{let r=new URL(e,n);return`${r.origin}${r.pathname}`.slice(0,t)}catch{return(e??``).split(`?`)[0].split(`#`)[0].slice(0,t)}}function q(e,t){return String(e??``).slice(0,t)}function se(e){globalThis.addEventListener(`error`,t=>{let n=t.error;e({kind:`error`,name:n?.name??`Error`,attributes:{message:q(n?.message??t.message,1e3),stack:n?.stack?q(n.stack,4e3):void 0,url:K(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})}),globalThis.addEventListener(`unhandledrejection`,t=>{let n=t.reason;e({kind:`error`,name:`unhandledrejection`,attributes:{message:q(n?.message??n,1e3),stack:n?.stack?q(n.stack,4e3):void 0,url:K(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})})}const J=Symbol.for(`taiga.monitor.fetch`),Y=Symbol.for(`taiga.monitor.xhr`);function X(){return globalThis.performance?.now?.()??Date.now()}function Z(e,t,n,r){let i=K(t);return{kind:`api_call`,name:`${e} ${i}`.slice(0,120),value:Math.round(r),unit:`ms`,attributes:{method:e,url:i,statusCode:n},occurredAt:new Date().toISOString()}}function ce(e,t){return(t?.method??(typeof e==`object`&&`method`in e?e.method:void 0)??`GET`).toUpperCase()}function le(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function ue(e){let t=globalThis,n=t.fetch;typeof n!=`function`||t[J]||(t[J]=!0,t.fetch=function(...t){let r=X(),i=ce(t[0],t[1]),a=le(t[0]);return Reflect.apply(n,this,t).then(t=>{try{e(Z(i,a,t.status,X()-r))}catch{}return t},t=>{try{e(Z(i,a,0,X()-r))}catch{}throw t})})}function Q(e){let t=globalThis.XMLHttpRequest,n=t?.prototype;if(!t||!n||n[Y])return;let r=n.open,i=n.send,a=Symbol.for(`taiga.monitor.xhrctx`);n.open=function(e,t,...n){return this[a]={method:String(e).toUpperCase(),url:String(t),start:0},r.apply(this,[e,t,...n])},n.send=function(...t){let n=this[a];return n&&(n.start=X(),this.addEventListener(`loadend`,()=>{try{e(Z(n.method,n.url,this.status,X()-n.start))}catch{}},{once:!0})),i.apply(this,t)},n[Y]=!0}let $=!1;function de(e){if($||globalThis.window===void 0)return;let t=e?o(e):null;if(!t)return;$=!0;let n=e.sampleRate??1;if(!(n<1&&Math.random()>=n))try{let n=new i(t),r=e=>n.enqueue(e);e.captureVitals!==!1&&G(r),e.captureErrors!==!1&&se(r),e.captureRequests!==!1&&(ue(r),Q(r));let a=()=>n.flush();globalThis.addEventListener(`visibilitychange`,()=>{globalThis.document?.visibilityState===`hidden`&&a()}),globalThis.addEventListener(`pagehide`,a)}catch{$=!1}}function fe(){$=!1}export{e as SDK_NAME,t as SDK_VERSION,fe as __resetForTests,de as init,a as parseDsn};
@@ -1 +1 @@
1
- var TaigaMonitor=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});let t=`@taiga-ai/monitor-web`,n=`0.1.0`;function r(){let e=globalThis.crypto;return e&&typeof e.randomUUID==`function`?e.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function i(e,t){return`${e}${e.includes(`?`)?`&`:`?`}k=${encodeURIComponent(t)}`}var a=class{constructor(e){this.config=e,this.queue=[],this.fetchImpl=globalThis.fetch?globalThis.fetch.bind(globalThis):void 0}enqueue(e){let t=e;if(this.config.beforeSend)try{t=this.config.beforeSend(e)}catch{return}t&&(this.queue.push(t),this.queue.length>=50?this.flush():this.scheduleFlush())}flush(){for(this.timer!==void 0&&(clearTimeout(this.timer),this.timer=void 0);this.queue.length>0;){let e=this.queue.splice(0,50);this.send(e)}}scheduleFlush(){this.timer===void 0&&(this.timer=setTimeout(()=>this.flush(),5e3))}send(e){let a;try{a=JSON.stringify({batchId:r(),meta:{sdk:t,sdkVersion:n,sentAt:new Date().toISOString()},events:e})}catch{return}let o=i(this.config.url,this.config.key);try{let e=globalThis.navigator;if(e&&typeof e.sendBeacon==`function`&&e.sendBeacon(o,new Blob([a],{type:`text/plain`})))return}catch{}try{this.fetchImpl?.(o,{method:`POST`,body:a,keepalive:!0,headers:{"content-type":`text/plain`},mode:`cors`})}catch{}}};let o=-1,s=e=>{addEventListener(`pageshow`,t=>{t.persisted&&(o=t.timeStamp,e(t))},!0)},c=(e,t,n,r)=>{let i,a;return o=>{t.value>=0&&(o||r)&&(a=t.value-(i??0),(a||i===void 0)&&(i=t.value,t.delta=a,t.rating=((e,t)=>e>t[1]?`poor`:e>t[0]?`needs-improvement`:`good`)(t.value,n),e(t)))}},l=e=>{requestAnimationFrame(()=>requestAnimationFrame(e))},u=()=>{let e=performance.getEntriesByType(`navigation`)[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},d=()=>u()?.activationStart??0,f=(e,t=-1)=>{let n=u(),r=`navigate`;return o>=0?r=`back-forward-cache`:n&&(document.prerendering||d()>0?r=`prerender`:document.wasDiscarded?r=`restore`:n.type&&(r=n.type.replace(/_/g,`-`))),{name:e,value:t,rating:`good`,delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+0xe8d4a51000}`,navigationType:r}},p=new WeakMap;function m(e,t){return p.get(e)||p.set(e,new t),p.get(e)}var h=class{t;i=0;o=[];h(e){if(e.hadRecentInput)return;let t=this.o[0],n=this.o.at(-1);this.i&&t&&n&&e.startTime-n.startTime<1e3&&e.startTime-t.startTime<5e3?(this.i+=e.value,this.o.push(e)):(this.i=e.value,this.o=[e]),this.t?.(e)}};let g=(e,t,n={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let r=new PerformanceObserver(e=>{queueMicrotask(()=>{t(e.getEntries())})});return r.observe({type:e,buffered:!0,...n}),r}}catch{}},_=e=>{let t=!1;return()=>{t||=(e(),!0)}},v=-1,y=new Set,b=()=>document.visibilityState!==`hidden`||document.prerendering?1/0:0,x=e=>{if(document.visibilityState===`hidden`){if(e.type===`visibilitychange`)for(let e of y)e();isFinite(v)||(v=e.type===`visibilitychange`?e.timeStamp:0,removeEventListener(`prerenderingchange`,x,!0))}},S=()=>{if(v<0){let e=d();v=(document.prerendering?void 0:globalThis.performance.getEntriesByType(`visibility-state`).find(t=>t.name===`hidden`&&t.startTime>=e)?.startTime)??b(),addEventListener(`visibilitychange`,x,!0),addEventListener(`prerenderingchange`,x,!0),s(()=>{setTimeout(()=>{v=b()})})}return{get firstHiddenTime(){return v},onHidden(e){y.add(e)}}},C=e=>{document.prerendering?addEventListener(`prerenderingchange`,e,!0):e()},w=[1800,3e3],T=(e,t={})=>{C(()=>{let n=S(),r,i=f(`FCP`),a=g(`paint`,e=>{for(let t of e)t.name===`first-contentful-paint`&&(a.disconnect(),t.startTime<n.firstHiddenTime&&(i.value=Math.max(t.startTime-d(),0),i.entries.push(t),r(!0)))});a&&(r=c(e,i,w,t.reportAllChanges),s(n=>{i=f(`FCP`),r=c(e,i,w,t.reportAllChanges),l(()=>{i.value=performance.now()-n.timeStamp,r(!0)})}))})},E=[.1,.25],ee=(e,t={})=>{let n=S();T(_(()=>{let r,i=f(`CLS`,0),a=m(t,h),o=e=>{for(let t of e)a.h(t);a.i>i.value&&(i.value=a.i,i.entries=a.o,r())},u=g(`layout-shift`,o);u&&(r=c(e,i,E,t.reportAllChanges),n.onHidden(()=>{o(u.takeRecords()),r(!0)}),s(()=>{a.i=0,i=f(`CLS`,0),r=c(e,i,E,t.reportAllChanges),l(r)}),setTimeout(r))}))},D=0,O=1/0,k=0,A=e=>{for(let t of e)t.interactionId&&(O=Math.min(O,t.interactionId),k=Math.max(k,t.interactionId),D=k?(k-O)/7+1:0)},j,M=()=>j?D:performance.interactionCount??0,N=()=>{`interactionCount`in performance||j||(j=g(`event`,A,{durationThreshold:0}))},P=0;var F=class{l=[];u=new Map;m;p;v(){P=M(),this.l.length=0,this.u.clear()}T(){let e=Math.min(this.l.length-1,Math.floor((M()-P)/50));return this.l[e]}h(e){if(this.m?.(e),!e.interactionId&&e.entryType!==`first-input`)return;let t=this.l.at(-1),n=this.u.get(e.interactionId);if(n||this.l.length<10||e.duration>t.L){if(n?e.duration>n.L?(n.entries=[e],n.L=e.duration):e.duration===n.L&&e.startTime===n.entries[0].startTime&&n.entries.push(e):(n={id:e.interactionId,entries:[e],L:e.duration},this.u.set(n.id,n),this.l.push(n)),this.l.sort((e,t)=>t.L-e.L),this.l.length>10){let e=this.l.splice(10);for(let t of e)this.u.delete(t.id)}this.p?.(n)}}};let I=e=>{let t=globalThis.requestIdleCallback||setTimeout,n=globalThis.cancelIdleCallback||clearTimeout;if(document.visibilityState===`hidden`)e();else{let r=_(e),i=-1,a=()=>{n(i),r()};addEventListener(`visibilitychange`,a,{once:!0,capture:!0}),i=t(()=>{removeEventListener(`visibilitychange`,a,{capture:!0}),r()})}},L=[200,500],R=(e,t={})=>{if(!globalThis.PerformanceEventTiming||!(`interactionId`in PerformanceEventTiming.prototype))return;let n=S();C(()=>{N();let r,i=f(`INP`),a=m(t,F),o=e=>{I(()=>{for(let t of e)a.h(t);let t=a.T();t&&t.L!==i.value&&(i.value=t.L,i.entries=t.entries,r())})},l=g(`event`,o,{durationThreshold:t.durationThreshold??40});r=c(e,i,L,t.reportAllChanges),l&&(l.observe({type:`first-input`,buffered:!0}),n.onHidden(()=>{o(l.takeRecords()),r(!0)}),s(()=>{a.v(),i=f(`INP`),r=c(e,i,L,t.reportAllChanges)}))})};var z=class{m;h(e){this.m?.(e)}};let B=[2500,4e3],V=(e,t={})=>{C(()=>{let n=S(),r,i=f(`LCP`),a=m(t,z),o=e=>{t.reportAllChanges||(e=e.slice(-1));for(let t of e)a.h(t),t.startTime<n.firstHiddenTime&&(i.value=Math.max(t.startTime-d(),0),i.entries=[t],r())},u=g(`largest-contentful-paint`,o);if(u){r=c(e,i,B,t.reportAllChanges);let n=_(()=>{o(u.takeRecords()),u.disconnect(),r(!0)}),a=e=>{e.isTrusted&&(I(n),removeEventListener(e.type,a,{capture:!0}))};for(let e of[`keydown`,`click`,`visibilitychange`])addEventListener(e,a,{capture:!0});s(n=>{i=f(`LCP`),r=c(e,i,B,t.reportAllChanges),l(()=>{i.value=performance.now()-n.timeStamp,r(!0)})})}})},H=[800,1800],U=e=>{document.prerendering?C(()=>U(e)):document.readyState===`complete`?setTimeout(e):addEventListener(`load`,()=>U(e),!0)},W=(e,t={})=>{let n=f(`TTFB`),r=c(e,n,H,t.reportAllChanges);U(()=>{let i=u();i&&(n.value=Math.max(i.responseStart-d(),0),n.entries=[i],r(!0),s(()=>{n=f(`TTFB`,0),r=c(e,n,H,t.reportAllChanges),r(!0)}))})},G={LCP:`ms`,INP:`ms`,FCP:`ms`,TTFB:`ms`,CLS:`score`};function K(e){let t=t=>{e({kind:`web_vital`,name:t.name,value:t.value,unit:G[t.name]??`ms`,attributes:{rating:t.rating,id:t.id,navigationType:t.navigationType},occurredAt:new Date().toISOString()})};V(t),R(t),ee(t),T(t),W(t)}function q(e,t=2048){let n=globalThis.location?.href;try{let r=new URL(e,n);return`${r.origin}${r.pathname}`.slice(0,t)}catch{return(e??``).split(`?`)[0].split(`#`)[0].slice(0,t)}}function J(e,t){return String(e??``).slice(0,t)}function te(e){globalThis.addEventListener(`error`,t=>{let n=t.error;e({kind:`error`,name:n?.name??`Error`,attributes:{message:J(t.message,1e3),stack:n?.stack?J(n.stack,4e3):void 0,url:q(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})}),globalThis.addEventListener(`unhandledrejection`,t=>{let n=t.reason;e({kind:`error`,name:`unhandledrejection`,attributes:{message:J(n?.message??n,1e3),stack:n?.stack?J(n.stack,4e3):void 0,url:q(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})})}let Y=Symbol.for(`taiga.monitor.fetch`),X=Symbol.for(`taiga.monitor.xhr`);function Z(){return globalThis.performance?.now?.()??Date.now()}function Q(e,t,n,r){let i=q(t);return{kind:`api_call`,name:`${e} ${i}`.slice(0,120),value:Math.round(r),unit:`ms`,attributes:{method:e,url:i,statusCode:n},occurredAt:new Date().toISOString()}}function ne(e,t){return(t?.method??(typeof e==`object`&&`method`in e?e.method:void 0)??`GET`).toUpperCase()}function re(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function ie(e){let t=globalThis,n=t.fetch;typeof n!=`function`||t[Y]||(t[Y]=!0,t.fetch=function(...t){let r=Z(),i=ne(t[0],t[1]),a=re(t[0]);return Reflect.apply(n,this,t).then(t=>{try{e(Q(i,a,t.status,Z()-r))}catch{}return t},t=>{try{e(Q(i,a,0,Z()-r))}catch{}throw t})})}function ae(e){let t=globalThis.XMLHttpRequest,n=t?.prototype;if(!t||!n||n[X])return;let r=n.open,i=n.send,a=Symbol.for(`taiga.monitor.xhrctx`);n.open=function(e,t,...n){return this[a]={method:String(e).toUpperCase(),url:String(t),start:0},r.apply(this,[e,t,...n])},n.send=function(...t){let n=this[a];return n&&(n.start=Z(),this.addEventListener(`loadend`,()=>{try{e(Q(n.method,n.url,this.status,Z()-n.start))}catch{}},{once:!0})),i.apply(this,t)},n[X]=!0}let $=!1;function oe(e){if($||!e?.key||!e?.url||globalThis.window===void 0)return;$=!0;let t=e.sampleRate??1;if(!(t<1&&Math.random()>=t))try{let t=new a(e),n=e=>t.enqueue(e);e.captureVitals!==!1&&K(n),e.captureErrors!==!1&&te(n),e.captureRequests!==!1&&(ie(n),ae(n));let r=()=>t.flush();globalThis.addEventListener(`visibilitychange`,()=>{globalThis.document?.visibilityState===`hidden`&&r()}),globalThis.addEventListener(`pagehide`,r)}catch{$=!1}}function se(){$=!1}return e.SDK_NAME=t,e.SDK_VERSION=n,e.__resetForTests=se,e.init=oe,e})({});
1
+ var TaigaMonitor=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});let t=`@taiga-ai/monitor-web`,n=`0.2.0`;function r(){let e=globalThis.crypto;return e&&typeof e.randomUUID==`function`?e.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function i(e,t){return`${e}${e.includes(`?`)?`&`:`?`}k=${encodeURIComponent(t)}`}var a=class{constructor(e){this.config=e,this.queue=[],this.fetchImpl=globalThis.fetch?globalThis.fetch.bind(globalThis):void 0}enqueue(e){let t=e;if(this.config.beforeSend)try{t=this.config.beforeSend(e)}catch{return}t&&(this.queue.push(t),this.queue.length>=50?this.flush():this.scheduleFlush())}flush(){for(this.timer!==void 0&&(clearTimeout(this.timer),this.timer=void 0);this.queue.length>0;){let e=this.queue.splice(0,50);this.send(e)}}scheduleFlush(){this.timer===void 0&&(this.timer=setTimeout(()=>this.flush(),5e3))}send(e){let a;try{a=JSON.stringify({batchId:r(),meta:{sdk:t,sdkVersion:n,sentAt:new Date().toISOString()},events:e})}catch{return}let o=i(this.config.url,this.config.key);try{let e=globalThis.navigator;if(e&&typeof e.sendBeacon==`function`&&e.sendBeacon(o,new Blob([a],{type:`text/plain`})))return}catch{}try{this.fetchImpl?.(o,{method:`POST`,body:a,keepalive:!0,headers:{"content-type":`text/plain`},mode:`cors`})}catch{}}};function o(e){try{let t=new URL(e);if(t.protocol!==`https:`&&t.protocol!==`http:`)return null;let n=decodeURIComponent(t.username);return n?(t.username=``,t.password=``,{key:n,url:`${t.origin}${t.pathname}`}):null}catch{return null}}function s(e){let t=(e.dsn?o(e.dsn):null)??(e.key&&e.url?{key:e.key,url:e.url}:null);return t?{...t,beforeSend:e.beforeSend}:null}let c=-1,l=()=>c,u=e=>{addEventListener(`pageshow`,t=>{t.persisted&&(c=t.timeStamp,e(t))},!0)},d=(e,t,n,r)=>{let i,a;return o=>{t.value>=0&&(o||r)&&(a=t.value-(i??0),(a||i===void 0)&&(i=t.value,t.delta=a,t.rating=((e,t)=>e>t[1]?`poor`:e>t[0]?`needs-improvement`:`good`)(t.value,n),e(t)))}},f=e=>{requestAnimationFrame(()=>requestAnimationFrame(e))},p=()=>{let e=performance.getEntriesByType(`navigation`)[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},m=()=>p()?.activationStart??0,h=-1,g=new Set,_=()=>document.visibilityState!==`hidden`||document.prerendering?1/0:0,v=e=>{if(document.visibilityState===`hidden`){if(e.type===`visibilitychange`)for(let e of g)e();isFinite(h)||(h=e.type===`visibilitychange`?e.timeStamp:0,removeEventListener(`prerenderingchange`,v,!0))}},y=(e=!1)=>{if(e&&(h=1/0),h<0){let e=m();h=(document.prerendering?void 0:globalThis.performance.getEntriesByType(`visibility-state`).find(t=>t.name===`hidden`&&t.startTime>=e)?.startTime)??_(),addEventListener(`visibilitychange`,v,!0),addEventListener(`prerenderingchange`,v,!0),u(()=>{setTimeout(()=>{h=_()})})}return{get firstHiddenTime(){return h},onHidden(e){g.add(e)}}},b=(e,t=-1,n,r=0,i,a,o)=>{let s=p(),c=s?.navigationId||0,u=`navigate`;return n?u=n:l()>=0?u=`back-forward-cache`:s&&(document.prerendering||m()>0?u=`prerender`:document.wasDiscarded?u=`restore`:s.type&&(u=s.type.replace(/_/g,`-`))),{name:e,value:t,rating:`good`,delta:0,entries:[],id:`v6-${Date.now()}-${Math.floor(8999999999999*Math.random())+0xe8d4a51000}`,navigationType:u,navigationId:r||c,navigationInteractionId:i,navigationURL:a||s?.name,navigationStartTime:o||0}},x=new WeakMap;function S(e,t){let n=x.get(t);return n||(n=new WeakMap,x.set(t,n)),n.get(e)||n.set(e,new t),n.get(e)}var ee=class{t;i=0;o=[];h(e){if(e.hadRecentInput)return;let t=this.o[0],n=this.o.at(-1);this.i&&t&&n&&e.startTime-n.startTime<1e3&&e.startTime-t.startTime<5e3?(this.i+=e.value,this.o.push(e)):(this.i=e.value,this.o=[e]),this.t?.(e)}};let C=(e,t,n={})=>{try{let r=e.filter(e=>PerformanceObserver.supportedEntryTypes.includes(e));if(r.length>0){let e=new PerformanceObserver(e=>{queueMicrotask(()=>{let n=e.getEntries();r.length>1&&n.sort((e,t)=>e.startTime+e.duration-(t.startTime+t.duration)),t(n)})});for(let t of r)e.observe({type:t,buffered:!0,...n});return e}}catch{}},w=e=>globalThis.PerformanceObserver?.supportedEntryTypes.includes(`soft-navigation`)&&typeof globalThis.PerformanceSoftNavigation?.prototype?.getLargestInteractionContentfulPaint==`function`&&e&&e.reportSoftNavs,T=(e,t)=>{if(e.set(t.navigationId,t),e.size>2){let t=e.keys().next().value;t!==void 0&&e.delete(t)}},E=e=>{let t=!1;return()=>{t||=(e(),!0)}};var D=class{l};let O=e=>{document.prerendering?addEventListener(`prerenderingchange`,e,!0):e()},k=[1800,3e3],A=(e,t={})=>{let n=w(t);O(()=>{let r=S(t,D),i=y(),a,o=b(`FCP`),s=C([`paint`],e=>{for(let t of e)t.name===`first-contentful-paint`&&(s.disconnect(),t.startTime<i.firstHiddenTime&&(o.value=Math.max(t.startTime-m(),0),o.entries.push(t),o.navigationId=t.navigationId||o.navigationId,a(!0)))});s&&(a=d(e,o,k,t.reportAllChanges),u(n=>{o=b(`FCP`,-1,`back-forward-cache`,o.navigationId,o.navigationInteractionId,o.navigationURL,l()),a=d(e,o,k,t.reportAllChanges),f(()=>{o.value=performance.now()-n.timeStamp,a(!0)})})),n&&C([`soft-navigation`],n=>{n.forEach(n=>{r.l&&n.navigationId&&T(r.l,n);let i=Math.max((n.presentationTime||n.paintTime||0)-n.startTime,0);o=b(`FCP`,i,`soft-navigation`,n.navigationId,n.interactionId,n.name,n.startTime),a=d(e,o,k,t.reportAllChanges),a(!0)})},t)})},j=[.1,.25],te=(e,t={})=>{let n=y();A(E(()=>{let r,i=b(`CLS`,0),a=S(t,ee),o=(n,o,s,c,l)=>{i=b(`CLS`,0,n,o,s,c,l),a.i=0,r=d(e,i,j,t.reportAllChanges)},s=(e=!1)=>{a.i>i.value&&(i.value=a.i,i.entries=a.o),r(e)},c=e=>{s(!0),o(`soft-navigation`,e.navigationId,e.interactionId,e.name,e.startTime)},p=e=>{for(let t of e)t.entryType===`soft-navigation`?c(t):a.h(t);s()},m=[`layout-shift`];w(t)&&m.push(`soft-navigation`);let h=C(m,p);h&&(r=d(e,i,j,t.reportAllChanges),n.onHidden(()=>{p(h.takeRecords()),r(!0)}),u(()=>{o(`back-forward-cache`,i.navigationId,i.navigationInteractionId,i.navigationURL,l()),f(r)}),setTimeout(r))}))},M=0,N=1/0,P=0,ne=e=>{for(let t of e)t.interactionId&&(N=Math.min(N,t.interactionId),P=Math.max(P,t.interactionId),M=P?(P-N)/7+1:0)},F,I=()=>F?M:performance.interactionCount??0,L=()=>{`interactionCount`in performance||F||(F=C([`event`],ne,{durationThreshold:0}))},R=0;var z=class{u=[];v=new Map;m;p;T(){R=I(),this.u.length=0,this.v.clear()}M(e){let t=I()-R,n=Math.min(this.u.length-1,Math.floor(t/50));return!t||n!==-1||e!==`soft-navigation`&&e!==`back-forward-cache`?this.u[n]:{_:8,id:-1,entries:[]}}h(e){if(this.m?.(e),!e.interactionId&&e.entryType!==`first-input`)return;let t=this.u.at(-1),n=this.v.get(e.interactionId);if(n||this.u.length<10||e.duration>t._){if(n?e.duration>n._?(n.entries=[e],n._=e.duration):e.duration===n._&&e.startTime===n.entries[0].startTime&&n.entries.push(e):(n={id:e.interactionId,entries:[e],_:e.duration},this.v.set(n.id,n),this.u.push(n)),this.u.sort((e,t)=>t._-e._),this.u.length>10){let e=this.u.splice(10);for(let t of e)this.v.delete(t.id)}this.p?.(n)}}};let B=e=>{let t=`requestIdleCallback`in globalThis?1e3:0,n=globalThis.requestIdleCallback||setTimeout,r=globalThis.cancelIdleCallback||clearTimeout;if(document.visibilityState===`hidden`)e();else{let i=E(e),a=-1,o=()=>{r(a),i()};addEventListener(`visibilitychange`,o,{once:!0,capture:!0}),a=n(()=>{removeEventListener(`visibilitychange`,o,{capture:!0}),i()},{timeout:t})}},V=[200,500],H=(e,t={})=>{if(!globalThis.PerformanceEventTiming||!(`interactionId`in PerformanceEventTiming.prototype))return;let n=y();O(()=>{L();let r,i=b(`INP`),a=S(t,z),o=(n,o,s,c,l)=>{a.T(),i=b(`INP`,-1,n,o,s,c,l),r=d(e,i,V,t.reportAllChanges)},s=()=>{let e=a.M(i.navigationType);e&&e._!==i.value&&(i.value=e._,i.entries=e.entries,r())},c=e=>{s(),r(!0),o(`soft-navigation`,e.navigationId,e.interactionId,e.name,e.startTime)},f=(e,t=!1)=>{B(()=>{for(let t of e)t.entryType===`soft-navigation`?c(t):a.h(t);s(),t&&r(!0)})},p=[`event`,`first-input`];w(t)&&p.push(`soft-navigation`);let m=C(p,f,{...t,durationThreshold:t.durationThreshold??40});r=d(e,i,V,t.reportAllChanges),m&&(n.onHidden(()=>{f(m.takeRecords(),!0)}),u(()=>{o(`back-forward-cache`,i.navigationId,i.navigationInteractionId,i.navigationURL,l())}))})};var U=class{m;l;h(e){this.m?.(e)}};let W=[2500,4e3],re=(e,t={})=>{let n=!1,r=w(t);O(()=>{let i,a=y(),o=b(`LCP`),s=S(t,U),c=(r,s,c,l,u)=>{o=b(`LCP`,-1,r,s,c,l,u),i=d(e,o,W,t.reportAllChanges),n=!1,r===`soft-navigation`&&(a=y(!0))},p=e=>{s.l&&e.navigationId&&T(s.l,e),n||i(!0),c(`soft-navigation`,e.navigationId,e.interactionId,e.name,e.startTime);let t=e.getLargestInteractionContentfulPaint?.();t&&h([t])},h=e=>{t.reportAllChanges||r||(e=e.slice(-1));for(let t of e){if(!t)continue;if(t.entryType===`soft-navigation`){p(t);continue}let e=0,n=[],r=t.startTime;if(t.entryType===`largest-contentful-paint`)e=Math.max(t.startTime-m(),0),s.h(t),n=[t];else if(t.entryType===`interaction-contentful-paint`){let i=t;if(!o.navigationId||`interactionId`in i&&i.interactionId!=o.navigationInteractionId)continue;r=i.largestContentfulPaint?.renderTime||0,e=Math.max(r-t.startTime,0),i.largestContentfulPaint&&(s.h(i.largestContentfulPaint),n=[i.largestContentfulPaint])}r<a.firstHiddenTime&&(o.value=e,o.entries=n,i())}},g=[`largest-contentful-paint`];r&&g.push(`interaction-contentful-paint`,`soft-navigation`);let _=C(g,h);if(_){i=d(e,o,W,t.reportAllChanges);let a=[`keydown`,`click`,`visibilitychange`],s=e=>{if(e.isTrusted&&!n){let e=o.id;B(()=>{if(!n){if(!r){_.disconnect();for(let e of a)removeEventListener(e,s,{capture:!0})}e===o.id&&(n=!0,i(!0))}})}};for(let e of a)addEventListener(e,s,{capture:!0});u(r=>{c(`back-forward-cache`,o.navigationId,o.navigationInteractionId,o.navigationURL,l()),i=d(e,o,W,t.reportAllChanges),f(()=>{o.value=performance.now()-r.timeStamp,n=!0,i(!0)})})}})},G=[800,1800],K=e=>{document.prerendering?O(()=>K(e)):document.readyState===`complete`?setTimeout(e):addEventListener(`load`,()=>K(e),!0)},ie=(e,t={})=>{let n=w(t),r=b(`TTFB`),i=d(e,r,G,t.reportAllChanges);K(()=>{let a=p();if(a){let o=a.responseStart;r.value=Math.max(o-m(),0),r.entries=[a],i(!0),u(()=>{r=b(`TTFB`,0,`back-forward-cache`,r.navigationId,r.navigationInteractionId,r.navigationURL,l()),i=d(e,r,G,t.reportAllChanges),i(!0)}),n&&C([`soft-navigation`],n=>{n.forEach(n=>{n.navigationId&&(r=b(`TTFB`,0,`soft-navigation`,n.navigationId,n.interactionId,n.name,n.startTime),r.entries=[n],i=d(e,r,G,t.reportAllChanges),i(!0))})},t)}})},ae={LCP:`ms`,INP:`ms`,FCP:`ms`,TTFB:`ms`,CLS:`score`};function oe(e){let t=t=>{e({kind:`web_vital`,name:t.name,value:t.value,unit:ae[t.name]??`ms`,attributes:{rating:t.rating,id:t.id,navigationType:t.navigationType},occurredAt:new Date().toISOString()})};re(t),H(t),te(t),A(t),ie(t)}function q(e,t=2048){let n=globalThis.location?.href;try{let r=new URL(e,n);return`${r.origin}${r.pathname}`.slice(0,t)}catch{return(e??``).split(`?`)[0].split(`#`)[0].slice(0,t)}}function J(e,t){return String(e??``).slice(0,t)}function se(e){globalThis.addEventListener(`error`,t=>{let n=t.error;e({kind:`error`,name:n?.name??`Error`,attributes:{message:J(n?.message??t.message,1e3),stack:n?.stack?J(n.stack,4e3):void 0,url:q(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})}),globalThis.addEventListener(`unhandledrejection`,t=>{let n=t.reason;e({kind:`error`,name:`unhandledrejection`,attributes:{message:J(n?.message??n,1e3),stack:n?.stack?J(n.stack,4e3):void 0,url:q(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})})}let Y=Symbol.for(`taiga.monitor.fetch`),X=Symbol.for(`taiga.monitor.xhr`);function Z(){return globalThis.performance?.now?.()??Date.now()}function Q(e,t,n,r){let i=q(t);return{kind:`api_call`,name:`${e} ${i}`.slice(0,120),value:Math.round(r),unit:`ms`,attributes:{method:e,url:i,statusCode:n},occurredAt:new Date().toISOString()}}function ce(e,t){return(t?.method??(typeof e==`object`&&`method`in e?e.method:void 0)??`GET`).toUpperCase()}function le(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function ue(e){let t=globalThis,n=t.fetch;typeof n!=`function`||t[Y]||(t[Y]=!0,t.fetch=function(...t){let r=Z(),i=ce(t[0],t[1]),a=le(t[0]);return Reflect.apply(n,this,t).then(t=>{try{e(Q(i,a,t.status,Z()-r))}catch{}return t},t=>{try{e(Q(i,a,0,Z()-r))}catch{}throw t})})}function de(e){let t=globalThis.XMLHttpRequest,n=t?.prototype;if(!t||!n||n[X])return;let r=n.open,i=n.send,a=Symbol.for(`taiga.monitor.xhrctx`);n.open=function(e,t,...n){return this[a]={method:String(e).toUpperCase(),url:String(t),start:0},r.apply(this,[e,t,...n])},n.send=function(...t){let n=this[a];return n&&(n.start=Z(),this.addEventListener(`loadend`,()=>{try{e(Q(n.method,n.url,this.status,Z()-n.start))}catch{}},{once:!0})),i.apply(this,t)},n[X]=!0}let $=!1;function fe(e){if($||globalThis.window===void 0)return;let t=e?s(e):null;if(!t)return;$=!0;let n=e.sampleRate??1;if(!(n<1&&Math.random()>=n))try{let n=new a(t),r=e=>n.enqueue(e);e.captureVitals!==!1&&oe(r),e.captureErrors!==!1&&se(r),e.captureRequests!==!1&&(ue(r),de(r));let i=()=>n.flush();globalThis.addEventListener(`visibilitychange`,()=>{globalThis.document?.visibilityState===`hidden`&&i()}),globalThis.addEventListener(`pagehide`,i)}catch{$=!1}}function pe(){$=!1}return e.SDK_NAME=t,e.SDK_VERSION=n,e.__resetForTests=pe,e.init=fe,e.parseDsn=o,e})({});
@@ -1,4 +1,4 @@
1
- import type { BeaconEvent, MonitorConfig } from './types.js';
1
+ import type { BeaconEvent, ResolvedConfig } from './types.js';
2
2
  /**
3
3
  * Batches events and flushes them to the ingest, fire-and-forget. Uses
4
4
  * `navigator.sendBeacon` (a text/plain POST that survives page discard and skips
@@ -11,7 +11,7 @@ export declare class Transport {
11
11
  private queue;
12
12
  private timer;
13
13
  private readonly fetchImpl;
14
- constructor(config: MonitorConfig);
14
+ constructor(config: ResolvedConfig);
15
15
  enqueue(event: BeaconEvent): void;
16
16
  flush(): void;
17
17
  private scheduleFlush;
package/dist/types.d.ts CHANGED
@@ -11,12 +11,24 @@ export interface BeaconEvent {
11
11
  attributes?: Record<string, unknown>;
12
12
  occurredAt: string;
13
13
  }
14
- /** Configuration for {@link init}. */
14
+ /**
15
+ * Configuration for {@link init}. Provide EITHER a `dsn` (preferred: one
16
+ * env-correct token) OR an explicit `key` + `url` pair. If both are given, the
17
+ * `dsn` wins.
18
+ */
15
19
  export interface MonitorConfig {
16
- /** Per-environment write-only ingest key (safe to embed in the client bundle). */
17
- key: string;
18
- /** Ingest endpoint URL (e.g. `https://api.eu.tai.ga/beacon`). */
19
- url: string;
20
+ /**
21
+ * Per-environment ingest DSN — a single token that encodes the endpoint and
22
+ * the write-only key: `https://<key>@<host>/<beacon-path>`
23
+ * (e.g. `https://taiga_ing_abc123@api.eu.tai.ga/beacon`). Minted per
24
+ * environment by Taiga, so it always points at the right endpoint. Preferred
25
+ * over `key` + `url`.
26
+ */
27
+ dsn?: string;
28
+ /** Per-environment write-only ingest key (safe to embed in the client bundle). Use with `url`, or prefer `dsn`. */
29
+ key?: string;
30
+ /** Ingest endpoint URL (e.g. `https://api.eu.tai.ga/beacon`). Use with `key`, or prefer `dsn`. */
31
+ url?: string;
20
32
  /** Fraction of sessions to instrument, 0..1 (default 1). Decided once per page load. */
21
33
  sampleRate?: number;
22
34
  /** Collect Core Web Vitals (default true). */
@@ -28,5 +40,11 @@ export interface MonitorConfig {
28
40
  /** Transform or drop each event before it is queued (return null to drop). PII scrubbing hook. */
29
41
  beforeSend?: (event: BeaconEvent) => BeaconEvent | null;
30
42
  }
43
+ /** The resolved ingest target the transport sends to (derived from `dsn` or `key`+`url`). */
44
+ export interface ResolvedConfig {
45
+ key: string;
46
+ url: string;
47
+ beforeSend?: (event: BeaconEvent) => BeaconEvent | null;
48
+ }
31
49
  /** Emit an event into the transport queue. */
32
50
  export type Emit = (event: BeaconEvent) => void;
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Beacon identity, sent as `meta.sdk`/`meta.sdkVersion` for server-side skew observability. */
2
2
  export declare const SDK_NAME = "@taiga-ai/monitor-web";
3
- export declare const SDK_VERSION = "0.1.0";
3
+ export declare const SDK_VERSION = "0.2.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ai/monitor-web",
3
- "version": "0.1.0-rc.3",
3
+ "version": "0.2.0-dev.9",
4
4
  "description": "Taiga app monitoring — a tiny, self-contained RUM beacon (Core Web Vitals, JS errors, client-observed API health) for apps built with Taiga.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -37,12 +37,12 @@
37
37
  "test": "vitest run"
38
38
  },
39
39
  "devDependencies": {
40
- "@types/node": "^22.19.17",
41
- "jsdom": "^27.4.0",
42
- "rolldown": "^1.0.3",
40
+ "@types/node": "^22.20.1",
41
+ "jsdom": "^30.0.1",
42
+ "rolldown": "^1.2.3",
43
43
  "typescript": "^7.0.2",
44
- "vitest": "^4.1.8",
45
- "web-vitals": "^5.1.0"
44
+ "vitest": "^4.1.10",
45
+ "web-vitals": "^6.1.0"
46
46
  },
47
47
  "publishConfig": {
48
48
  "access": "public"