@syntrologie/runtime-sdk 2.8.0-canary.207 → 2.8.0-canary.209

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.
@@ -8,9 +8,16 @@
8
8
  * via the __VITE_IMPORT_META_ENV__ define.
9
9
  */
10
10
  export declare function getEnvVar(name: string): string | undefined;
11
+ export declare function loadCached<T>(key: string, ttlMs?: number): T | null;
12
+ export declare function writeCached(key: string, data: unknown): void;
11
13
  /**
12
14
  * Load cached segment attributes from localStorage.
13
15
  * Returns cached values for instant Phase 1 evaluation.
16
+ *
17
+ * Data is stored in the generic { ts, data } envelope. Legacy entries written
18
+ * without the envelope (bare JSON objects) will fail to parse as an envelope
19
+ * and return null — `loadCachedSegmentAttributes` returns {} in that case.
20
+ * The next /decide call repopulates the cache in the new format automatically.
14
21
  */
15
22
  export declare function loadCachedSegmentAttributes(): Record<string, boolean>;
16
23
  /**
@@ -27,9 +34,14 @@ export declare function extractSegmentFlags(allFlags: Record<string, boolean | s
27
34
  * Only non-empty values are included.
28
35
  */
29
36
  export declare function collectBrowserMetadata(): Record<string, string | string[]>;
37
+ type InitialAttrs = Record<string, string>;
38
+ export declare function computeInitialAttrs(fresh: Record<string, string | string[]>, cached: InitialAttrs | null): InitialAttrs;
39
+ export declare function loadInitialAttrs(): InitialAttrs | null;
40
+ export declare function saveInitialAttrs(attrs: InitialAttrs): void;
30
41
  export declare const GEO_DEFAULT_HOST = "https://geo.syntrologie.com";
31
42
  /**
32
43
  * Fetch geo data from the Cloudflare Worker, with localStorage caching.
33
44
  * Returns cached data immediately on subsequent visits. Best-effort — never blocks init.
34
45
  */
35
46
  export declare function fetchGeo(geoHost: string): Promise<Record<string, string>>;
47
+ export {};
@@ -21,7 +21,7 @@ import type { AppLoader, AppLoadResult } from './apps/AppLoader';
21
21
  import type { SmartCanvasRuntime } from './runtime';
22
22
  import type { InterventionTracker } from './telemetry/InterventionTracker';
23
23
  import { decodeToken, encodeToken } from './token';
24
- export { collectBrowserMetadata, fetchGeo } from './bootstrap-init';
24
+ export { collectBrowserMetadata, computeInitialAttrs, fetchGeo, loadCached, writeCached, } from './bootstrap-init';
25
25
  export type { SyntroInitOptions, SyntroInitResult } from './bootstrap-types';
26
26
  /**
27
27
  * Initialize the Syntro SDK with a single token.
package/dist/index.js CHANGED
@@ -9935,7 +9935,7 @@ function bindWebVitals(reporter, options) {
9935
9935
  }
9936
9936
 
9937
9937
  // src/version.ts
9938
- var SDK_VERSION = "2.8.0-canary.207";
9938
+ var SDK_VERSION = "2.8.0-canary.209";
9939
9939
 
9940
9940
  // src/types.ts
9941
9941
  var SDK_SCHEMA_VERSION = "2.0";
@@ -14120,30 +14120,40 @@ function getEnvVar(name) {
14120
14120
  }
14121
14121
  return void 0;
14122
14122
  }
14123
- var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
14124
- function loadCachedSegmentAttributes() {
14125
- if (typeof window === "undefined") return {};
14123
+ function loadCached(key, ttlMs) {
14124
+ if (typeof window === "undefined") return null;
14126
14125
  try {
14127
- const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
14128
- if (cached) {
14129
- const attrs = JSON.parse(cached);
14130
- debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
14131
- return attrs;
14132
- }
14133
- } catch (err) {
14134
- warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
14126
+ const raw = localStorage.getItem(key);
14127
+ if (!raw) return null;
14128
+ const envelope = JSON.parse(raw);
14129
+ if (!envelope || typeof envelope.ts !== "number" || !("data" in envelope)) return null;
14130
+ if (ttlMs != null && Date.now() - envelope.ts > ttlMs) return null;
14131
+ return envelope.data;
14132
+ } catch {
14133
+ return null;
14135
14134
  }
14136
- return {};
14137
14135
  }
14138
- function cacheSegmentAttributes(attrs) {
14136
+ function writeCached(key, data) {
14139
14137
  if (typeof window === "undefined") return;
14140
14138
  try {
14141
- localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
14142
- debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
14143
- } catch (err) {
14144
- warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
14139
+ const envelope = { ts: Date.now(), data };
14140
+ localStorage.setItem(key, JSON.stringify(envelope));
14141
+ } catch {
14145
14142
  }
14146
14143
  }
14144
+ var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
14145
+ function loadCachedSegmentAttributes() {
14146
+ const cached = loadCached(SEGMENT_CACHE_KEY);
14147
+ if (cached) {
14148
+ debug("Syntro Bootstrap", "Loaded cached segment attributes:", cached);
14149
+ return cached;
14150
+ }
14151
+ return {};
14152
+ }
14153
+ function cacheSegmentAttributes(attrs) {
14154
+ writeCached(SEGMENT_CACHE_KEY, attrs);
14155
+ debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
14156
+ }
14147
14157
  function extractSegmentFlags(allFlags) {
14148
14158
  if (!allFlags) return {};
14149
14159
  const segmentFlags = {};
@@ -14234,6 +14244,51 @@ function collectBrowserMetadata() {
14234
14244
  }
14235
14245
  return attrs;
14236
14246
  }
14247
+ var INITIAL_ATTRS_KEY = "syntro_initial_attrs";
14248
+ var INITIAL_ATTRS_TTL = 30 * 60 * 1e3;
14249
+ var UTM_KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"];
14250
+ function isInternalReferrer(referrerHostname) {
14251
+ if (typeof window === "undefined") return false;
14252
+ try {
14253
+ return referrerHostname === window.location.hostname;
14254
+ } catch {
14255
+ return false;
14256
+ }
14257
+ }
14258
+ function computeInitialAttrs(fresh, cached) {
14259
+ const result = {};
14260
+ const hasFreshUtms = UTM_KEYS.some((k2) => typeof fresh[k2] === "string");
14261
+ for (const key of UTM_KEYS) {
14262
+ const value = hasFreshUtms ? fresh[key] : cached == null ? void 0 : cached[key];
14263
+ if (value) result[key] = value;
14264
+ }
14265
+ const freshReferrerHostname = typeof fresh.referrer_hostname === "string" ? fresh.referrer_hostname : void 0;
14266
+ const isInternal = freshReferrerHostname ? isInternalReferrer(freshReferrerHostname) : true;
14267
+ if (!isInternal && typeof fresh.referrer === "string") {
14268
+ result.referrer = fresh.referrer;
14269
+ if (freshReferrerHostname) result.referrer_hostname = freshReferrerHostname;
14270
+ } else if (cached == null ? void 0 : cached.referrer) {
14271
+ result.referrer = cached.referrer;
14272
+ if (cached.referrer_hostname) result.referrer_hostname = cached.referrer_hostname;
14273
+ }
14274
+ if (cached == null ? void 0 : cached.initial_page_url) {
14275
+ result.initial_page_url = cached.initial_page_url;
14276
+ if (cached.initial_page_path) result.initial_page_path = cached.initial_page_path;
14277
+ if (cached.initial_page_query) result.initial_page_query = cached.initial_page_query;
14278
+ } else {
14279
+ if (typeof fresh.page_url === "string") result.initial_page_url = fresh.page_url;
14280
+ if (typeof fresh.page_path === "string") result.initial_page_path = fresh.page_path;
14281
+ if (typeof fresh.page_query === "string") result.initial_page_query = fresh.page_query;
14282
+ }
14283
+ return result;
14284
+ }
14285
+ function loadInitialAttrs() {
14286
+ return loadCached(INITIAL_ATTRS_KEY, INITIAL_ATTRS_TTL);
14287
+ }
14288
+ function saveInitialAttrs(attrs) {
14289
+ writeCached(INITIAL_ATTRS_KEY, attrs);
14290
+ debug("Syntro Bootstrap", "Cached initial attrs:", attrs);
14291
+ }
14237
14292
  var GEO_CACHE_KEY = "syntro_geo";
14238
14293
  var GEO_DEFAULT_HOST = "https://geo.syntrologie.com";
14239
14294
  async function fetchGeo(geoHost) {
@@ -14462,7 +14517,7 @@ function identifyFromUrlParam(telemetry, consentGate) {
14462
14517
  }
14463
14518
 
14464
14519
  // src/defaults/initialProperties.ts
14465
- var UTM_KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"];
14520
+ var UTM_KEYS2 = ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"];
14466
14521
  function isStrictRegion(geo) {
14467
14522
  if (geo.is_eu === "true") return true;
14468
14523
  if (geo.country_code === "GB" || geo.country_code === "CH") return true;
@@ -14491,7 +14546,7 @@ function captureInitialProperties(telemetry, geoPromise) {
14491
14546
  $initial_referrer: referrer,
14492
14547
  $initial_referring_domain: safeReferringDomain(referrer)
14493
14548
  };
14494
- for (const key of UTM_KEYS) {
14549
+ for (const key of UTM_KEYS2) {
14495
14550
  const value = params.get(key);
14496
14551
  if (value) {
14497
14552
  props[`$initial_${key}`] = value;
@@ -18423,8 +18478,17 @@ async function _initCore(options) {
18423
18478
  const cachedSegmentAttrs = loadCachedSegmentAttributes();
18424
18479
  const browserMetadata = collectBrowserMetadata();
18425
18480
  const appSignalsInit = (_e2 = options.appSignalsInit) != null ? _e2 : {};
18426
- const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs, ...appSignalsInit };
18481
+ const cachedInitialAttrs = loadInitialAttrs();
18482
+ const initialAttrs = computeInitialAttrs(browserMetadata, cachedInitialAttrs);
18483
+ saveInitialAttrs(initialAttrs);
18484
+ const phaseOneAttrs = {
18485
+ ...browserMetadata,
18486
+ ...initialAttrs,
18487
+ ...cachedSegmentAttrs,
18488
+ ...appSignalsInit
18489
+ };
18427
18490
  debug("Syntro Bootstrap", "Phase 1: Browser metadata:", browserMetadata);
18491
+ debug("Syntro Bootstrap", "Phase 1: Initial attrs:", initialAttrs);
18428
18492
  debug("Syntro Bootstrap", "Phase 1: Cached segment attributes:", cachedSegmentAttrs);
18429
18493
  if (Object.keys(appSignalsInit).length > 0) {
18430
18494
  debug("Syntro Bootstrap", "Phase 1: App signals:", appSignalsInit);
@@ -18520,6 +18584,7 @@ async function _initCore(options) {
18520
18584
  const sessionAttrs = (_b2 = (_a4 = sessionMetrics == null ? void 0 : sessionMetrics.getAll) == null ? void 0 : _a4.call(sessionMetrics)) != null ? _b2 : {};
18521
18585
  const updatedAttrs = {
18522
18586
  ...browserMetadata,
18587
+ ...initialAttrs,
18523
18588
  ...sessionAttrs,
18524
18589
  ...segmentFlags,
18525
18590
  ...appSignalsInit
@@ -18741,7 +18806,7 @@ async function _initCore(options) {
18741
18806
  }
18742
18807
  const geoData = await geoPromise;
18743
18808
  if (experiments && Object.keys(geoData).length > 0) {
18744
- const mergedAttrs = { ...browserMetadata, ...geoData, ...appSignalsInit };
18809
+ const mergedAttrs = { ...browserMetadata, ...initialAttrs, ...geoData, ...appSignalsInit };
18745
18810
  debug("Syntro Bootstrap", "Merging geo data into GrowthBook attributes:", geoData);
18746
18811
  (_l = experiments.setAttributes) == null ? void 0 : _l.call(experiments, mergedAttrs);
18747
18812
  }
@@ -18749,7 +18814,7 @@ async function _initCore(options) {
18749
18814
  if (mcpHost && experiments) {
18750
18815
  browserMetadata.surface_type = "mcp-app";
18751
18816
  browserMetadata.surface_host = mcpHost.name;
18752
- (_m = experiments.setAttributes) == null ? void 0 : _m.call(experiments, { ...browserMetadata, ...geoData });
18817
+ (_m = experiments.setAttributes) == null ? void 0 : _m.call(experiments, { ...browserMetadata, ...initialAttrs, ...geoData });
18753
18818
  runtime5.context.setSurfaceType("mcp-app");
18754
18819
  runtime5.context.setSurfaceHost(mcpHost.name);
18755
18820
  debug("Syntro Bootstrap", "MCP App detected:", mcpHost.name);