@syntrologie/runtime-sdk 0.2.13 → 0.2.14

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.
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { decodeToken, encodeToken } from "./token";
14
14
  import { SmartCanvasConfig, SmartCanvasHandle } from "./api";
15
+ import { SessionMetricTracker } from "./metrics";
15
16
  import type { ExperimentClient } from "./experiments/types";
16
17
  import type { TelemetryClient } from "./telemetry/types";
17
18
  import type { CanvasConfigFetcher } from "./types";
@@ -35,6 +36,14 @@ export interface SyntroInitOptions {
35
36
  * The token's telemetry credentials (t field) are still used if present.
36
37
  */
37
38
  fetcher?: CanvasConfigFetcher;
39
+ /**
40
+ * Enable session-based metric tracking.
41
+ * When true, a SessionMetricTracker is created that tracks metrics during
42
+ * the user's session and updates GrowthBook attributes in real-time.
43
+ *
44
+ * @default false
45
+ */
46
+ enableSessionMetrics?: boolean;
38
47
  }
39
48
  export interface SyntroInitResult {
40
49
  /**
@@ -49,6 +58,11 @@ export interface SyntroInitResult {
49
58
  * The telemetry client, if telemetry is configured in the token.
50
59
  */
51
60
  telemetry?: TelemetryClient;
61
+ /**
62
+ * The session metric tracker, if enableSessionMetrics is true.
63
+ * Use this to track session-based metrics for real-time targeting.
64
+ */
65
+ sessionMetrics?: SessionMetricTracker;
52
66
  }
53
67
  /**
54
68
  * Initialize the Syntro SDK with a single token.
package/dist/bootstrap.js CHANGED
@@ -16,6 +16,7 @@ import { createTelemetryClient } from "./telemetry/registry";
16
16
  import { createConfigFetcher } from "./fetchers/registry";
17
17
  import { createCanvasConfigFetcher } from "./configFetcher";
18
18
  import { createSmartCanvas } from "./api";
19
+ import { createSessionMetricTracker } from "./metrics";
19
20
  /**
20
21
  * Get environment variable, supporting both Vite and Next.js patterns.
21
22
  */
@@ -54,6 +55,58 @@ function isEditorMode() {
54
55
  });
55
56
  return hasToken;
56
57
  }
58
+ // ============================================================================
59
+ // Segment Attribute Caching (localStorage)
60
+ // ============================================================================
61
+ const SEGMENT_CACHE_KEY = 'syntro_segment_attributes';
62
+ /**
63
+ * Load cached segment attributes from localStorage.
64
+ * Returns cached values for instant Phase 1 evaluation.
65
+ */
66
+ function loadCachedSegmentAttributes() {
67
+ if (typeof window === 'undefined')
68
+ return {};
69
+ try {
70
+ const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
71
+ if (cached) {
72
+ const attrs = JSON.parse(cached);
73
+ console.log('[Syntro Bootstrap] Loaded cached segment attributes:', attrs);
74
+ return attrs;
75
+ }
76
+ }
77
+ catch (err) {
78
+ console.warn('[Syntro Bootstrap] Failed to load cached segment attributes:', err);
79
+ }
80
+ return {};
81
+ }
82
+ /**
83
+ * Save segment attributes to localStorage for faster future loads.
84
+ */
85
+ function cacheSegmentAttributes(attrs) {
86
+ if (typeof window === 'undefined')
87
+ return;
88
+ try {
89
+ localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
90
+ console.log('[Syntro Bootstrap] Cached segment attributes:', attrs);
91
+ }
92
+ catch (err) {
93
+ console.warn('[Syntro Bootstrap] Failed to cache segment attributes:', err);
94
+ }
95
+ }
96
+ /**
97
+ * Extract segment flags (in_segment_*) from PostHog feature flags.
98
+ */
99
+ function extractSegmentFlags(allFlags) {
100
+ if (!allFlags)
101
+ return {};
102
+ const segmentFlags = {};
103
+ for (const [key, value] of Object.entries(allFlags)) {
104
+ if (key.startsWith('in_segment_')) {
105
+ segmentFlags[key] = value === true;
106
+ }
107
+ }
108
+ return segmentFlags;
109
+ }
57
110
  /**
58
111
  * Initialize the Syntro SDK with a single token.
59
112
  *
@@ -116,20 +169,55 @@ async function init(options) {
116
169
  const editorUrl = getEnvVar("NEXT_PUBLIC_SYNTRO_EDITOR_URL")
117
170
  || getEnvVar("VITE_SYNTRO_EDITOR_URL")
118
171
  || ((_b = options.canvas) === null || _b === void 0 ? void 0 : _b.editorUrl);
119
- // Initialize telemetry client FIRST (so experiments can wire tracking callback)
172
+ // ============================================================================
173
+ // PHASE 1: Load cached segment attributes for instant evaluation
174
+ // ============================================================================
175
+ const cachedSegmentAttrs = loadCachedSegmentAttributes();
176
+ console.log('[Syntro Bootstrap] Phase 1: Using cached segment attributes:', cachedSegmentAttrs);
177
+ // Will be set when experiments client is created
178
+ let experiments;
179
+ // Callback for when PostHog feature flags are loaded (Phase 2)
180
+ const onFeatureFlagsLoaded = (allFlags) => {
181
+ var _a, _b, _c;
182
+ console.log('[Syntro Bootstrap] Phase 2: PostHog feature flags loaded');
183
+ // Extract segment flags (in_segment_*)
184
+ const segmentFlags = extractSegmentFlags(allFlags);
185
+ console.log('[Syntro Bootstrap] Segment flags from PostHog:', segmentFlags);
186
+ // Cache for next page load
187
+ cacheSegmentAttributes(segmentFlags);
188
+ // Update GrowthBook with fresh segment attributes
189
+ if (experiments) {
190
+ // Get current session metrics if available
191
+ const sessionAttrs = (_b = (_a = sessionMetrics === null || sessionMetrics === void 0 ? void 0 : sessionMetrics.getAll) === null || _a === void 0 ? void 0 : _a.call(sessionMetrics)) !== null && _b !== void 0 ? _b : {};
192
+ // Merge session metrics + segment flags and update GrowthBook
193
+ const updatedAttrs = { ...sessionAttrs, ...segmentFlags };
194
+ console.log('[Syntro Bootstrap] Updating GrowthBook with attributes:', updatedAttrs);
195
+ (_c = experiments.setAttributes) === null || _c === void 0 ? void 0 : _c.call(experiments, updatedAttrs);
196
+ }
197
+ };
198
+ // Initialize telemetry client with feature flags callback
120
199
  let telemetry;
121
200
  if (payload === null || payload === void 0 ? void 0 : payload.t) {
122
201
  telemetry = createTelemetryClient("posthog", {
123
202
  apiKey: payload.t,
124
203
  apiHost: telemetryHost, // undefined falls back to adapter default
204
+ // Enable PostHog feature flags for segment membership
205
+ enableFeatureFlags: true,
206
+ // Wire up callback for when flags are loaded (Phase 2)
207
+ onFeatureFlagsLoaded,
125
208
  });
126
209
  }
127
- // Initialize experiment client with tracking callback wired to telemetry
128
- let experiments;
210
+ // ============================================================================
211
+ // Initialize experiment client with CACHED attributes (Phase 1)
212
+ // PostHog will update these when /decide returns (Phase 2)
213
+ // ============================================================================
214
+ let sessionMetrics;
129
215
  if (payload === null || payload === void 0 ? void 0 : payload.e) {
130
216
  experiments = createExperimentClient("growthbook", {
131
217
  clientKey: payload.e,
132
218
  apiHost: experimentHost, // undefined falls back to adapter default
219
+ // Phase 1: Use cached segment attributes for instant evaluation
220
+ attributes: cachedSegmentAttrs,
133
221
  // Wire experiment tracking to telemetry provider
134
222
  onExperimentViewed: (telemetry === null || telemetry === void 0 ? void 0 : telemetry.trackExperiment)
135
223
  ? (key, variationId, variationName) => {
@@ -161,6 +249,16 @@ async function init(options) {
161
249
  // Default: use experiments-based fetcher (GrowthBook config or URI)
162
250
  fetcher = createCanvasConfigFetcher({ experiments });
163
251
  }
252
+ // Create session metric tracker if enabled
253
+ if (options.enableSessionMetrics) {
254
+ sessionMetrics = createSessionMetricTracker({
255
+ experiments,
256
+ onMetricChange: (key, value) => {
257
+ console.log(`[Syntro Bootstrap] Session metric changed: ${key} = ${value}`);
258
+ },
259
+ });
260
+ console.log('[Syntro Bootstrap] SessionMetricTracker created');
261
+ }
164
262
  // Create canvas with integrations
165
263
  const canvas = await createSmartCanvas({
166
264
  ...options.canvas,
@@ -168,7 +266,7 @@ async function init(options) {
168
266
  integrations: { experiments, telemetry },
169
267
  editorUrl,
170
268
  });
171
- return { canvas, experiments, telemetry };
269
+ return { canvas, experiments, telemetry, sessionMetrics };
172
270
  }
173
271
  /**
174
272
  * The Syntro namespace for single-token initialization.
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,11 @@ import type { ExperimentClient } from "./types";
10
10
  export interface CreateExperimentClientConfig {
11
11
  clientKey: string;
12
12
  apiHost?: string;
13
+ /**
14
+ * Initial user attributes for targeting.
15
+ * Used for segment-based targeting.
16
+ */
17
+ attributes?: Record<string, unknown>;
13
18
  /**
14
19
  * Callback fired when a user is assigned to an experiment.
15
20
  * Use this to send experiment data to your analytics provider.
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/experiments/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,sBAAsB,GAGvB,MAAM,uBAAuB,CAAC;AAK/B,MAAM,QAAQ,GAAmC;IAC/C,UAAU,EAAE,CAAC,MAAgC,EAAE,EAAE,CAC/C,sBAAsB,CAAC;QACrB,GAAG,MAAM;QACT,QAAQ,EAAE,IAAI;KACf,CAAC;CACL,CAAC;AAYF;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,MAAoC;IAEpC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,gBAAgB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/experiments/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,sBAAsB,GAGvB,MAAM,uBAAuB,CAAC;AAK/B,MAAM,QAAQ,GAAmC;IAC/C,UAAU,EAAE,CAAC,MAAgC,EAAE,EAAE,CAC/C,sBAAsB,CAAC;QACrB,GAAG,MAAM;QACT,QAAQ,EAAE,IAAI;KACf,CAAC;CACL,CAAC;AAiBF;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,MAAoC;IAEpC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,gBAAgB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export * from "./configFetcher";
14
14
  export * from "./overlays/types";
15
15
  export * from "./overlays/schema";
16
16
  export * from "./overlays/fetcher";
17
+ export * from "./metrics";
17
18
  export { Syntro } from "./bootstrap";
18
19
  export type { SyntroInitOptions, SyntroInitResult } from "./bootstrap";
19
20
  export { encodeToken, decodeToken } from "./token";
package/dist/index.js CHANGED
@@ -14,6 +14,8 @@ export * from "./configFetcher";
14
14
  export * from "./overlays/types";
15
15
  export * from "./overlays/schema";
16
16
  export * from "./overlays/fetcher";
17
+ // Metrics for session-based targeting
18
+ export * from "./metrics";
17
19
  // Single-token initialization
18
20
  export { Syntro } from "./bootstrap";
19
21
  export { encodeToken, decodeToken } from "./token";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AAEnC,8BAA8B;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AAEnC,sCAAsC;AACtC,cAAc,WAAW,CAAC;AAE1B,8BAA8B;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Metrics module for session-based real-time targeting.
3
+ */
4
+ export { SessionMetricTracker, createSessionMetricTracker, type SessionMetricTrackerOptions, } from "./sessionMetrics";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Metrics module for session-based real-time targeting.
3
+ */
4
+ export { SessionMetricTracker, createSessionMetricTracker, } from "./sessionMetrics";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,oBAAoB,EACpB,0BAA0B,GAE3B,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * SessionMetricTracker - Real-time session-based metrics for segment targeting.
3
+ *
4
+ * This module tracks metrics during a user's session and updates GrowthBook
5
+ * attributes in real-time, enabling instant segment targeting without waiting
6
+ * for batch PostHog cohort computation.
7
+ *
8
+ * Use cases:
9
+ * - "Show action plan after 3+ button clicks in this session"
10
+ * - "Target users who viewed 5+ products this session"
11
+ * - "Trigger intervention when user hovers a CTA 2+ times"
12
+ */
13
+ import type { ExperimentClient } from "../experiments/types";
14
+ /**
15
+ * Options for creating a SessionMetricTracker.
16
+ */
17
+ export interface SessionMetricTrackerOptions {
18
+ /**
19
+ * The experiment client to update attributes on.
20
+ * When a metric changes, the session_${metricKey} attribute is updated.
21
+ */
22
+ experiments?: ExperimentClient;
23
+ /**
24
+ * Prefix for attribute keys sent to GrowthBook.
25
+ * @default "session_"
26
+ */
27
+ attributePrefix?: string;
28
+ /**
29
+ * Callback fired when any metric value changes.
30
+ * Useful for debugging or custom integrations.
31
+ */
32
+ onMetricChange?: (key: string, newValue: number) => void;
33
+ }
34
+ /**
35
+ * Tracks session-based metrics for real-time segment targeting.
36
+ */
37
+ export declare class SessionMetricTracker {
38
+ private metrics;
39
+ private experiments?;
40
+ private attributePrefix;
41
+ private onMetricChange?;
42
+ constructor(options?: SessionMetricTrackerOptions);
43
+ /**
44
+ * Increment a metric by the specified amount.
45
+ *
46
+ * @param metricKey - The metric to increment (e.g., "button_clicks", "page_views")
47
+ * @param amount - Amount to increment by (default: 1)
48
+ * @returns The new metric value
49
+ */
50
+ increment(metricKey: string, amount?: number): number;
51
+ /**
52
+ * Set a metric to a specific value.
53
+ *
54
+ * @param metricKey - The metric to set
55
+ * @param value - The value to set
56
+ */
57
+ set(metricKey: string, value: number): void;
58
+ /**
59
+ * Get the current value of a metric.
60
+ *
61
+ * @param metricKey - The metric to get
62
+ * @returns The current value (0 if not set)
63
+ */
64
+ get(metricKey: string): number;
65
+ /**
66
+ * Check if a metric meets or exceeds a threshold.
67
+ *
68
+ * @param metricKey - The metric to check
69
+ * @param threshold - The threshold value
70
+ * @returns True if metric >= threshold
71
+ */
72
+ meetsThreshold(metricKey: string, threshold: number): boolean;
73
+ /**
74
+ * Get all current metric values.
75
+ *
76
+ * @returns Record of metric keys to values
77
+ */
78
+ getAll(): Record<string, number>;
79
+ /**
80
+ * Reset a specific metric to zero.
81
+ *
82
+ * @param metricKey - The metric to reset
83
+ */
84
+ reset(metricKey: string): void;
85
+ /**
86
+ * Reset all metrics (clear the session).
87
+ */
88
+ resetAll(): void;
89
+ /**
90
+ * Update the experiment client (useful if experiments client changes).
91
+ */
92
+ setExperiments(experiments: ExperimentClient): void;
93
+ private updateExperimentAttributes;
94
+ private syncAllToExperiments;
95
+ private loadFromStorage;
96
+ private saveToStorage;
97
+ }
98
+ /**
99
+ * Create a SessionMetricTracker instance.
100
+ */
101
+ export declare function createSessionMetricTracker(options?: SessionMetricTrackerOptions): SessionMetricTracker;
@@ -0,0 +1,178 @@
1
+ /**
2
+ * SessionMetricTracker - Real-time session-based metrics for segment targeting.
3
+ *
4
+ * This module tracks metrics during a user's session and updates GrowthBook
5
+ * attributes in real-time, enabling instant segment targeting without waiting
6
+ * for batch PostHog cohort computation.
7
+ *
8
+ * Use cases:
9
+ * - "Show action plan after 3+ button clicks in this session"
10
+ * - "Target users who viewed 5+ products this session"
11
+ * - "Trigger intervention when user hovers a CTA 2+ times"
12
+ */
13
+ const STORAGE_KEY = "syntro_session_metrics";
14
+ /**
15
+ * Tracks session-based metrics for real-time segment targeting.
16
+ */
17
+ export class SessionMetricTracker {
18
+ constructor(options = {}) {
19
+ var _a;
20
+ this.metrics = new Map();
21
+ this.experiments = options.experiments;
22
+ this.attributePrefix = (_a = options.attributePrefix) !== null && _a !== void 0 ? _a : "session_";
23
+ this.onMetricChange = options.onMetricChange;
24
+ // Restore metrics from sessionStorage
25
+ this.loadFromStorage();
26
+ }
27
+ /**
28
+ * Increment a metric by the specified amount.
29
+ *
30
+ * @param metricKey - The metric to increment (e.g., "button_clicks", "page_views")
31
+ * @param amount - Amount to increment by (default: 1)
32
+ * @returns The new metric value
33
+ */
34
+ increment(metricKey, amount = 1) {
35
+ var _a, _b;
36
+ const currentValue = (_a = this.metrics.get(metricKey)) !== null && _a !== void 0 ? _a : 0;
37
+ const newValue = currentValue + amount;
38
+ this.metrics.set(metricKey, newValue);
39
+ this.saveToStorage();
40
+ // Update GrowthBook attributes for real-time targeting
41
+ this.updateExperimentAttributes(metricKey, newValue);
42
+ // Fire callback if configured
43
+ (_b = this.onMetricChange) === null || _b === void 0 ? void 0 : _b.call(this, metricKey, newValue);
44
+ return newValue;
45
+ }
46
+ /**
47
+ * Set a metric to a specific value.
48
+ *
49
+ * @param metricKey - The metric to set
50
+ * @param value - The value to set
51
+ */
52
+ set(metricKey, value) {
53
+ var _a;
54
+ this.metrics.set(metricKey, value);
55
+ this.saveToStorage();
56
+ this.updateExperimentAttributes(metricKey, value);
57
+ (_a = this.onMetricChange) === null || _a === void 0 ? void 0 : _a.call(this, metricKey, value);
58
+ }
59
+ /**
60
+ * Get the current value of a metric.
61
+ *
62
+ * @param metricKey - The metric to get
63
+ * @returns The current value (0 if not set)
64
+ */
65
+ get(metricKey) {
66
+ var _a;
67
+ return (_a = this.metrics.get(metricKey)) !== null && _a !== void 0 ? _a : 0;
68
+ }
69
+ /**
70
+ * Check if a metric meets or exceeds a threshold.
71
+ *
72
+ * @param metricKey - The metric to check
73
+ * @param threshold - The threshold value
74
+ * @returns True if metric >= threshold
75
+ */
76
+ meetsThreshold(metricKey, threshold) {
77
+ return this.get(metricKey) >= threshold;
78
+ }
79
+ /**
80
+ * Get all current metric values.
81
+ *
82
+ * @returns Record of metric keys to values
83
+ */
84
+ getAll() {
85
+ return Object.fromEntries(this.metrics);
86
+ }
87
+ /**
88
+ * Reset a specific metric to zero.
89
+ *
90
+ * @param metricKey - The metric to reset
91
+ */
92
+ reset(metricKey) {
93
+ var _a;
94
+ this.metrics.delete(metricKey);
95
+ this.saveToStorage();
96
+ this.updateExperimentAttributes(metricKey, 0);
97
+ (_a = this.onMetricChange) === null || _a === void 0 ? void 0 : _a.call(this, metricKey, 0);
98
+ }
99
+ /**
100
+ * Reset all metrics (clear the session).
101
+ */
102
+ resetAll() {
103
+ var _a, _b, _c;
104
+ const keys = Array.from(this.metrics.keys());
105
+ this.metrics.clear();
106
+ this.saveToStorage();
107
+ // Update all attributes to 0
108
+ const attrs = {};
109
+ for (const key of keys) {
110
+ attrs[`${this.attributePrefix}${key}`] = 0;
111
+ (_a = this.onMetricChange) === null || _a === void 0 ? void 0 : _a.call(this, key, 0);
112
+ }
113
+ (_c = (_b = this.experiments) === null || _b === void 0 ? void 0 : _b.setAttributes) === null || _c === void 0 ? void 0 : _c.call(_b, attrs);
114
+ }
115
+ /**
116
+ * Update the experiment client (useful if experiments client changes).
117
+ */
118
+ setExperiments(experiments) {
119
+ this.experiments = experiments;
120
+ // Sync all current metrics to the new experiment client
121
+ this.syncAllToExperiments();
122
+ }
123
+ // ==================== Private Methods ====================
124
+ updateExperimentAttributes(metricKey, value) {
125
+ var _a;
126
+ if (!((_a = this.experiments) === null || _a === void 0 ? void 0 : _a.setAttributes))
127
+ return;
128
+ const attributeKey = `${this.attributePrefix}${metricKey}`;
129
+ this.experiments.setAttributes({ [attributeKey]: value });
130
+ }
131
+ syncAllToExperiments() {
132
+ var _a;
133
+ if (!((_a = this.experiments) === null || _a === void 0 ? void 0 : _a.setAttributes))
134
+ return;
135
+ const attrs = {};
136
+ for (const [key, value] of this.metrics) {
137
+ attrs[`${this.attributePrefix}${key}`] = value;
138
+ }
139
+ this.experiments.setAttributes(attrs);
140
+ }
141
+ loadFromStorage() {
142
+ if (typeof window === "undefined" || typeof sessionStorage === "undefined")
143
+ return;
144
+ try {
145
+ const stored = sessionStorage.getItem(STORAGE_KEY);
146
+ if (stored) {
147
+ const data = JSON.parse(stored);
148
+ for (const [key, value] of Object.entries(data)) {
149
+ this.metrics.set(key, value.count);
150
+ }
151
+ }
152
+ }
153
+ catch (err) {
154
+ console.warn("[SessionMetricTracker] Failed to load from sessionStorage:", err);
155
+ }
156
+ }
157
+ saveToStorage() {
158
+ if (typeof window === "undefined" || typeof sessionStorage === "undefined")
159
+ return;
160
+ try {
161
+ const data = {};
162
+ for (const [key, count] of this.metrics) {
163
+ data[key] = { count, lastUpdated: Date.now() };
164
+ }
165
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
166
+ }
167
+ catch (err) {
168
+ console.warn("[SessionMetricTracker] Failed to save to sessionStorage:", err);
169
+ }
170
+ }
171
+ }
172
+ /**
173
+ * Create a SessionMetricTracker instance.
174
+ */
175
+ export function createSessionMetricTracker(options = {}) {
176
+ return new SessionMetricTracker(options);
177
+ }
178
+ //# sourceMappingURL=sessionMetrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionMetrics.js","sourceRoot":"","sources":["../../src/metrics/sessionMetrics.ts"],"names":[],"mappings":"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"}
@@ -7,4 +7,6 @@ export declare function showHighlight(anchorEl: HTMLElement, overlayRoot: HTMLEl
7
7
  scrimOpacity?: number;
8
8
  ringColor?: string;
9
9
  blocking?: boolean;
10
+ onClickOutside?: boolean;
11
+ onEsc?: boolean;
10
12
  }): HighlightHandle;
@@ -1,22 +1,26 @@
1
1
  var _a;
2
2
  const supportsPathClip = typeof CSS !== "undefined" && ((_a = CSS.supports) === null || _a === void 0 ? void 0 : _a.call(CSS, "clip-path", "path('M0 0 H1 V1 Z')"));
3
3
  export function showHighlight(anchorEl, overlayRoot, opts) {
4
- var _a, _b, _c, _d, _e;
4
+ var _a, _b, _c, _d, _e, _f, _g;
5
5
  const padding = (_a = opts === null || opts === void 0 ? void 0 : opts.paddingPx) !== null && _a !== void 0 ? _a : 12;
6
6
  const radius = (_b = opts === null || opts === void 0 ? void 0 : opts.radiusPx) !== null && _b !== void 0 ? _b : 12;
7
7
  const opacity = Math.min(Math.max((_c = opts === null || opts === void 0 ? void 0 : opts.scrimOpacity) !== null && _c !== void 0 ? _c : 0.55, 0), 1);
8
8
  const ringColor = (_d = opts === null || opts === void 0 ? void 0 : opts.ringColor) !== null && _d !== void 0 ? _d : "var(--syntro-ring, #5b8cff)";
9
9
  const blocking = (_e = opts === null || opts === void 0 ? void 0 : opts.blocking) !== null && _e !== void 0 ? _e : false;
10
+ const onClickOutside = (_f = opts === null || opts === void 0 ? void 0 : opts.onClickOutside) !== null && _f !== void 0 ? _f : true; // Default to true for backwards compat
11
+ const onEsc = (_g = opts === null || opts === void 0 ? void 0 : opts.onEsc) !== null && _g !== void 0 ? _g : true; // Default to true for backwards compat
10
12
  const rootStyles = getComputedStyle(document.documentElement);
11
13
  const tokenScrim = rootStyles.getPropertyValue("--syntro-spotlight-backdrop").trim();
12
14
  const tokenRing = rootStyles.getPropertyValue("--syntro-ring").trim();
13
15
  const scrim = document.createElement("div");
14
16
  scrim.className = "syntro-spotlight-scrim";
17
+ // Enable pointer events if blocking OR if we want to dismiss on click outside
18
+ const needsPointerEvents = blocking || onClickOutside;
15
19
  Object.assign(scrim.style, {
16
20
  position: "fixed",
17
21
  inset: "0",
18
22
  zIndex: "2147483646",
19
- pointerEvents: blocking ? "auto" : "none",
23
+ pointerEvents: needsPointerEvents ? "auto" : "none",
20
24
  background: tokenScrim || `rgba(2, 6, 23, ${opacity})`,
21
25
  transition: "opacity 220ms ease",
22
26
  opacity: "0",
@@ -118,18 +122,20 @@ export function showHighlight(anchorEl, overlayRoot, opts) {
118
122
  window.addEventListener("scroll", onScroll, true);
119
123
  window.addEventListener("resize", onResize);
120
124
  const onKey = (e) => {
121
- if (e.key === "Escape")
125
+ if (e.key === "Escape" && onEsc)
122
126
  handle.destroy();
123
127
  };
124
- window.addEventListener("keydown", onKey);
128
+ if (onEsc) {
129
+ window.addEventListener("keydown", onKey);
130
+ }
125
131
  const onClick = (event) => {
126
- if (!blocking) {
127
- handle.destroy();
128
- }
129
- else {
132
+ if (blocking) {
130
133
  event.preventDefault();
131
134
  event.stopPropagation();
132
135
  }
136
+ else if (onClickOutside) {
137
+ handle.destroy();
138
+ }
133
139
  };
134
140
  scrim.addEventListener("click", onClick);
135
141
  const handle = {
@@ -137,7 +143,9 @@ export function showHighlight(anchorEl, overlayRoot, opts) {
137
143
  ro.disconnect();
138
144
  window.removeEventListener("scroll", onScroll, true);
139
145
  window.removeEventListener("resize", onResize);
140
- window.removeEventListener("keydown", onKey);
146
+ if (onEsc) {
147
+ window.removeEventListener("keydown", onKey);
148
+ }
141
149
  scrim.removeEventListener("click", onClick);
142
150
  scrim.style.opacity = "0";
143
151
  setTimeout(() => {