@syntrologie/runtime-sdk 2.6.0-canary.1 → 2.6.0-canary.3

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.
@@ -46,11 +46,7 @@ export interface SyntroInitOptions {
46
46
  */
47
47
  fetcher?: CanvasConfigFetcher;
48
48
  /**
49
- * Enable session-based metric tracking.
50
- * When true, a SessionMetricTracker is created that tracks metrics during
51
- * the user's session and updates GrowthBook attributes in real-time.
52
- *
53
- * @default false
49
+ * @deprecated Session metrics are always enabled. This flag has no effect.
54
50
  */
55
51
  enableSessionMetrics?: boolean;
56
52
  /**
@@ -97,6 +93,12 @@ export interface SyntroInitResult {
97
93
  */
98
94
  appLoader: AppLoader;
99
95
  }
96
+ /**
97
+ * Collect browser metadata for instant GrowthBook targeting.
98
+ * This data is available synchronously from browser APIs — no network call needed.
99
+ * Only non-empty values are included.
100
+ */
101
+ export declare function collectBrowserMetadata(): Record<string, string | string[]>;
100
102
  /**
101
103
  * Initialize the Syntro SDK with a single token.
102
104
  *
@@ -3358,7 +3358,7 @@ function getAntiFlickerSnippet(config = {}) {
3358
3358
  }
3359
3359
 
3360
3360
  // src/version.ts
3361
- var SDK_VERSION = "2.6.0-canary.1";
3361
+ var SDK_VERSION = "2.6.0-canary.3";
3362
3362
 
3363
3363
  // src/types.ts
3364
3364
  var SDK_SCHEMA_VERSION = "2.0";
@@ -8578,7 +8578,7 @@ function matchPattern(pathname, pattern) {
8578
8578
  return regex.test(normalizedPath);
8579
8579
  }
8580
8580
  var ContextManager = class {
8581
- constructor(options = {}) {
8581
+ constructor(options) {
8582
8582
  __publicField(this, "context");
8583
8583
  __publicField(this, "previousContext");
8584
8584
  __publicField(this, "listeners", /* @__PURE__ */ new Set());
@@ -8671,30 +8671,8 @@ var ContextManager = class {
8671
8671
  };
8672
8672
  window.addEventListener("resize", handleResize);
8673
8673
  this.cleanupFns.push(() => window.removeEventListener("resize", handleResize));
8674
- if (this.navigation) {
8675
- const unsub = this.navigation.subscribe(() => this.updatePage());
8676
- this.cleanupFns.push(unsub);
8677
- } else {
8678
- const handlePopState = () => {
8679
- this.updatePage();
8680
- };
8681
- window.addEventListener("popstate", handlePopState);
8682
- this.cleanupFns.push(() => window.removeEventListener("popstate", handlePopState));
8683
- const originalPushState = history.pushState.bind(history);
8684
- const originalReplaceState = history.replaceState.bind(history);
8685
- history.pushState = (...args) => {
8686
- originalPushState(...args);
8687
- queueMicrotask(() => this.updatePage());
8688
- };
8689
- history.replaceState = (...args) => {
8690
- originalReplaceState(...args);
8691
- queueMicrotask(() => this.updatePage());
8692
- };
8693
- this.cleanupFns.push(() => {
8694
- history.pushState = originalPushState;
8695
- history.replaceState = originalReplaceState;
8696
- });
8697
- }
8674
+ const unsub = this.navigation.subscribe(() => this.updatePage());
8675
+ this.cleanupFns.push(unsub);
8698
8676
  }
8699
8677
  updateViewport() {
8700
8678
  const newViewport = {
@@ -8750,7 +8728,7 @@ var ContextManager = class {
8750
8728
  }
8751
8729
  }
8752
8730
  };
8753
- function createContextManager(options = {}) {
8731
+ function createContextManager(options) {
8754
8732
  return new ContextManager(options);
8755
8733
  }
8756
8734
 
@@ -8789,8 +8767,9 @@ function evaluateCondition(condition, evalContext) {
8789
8767
  return events.hasRecentEvent(condition.eventName, withinMs);
8790
8768
  }
8791
8769
  case "state_equals": {
8792
- if (!state) return false;
8793
- return false;
8770
+ if (!(state == null ? void 0 : state.getValue)) return false;
8771
+ const actual = state.getValue(condition.key);
8772
+ return actual === condition.value;
8794
8773
  }
8795
8774
  case "viewport": {
8796
8775
  const { width, height } = context.viewport;
@@ -8931,6 +8910,10 @@ function createEvaluationContext(context, options) {
8931
8910
  getSessionMetric: (key) => {
8932
8911
  var _a2;
8933
8912
  return (_a2 = sessionMetrics == null ? void 0 : sessionMetrics.get(key)) != null ? _a2 : 0;
8913
+ },
8914
+ getValue: (key) => {
8915
+ var _a2;
8916
+ return (_a2 = state.session.get(key)) != null ? _a2 : state.user.get(key);
8934
8917
  }
8935
8918
  } : void 0,
8936
8919
  events: events ? {
@@ -10507,6 +10490,22 @@ function createSmartCanvasRuntime(options = {}) {
10507
10490
  accumulator
10508
10491
  }
10509
10492
  });
10493
+ let unsubPageViews;
10494
+ if (sessionMetrics) {
10495
+ sessionMetrics.increment("page_views");
10496
+ let lastCountedPath = typeof window !== "undefined" ? window.location.pathname : "/";
10497
+ unsubPageViews = navigation.subscribe((url, method) => {
10498
+ if (method === "replaceState") return;
10499
+ try {
10500
+ const newPath = new URL(url).pathname;
10501
+ if (newPath !== lastCountedPath) {
10502
+ lastCountedPath = newPath;
10503
+ sessionMetrics.increment("page_views");
10504
+ }
10505
+ } catch {
10506
+ }
10507
+ });
10508
+ }
10510
10509
  const runtime3 = {
10511
10510
  telemetry,
10512
10511
  context,
@@ -10566,6 +10565,7 @@ function createSmartCanvasRuntime(options = {}) {
10566
10565
  apps.unbind().catch((err) => {
10567
10566
  console.error("[Runtime] Error unbinding apps registry:", err);
10568
10567
  });
10568
+ unsubPageViews == null ? void 0 : unsubPageViews();
10569
10569
  anchorResolverService.destroy();
10570
10570
  accumulator.destroy();
10571
10571
  navigation.destroy();
@@ -10926,6 +10926,45 @@ function extractSegmentFlags(allFlags) {
10926
10926
  }
10927
10927
  return segmentFlags;
10928
10928
  }
10929
+ function collectBrowserMetadata() {
10930
+ var _a2;
10931
+ if (typeof window === "undefined") return {};
10932
+ const attrs = {};
10933
+ try {
10934
+ const params = new URLSearchParams(window.location.search);
10935
+ for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
10936
+ const val = params.get(key);
10937
+ if (val) attrs[key] = val;
10938
+ }
10939
+ } catch {
10940
+ }
10941
+ try {
10942
+ if (navigator.language) attrs.browser_language = navigator.language;
10943
+ if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
10944
+ } catch {
10945
+ }
10946
+ try {
10947
+ const w = window.innerWidth;
10948
+ attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
10949
+ } catch {
10950
+ }
10951
+ try {
10952
+ if (document.referrer) {
10953
+ attrs.referrer = document.referrer;
10954
+ try {
10955
+ attrs.referrer_hostname = new URL(document.referrer).hostname;
10956
+ } catch {
10957
+ }
10958
+ }
10959
+ } catch {
10960
+ }
10961
+ try {
10962
+ attrs.page_url = window.location.href;
10963
+ attrs.page_path = window.location.pathname;
10964
+ } catch {
10965
+ }
10966
+ return attrs;
10967
+ }
10929
10968
  async function init(options) {
10930
10969
  var _a2, _b, _c, _d, _e, _f;
10931
10970
  initLogger();
@@ -10998,7 +11037,10 @@ async function init(options) {
10998
11037
  const telemetryHost = getEnvVar("NEXT_PUBLIC_SYNTRO_TELEMETRY_HOST") || getEnvVar("VITE_SYNTRO_TELEMETRY_HOST") || (payload == null ? void 0 : payload.th);
10999
11038
  const editorUrl = getEnvVar("NEXT_PUBLIC_SYNTRO_EDITOR_URL") || getEnvVar("VITE_SYNTRO_EDITOR_URL") || ((_b = options.canvas) == null ? void 0 : _b.editorUrl);
11000
11039
  const cachedSegmentAttrs = loadCachedSegmentAttributes();
11001
- debug("Syntro Bootstrap", "Phase 1: Using cached segment attributes:", cachedSegmentAttrs);
11040
+ const browserMetadata = collectBrowserMetadata();
11041
+ const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs };
11042
+ debug("Syntro Bootstrap", "Phase 1: Browser metadata:", browserMetadata);
11043
+ debug("Syntro Bootstrap", "Phase 1: Cached segment attributes:", cachedSegmentAttrs);
11002
11044
  let experiments;
11003
11045
  const events = createEventBus();
11004
11046
  console.log("[Syntro Bootstrap] EventBus created");
@@ -11013,7 +11055,7 @@ async function init(options) {
11013
11055
  cacheSegmentAttributes(segmentFlags);
11014
11056
  if (experiments) {
11015
11057
  const sessionAttrs = (_b2 = (_a3 = sessionMetrics == null ? void 0 : sessionMetrics.getAll) == null ? void 0 : _a3.call(sessionMetrics)) != null ? _b2 : {};
11016
- const updatedAttrs = { ...sessionAttrs, ...segmentFlags };
11058
+ const updatedAttrs = { ...browserMetadata, ...sessionAttrs, ...segmentFlags };
11017
11059
  debug("Syntro Bootstrap", "Updating GrowthBook with attributes:", updatedAttrs);
11018
11060
  (_c2 = experiments.setAttributes) == null ? void 0 : _c2.call(experiments, updatedAttrs);
11019
11061
  }
@@ -11040,23 +11082,21 @@ async function init(options) {
11040
11082
  clientKey: payload.e,
11041
11083
  apiHost: experimentHost,
11042
11084
  // undefined falls back to adapter default
11043
- // Phase 1: Use cached segment attributes for instant evaluation
11044
- attributes: cachedSegmentAttrs,
11085
+ // Phase 1: Use browser metadata + cached segment attributes for instant evaluation
11086
+ attributes: phaseOneAttrs,
11045
11087
  // Wire experiment tracking to telemetry provider
11046
11088
  onExperimentViewed: (telemetry == null ? void 0 : telemetry.trackExperiment) ? (key, variationId, variationName) => {
11047
11089
  telemetry.trackExperiment(key, variationId, variationName);
11048
11090
  } : void 0
11049
11091
  });
11050
11092
  }
11051
- if (options.enableSessionMetrics) {
11052
- sessionMetrics = createSessionMetricTracker({
11053
- experiments,
11054
- onMetricChange: (key, value) => {
11055
- debug("Syntro Bootstrap", `Session metric changed: ${key} = ${value}`);
11056
- }
11057
- });
11058
- debug("Syntro Bootstrap", "SessionMetricTracker created");
11059
- }
11093
+ sessionMetrics = createSessionMetricTracker({
11094
+ experiments,
11095
+ onMetricChange: (key, value) => {
11096
+ debug("Syntro Bootstrap", `Session metric changed: ${key} = ${value}`);
11097
+ }
11098
+ });
11099
+ debug("Syntro Bootstrap", "SessionMetricTracker created");
11060
11100
  let runtimeMode = "production";
11061
11101
  if (editorMode) runtimeMode = "editor";
11062
11102
  else if (auditMode) runtimeMode = "audit";
@@ -11328,4 +11368,4 @@ export {
11328
11368
  encodeToken,
11329
11369
  Syntro
11330
11370
  };
11331
- //# sourceMappingURL=chunk-Q4WGXNKC.js.map
11371
+ //# sourceMappingURL=chunk-AUDHAZ3R.js.map