@taiga-ai/monitor-web 0.1.0-rc.3 → 0.2.0-dev.4
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 +25 -19
- package/dist/dsn.d.ts +22 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +1 -1
- package/dist/monitor-web.global.js +1 -1
- package/dist/transport.d.ts +2 -2
- package/dist/types.d.ts +23 -5
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
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.
|
|
5
|
+
- **~3.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
|
-
|
|
22
|
-
|
|
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({
|
|
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.
|
|
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
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
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
|
|
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
|
|
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
|
|
9
|
-
* fire-and-forget — the beacon never
|
|
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({
|
|
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=e=>{addEventListener(`pageshow`,t=>{t.persisted&&(s=t.timeStamp,e(t))},!0)},l=(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)))}},u=e=>{requestAnimationFrame(()=>requestAnimationFrame(e))},d=()=>{let e=performance.getEntriesByType(`navigation`)[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},f=()=>d()?.activationStart??0,p=(e,t=-1)=>{let n=d(),r=`navigate`;return s>=0?r=`back-forward-cache`:n&&(document.prerendering||f()>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}},m=new WeakMap;function h(e,t){return m.get(e)||m.set(e,new t),m.get(e)}var g=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 _=(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{}},v=e=>{let t=!1;return()=>{t||=(e(),!0)}};let y=-1;const b=new Set,x=()=>document.visibilityState!==`hidden`||document.prerendering?1/0:0,S=e=>{if(document.visibilityState===`hidden`){if(e.type===`visibilitychange`)for(let e of b)e();isFinite(y)||(y=e.type===`visibilitychange`?e.timeStamp:0,removeEventListener(`prerenderingchange`,S,!0))}},C=()=>{if(y<0){let e=f();y=(document.prerendering?void 0:globalThis.performance.getEntriesByType(`visibility-state`).find(t=>t.name===`hidden`&&t.startTime>=e)?.startTime)??x(),addEventListener(`visibilitychange`,S,!0),addEventListener(`prerenderingchange`,S,!0),c(()=>{setTimeout(()=>{y=x()})})}return{get firstHiddenTime(){return y},onHidden(e){b.add(e)}}},w=e=>{document.prerendering?addEventListener(`prerenderingchange`,e,!0):e()},T=[1800,3e3],E=(e,t={})=>{w(()=>{let n=C(),r,i=p(`FCP`),a=_(`paint`,e=>{for(let t of e)t.name===`first-contentful-paint`&&(a.disconnect(),t.startTime<n.firstHiddenTime&&(i.value=Math.max(t.startTime-f(),0),i.entries.push(t),r(!0)))});a&&(r=l(e,i,T,t.reportAllChanges),c(n=>{i=p(`FCP`),r=l(e,i,T,t.reportAllChanges),u(()=>{i.value=performance.now()-n.timeStamp,r(!0)})}))})},D=[.1,.25],O=(e,t={})=>{let n=C();E(v(()=>{let r,i=p(`CLS`,0),a=h(t,g),o=e=>{for(let t of e)a.h(t);a.i>i.value&&(i.value=a.i,i.entries=a.o,r())},s=_(`layout-shift`,o);s&&(r=l(e,i,D,t.reportAllChanges),n.onHidden(()=>{o(s.takeRecords()),r(!0)}),c(()=>{a.i=0,i=p(`CLS`,0),r=l(e,i,D,t.reportAllChanges),u(r)}),setTimeout(r))}))};let k=0,A=1/0,j=0;const ee=e=>{for(let t of e)t.interactionId&&(A=Math.min(A,t.interactionId),j=Math.max(j,t.interactionId),k=j?(j-A)/7+1:0)};let M;const N=()=>M?k:performance.interactionCount??0,te=()=>{`interactionCount`in performance||M||(M=_(`event`,ee,{durationThreshold:0}))};let P=0;var ne=class{l=[];u=new Map;m;p;v(){P=N(),this.l.length=0,this.u.clear()}T(){let e=Math.min(this.l.length-1,Math.floor((N()-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)}}};const F=e=>{let t=globalThis.requestIdleCallback||setTimeout,n=globalThis.cancelIdleCallback||clearTimeout;if(document.visibilityState===`hidden`)e();else{let r=v(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=C();w(()=>{te();let r,i=p(`INP`),a=h(t,ne),o=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())})},s=_(`event`,o,{durationThreshold:t.durationThreshold??40});r=l(e,i,I,t.reportAllChanges),s&&(s.observe({type:`first-input`,buffered:!0}),n.onHidden(()=>{o(s.takeRecords()),r(!0)}),c(()=>{a.v(),i=p(`INP`),r=l(e,i,I,t.reportAllChanges)}))})};var R=class{m;h(e){this.m?.(e)}};const z=[2500,4e3],re=(e,t={})=>{w(()=>{let n=C(),r,i=p(`LCP`),a=h(t,R),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-f(),0),i.entries=[t],r())},s=_(`largest-contentful-paint`,o);if(s){r=l(e,i,z,t.reportAllChanges);let n=v(()=>{o(s.takeRecords()),s.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});c(n=>{i=p(`LCP`),r=l(e,i,z,t.reportAllChanges),u(()=>{i.value=performance.now()-n.timeStamp,r(!0)})})}})},B=[800,1800],V=e=>{document.prerendering?w(()=>V(e)):document.readyState===`complete`?setTimeout(e):addEventListener(`load`,()=>V(e),!0)},H=(e,t={})=>{let n=p(`TTFB`),r=l(e,n,B,t.reportAllChanges);V(()=>{let i=d();i&&(n.value=Math.max(i.responseStart-f(),0),n.entries=[i],r(!0),c(()=>{n=p(`TTFB`,0),r=l(e,n,B,t.reportAllChanges),r(!0)}))})},U={LCP:`ms`,INP:`ms`,FCP:`ms`,TTFB:`ms`,CLS:`score`};function W(e){let t=t=>{e({kind:`web_vital`,name:t.name,value:t.value,unit:U[t.name]??`ms`,attributes:{rating:t.rating,id:t.id,navigationType:t.navigationType},occurredAt:new Date().toISOString()})};re(t),L(t),O(t),E(t),H(t)}function G(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 K(e,t){return String(e??``).slice(0,t)}function q(e){globalThis.addEventListener(`error`,t=>{let n=t.error;e({kind:`error`,name:n?.name??`Error`,attributes:{message:K(t.message,1e3),stack:n?.stack?K(n.stack,4e3):void 0,url:G(globalThis.location?.href??``)},occurredAt:new Date().toISOString()})}),globalThis.addEventListener(`unhandledrejection`,t=>{let n=t.reason;e({kind:`error`,name:`unhandledrejection`,attributes:{message:K(n?.message??n,1e3),stack:n?.stack?K(n.stack,4e3):void 0,url:G(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=G(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 Q(e,t){return(t?.method??(typeof e==`object`&&`method`in e?e.method:void 0)??`GET`).toUpperCase()}function ie(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function ae(e){let t=globalThis,n=t.fetch;typeof n!=`function`||t[J]||(t[J]=!0,t.fetch=function(...t){let r=X(),i=Q(t[0],t[1]),a=ie(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 oe(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 se(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&&W(r),e.captureErrors!==!1&&q(r),e.captureRequests!==!1&&(ae(r),oe(r));let a=()=>n.flush();globalThis.addEventListener(`visibilitychange`,()=>{globalThis.document?.visibilityState===`hidden`&&a()}),globalThis.addEventListener(`pagehide`,a)}catch{$=!1}}function ce(){$=!1}export{e as SDK_NAME,t as SDK_VERSION,ce as __resetForTests,se 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=e=>{addEventListener(`pageshow`,t=>{t.persisted&&(c=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,m=(e,t=-1)=>{let n=f(),r=`navigate`;return c>=0?r=`back-forward-cache`:n&&(document.prerendering||p()>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}},h=new WeakMap;function g(e,t){return h.get(e)||h.set(e,new t),h.get(e)}var _=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 v=(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{}},y=e=>{let t=!1;return()=>{t||=(e(),!0)}},b=-1,x=new Set,S=()=>document.visibilityState!==`hidden`||document.prerendering?1/0:0,C=e=>{if(document.visibilityState===`hidden`){if(e.type===`visibilitychange`)for(let e of x)e();isFinite(b)||(b=e.type===`visibilitychange`?e.timeStamp:0,removeEventListener(`prerenderingchange`,C,!0))}},w=()=>{if(b<0){let e=p();b=(document.prerendering?void 0:globalThis.performance.getEntriesByType(`visibility-state`).find(t=>t.name===`hidden`&&t.startTime>=e)?.startTime)??S(),addEventListener(`visibilitychange`,C,!0),addEventListener(`prerenderingchange`,C,!0),l(()=>{setTimeout(()=>{b=S()})})}return{get firstHiddenTime(){return b},onHidden(e){x.add(e)}}},T=e=>{document.prerendering?addEventListener(`prerenderingchange`,e,!0):e()},E=[1800,3e3],D=(e,t={})=>{T(()=>{let n=w(),r,i=m(`FCP`),a=v(`paint`,e=>{for(let t of e)t.name===`first-contentful-paint`&&(a.disconnect(),t.startTime<n.firstHiddenTime&&(i.value=Math.max(t.startTime-p(),0),i.entries.push(t),r(!0)))});a&&(r=u(e,i,E,t.reportAllChanges),l(n=>{i=m(`FCP`),r=u(e,i,E,t.reportAllChanges),d(()=>{i.value=performance.now()-n.timeStamp,r(!0)})}))})},O=[.1,.25],ee=(e,t={})=>{let n=w();D(y(()=>{let r,i=m(`CLS`,0),a=g(t,_),o=e=>{for(let t of e)a.h(t);a.i>i.value&&(i.value=a.i,i.entries=a.o,r())},s=v(`layout-shift`,o);s&&(r=u(e,i,O,t.reportAllChanges),n.onHidden(()=>{o(s.takeRecords()),r(!0)}),l(()=>{a.i=0,i=m(`CLS`,0),r=u(e,i,O,t.reportAllChanges),d(r)}),setTimeout(r))}))},k=0,A=1/0,j=0,M=e=>{for(let t of e)t.interactionId&&(A=Math.min(A,t.interactionId),j=Math.max(j,t.interactionId),k=j?(j-A)/7+1:0)},N,P=()=>N?k:performance.interactionCount??0,F=()=>{`interactionCount`in performance||N||(N=v(`event`,M,{durationThreshold:0}))},I=0;var L=class{l=[];u=new Map;m;p;v(){I=P(),this.l.length=0,this.u.clear()}T(){let e=Math.min(this.l.length-1,Math.floor((P()-I)/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 R=e=>{let t=globalThis.requestIdleCallback||setTimeout,n=globalThis.cancelIdleCallback||clearTimeout;if(document.visibilityState===`hidden`)e();else{let r=y(e),i=-1,a=()=>{n(i),r()};addEventListener(`visibilitychange`,a,{once:!0,capture:!0}),i=t(()=>{removeEventListener(`visibilitychange`,a,{capture:!0}),r()})}},z=[200,500],B=(e,t={})=>{if(!globalThis.PerformanceEventTiming||!(`interactionId`in PerformanceEventTiming.prototype))return;let n=w();T(()=>{F();let r,i=m(`INP`),a=g(t,L),o=e=>{R(()=>{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())})},s=v(`event`,o,{durationThreshold:t.durationThreshold??40});r=u(e,i,z,t.reportAllChanges),s&&(s.observe({type:`first-input`,buffered:!0}),n.onHidden(()=>{o(s.takeRecords()),r(!0)}),l(()=>{a.v(),i=m(`INP`),r=u(e,i,z,t.reportAllChanges)}))})};var V=class{m;h(e){this.m?.(e)}};let H=[2500,4e3],U=(e,t={})=>{T(()=>{let n=w(),r,i=m(`LCP`),a=g(t,V),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-p(),0),i.entries=[t],r())},s=v(`largest-contentful-paint`,o);if(s){r=u(e,i,H,t.reportAllChanges);let n=y(()=>{o(s.takeRecords()),s.disconnect(),r(!0)}),a=e=>{e.isTrusted&&(R(n),removeEventListener(e.type,a,{capture:!0}))};for(let e of[`keydown`,`click`,`visibilitychange`])addEventListener(e,a,{capture:!0});l(n=>{i=m(`LCP`),r=u(e,i,H,t.reportAllChanges),d(()=>{i.value=performance.now()-n.timeStamp,r(!0)})})}})},W=[800,1800],G=e=>{document.prerendering?T(()=>G(e)):document.readyState===`complete`?setTimeout(e):addEventListener(`load`,()=>G(e),!0)},K=(e,t={})=>{let n=m(`TTFB`),r=u(e,n,W,t.reportAllChanges);G(()=>{let i=f();i&&(n.value=Math.max(i.responseStart-p(),0),n.entries=[i],r(!0),l(()=>{n=m(`TTFB`,0),r=u(e,n,W,t.reportAllChanges),r(!0)}))})},te={LCP:`ms`,INP:`ms`,FCP:`ms`,TTFB:`ms`,CLS:`score`};function ne(e){let t=t=>{e({kind:`web_vital`,name:t.name,value:t.value,unit:te[t.name]??`ms`,attributes:{rating:t.rating,id:t.id,navigationType:t.navigationType},occurredAt:new Date().toISOString()})};U(t),B(t),ee(t),D(t),K(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 re(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 ie(e,t){return(t?.method??(typeof e==`object`&&`method`in e?e.method:void 0)??`GET`).toUpperCase()}function ae(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function oe(e){let t=globalThis,n=t.fetch;typeof n!=`function`||t[Y]||(t[Y]=!0,t.fetch=function(...t){let r=Z(),i=ie(t[0],t[1]),a=ae(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 se(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 ce(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&&ne(r),e.captureErrors!==!1&&re(r),e.captureRequests!==!1&&(oe(r),se(r));let i=()=>n.flush();globalThis.addEventListener(`visibilitychange`,()=>{globalThis.document?.visibilityState===`hidden`&&i()}),globalThis.addEventListener(`pagehide`,i)}catch{$=!1}}function le(){$=!1}return e.SDK_NAME=t,e.SDK_VERSION=n,e.__resetForTests=le,e.init=ce,e.parseDsn=o,e})({});
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BeaconEvent,
|
|
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:
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taiga-ai/monitor-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-dev.4",
|
|
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,
|