svoose 0.1.5 → 0.1.6

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,12 +2,15 @@
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**.
5
+ Lightweight observability + state machines for Svelte 5. Zero dependencies. Tree-shakeable. **< 5KB gzipped** (core ~3.5KB).
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
+ - **Custom Metrics** — `metric()` for custom analytics events (v0.1.6+)
12
+ - **Session Tracking** — automatic sessionId with timeout (v0.1.5+)
13
+ - **Sampling** — per-event-type rate limiting (v0.1.3+)
11
14
  - **State Machines** — minimal FSM with TypeScript inference
12
15
  - **Svelte 5 Native** — reactive `useMachine()` hook with $state runes
13
16
  - **Tree-shakeable** — pay only for what you use
@@ -77,9 +80,7 @@ const cleanup = observe({
77
80
  batchSize: 10,
78
81
  flushInterval: 5000,
79
82
 
80
- // Sampling (v0.1.3+)
81
- sampling: 0.1, // 10% of all events
82
- // or per-event-type (recommended)
83
+ // Sampling (v0.1.3+) — number or per-event-type config
83
84
  sampling: {
84
85
  vitals: 0.1, // 10% — sufficient for statistics
85
86
  errors: 1.0, // 100% — all errors matter
@@ -87,6 +88,9 @@ const cleanup = observe({
87
88
  transitions: 0.0, // disabled
88
89
  },
89
90
 
91
+ // Sessions (v0.1.5+)
92
+ session: true, // or { timeout: 30 * 60 * 1000, storage: 'sessionStorage' }
93
+
90
94
  // Debug
91
95
  debug: false,
92
96
  });
@@ -116,7 +120,6 @@ observe({
116
120
  errors: 1.0, // 100% — capture all errors
117
121
  custom: 0.5, // 50% of custom metrics
118
122
  transitions: 0.0, // disabled — no state machine events
119
- identify: 1.0, // 100% — always track user identification
120
123
  },
121
124
  });
122
125
  ```
@@ -198,6 +201,34 @@ observe({ vitals: ['CLS', 'LCP', 'INP'] });
198
201
 
199
202
  > **Note (v0.1.5 breaking change)**: CLS, LCP, and INP now report once per page lifecycle instead of on every update. This matches Chrome DevTools and Google Search Console behavior.
200
203
 
204
+ #### Custom Metrics (v0.1.6+)
205
+
206
+ Track custom events for analytics:
207
+
208
+ ```typescript
209
+ import { metric } from 'svoose';
210
+
211
+ // Basic usage
212
+ metric('checkout_started', { step: 1, cartTotal: 99.99 });
213
+ metric('button_clicked', { id: 'submit-btn' });
214
+ metric('feature_used', { name: 'dark_mode', enabled: true });
215
+ ```
216
+
217
+ Events are automatically batched with other metrics. You can control the sampling rate:
218
+
219
+ ```typescript
220
+ observe({
221
+ endpoint: '/api/metrics',
222
+ sampling: {
223
+ custom: 0.5, // 50% of custom metrics
224
+ vitals: 0.1,
225
+ errors: 1.0,
226
+ },
227
+ });
228
+ ```
229
+
230
+ **Buffer behavior**: If `metric()` is called before `observe()`, events are buffered (max 100). They're automatically flushed when `observe()` initializes.
231
+
201
232
  ### `createMachine(config)`
202
233
 
203
234
  Create a state machine.
@@ -349,12 +380,12 @@ Tree-shakeable — pay only for what you use:
349
380
 
350
381
  | Import | Size (gzip) |
351
382
  |--------|-------------|
352
- | `observe()` core | ~2.5 KB |
383
+ | `observe()` + vitals + errors + metrics | ~3.5 KB |
353
384
  | `createMachine()` only | ~0.8 KB |
354
- | Full bundle (v0.1.x) | ~3.5 KB |
355
- | Full production (v0.2.0+) | ~5.5 KB |
385
+ | Full bundle (v0.1.x) | ~4.5 KB |
386
+ | Full production (v0.2.0+) | ~6 KB |
356
387
 
357
- > Most apps only need `observe()` core (~2.5 KB). Compare: Sentry ~20KB, PostHog ~40KB.
388
+ > Most apps only need `observe()` core (~3.5 KB). Compare: Sentry ~20KB, PostHog ~40KB.
358
389
 
359
390
  ## TypeScript
360
391
 
@@ -501,8 +532,12 @@ const machine = createMachine({
501
532
 
502
533
  - **v0.1.3** ✅ — Sampling (per-event-type rate limiting)
503
534
  - **v0.1.4** ✅ — Hotfix (missing sampling.js)
504
- - **v0.1.5** — Session Tracking + CLS Session Windows fix
505
- - **v0.1.6-v0.1.10** — Custom metrics, retry, beacon transport, privacy
535
+ - **v0.1.5** — Session Tracking + CLS Session Windows fix
536
+ - **v0.1.6** — Custom metrics (`metric()` API)
537
+ - **v0.1.7** — Extended Metrics (counter/gauge/histogram + typed API)
538
+ - **v0.1.8** — Beacon + Hybrid Transport
539
+ - **v0.1.9** — Retry Logic
540
+ - **v0.1.10** — Privacy Utilities
506
541
  - **v0.2.0** — Production-Ready Observability + Bundle Restructure (modular entry points)
507
542
  - **v0.3.0** — SvelteKit Integration (Vite plugin, hooks, route tracking)
508
543
  - **v1.0.0** — Stable Release (Q1 2027)
package/dist/index.d.ts CHANGED
@@ -15,5 +15,6 @@ export { createFetchTransport, createConsoleTransport } from './transport/index.
15
15
  export type { Transport, TransportOptions } 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
- export type { VitalEvent, TransitionEvent, ObserveEvent, } from './types/index.js';
18
+ export { metric } from './metrics/index.js';
19
+ export type { VitalEvent, TransitionEvent, CustomMetricEvent, ObserveEvent, } from './types/index.js';
19
20
  //# sourceMappingURL=index.d.ts.map
@@ -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,YAAY,EACV,UAAU,EACV,eAAe,EACf,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,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,MAAM,oBAAoB,CAAC;AAK5C,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 i,registerMachineContext as a,unregisterMachineContext as v}from"./observe/index.js";import{observeCLS as m,observeLCP as f,observeFID as b,observeINP as c,observeFCP as E,observeTTFB as T,vitalObservers as y}from"./observe/index.js";import{createFetchTransport as g,createConsoleTransport as l}from"./transport/index.js";import{createMachine as j,createEvent as S}from"./machine/index.js";export{l as createConsoleTransport,S as createEvent,g as createFetchTransport,j as createMachine,n as createSampler,s as eventTypeToSamplingType,t as observe,m as observeCLS,i as observeErrors,E as observeFCP,b as observeFID,c as observeINP,f as observeLCP,T as observeTTFB,a as registerMachineContext,v as unregisterMachineContext,y 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 x,observeLCP as f,observeFID as c,observeINP as b,observeFCP as E,observeTTFB as T,vitalObservers as y}from"./observe/index.js";import{createFetchTransport as d,createConsoleTransport as g}from"./transport/index.js";import{createMachine as j,createEvent as M}from"./machine/index.js";import{metric as h}from"./metrics/index.js";export{g as createConsoleTransport,M as createEvent,d as createFetchTransport,j as createMachine,n as createSampler,s as eventTypeToSamplingType,h as metric,t as observe,x as observeCLS,i as observeErrors,E as observeFCP,c as observeFID,b as observeINP,f as observeLCP,T as observeTTFB,a as registerMachineContext,v as unregisterMachineContext,y 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// Shared Types\n// ============================================\nexport type {\n VitalEvent,\n TransitionEvent,\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",
6
- "names": ["observe", "createSampler", "eventTypeToSamplingType", "observeErrors", "registerMachineContext", "unregisterMachineContext", "observeCLS", "observeLCP", "observeFID", "observeINP", "observeFCP", "observeTTFB", "vitalObservers", "createFetchTransport", "createConsoleTransport", "createMachine", "createEvent"]
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 } 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,MAAc",
6
+ "names": ["observe", "createSampler", "eventTypeToSamplingType", "observeErrors", "registerMachineContext", "unregisterMachineContext", "observeCLS", "observeLCP", "observeFID", "observeINP", "observeFCP", "observeTTFB", "vitalObservers", "createFetchTransport", "createConsoleTransport", "createMachine", "createEvent", "metric"]
7
7
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Metrics module exports
3
+ */
4
+ export { metric, setMetricEmitter, getMetricEmitter, _getPendingEventsCount, _clearPendingEvents, } from './metric.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,MAAM,EACN,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{metric as r,setMetricEmitter as i,getMetricEmitter as n,_getPendingEventsCount as c,_clearPendingEvents as g}from"./metric.js";export{g as _clearPendingEvents,c as _getPendingEventsCount,n as getMetricEmitter,r as metric,i as setMetricEmitter};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/metrics/index.ts"],
4
+ "sourcesContent": ["/**\n * Metrics module exports\n */\n\nexport {\n metric,\n setMetricEmitter,\n getMetricEmitter,\n _getPendingEventsCount,\n _clearPendingEvents,\n} from './metric.js';\n"],
5
+ "mappings": "AAIA,OACE,UAAAA,EACA,oBAAAC,EACA,oBAAAC,EACA,0BAAAC,EACA,uBAAAC,MACK",
6
+ "names": ["metric", "setMetricEmitter", "getMetricEmitter", "_getPendingEventsCount", "_clearPendingEvents"]
7
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Custom metrics module
3
+ *
4
+ * Provides metric() function for sending custom events with pending buffer support.
5
+ */
6
+ import type { ObserveEvent } from '../types/index.js';
7
+ /**
8
+ * Set the metric emitter function
9
+ * Called by observe() to wire up the metric system
10
+ *
11
+ * @param emit - The emit function from observe(), or null to disconnect
12
+ */
13
+ export declare function setMetricEmitter(emit: ((event: ObserveEvent) => void) | null): void;
14
+ /**
15
+ * Send a custom metric event
16
+ *
17
+ * Events are automatically batched with other metrics and sent to your backend.
18
+ * If called before observe() is initialized, events are buffered (max 100).
19
+ *
20
+ * @param name - Metric name (e.g., 'checkout_started', 'button_clicked')
21
+ * @param data - Optional data payload
22
+ *
23
+ * @example
24
+ * metric('checkout_started', { step: 1, cartTotal: 99.99 });
25
+ * metric('button_clicked', { id: 'submit-btn' });
26
+ * metric('feature_used', { name: 'dark_mode', enabled: true });
27
+ */
28
+ /**
29
+ * Get the current metric emitter function (for internal use)
30
+ * @internal
31
+ */
32
+ export declare function getMetricEmitter(): ((event: ObserveEvent) => void) | null;
33
+ export declare function metric(name: string, data?: Record<string, unknown>): void;
34
+ /**
35
+ * Get number of pending events (for testing)
36
+ * @internal
37
+ */
38
+ export declare function _getPendingEventsCount(): number;
39
+ /**
40
+ * Clear pending events (for testing)
41
+ * @internal
42
+ */
43
+ export declare function _clearPendingEvents(): void;
44
+ //# sourceMappingURL=metric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric.d.ts","sourceRoot":"","sources":["../../src/metrics/metric.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAqB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWzE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAUnF;AAED;;;;;;;;;;;;;GAaG;AACH;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAI,CAEzE;AAkBD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI,CAuB7E;AAMD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -0,0 +1,2 @@
1
+ let t=null;const e=[];function i(r){if(t=r,t&&e.length>0){const o=e.splice(0,e.length);for(const n of o)t(n)}}function v(){return t}function s(){try{return typeof process<"u",import.meta.env?.DEV===!0}catch{return!1}}function u(r,o={}){const n={type:"custom",name:r,data:o,timestamp:Date.now()};if(t)t(n);else{if(e.length>=100){s()&&console.warn("[svoose] metric() buffer full (100 events). Call observe() to start sending events. New events are being dropped.");return}e.push(n)}}function c(){return e.length}function l(){e.length=0}export{l as _clearPendingEvents,c as _getPendingEventsCount,v as getMetricEmitter,u as metric,i as setMetricEmitter};
2
+ //# sourceMappingURL=metric.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/metrics/metric.ts"],
4
+ "sourcesContent": ["/**\n * Custom metrics module\n *\n * Provides metric() function for sending custom events with pending buffer support.\n */\n\nimport type { CustomMetricEvent, ObserveEvent } from '../types/index.js';\n\n// Maximum pending events before dropping (with warning in dev)\nconst MAX_PENDING_EVENTS = 100;\n\n// Emitter function set by observe()\nlet emitter: ((event: ObserveEvent) => void) | null = null;\n\n// Pending events buffer for events sent before observe() is initialized\nconst pendingEvents: CustomMetricEvent[] = [];\n\n/**\n * Set the metric emitter function\n * Called by observe() to wire up the metric system\n *\n * @param emit - The emit function from observe(), or null to disconnect\n */\nexport function setMetricEmitter(emit: ((event: ObserveEvent) => void) | null): void {\n emitter = emit;\n\n // Flush pending events when emitter is set\n if (emitter && pendingEvents.length > 0) {\n const events = pendingEvents.splice(0, pendingEvents.length);\n for (const event of events) {\n emitter(event);\n }\n }\n}\n\n/**\n * Send a custom metric event\n *\n * Events are automatically batched with other metrics and sent to your backend.\n * If called before observe() is initialized, events are buffered (max 100).\n *\n * @param name - Metric name (e.g., 'checkout_started', 'button_clicked')\n * @param data - Optional data payload\n *\n * @example\n * metric('checkout_started', { step: 1, cartTotal: 99.99 });\n * metric('button_clicked', { id: 'submit-btn' });\n * metric('feature_used', { name: 'dark_mode', enabled: true });\n */\n/**\n * Get the current metric emitter function (for internal use)\n * @internal\n */\nexport function getMetricEmitter(): ((event: ObserveEvent) => void) | null {\n return emitter;\n}\n\ndeclare const process: { env: Record<string, string | undefined> } | undefined;\n\nfunction isDev(): boolean {\n try {\n if (typeof process !== 'undefined' && process?.env?.NODE_ENV === 'development') {\n return true;\n }\n if ((import.meta as any).env?.DEV === true) {\n return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\nexport function metric(name: string, data: Record<string, unknown> = {}): void {\n const event: CustomMetricEvent = {\n type: 'custom',\n name,\n data,\n timestamp: Date.now(),\n };\n\n if (emitter) {\n emitter(event);\n } else {\n // Buffer event until observe() is initialized\n if (pendingEvents.length >= MAX_PENDING_EVENTS) {\n if (isDev()) {\n console.warn(\n `[svoose] metric() buffer full (${MAX_PENDING_EVENTS} events). ` +\n `Call observe() to start sending events. New events are being dropped.`\n );\n }\n return;\n }\n pendingEvents.push(event);\n }\n}\n\n// ============================================\n// Test helpers (not exported in production builds)\n// ============================================\n\n/**\n * Get number of pending events (for testing)\n * @internal\n */\nexport function _getPendingEventsCount(): number {\n return pendingEvents.length;\n}\n\n/**\n * Clear pending events (for testing)\n * @internal\n */\nexport function _clearPendingEvents(): void {\n pendingEvents.length = 0;\n}\n"],
5
+ "mappings": "AAYA,IAAIA,EAAkD,KAGtD,MAAMC,EAAqC,CAAC,EAQrC,SAASC,EAAiBC,EAAoD,CAInF,GAHAH,EAAUG,EAGNH,GAAWC,EAAc,OAAS,EAAG,CACvC,MAAMG,EAASH,EAAc,OAAO,EAAGA,EAAc,MAAM,EAC3D,UAAWI,KAASD,EAClBJ,EAAQK,CAAK,CAEjB,CACF,CAoBO,SAASC,GAA2D,CACzE,OAAON,CACT,CAIA,SAASO,GAAiB,CACxB,GAAI,CAIF,OAHI,OAAO,QAAY,IAGlB,YAAoB,KAAK,MAAQ,EAIxC,MAAQ,CACN,MAAO,EACT,CACF,CAEO,SAASC,EAAOC,EAAcC,EAAgC,CAAC,EAAS,CAC7E,MAAML,EAA2B,CAC/B,KAAM,SACN,KAAAI,EACA,KAAAC,EACA,UAAW,KAAK,IAAI,CACtB,EAEA,GAAIV,EACFA,EAAQK,CAAK,MACR,CAEL,GAAIJ,EAAc,QAAU,IAAoB,CAC1CM,EAAM,GACR,QAAQ,KACN,mHAEF,EAEF,MACF,CACAN,EAAc,KAAKI,CAAK,CAC1B,CACF,CAUO,SAASM,GAAiC,CAC/C,OAAOV,EAAc,MACvB,CAMO,SAASW,GAA4B,CAC1CX,EAAc,OAAS,CACzB",
6
+ "names": ["emitter", "pendingEvents", "setMetricEmitter", "emit", "events", "event", "getMetricEmitter", "isDev", "metric", "name", "data", "_getPendingEventsCount", "_clearPendingEvents"]
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"observe.svelte.d.ts","sourceRoot":"","sources":["../../src/observe/observe.svelte.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,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,CAiKhE;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,CA+KhE;AAED,YAAY,EAAE,cAAc,EAAE,CAAC"}
@@ -1,2 +1,2 @@
1
- import{vitalObservers as h}from"./vitals.js";import{observeErrors as y}from"./errors.js";import{createFetchTransport as O}from"../transport/fetch.js";import{createSampler as E,eventTypeToSamplingType as S}from"./sampling.js";import{createSessionManager as T}from"./session.js";const f={endpoint:"/api/observe",vitals:!0,errors:!0,batchSize:10,flushInterval:5e3,sampleRate:1,debug:!1};let d=null;function c(i){d=i}function x(){return d}function R(i={}){if(Math.random()>(i.sampleRate??f.sampleRate))return()=>{};const t={...f,...i},b=t.transport??O(t.endpoint),u=t.sampling!=null?E(t.sampling):null,l=t.session!=null?T(t.session):null,n=[];l&&n.push(()=>l.destroy());const s=[];let p=null;const m=()=>{try{return typeof location<"u"?location.href:""}catch{return""}},v=e=>{if(!(t.filter&&!t.filter(e))){if(u){const r=S(e.type);if(r&&!u.shouldSample(r))return}l&&(e.sessionId=l.getSessionId()),t.debug&&console.log("[svoose]",e),s.push(e),s.length>=t.batchSize&&o()}},o=()=>{if(s.length===0)return;const e=s.splice(0,s.length),r=b.send(e);r&&typeof r.catch=="function"&&r.catch(a=>{t.debug&&console.error("[svoose] transport error:",a)})},g=e=>{const r={type:"vital",name:e.name,value:e.value,rating:e.rating,delta:e.delta,timestamp:e.timestamp,url:m()};v(r)};if(t.vitals){const e=t.vitals===!0?["CLS","LCP","FID","INP","FCP","TTFB"]:t.vitals;for(const r of e){const a=h[r];a&&n.push(a(g))}}if(t.errors&&n.push(y(e=>{v(e)})),c(v),n.push(()=>c(null)),p=setInterval(o,t.flushInterval),n.push(()=>{p&&clearInterval(p)}),typeof document<"u"){const e=()=>{document.visibilityState==="hidden"&&o()};document.addEventListener("visibilitychange",e),n.push(()=>{document.removeEventListener("visibilitychange",e)})}if(typeof window<"u"){const e=()=>{o()};window.addEventListener("beforeunload",e),n.push(()=>{window.removeEventListener("beforeunload",e)})}return()=>{o(),n.forEach(e=>e())}}export{x as getGlobalObserver,R as observe,c 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 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/observe",vitals:!0,errors:!0,batchSize:10,flushInterval:5e3,sampleRate:1,debug:!1};let b=null;function d(l){b=l}function w(){return b}function N(l={}){if(Math.random()>(l.sampleRate??c.sampleRate))return()=>{};const t={...c,...l},m=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=m.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};
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 type { ObserveOptions, VitalEvent, ObserveEvent, Transport } from '../types/index.js';\n\n// Default configuration\nconst defaults = {\n endpoint: '/api/observe',\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(() => setGlobalObserver(null));\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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",
6
- "names": ["vitalObservers", "observeErrors", "createFetchTransport", "createSampler", "eventTypeToSamplingType", "createSessionManager", "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"]
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/observe',\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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",
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,26 +1,8 @@
1
1
  /**
2
2
  * Sampling utilities for rate limiting events by type
3
3
  */
4
- /**
5
- * Per-event-type sampling rates
6
- * Each rate is a number between 0 and 1 (0 = disabled, 1 = all)
7
- */
8
- export interface SamplingConfig {
9
- /** Sampling rate for Web Vitals events (default: 1) */
10
- vitals?: number;
11
- /** Sampling rate for error events (default: 1) */
12
- errors?: number;
13
- /** Sampling rate for custom metric events (default: 1) */
14
- custom?: number;
15
- /** Sampling rate for state machine transition events (default: 1) */
16
- transitions?: number;
17
- /** Sampling rate for identify events (default: 1) */
18
- identify?: number;
19
- }
20
- /**
21
- * Sampling option - either a single rate for all events or per-type config
22
- */
23
- export type SamplingOption = number | SamplingConfig;
4
+ import type { SamplingConfig, SamplingOption } from '../types/index.js';
5
+ export type { SamplingConfig, SamplingOption };
24
6
  /**
25
7
  * Event types that can be sampled
26
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"sampling.d.ts","sourceRoot":"","sources":["../../src/observe/sampling.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,cAAc,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,cAAc,CAAC;AAMrD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;;;OAIG;IACH,YAAY,CAAC,SAAS,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAEpD;;;;OAIG;IACH,OAAO,CAAC,SAAS,EAAE,iBAAiB,GAAG,MAAM,CAAC;CAC/C;AAWD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAmC7D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAChB,iBAAiB,GAAG,IAAI,CAgB1B"}
1
+ {"version":3,"file":"sampling.d.ts","sourceRoot":"","sources":["../../src/observe/sampling.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,cAAc,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;;;OAIG;IACH,YAAY,CAAC,SAAS,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAEpD;;;;OAIG;IACH,OAAO,CAAC,SAAS,EAAE,iBAAiB,GAAG,MAAM,CAAC;CAC/C;AAWD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAmC7D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAChB,iBAAiB,GAAG,IAAI,CAgB1B"}
@@ -1,2 +1,2 @@
1
- function t(e){return e<=0?0:e>=1?1:e}function a(e){const i=typeof e=="number"?{vitals:t(e),errors:t(e),custom:t(e),transitions:t(e),identify:1}:{vitals:t(e.vitals??1),errors:t(e.errors??1),custom:t(e.custom??1),transitions:t(e.transitions??1),identify:t(e.identify??1)};return{shouldSample(n){const r=i[n];return r>=1?!0:r<=0?!1:Math.random()<r},getRate(n){return i[n]}}}function u(e){switch(e){case"vital":return"vitals";case"error":case"unhandled-rejection":return"errors";case"custom":return"custom";case"transition":return"transitions";case"identify":return"identify";default:return null}}export{a as createSampler,u as eventTypeToSamplingType};
1
+ function t(e){return e<=0?0:e>=1?1:e}function a(e){const i=typeof e=="number"?{vitals:t(e),errors:t(e),custom:t(e),transitions:t(e),identify:1}:{vitals:t(e.vitals??1),errors:t(e.errors??1),custom:t(e.custom??1),transitions:t(e.transitions??1),identify:t(e.identify??1)};return{shouldSample(n){const r=i[n];return r>=1?!0:r<=0?!1:Math.random()<r},getRate(n){return i[n]}}}function p(e){switch(e){case"vital":return"vitals";case"error":case"unhandled-rejection":return"errors";case"custom":return"custom";case"transition":return"transitions";case"identify":return"identify";default:return null}}export{a as createSampler,p as eventTypeToSamplingType};
2
2
  //# sourceMappingURL=sampling.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/observe/sampling.ts"],
4
- "sourcesContent": ["/**\n * Sampling utilities for rate limiting events by type\n */\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Per-event-type sampling rates\n * Each rate is a number between 0 and 1 (0 = disabled, 1 = all)\n */\nexport interface SamplingConfig {\n /** Sampling rate for Web Vitals events (default: 1) */\n vitals?: number;\n /** Sampling rate for error events (default: 1) */\n errors?: number;\n /** Sampling rate for custom metric events (default: 1) */\n custom?: number;\n /** Sampling rate for state machine transition events (default: 1) */\n transitions?: number;\n /** Sampling rate for identify events (default: 1) */\n identify?: number;\n}\n\n/**\n * Sampling option - either a single rate for all events or per-type config\n */\nexport type SamplingOption = number | SamplingConfig;\n\n/**\n * Event types that can be sampled\n */\nexport type SamplingEventType = keyof SamplingConfig;\n\n// ============================================\n// Sampler\n// ============================================\n\n/**\n * Sampler interface returned by createSampler\n */\nexport interface Sampler {\n /**\n * Check if an event should be sampled (included)\n * @param eventType - The type of event\n * @returns true if the event should be included, false if dropped\n */\n shouldSample(eventType: SamplingEventType): boolean;\n\n /**\n * Get the sampling rate for an event type\n * @param eventType - The type of event\n * @returns The rate (0-1)\n */\n getRate(eventType: SamplingEventType): number;\n}\n\n/**\n * Normalize a sampling rate to be between 0 and 1\n */\nfunction normalizeRate(rate: number): number {\n if (rate <= 0) return 0;\n if (rate >= 1) return 1;\n return rate;\n}\n\n/**\n * Create a sampler instance for filtering events by sampling rate\n *\n * @param config - Sampling configuration (number or per-type config)\n * @returns Sampler instance\n *\n * @example\n * // Simple - same rate for all events\n * const sampler = createSampler(0.1); // 10% of all events\n *\n * @example\n * // Per-event-type rates\n * const sampler = createSampler({\n * vitals: 0.1, // 10% of vitals\n * errors: 1.0, // 100% of errors\n * custom: 0.5, // 50% of custom metrics\n * transitions: 0.0, // disabled\n * });\n */\nexport function createSampler(config: SamplingOption): Sampler {\n // Build rates object with defaults\n const rates: Required<SamplingConfig> =\n typeof config === 'number'\n ? {\n vitals: normalizeRate(config),\n errors: normalizeRate(config),\n custom: normalizeRate(config),\n transitions: normalizeRate(config),\n identify: 1, // Always send identify events by default\n }\n : {\n vitals: normalizeRate(config.vitals ?? 1),\n errors: normalizeRate(config.errors ?? 1),\n custom: normalizeRate(config.custom ?? 1),\n transitions: normalizeRate(config.transitions ?? 1),\n identify: normalizeRate(config.identify ?? 1),\n };\n\n return {\n shouldSample(eventType: SamplingEventType): boolean {\n const rate = rates[eventType];\n\n // Fast paths\n if (rate >= 1) return true;\n if (rate <= 0) return false;\n\n // Random sampling\n return Math.random() < rate;\n },\n\n getRate(eventType: SamplingEventType): number {\n return rates[eventType];\n },\n };\n}\n\n/**\n * Map ObserveEvent.type to SamplingEventType\n */\nexport function eventTypeToSamplingType(\n eventType: string\n): SamplingEventType | null {\n switch (eventType) {\n case 'vital':\n return 'vitals';\n case 'error':\n case 'unhandled-rejection':\n return 'errors';\n case 'custom':\n return 'custom';\n case 'transition':\n return 'transitions';\n case 'identify':\n return 'identify';\n default:\n return null;\n }\n}\n"],
5
- "mappings": "AA6DA,SAASA,EAAcC,EAAsB,CAC3C,OAAIA,GAAQ,EAAU,EAClBA,GAAQ,EAAU,EACfA,CACT,CAqBO,SAASC,EAAcC,EAAiC,CAE7D,MAAMC,EACJ,OAAOD,GAAW,SACd,CACE,OAAQH,EAAcG,CAAM,EAC5B,OAAQH,EAAcG,CAAM,EAC5B,OAAQH,EAAcG,CAAM,EAC5B,YAAaH,EAAcG,CAAM,EACjC,SAAU,CACZ,EACA,CACE,OAAQH,EAAcG,EAAO,QAAU,CAAC,EACxC,OAAQH,EAAcG,EAAO,QAAU,CAAC,EACxC,OAAQH,EAAcG,EAAO,QAAU,CAAC,EACxC,YAAaH,EAAcG,EAAO,aAAe,CAAC,EAClD,SAAUH,EAAcG,EAAO,UAAY,CAAC,CAC9C,EAEN,MAAO,CACL,aAAaE,EAAuC,CAClD,MAAMJ,EAAOG,EAAMC,CAAS,EAG5B,OAAIJ,GAAQ,EAAU,GAClBA,GAAQ,EAAU,GAGf,KAAK,OAAO,EAAIA,CACzB,EAEA,QAAQI,EAAsC,CAC5C,OAAOD,EAAMC,CAAS,CACxB,CACF,CACF,CAKO,SAASC,EACdD,EAC0B,CAC1B,OAAQA,EAAW,CACjB,IAAK,QACH,MAAO,SACT,IAAK,QACL,IAAK,sBACH,MAAO,SACT,IAAK,SACH,MAAO,SACT,IAAK,aACH,MAAO,cACT,IAAK,WACH,MAAO,WACT,QACE,OAAO,IACX,CACF",
4
+ "sourcesContent": ["/**\n * Sampling utilities for rate limiting events by type\n */\n\nimport type { SamplingConfig, SamplingOption } from '../types/index.js';\n\n// Re-export types from canonical source\nexport type { SamplingConfig, SamplingOption };\n\n/**\n * Event types that can be sampled\n */\nexport type SamplingEventType = keyof SamplingConfig;\n\n/**\n * Sampler interface returned by createSampler\n */\nexport interface Sampler {\n /**\n * Check if an event should be sampled (included)\n * @param eventType - The type of event\n * @returns true if the event should be included, false if dropped\n */\n shouldSample(eventType: SamplingEventType): boolean;\n\n /**\n * Get the sampling rate for an event type\n * @param eventType - The type of event\n * @returns The rate (0-1)\n */\n getRate(eventType: SamplingEventType): number;\n}\n\n/**\n * Normalize a sampling rate to be between 0 and 1\n */\nfunction normalizeRate(rate: number): number {\n if (rate <= 0) return 0;\n if (rate >= 1) return 1;\n return rate;\n}\n\n/**\n * Create a sampler instance for filtering events by sampling rate\n *\n * @param config - Sampling configuration (number or per-type config)\n * @returns Sampler instance\n *\n * @example\n * // Simple - same rate for all events\n * const sampler = createSampler(0.1); // 10% of all events\n *\n * @example\n * // Per-event-type rates\n * const sampler = createSampler({\n * vitals: 0.1, // 10% of vitals\n * errors: 1.0, // 100% of errors\n * custom: 0.5, // 50% of custom metrics\n * transitions: 0.0, // disabled\n * });\n */\nexport function createSampler(config: SamplingOption): Sampler {\n // Build rates object with defaults\n const rates: Required<SamplingConfig> =\n typeof config === 'number'\n ? {\n vitals: normalizeRate(config),\n errors: normalizeRate(config),\n custom: normalizeRate(config),\n transitions: normalizeRate(config),\n identify: 1, // Always send identify events by default\n }\n : {\n vitals: normalizeRate(config.vitals ?? 1),\n errors: normalizeRate(config.errors ?? 1),\n custom: normalizeRate(config.custom ?? 1),\n transitions: normalizeRate(config.transitions ?? 1),\n identify: normalizeRate(config.identify ?? 1),\n };\n\n return {\n shouldSample(eventType: SamplingEventType): boolean {\n const rate = rates[eventType];\n\n // Fast paths\n if (rate >= 1) return true;\n if (rate <= 0) return false;\n\n // Random sampling\n return Math.random() < rate;\n },\n\n getRate(eventType: SamplingEventType): number {\n return rates[eventType];\n },\n };\n}\n\n/**\n * Map ObserveEvent.type to SamplingEventType\n */\nexport function eventTypeToSamplingType(\n eventType: string\n): SamplingEventType | null {\n switch (eventType) {\n case 'vital':\n return 'vitals';\n case 'error':\n case 'unhandled-rejection':\n return 'errors';\n case 'custom':\n return 'custom';\n case 'transition':\n return 'transitions';\n case 'identify':\n return 'identify';\n default:\n return null;\n }\n}\n"],
5
+ "mappings": "AAoCA,SAASA,EAAcC,EAAsB,CAC3C,OAAIA,GAAQ,EAAU,EAClBA,GAAQ,EAAU,EACfA,CACT,CAqBO,SAASC,EAAcC,EAAiC,CAE7D,MAAMC,EACJ,OAAOD,GAAW,SACd,CACE,OAAQH,EAAcG,CAAM,EAC5B,OAAQH,EAAcG,CAAM,EAC5B,OAAQH,EAAcG,CAAM,EAC5B,YAAaH,EAAcG,CAAM,EACjC,SAAU,CACZ,EACA,CACE,OAAQH,EAAcG,EAAO,QAAU,CAAC,EACxC,OAAQH,EAAcG,EAAO,QAAU,CAAC,EACxC,OAAQH,EAAcG,EAAO,QAAU,CAAC,EACxC,YAAaH,EAAcG,EAAO,aAAe,CAAC,EAClD,SAAUH,EAAcG,EAAO,UAAY,CAAC,CAC9C,EAEN,MAAO,CACL,aAAaE,EAAuC,CAClD,MAAMJ,EAAOG,EAAMC,CAAS,EAG5B,OAAIJ,GAAQ,EAAU,GAClBA,GAAQ,EAAU,GAGf,KAAK,OAAO,EAAIA,CACzB,EAEA,QAAQI,EAAsC,CAC5C,OAAOD,EAAMC,CAAS,CACxB,CACF,CACF,CAKO,SAASC,EACdD,EAC0B,CAC1B,OAAQA,EAAW,CACjB,IAAK,QACH,MAAO,SACT,IAAK,QACL,IAAK,sBACH,MAAO,SACT,IAAK,SACH,MAAO,SACT,IAAK,aACH,MAAO,cACT,IAAK,WACH,MAAO,WACT,QACE,OAAO,IACX,CACF",
6
6
  "names": ["normalizeRate", "rate", "createSampler", "config", "rates", "eventType", "eventTypeToSamplingType"]
7
7
  }
@@ -1,13 +1,8 @@
1
1
  /**
2
2
  * Session Tracking - automatic sessionId generation with timeout
3
3
  */
4
- export interface SessionConfig {
5
- /** Session timeout in milliseconds (default: 30 minutes) */
6
- timeout: number;
7
- /** Storage type for session persistence */
8
- storage: 'sessionStorage' | 'localStorage' | 'memory';
9
- }
10
- export type SessionOption = boolean | Partial<SessionConfig>;
4
+ import type { SessionConfig, SessionOption } from '../types/index.js';
5
+ export type { SessionConfig, SessionOption };
11
6
  export interface SessionManager {
12
7
  /** Get current session ID (creates new session if expired) */
13
8
  getSessionId: () => string;
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/observe/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,OAAO,EAAE,gBAAgB,GAAG,cAAc,GAAG,QAAQ,CAAC;CACvD;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAW7D,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,iCAAiC;IACjC,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CAuIjF"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/observe/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGtE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;AAW7C,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,iCAAiC;IACjC,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CAuIjF"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/observe/session.ts"],
4
- "sourcesContent": ["/**\n * Session Tracking - automatic sessionId generation with timeout\n */\n\nexport interface SessionConfig {\n /** Session timeout in milliseconds (default: 30 minutes) */\n timeout: number;\n /** Storage type for session persistence */\n storage: 'sessionStorage' | 'localStorage' | 'memory';\n}\n\nexport type SessionOption = boolean | Partial<SessionConfig>;\n\ninterface Session {\n id: string;\n startedAt: number;\n lastActivity: number;\n}\n\nconst DEFAULT_TIMEOUT = 30 * 60 * 1000; // 30 minutes\nconst STORAGE_KEY = 'svoose_session';\n\nexport interface SessionManager {\n /** Get current session ID (creates new session if expired) */\n getSessionId: () => string;\n /** Force create a new session */\n reset: () => string;\n /** Destroy session manager and clear storage */\n destroy: () => void;\n}\n\n/**\n * Generate a unique session ID\n * Format: timestamp-randomString (e.g., \"1706123456789-abc123def\")\n */\nfunction generateId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).slice(2, 11);\n return `${timestamp}-${random}`;\n}\n\n/**\n * Create a session manager\n *\n * @param config - Session configuration (true = defaults, false = disabled)\n * @returns SessionManager or null if disabled\n *\n * @example\n * // Enable with defaults\n * const session = createSessionManager(true);\n * session?.getSessionId(); // \"1706123456789-abc123def\"\n *\n * @example\n * // Custom config\n * const session = createSessionManager({\n * timeout: 60 * 60 * 1000, // 1 hour\n * storage: 'localStorage',\n * });\n */\nexport function createSessionManager(config: SessionOption): SessionManager | null {\n // Disabled\n if (config === false) return null;\n\n // Normalize config\n const opts: SessionConfig = config === true\n ? { timeout: DEFAULT_TIMEOUT, storage: 'sessionStorage' }\n : {\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n storage: config.storage ?? 'sessionStorage',\n };\n\n let currentSession: Session | null = null;\n\n /**\n * Get storage instance (with SSR and private mode safety)\n */\n function getStorage(): Storage | null {\n if (opts.storage === 'memory') return null;\n if (typeof window === 'undefined') return null;\n\n try {\n const storage = opts.storage === 'localStorage' ? localStorage : sessionStorage;\n // Test if storage is available (throws in private mode on some browsers)\n const testKey = '__svoose_test__';\n storage.setItem(testKey, '1');\n storage.removeItem(testKey);\n return storage;\n } catch {\n return null;\n }\n }\n\n /**\n * Load session from storage\n */\n function load(): Session | null {\n const storage = getStorage();\n if (!storage) return null;\n\n try {\n const data = storage.getItem(STORAGE_KEY);\n if (!data) return null;\n\n const session = JSON.parse(data) as Session;\n\n // Validate session structure\n if (\n typeof session.id !== 'string' ||\n typeof session.startedAt !== 'number' ||\n typeof session.lastActivity !== 'number'\n ) {\n return null;\n }\n\n return session;\n } catch {\n return null;\n }\n }\n\n /**\n * Save session to storage\n */\n function save(session: Session): void {\n const storage = getStorage();\n if (!storage) return;\n\n try {\n storage.setItem(STORAGE_KEY, JSON.stringify(session));\n } catch {\n // Quota exceeded - fail silently\n }\n }\n\n /**\n * Create a new session\n */\n function createNew(): Session {\n const now = Date.now();\n const session: Session = {\n id: generateId(),\n startedAt: now,\n lastActivity: now,\n };\n save(session);\n return session;\n }\n\n /**\n * Check if session is expired\n */\n function isExpired(session: Session): boolean {\n const now = Date.now();\n return now - session.lastActivity > opts.timeout;\n }\n\n return {\n getSessionId(): string {\n const now = Date.now();\n\n // Try to load from storage if not in memory\n if (!currentSession) {\n currentSession = load();\n }\n\n // Create new session if none exists or expired\n if (!currentSession || isExpired(currentSession)) {\n currentSession = createNew();\n return currentSession.id;\n }\n\n // Update last activity\n currentSession.lastActivity = now;\n save(currentSession);\n return currentSession.id;\n },\n\n reset(): string {\n currentSession = createNew();\n return currentSession.id;\n },\n\n destroy(): void {\n currentSession = null;\n const storage = getStorage();\n if (storage) {\n try {\n storage.removeItem(STORAGE_KEY);\n } catch {\n // Ignore errors\n }\n }\n },\n };\n}\n"],
5
- "mappings": "AAoBA,MAAMA,EAAc,iBAepB,SAASC,GAAqB,CAC5B,MAAMC,EAAY,KAAK,IAAI,EACrBC,EAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,EACrD,MAAO,GAAGD,CAAS,IAAIC,CAAM,EAC/B,CAoBO,SAASC,EAAqBC,EAA8C,CAEjF,GAAIA,IAAW,GAAO,OAAO,KAG7B,MAAMC,EAAsBD,IAAW,GACnC,CAAE,QAAS,KAAiB,QAAS,gBAAiB,EACtD,CACE,QAASA,EAAO,SAAW,KAC3B,QAASA,EAAO,SAAW,gBAC7B,EAEJ,IAAIE,EAAiC,KAKrC,SAASC,GAA6B,CAEpC,GADIF,EAAK,UAAY,UACjB,OAAO,OAAW,IAAa,OAAO,KAE1C,GAAI,CACF,MAAMG,EAAUH,EAAK,UAAY,eAAiB,aAAe,eAE3DI,EAAU,kBAChB,OAAAD,EAAQ,QAAQC,EAAS,GAAG,EAC5BD,EAAQ,WAAWC,CAAO,EACnBD,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAKA,SAASE,GAAuB,CAC9B,MAAMF,EAAUD,EAAW,EAC3B,GAAI,CAACC,EAAS,OAAO,KAErB,GAAI,CACF,MAAMG,EAAOH,EAAQ,QAAQT,CAAW,EACxC,GAAI,CAACY,EAAM,OAAO,KAElB,MAAMC,EAAU,KAAK,MAAMD,CAAI,EAG/B,OACE,OAAOC,EAAQ,IAAO,UACtB,OAAOA,EAAQ,WAAc,UAC7B,OAAOA,EAAQ,cAAiB,SAEzB,KAGFA,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAKA,SAASC,EAAKD,EAAwB,CACpC,MAAMJ,EAAUD,EAAW,EAC3B,GAAKC,EAEL,GAAI,CACFA,EAAQ,QAAQT,EAAa,KAAK,UAAUa,CAAO,CAAC,CACtD,MAAQ,CAER,CACF,CAKA,SAASE,GAAqB,CAC5B,MAAMC,EAAM,KAAK,IAAI,EACfH,EAAmB,CACvB,GAAIZ,EAAW,EACf,UAAWe,EACX,aAAcA,CAChB,EACA,OAAAF,EAAKD,CAAO,EACLA,CACT,CAKA,SAASI,EAAUJ,EAA2B,CAE5C,OADY,KAAK,IAAI,EACRA,EAAQ,aAAeP,EAAK,OAC3C,CAEA,MAAO,CACL,cAAuB,CACrB,MAAMU,EAAM,KAAK,IAAI,EAQrB,OALKT,IACHA,EAAiBI,EAAK,GAIpB,CAACJ,GAAkBU,EAAUV,CAAc,GAC7CA,EAAiBQ,EAAU,EACpBR,EAAe,KAIxBA,EAAe,aAAeS,EAC9BF,EAAKP,CAAc,EACZA,EAAe,GACxB,EAEA,OAAgB,CACd,OAAAA,EAAiBQ,EAAU,EACpBR,EAAe,EACxB,EAEA,SAAgB,CACdA,EAAiB,KACjB,MAAME,EAAUD,EAAW,EAC3B,GAAIC,EACF,GAAI,CACFA,EAAQ,WAAWT,CAAW,CAChC,MAAQ,CAER,CAEJ,CACF,CACF",
4
+ "sourcesContent": ["/**\n * Session Tracking - automatic sessionId generation with timeout\n */\n\nimport type { SessionConfig, SessionOption } from '../types/index.js';\n\n// Re-export types from canonical source\nexport type { SessionConfig, SessionOption };\n\ninterface Session {\n id: string;\n startedAt: number;\n lastActivity: number;\n}\n\nconst DEFAULT_TIMEOUT = 30 * 60 * 1000; // 30 minutes\nconst STORAGE_KEY = 'svoose_session';\n\nexport interface SessionManager {\n /** Get current session ID (creates new session if expired) */\n getSessionId: () => string;\n /** Force create a new session */\n reset: () => string;\n /** Destroy session manager and clear storage */\n destroy: () => void;\n}\n\n/**\n * Generate a unique session ID\n * Format: timestamp-randomString (e.g., \"1706123456789-abc123def\")\n */\nfunction generateId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).slice(2, 11);\n return `${timestamp}-${random}`;\n}\n\n/**\n * Create a session manager\n *\n * @param config - Session configuration (true = defaults, false = disabled)\n * @returns SessionManager or null if disabled\n *\n * @example\n * // Enable with defaults\n * const session = createSessionManager(true);\n * session?.getSessionId(); // \"1706123456789-abc123def\"\n *\n * @example\n * // Custom config\n * const session = createSessionManager({\n * timeout: 60 * 60 * 1000, // 1 hour\n * storage: 'localStorage',\n * });\n */\nexport function createSessionManager(config: SessionOption): SessionManager | null {\n // Disabled\n if (config === false) return null;\n\n // Normalize config\n const opts: SessionConfig = config === true\n ? { timeout: DEFAULT_TIMEOUT, storage: 'sessionStorage' }\n : {\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n storage: config.storage ?? 'sessionStorage',\n };\n\n let currentSession: Session | null = null;\n\n /**\n * Get storage instance (with SSR and private mode safety)\n */\n function getStorage(): Storage | null {\n if (opts.storage === 'memory') return null;\n if (typeof window === 'undefined') return null;\n\n try {\n const storage = opts.storage === 'localStorage' ? localStorage : sessionStorage;\n // Test if storage is available (throws in private mode on some browsers)\n const testKey = '__svoose_test__';\n storage.setItem(testKey, '1');\n storage.removeItem(testKey);\n return storage;\n } catch {\n return null;\n }\n }\n\n /**\n * Load session from storage\n */\n function load(): Session | null {\n const storage = getStorage();\n if (!storage) return null;\n\n try {\n const data = storage.getItem(STORAGE_KEY);\n if (!data) return null;\n\n const session = JSON.parse(data) as Session;\n\n // Validate session structure\n if (\n typeof session.id !== 'string' ||\n typeof session.startedAt !== 'number' ||\n typeof session.lastActivity !== 'number'\n ) {\n return null;\n }\n\n return session;\n } catch {\n return null;\n }\n }\n\n /**\n * Save session to storage\n */\n function save(session: Session): void {\n const storage = getStorage();\n if (!storage) return;\n\n try {\n storage.setItem(STORAGE_KEY, JSON.stringify(session));\n } catch {\n // Quota exceeded - fail silently\n }\n }\n\n /**\n * Create a new session\n */\n function createNew(): Session {\n const now = Date.now();\n const session: Session = {\n id: generateId(),\n startedAt: now,\n lastActivity: now,\n };\n save(session);\n return session;\n }\n\n /**\n * Check if session is expired\n */\n function isExpired(session: Session): boolean {\n const now = Date.now();\n return now - session.lastActivity > opts.timeout;\n }\n\n return {\n getSessionId(): string {\n const now = Date.now();\n\n // Try to load from storage if not in memory\n if (!currentSession) {\n currentSession = load();\n }\n\n // Create new session if none exists or expired\n if (!currentSession || isExpired(currentSession)) {\n currentSession = createNew();\n return currentSession.id;\n }\n\n // Update last activity\n currentSession.lastActivity = now;\n save(currentSession);\n return currentSession.id;\n },\n\n reset(): string {\n currentSession = createNew();\n return currentSession.id;\n },\n\n destroy(): void {\n currentSession = null;\n const storage = getStorage();\n if (storage) {\n try {\n storage.removeItem(STORAGE_KEY);\n } catch {\n // Ignore errors\n }\n }\n },\n };\n}\n"],
5
+ "mappings": "AAgBA,MAAMA,EAAc,iBAepB,SAASC,GAAqB,CAC5B,MAAMC,EAAY,KAAK,IAAI,EACrBC,EAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,EACrD,MAAO,GAAGD,CAAS,IAAIC,CAAM,EAC/B,CAoBO,SAASC,EAAqBC,EAA8C,CAEjF,GAAIA,IAAW,GAAO,OAAO,KAG7B,MAAMC,EAAsBD,IAAW,GACnC,CAAE,QAAS,KAAiB,QAAS,gBAAiB,EACtD,CACE,QAASA,EAAO,SAAW,KAC3B,QAASA,EAAO,SAAW,gBAC7B,EAEJ,IAAIE,EAAiC,KAKrC,SAASC,GAA6B,CAEpC,GADIF,EAAK,UAAY,UACjB,OAAO,OAAW,IAAa,OAAO,KAE1C,GAAI,CACF,MAAMG,EAAUH,EAAK,UAAY,eAAiB,aAAe,eAE3DI,EAAU,kBAChB,OAAAD,EAAQ,QAAQC,EAAS,GAAG,EAC5BD,EAAQ,WAAWC,CAAO,EACnBD,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAKA,SAASE,GAAuB,CAC9B,MAAMF,EAAUD,EAAW,EAC3B,GAAI,CAACC,EAAS,OAAO,KAErB,GAAI,CACF,MAAMG,EAAOH,EAAQ,QAAQT,CAAW,EACxC,GAAI,CAACY,EAAM,OAAO,KAElB,MAAMC,EAAU,KAAK,MAAMD,CAAI,EAG/B,OACE,OAAOC,EAAQ,IAAO,UACtB,OAAOA,EAAQ,WAAc,UAC7B,OAAOA,EAAQ,cAAiB,SAEzB,KAGFA,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAKA,SAASC,EAAKD,EAAwB,CACpC,MAAMJ,EAAUD,EAAW,EAC3B,GAAKC,EAEL,GAAI,CACFA,EAAQ,QAAQT,EAAa,KAAK,UAAUa,CAAO,CAAC,CACtD,MAAQ,CAER,CACF,CAKA,SAASE,GAAqB,CAC5B,MAAMC,EAAM,KAAK,IAAI,EACfH,EAAmB,CACvB,GAAIZ,EAAW,EACf,UAAWe,EACX,aAAcA,CAChB,EACA,OAAAF,EAAKD,CAAO,EACLA,CACT,CAKA,SAASI,EAAUJ,EAA2B,CAE5C,OADY,KAAK,IAAI,EACRA,EAAQ,aAAeP,EAAK,OAC3C,CAEA,MAAO,CACL,cAAuB,CACrB,MAAMU,EAAM,KAAK,IAAI,EAQrB,OALKT,IACHA,EAAiBI,EAAK,GAIpB,CAACJ,GAAkBU,EAAUV,CAAc,GAC7CA,EAAiBQ,EAAU,EACpBR,EAAe,KAIxBA,EAAe,aAAeS,EAC9BF,EAAKP,CAAc,EACZA,EAAe,GACxB,EAEA,OAAgB,CACd,OAAAA,EAAiBQ,EAAU,EACpBR,EAAe,EACxB,EAEA,SAAgB,CACdA,EAAiB,KACjB,MAAME,EAAUD,EAAW,EAC3B,GAAIC,EACF,GAAI,CACFA,EAAQ,WAAWT,CAAW,CAChC,MAAQ,CAER,CAEJ,CACF,CACF",
6
6
  "names": ["STORAGE_KEY", "generateId", "timestamp", "random", "createSessionManager", "config", "opts", "currentSession", "getStorage", "storage", "testKey", "load", "data", "session", "save", "createNew", "now", "isExpired"]
7
7
  }
@@ -0,0 +1,2 @@
1
+ import{createMachine as r}from"../machine/index.js";function s(o){const e=r(o);let n=$state(e.state),a=$state(e.context);const c=e.send.bind(e);return{get state(){return n},get context(){return a},matches(t){return n===t},matchesAny(...t){return t.includes(n)},can(t){return e.can(t)},send:t=>{c(t),n=e.state,a=e.context},destroy:e.destroy.bind(e)}}const v=s;export{v as fromMachine,s as useMachine};
2
+ //# sourceMappingURL=index.svelte.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/svelte/index.svelte.ts"],
4
+ "sourcesContent": ["/**\n * Svelte 5 specific utilities for svoose\n *\n * Provides reactive wrappers and hooks for state machines\n */\n\n/// <reference path=\"./runes.d.ts\" />\n\nimport { createMachine, type MachineConfig, type EventObject } from '../machine/index.js';\n\n/**\n * Reactive machine state for Svelte 5 components\n */\nexport interface ReactiveMachine<\n TContext extends object,\n TState extends string,\n TEvent extends EventObject\n> {\n /** Current state (reactive - triggers re-render on change) */\n readonly state: TState;\n /** Current context (reactive - triggers re-render on change) */\n readonly context: TContext;\n /** Check if machine is in given state */\n matches(state: TState): boolean;\n /** Check if machine is in any of given states */\n matchesAny(...states: TState[]): boolean;\n /** Check if event can be sent */\n can(eventType: TEvent['type']): boolean;\n /** Send event to machine */\n send(event: TEvent | TEvent['type']): void;\n /** Cleanup machine */\n destroy(): void;\n}\n\n/**\n * Create a reactive state machine for Svelte 5 components\n *\n * This is the recommended way to use svoose in Svelte 5 components.\n * The returned machine's state and context are automatically reactive\n * and will trigger component re-renders when they change.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useMachine } from 'svoose/svelte';\n *\n * const toggle = useMachine({\n * id: 'toggle',\n * initial: 'off',\n * states: {\n * off: { on: { TOGGLE: 'on' } },\n * on: { on: { TOGGLE: 'off' } },\n * },\n * });\n * </script>\n *\n * <button onclick={() => toggle.send('TOGGLE')}>\n * {toggle.state}\n * </button>\n * ```\n */\nexport function useMachine<\n TContext extends object,\n TState extends string,\n TEvent extends EventObject\n>(config: MachineConfig<TContext, TState, TEvent>): ReactiveMachine<TContext, TState, TEvent> {\n // Create base machine\n const machine = createMachine(config);\n\n // Reactive state using Svelte 5 $state rune\n let reactiveState = $state<TState>(machine.state);\n let reactiveContext = $state<TContext>(machine.context);\n\n // Wrap send to update reactive state\n const originalSend = machine.send.bind(machine);\n\n const reactiveSend = (event: TEvent | TEvent['type']): void => {\n originalSend(event);\n // Update reactive state after transition\n reactiveState = machine.state;\n reactiveContext = machine.context;\n };\n\n // Return reactive wrapper\n return {\n get state(): TState {\n return reactiveState;\n },\n get context(): TContext {\n return reactiveContext;\n },\n matches(state: TState): boolean {\n return reactiveState === state;\n },\n matchesAny(...states: TState[]): boolean {\n return states.includes(reactiveState);\n },\n can(eventType: TEvent['type']): boolean {\n return machine.can(eventType);\n },\n send: reactiveSend,\n destroy: machine.destroy.bind(machine),\n };\n}\n\n/**\n * Create a machine from an existing config with reactive state\n *\n * Use this when you have a pre-defined machine config that you want\n * to instantiate as a reactive machine in a component.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { fromMachine } from 'svoose/svelte';\n * import { toggleConfig } from './machines/toggle';\n *\n * const toggle = fromMachine(toggleConfig);\n * </script>\n * ```\n */\nexport const fromMachine = useMachine;\n\n// Re-export useful types\nexport type { MachineConfig, EventObject } from '../machine/index.js';\n"],
5
+ "mappings": "AAQA,OAAS,iBAAAA,MAA2D,sBAqD7D,SAASC,EAIdC,EAA4F,CAE5F,MAAMC,EAAUH,EAAcE,CAAM,EAGpC,IAAIE,EAAgB,OAAeD,EAAQ,KAAK,EAC5CE,EAAkB,OAAiBF,EAAQ,OAAO,EAGtD,MAAMG,EAAeH,EAAQ,KAAK,KAAKA,CAAO,EAU9C,MAAO,CACL,IAAI,OAAgB,CAClB,OAAOC,CACT,EACA,IAAI,SAAoB,CACtB,OAAOC,CACT,EACA,QAAQE,EAAwB,CAC9B,OAAOH,IAAkBG,CAC3B,EACA,cAAcC,EAA2B,CACvC,OAAOA,EAAO,SAASJ,CAAa,CACtC,EACA,IAAIK,EAAoC,CACtC,OAAON,EAAQ,IAAIM,CAAS,CAC9B,EACA,KAxBoBC,GAAyC,CAC7DJ,EAAaI,CAAK,EAElBN,EAAgBD,EAAQ,MACxBE,EAAkBF,EAAQ,OAC5B,EAoBE,QAASA,EAAQ,QAAQ,KAAKA,CAAO,CACvC,CACF,CAkBO,MAAMQ,EAAcV",
6
+ "names": ["createMachine", "useMachine", "config", "machine", "reactiveState", "reactiveContext", "originalSend", "state", "states", "eventType", "event", "fromMachine"]
7
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Fetch-based transport with sendBeacon fallback
3
3
  */
4
- import type { Transport, TransportOptions } from './transport.js';
4
+ import type { Transport, TransportOptions } from '../types/index.js';
5
5
  /**
6
6
  * Create a fetch-based transport
7
7
  * Uses sendBeacon for page unload, fetch otherwise
@@ -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,gBAAgB,CAAC;AAElE;;;;;;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,CAwCX;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 r=JSON.stringify(e);if(typeof document<"u"&&document.visibilityState==="hidden"&&typeof navigator<"u"&&navigator.sendBeacon){const t=new Blob([r],{type:"application/json"});if(!navigator.sendBeacon(o,t))throw new Error("sendBeacon failed");return}await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",...n.headers},body:r,keepalive:!0})}catch(r){n.onError?.(r)}}}}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 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};
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 './transport.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"],
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
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
6
  "names": ["createFetchTransport", "endpoint", "options", "events", "payload", "blob", "error", "createConsoleTransport", "event"]
7
7
  }
@@ -1,13 +1,5 @@
1
1
  /**
2
- * Transport interface - defines how events are sent to backend
2
+ * Transport interface - re-exported from types for convenience
3
3
  */
4
- import type { ObserveEvent } from '../types/index.js';
5
- export interface Transport {
6
- /** Send events to backend. Can return Promise or void for sync transports. */
7
- send(events: ObserveEvent[]): Promise<void> | void;
8
- }
9
- export interface TransportOptions {
10
- headers?: Record<string, string>;
11
- onError?: (error: Error) => void;
12
- }
4
+ export type { Transport, TransportOptions } from '../types/index.js';
13
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,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACpD;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC"}
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"}
@@ -50,7 +50,14 @@ export interface TransitionEvent {
50
50
  sessionId?: string;
51
51
  context?: Record<string, unknown>;
52
52
  }
53
- export type ObserveEvent = VitalEvent | ObserveErrorEvent | TransitionEvent;
53
+ export interface CustomMetricEvent {
54
+ type: 'custom';
55
+ name: string;
56
+ data: Record<string, unknown>;
57
+ timestamp: number;
58
+ sessionId?: string;
59
+ }
60
+ export type ObserveEvent = VitalEvent | ObserveErrorEvent | TransitionEvent | CustomMetricEvent;
54
61
  export interface Transport {
55
62
  /** Send events to backend. Can return Promise or void for sync transports. */
56
63
  send(events: ObserveEvent[]): Promise<void> | void;
@@ -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.5",
3
+ "version": "0.1.6",
4
4
  "description": "Observability + State Machines for Svelte 5 — the goose that sees everything",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -55,6 +55,11 @@
55
55
  "peerDependencies": {
56
56
  "svelte": "^5.0.0"
57
57
  },
58
+ "peerDependenciesMeta": {
59
+ "svelte": {
60
+ "optional": true
61
+ }
62
+ },
58
63
  "devDependencies": {
59
64
  "@vitest/coverage-v8": "^2.1.9",
60
65
  "esbuild": "^0.27.2",