svoose 0.1.7 → 0.1.8

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,13 +2,14 @@
2
2
 
3
3
  > Svelte + Goose = **svoose** — the goose that sees everything
4
4
 
5
- Lightweight observability + state machines for Svelte 5. Zero dependencies. Tree-shakeable. **< 5KB gzipped** (core ~3.5KB).
5
+ Lightweight observability + state machines for Svelte 5. Zero dependencies. Tree-shakeable. **~5.3KB gzipped** (core ~3.6KB).
6
6
 
7
7
  ## Features
8
8
 
9
9
  - **Web Vitals** — CLS, LCP, FID, INP, FCP, TTFB (no external deps)
10
10
  - **Error Tracking** — global errors + unhandled rejections
11
11
  - **Custom Metrics** — `metric()`, `counter()`, `gauge()`, `histogram()` (v0.1.6+)
12
+ - **Beacon Transport** — reliable delivery on page close with auto-chunking (v0.1.8+)
12
13
  - **Session Tracking** — automatic sessionId with timeout (v0.1.5+)
13
14
  - **Sampling** — per-event-type rate limiting (v0.1.3+)
14
15
  - **State Machines** — minimal FSM with TypeScript inference
@@ -413,6 +414,34 @@ observe({
413
414
  });
414
415
  ```
415
416
 
417
+ #### Beacon & Hybrid Transport (v0.1.8+)
418
+
419
+ Prevent data loss on page close with `sendBeacon`:
420
+
421
+ ```typescript
422
+ import { createBeaconTransport, createHybridTransport } from 'svoose';
423
+
424
+ // Beacon only — guaranteed delivery on page close
425
+ observe({
426
+ transport: createBeaconTransport('/api/metrics', {
427
+ maxPayloadSize: 60000, // auto-chunks if exceeded (default: 60KB)
428
+ }),
429
+ });
430
+
431
+ // Hybrid (recommended for production)
432
+ // Uses fetch normally, switches to beacon on page close
433
+ const transport = createHybridTransport('/api/metrics', {
434
+ default: 'fetch', // normal operation
435
+ onUnload: 'beacon', // page close / tab switch
436
+ headers: { 'Authorization': 'Bearer xxx' },
437
+ });
438
+
439
+ observe({ transport });
440
+
441
+ // Cleanup when done (removes lifecycle listeners)
442
+ transport.destroy();
443
+ ```
444
+
416
445
  ## Bundle Size
417
446
 
418
447
  Tree-shakeable — pay only for what you use:
@@ -421,10 +450,10 @@ Tree-shakeable — pay only for what you use:
421
450
  |--------|-------------|
422
451
  | `observe()` + vitals + errors + metrics | ~3.6 KB |
423
452
  | `createMachine()` only | ~0.8 KB |
424
- | Full bundle (v0.1.x) | ~4.7 KB |
453
+ | Full bundle (v0.1.x) | ~5.3 KB |
425
454
  | Full production (v0.2.0+) | ~6 KB |
426
455
 
427
- > Most apps only need `observe()` core (~3.5 KB). Compare: Sentry ~20KB, PostHog ~40KB.
456
+ > Most apps only need `observe()` core (~3.6 KB). Compare: Sentry ~20KB, PostHog ~40KB.
428
457
 
429
458
  ## TypeScript
430
459
 
@@ -574,7 +603,7 @@ const machine = createMachine({
574
603
  - **v0.1.5** ✅ — Session Tracking + CLS Session Windows fix
575
604
  - **v0.1.6** ✅ — Custom metrics (`metric()` API)
576
605
  - **v0.1.7** ✅ — Extended Metrics (counter/gauge/histogram + typed API)
577
- - **v0.1.8** — Beacon + Hybrid Transport
606
+ - **v0.1.8** — Beacon + Hybrid Transport
578
607
  - **v0.1.9** — Retry Logic
579
608
  - **v0.1.10** — Privacy Utilities
580
609
  - **v0.2.0** — Production-Ready Observability + Bundle Restructure (modular entry points)
package/dist/index.d.ts CHANGED
@@ -11,8 +11,8 @@ export { observeErrors, registerMachineContext, unregisterMachineContext, } from
11
11
  export type { ObserveErrorEvent, ErrorEvent, UnhandledRejectionEvent, } from './observe/index.js';
12
12
  export { observeCLS, observeLCP, observeFID, observeINP, observeFCP, observeTTFB, vitalObservers, } from './observe/index.js';
13
13
  export type { Metric, MetricName, MetricRating } from './observe/index.js';
14
- export { createFetchTransport, createConsoleTransport } from './transport/index.js';
15
- export type { Transport, TransportOptions } from './transport/index.js';
14
+ export { createFetchTransport, createConsoleTransport, createBeaconTransport, createHybridTransport } from './transport/index.js';
15
+ export type { Transport, TransportOptions, BeaconTransportOptions, HybridTransportOptions, HybridTransport } from './transport/index.js';
16
16
  export { createMachine, createEvent } from './machine/index.js';
17
17
  export type { MachineConfig, Machine, EventObject, StateNode, TransitionConfig, InferStates, InferEvents, InferContext, } from './machine/index.js';
18
18
  export { metric, counter, gauge, histogram, createTypedMetric } from './metrics/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKzD,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAKrG,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,iBAAiB,EACjB,UAAU,EACV,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EACL,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAK3E,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACpF,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAKxE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,aAAa,EACb,OAAO,EACP,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,YAAY,GACb,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAK1F,YAAY,EACV,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKzD,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAKrG,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,iBAAiB,EACjB,UAAU,EACV,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EACL,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAK3E,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClI,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKzI,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,aAAa,EACb,OAAO,EACP,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,YAAY,GACb,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAK1F,YAAY,EACV,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{observe as t}from"./observe/index.js";import{createSampler as n,eventTypeToSamplingType as s}from"./observe/index.js";import{observeErrors as p,registerMachineContext as a,unregisterMachineContext as v}from"./observe/index.js";import{observeCLS as x,observeLCP as c,observeFID as f,observeINP as b,observeFCP as E,observeTTFB as g,vitalObservers as T}from"./observe/index.js";import{createFetchTransport as d,createConsoleTransport as C}from"./transport/index.js";import{createMachine as M,createEvent as h}from"./machine/index.js";import{metric as S,counter as O,gauge as I,histogram as u,createTypedMetric as F}from"./metrics/index.js";export{O as counter,C as createConsoleTransport,h as createEvent,d as createFetchTransport,M as createMachine,n as createSampler,F as createTypedMetric,s as eventTypeToSamplingType,I as gauge,u as histogram,S as metric,t as observe,x as observeCLS,p as observeErrors,E as observeFCP,f as observeFID,b as observeINP,c as observeLCP,g as observeTTFB,a as registerMachineContext,v as unregisterMachineContext,T as vitalObservers};
1
+ import{observe as t}from"./observe/index.js";import{createSampler as n,eventTypeToSamplingType as s}from"./observe/index.js";import{observeErrors as i,registerMachineContext as a,unregisterMachineContext as v}from"./observe/index.js";import{observeCLS as m,observeLCP as x,observeFID as b,observeINP as f,observeFCP as T,observeTTFB as y,vitalObservers as d}from"./observe/index.js";import{createFetchTransport as g,createConsoleTransport as C,createBeaconTransport as l,createHybridTransport as M}from"./transport/index.js";import{createMachine as h,createEvent as j}from"./machine/index.js";import{metric as I,counter as u,gauge as F,histogram as B,createTypedMetric as H}from"./metrics/index.js";export{u as counter,l as createBeaconTransport,C as createConsoleTransport,j as createEvent,g as createFetchTransport,M as createHybridTransport,h as createMachine,n as createSampler,H as createTypedMetric,s as eventTypeToSamplingType,F as gauge,B as histogram,I as metric,t as observe,m as observeCLS,i as observeErrors,T as observeFCP,b as observeFID,f as observeINP,x as observeLCP,y as observeTTFB,a as registerMachineContext,v as unregisterMachineContext,d as vitalObservers};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/**\n * \uD83E\uDEBF svoose - Observability + State Machines for Svelte 5\n *\n * @packageDocumentation\n */\n\n// ============================================\n// Core Observability\n// ============================================\nexport { observe } from './observe/index.js';\nexport type { ObserveOptions } from './observe/index.js';\n\n// ============================================\n// Sampling\n// ============================================\nexport { createSampler, eventTypeToSamplingType } from './observe/index.js';\nexport type { SamplingConfig, SamplingOption, SamplingEventType, Sampler } from './observe/index.js';\n\n// ============================================\n// Error Tracking\n// ============================================\nexport {\n observeErrors,\n registerMachineContext,\n unregisterMachineContext,\n} from './observe/index.js';\nexport type {\n ObserveErrorEvent,\n ErrorEvent,\n UnhandledRejectionEvent,\n} from './observe/index.js';\n\n// ============================================\n// Web Vitals\n// ============================================\nexport {\n observeCLS,\n observeLCP,\n observeFID,\n observeINP,\n observeFCP,\n observeTTFB,\n vitalObservers,\n} from './observe/index.js';\nexport type { Metric, MetricName, MetricRating } from './observe/index.js';\n\n// ============================================\n// Transport\n// ============================================\nexport { createFetchTransport, createConsoleTransport } from './transport/index.js';\nexport type { Transport, TransportOptions } from './transport/index.js';\n\n// ============================================\n// State Machines\n// ============================================\nexport { createMachine, createEvent } from './machine/index.js';\nexport type {\n MachineConfig,\n Machine,\n EventObject,\n StateNode,\n TransitionConfig,\n InferStates,\n InferEvents,\n InferContext,\n} from './machine/index.js';\n\n// ============================================\n// Custom Metrics\n// ============================================\nexport { metric, counter, gauge, histogram, createTypedMetric } from './metrics/index.js';\n\n// ============================================\n// Shared Types\n// ============================================\nexport type {\n VitalEvent,\n TransitionEvent,\n CustomMetricEvent,\n ObserveEvent,\n} from './types/index.js';\n"],
5
- "mappings": "AASA,OAAS,WAAAA,MAAe,qBAMxB,OAAS,iBAAAC,EAAe,2BAAAC,MAA+B,qBAMvD,OACE,iBAAAC,EACA,0BAAAC,EACA,4BAAAC,MACK,qBAUP,OACE,cAAAC,EACA,cAAAC,EACA,cAAAC,EACA,cAAAC,EACA,cAAAC,EACA,eAAAC,EACA,kBAAAC,MACK,qBAMP,OAAS,wBAAAC,EAAsB,0BAAAC,MAA8B,uBAM7D,OAAS,iBAAAC,EAAe,eAAAC,MAAmB,qBAe3C,OAAS,UAAAC,EAAQ,WAAAC,EAAS,SAAAC,EAAO,aAAAC,EAAW,qBAAAC,MAAyB",
6
- "names": ["observe", "createSampler", "eventTypeToSamplingType", "observeErrors", "registerMachineContext", "unregisterMachineContext", "observeCLS", "observeLCP", "observeFID", "observeINP", "observeFCP", "observeTTFB", "vitalObservers", "createFetchTransport", "createConsoleTransport", "createMachine", "createEvent", "metric", "counter", "gauge", "histogram", "createTypedMetric"]
4
+ "sourcesContent": ["/**\n * \uD83E\uDEBF svoose - Observability + State Machines for Svelte 5\n *\n * @packageDocumentation\n */\n\n// ============================================\n// Core Observability\n// ============================================\nexport { observe } from './observe/index.js';\nexport type { ObserveOptions } from './observe/index.js';\n\n// ============================================\n// Sampling\n// ============================================\nexport { createSampler, eventTypeToSamplingType } from './observe/index.js';\nexport type { SamplingConfig, SamplingOption, SamplingEventType, Sampler } from './observe/index.js';\n\n// ============================================\n// Error Tracking\n// ============================================\nexport {\n observeErrors,\n registerMachineContext,\n unregisterMachineContext,\n} from './observe/index.js';\nexport type {\n ObserveErrorEvent,\n ErrorEvent,\n UnhandledRejectionEvent,\n} from './observe/index.js';\n\n// ============================================\n// Web Vitals\n// ============================================\nexport {\n observeCLS,\n observeLCP,\n observeFID,\n observeINP,\n observeFCP,\n observeTTFB,\n vitalObservers,\n} from './observe/index.js';\nexport type { Metric, MetricName, MetricRating } from './observe/index.js';\n\n// ============================================\n// Transport\n// ============================================\nexport { createFetchTransport, createConsoleTransport, createBeaconTransport, createHybridTransport } from './transport/index.js';\nexport type { Transport, TransportOptions, BeaconTransportOptions, HybridTransportOptions, HybridTransport } from './transport/index.js';\n\n// ============================================\n// State Machines\n// ============================================\nexport { createMachine, createEvent } from './machine/index.js';\nexport type {\n MachineConfig,\n Machine,\n EventObject,\n StateNode,\n TransitionConfig,\n InferStates,\n InferEvents,\n InferContext,\n} from './machine/index.js';\n\n// ============================================\n// Custom Metrics\n// ============================================\nexport { metric, counter, gauge, histogram, createTypedMetric } from './metrics/index.js';\n\n// ============================================\n// Shared Types\n// ============================================\nexport type {\n VitalEvent,\n TransitionEvent,\n CustomMetricEvent,\n ObserveEvent,\n} from './types/index.js';\n"],
5
+ "mappings": "AASA,OAAS,WAAAA,MAAe,qBAMxB,OAAS,iBAAAC,EAAe,2BAAAC,MAA+B,qBAMvD,OACE,iBAAAC,EACA,0BAAAC,EACA,4BAAAC,MACK,qBAUP,OACE,cAAAC,EACA,cAAAC,EACA,cAAAC,EACA,cAAAC,EACA,cAAAC,EACA,eAAAC,EACA,kBAAAC,MACK,qBAMP,OAAS,wBAAAC,EAAsB,0BAAAC,EAAwB,yBAAAC,EAAuB,yBAAAC,MAA6B,uBAM3G,OAAS,iBAAAC,EAAe,eAAAC,MAAmB,qBAe3C,OAAS,UAAAC,EAAQ,WAAAC,EAAS,SAAAC,EAAO,aAAAC,EAAW,qBAAAC,MAAyB",
6
+ "names": ["observe", "createSampler", "eventTypeToSamplingType", "observeErrors", "registerMachineContext", "unregisterMachineContext", "observeCLS", "observeLCP", "observeFID", "observeINP", "observeFCP", "observeTTFB", "vitalObservers", "createFetchTransport", "createConsoleTransport", "createBeaconTransport", "createHybridTransport", "createMachine", "createEvent", "metric", "counter", "gauge", "histogram", "createTypedMetric"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"observe.svelte.d.ts","sourceRoot":"","sources":["../../src/observe/observe.svelte.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,KAAK,EAAE,cAAc,EAAc,YAAY,EAAa,MAAM,mBAAmB,CAAC;AAc7F,QAAA,IAAI,sBAAsB,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAW,CAAC;AAE1E;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,sBAAsB,GAAG,IAAI,CAE/E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,sBAAsB,CAEjE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,IAAI,CA+KhE;AAED,YAAY,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"observe.svelte.d.ts","sourceRoot":"","sources":["../../src/observe/observe.svelte.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,KAAK,EAAE,cAAc,EAAc,YAAY,EAAa,MAAM,mBAAmB,CAAC;AAc7F,QAAA,IAAI,sBAAsB,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAW,CAAC;AAE1E;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,sBAAsB,GAAG,IAAI,CAE/E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,sBAAsB,CAEjE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,IAAI,CAiLhE;AAED,YAAY,EAAE,cAAc,EAAE,CAAC"}
@@ -1,2 +1,2 @@
1
- import{vitalObservers as y}from"./vitals.js";import{observeErrors as O}from"./errors.js";import{createFetchTransport as E}from"../transport/fetch.js";import{createSampler as S,eventTypeToSamplingType as M}from"./sampling.js";import{createSessionManager as T}from"./session.js";import{setMetricEmitter as f,getMetricEmitter as I}from"../metrics/index.js";const c={endpoint:"/api/metrics",vitals:!0,errors:!0,batchSize:10,flushInterval:5e3,sampleRate:1,debug:!1};let m=null;function d(l){m=l}function w(){return m}function N(l={}){if(Math.random()>(l.sampleRate??c.sampleRate))return()=>{};const t={...c,...l},b=t.transport??E(t.endpoint),u=t.sampling!=null?S(t.sampling):null,a=t.session!=null?T(t.session):null,n=[];a&&n.push(()=>a.destroy());const o=[];let v=null;const g=()=>{try{return typeof location<"u"?location.href:""}catch{return""}},s=e=>{if(!(t.filter&&!t.filter(e))){if(u){const r=M(e.type);if(r&&!u.shouldSample(r))return}a&&(e.sessionId=a.getSessionId()),t.debug&&console.log("[svoose]",e),o.push(e),o.length>=t.batchSize&&i()}},i=()=>{if(o.length===0)return;const e=o.splice(0,o.length),r=b.send(e);r&&typeof r.catch=="function"&&r.catch(p=>{t.debug&&console.error("[svoose] transport error:",p)})},h=e=>{const r={type:"vital",name:e.name,value:e.value,rating:e.rating,delta:e.delta,timestamp:e.timestamp,url:g()};s(r)};if(t.vitals){const e=t.vitals===!0?["CLS","LCP","FID","INP","FCP","TTFB"]:t.vitals;for(const r of e){const p=y[r];p&&n.push(p(h))}}if(t.errors&&n.push(O(e=>{s(e)})),d(s),n.push(()=>{w()===s&&d(null)}),f(s),n.push(()=>{I()===s&&f(null)}),v=setInterval(i,t.flushInterval),n.push(()=>{v&&clearInterval(v)}),typeof document<"u"){const e=()=>{document.visibilityState==="hidden"&&i()};document.addEventListener("visibilitychange",e),n.push(()=>{document.removeEventListener("visibilitychange",e)})}if(typeof window<"u"){const e=()=>{i()};window.addEventListener("beforeunload",e),n.push(()=>{window.removeEventListener("beforeunload",e)})}return()=>{i(),n.forEach(e=>e())}}export{w as getGlobalObserver,N as observe,d as setGlobalObserver};
1
+ import{vitalObservers as y}from"./vitals.js";import{observeErrors as O}from"./errors.js";import{createFetchTransport as E}from"../transport/fetch.js";import{createSampler as S,eventTypeToSamplingType as T}from"./sampling.js";import{createSessionManager as M}from"./session.js";import{setMetricEmitter as c,getMetricEmitter as I}from"../metrics/index.js";const d={endpoint:"/api/metrics",vitals:!0,errors:!0,batchSize:10,flushInterval:5e3,sampleRate:1,debug:!1};let b=null;function m(l){b=l}function w(){return b}function N(l={}){if(Math.random()>(l.sampleRate??d.sampleRate))return()=>{};const t={...d,...l},u=t.transport??E(t.endpoint),f=t.sampling!=null?S(t.sampling):null,a=t.session!=null?M(t.session):null,s=[];a&&s.push(()=>a.destroy());const o=[];let v=null;const g=()=>{try{return typeof location<"u"?location.href:""}catch{return""}},n=e=>{if(!(t.filter&&!t.filter(e))){if(f){const r=T(e.type);if(r&&!f.shouldSample(r))return}a&&(e.sessionId=a.getSessionId()),t.debug&&console.log("[svoose]",e),o.push(e),o.length>=t.batchSize&&i()}},i=()=>{if(o.length===0)return;const e=o.splice(0,o.length),r=u.send(e);r&&typeof r.catch=="function"&&r.catch(p=>{t.debug&&console.error("[svoose] transport error:",p)})},h=e=>{const r={type:"vital",name:e.name,value:e.value,rating:e.rating,delta:e.delta,timestamp:e.timestamp,url:g()};n(r)};if(t.vitals){const e=t.vitals===!0?["CLS","LCP","FID","INP","FCP","TTFB"]:t.vitals;for(const r of e){const p=y[r];p&&s.push(p(h))}}if(t.errors&&s.push(O(e=>{n(e)})),m(n),s.push(()=>{w()===n&&m(null)}),c(n),s.push(()=>{I()===n&&c(null)}),v=setInterval(i,t.flushInterval),s.push(()=>{v&&clearInterval(v)}),typeof document<"u"){const e=()=>{document.visibilityState==="hidden"&&i()};document.addEventListener("visibilitychange",e),s.push(()=>{document.removeEventListener("visibilitychange",e)})}if(typeof window<"u"){const e=()=>{i()};window.addEventListener("beforeunload",e),s.push(()=>{window.removeEventListener("beforeunload",e)})}return()=>{i(),s.forEach(e=>e()),u.destroy?.()}}export{w as getGlobalObserver,N as observe,m as setGlobalObserver};
2
2
  //# sourceMappingURL=observe.svelte.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/observe/observe.svelte.ts"],
4
- "sourcesContent": ["/**\n * Main observe() function - combines vitals, errors, and transport\n */\n\nimport { vitalObservers, type Metric, type MetricName } from './vitals.js';\nimport { observeErrors, type ObserveErrorEvent } from './errors.js';\nimport { createFetchTransport } from '../transport/fetch.js';\nimport {\n createSampler,\n eventTypeToSamplingType,\n type Sampler,\n} from './sampling.js';\nimport { createSessionManager, type SessionManager } from './session.js';\nimport { setMetricEmitter, getMetricEmitter } from '../metrics/index.js';\nimport type { ObserveOptions, VitalEvent, ObserveEvent, Transport } from '../types/index.js';\n\n// Default configuration\nconst defaults = {\n endpoint: '/api/metrics',\n vitals: true as const,\n errors: true,\n batchSize: 10,\n flushInterval: 5000,\n sampleRate: 1,\n debug: false,\n} satisfies Required<Omit<ObserveOptions, 'transport' | 'filter' | 'sampling' | 'session'>>;\n\n// Global observer callback for state machines\nlet globalObserverCallback: ((event: ObserveEvent) => void) | null = null;\n\n/**\n * Set global observer callback for state machines\n * Called internally to connect machines to observe()\n */\nexport function setGlobalObserver(callback: typeof globalObserverCallback): void {\n globalObserverCallback = callback;\n}\n\n/**\n * Get global observer callback\n * Used by createMachine to send transition events\n */\nexport function getGlobalObserver(): typeof globalObserverCallback {\n return globalObserverCallback;\n}\n\n/**\n * Main observe function - starts collecting metrics and errors\n *\n * @param options - Configuration options\n * @returns Cleanup function to stop observing\n *\n * @example\n * // Basic usage\n * observe();\n *\n * @example\n * // With options\n * observe({\n * endpoint: '/api/metrics',\n * vitals: ['CLS', 'LCP', 'INP'],\n * errors: true,\n * debug: true,\n * });\n */\nexport function observe(options: ObserveOptions = {}): () => void {\n // Legacy sampleRate support (deprecated) - skip entire observer\n if (Math.random() > (options.sampleRate ?? defaults.sampleRate)) {\n return () => {};\n }\n\n const config = { ...defaults, ...options };\n const transport: Transport = config.transport ?? createFetchTransport(config.endpoint);\n\n // Create sampler if sampling option is provided\n const sampler: Sampler | null = config.sampling != null\n ? createSampler(config.sampling)\n : null;\n\n // Create session manager if session option is provided\n const sessionManager: SessionManager | null = config.session != null\n ? createSessionManager(config.session)\n : null;\n\n const cleanups: (() => void)[] = [];\n\n // Cleanup session manager on destroy\n if (sessionManager) {\n cleanups.push(() => sessionManager.destroy());\n }\n const buffer: ObserveEvent[] = [];\n let flushTimer: ReturnType<typeof setInterval> | null = null;\n\n // Get current URL\n const getUrl = (): string => {\n try {\n return typeof location !== 'undefined' ? location.href : '';\n } catch {\n return '';\n }\n };\n\n // Buffer an event and potentially flush\n const bufferEvent = (event: ObserveEvent): void => {\n // Apply filter if provided\n if (config.filter && !config.filter(event)) {\n return;\n }\n\n // Apply per-event-type sampling\n if (sampler) {\n const samplingType = eventTypeToSamplingType(event.type);\n if (samplingType && !sampler.shouldSample(samplingType)) {\n return;\n }\n }\n\n // Add sessionId if session manager is enabled\n if (sessionManager) {\n (event as ObserveEvent & { sessionId?: string }).sessionId = sessionManager.getSessionId();\n }\n\n if (config.debug) {\n console.log('[svoose]', event);\n }\n\n buffer.push(event);\n\n if (buffer.length >= config.batchSize) {\n flush();\n }\n };\n\n // Send buffered events to transport\n const flush = (): void => {\n if (buffer.length === 0) return;\n\n const events = buffer.splice(0, buffer.length);\n // Handle both Promise and non-Promise returns from transport.send()\n const result = transport.send(events);\n if (result && typeof result.catch === 'function') {\n result.catch((err) => {\n if (config.debug) {\n console.error('[svoose] transport error:', err);\n }\n });\n }\n };\n\n // Convert metric to vital event\n const handleMetric = (metric: Metric): void => {\n const vitalEvent: VitalEvent = {\n type: 'vital',\n name: metric.name,\n value: metric.value,\n rating: metric.rating,\n delta: metric.delta,\n timestamp: metric.timestamp,\n url: getUrl(),\n };\n bufferEvent(vitalEvent);\n };\n\n // Setup vitals observers\n if (config.vitals) {\n const vitalsToObserve: MetricName[] =\n config.vitals === true\n ? ['CLS', 'LCP', 'FID', 'INP', 'FCP', 'TTFB']\n : config.vitals;\n\n for (const name of vitalsToObserve) {\n const observer = vitalObservers[name];\n if (observer) {\n cleanups.push(observer(handleMetric));\n }\n }\n }\n\n // Setup error observer\n if (config.errors) {\n cleanups.push(\n observeErrors((event: ObserveErrorEvent) => {\n bufferEvent(event);\n })\n );\n }\n\n // Setup global observer for state machines\n setGlobalObserver(bufferEvent);\n cleanups.push(() => {\n // Only clear if we're still the active observer\n if (getGlobalObserver() === bufferEvent) {\n setGlobalObserver(null);\n }\n });\n\n // Setup metric emitter for custom metrics\n setMetricEmitter(bufferEvent);\n cleanups.push(() => {\n // Only clear if we're still the active emitter\n if (getMetricEmitter() === bufferEvent) {\n setMetricEmitter(null);\n }\n });\n\n // Setup flush interval\n flushTimer = setInterval(flush, config.flushInterval);\n cleanups.push(() => {\n if (flushTimer) clearInterval(flushTimer);\n });\n\n // Flush on page visibility change (user navigating away)\n if (typeof document !== 'undefined') {\n const visibilityHandler = (): void => {\n if (document.visibilityState === 'hidden') {\n flush();\n }\n };\n document.addEventListener('visibilitychange', visibilityHandler);\n cleanups.push(() => {\n document.removeEventListener('visibilitychange', visibilityHandler);\n });\n }\n\n // Flush on beforeunload\n if (typeof window !== 'undefined') {\n const unloadHandler = (): void => {\n flush();\n };\n window.addEventListener('beforeunload', unloadHandler);\n cleanups.push(() => {\n window.removeEventListener('beforeunload', unloadHandler);\n });\n }\n\n // Return cleanup function\n return () => {\n flush();\n cleanups.forEach((fn) => fn());\n };\n}\n\nexport type { ObserveOptions };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Main observe() function - combines vitals, errors, and transport\n */\n\nimport { vitalObservers, type Metric, type MetricName } from './vitals.js';\nimport { observeErrors, type ObserveErrorEvent } from './errors.js';\nimport { createFetchTransport } from '../transport/fetch.js';\nimport {\n createSampler,\n eventTypeToSamplingType,\n type Sampler,\n} from './sampling.js';\nimport { createSessionManager, type SessionManager } from './session.js';\nimport { setMetricEmitter, getMetricEmitter } from '../metrics/index.js';\nimport type { ObserveOptions, VitalEvent, ObserveEvent, Transport } from '../types/index.js';\n\n// Default configuration\nconst defaults = {\n endpoint: '/api/metrics',\n vitals: true as const,\n errors: true,\n batchSize: 10,\n flushInterval: 5000,\n sampleRate: 1,\n debug: false,\n} satisfies Required<Omit<ObserveOptions, 'transport' | 'filter' | 'sampling' | 'session'>>;\n\n// Global observer callback for state machines\nlet globalObserverCallback: ((event: ObserveEvent) => void) | null = null;\n\n/**\n * Set global observer callback for state machines\n * Called internally to connect machines to observe()\n */\nexport function setGlobalObserver(callback: typeof globalObserverCallback): void {\n globalObserverCallback = callback;\n}\n\n/**\n * Get global observer callback\n * Used by createMachine to send transition events\n */\nexport function getGlobalObserver(): typeof globalObserverCallback {\n return globalObserverCallback;\n}\n\n/**\n * Main observe function - starts collecting metrics and errors\n *\n * @param options - Configuration options\n * @returns Cleanup function to stop observing\n *\n * @example\n * // Basic usage\n * observe();\n *\n * @example\n * // With options\n * observe({\n * endpoint: '/api/metrics',\n * vitals: ['CLS', 'LCP', 'INP'],\n * errors: true,\n * debug: true,\n * });\n */\nexport function observe(options: ObserveOptions = {}): () => void {\n // Legacy sampleRate support (deprecated) - skip entire observer\n if (Math.random() > (options.sampleRate ?? defaults.sampleRate)) {\n return () => {};\n }\n\n const config = { ...defaults, ...options };\n const transport: Transport = config.transport ?? createFetchTransport(config.endpoint);\n\n // Create sampler if sampling option is provided\n const sampler: Sampler | null = config.sampling != null\n ? createSampler(config.sampling)\n : null;\n\n // Create session manager if session option is provided\n const sessionManager: SessionManager | null = config.session != null\n ? createSessionManager(config.session)\n : null;\n\n const cleanups: (() => void)[] = [];\n\n // Cleanup session manager on destroy\n if (sessionManager) {\n cleanups.push(() => sessionManager.destroy());\n }\n const buffer: ObserveEvent[] = [];\n let flushTimer: ReturnType<typeof setInterval> | null = null;\n\n // Get current URL\n const getUrl = (): string => {\n try {\n return typeof location !== 'undefined' ? location.href : '';\n } catch {\n return '';\n }\n };\n\n // Buffer an event and potentially flush\n const bufferEvent = (event: ObserveEvent): void => {\n // Apply filter if provided\n if (config.filter && !config.filter(event)) {\n return;\n }\n\n // Apply per-event-type sampling\n if (sampler) {\n const samplingType = eventTypeToSamplingType(event.type);\n if (samplingType && !sampler.shouldSample(samplingType)) {\n return;\n }\n }\n\n // Add sessionId if session manager is enabled\n if (sessionManager) {\n (event as ObserveEvent & { sessionId?: string }).sessionId = sessionManager.getSessionId();\n }\n\n if (config.debug) {\n console.log('[svoose]', event);\n }\n\n buffer.push(event);\n\n if (buffer.length >= config.batchSize) {\n flush();\n }\n };\n\n // Send buffered events to transport\n const flush = (): void => {\n if (buffer.length === 0) return;\n\n const events = buffer.splice(0, buffer.length);\n // Handle both Promise and non-Promise returns from transport.send()\n const result = transport.send(events);\n if (result && typeof result.catch === 'function') {\n result.catch((err) => {\n if (config.debug) {\n console.error('[svoose] transport error:', err);\n }\n });\n }\n };\n\n // Convert metric to vital event\n const handleMetric = (metric: Metric): void => {\n const vitalEvent: VitalEvent = {\n type: 'vital',\n name: metric.name,\n value: metric.value,\n rating: metric.rating,\n delta: metric.delta,\n timestamp: metric.timestamp,\n url: getUrl(),\n };\n bufferEvent(vitalEvent);\n };\n\n // Setup vitals observers\n if (config.vitals) {\n const vitalsToObserve: MetricName[] =\n config.vitals === true\n ? ['CLS', 'LCP', 'FID', 'INP', 'FCP', 'TTFB']\n : config.vitals;\n\n for (const name of vitalsToObserve) {\n const observer = vitalObservers[name];\n if (observer) {\n cleanups.push(observer(handleMetric));\n }\n }\n }\n\n // Setup error observer\n if (config.errors) {\n cleanups.push(\n observeErrors((event: ObserveErrorEvent) => {\n bufferEvent(event);\n })\n );\n }\n\n // Setup global observer for state machines\n setGlobalObserver(bufferEvent);\n cleanups.push(() => {\n // Only clear if we're still the active observer\n if (getGlobalObserver() === bufferEvent) {\n setGlobalObserver(null);\n }\n });\n\n // Setup metric emitter for custom metrics\n setMetricEmitter(bufferEvent);\n cleanups.push(() => {\n // Only clear if we're still the active emitter\n if (getMetricEmitter() === bufferEvent) {\n setMetricEmitter(null);\n }\n });\n\n // Setup flush interval\n flushTimer = setInterval(flush, config.flushInterval);\n cleanups.push(() => {\n if (flushTimer) clearInterval(flushTimer);\n });\n\n // Flush on page visibility change (user navigating away)\n if (typeof document !== 'undefined') {\n const visibilityHandler = (): void => {\n if (document.visibilityState === 'hidden') {\n flush();\n }\n };\n document.addEventListener('visibilitychange', visibilityHandler);\n cleanups.push(() => {\n document.removeEventListener('visibilitychange', visibilityHandler);\n });\n }\n\n // Flush on beforeunload\n if (typeof window !== 'undefined') {\n const unloadHandler = (): void => {\n flush();\n };\n window.addEventListener('beforeunload', unloadHandler);\n cleanups.push(() => {\n window.removeEventListener('beforeunload', unloadHandler);\n });\n }\n\n // Return cleanup function\n return () => {\n flush();\n cleanups.forEach((fn) => fn());\n // Destroy transport if it has a destroy method (e.g. HybridTransport)\n (transport as Transport & { destroy?: () => void }).destroy?.();\n };\n}\n\nexport type { ObserveOptions };\n"],
5
+ "mappings": "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",
6
6
  "names": ["vitalObservers", "observeErrors", "createFetchTransport", "createSampler", "eventTypeToSamplingType", "createSessionManager", "setMetricEmitter", "getMetricEmitter", "defaults", "globalObserverCallback", "setGlobalObserver", "callback", "getGlobalObserver", "observe", "options", "config", "transport", "sampler", "sessionManager", "cleanups", "buffer", "flushTimer", "getUrl", "bufferEvent", "event", "samplingType", "flush", "events", "result", "err", "handleMetric", "metric", "vitalEvent", "vitalsToObserve", "name", "observer", "visibilityHandler", "unloadHandler", "fn"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"vitals.d.ts","sourceRoot":"","sources":["../../src/observe/vitals.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA2C1E;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CA4FzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CA8DzE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAczE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CA8DzE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAczE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAgB1E;AAcD,eAAO,MAAM,cAAc;;;;;;;CAOjB,CAAC;AAEX,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"vitals.d.ts","sourceRoot":"","sources":["../../src/observe/vitals.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA2C1E;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CA4FzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CA8DzE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAczE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAmEzE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAczE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAgB1E;AAcD,eAAO,MAAM,cAAc;;;;;;;CAOjB,CAAC;AAEX,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC"}
@@ -1,2 +1,2 @@
1
- const P={CLS:[.1,.25],LCP:[2500,4e3],FID:[100,300],INP:[200,500],FCP:[1800,3e3],TTFB:[800,1800]};function h(r,e){const[n,t]=P[r];return e<=n?"good":e<=t?"needs-improvement":"poor"}function v(r,e,n=0){return{name:r,value:e,rating:h(r,e),delta:e-n,timestamp:Date.now()}}function m(r){if(typeof PerformanceObserver>"u")return!1;try{return PerformanceObserver.supportedEntryTypes?.includes(r)??!1}catch{return!1}}function L(r){if(!m("layout-shift"))return()=>{};let e=0,n=-1,t=0,i=0,o=0,a=!1;const d=1e3,u=5e3,f=l=>{for(const E of l){const g=E;if(g.hadRecentInput)continue;const b=g.startTime;(n===-1||b-t>d||b-n>u)&&(n=b,e=0),e+=g.value,t=b,e>i&&(i=e)}},s=()=>{i>0&&i!==o&&(r(v("CLS",i,o)),o=i,a=!0)},c=()=>{document.visibilityState==="hidden"&&s()},p=()=>{s()},y=new PerformanceObserver(l=>{f(l.getEntries())});return y.observe({type:"layout-shift",buffered:!0}),document.addEventListener("visibilitychange",c),window.addEventListener("pagehide",p),()=>{y.disconnect(),document.removeEventListener("visibilitychange",c),window.removeEventListener("pagehide",p),!a&&i>0&&s()}}function S(r){if(!m("largest-contentful-paint"))return()=>{};let e=0,n=0,t=!1;const i=()=>{e>0&&!t&&(r(v("LCP",e,n)),n=e,t=!0)},o=new PerformanceObserver(s=>{const c=s.getEntries(),p=c[c.length-1];p&&(e=p.startTime)}),a=()=>{i(),o.disconnect(),f()},d=()=>a(),u=()=>{document.visibilityState==="hidden"&&a()},f=()=>{document.removeEventListener("visibilitychange",u),["keydown","click","pointerdown"].forEach(s=>{document.removeEventListener(s,d,{capture:!0})})};return o.observe({type:"largest-contentful-paint",buffered:!0}),document.addEventListener("visibilitychange",u),["keydown","click","pointerdown"].forEach(s=>{document.addEventListener(s,d,{capture:!0,once:!0})}),()=>{!t&&e>0&&i(),o.disconnect(),f()}}function T(r){if(!m("first-input"))return()=>{};const e=new PerformanceObserver(n=>{const t=n.getEntries()[0];if(t){const i=t.processingStart-t.startTime;r(v("FID",i)),e.disconnect()}});return e.observe({type:"first-input",buffered:!0}),()=>e.disconnect()}function I(r){if(!m("event"))return()=>{};let e=0,n=0,t=!1;const i=new Set,o=()=>{e>0&&!t&&(r(v("INP",e,n)),n=e,t=!0)},a=new PerformanceObserver(f=>{for(const s of f.getEntries()){const c=s;c.interactionId&&(i.has(c.interactionId)||(i.add(c.interactionId),c.duration>e&&(e=c.duration)))}}),d=()=>{document.visibilityState==="hidden"&&o()},u=()=>{o()};return a.observe({type:"event",buffered:!0,durationThreshold:16}),document.addEventListener("visibilitychange",d),window.addEventListener("pagehide",u),()=>{a.disconnect(),document.removeEventListener("visibilitychange",d),window.removeEventListener("pagehide",u),!t&&e>0&&o()}}function w(r){if(!m("paint"))return()=>{};const e=new PerformanceObserver(n=>{for(const t of n.getEntries())t.name==="first-contentful-paint"&&(r(v("FCP",t.startTime)),e.disconnect())});return e.observe({type:"paint",buffered:!0}),()=>e.disconnect()}function M(r){if(!m("navigation"))return()=>{};const e=new PerformanceObserver(n=>{const t=n.getEntries()[0];if(t){const i=t.activationStart??0,o=Math.max(t.responseStart-i,0);r(v("TTFB",o)),e.disconnect()}});return e.observe({type:"navigation",buffered:!0}),()=>e.disconnect()}const C={CLS:L,LCP:S,FID:T,INP:I,FCP:w,TTFB:M};export{L as observeCLS,w as observeFCP,T as observeFID,I as observeINP,S as observeLCP,M as observeTTFB,C as vitalObservers};
1
+ const P={CLS:[.1,.25],LCP:[2500,4e3],FID:[100,300],INP:[200,500],FCP:[1800,3e3],TTFB:[800,1800]};function h(i,e){const[n,t]=P[i];return e<=n?"good":e<=t?"needs-improvement":"poor"}function v(i,e,n=0){return{name:i,value:e,rating:h(i,e),delta:e-n,timestamp:Date.now()}}function m(i){if(typeof PerformanceObserver>"u")return!1;try{return PerformanceObserver.supportedEntryTypes?.includes(i)??!1}catch{return!1}}function L(i){if(!m("layout-shift"))return()=>{};let e=0,n=-1,t=0,r=0,o=0,a=!1;const d=1e3,f=5e3,u=l=>{for(const E of l){const g=E;if(g.hadRecentInput)continue;const b=g.startTime;(n===-1||b-t>d||b-n>f)&&(n=b,e=0),e+=g.value,t=b,e>r&&(r=e)}},s=()=>{r>0&&r!==o&&(i(v("CLS",r,o)),o=r,a=!0)},c=()=>{document.visibilityState==="hidden"&&s()},p=()=>{s()},y=new PerformanceObserver(l=>{u(l.getEntries())});return y.observe({type:"layout-shift",buffered:!0}),document.addEventListener("visibilitychange",c),window.addEventListener("pagehide",p),()=>{y.disconnect(),document.removeEventListener("visibilitychange",c),window.removeEventListener("pagehide",p),!a&&r>0&&s()}}function S(i){if(!m("largest-contentful-paint"))return()=>{};let e=0,n=0,t=!1;const r=()=>{e>0&&!t&&(i(v("LCP",e,n)),n=e,t=!0)},o=new PerformanceObserver(s=>{const c=s.getEntries(),p=c[c.length-1];p&&(e=p.startTime)}),a=()=>{r(),o.disconnect(),u()},d=()=>a(),f=()=>{document.visibilityState==="hidden"&&a()},u=()=>{document.removeEventListener("visibilitychange",f),["keydown","click","pointerdown"].forEach(s=>{document.removeEventListener(s,d,{capture:!0})})};return o.observe({type:"largest-contentful-paint",buffered:!0}),document.addEventListener("visibilitychange",f),["keydown","click","pointerdown"].forEach(s=>{document.addEventListener(s,d,{capture:!0,once:!0})}),()=>{!t&&e>0&&r(),o.disconnect(),u()}}function T(i){if(!m("first-input"))return()=>{};const e=new PerformanceObserver(n=>{const t=n.getEntries()[0];if(t){const r=t.processingStart-t.startTime;i(v("FID",r)),e.disconnect()}});return e.observe({type:"first-input",buffered:!0}),()=>e.disconnect()}function I(i){if(!m("event"))return()=>{};let e=0,n=0,t=!1;const r=new Set,o=()=>{e>0&&!t&&(i(v("INP",e,n)),n=e,t=!0)},a=new PerformanceObserver(u=>{for(const s of u.getEntries()){const c=s;c.interactionId&&(r.has(c.interactionId)||(r.size>=1e3&&r.clear(),r.add(c.interactionId),c.duration>e&&(e=c.duration)))}}),d=()=>{document.visibilityState==="hidden"&&o()},f=()=>{o()};return a.observe({type:"event",buffered:!0,durationThreshold:16}),document.addEventListener("visibilitychange",d),window.addEventListener("pagehide",f),()=>{a.disconnect(),document.removeEventListener("visibilitychange",d),window.removeEventListener("pagehide",f),!t&&e>0&&o()}}function w(i){if(!m("paint"))return()=>{};const e=new PerformanceObserver(n=>{for(const t of n.getEntries())t.name==="first-contentful-paint"&&(i(v("FCP",t.startTime)),e.disconnect())});return e.observe({type:"paint",buffered:!0}),()=>e.disconnect()}function M(i){if(!m("navigation"))return()=>{};const e=new PerformanceObserver(n=>{const t=n.getEntries()[0];if(t){const r=t.activationStart??0,o=Math.max(t.responseStart-r,0);i(v("TTFB",o)),e.disconnect()}});return e.observe({type:"navigation",buffered:!0}),()=>e.disconnect()}const C={CLS:L,LCP:S,FID:T,INP:I,FCP:w,TTFB:M};export{L as observeCLS,w as observeFCP,T as observeFID,I as observeINP,S as observeLCP,M as observeTTFB,C as vitalObservers};
2
2
  //# sourceMappingURL=vitals.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/observe/vitals.ts"],
4
- "sourcesContent": ["/**\n * Web Vitals collection - NO external dependencies\n * Uses PerformanceObserver API directly\n */\n\nimport type { MetricName, MetricRating, Metric } from '../types/index.js';\n\n// Google's official thresholds\nconst THRESHOLDS: Record<MetricName, [number, number]> = {\n CLS: [0.1, 0.25],\n LCP: [2500, 4000],\n FID: [100, 300],\n INP: [200, 500],\n FCP: [1800, 3000],\n TTFB: [800, 1800],\n};\n\nfunction getRating(name: MetricName, value: number): MetricRating {\n const [good, poor] = THRESHOLDS[name];\n if (value <= good) return 'good';\n if (value <= poor) return 'needs-improvement';\n return 'poor';\n}\n\nfunction createMetric(\n name: MetricName,\n value: number,\n prevValue: number = 0\n): Metric {\n return {\n name,\n value,\n rating: getRating(name, value),\n delta: value - prevValue,\n timestamp: Date.now(),\n };\n}\n\n// Check if PerformanceObserver supports given entry type\nfunction isSupported(type: string): boolean {\n if (typeof PerformanceObserver === 'undefined') return false;\n try {\n return PerformanceObserver.supportedEntryTypes?.includes(type) ?? false;\n } catch {\n return false;\n }\n}\n\n/**\n * CLS - Cumulative Layout Shift\n * Measures visual stability using session windows algorithm (web-vitals standard)\n *\n * Session window rules:\n * - Max duration: 5 seconds\n * - Max gap between shifts: 1 second\n * - Reports final value on visibility change (hidden) or pagehide\n *\n * @see https://web.dev/cls/#what-is-a-good-cls-score\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onCLS.ts\n */\nexport function observeCLS(callback: (metric: Metric) => void): () => void {\n if (!isSupported('layout-shift')) return () => {};\n\n // Session window state\n let sessionValue = 0;\n let sessionStart = -1;\n let lastEntryTime = 0;\n\n // Track max session for final CLS value\n let maxSessionValue = 0;\n let prevReportedValue = 0;\n let hasReported = false;\n\n const SESSION_GAP = 1000; // 1 second max gap\n const SESSION_MAX = 5000; // 5 seconds max duration\n\n const processEntries = (entries: PerformanceEntryList) => {\n for (const entry of entries) {\n const shift = entry as LayoutShiftEntry;\n\n // Ignore shifts with recent user input (clicks, taps, key presses)\n if (shift.hadRecentInput) continue;\n\n const entryTime = shift.startTime;\n\n // Start new session if:\n // 1. First entry ever\n // 2. Gap from last entry > 1 second\n // 3. Session duration would exceed 5 seconds\n if (\n sessionStart === -1 ||\n entryTime - lastEntryTime > SESSION_GAP ||\n entryTime - sessionStart > SESSION_MAX\n ) {\n // Start new session\n sessionStart = entryTime;\n sessionValue = 0;\n }\n\n // Accumulate shift in current session\n sessionValue += shift.value;\n lastEntryTime = entryTime;\n\n // Track maximum session value (this is the CLS score)\n if (sessionValue > maxSessionValue) {\n maxSessionValue = sessionValue;\n }\n }\n };\n\n const reportCLS = () => {\n // Only report if we have a value and it changed\n if (maxSessionValue > 0 && maxSessionValue !== prevReportedValue) {\n callback(createMetric('CLS', maxSessionValue, prevReportedValue));\n prevReportedValue = maxSessionValue;\n hasReported = true;\n }\n };\n\n // Report on visibility change (user switches tab or minimizes)\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n reportCLS();\n }\n };\n\n // Report on page unload (closing tab, navigation away)\n const onPageHide = () => {\n reportCLS();\n };\n\n const observer = new PerformanceObserver((list) => {\n processEntries(list.getEntries());\n });\n\n observer.observe({ type: 'layout-shift', buffered: true });\n\n // Listen for lifecycle events to report final CLS\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pagehide', onPageHide);\n\n // Cleanup function\n return () => {\n observer.disconnect();\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pagehide', onPageHide);\n\n // Report final value on disconnect if not already reported\n if (!hasReported && maxSessionValue > 0) {\n reportCLS();\n }\n };\n}\n\n/**\n * LCP - Largest Contentful Paint\n * Measures loading performance\n *\n * LCP is finalized when:\n * - User interacts with the page (click, keydown, scroll, etc.)\n * - Page becomes hidden (visibility change)\n *\n * @see https://web.dev/lcp/\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onLCP.ts\n */\nexport function observeLCP(callback: (metric: Metric) => void): () => void {\n if (!isSupported('largest-contentful-paint')) return () => {};\n\n let lcpValue = 0;\n let prevReportedValue = 0;\n let hasReported = false;\n\n const reportLCP = () => {\n if (lcpValue > 0 && !hasReported) {\n callback(createMetric('LCP', lcpValue, prevReportedValue));\n prevReportedValue = lcpValue;\n hasReported = true;\n }\n };\n\n const observer = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n // LCP can have multiple entries, track the last one\n const lastEntry = entries[entries.length - 1];\n if (lastEntry) {\n lcpValue = lastEntry.startTime;\n }\n });\n\n // LCP is finalized on first user input\n const stopListening = () => {\n reportLCP();\n observer.disconnect();\n removeEventListeners();\n };\n\n // User input events that finalize LCP\n const onInput = () => stopListening();\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n stopListening();\n }\n };\n\n const removeEventListeners = () => {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n // Use capture to catch events before they're handled\n ['keydown', 'click', 'pointerdown'].forEach((type) => {\n document.removeEventListener(type, onInput, { capture: true } as EventListenerOptions);\n });\n };\n\n observer.observe({ type: 'largest-contentful-paint', buffered: true });\n\n // Listen for events that finalize LCP\n document.addEventListener('visibilitychange', onVisibilityChange);\n ['keydown', 'click', 'pointerdown'].forEach((type) => {\n document.addEventListener(type, onInput, { capture: true, once: true });\n });\n\n return () => {\n if (!hasReported && lcpValue > 0) {\n reportLCP();\n }\n observer.disconnect();\n removeEventListeners();\n };\n}\n\n/**\n * FID - First Input Delay\n * Measures interactivity (deprecated in favor of INP)\n */\nexport function observeFID(callback: (metric: Metric) => void): () => void {\n if (!isSupported('first-input')) return () => {};\n\n const observer = new PerformanceObserver((list) => {\n const entry = list.getEntries()[0] as PerformanceEventTiming | undefined;\n if (entry) {\n const value = entry.processingStart - entry.startTime;\n callback(createMetric('FID', value));\n observer.disconnect();\n }\n });\n\n observer.observe({ type: 'first-input', buffered: true });\n return () => observer.disconnect();\n}\n\n/**\n * INP - Interaction to Next Paint\n * Measures responsiveness (replaced FID as Core Web Vital)\n *\n * INP tracks the worst interaction latency during the page lifecycle.\n * Reports on visibility change (hidden) or pagehide.\n *\n * Simplified algorithm (vs web-vitals p98):\n * - Tracks max interaction duration\n * - Only counts discrete events (click, keydown, pointerdown)\n * - Reports once on page hide\n *\n * @see https://web.dev/inp/\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onINP.ts\n */\nexport function observeINP(callback: (metric: Metric) => void): () => void {\n if (!isSupported('event')) return () => {};\n\n let maxINP = 0;\n let prevReportedValue = 0;\n let hasReported = false;\n\n // Track interactions by interactionId to avoid counting same interaction twice\n const processedInteractions = new Set<number>();\n\n const reportINP = () => {\n if (maxINP > 0 && !hasReported) {\n callback(createMetric('INP', maxINP, prevReportedValue));\n prevReportedValue = maxINP;\n hasReported = true;\n }\n };\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n const eventEntry = entry as PerformanceEventTimingExtended;\n\n // Only count discrete events (not scroll, mousemove, etc.)\n // interactionId is 0 or undefined for non-interaction events\n if (!eventEntry.interactionId) continue;\n\n // Avoid counting the same interaction multiple times\n // (e.g., pointerdown + pointerup for same click)\n if (processedInteractions.has(eventEntry.interactionId)) continue;\n processedInteractions.add(eventEntry.interactionId);\n\n // Track maximum interaction duration\n if (eventEntry.duration > maxINP) {\n maxINP = eventEntry.duration;\n }\n }\n });\n\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n reportINP();\n }\n };\n\n const onPageHide = () => {\n reportINP();\n };\n\n observer.observe({ type: 'event', buffered: true, durationThreshold: 16 } as PerformanceObserverInit);\n\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pagehide', onPageHide);\n\n return () => {\n observer.disconnect();\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pagehide', onPageHide);\n\n if (!hasReported && maxINP > 0) {\n reportINP();\n }\n };\n}\n\n/**\n * FCP - First Contentful Paint\n * Measures when first content is painted\n */\nexport function observeFCP(callback: (metric: Metric) => void): () => void {\n if (!isSupported('paint')) return () => {};\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name === 'first-contentful-paint') {\n callback(createMetric('FCP', entry.startTime));\n observer.disconnect();\n }\n }\n });\n\n observer.observe({ type: 'paint', buffered: true });\n return () => observer.disconnect();\n}\n\n/**\n * TTFB - Time to First Byte\n * Measures server response time from navigation start\n *\n * TTFB = responseStart - activationStart (or 0 if no bfcache)\n *\n * activationStart is non-zero for bfcache restores, ensuring we measure\n * the actual server response time, not time in cache.\n *\n * @see https://web.dev/ttfb/\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onTTFB.ts\n */\nexport function observeTTFB(callback: (metric: Metric) => void): () => void {\n if (!isSupported('navigation')) return () => {};\n\n const observer = new PerformanceObserver((list) => {\n const entry = list.getEntries()[0] as PerformanceNavigationTiming | undefined;\n if (entry) {\n // activationStart is non-zero for bfcache restores\n const activationStart = (entry as PerformanceNavigationTiming & { activationStart?: number }).activationStart ?? 0;\n const value = Math.max(entry.responseStart - activationStart, 0);\n callback(createMetric('TTFB', value));\n observer.disconnect();\n }\n });\n\n observer.observe({ type: 'navigation', buffered: true });\n return () => observer.disconnect();\n}\n\n// Type for layout-shift entries (not in standard lib)\ninterface LayoutShiftEntry extends PerformanceEntry {\n value: number;\n hadRecentInput: boolean;\n}\n\n// Extended PerformanceEventTiming with interactionId (not in all TS versions)\ninterface PerformanceEventTimingExtended extends PerformanceEventTiming {\n interactionId?: number;\n}\n\n// Export observer map for easy access\nexport const vitalObservers = {\n CLS: observeCLS,\n LCP: observeLCP,\n FID: observeFID,\n INP: observeINP,\n FCP: observeFCP,\n TTFB: observeTTFB,\n} as const;\n\nexport type { Metric, MetricName, MetricRating };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Web Vitals collection - NO external dependencies\n * Uses PerformanceObserver API directly\n */\n\nimport type { MetricName, MetricRating, Metric } from '../types/index.js';\n\n// Google's official thresholds\nconst THRESHOLDS: Record<MetricName, [number, number]> = {\n CLS: [0.1, 0.25],\n LCP: [2500, 4000],\n FID: [100, 300],\n INP: [200, 500],\n FCP: [1800, 3000],\n TTFB: [800, 1800],\n};\n\nfunction getRating(name: MetricName, value: number): MetricRating {\n const [good, poor] = THRESHOLDS[name];\n if (value <= good) return 'good';\n if (value <= poor) return 'needs-improvement';\n return 'poor';\n}\n\nfunction createMetric(\n name: MetricName,\n value: number,\n prevValue: number = 0\n): Metric {\n return {\n name,\n value,\n rating: getRating(name, value),\n delta: value - prevValue,\n timestamp: Date.now(),\n };\n}\n\n// Check if PerformanceObserver supports given entry type\nfunction isSupported(type: string): boolean {\n if (typeof PerformanceObserver === 'undefined') return false;\n try {\n return PerformanceObserver.supportedEntryTypes?.includes(type) ?? false;\n } catch {\n return false;\n }\n}\n\n/**\n * CLS - Cumulative Layout Shift\n * Measures visual stability using session windows algorithm (web-vitals standard)\n *\n * Session window rules:\n * - Max duration: 5 seconds\n * - Max gap between shifts: 1 second\n * - Reports final value on visibility change (hidden) or pagehide\n *\n * @see https://web.dev/cls/#what-is-a-good-cls-score\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onCLS.ts\n */\nexport function observeCLS(callback: (metric: Metric) => void): () => void {\n if (!isSupported('layout-shift')) return () => {};\n\n // Session window state\n let sessionValue = 0;\n let sessionStart = -1;\n let lastEntryTime = 0;\n\n // Track max session for final CLS value\n let maxSessionValue = 0;\n let prevReportedValue = 0;\n let hasReported = false;\n\n const SESSION_GAP = 1000; // 1 second max gap\n const SESSION_MAX = 5000; // 5 seconds max duration\n\n const processEntries = (entries: PerformanceEntryList) => {\n for (const entry of entries) {\n const shift = entry as LayoutShiftEntry;\n\n // Ignore shifts with recent user input (clicks, taps, key presses)\n if (shift.hadRecentInput) continue;\n\n const entryTime = shift.startTime;\n\n // Start new session if:\n // 1. First entry ever\n // 2. Gap from last entry > 1 second\n // 3. Session duration would exceed 5 seconds\n if (\n sessionStart === -1 ||\n entryTime - lastEntryTime > SESSION_GAP ||\n entryTime - sessionStart > SESSION_MAX\n ) {\n // Start new session\n sessionStart = entryTime;\n sessionValue = 0;\n }\n\n // Accumulate shift in current session\n sessionValue += shift.value;\n lastEntryTime = entryTime;\n\n // Track maximum session value (this is the CLS score)\n if (sessionValue > maxSessionValue) {\n maxSessionValue = sessionValue;\n }\n }\n };\n\n const reportCLS = () => {\n // Only report if we have a value and it changed\n if (maxSessionValue > 0 && maxSessionValue !== prevReportedValue) {\n callback(createMetric('CLS', maxSessionValue, prevReportedValue));\n prevReportedValue = maxSessionValue;\n hasReported = true;\n }\n };\n\n // Report on visibility change (user switches tab or minimizes)\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n reportCLS();\n }\n };\n\n // Report on page unload (closing tab, navigation away)\n const onPageHide = () => {\n reportCLS();\n };\n\n const observer = new PerformanceObserver((list) => {\n processEntries(list.getEntries());\n });\n\n observer.observe({ type: 'layout-shift', buffered: true });\n\n // Listen for lifecycle events to report final CLS\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pagehide', onPageHide);\n\n // Cleanup function\n return () => {\n observer.disconnect();\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pagehide', onPageHide);\n\n // Report final value on disconnect if not already reported\n if (!hasReported && maxSessionValue > 0) {\n reportCLS();\n }\n };\n}\n\n/**\n * LCP - Largest Contentful Paint\n * Measures loading performance\n *\n * LCP is finalized when:\n * - User interacts with the page (click, keydown, scroll, etc.)\n * - Page becomes hidden (visibility change)\n *\n * @see https://web.dev/lcp/\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onLCP.ts\n */\nexport function observeLCP(callback: (metric: Metric) => void): () => void {\n if (!isSupported('largest-contentful-paint')) return () => {};\n\n let lcpValue = 0;\n let prevReportedValue = 0;\n let hasReported = false;\n\n const reportLCP = () => {\n if (lcpValue > 0 && !hasReported) {\n callback(createMetric('LCP', lcpValue, prevReportedValue));\n prevReportedValue = lcpValue;\n hasReported = true;\n }\n };\n\n const observer = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n // LCP can have multiple entries, track the last one\n const lastEntry = entries[entries.length - 1];\n if (lastEntry) {\n lcpValue = lastEntry.startTime;\n }\n });\n\n // LCP is finalized on first user input\n const stopListening = () => {\n reportLCP();\n observer.disconnect();\n removeEventListeners();\n };\n\n // User input events that finalize LCP\n const onInput = () => stopListening();\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n stopListening();\n }\n };\n\n const removeEventListeners = () => {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n // Use capture to catch events before they're handled\n ['keydown', 'click', 'pointerdown'].forEach((type) => {\n document.removeEventListener(type, onInput, { capture: true } as EventListenerOptions);\n });\n };\n\n observer.observe({ type: 'largest-contentful-paint', buffered: true });\n\n // Listen for events that finalize LCP\n document.addEventListener('visibilitychange', onVisibilityChange);\n ['keydown', 'click', 'pointerdown'].forEach((type) => {\n document.addEventListener(type, onInput, { capture: true, once: true });\n });\n\n return () => {\n if (!hasReported && lcpValue > 0) {\n reportLCP();\n }\n observer.disconnect();\n removeEventListeners();\n };\n}\n\n/**\n * FID - First Input Delay\n * Measures interactivity (deprecated in favor of INP)\n */\nexport function observeFID(callback: (metric: Metric) => void): () => void {\n if (!isSupported('first-input')) return () => {};\n\n const observer = new PerformanceObserver((list) => {\n const entry = list.getEntries()[0] as PerformanceEventTiming | undefined;\n if (entry) {\n const value = entry.processingStart - entry.startTime;\n callback(createMetric('FID', value));\n observer.disconnect();\n }\n });\n\n observer.observe({ type: 'first-input', buffered: true });\n return () => observer.disconnect();\n}\n\n/**\n * INP - Interaction to Next Paint\n * Measures responsiveness (replaced FID as Core Web Vital)\n *\n * INP tracks the worst interaction latency during the page lifecycle.\n * Reports on visibility change (hidden) or pagehide.\n *\n * Simplified algorithm (vs web-vitals p98):\n * - Tracks max interaction duration\n * - Only counts discrete events (click, keydown, pointerdown)\n * - Reports once on page hide\n *\n * @see https://web.dev/inp/\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onINP.ts\n */\nexport function observeINP(callback: (metric: Metric) => void): () => void {\n if (!isSupported('event')) return () => {};\n\n let maxINP = 0;\n let prevReportedValue = 0;\n let hasReported = false;\n\n // Track interactions by interactionId to avoid counting same interaction twice\n const processedInteractions = new Set<number>();\n\n const reportINP = () => {\n if (maxINP > 0 && !hasReported) {\n callback(createMetric('INP', maxINP, prevReportedValue));\n prevReportedValue = maxINP;\n hasReported = true;\n }\n };\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n const eventEntry = entry as PerformanceEventTimingExtended;\n\n // Only count discrete events (not scroll, mousemove, etc.)\n // interactionId is 0 or undefined for non-interaction events\n if (!eventEntry.interactionId) continue;\n\n // Avoid counting the same interaction multiple times\n // (e.g., pointerdown + pointerup for same click)\n if (processedInteractions.has(eventEntry.interactionId)) continue;\n\n // Prevent unbounded growth in long-lived SPAs\n if (processedInteractions.size >= 1000) {\n processedInteractions.clear();\n }\n processedInteractions.add(eventEntry.interactionId);\n\n // Track maximum interaction duration\n if (eventEntry.duration > maxINP) {\n maxINP = eventEntry.duration;\n }\n }\n });\n\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n reportINP();\n }\n };\n\n const onPageHide = () => {\n reportINP();\n };\n\n observer.observe({ type: 'event', buffered: true, durationThreshold: 16 } as PerformanceObserverInit);\n\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pagehide', onPageHide);\n\n return () => {\n observer.disconnect();\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pagehide', onPageHide);\n\n if (!hasReported && maxINP > 0) {\n reportINP();\n }\n };\n}\n\n/**\n * FCP - First Contentful Paint\n * Measures when first content is painted\n */\nexport function observeFCP(callback: (metric: Metric) => void): () => void {\n if (!isSupported('paint')) return () => {};\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name === 'first-contentful-paint') {\n callback(createMetric('FCP', entry.startTime));\n observer.disconnect();\n }\n }\n });\n\n observer.observe({ type: 'paint', buffered: true });\n return () => observer.disconnect();\n}\n\n/**\n * TTFB - Time to First Byte\n * Measures server response time from navigation start\n *\n * TTFB = responseStart - activationStart (or 0 if no bfcache)\n *\n * activationStart is non-zero for bfcache restores, ensuring we measure\n * the actual server response time, not time in cache.\n *\n * @see https://web.dev/ttfb/\n * @see https://github.com/GoogleChrome/web-vitals/blob/main/src/onTTFB.ts\n */\nexport function observeTTFB(callback: (metric: Metric) => void): () => void {\n if (!isSupported('navigation')) return () => {};\n\n const observer = new PerformanceObserver((list) => {\n const entry = list.getEntries()[0] as PerformanceNavigationTiming | undefined;\n if (entry) {\n // activationStart is non-zero for bfcache restores\n const activationStart = (entry as PerformanceNavigationTiming & { activationStart?: number }).activationStart ?? 0;\n const value = Math.max(entry.responseStart - activationStart, 0);\n callback(createMetric('TTFB', value));\n observer.disconnect();\n }\n });\n\n observer.observe({ type: 'navigation', buffered: true });\n return () => observer.disconnect();\n}\n\n// Type for layout-shift entries (not in standard lib)\ninterface LayoutShiftEntry extends PerformanceEntry {\n value: number;\n hadRecentInput: boolean;\n}\n\n// Extended PerformanceEventTiming with interactionId (not in all TS versions)\ninterface PerformanceEventTimingExtended extends PerformanceEventTiming {\n interactionId?: number;\n}\n\n// Export observer map for easy access\nexport const vitalObservers = {\n CLS: observeCLS,\n LCP: observeLCP,\n FID: observeFID,\n INP: observeINP,\n FCP: observeFCP,\n TTFB: observeTTFB,\n} as const;\n\nexport type { Metric, MetricName, MetricRating };\n"],
5
+ "mappings": "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",
6
6
  "names": ["THRESHOLDS", "getRating", "name", "value", "good", "poor", "createMetric", "prevValue", "isSupported", "type", "observeCLS", "callback", "sessionValue", "sessionStart", "lastEntryTime", "maxSessionValue", "prevReportedValue", "hasReported", "SESSION_GAP", "SESSION_MAX", "processEntries", "entries", "entry", "shift", "entryTime", "reportCLS", "onVisibilityChange", "onPageHide", "observer", "list", "observeLCP", "lcpValue", "reportLCP", "lastEntry", "stopListening", "removeEventListeners", "onInput", "observeFID", "observeINP", "maxINP", "processedInteractions", "reportINP", "eventEntry", "observeFCP", "observeTTFB", "activationStart", "vitalObservers"]
7
7
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Beacon-based transport using navigator.sendBeacon
3
+ * Guarantees delivery even during page unload
4
+ */
5
+ import type { Transport, BeaconTransportOptions } from '../types/index.js';
6
+ /**
7
+ * Create a beacon-based transport
8
+ * Uses navigator.sendBeacon for reliable delivery during page unload
9
+ *
10
+ * @param endpoint - URL to send events to
11
+ * @param options - Beacon transport options
12
+ */
13
+ export declare function createBeaconTransport(endpoint: string, options?: BeaconTransportOptions): Transport;
14
+ //# sourceMappingURL=beacon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beacon.d.ts","sourceRoot":"","sources":["../../src/transport/beacon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAgB,MAAM,mBAAmB,CAAC;AAKzF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,SAAS,CA8CX"}
@@ -0,0 +1,2 @@
1
+ function l(i,r={}){const s=r.maxPayloadSize??61440;function e(n,o){if(n.length===0)return;if(o>=20){console.error("[svoose] Beacon chunk depth limit reached, dropping events");return}const t=JSON.stringify(n);if(t.length>s){if(n.length===1){console.error("[svoose] Single event exceeds maxPayloadSize, dropping");return}const a=Math.floor(n.length/2);e(n.slice(0,a),o+1),e(n.slice(a),o+1);return}if(typeof navigator>"u"||!navigator.sendBeacon)return;const c=new Blob([t],{type:"application/json"});navigator.sendBeacon(i,c)||r.onError?.(new Error("sendBeacon failed"))}return{send(n){n.length!==0&&(typeof navigator>"u"||e(n,0))}}}export{l as createBeaconTransport};
2
+ //# sourceMappingURL=beacon.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/transport/beacon.ts"],
4
+ "sourcesContent": ["/**\n * Beacon-based transport using navigator.sendBeacon\n * Guarantees delivery even during page unload\n */\n\nimport type { Transport, BeaconTransportOptions, ObserveEvent } from '../types/index.js';\n\nconst DEFAULT_MAX_PAYLOAD_SIZE = 60 * 1024; // 60KB\nconst MAX_CHUNK_DEPTH = 20;\n\n/**\n * Create a beacon-based transport\n * Uses navigator.sendBeacon for reliable delivery during page unload\n *\n * @param endpoint - URL to send events to\n * @param options - Beacon transport options\n */\nexport function createBeaconTransport(\n endpoint: string,\n options: BeaconTransportOptions = {}\n): Transport {\n const maxPayloadSize = options.maxPayloadSize ?? DEFAULT_MAX_PAYLOAD_SIZE;\n\n function sendChunk(events: ObserveEvent[], depth: number): void {\n if (events.length === 0) return;\n\n if (depth >= MAX_CHUNK_DEPTH) {\n console.error('[svoose] Beacon chunk depth limit reached, dropping events');\n return;\n }\n\n const payload = JSON.stringify(events);\n\n if (payload.length > maxPayloadSize) {\n if (events.length === 1) {\n console.error('[svoose] Single event exceeds maxPayloadSize, dropping');\n return;\n }\n\n // Split in half and recurse\n const mid = Math.floor(events.length / 2);\n sendChunk(events.slice(0, mid), depth + 1);\n sendChunk(events.slice(mid), depth + 1);\n return;\n }\n\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return;\n\n const blob = new Blob([payload], { type: 'application/json' });\n const success = navigator.sendBeacon(endpoint, blob);\n\n if (!success) {\n options.onError?.(new Error('sendBeacon failed'));\n }\n }\n\n return {\n send(events) {\n if (events.length === 0) return;\n\n // SSR guard\n if (typeof navigator === 'undefined') return;\n\n sendChunk(events, 0);\n },\n };\n}\n"],
5
+ "mappings": "AAiBO,SAASA,EACdC,EACAC,EAAkC,CAAC,EACxB,CACX,MAAMC,EAAiBD,EAAQ,gBAAkB,MAEjD,SAASE,EAAUC,EAAwBC,EAAqB,CAC9D,GAAID,EAAO,SAAW,EAAG,OAEzB,GAAIC,GAAS,GAAiB,CAC5B,QAAQ,MAAM,4DAA4D,EAC1E,MACF,CAEA,MAAMC,EAAU,KAAK,UAAUF,CAAM,EAErC,GAAIE,EAAQ,OAASJ,EAAgB,CACnC,GAAIE,EAAO,SAAW,EAAG,CACvB,QAAQ,MAAM,wDAAwD,EACtE,MACF,CAGA,MAAMG,EAAM,KAAK,MAAMH,EAAO,OAAS,CAAC,EACxCD,EAAUC,EAAO,MAAM,EAAGG,CAAG,EAAGF,EAAQ,CAAC,EACzCF,EAAUC,EAAO,MAAMG,CAAG,EAAGF,EAAQ,CAAC,EACtC,MACF,CAEA,GAAI,OAAO,UAAc,KAAe,CAAC,UAAU,WAAY,OAE/D,MAAMG,EAAO,IAAI,KAAK,CAACF,CAAO,EAAG,CAAE,KAAM,kBAAmB,CAAC,EAC7C,UAAU,WAAWN,EAAUQ,CAAI,GAGjDP,EAAQ,UAAU,IAAI,MAAM,mBAAmB,CAAC,CAEpD,CAEA,MAAO,CACL,KAAKG,EAAQ,CACPA,EAAO,SAAW,IAGlB,OAAO,UAAc,KAEzBD,EAAUC,EAAQ,CAAC,EACrB,CACF,CACF",
6
+ "names": ["createBeaconTransport", "endpoint", "options", "maxPayloadSize", "sendChunk", "events", "depth", "payload", "mid", "blob"]
7
+ }
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Fetch-based transport with sendBeacon fallback
2
+ * Fetch-based transport
3
3
  */
4
4
  import type { Transport, TransportOptions } from '../types/index.js';
5
5
  /**
6
6
  * Create a fetch-based transport
7
- * Uses sendBeacon for page unload, fetch otherwise
7
+ * Always uses fetch with keepalive: true
8
8
  *
9
9
  * @param endpoint - URL to send events to
10
10
  * @param options - Transport options (headers, error callback)
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/transport/fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,SAAS,CAwCX;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,SAAS,CAYpF"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/transport/fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,SAAS,CAoBX;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,SAAS,CAYpF"}
@@ -1,2 +1,2 @@
1
- function a(o,n={}){return{async send(e){if(e.length!==0)try{const t=JSON.stringify(e);if(typeof document<"u"&&document.visibilityState==="hidden"&&typeof navigator<"u"&&navigator.sendBeacon){const r=new Blob([t],{type:"application/json"});if(!navigator.sendBeacon(o,r))throw new Error("sendBeacon failed");return}await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",...n.headers},body:t,keepalive:!0})}catch(t){n.onError?.(t)}}}}function i(o={}){return{async send(n){for(const e of n)o.pretty?console.log("[svoose]",JSON.stringify(e,null,2)):console.log("[svoose]",e)}}}export{i as createConsoleTransport,a as createFetchTransport};
1
+ function n(o,e={}){return{async send(r){if(r.length!==0)try{await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(r),keepalive:!0})}catch(t){e.onError?.(t)}}}}function s(o={}){return{async send(e){for(const r of e)o.pretty?console.log("[svoose]",JSON.stringify(r,null,2)):console.log("[svoose]",r)}}}export{s as createConsoleTransport,n as createFetchTransport};
2
2
  //# sourceMappingURL=fetch.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/transport/fetch.ts"],
4
- "sourcesContent": ["/**\n * Fetch-based transport with sendBeacon fallback\n */\n\nimport type { Transport, TransportOptions } from '../types/index.js';\n\n/**\n * Create a fetch-based transport\n * Uses sendBeacon for page unload, fetch otherwise\n *\n * @param endpoint - URL to send events to\n * @param options - Transport options (headers, error callback)\n */\nexport function createFetchTransport(\n endpoint: string,\n options: TransportOptions = {}\n): Transport {\n return {\n async send(events) {\n if (events.length === 0) return;\n\n try {\n const payload = JSON.stringify(events);\n\n // Use sendBeacon when page is hidden (e.g., user navigating away)\n // sendBeacon is more reliable for unload scenarios\n if (\n typeof document !== 'undefined' &&\n document.visibilityState === 'hidden' &&\n typeof navigator !== 'undefined' &&\n navigator.sendBeacon\n ) {\n const blob = new Blob([payload], { type: 'application/json' });\n const success = navigator.sendBeacon(endpoint, blob);\n if (!success) {\n throw new Error('sendBeacon failed');\n }\n return;\n }\n\n // Use fetch for normal operation\n await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n body: payload,\n // keepalive ensures request completes even if page is closed\n keepalive: true,\n });\n } catch (error) {\n options.onError?.(error as Error);\n }\n },\n };\n}\n\n/**\n * Create a console transport for development/debugging\n */\nexport function createConsoleTransport(options: { pretty?: boolean } = {}): Transport {\n return {\n async send(events) {\n for (const event of events) {\n if (options.pretty) {\n console.log('[svoose]', JSON.stringify(event, null, 2));\n } else {\n console.log('[svoose]', event);\n }\n }\n },\n };\n}\n"],
5
- "mappings": "AAaO,SAASA,EACdC,EACAC,EAA4B,CAAC,EAClB,CACX,MAAO,CACL,MAAM,KAAKC,EAAQ,CACjB,GAAIA,EAAO,SAAW,EAEtB,GAAI,CACF,MAAMC,EAAU,KAAK,UAAUD,CAAM,EAIrC,GACE,OAAO,SAAa,KACpB,SAAS,kBAAoB,UAC7B,OAAO,UAAc,KACrB,UAAU,WACV,CACA,MAAME,EAAO,IAAI,KAAK,CAACD,CAAO,EAAG,CAAE,KAAM,kBAAmB,CAAC,EAE7D,GAAI,CADY,UAAU,WAAWH,EAAUI,CAAI,EAEjD,MAAM,IAAI,MAAM,mBAAmB,EAErC,MACF,CAGA,MAAM,MAAMJ,EAAU,CACpB,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,GAAGC,EAAQ,OACb,EACA,KAAME,EAEN,UAAW,EACb,CAAC,CACH,OAASE,EAAO,CACdJ,EAAQ,UAAUI,CAAc,CAClC,CACF,CACF,CACF,CAKO,SAASC,EAAuBL,EAAgC,CAAC,EAAc,CACpF,MAAO,CACL,MAAM,KAAKC,EAAQ,CACjB,UAAWK,KAASL,EACdD,EAAQ,OACV,QAAQ,IAAI,WAAY,KAAK,UAAUM,EAAO,KAAM,CAAC,CAAC,EAEtD,QAAQ,IAAI,WAAYA,CAAK,CAGnC,CACF,CACF",
6
- "names": ["createFetchTransport", "endpoint", "options", "events", "payload", "blob", "error", "createConsoleTransport", "event"]
4
+ "sourcesContent": ["/**\n * Fetch-based transport\n */\n\nimport type { Transport, TransportOptions } from '../types/index.js';\n\n/**\n * Create a fetch-based transport\n * Always uses fetch with keepalive: true\n *\n * @param endpoint - URL to send events to\n * @param options - Transport options (headers, error callback)\n */\nexport function createFetchTransport(\n endpoint: string,\n options: TransportOptions = {}\n): Transport {\n return {\n async send(events) {\n if (events.length === 0) return;\n\n try {\n await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n body: JSON.stringify(events),\n keepalive: true,\n });\n } catch (error) {\n options.onError?.(error as Error);\n }\n },\n };\n}\n\n/**\n * Create a console transport for development/debugging\n */\nexport function createConsoleTransport(options: { pretty?: boolean } = {}): Transport {\n return {\n async send(events) {\n for (const event of events) {\n if (options.pretty) {\n console.log('[svoose]', JSON.stringify(event, null, 2));\n } else {\n console.log('[svoose]', event);\n }\n }\n },\n };\n}\n"],
5
+ "mappings": "AAaO,SAASA,EACdC,EACAC,EAA4B,CAAC,EAClB,CACX,MAAO,CACL,MAAM,KAAKC,EAAQ,CACjB,GAAIA,EAAO,SAAW,EAEtB,GAAI,CACF,MAAM,MAAMF,EAAU,CACpB,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,GAAGC,EAAQ,OACb,EACA,KAAM,KAAK,UAAUC,CAAM,EAC3B,UAAW,EACb,CAAC,CACH,OAASC,EAAO,CACdF,EAAQ,UAAUE,CAAc,CAClC,CACF,CACF,CACF,CAKO,SAASC,EAAuBH,EAAgC,CAAC,EAAc,CACpF,MAAO,CACL,MAAM,KAAKC,EAAQ,CACjB,UAAWG,KAASH,EACdD,EAAQ,OACV,QAAQ,IAAI,WAAY,KAAK,UAAUI,EAAO,KAAM,CAAC,CAAC,EAEtD,QAAQ,IAAI,WAAYA,CAAK,CAGnC,CACF,CACF",
6
+ "names": ["createFetchTransport", "endpoint", "options", "events", "error", "createConsoleTransport", "event"]
7
7
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Hybrid transport — fetch by default, beacon on page unload
3
+ */
4
+ import type { HybridTransport, HybridTransportOptions } from '../types/index.js';
5
+ /**
6
+ * Create a hybrid transport that switches between fetch and beacon
7
+ * based on page lifecycle events
8
+ *
9
+ * @param endpoint - URL to send events to
10
+ * @param options - Hybrid transport options
11
+ */
12
+ export declare function createHybridTransport(endpoint: string, options?: HybridTransportOptions): HybridTransport;
13
+ //# sourceMappingURL=hybrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/transport/hybrid.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAgB,MAAM,mBAAmB,CAAC;AAI/F;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,eAAe,CA2CjB"}
@@ -0,0 +1,2 @@
1
+ import{createFetchTransport as b}from"./fetch.js";import{createBeaconTransport as l}from"./beacon.js";function v(n,e={}){const d=e.default??"fetch",s=e.onUnload??"beacon",a=b(n,e),c=l(n,e);let t=!1;const r=()=>{t=!0},o=()=>{document.visibilityState==="hidden"?t=!0:document.visibilityState==="visible"&&(t=!1)};typeof window<"u"&&(window.addEventListener("beforeunload",r),document.addEventListener("visibilitychange",o));function f(){return(t?s:d)==="beacon"?c:a}return{send(i){return f().send(i)},destroy(){typeof window<"u"&&(window.removeEventListener("beforeunload",r),document.removeEventListener("visibilitychange",o))}}}export{v as createHybridTransport};
2
+ //# sourceMappingURL=hybrid.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/transport/hybrid.ts"],
4
+ "sourcesContent": ["/**\n * Hybrid transport \u2014 fetch by default, beacon on page unload\n */\n\nimport type { HybridTransport, HybridTransportOptions, ObserveEvent } from '../types/index.js';\nimport { createFetchTransport } from './fetch.js';\nimport { createBeaconTransport } from './beacon.js';\n\n/**\n * Create a hybrid transport that switches between fetch and beacon\n * based on page lifecycle events\n *\n * @param endpoint - URL to send events to\n * @param options - Hybrid transport options\n */\nexport function createHybridTransport(\n endpoint: string,\n options: HybridTransportOptions = {}\n): HybridTransport {\n const defaultMode = options.default ?? 'fetch';\n const unloadMode = options.onUnload ?? 'beacon';\n\n const fetchTransport = createFetchTransport(endpoint, options);\n const beaconTransport = createBeaconTransport(endpoint, options);\n\n let isUnloading = false;\n\n const onBeforeUnload = () => {\n isUnloading = true;\n };\n\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n isUnloading = true;\n } else if (document.visibilityState === 'visible') {\n isUnloading = false;\n }\n };\n\n // SSR guard\n if (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', onBeforeUnload);\n document.addEventListener('visibilitychange', onVisibilityChange);\n }\n\n function getActiveTransport() {\n const mode = isUnloading ? unloadMode : defaultMode;\n return mode === 'beacon' ? beaconTransport : fetchTransport;\n }\n\n return {\n send(events: ObserveEvent[]) {\n return getActiveTransport().send(events);\n },\n destroy() {\n if (typeof window !== 'undefined') {\n window.removeEventListener('beforeunload', onBeforeUnload);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n }\n },\n };\n}\n"],
5
+ "mappings": "AAKA,OAAS,wBAAAA,MAA4B,aACrC,OAAS,yBAAAC,MAA6B,cAS/B,SAASC,EACdC,EACAC,EAAkC,CAAC,EAClB,CACjB,MAAMC,EAAcD,EAAQ,SAAW,QACjCE,EAAaF,EAAQ,UAAY,SAEjCG,EAAiBP,EAAqBG,EAAUC,CAAO,EACvDI,EAAkBP,EAAsBE,EAAUC,CAAO,EAE/D,IAAIK,EAAc,GAElB,MAAMC,EAAiB,IAAM,CAC3BD,EAAc,EAChB,EAEME,EAAqB,IAAM,CAC3B,SAAS,kBAAoB,SAC/BF,EAAc,GACL,SAAS,kBAAoB,YACtCA,EAAc,GAElB,EAGI,OAAO,OAAW,MACpB,OAAO,iBAAiB,eAAgBC,CAAc,EACtD,SAAS,iBAAiB,mBAAoBC,CAAkB,GAGlE,SAASC,GAAqB,CAE5B,OADaH,EAAcH,EAAaD,KACxB,SAAWG,EAAkBD,CAC/C,CAEA,MAAO,CACL,KAAKM,EAAwB,CAC3B,OAAOD,EAAmB,EAAE,KAAKC,CAAM,CACzC,EACA,SAAU,CACJ,OAAO,OAAW,MACpB,OAAO,oBAAoB,eAAgBH,CAAc,EACzD,SAAS,oBAAoB,mBAAoBC,CAAkB,EAEvE,CACF,CACF",
6
+ "names": ["createFetchTransport", "createBeaconTransport", "createHybridTransport", "endpoint", "options", "defaultMode", "unloadMode", "fetchTransport", "beaconTransport", "isUnloading", "onBeforeUnload", "onVisibilityChange", "getActiveTransport", "events"]
7
+ }
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Transport exports
3
3
  */
4
- export type { Transport, TransportOptions } from './transport.js';
4
+ export type { Transport, TransportOptions, BeaconTransportOptions, HybridTransportOptions, HybridTransport } from './transport.js';
5
5
  export { createFetchTransport, createConsoleTransport } from './fetch.js';
6
+ export { createBeaconTransport } from './beacon.js';
7
+ export { createHybridTransport } from './hybrid.js';
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACnI,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -1,2 +1,2 @@
1
- import{createFetchTransport as o,createConsoleTransport as e}from"./fetch.js";export{e as createConsoleTransport,o as createFetchTransport};
1
+ import{createFetchTransport as t,createConsoleTransport as p}from"./fetch.js";import{createBeaconTransport as a}from"./beacon.js";import{createHybridTransport as s}from"./hybrid.js";export{a as createBeaconTransport,p as createConsoleTransport,t as createFetchTransport,s as createHybridTransport};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/transport/index.ts"],
4
- "sourcesContent": ["/**\n * Transport exports\n */\n\nexport type { Transport, TransportOptions } from './transport.js';\nexport { createFetchTransport, createConsoleTransport } from './fetch.js';\n"],
5
- "mappings": "AAKA,OAAS,wBAAAA,EAAsB,0BAAAC,MAA8B",
6
- "names": ["createFetchTransport", "createConsoleTransport"]
4
+ "sourcesContent": ["/**\n * Transport exports\n */\n\nexport type { Transport, TransportOptions, BeaconTransportOptions, HybridTransportOptions, HybridTransport } from './transport.js';\nexport { createFetchTransport, createConsoleTransport } from './fetch.js';\nexport { createBeaconTransport } from './beacon.js';\nexport { createHybridTransport } from './hybrid.js';\n"],
5
+ "mappings": "AAKA,OAAS,wBAAAA,EAAsB,0BAAAC,MAA8B,aAC7D,OAAS,yBAAAC,MAA6B,cACtC,OAAS,yBAAAC,MAA6B",
6
+ "names": ["createFetchTransport", "createConsoleTransport", "createBeaconTransport", "createHybridTransport"]
7
7
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Transport interface - re-exported from types for convenience
3
3
  */
4
- export type { Transport, TransportOptions } from '../types/index.js';
4
+ export type { Transport, TransportOptions, BeaconTransportOptions, HybridTransportOptions, HybridTransport } from '../types/index.js';
5
5
  //# sourceMappingURL=transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport/transport.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport/transport.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
@@ -68,6 +68,21 @@ export interface TransportOptions {
68
68
  headers?: Record<string, string>;
69
69
  onError?: (error: Error) => void;
70
70
  }
71
+ export interface BeaconTransportOptions {
72
+ /** Maximum payload size in bytes before chunking (default: 60KB) */
73
+ maxPayloadSize?: number;
74
+ onError?: (error: Error) => void;
75
+ }
76
+ export interface HybridTransportOptions extends TransportOptions {
77
+ /** Default transport mode (default: 'fetch') */
78
+ default?: 'fetch' | 'beacon';
79
+ /** Transport mode during page unload (default: 'beacon') */
80
+ onUnload?: 'fetch' | 'beacon';
81
+ }
82
+ export interface HybridTransport extends Transport {
83
+ /** Remove event listeners and stop the transport */
84
+ destroy(): void;
85
+ }
71
86
  /**
72
87
  * Session configuration
73
88
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svoose",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Observability + State Machines for Svelte 5 — the goose that sees everything",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",