svoose 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +23 -16
  2. package/dist/machine/machine.svelte.d.ts.map +1 -1
  3. package/dist/machine/machine.svelte.js +1 -1
  4. package/dist/machine/machine.svelte.js.map +3 -3
  5. package/dist/machine/types.d.ts +2 -2
  6. package/dist/machine/types.d.ts.map +1 -1
  7. package/dist/metrics/index.d.ts +1 -1
  8. package/dist/metrics/index.d.ts.map +1 -1
  9. package/dist/metrics/index.js +1 -1
  10. package/dist/metrics/index.js.map +3 -3
  11. package/dist/metrics/metric.d.ts +1 -15
  12. package/dist/metrics/metric.d.ts.map +1 -1
  13. package/dist/metrics/metric.js +1 -1
  14. package/dist/metrics/metric.js.map +3 -3
  15. package/dist/metrics/typed.d.ts +1 -1
  16. package/dist/metrics/typed.d.ts.map +1 -1
  17. package/dist/metrics/typed.js.map +3 -3
  18. package/dist/observe/errors.d.ts.map +1 -1
  19. package/dist/observe/errors.js +1 -1
  20. package/dist/observe/errors.js.map +3 -3
  21. package/dist/observe/observe.svelte.d.ts.map +1 -1
  22. package/dist/observe/observe.svelte.js +1 -1
  23. package/dist/observe/observe.svelte.js.map +3 -3
  24. package/dist/observe/sampling.d.ts.map +1 -1
  25. package/dist/observe/sampling.js +1 -1
  26. package/dist/observe/sampling.js.map +2 -2
  27. package/dist/observe/session.d.ts +1 -1
  28. package/dist/observe/session.d.ts.map +1 -1
  29. package/dist/observe/session.js +1 -1
  30. package/dist/observe/session.js.map +3 -3
  31. package/dist/svelte/index.svelte.d.ts +2 -2
  32. package/dist/svelte/index.svelte.d.ts.map +1 -1
  33. package/dist/svelte/index.svelte.js +1 -1
  34. package/dist/svelte/index.svelte.js.map +3 -3
  35. package/dist/transport/fetch.js +1 -1
  36. package/dist/transport/fetch.js.map +2 -2
  37. package/dist/types/index.d.ts +11 -8
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/dist/upgrade/after.d.ts +0 -28
  41. package/dist/upgrade/after.d.ts.map +0 -1
  42. package/dist/upgrade/history.d.ts +0 -36
  43. package/dist/upgrade/history.d.ts.map +0 -1
  44. package/dist/upgrade/index.d.ts +0 -25
  45. package/dist/upgrade/index.d.ts.map +0 -1
  46. package/dist/upgrade/invoke.d.ts +0 -39
  47. package/dist/upgrade/invoke.d.ts.map +0 -1
  48. package/dist/upgrade/parallel.d.ts +0 -36
  49. package/dist/upgrade/parallel.d.ts.map +0 -1
  50. package/dist/upgrade/spawn.d.ts +0 -35
  51. package/dist/upgrade/spawn.d.ts.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
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. **~5.3KB gzipped** (core ~3.6KB).
5
+ Lightweight observability + state machines for Svelte 5. Zero dependencies. Tree-shakeable. **~5.5KB gzipped** (core ~3.8KB).
6
6
 
7
7
  ## Features
8
8
 
@@ -92,6 +92,9 @@ const cleanup = observe({
92
92
  // Sessions (v0.1.5+)
93
93
  session: true, // or { timeout: 30 * 60 * 1000, storage: 'sessionStorage' }
94
94
 
95
+ // Error callback (v0.1.9+) — handle transport failures
96
+ onError: (err) => console.error('Transport failed:', err),
97
+
95
98
  // Debug
96
99
  debug: false,
97
100
  });
@@ -125,8 +128,6 @@ observe({
125
128
  });
126
129
  ```
127
130
 
128
- > **Note**: `sampleRate` is deprecated. Use `sampling` instead.
129
-
130
131
  #### Sessions (v0.1.5+)
131
132
 
132
133
  Automatic session tracking with configurable timeout:
@@ -209,7 +210,7 @@ Track custom events for analytics:
209
210
  ```typescript
210
211
  import { metric } from 'svoose';
211
212
 
212
- // Basic usage
213
+ // Basic usage — metric(name, metadata?)
213
214
  metric('checkout_started', { step: 1, cartTotal: 99.99 });
214
215
  metric('button_clicked', { id: 'submit-btn' });
215
216
  metric('feature_used', { name: 'dark_mode', enabled: true });
@@ -235,11 +236,11 @@ histogram('response_time_ms', 123);
235
236
  histogram('payload_size', 4096, { route: '/api/data' });
236
237
  ```
237
238
 
238
- All helpers emit events with top-level `metricKind` and `value` fields for easy backend processing.
239
+ All helpers emit `CustomMetricEvent` with top-level `metricKind`, `value`, and optional `metadata` fields for easy backend processing.
239
240
 
240
241
  ##### Typed Metrics (v0.1.7+)
241
242
 
242
- Full TypeScript autocomplete for metric names and data shapes:
243
+ Full TypeScript autocomplete for metric names and metadata shapes:
243
244
 
244
245
  ```typescript
245
246
  import { createTypedMetric } from 'svoose';
@@ -299,6 +300,7 @@ machine.matchesAny('on', 'off'); // true
299
300
 
300
301
  // Check if event is valid
301
302
  machine.can('TOGGLE'); // true
303
+ machine.can({ type: 'SET', value: 42 }); // full event for payload-dependent guards
302
304
 
303
305
  // Send events
304
306
  machine.send('TOGGLE');
@@ -375,8 +377,8 @@ const auth = createMachine({
375
377
  },
376
378
  });
377
379
 
378
- // When an error occurs, it includes:
379
- // { machineId: 'auth', machineState: 'loading', ... }
380
+ // When an error occurs, it includes all active machines:
381
+ // { machineId: 'auth', machineState: 'loading', machines: [{ id: 'auth', state: 'loading' }], ... }
380
382
  ```
381
383
 
382
384
  ### Custom Transport
@@ -448,12 +450,12 @@ Tree-shakeable — pay only for what you use:
448
450
 
449
451
  | Import | Size (gzip) |
450
452
  |--------|-------------|
451
- | `observe()` + vitals + errors + metrics | ~3.6 KB |
452
- | `createMachine()` only | ~0.8 KB |
453
- | Full bundle (v0.1.x) | ~5.3 KB |
453
+ | `observe()` + vitals + errors + metrics | ~3.8 KB |
454
+ | `createMachine()` only | ~0.85 KB |
455
+ | Full bundle (v0.1.x) | ~5.5 KB |
454
456
  | Full production (v0.2.0+) | ~6 KB |
455
457
 
456
- > Most apps only need `observe()` core (~3.6 KB). Compare: Sentry ~20KB, PostHog ~40KB.
458
+ > Most apps only need `observe()` core (~3.8 KB). Compare: Sentry ~20KB, PostHog ~40KB.
457
459
 
458
460
  ## TypeScript
459
461
 
@@ -604,10 +606,15 @@ const machine = createMachine({
604
606
  - **v0.1.6** ✅ — Custom metrics (`metric()` API)
605
607
  - **v0.1.7** ✅ — Extended Metrics (counter/gauge/histogram + typed API)
606
608
  - **v0.1.8** ✅ — Beacon + Hybrid Transport
607
- - **v0.1.9** — Retry Logic
608
- - **v0.1.10** — Privacy Utilities
609
- - **v0.2.0** — Production-Ready Observability + Bundle Restructure (modular entry points)
610
- - **v0.3.0** — SvelteKit Integration (Vite plugin, hooks, route tracking)
609
+ - **v0.1.9** API Cleanup: `data`→`metadata`, `can()` accepts full events, `onError` callback, multi-machine error context, validation
610
+ - **v0.1.10** — Retry Logic
611
+ - **v0.1.11** — Privacy Utilities
612
+ - **v0.2.0** — Production-Ready Observability (User ID, Offline, flush API, Rate Limiter)
613
+ - **v0.2.1** — Breadcrumbs
614
+ - **v0.2.2** — Navigation Events + Soft Navigation
615
+ - **v0.2.3** — Request Correlation
616
+ - **v0.3.0** — SvelteKit Core Integration
617
+ - **v0.3.1** — SvelteKit Vite Plugin
611
618
  - **v1.0.0** — Stable Release (Q1 2027)
612
619
 
613
620
  > **Note**: FSM is a lightweight bonus feature, not an XState competitor. For complex state machines, use XState.
@@ -1 +1 @@
1
- {"version":3,"file":"machine.svelte.d.ts","sourceRoot":"","sources":["../../src/machine/machine.svelte.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,OAAO,EAGR,MAAM,YAAY,CAAC;AAGpB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,SAAS,MAAM,EACvB,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS,WAAW,EAC1B,MAAM,EAAE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAqMpF;AAGD,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"machine.svelte.d.ts","sourceRoot":"","sources":["../../src/machine/machine.svelte.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,OAAO,EAGR,MAAM,YAAY,CAAC;AAGpB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,SAAS,MAAM,EACvB,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS,WAAW,EAC1B,MAAM,EAAE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CA4MpF;AAGD,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -1,2 +1,2 @@
1
- import{registerMachineContext as E,unregisterMachineContext as b}from"../observe/errors.js";import{getGlobalObserver as C}from"../observe/observe.svelte.js";function m(t){if(!(t.initial in t.states))throw new Error(`[svoose] Invalid initial state "${t.initial}" for machine "${t.id}". Available states: ${Object.keys(t.states).join(", ")}`);let o=t.initial,r=t.context?{...t.context}:{};const c=t.observe===!0?{transitions:!0,context:!1}:t.observe===!1||t.observe===void 0?{transitions:!1,context:!1}:t.observe;E(t.id,()=>o);const f=t.states[t.initial];if(f?.entry)try{const e=f.entry(r);e&&(r={...r,...e})}catch(e){console.error(`[svoose] Error in entry action for initial state "${t.initial}":`,e)}function y(e,a){return e.on?.[a]}function v(e){const a=t.states[o];if(!a?.on)return!1;const s=y(a,e);return s?typeof s=="string"?!0:s.guard?s.guard(r,{type:e}):!0:!1}function p(e){const a=typeof e=="string"?{type:e}:e,s=t.states[o];if(!s?.on)return;const i=y(s,a.type);if(!i)return;const d=typeof i=="string"?i:i.target;if(typeof i=="object"&&i.guard)try{if(!i.guard(r,a))return}catch(n){console.error(`[svoose] Error in guard for event "${a.type}":`,n);return}const l=o;if(s.exit)try{s.exit(r)}catch(n){console.error(`[svoose] Error in exit action for state "${o}":`,n)}if(typeof i=="object"&&i.action)try{const n=i.action(r,a);n&&(r={...r,...n})}catch(n){console.error(`[svoose] Error in action for event "${a.type}":`,n)}o=d;const T=t.states[o];if(T?.entry)try{const n=T.entry(r);n&&(r={...r,...n})}catch(n){console.error(`[svoose] Error in entry action for state "${o}":`,n)}if(c.transitions){const n=C();if(n){const x={type:"transition",machineId:t.id,from:l,to:o,event:a.type,timestamp:Date.now(),...c.context?{context:{...r}}:{}};n(x)}}}function u(){b(t.id)}return{get state(){return o},get context(){return r},matches(e){return o===e},matchesAny(...e){return e.includes(o)},can(e){return v(e)},send:p,destroy:u}}export{m as createMachine};
1
+ import{registerMachineContext,unregisterMachineContext}from"../observe/errors.js";import{getGlobalObserver}from"../observe/observe.svelte.js";function createMachine(config){if(!(config.initial in config.states))throw new Error(`[svoose] Invalid initial state "${config.initial}" for machine "${config.id}". Available states: ${Object.keys(config.states).join(", ")}`);let _state=config.initial,_context=config.context?{...config.context}:{};const observeConfig=config.observe===!0?{transitions:!0,context:!1}:config.observe===!1||config.observe===void 0?{transitions:!1,context:!1}:config.observe;registerMachineContext(config.id,()=>_state);const initialState=config.states[config.initial];if(initialState?.entry)try{const update=initialState.entry(_context);update&&(_context={..._context,...update})}catch(err){console.error(`[svoose] Error in entry action for initial state "${config.initial}":`,err)}function getTransition(stateConfig,eventType){return stateConfig.on?.[eventType]}function canTransition(event){const eventType=typeof event=="string"?event:event.type,eventObj=typeof event=="string"?{type:event}:event,stateConfig=config.states[_state];if(!stateConfig?.on)return!1;const transition=getTransition(stateConfig,eventType);if(!transition)return!1;if(typeof transition=="string")return!0;if(transition.guard)try{return transition.guard(_context,eventObj)}catch{return!1}return!0}function send(event){const eventObj=typeof event=="string"?{type:event}:event,stateConfig=config.states[_state];if(!stateConfig?.on)return;const transition=getTransition(stateConfig,eventObj.type);if(!transition)return;const targetState=typeof transition=="string"?transition:transition.target;if(typeof transition=="object"&&transition.guard)try{if(!transition.guard(_context,eventObj))return}catch(err){console.error(`[svoose] Error in guard for event "${eventObj.type}":`,err);return}const prevState=_state;if(stateConfig.exit)try{stateConfig.exit(_context)}catch(err){console.error(`[svoose] Error in exit action for state "${_state}":`,err)}if(typeof transition=="object"&&transition.action)try{const update=transition.action(_context,eventObj);update&&(_context={..._context,...update})}catch(err){console.error(`[svoose] Error in action for event "${eventObj.type}":`,err)}_state=targetState;const newStateConfig=config.states[_state];if(newStateConfig?.entry)try{const update=newStateConfig.entry(_context);update&&(_context={..._context,...update})}catch(err){console.error(`[svoose] Error in entry action for state "${_state}":`,err)}if(observeConfig.transitions){const observer=getGlobalObserver();if(observer){const transitionEvent={type:"transition",machineId:config.id,from:prevState,to:_state,event:eventObj.type,timestamp:Date.now(),...observeConfig.context?{context:{..._context}}:{}};observer(transitionEvent)}}}function destroy(){unregisterMachineContext(config.id)}return{get state(){return _state},get context(){return _context},matches(state){return _state===state},matchesAny(...states){return states.includes(_state)},can(event){return canTransition(event)},send,destroy}}export{createMachine};
2
2
  //# sourceMappingURL=machine.svelte.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/machine/machine.svelte.ts"],
4
- "sourcesContent": ["/**\n * Minimal FSM with Svelte 5 Runes support\n *\n * Note: When used with Svelte 5, state and context are reactive via $state.\n * When used outside Svelte, they work as regular properties.\n */\n\nimport { registerMachineContext, unregisterMachineContext } from '../observe/errors.js';\nimport { getGlobalObserver } from '../observe/observe.svelte.js';\nimport type {\n EventObject,\n MachineConfig,\n Machine,\n StateNode,\n TransitionConfig,\n} from './types.js';\nimport type { TransitionEvent } from '../types/index.js';\n\n/**\n * Create a state machine\n *\n * @example\n * const toggle = createMachine({\n * id: 'toggle',\n * initial: 'off',\n * states: {\n * off: { on: { TOGGLE: 'on' } },\n * on: { on: { TOGGLE: 'off' } },\n * },\n * });\n *\n * toggle.send('TOGGLE');\n * console.log(toggle.state); // 'on'\n */\nexport function createMachine<\n TContext extends object,\n TState extends string,\n TEvent extends EventObject\n>(config: MachineConfig<TContext, TState, TEvent>): Machine<TContext, TState, TEvent> {\n // Validate initial state exists\n if (!(config.initial in config.states)) {\n throw new Error(\n `[svoose] Invalid initial state \"${config.initial}\" for machine \"${config.id}\". ` +\n `Available states: ${Object.keys(config.states).join(', ')}`\n );\n }\n\n // Internal state\n // For Svelte 5 reactivity, use useMachine() from 'svoose/svelte'\n let _state: TState = config.initial;\n let _context: TContext = config.context ? { ...config.context } : ({} as TContext);\n\n // Parse observe config\n const observeConfig =\n config.observe === true\n ? { transitions: true, context: false }\n : config.observe === false || config.observe === undefined\n ? { transitions: false, context: false }\n : config.observe;\n\n // Register for error context tracking\n registerMachineContext(config.id, () => _state);\n\n // Run entry action for initial state (with error handling)\n const initialState = config.states[config.initial];\n if (initialState?.entry) {\n try {\n const update = initialState.entry(_context);\n if (update) {\n _context = { ..._context, ...update };\n }\n } catch (err) {\n console.error(`[svoose] Error in entry action for initial state \"${config.initial}\":`, err);\n }\n }\n\n /**\n * Get transition config for an event\n */\n function getTransition(\n stateConfig: StateNode<TContext, TState, TEvent>,\n eventType: TEvent['type']\n ): TransitionConfig<TContext, TState, TEvent> | TState | undefined {\n return stateConfig.on?.[eventType as keyof typeof stateConfig.on] as\n | TransitionConfig<TContext, TState, TEvent>\n | TState\n | undefined;\n }\n\n /**\n * Check if a transition is valid (exists and guard passes)\n */\n function canTransition(eventType: TEvent['type']): boolean {\n const stateConfig = config.states[_state];\n if (!stateConfig?.on) return false;\n\n const transition = getTransition(stateConfig, eventType);\n if (!transition) return false;\n\n // If it's just a target state string, it's always valid\n if (typeof transition === 'string') return true;\n\n // If there's a guard, check it (with empty event for can() check)\n if (transition.guard) {\n return transition.guard(_context, { type: eventType } as Extract<\n TEvent,\n { type: typeof eventType }\n >);\n }\n\n return true;\n }\n\n /**\n * Send an event to the machine\n */\n function send(event: TEvent | TEvent['type']): void {\n const eventObj: TEvent =\n typeof event === 'string' ? ({ type: event } as TEvent) : event;\n\n const stateConfig = config.states[_state];\n if (!stateConfig?.on) return;\n\n const transition = getTransition(stateConfig, eventObj.type);\n if (!transition) return;\n\n const targetState: TState =\n typeof transition === 'string' ? transition : transition.target;\n\n // Check guard (with error handling)\n if (typeof transition === 'object' && transition.guard) {\n try {\n if (\n !transition.guard(\n _context,\n eventObj as Extract<TEvent, { type: (typeof eventObj)['type'] }>\n )\n ) {\n return;\n }\n } catch (err) {\n console.error(`[svoose] Error in guard for event \"${eventObj.type}\":`, err);\n return; // Don't transition if guard throws\n }\n }\n\n const prevState = _state;\n\n // Run exit action (with error handling)\n if (stateConfig.exit) {\n try {\n stateConfig.exit(_context);\n } catch (err) {\n console.error(`[svoose] Error in exit action for state \"${_state}\":`, err);\n }\n }\n\n // Run transition action (with error handling)\n if (typeof transition === 'object' && transition.action) {\n try {\n const update = transition.action(\n _context,\n eventObj as Extract<TEvent, { type: (typeof eventObj)['type'] }>\n );\n if (update) {\n _context = { ..._context, ...update };\n }\n } catch (err) {\n console.error(`[svoose] Error in action for event \"${eventObj.type}\":`, err);\n }\n }\n\n // Update state\n _state = targetState;\n\n // Run entry action for new state (with error handling)\n const newStateConfig = config.states[_state];\n if (newStateConfig?.entry) {\n try {\n const update = newStateConfig.entry(_context);\n if (update) {\n _context = { ..._context, ...update };\n }\n } catch (err) {\n console.error(`[svoose] Error in entry action for state \"${_state}\":`, err);\n }\n }\n\n // Emit observation event\n if (observeConfig.transitions) {\n const observer = getGlobalObserver();\n if (observer) {\n const transitionEvent: TransitionEvent = {\n type: 'transition',\n machineId: config.id,\n from: prevState,\n to: _state,\n event: eventObj.type,\n timestamp: Date.now(),\n ...(observeConfig.context\n ? { context: { ..._context } as Record<string, unknown> }\n : {}),\n };\n observer(transitionEvent);\n }\n }\n }\n\n /**\n * Cleanup machine\n */\n function destroy(): void {\n unregisterMachineContext(config.id);\n }\n\n // Return machine instance\n return {\n get state(): TState {\n return _state;\n },\n get context(): TContext {\n return _context;\n },\n matches(state: TState): boolean {\n return _state === state;\n },\n matchesAny(...states: TState[]): boolean {\n return states.includes(_state);\n },\n can(eventType: TEvent['type']): boolean {\n return canTransition(eventType);\n },\n send,\n destroy,\n };\n}\n\n// Re-export types\nexport type { MachineConfig, Machine, EventObject, StateNode, TransitionConfig } from './types.js';\n"],
5
- "mappings": "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",
6
- "names": ["registerMachineContext", "unregisterMachineContext", "getGlobalObserver", "createMachine", "config", "_state", "_context", "observeConfig", "initialState", "update", "err", "getTransition", "stateConfig", "eventType", "canTransition", "transition", "send", "event", "eventObj", "targetState", "prevState", "newStateConfig", "observer", "transitionEvent", "destroy", "state", "states"]
4
+ "sourcesContent": ["/**\n * Minimal FSM with Svelte 5 Runes support\n *\n * Note: When used with Svelte 5, state and context are reactive via $state.\n * When used outside Svelte, they work as regular properties.\n */\n\nimport { registerMachineContext, unregisterMachineContext } from '../observe/errors.js';\nimport { getGlobalObserver } from '../observe/observe.svelte.js';\nimport type {\n EventObject,\n MachineConfig,\n Machine,\n StateNode,\n TransitionConfig,\n} from './types.js';\nimport type { TransitionEvent } from '../types/index.js';\n\n/**\n * Create a state machine\n *\n * @example\n * const toggle = createMachine({\n * id: 'toggle',\n * initial: 'off',\n * states: {\n * off: { on: { TOGGLE: 'on' } },\n * on: { on: { TOGGLE: 'off' } },\n * },\n * });\n *\n * toggle.send('TOGGLE');\n * console.log(toggle.state); // 'on'\n */\nexport function createMachine<\n TContext extends object,\n TState extends string,\n TEvent extends EventObject\n>(config: MachineConfig<TContext, TState, TEvent>): Machine<TContext, TState, TEvent> {\n // Validate initial state exists\n if (!(config.initial in config.states)) {\n throw new Error(\n `[svoose] Invalid initial state \"${config.initial}\" for machine \"${config.id}\". ` +\n `Available states: ${Object.keys(config.states).join(', ')}`\n );\n }\n\n // Internal state\n // For Svelte 5 reactivity, use useMachine() from 'svoose/svelte'\n let _state: TState = config.initial;\n let _context: TContext = config.context ? { ...config.context } : ({} as TContext);\n\n // Parse observe config\n const observeConfig =\n config.observe === true\n ? { transitions: true, context: false }\n : config.observe === false || config.observe === undefined\n ? { transitions: false, context: false }\n : config.observe;\n\n // Register for error context tracking\n registerMachineContext(config.id, () => _state);\n\n // Run entry action for initial state (with error handling)\n const initialState = config.states[config.initial];\n if (initialState?.entry) {\n try {\n const update = initialState.entry(_context);\n if (update) {\n _context = { ..._context, ...update };\n }\n } catch (err) {\n console.error(`[svoose] Error in entry action for initial state \"${config.initial}\":`, err);\n }\n }\n\n /**\n * Get transition config for an event\n */\n function getTransition(\n stateConfig: StateNode<TContext, TState, TEvent>,\n eventType: TEvent['type']\n ): TransitionConfig<TContext, TState, TEvent> | TState | undefined {\n return stateConfig.on?.[eventType as keyof typeof stateConfig.on] as\n | TransitionConfig<TContext, TState, TEvent>\n | TState\n | undefined;\n }\n\n /**\n * Check if a transition is valid (exists and guard passes)\n */\n function canTransition(event: TEvent['type'] | TEvent): boolean {\n const eventType = typeof event === 'string' ? event : event.type;\n const eventObj = typeof event === 'string' ? { type: event } as TEvent : event;\n\n const stateConfig = config.states[_state];\n if (!stateConfig?.on) return false;\n\n const transition = getTransition(stateConfig, eventType);\n if (!transition) return false;\n\n // If it's just a target state string, it's always valid\n if (typeof transition === 'string') return true;\n\n // If there's a guard, check it\n if (transition.guard) {\n try {\n return transition.guard(_context, eventObj as Extract<\n TEvent,\n { type: typeof eventType }\n >);\n } catch {\n return false; // guard threw = can't transition\n }\n }\n\n return true;\n }\n\n /**\n * Send an event to the machine\n */\n function send(event: TEvent | TEvent['type']): void {\n const eventObj: TEvent =\n typeof event === 'string' ? ({ type: event } as TEvent) : event;\n\n const stateConfig = config.states[_state];\n if (!stateConfig?.on) return;\n\n const transition = getTransition(stateConfig, eventObj.type);\n if (!transition) return;\n\n const targetState: TState =\n typeof transition === 'string' ? transition : transition.target;\n\n // Check guard (with error handling)\n if (typeof transition === 'object' && transition.guard) {\n try {\n if (\n !transition.guard(\n _context,\n eventObj as Extract<TEvent, { type: (typeof eventObj)['type'] }>\n )\n ) {\n return;\n }\n } catch (err) {\n console.error(`[svoose] Error in guard for event \"${eventObj.type}\":`, err);\n return; // Don't transition if guard throws\n }\n }\n\n const prevState = _state;\n\n // Run exit action (with error handling)\n if (stateConfig.exit) {\n try {\n stateConfig.exit(_context);\n } catch (err) {\n console.error(`[svoose] Error in exit action for state \"${_state}\":`, err);\n }\n }\n\n // Run transition action (with error handling)\n if (typeof transition === 'object' && transition.action) {\n try {\n const update = transition.action(\n _context,\n eventObj as Extract<TEvent, { type: (typeof eventObj)['type'] }>\n );\n if (update) {\n _context = { ..._context, ...update };\n }\n } catch (err) {\n console.error(`[svoose] Error in action for event \"${eventObj.type}\":`, err);\n }\n }\n\n // Update state\n _state = targetState;\n\n // Run entry action for new state (with error handling)\n const newStateConfig = config.states[_state];\n if (newStateConfig?.entry) {\n try {\n const update = newStateConfig.entry(_context);\n if (update) {\n _context = { ..._context, ...update };\n }\n } catch (err) {\n console.error(`[svoose] Error in entry action for state \"${_state}\":`, err);\n }\n }\n\n // Emit observation event\n if (observeConfig.transitions) {\n const observer = getGlobalObserver();\n if (observer) {\n const transitionEvent: TransitionEvent = {\n type: 'transition',\n machineId: config.id,\n from: prevState,\n to: _state,\n event: eventObj.type,\n timestamp: Date.now(),\n ...(observeConfig.context\n ? { context: { ..._context } as Record<string, unknown> }\n : {}),\n };\n observer(transitionEvent);\n }\n }\n }\n\n /**\n * Cleanup machine\n */\n function destroy(): void {\n unregisterMachineContext(config.id);\n }\n\n // Return machine instance\n return {\n get state(): TState {\n return _state;\n },\n get context(): TContext {\n return _context;\n },\n matches(state: TState): boolean {\n return _state === state;\n },\n matchesAny(...states: TState[]): boolean {\n return states.includes(_state);\n },\n can(event: TEvent['type'] | TEvent): boolean {\n return canTransition(event);\n },\n send,\n destroy,\n };\n}\n\n// Re-export types\nexport type { MachineConfig, Machine, EventObject, StateNode, TransitionConfig } from './types.js';\n"],
5
+ "mappings": "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",
6
+ "names": []
7
7
  }
@@ -55,8 +55,8 @@ export interface Machine<TContext extends object, TState extends string, TEvent
55
55
  matches(state: TState): boolean;
56
56
  /** Check if machine is in any of given states */
57
57
  matchesAny(...states: TState[]): boolean;
58
- /** Check if event can be sent (has valid transition) */
59
- can(eventType: TEvent['type']): boolean;
58
+ /** Check if event can be sent (has valid transition). Accepts string or full event object for payload-dependent guards. */
59
+ can(event: TEvent['type'] | TEvent): boolean;
60
60
  /** Send event to machine */
61
61
  send(event: TEvent | TEvent['type']): void;
62
62
  /** Cleanup machine (unregister from error tracking) */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/machine/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/machine/types.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Metrics module exports
3
3
  */
4
- export { metric, counter, gauge, histogram, setMetricEmitter, getMetricEmitter, _getPendingEventsCount, _clearPendingEvents, } from './metric.js';
4
+ export { metric, counter, gauge, histogram, setMetricEmitter, getMetricEmitter, } from './metric.js';
5
5
  export { createTypedMetric } from './typed.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,MAAM,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,MAAM,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
@@ -1,2 +1,2 @@
1
- import{metric as r,counter as i,gauge as n,histogram as c,setMetricEmitter as g,getMetricEmitter as o,_getPendingEventsCount as m,_clearPendingEvents as a}from"./metric.js";import{createTypedMetric as E}from"./typed.js";export{a as _clearPendingEvents,m as _getPendingEventsCount,i as counter,E as createTypedMetric,n as gauge,o as getMetricEmitter,c as histogram,r as metric,g as setMetricEmitter};
1
+ import{metric as r,counter as i,gauge as c,histogram as m,setMetricEmitter as o,getMetricEmitter as g}from"./metric.js";import{createTypedMetric as p}from"./typed.js";export{i as counter,p as createTypedMetric,c as gauge,g as getMetricEmitter,m as histogram,r as metric,o as setMetricEmitter};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/metrics/index.ts"],
4
- "sourcesContent": ["/**\n * Metrics module exports\n */\n\nexport {\n metric,\n counter,\n gauge,\n histogram,\n setMetricEmitter,\n getMetricEmitter,\n _getPendingEventsCount,\n _clearPendingEvents,\n} from './metric.js';\n\nexport { createTypedMetric } from './typed.js';\n"],
5
- "mappings": "AAIA,OACE,UAAAA,EACA,WAAAC,EACA,SAAAC,EACA,aAAAC,EACA,oBAAAC,EACA,oBAAAC,EACA,0BAAAC,EACA,uBAAAC,MACK,cAEP,OAAS,qBAAAC,MAAyB",
6
- "names": ["metric", "counter", "gauge", "histogram", "setMetricEmitter", "getMetricEmitter", "_getPendingEventsCount", "_clearPendingEvents", "createTypedMetric"]
4
+ "sourcesContent": ["/**\n * Metrics module exports\n */\n\nexport {\n metric,\n counter,\n gauge,\n histogram,\n setMetricEmitter,\n getMetricEmitter,\n} from './metric.js';\n\nexport { createTypedMetric } from './typed.js';\n"],
5
+ "mappings": "AAIA,OACE,UAAAA,EACA,WAAAC,EACA,SAAAC,EACA,aAAAC,EACA,oBAAAC,EACA,oBAAAC,MACK,cAEP,OAAS,qBAAAC,MAAyB",
6
+ "names": ["metric", "counter", "gauge", "histogram", "setMetricEmitter", "getMetricEmitter", "createTypedMetric"]
7
7
  }
@@ -11,26 +11,12 @@ import type { ObserveEvent } from '../types/index.js';
11
11
  * @param emit - The emit function from observe(), or null to disconnect
12
12
  */
13
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
14
  /**
29
15
  * Get the current metric emitter function (for internal use)
30
16
  * @internal
31
17
  */
32
18
  export declare function getMetricEmitter(): ((event: ObserveEvent) => void) | null;
33
- export declare function metric(name: string, data?: Record<string, unknown>): void;
19
+ export declare function metric(name: string, metadata?: Record<string, unknown>): void;
34
20
  /**
35
21
  * Increment a counter metric
36
22
  *
@@ -1 +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,CAE7E;AAkCD;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEjG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE3F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE/F;AAMD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
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;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAI,CAEzE;AAkBD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI,CAEjF;AAkCD;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEjG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE3F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE/F;AAMD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -1,2 +1,2 @@
1
- let o=null;const r=[];function v(e){if(o=e,o&&r.length>0){const n=r.splice(0,r.length);for(const t of n)o(t)}}function d(){return o}function c(){try{return typeof process<"u",import.meta.env?.DEV===!0}catch{return!1}}function g(e,n={}){s({type:"custom",name:e,data:n,timestamp:Date.now()})}function s(e){if(o)o(e);else{if(r.length>=100){c()&&console.warn("[svoose] metric() buffer full (100 events). Call observe() to start sending events. New events are being dropped.");return}r.push(e)}}function i(e,n,t,u={}){s({type:"custom",name:e,metricKind:n,value:t,data:u,timestamp:Date.now()})}function f(e,n=1,t){i(e,"counter",n,t)}function m(e,n,t){i(e,"gauge",n,t)}function l(e,n,t){i(e,"histogram",n,t)}function p(){return r.length}function a(){r.length=0}export{a as _clearPendingEvents,p as _getPendingEventsCount,f as counter,m as gauge,d as getMetricEmitter,l as histogram,g as metric,v as setMetricEmitter};
1
+ let o=null;const r=[];function v(e){if(o=e,o&&r.length>0){const n=r.splice(0,r.length);for(const t of n)o(t)}}function g(){return o}function c(){try{return typeof process<"u",import.meta.env?.DEV===!0}catch{return!1}}function d(e,n={}){s({type:"custom",name:e,metadata:n,timestamp:Date.now()})}function s(e){if(o)o(e);else{if(r.length>=100){c()&&console.warn("[svoose] metric() buffer full (100 events). Call observe() to start sending events. New events are being dropped.");return}r.push(e)}}function i(e,n,t,u={}){s({type:"custom",name:e,metricKind:n,value:t,metadata:u,timestamp:Date.now()})}function f(e,n=1,t){i(e,"counter",n,t)}function m(e,n,t){i(e,"gauge",n,t)}function l(e,n,t){i(e,"histogram",n,t)}function p(){return r.length}function E(){r.length=0}export{E as _clearPendingEvents,p as _getPendingEventsCount,f as counter,m as gauge,g as getMetricEmitter,l as histogram,d as metric,v as setMetricEmitter};
2
2
  //# sourceMappingURL=metric.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 emitEvent({ type: 'custom', name, data, timestamp: Date.now() });\n}\n\n/**\n * Internal helper to emit or buffer a CustomMetricEvent\n */\nfunction emitEvent(event: CustomMetricEvent): void {\n if (emitter) {\n emitter(event);\n } else {\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 * Internal helper for typed metric helpers (counter, gauge, histogram)\n */\nfunction emitMetric(\n name: string,\n metricKind: 'counter' | 'gauge' | 'histogram',\n value: number,\n metadata: Record<string, unknown> = {},\n): void {\n emitEvent({ type: 'custom', name, metricKind, value, data: metadata, timestamp: Date.now() });\n}\n\n/**\n * Increment a counter metric\n *\n * @param name - Counter name\n * @param value - Increment amount (default: 1)\n * @param metadata - Optional metadata\n *\n * @example\n * counter('page_views');\n * counter('items_purchased', 3);\n * counter('api_calls', 1, { endpoint: '/users' });\n */\nexport function counter(name: string, value: number = 1, metadata?: Record<string, unknown>): void {\n emitMetric(name, 'counter', value, metadata);\n}\n\n/**\n * Set a gauge metric (point-in-time value)\n *\n * @param name - Gauge name\n * @param value - Current value\n * @param metadata - Optional metadata\n *\n * @example\n * gauge('active_users', 42);\n * gauge('memory_usage_mb', 256, { heap: 'old' });\n */\nexport function gauge(name: string, value: number, metadata?: Record<string, unknown>): void {\n emitMetric(name, 'gauge', value, metadata);\n}\n\n/**\n * Record a histogram metric (distribution value)\n *\n * @param name - Histogram name\n * @param value - Observed value\n * @param metadata - Optional metadata\n *\n * @example\n * histogram('response_time_ms', 123);\n * histogram('payload_size', 4096, { route: '/api/data' });\n */\nexport function histogram(name: string, value: number, metadata?: Record<string, unknown>): void {\n emitMetric(name, 'histogram', value, metadata);\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,CAC7EC,EAAU,CAAE,KAAM,SAAU,KAAAF,EAAM,KAAAC,EAAM,UAAW,KAAK,IAAI,CAAE,CAAC,CACjE,CAKA,SAASC,EAAUN,EAAgC,CACjD,GAAIL,EACFA,EAAQK,CAAK,MACR,CACL,GAAIJ,EAAc,QAAU,IAAoB,CAC1CM,EAAM,GACR,QAAQ,KACN,mHAEF,EAEF,MACF,CACAN,EAAc,KAAKI,CAAK,CAC1B,CACF,CAKA,SAASO,EACPH,EACAI,EACAC,EACAC,EAAoC,CAAC,EAC/B,CACNJ,EAAU,CAAE,KAAM,SAAU,KAAAF,EAAM,WAAAI,EAAY,MAAAC,EAAO,KAAMC,EAAU,UAAW,KAAK,IAAI,CAAE,CAAC,CAC9F,CAcO,SAASC,EAAQP,EAAcK,EAAgB,EAAGC,EAA0C,CACjGH,EAAWH,EAAM,UAAWK,EAAOC,CAAQ,CAC7C,CAaO,SAASE,EAAMR,EAAcK,EAAeC,EAA0C,CAC3FH,EAAWH,EAAM,QAASK,EAAOC,CAAQ,CAC3C,CAaO,SAASG,EAAUT,EAAcK,EAAeC,EAA0C,CAC/FH,EAAWH,EAAM,YAAaK,EAAOC,CAAQ,CAC/C,CAUO,SAASI,GAAiC,CAC/C,OAAOlB,EAAc,MACvB,CAMO,SAASmB,GAA4B,CAC1CnB,EAAc,OAAS,CACzB",
6
- "names": ["emitter", "pendingEvents", "setMetricEmitter", "emit", "events", "event", "getMetricEmitter", "isDev", "metric", "name", "data", "emitEvent", "emitMetric", "metricKind", "value", "metadata", "counter", "gauge", "histogram", "_getPendingEventsCount", "_clearPendingEvents"]
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 * 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, metadata: Record<string, unknown> = {}): void {\n emitEvent({ type: 'custom', name, metadata, timestamp: Date.now() });\n}\n\n/**\n * Internal helper to emit or buffer a CustomMetricEvent\n */\nfunction emitEvent(event: CustomMetricEvent): void {\n if (emitter) {\n emitter(event);\n } else {\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 * Internal helper for typed metric helpers (counter, gauge, histogram)\n */\nfunction emitMetric(\n name: string,\n metricKind: 'counter' | 'gauge' | 'histogram',\n value: number,\n metadata: Record<string, unknown> = {},\n): void {\n emitEvent({ type: 'custom', name, metricKind, value, metadata, timestamp: Date.now() });\n}\n\n/**\n * Increment a counter metric\n *\n * @param name - Counter name\n * @param value - Increment amount (default: 1)\n * @param metadata - Optional metadata\n *\n * @example\n * counter('page_views');\n * counter('items_purchased', 3);\n * counter('api_calls', 1, { endpoint: '/users' });\n */\nexport function counter(name: string, value: number = 1, metadata?: Record<string, unknown>): void {\n emitMetric(name, 'counter', value, metadata);\n}\n\n/**\n * Set a gauge metric (point-in-time value)\n *\n * @param name - Gauge name\n * @param value - Current value\n * @param metadata - Optional metadata\n *\n * @example\n * gauge('active_users', 42);\n * gauge('memory_usage_mb', 256, { heap: 'old' });\n */\nexport function gauge(name: string, value: number, metadata?: Record<string, unknown>): void {\n emitMetric(name, 'gauge', value, metadata);\n}\n\n/**\n * Record a histogram metric (distribution value)\n *\n * @param name - Histogram name\n * @param value - Observed value\n * @param metadata - Optional metadata\n *\n * @example\n * histogram('response_time_ms', 123);\n * histogram('payload_size', 4096, { route: '/api/data' });\n */\nexport function histogram(name: string, value: number, metadata?: Record<string, unknown>): void {\n emitMetric(name, 'histogram', value, metadata);\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,CAMO,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,EAAoC,CAAC,EAAS,CACjFC,EAAU,CAAE,KAAM,SAAU,KAAAF,EAAM,SAAAC,EAAU,UAAW,KAAK,IAAI,CAAE,CAAC,CACrE,CAKA,SAASC,EAAUN,EAAgC,CACjD,GAAIL,EACFA,EAAQK,CAAK,MACR,CACL,GAAIJ,EAAc,QAAU,IAAoB,CAC1CM,EAAM,GACR,QAAQ,KACN,mHAEF,EAEF,MACF,CACAN,EAAc,KAAKI,CAAK,CAC1B,CACF,CAKA,SAASO,EACPH,EACAI,EACAC,EACAJ,EAAoC,CAAC,EAC/B,CACNC,EAAU,CAAE,KAAM,SAAU,KAAAF,EAAM,WAAAI,EAAY,MAAAC,EAAO,SAAAJ,EAAU,UAAW,KAAK,IAAI,CAAE,CAAC,CACxF,CAcO,SAASK,EAAQN,EAAcK,EAAgB,EAAGJ,EAA0C,CACjGE,EAAWH,EAAM,UAAWK,EAAOJ,CAAQ,CAC7C,CAaO,SAASM,EAAMP,EAAcK,EAAeJ,EAA0C,CAC3FE,EAAWH,EAAM,QAASK,EAAOJ,CAAQ,CAC3C,CAaO,SAASO,EAAUR,EAAcK,EAAeJ,EAA0C,CAC/FE,EAAWH,EAAM,YAAaK,EAAOJ,CAAQ,CAC/C,CAUO,SAASQ,GAAiC,CAC/C,OAAOjB,EAAc,MACvB,CAMO,SAASkB,GAA4B,CAC1ClB,EAAc,OAAS,CACzB",
6
+ "names": ["emitter", "pendingEvents", "setMetricEmitter", "emit", "events", "event", "getMetricEmitter", "isDev", "metric", "name", "metadata", "emitEvent", "emitMetric", "metricKind", "value", "counter", "gauge", "histogram", "_getPendingEventsCount", "_clearPendingEvents"]
7
7
  }
@@ -14,5 +14,5 @@
14
14
  * m('button_clicked', { id: 'submit' }); // ✅
15
15
  * m('unknown_event', {}); // ❌ TypeScript error
16
16
  */
17
- export declare function createTypedMetric<T extends Record<string, Record<string, unknown>>>(): <K extends keyof T & string>(name: K, data: T[K]) => void;
17
+ export declare function createTypedMetric<T extends Record<string, Record<string, unknown>>>(): <K extends keyof T & string>(name: K, metadata: T[K]) => void;
18
18
  //# sourceMappingURL=typed.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"typed.d.ts","sourceRoot":"","sources":["../../src/metrics/typed.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,MAChE,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAG,IAAI,CAGxE"}
1
+ {"version":3,"file":"typed.d.ts","sourceRoot":"","sources":["../../src/metrics/typed.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,MAChE,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,KAAG,IAAI,CAG5E"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/metrics/typed.ts"],
4
- "sourcesContent": ["/**\n * Typed metric factory for TypeScript autocomplete\n */\n\nimport { metric } from './metric.js';\n\n/**\n * Create a typed metric function with autocomplete for metric names and data shapes\n *\n * @example\n * const m = createTypedMetric<{\n * checkout_started: { step: number; cartTotal: number };\n * button_clicked: { id: string };\n * }>();\n *\n * m('checkout_started', { step: 1, cartTotal: 99.99 }); // \u2705 autocomplete works\n * m('button_clicked', { id: 'submit' }); // \u2705\n * m('unknown_event', {}); // \u274C TypeScript error\n */\nexport function createTypedMetric<T extends Record<string, Record<string, unknown>>>() {\n return function <K extends keyof T & string>(name: K, data: T[K]): void {\n metric(name, data);\n };\n}\n"],
5
- "mappings": "AAIA,OAAS,UAAAA,MAAc,cAehB,SAASC,GAAuE,CACrF,OAAO,SAAsCC,EAASC,EAAkB,CACtEH,EAAOE,EAAMC,CAAI,CACnB,CACF",
6
- "names": ["metric", "createTypedMetric", "name", "data"]
4
+ "sourcesContent": ["/**\n * Typed metric factory for TypeScript autocomplete\n */\n\nimport { metric } from './metric.js';\n\n/**\n * Create a typed metric function with autocomplete for metric names and data shapes\n *\n * @example\n * const m = createTypedMetric<{\n * checkout_started: { step: number; cartTotal: number };\n * button_clicked: { id: string };\n * }>();\n *\n * m('checkout_started', { step: 1, cartTotal: 99.99 }); // \u2705 autocomplete works\n * m('button_clicked', { id: 'submit' }); // \u2705\n * m('unknown_event', {}); // \u274C TypeScript error\n */\nexport function createTypedMetric<T extends Record<string, Record<string, unknown>>>() {\n return function <K extends keyof T & string>(name: K, metadata: T[K]): void {\n metric(name, metadata);\n };\n}\n"],
5
+ "mappings": "AAIA,OAAS,UAAAA,MAAc,cAehB,SAASC,GAAuE,CACrF,OAAO,SAAsCC,EAASC,EAAsB,CAC1EH,EAAOE,EAAMC,CAAQ,CACvB,CACF",
6
+ "names": ["metric", "createTypedMetric", "name", "metadata"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/observe/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAKhG;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,MAAM,GAAG,IAAI,CAE/E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEzD;AA4BD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC3C,MAAM,IAAI,CAsDZ;AAED,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/observe/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAKhG;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,MAAM,GAAG,IAAI,CAE/E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEzD;AA6CD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC3C,MAAM,IAAI,CAsDZ;AAED,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,2 +1,2 @@
1
- const i=new Map;function E(e,r){i.set(e,{getState:r})}function v(e){i.delete(e)}function a(){for(const[e,r]of i)try{return{machineId:e,machineState:r.getState()}}catch{}return{}}function c(){try{return typeof location<"u"?location.href:""}catch{return""}}function g(e){if(typeof window>"u")return()=>{};const r=t=>{const n={type:"error",message:t.message||"Unknown error",stack:t.error?.stack,filename:t.filename,lineno:t.lineno,colno:t.colno,timestamp:Date.now(),url:c(),...a()};e(n)},s=t=>{const n=t.reason;let o;if(n instanceof Error)o=n.message;else if(typeof n=="string")o=n;else try{o=JSON.stringify(n)}catch{o=String(n)}const d={type:"unhandled-rejection",reason:o,timestamp:Date.now(),url:c(),...a()};e(d)};return window.addEventListener("error",r),window.addEventListener("unhandledrejection",s),()=>{window.removeEventListener("error",r),window.removeEventListener("unhandledrejection",s)}}export{g as observeErrors,E as registerMachineContext,v as unregisterMachineContext};
1
+ const s=new Map;function E(e,r){s.set(e,{getState:r})}function l(e){s.delete(e)}const g=10;function a(){if(s.size===0)return{};const e=[];for(const[r,i]of s){if(e.length>=g)break;try{e.push({id:r,state:i.getState()})}catch{}}return e.length===0?{}:{machineId:e[0].id,machineState:e[0].state,machines:e}}function c(){try{return typeof location<"u"?location.href:""}catch{return""}}function f(e){if(typeof window>"u")return()=>{};const r=t=>{const n={type:"error",message:t.message||"Unknown error",stack:t.error?.stack,filename:t.filename,lineno:t.lineno,colno:t.colno,timestamp:Date.now(),url:c(),...a()};e(n)},i=t=>{const n=t.reason;let o;if(n instanceof Error)o=n.message;else if(typeof n=="string")o=n;else try{o=JSON.stringify(n)}catch{o=String(n)}const d={type:"unhandled-rejection",reason:o,timestamp:Date.now(),url:c(),...a()};e(d)};return window.addEventListener("error",r),window.addEventListener("unhandledrejection",i),()=>{window.removeEventListener("error",r),window.removeEventListener("unhandledrejection",i)}}export{f as observeErrors,E as registerMachineContext,l as unregisterMachineContext};
2
2
  //# sourceMappingURL=errors.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/observe/errors.ts"],
4
- "sourcesContent": ["/**\n * Error tracking - captures errors and unhandled promise rejections\n * Integrates with state machines to include machine context in error reports\n */\n\nimport type { ErrorEvent, UnhandledRejectionEvent, ObserveErrorEvent } from '../types/index.js';\n\n// Global machine context registry (populated by createMachine)\nconst machineContexts = new Map<string, { getState: () => string }>();\n\n/**\n * Register a machine's context for error tracking\n * Called internally by createMachine()\n */\nexport function registerMachineContext(id: string, getState: () => string): void {\n machineContexts.set(id, { getState });\n}\n\n/**\n * Unregister a machine's context\n * Called internally when machine is destroyed\n */\nexport function unregisterMachineContext(id: string): void {\n machineContexts.delete(id);\n}\n\n/**\n * Get current machine context for error reports\n * Returns first active machine (could be enhanced for multiple)\n */\nfunction getMachineContext(): { machineId?: string; machineState?: string } {\n for (const [id, ctx] of machineContexts) {\n try {\n return { machineId: id, machineState: ctx.getState() };\n } catch {\n // Machine might be in invalid state, skip it\n }\n }\n return {};\n}\n\n/**\n * Get current URL safely\n */\nfunction getCurrentUrl(): string {\n try {\n return typeof location !== 'undefined' ? location.href : '';\n } catch {\n return '';\n }\n}\n\n/**\n * Observe global errors and unhandled promise rejections\n * @param callback - Called for each error event\n * @returns Cleanup function\n */\nexport function observeErrors(\n callback: (event: ObserveErrorEvent) => void\n): () => void {\n // Check if we're in a browser environment\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n const errorHandler = (event: globalThis.ErrorEvent) => {\n const errorEvent: ErrorEvent = {\n type: 'error',\n message: event.message || 'Unknown error',\n stack: event.error?.stack,\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n timestamp: Date.now(),\n url: getCurrentUrl(),\n ...getMachineContext(),\n };\n callback(errorEvent);\n };\n\n const rejectionHandler = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n let message: string;\n\n if (reason instanceof Error) {\n message = reason.message;\n } else if (typeof reason === 'string') {\n message = reason;\n } else {\n try {\n message = JSON.stringify(reason);\n } catch {\n message = String(reason);\n }\n }\n\n const rejectionEvent: UnhandledRejectionEvent = {\n type: 'unhandled-rejection',\n reason: message,\n timestamp: Date.now(),\n url: getCurrentUrl(),\n ...getMachineContext(),\n };\n callback(rejectionEvent);\n };\n\n window.addEventListener('error', errorHandler);\n window.addEventListener('unhandledrejection', rejectionHandler);\n\n return () => {\n window.removeEventListener('error', errorHandler);\n window.removeEventListener('unhandledrejection', rejectionHandler);\n };\n}\n\nexport type { ErrorEvent, UnhandledRejectionEvent, ObserveErrorEvent };\n"],
5
- "mappings": "AAQA,MAAMA,EAAkB,IAAI,IAMrB,SAASC,EAAuBC,EAAYC,EAA8B,CAC/EH,EAAgB,IAAIE,EAAI,CAAE,SAAAC,CAAS,CAAC,CACtC,CAMO,SAASC,EAAyBF,EAAkB,CACzDF,EAAgB,OAAOE,CAAE,CAC3B,CAMA,SAASG,GAAmE,CAC1E,SAAW,CAACH,EAAII,CAAG,IAAKN,EACtB,GAAI,CACF,MAAO,CAAE,UAAWE,EAAI,aAAcI,EAAI,SAAS,CAAE,CACvD,MAAQ,CAER,CAEF,MAAO,CAAC,CACV,CAKA,SAASC,GAAwB,CAC/B,GAAI,CACF,OAAO,OAAO,SAAa,IAAc,SAAS,KAAO,EAC3D,MAAQ,CACN,MAAO,EACT,CACF,CAOO,SAASC,EACdC,EACY,CAEZ,GAAI,OAAO,OAAW,IACpB,MAAO,IAAM,CAAC,EAGhB,MAAMC,EAAgBC,GAAiC,CACrD,MAAMC,EAAyB,CAC7B,KAAM,QACN,QAASD,EAAM,SAAW,gBAC1B,MAAOA,EAAM,OAAO,MACpB,SAAUA,EAAM,SAChB,OAAQA,EAAM,OACd,MAAOA,EAAM,MACb,UAAW,KAAK,IAAI,EACpB,IAAKJ,EAAc,EACnB,GAAGF,EAAkB,CACvB,EACAI,EAASG,CAAU,CACrB,EAEMC,EAAoBF,GAAiC,CACzD,MAAMG,EAASH,EAAM,OACrB,IAAII,EAEJ,GAAID,aAAkB,MACpBC,EAAUD,EAAO,gBACR,OAAOA,GAAW,SAC3BC,EAAUD,MAEV,IAAI,CACFC,EAAU,KAAK,UAAUD,CAAM,CACjC,MAAQ,CACNC,EAAU,OAAOD,CAAM,CACzB,CAGF,MAAME,EAA0C,CAC9C,KAAM,sBACN,OAAQD,EACR,UAAW,KAAK,IAAI,EACpB,IAAKR,EAAc,EACnB,GAAGF,EAAkB,CACvB,EACAI,EAASO,CAAc,CACzB,EAEA,cAAO,iBAAiB,QAASN,CAAY,EAC7C,OAAO,iBAAiB,qBAAsBG,CAAgB,EAEvD,IAAM,CACX,OAAO,oBAAoB,QAASH,CAAY,EAChD,OAAO,oBAAoB,qBAAsBG,CAAgB,CACnE,CACF",
6
- "names": ["machineContexts", "registerMachineContext", "id", "getState", "unregisterMachineContext", "getMachineContext", "ctx", "getCurrentUrl", "observeErrors", "callback", "errorHandler", "event", "errorEvent", "rejectionHandler", "reason", "message", "rejectionEvent"]
4
+ "sourcesContent": ["/**\n * Error tracking - captures errors and unhandled promise rejections\n * Integrates with state machines to include machine context in error reports\n */\n\nimport type { ErrorEvent, UnhandledRejectionEvent, ObserveErrorEvent } from '../types/index.js';\n\n// Global machine context registry (populated by createMachine)\nconst machineContexts = new Map<string, { getState: () => string }>();\n\n/**\n * Register a machine's context for error tracking\n * Called internally by createMachine()\n */\nexport function registerMachineContext(id: string, getState: () => string): void {\n machineContexts.set(id, { getState });\n}\n\n/**\n * Unregister a machine's context\n * Called internally when machine is destroyed\n */\nexport function unregisterMachineContext(id: string): void {\n machineContexts.delete(id);\n}\n\nconst MAX_MACHINES_IN_ERROR = 10;\n\n/**\n * Get current machine context for error reports\n * Returns all active machines (max 10) + backward compat fields from first\n */\nfunction getMachineContext(): {\n machineId?: string;\n machineState?: string;\n machines?: Array<{ id: string; state: string }>;\n} {\n if (machineContexts.size === 0) return {};\n\n const machines: Array<{ id: string; state: string }> = [];\n for (const [id, ctx] of machineContexts) {\n if (machines.length >= MAX_MACHINES_IN_ERROR) break;\n try {\n machines.push({ id, state: ctx.getState() });\n } catch {\n // Machine might be in invalid state, skip it\n }\n }\n\n if (machines.length === 0) return {};\n\n return {\n machineId: machines[0].id,\n machineState: machines[0].state,\n machines,\n };\n}\n\n/**\n * Get current URL safely\n */\nfunction getCurrentUrl(): string {\n try {\n return typeof location !== 'undefined' ? location.href : '';\n } catch {\n return '';\n }\n}\n\n/**\n * Observe global errors and unhandled promise rejections\n * @param callback - Called for each error event\n * @returns Cleanup function\n */\nexport function observeErrors(\n callback: (event: ObserveErrorEvent) => void\n): () => void {\n // Check if we're in a browser environment\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n const errorHandler = (event: globalThis.ErrorEvent) => {\n const errorEvent: ErrorEvent = {\n type: 'error',\n message: event.message || 'Unknown error',\n stack: event.error?.stack,\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n timestamp: Date.now(),\n url: getCurrentUrl(),\n ...getMachineContext(),\n };\n callback(errorEvent);\n };\n\n const rejectionHandler = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n let message: string;\n\n if (reason instanceof Error) {\n message = reason.message;\n } else if (typeof reason === 'string') {\n message = reason;\n } else {\n try {\n message = JSON.stringify(reason);\n } catch {\n message = String(reason);\n }\n }\n\n const rejectionEvent: UnhandledRejectionEvent = {\n type: 'unhandled-rejection',\n reason: message,\n timestamp: Date.now(),\n url: getCurrentUrl(),\n ...getMachineContext(),\n };\n callback(rejectionEvent);\n };\n\n window.addEventListener('error', errorHandler);\n window.addEventListener('unhandledrejection', rejectionHandler);\n\n return () => {\n window.removeEventListener('error', errorHandler);\n window.removeEventListener('unhandledrejection', rejectionHandler);\n };\n}\n\nexport type { ErrorEvent, UnhandledRejectionEvent, ObserveErrorEvent };\n"],
5
+ "mappings": "AAQA,MAAMA,EAAkB,IAAI,IAMrB,SAASC,EAAuBC,EAAYC,EAA8B,CAC/EH,EAAgB,IAAIE,EAAI,CAAE,SAAAC,CAAS,CAAC,CACtC,CAMO,SAASC,EAAyBF,EAAkB,CACzDF,EAAgB,OAAOE,CAAE,CAC3B,CAEA,MAAMG,EAAwB,GAM9B,SAASC,GAIP,CACA,GAAIN,EAAgB,OAAS,EAAG,MAAO,CAAC,EAExC,MAAMO,EAAiD,CAAC,EACxD,SAAW,CAACL,EAAIM,CAAG,IAAKR,EAAiB,CACvC,GAAIO,EAAS,QAAUF,EAAuB,MAC9C,GAAI,CACFE,EAAS,KAAK,CAAE,GAAAL,EAAI,MAAOM,EAAI,SAAS,CAAE,CAAC,CAC7C,MAAQ,CAER,CACF,CAEA,OAAID,EAAS,SAAW,EAAU,CAAC,EAE5B,CACL,UAAWA,EAAS,CAAC,EAAE,GACvB,aAAcA,EAAS,CAAC,EAAE,MAC1B,SAAAA,CACF,CACF,CAKA,SAASE,GAAwB,CAC/B,GAAI,CACF,OAAO,OAAO,SAAa,IAAc,SAAS,KAAO,EAC3D,MAAQ,CACN,MAAO,EACT,CACF,CAOO,SAASC,EACdC,EACY,CAEZ,GAAI,OAAO,OAAW,IACpB,MAAO,IAAM,CAAC,EAGhB,MAAMC,EAAgBC,GAAiC,CACrD,MAAMC,EAAyB,CAC7B,KAAM,QACN,QAASD,EAAM,SAAW,gBAC1B,MAAOA,EAAM,OAAO,MACpB,SAAUA,EAAM,SAChB,OAAQA,EAAM,OACd,MAAOA,EAAM,MACb,UAAW,KAAK,IAAI,EACpB,IAAKJ,EAAc,EACnB,GAAGH,EAAkB,CACvB,EACAK,EAASG,CAAU,CACrB,EAEMC,EAAoBF,GAAiC,CACzD,MAAMG,EAASH,EAAM,OACrB,IAAII,EAEJ,GAAID,aAAkB,MACpBC,EAAUD,EAAO,gBACR,OAAOA,GAAW,SAC3BC,EAAUD,MAEV,IAAI,CACFC,EAAU,KAAK,UAAUD,CAAM,CACjC,MAAQ,CACNC,EAAU,OAAOD,CAAM,CACzB,CAGF,MAAME,EAA0C,CAC9C,KAAM,sBACN,OAAQD,EACR,UAAW,KAAK,IAAI,EACpB,IAAKR,EAAc,EACnB,GAAGH,EAAkB,CACvB,EACAK,EAASO,CAAc,CACzB,EAEA,cAAO,iBAAiB,QAASN,CAAY,EAC7C,OAAO,iBAAiB,qBAAsBG,CAAgB,EAEvD,IAAM,CACX,OAAO,oBAAoB,QAASH,CAAY,EAChD,OAAO,oBAAoB,qBAAsBG,CAAgB,CACnE,CACF",
6
+ "names": ["machineContexts", "registerMachineContext", "id", "getState", "unregisterMachineContext", "MAX_MACHINES_IN_ERROR", "getMachineContext", "machines", "ctx", "getCurrentUrl", "observeErrors", "callback", "errorHandler", "event", "errorEvent", "rejectionHandler", "reason", "message", "rejectionEvent"]
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,CAiLhE;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;AA4B7F,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,CAyLhE;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 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};
1
+ import{vitalObservers}from"./vitals.js";import{observeErrors}from"./errors.js";import{createFetchTransport}from"../transport/fetch.js";import{createSampler,eventTypeToSamplingType}from"./sampling.js";import{createSessionManager}from"./session.js";import{setMetricEmitter,getMetricEmitter}from"../metrics/index.js";const defaults={endpoint:"/api/metrics",vitals:!0,errors:!0,batchSize:10,flushInterval:5e3,debug:!1};function validateOptions(options){if(options.batchSize!==void 0&&(options.batchSize<1||!Number.isFinite(options.batchSize)))throw new Error(`[svoose] batchSize must be >= 1, got ${options.batchSize}`);if(options.flushInterval!==void 0&&(options.flushInterval<100||!Number.isFinite(options.flushInterval)))throw new Error(`[svoose] flushInterval must be >= 100ms, got ${options.flushInterval}`);if(typeof options.sampling=="number"&&(options.sampling<0||options.sampling>1))throw new Error(`[svoose] sampling rate must be between 0 and 1, got ${options.sampling}`)}let globalObserverCallback=null;function setGlobalObserver(callback){globalObserverCallback=callback}function getGlobalObserver(){return globalObserverCallback}function observe(options={}){validateOptions(options);const config={...defaults,...options},transport=config.transport??createFetchTransport(config.endpoint),sampler=config.sampling!=null?createSampler(config.sampling):null,sessionManager=config.session!=null?createSessionManager(config.session,config.debug):null,cleanups=[];sessionManager&&cleanups.push(()=>sessionManager.destroy());const buffer=[];let flushTimer=null;const getUrl=()=>{try{return typeof location<"u"?location.href:""}catch{return""}},bufferEvent=event=>{if(!(config.filter&&!config.filter(event))){if(sampler){const samplingType=eventTypeToSamplingType(event.type);if(samplingType&&!sampler.shouldSample(samplingType))return}sessionManager&&(event.sessionId=sessionManager.getSessionId()),config.debug&&console.log("[svoose]",event),buffer.push(event),buffer.length>=config.batchSize&&flush()}},handleError=err=>{const error=err instanceof Error?err:new Error(String(err));config.onError&&config.onError(error),config.debug&&console.error("[svoose] transport error:",error)},flush=()=>{if(buffer.length===0)return;const events=buffer.splice(0,buffer.length);try{const result=transport.send(events);result&&typeof result.catch=="function"&&result.catch(handleError)}catch(err){handleError(err)}},handleMetric=metric=>{const vitalEvent={type:"vital",name:metric.name,value:metric.value,rating:metric.rating,delta:metric.delta,timestamp:metric.timestamp,url:getUrl()};bufferEvent(vitalEvent)};if(config.vitals){const vitalsToObserve=config.vitals===!0?["CLS","LCP","FID","INP","FCP","TTFB"]:config.vitals;for(const name of vitalsToObserve){const observer=vitalObservers[name];observer&&cleanups.push(observer(handleMetric))}}if(config.errors&&cleanups.push(observeErrors(event=>{bufferEvent(event)})),setGlobalObserver(bufferEvent),cleanups.push(()=>{getGlobalObserver()===bufferEvent&&setGlobalObserver(null)}),setMetricEmitter(bufferEvent),cleanups.push(()=>{getMetricEmitter()===bufferEvent&&setMetricEmitter(null)}),flushTimer=setInterval(flush,config.flushInterval),cleanups.push(()=>{flushTimer&&clearInterval(flushTimer)}),typeof document<"u"){const visibilityHandler=()=>{document.visibilityState==="hidden"&&flush()};document.addEventListener("visibilitychange",visibilityHandler),cleanups.push(()=>{document.removeEventListener("visibilitychange",visibilityHandler)})}if(typeof window<"u"){const unloadHandler=()=>{flush()};window.addEventListener("beforeunload",unloadHandler),cleanups.push(()=>{window.removeEventListener("beforeunload",unloadHandler)})}return()=>{flush(),cleanups.forEach(fn=>fn()),transport.destroy?.()}}export{getGlobalObserver,observe,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 // 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
- "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"]
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 debug: false,\n} satisfies Required<Omit<ObserveOptions, 'transport' | 'filter' | 'sampling' | 'session' | 'onError'>>;\n\n/**\n * Validate observe options at startup\n */\nfunction validateOptions(options: ObserveOptions): void {\n if (options.batchSize !== undefined && (options.batchSize < 1 || !Number.isFinite(options.batchSize))) {\n throw new Error(`[svoose] batchSize must be >= 1, got ${options.batchSize}`);\n }\n if (options.flushInterval !== undefined && (options.flushInterval < 100 || !Number.isFinite(options.flushInterval))) {\n throw new Error(`[svoose] flushInterval must be >= 100ms, got ${options.flushInterval}`);\n }\n if (typeof options.sampling === 'number' && (options.sampling < 0 || options.sampling > 1)) {\n throw new Error(`[svoose] sampling rate must be between 0 and 1, got ${options.sampling}`);\n }\n}\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 validateOptions(options);\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, config.debug)\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 // Handle transport errors consistently\n const handleError = (err: unknown): void => {\n const error = err instanceof Error ? err : new Error(String(err));\n if (config.onError) {\n config.onError(error);\n }\n if (config.debug) {\n console.error('[svoose] transport error:', error);\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 try {\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(handleError);\n }\n } catch (err) {\n handleError(err);\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": "AAIA,OAAS,mBAAoD,cAC7D,OAAS,kBAA6C,cACtD,OAAS,yBAA4B,wBACrC,OACE,cACA,4BAEK,gBACP,OAAS,yBAAiD,eAC1D,OAAS,iBAAkB,qBAAwB,sBAInD,MAAM,SAAW,CACf,SAAU,eACV,OAAQ,GACR,OAAQ,GACR,UAAW,GACX,cAAe,IACf,MAAO,EACT,EAKA,SAAS,gBAAgB,QAA+B,CACtD,GAAI,QAAQ,YAAc,SAAc,QAAQ,UAAY,GAAK,CAAC,OAAO,SAAS,QAAQ,SAAS,GACjG,MAAM,IAAI,MAAM,wCAAwC,QAAQ,SAAS,EAAE,EAE7E,GAAI,QAAQ,gBAAkB,SAAc,QAAQ,cAAgB,KAAO,CAAC,OAAO,SAAS,QAAQ,aAAa,GAC/G,MAAM,IAAI,MAAM,gDAAgD,QAAQ,aAAa,EAAE,EAEzF,GAAI,OAAO,QAAQ,UAAa,WAAa,QAAQ,SAAW,GAAK,QAAQ,SAAW,GACtF,MAAM,IAAI,MAAM,uDAAuD,QAAQ,QAAQ,EAAE,CAE7F,CAGA,IAAI,uBAAiE,KAM9D,SAAS,kBAAkB,SAA+C,CAC/E,uBAAyB,QAC3B,CAMO,SAAS,mBAAmD,CACjE,OAAO,sBACT,CAqBO,SAAS,QAAQ,QAA0B,CAAC,EAAe,CAChE,gBAAgB,OAAO,EAEvB,MAAM,OAAS,CAAE,GAAG,SAAU,GAAG,OAAQ,EACnC,UAAuB,OAAO,WAAa,qBAAqB,OAAO,QAAQ,EAG/E,QAA0B,OAAO,UAAY,KAC/C,cAAc,OAAO,QAAQ,EAC7B,KAGE,eAAwC,OAAO,SAAW,KAC5D,qBAAqB,OAAO,QAAS,OAAO,KAAK,EACjD,KAEE,SAA2B,CAAC,EAG9B,gBACF,SAAS,KAAK,IAAM,eAAe,QAAQ,CAAC,EAE9C,MAAM,OAAyB,CAAC,EAChC,IAAI,WAAoD,KAGxD,MAAM,OAAS,IAAc,CAC3B,GAAI,CACF,OAAO,OAAO,SAAa,IAAc,SAAS,KAAO,EAC3D,MAAQ,CACN,MAAO,EACT,CACF,EAGM,YAAe,OAA8B,CAEjD,GAAI,SAAO,QAAU,CAAC,OAAO,OAAO,KAAK,GAKzC,IAAI,QAAS,CACX,MAAM,aAAe,wBAAwB,MAAM,IAAI,EACvD,GAAI,cAAgB,CAAC,QAAQ,aAAa,YAAY,EACpD,MAEJ,CAGI,iBACD,MAAgD,UAAY,eAAe,aAAa,GAGvF,OAAO,OACT,QAAQ,IAAI,WAAY,KAAK,EAG/B,OAAO,KAAK,KAAK,EAEb,OAAO,QAAU,OAAO,WAC1B,MAAM,EAEV,EAGM,YAAe,KAAuB,CAC1C,MAAM,MAAQ,eAAe,MAAQ,IAAM,IAAI,MAAM,OAAO,GAAG,CAAC,EAC5D,OAAO,SACT,OAAO,QAAQ,KAAK,EAElB,OAAO,OACT,QAAQ,MAAM,4BAA6B,KAAK,CAEpD,EAGM,MAAQ,IAAY,CACxB,GAAI,OAAO,SAAW,EAAG,OAEzB,MAAM,OAAS,OAAO,OAAO,EAAG,OAAO,MAAM,EAC7C,GAAI,CAEF,MAAM,OAAS,UAAU,KAAK,MAAM,EAChC,QAAU,OAAO,OAAO,OAAU,YACpC,OAAO,MAAM,WAAW,CAE5B,OAAS,IAAK,CACZ,YAAY,GAAG,CACjB,CACF,EAGM,aAAgB,QAAyB,CAC7C,MAAM,WAAyB,CAC7B,KAAM,QACN,KAAM,OAAO,KACb,MAAO,OAAO,MACd,OAAQ,OAAO,OACf,MAAO,OAAO,MACd,UAAW,OAAO,UAClB,IAAK,OAAO,CACd,EACA,YAAY,UAAU,CACxB,EAGA,GAAI,OAAO,OAAQ,CACjB,MAAM,gBACJ,OAAO,SAAW,GACd,CAAC,MAAO,MAAO,MAAO,MAAO,MAAO,MAAM,EAC1C,OAAO,OAEb,UAAW,QAAQ,gBAAiB,CAClC,MAAM,SAAW,eAAe,IAAI,EAChC,UACF,SAAS,KAAK,SAAS,YAAY,CAAC,CAExC,CACF,CAoCA,GAjCI,OAAO,QACT,SAAS,KACP,cAAe,OAA6B,CAC1C,YAAY,KAAK,CACnB,CAAC,CACH,EAIF,kBAAkB,WAAW,EAC7B,SAAS,KAAK,IAAM,CAEd,kBAAkB,IAAM,aAC1B,kBAAkB,IAAI,CAE1B,CAAC,EAGD,iBAAiB,WAAW,EAC5B,SAAS,KAAK,IAAM,CAEd,iBAAiB,IAAM,aACzB,iBAAiB,IAAI,CAEzB,CAAC,EAGD,WAAa,YAAY,MAAO,OAAO,aAAa,EACpD,SAAS,KAAK,IAAM,CACd,YAAY,cAAc,UAAU,CAC1C,CAAC,EAGG,OAAO,SAAa,IAAa,CACnC,MAAM,kBAAoB,IAAY,CAChC,SAAS,kBAAoB,UAC/B,MAAM,CAEV,EACA,SAAS,iBAAiB,mBAAoB,iBAAiB,EAC/D,SAAS,KAAK,IAAM,CAClB,SAAS,oBAAoB,mBAAoB,iBAAiB,CACpE,CAAC,CACH,CAGA,GAAI,OAAO,OAAW,IAAa,CACjC,MAAM,cAAgB,IAAY,CAChC,MAAM,CACR,EACA,OAAO,iBAAiB,eAAgB,aAAa,EACrD,SAAS,KAAK,IAAM,CAClB,OAAO,oBAAoB,eAAgB,aAAa,CAC1D,CAAC,CACH,CAGA,MAAO,IAAM,CACX,MAAM,EACN,SAAS,QAAS,IAAO,GAAG,CAAC,EAE5B,UAAmD,UAAU,CAChE,CACF",
6
+ "names": []
7
7
  }
@@ -1 +1 @@
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
+ {"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,CAiC7D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAChB,iBAAiB,GAAG,IAAI,CAc1B"}
@@ -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 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};
1
+ function t(e){return e<=0?0:e>=1?1:e}function i(e){const a=typeof e=="number"?{vitals:t(e),errors:t(e),custom:t(e),transitions:t(e)}:{vitals:t(e.vitals??1),errors:t(e.errors??1),custom:t(e.custom??1),transitions:t(e.transitions??1)};return{shouldSample(n){const r=a[n];return r>=1?!0:r<=0?!1:Math.random()<r},getRate(n){return a[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";default:return null}}export{i 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\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",
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 }\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 };\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 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,CACnC,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,CACpD,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,QACE,OAAO,IACX,CACF",
6
6
  "names": ["normalizeRate", "rate", "createSampler", "config", "rates", "eventType", "eventTypeToSamplingType"]
7
7
  }
@@ -29,5 +29,5 @@ export interface SessionManager {
29
29
  * storage: 'localStorage',
30
30
  * });
31
31
  */
32
- export declare function createSessionManager(config: SessionOption): SessionManager | null;
32
+ export declare function createSessionManager(config: SessionOption, debug?: boolean): SessionManager | null;
33
33
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
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
+ {"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,EAAE,KAAK,GAAE,OAAe,GAAG,cAAc,GAAG,IAAI,CA0IzG"}
@@ -1,2 +1,2 @@
1
- const a="svoose_session";function S(){const s=Date.now(),o=Math.random().toString(36).slice(2,11);return`${s}-${o}`}function f(s){if(s===!1)return null;const o=s===!0?{timeout:18e5,storage:"sessionStorage"}:{timeout:s.timeout??18e5,storage:s.storage??"sessionStorage"};let e=null;function i(){if(o.storage==="memory"||typeof window>"u")return null;try{const t=o.storage==="localStorage"?localStorage:sessionStorage,n="__svoose_test__";return t.setItem(n,"1"),t.removeItem(n),t}catch{return null}}function c(){const t=i();if(!t)return null;try{const n=t.getItem(a);if(!n)return null;const r=JSON.parse(n);return typeof r.id!="string"||typeof r.startedAt!="number"||typeof r.lastActivity!="number"?null:r}catch{return null}}function u(t){const n=i();if(n)try{n.setItem(a,JSON.stringify(t))}catch{}}function l(){const t=Date.now(),n={id:S(),startedAt:t,lastActivity:t};return u(n),n}function g(t){return Date.now()-t.lastActivity>o.timeout}return{getSessionId(){const t=Date.now();return e||(e=c()),!e||g(e)?(e=l(),e.id):(e.lastActivity=t,u(e),e.id)},reset(){return e=l(),e.id},destroy(){e=null;const t=i();if(t)try{t.removeItem(a)}catch{}}}}export{f as createSessionManager};
1
+ const l="svoose_session";function f(){const s=Date.now(),r=Math.random().toString(36).slice(2,11);return`${s}-${r}`}function d(s,r=!1){if(s===!1)return null;const i=s===!0?{timeout:18e5,storage:"sessionStorage"}:{timeout:s.timeout??18e5,storage:s.storage??"sessionStorage"};let e=null;function a(){if(i.storage==="memory"||typeof window>"u")return null;try{const t=i.storage==="localStorage"?localStorage:sessionStorage,n="__svoose_test__";return t.setItem(n,"1"),t.removeItem(n),t}catch{return r&&typeof console<"u"&&console.warn("[svoose] Storage unavailable, falling back to in-memory sessions. SessionId will not persist across page reloads."),null}}function g(){const t=a();if(!t)return null;try{const n=t.getItem(l);if(!n)return null;const o=JSON.parse(n);return typeof o.id!="string"||typeof o.startedAt!="number"||typeof o.lastActivity!="number"?null:o}catch{return null}}function u(t){const n=a();if(n)try{n.setItem(l,JSON.stringify(t))}catch{}}function c(){const t=Date.now(),n={id:f(),startedAt:t,lastActivity:t};return u(n),n}function S(t){return Date.now()-t.lastActivity>i.timeout}return{getSessionId(){const t=Date.now();return e||(e=g()),!e||S(e)?(e=c(),e.id):(e.lastActivity=t,u(e),e.id)},reset(){return e=c(),e.id},destroy(){e=null;const t=a();if(t)try{t.removeItem(l)}catch{}}}}export{d as createSessionManager};
2
2
  //# sourceMappingURL=session.js.map
@@ -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\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
- "names": ["STORAGE_KEY", "generateId", "timestamp", "random", "createSessionManager", "config", "opts", "currentSession", "getStorage", "storage", "testKey", "load", "data", "session", "save", "createNew", "now", "isExpired"]
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, debug: boolean = false): 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 if (debug && typeof console !== 'undefined') {\n console.warn('[svoose] Storage unavailable, falling back to in-memory sessions. SessionId will not persist across page reloads.');\n }\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,EAAuBC,EAAiB,GAA8B,CAEzG,GAAID,IAAW,GAAO,OAAO,KAG7B,MAAME,EAAsBF,IAAW,GACnC,CAAE,QAAS,KAAiB,QAAS,gBAAiB,EACtD,CACE,QAASA,EAAO,SAAW,KAC3B,QAASA,EAAO,SAAW,gBAC7B,EAEJ,IAAIG,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,OAAIJ,GAAS,OAAO,QAAY,KAC9B,QAAQ,KAAK,mHAAmH,EAE3H,IACT,CACF,CAKA,SAASM,GAAuB,CAC9B,MAAMF,EAAUD,EAAW,EAC3B,GAAI,CAACC,EAAS,OAAO,KAErB,GAAI,CACF,MAAMG,EAAOH,EAAQ,QAAQV,CAAW,EACxC,GAAI,CAACa,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,QAAQV,EAAa,KAAK,UAAUc,CAAO,CAAC,CACtD,MAAQ,CAER,CACF,CAKA,SAASE,GAAqB,CAC5B,MAAMC,EAAM,KAAK,IAAI,EACfH,EAAmB,CACvB,GAAIb,EAAW,EACf,UAAWgB,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,WAAWV,CAAW,CAChC,MAAQ,CAER,CAEJ,CACF,CACF",
6
+ "names": ["STORAGE_KEY", "generateId", "timestamp", "random", "createSessionManager", "config", "debug", "opts", "currentSession", "getStorage", "storage", "testKey", "load", "data", "session", "save", "createNew", "now", "isExpired"]
7
7
  }
@@ -16,8 +16,8 @@ export interface ReactiveMachine<TContext extends object, TState extends string,
16
16
  matches(state: TState): boolean;
17
17
  /** Check if machine is in any of given states */
18
18
  matchesAny(...states: TState[]): boolean;
19
- /** Check if event can be sent */
20
- can(eventType: TEvent['type']): boolean;
19
+ /** Check if event can be sent. Accepts string or full event object for payload-dependent guards. */
20
+ can(event: TEvent['type'] | TEvent): boolean;
21
21
  /** Send event to machine */
22
22
  send(event: TEvent | TEvent['type']): void;
23
23
  /** Cleanup machine */
@@ -1 +1 @@
1
- {"version":3,"file":"index.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/index.svelte.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAiB,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE1F;;GAEG;AACH,MAAM,WAAW,eAAe,CAC9B,QAAQ,SAAS,MAAM,EACvB,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS,WAAW;IAE1B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,yCAAyC;IACzC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,iDAAiD;IACjD,UAAU,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACzC,iCAAiC;IACjC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;IACxC,4BAA4B;IAC5B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC3C,sBAAsB;IACtB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,UAAU,CACxB,QAAQ,SAAS,MAAM,EACvB,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS,WAAW,EAC1B,MAAM,EAAE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAsC5F;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW,mBAAa,CAAC;AAGtC,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/index.svelte.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAiB,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE1F;;GAEG;AACH,MAAM,WAAW,eAAe,CAC9B,QAAQ,SAAS,MAAM,EACvB,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS,WAAW;IAE1B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,yCAAyC;IACzC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,iDAAiD;IACjD,UAAU,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACzC,oGAAoG;IACpG,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7C,4BAA4B;IAC5B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC3C,sBAAsB;IACtB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,UAAU,CACxB,QAAQ,SAAS,MAAM,EACvB,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS,WAAW,EAC1B,MAAM,EAAE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAsC5F;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW,mBAAa,CAAC;AAGtC,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,2 +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};
1
+ import{createMachine}from"../machine/index.js";function useMachine(config){const machine=createMachine(config);let reactiveState=$state(machine.state),reactiveContext=$state(machine.context);const originalSend=machine.send.bind(machine);return{get state(){return reactiveState},get context(){return reactiveContext},matches(state){return reactiveState===state},matchesAny(...states){return states.includes(reactiveState)},can(event){return machine.can(event)},send:event=>{originalSend(event),reactiveState=machine.state,reactiveContext=machine.context},destroy:machine.destroy.bind(machine)}}const fromMachine=useMachine;export{fromMachine,useMachine};
2
2
  //# sourceMappingURL=index.svelte.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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"]
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. Accepts string or full event object for payload-dependent guards. */\n can(event: TEvent['type'] | TEvent): 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(event: TEvent['type'] | TEvent): boolean {\n return machine.can(event);\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,kBAA2D,sBAqD7D,SAAS,WAId,OAA4F,CAE5F,MAAM,QAAU,cAAc,MAAM,EAGpC,IAAI,cAAgB,OAAe,QAAQ,KAAK,EAC5C,gBAAkB,OAAiB,QAAQ,OAAO,EAGtD,MAAM,aAAe,QAAQ,KAAK,KAAK,OAAO,EAU9C,MAAO,CACL,IAAI,OAAgB,CAClB,OAAO,aACT,EACA,IAAI,SAAoB,CACtB,OAAO,eACT,EACA,QAAQ,MAAwB,CAC9B,OAAO,gBAAkB,KAC3B,EACA,cAAc,OAA2B,CACvC,OAAO,OAAO,SAAS,aAAa,CACtC,EACA,IAAI,MAAyC,CAC3C,OAAO,QAAQ,IAAI,KAAK,CAC1B,EACA,KAxBoB,OAAyC,CAC7D,aAAa,KAAK,EAElB,cAAgB,QAAQ,MACxB,gBAAkB,QAAQ,OAC5B,EAoBE,QAAS,QAAQ,QAAQ,KAAK,OAAO,CACvC,CACF,CAkBO,MAAM,YAAc",
6
+ "names": []
7
7
  }
@@ -1,2 +1,2 @@
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};
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{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\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",
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 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,KAAKC,EAAQ,CACX,UAAWG,KAASH,EACdD,EAAQ,OACV,QAAQ,IAAI,WAAY,KAAK,UAAUI,EAAO,KAAM,CAAC,CAAC,EAEtD,QAAQ,IAAI,WAAYA,CAAK,CAGnC,CACF,CACF",
6
6
  "names": ["createFetchTransport", "endpoint", "options", "events", "error", "createConsoleTransport", "event"]
7
7
  }
@@ -19,6 +19,10 @@ export interface ErrorEvent {
19
19
  sessionId?: string;
20
20
  machineId?: string;
21
21
  machineState?: string;
22
+ machines?: Array<{
23
+ id: string;
24
+ state: string;
25
+ }>;
22
26
  }
23
27
  export interface UnhandledRejectionEvent {
24
28
  type: 'unhandled-rejection';
@@ -28,6 +32,10 @@ export interface UnhandledRejectionEvent {
28
32
  sessionId?: string;
29
33
  machineId?: string;
30
34
  machineState?: string;
35
+ machines?: Array<{
36
+ id: string;
37
+ state: string;
38
+ }>;
31
39
  }
32
40
  export type ObserveErrorEvent = ErrorEvent | UnhandledRejectionEvent;
33
41
  export interface VitalEvent {
@@ -55,7 +63,7 @@ export interface CustomMetricEvent {
55
63
  name: string;
56
64
  metricKind?: 'counter' | 'gauge' | 'histogram';
57
65
  value?: number;
58
- data: Record<string, unknown>;
66
+ metadata?: Record<string, unknown>;
59
67
  timestamp: number;
60
68
  sessionId?: string;
61
69
  }
@@ -109,8 +117,6 @@ export interface SamplingConfig {
109
117
  custom?: number;
110
118
  /** Sampling rate for state machine transition events (default: 1) */
111
119
  transitions?: number;
112
- /** Sampling rate for identify events (default: 1) */
113
- identify?: number;
114
120
  }
115
121
  /**
116
122
  * Sampling option - either a single rate for all events or per-type config
@@ -167,11 +173,8 @@ export interface ObserveOptions {
167
173
  * session: false
168
174
  */
169
175
  session?: SessionOption;
170
- /**
171
- * @deprecated Use `sampling` instead. Will be removed in v0.3.0.
172
- * Global sampling rate (0-1) - applies to entire observer
173
- */
174
- sampleRate?: number;
176
+ /** Callback for transport errors (e.g., failed sends) */
177
+ onError?: (error: Error) => void;
175
178
  /** Log to console */
176
179
  debug?: boolean;
177
180
  }
@@ -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.8",
3
+ "version": "0.1.9",
4
4
  "description": "Observability + State Machines for Svelte 5 — the goose that sees everything",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,28 +0,0 @@
1
- /**
2
- * after() - Delayed transitions (v0.2)
3
- *
4
- * Автоматичний перехід після затримки
5
- *
6
- * @example
7
- * const notification = createMachine({
8
- * initial: 'visible',
9
- * states: {
10
- * visible: {
11
- * after: {
12
- * 3000: 'hidden', // Перехід через 3 секунди
13
- * },
14
- * on: { DISMISS: 'hidden' },
15
- * },
16
- * hidden: {},
17
- * },
18
- * });
19
- */
20
- export interface AfterConfig {
21
- /** Delay in ms -> target state */
22
- [delay: number]: string | {
23
- target: string;
24
- guard?: (context: unknown) => boolean;
25
- action?: (context: unknown) => Partial<unknown> | void;
26
- };
27
- }
28
- //# sourceMappingURL=after.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"after.d.ts","sourceRoot":"","sources":["../../src/upgrade/after.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG;QACxB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;QACtC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;KACxD,CAAC;CACH"}
@@ -1,36 +0,0 @@
1
- /**
2
- * History states (v0.3)
3
- *
4
- * Запам'ятовує попередній стан для повернення
5
- *
6
- * @example
7
- * const player = createMachine({
8
- * initial: 'stopped',
9
- * states: {
10
- * stopped: {
11
- * on: { PLAY: 'playing' },
12
- * },
13
- * playing: {
14
- * on: {
15
- * PAUSE: 'paused',
16
- * STOP: 'stopped',
17
- * },
18
- * },
19
- * paused: {
20
- * on: {
21
- * // Повертається до попереднього стану (playing)
22
- * RESUME: { target: 'playing.history' },
23
- * STOP: 'stopped',
24
- * },
25
- * },
26
- * },
27
- * });
28
- */
29
- export type HistoryType = 'shallow' | 'deep';
30
- export interface HistoryStateConfig {
31
- type: 'history';
32
- history: HistoryType;
33
- /** Default state if no history */
34
- target?: string;
35
- }
36
- //# sourceMappingURL=history.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/upgrade/history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -1,25 +0,0 @@
1
- /**
2
- * 🪿 svoose/upgrade - Future features
3
- *
4
- * v0.2 - Async & Time:
5
- * - invoke() - async functions/promises
6
- * - spawn() - dynamic child machines
7
- * - after() - delayed transitions
8
- *
9
- * v0.3 - Advanced States:
10
- * - Parallel states
11
- * - History states
12
- * - Devtools
13
- *
14
- * v0.4 - Integration:
15
- * - @svoose/reactor - svelte-reactor integration
16
- * (persist, middleware, sync, etc.)
17
- * - @svoose/sveltekit - SvelteKit hooks
18
- */
19
- export declare const UPGRADE_VERSION = "0.2.0";
20
- export type { InvokeConfig } from './invoke.js';
21
- export type { SpawnOptions, SpawnedMachine } from './spawn.js';
22
- export type { AfterConfig } from './after.js';
23
- export type { ParallelStateConfig } from './parallel.js';
24
- export type { HistoryType, HistoryStateConfig } from './history.js';
25
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/upgrade/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,eAAe,UAAU,CAAC;AAGvC,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
@@ -1,39 +0,0 @@
1
- /**
2
- * invoke() - Async service invocation (v0.2)
3
- *
4
- * Дозволяє викликати async функції/promises з машини станів
5
- *
6
- * @example
7
- * const auth = createMachine({
8
- * states: {
9
- * loading: {
10
- * invoke: {
11
- * src: async (ctx) => await api.login(ctx.email),
12
- * onDone: { target: 'success', action: (ctx, e) => ({ user: e.data }) },
13
- * onError: { target: 'error', action: (ctx, e) => ({ error: e.message }) },
14
- * },
15
- * },
16
- * },
17
- * });
18
- */
19
- export interface InvokeConfig<TContext, TData, TError = Error> {
20
- /** Async function to invoke */
21
- src: (context: TContext) => Promise<TData>;
22
- /** Transition on success */
23
- onDone?: {
24
- target: string;
25
- action?: (context: TContext, event: {
26
- type: 'done';
27
- data: TData;
28
- }) => Partial<TContext> | void;
29
- };
30
- /** Transition on error */
31
- onError?: {
32
- target: string;
33
- action?: (context: TContext, event: {
34
- type: 'error';
35
- error: TError;
36
- }) => Partial<TContext> | void;
37
- };
38
- }
39
- //# sourceMappingURL=invoke.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/upgrade/invoke.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,MAAM,WAAW,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAC3D,+BAA+B;IAC/B,GAAG,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3C,4BAA4B;IAC5B,MAAM,CAAC,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,KAAK,CAAA;SAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;KAChG,CAAC;IACF,0BAA0B;IAC1B,OAAO,CAAC,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;YAAE,IAAI,EAAE,OAAO,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;KACnG,CAAC;CACH"}
@@ -1,36 +0,0 @@
1
- /**
2
- * Parallel states (v0.3)
3
- *
4
- * Дозволяє мати кілька активних станів одночасно
5
- *
6
- * @example
7
- * const editor = createMachine({
8
- * type: 'parallel',
9
- * states: {
10
- * text: {
11
- * initial: 'idle',
12
- * states: {
13
- * idle: { on: { EDIT: 'editing' } },
14
- * editing: { on: { SAVE: 'idle' } },
15
- * },
16
- * },
17
- * toolbar: {
18
- * initial: 'collapsed',
19
- * states: {
20
- * collapsed: { on: { EXPAND: 'expanded' } },
21
- * expanded: { on: { COLLAPSE: 'collapsed' } },
22
- * },
23
- * },
24
- * },
25
- * });
26
- *
27
- * // editor.state = { text: 'idle', toolbar: 'collapsed' }
28
- */
29
- export interface ParallelStateConfig {
30
- type: 'parallel';
31
- states: Record<string, {
32
- initial: string;
33
- states: Record<string, unknown>;
34
- }>;
35
- }
36
- //# sourceMappingURL=parallel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"parallel.d.ts","sourceRoot":"","sources":["../../src/upgrade/parallel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC,CAAC,CAAC;CACJ"}
@@ -1,35 +0,0 @@
1
- /**
2
- * spawn() - Dynamic child machines (v0.2)
3
- *
4
- * Дозволяє динамічно створювати child machines
5
- *
6
- * @example
7
- * const parent = createMachine({
8
- * context: { children: [] },
9
- * states: {
10
- * active: {
11
- * on: {
12
- * ADD_CHILD: {
13
- * action: (ctx) => ({
14
- * children: [...ctx.children, spawn(childMachine, { id: `child-${Date.now()}` })],
15
- * }),
16
- * },
17
- * },
18
- * },
19
- * },
20
- * });
21
- */
22
- export interface SpawnOptions {
23
- /** Unique ID for the spawned machine */
24
- id?: string;
25
- /** Sync with parent (auto-cleanup) */
26
- sync?: boolean;
27
- }
28
- export interface SpawnedMachine<TContext, TState, TEvent> {
29
- id: string;
30
- state: TState;
31
- context: TContext;
32
- send: (event: TEvent) => void;
33
- stop: () => void;
34
- }
35
- //# sourceMappingURL=spawn.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/upgrade/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,QAAQ,CAAC;IAClB,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB"}