@syntrologie/runtime-sdk 2.15.0 → 2.16.0

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.
@@ -2,6 +2,7 @@ import { type ReactNode } from 'react';
2
2
  import type { BatchActionHandle } from './actions/types';
3
3
  import type { SmartCanvasController } from './controller';
4
4
  import type { ExperimentClient } from './experiments/types';
5
+ import type { PlatformAdapter } from './platform/PlatformAdapter';
5
6
  import type { SmartCanvasRuntime } from './runtime';
6
7
  import type { TelemetryClient } from './telemetry/types';
7
8
  import type { CanvasThemeConfig } from './theme';
@@ -34,5 +35,7 @@ export interface SmartCanvasAppProps {
34
35
  initialBatchHandle?: BatchActionHandle | null;
35
36
  /** Workspace-level theme for 3-layer inheritance (defaults → workspace → config) */
36
37
  workspaceTheme?: CanvasThemeConfig;
38
+ /** Platform adapter for host-platform-specific integrations (Shopify, WordPress, etc.) */
39
+ platformAdapter?: PlatformAdapter;
37
40
  }
38
- export declare function SmartCanvasApp({ controller, fetcher, configUri, configUriFeatureKey, configFeatureKey, fetchCredentials, pollIntervalMs, experiments, telemetry, runtime, overlayFetcher, overlayConfigUri, overlayConfigFeatureKey, overlayFetchCredentials, footerSlot, launcherLabel, canvasHost, initialBatchHandle, workspaceTheme, }: SmartCanvasAppProps): import("react/jsx-runtime").JSX.Element;
41
+ export declare function SmartCanvasApp({ controller, fetcher, configUri, configUriFeatureKey, configFeatureKey, fetchCredentials, pollIntervalMs, experiments, telemetry, runtime, overlayFetcher, overlayConfigUri, overlayConfigFeatureKey, overlayFetchCredentials, footerSlot, launcherLabel, canvasHost, initialBatchHandle, workspaceTheme, platformAdapter, }: SmartCanvasAppProps): import("react/jsx-runtime").JSX.Element;
package/dist/api.d.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { ExperimentClient } from './experiments/types';
8
8
  import type { OverlayRecipeFetcher } from './overlays/fetcher';
9
+ import type { PlatformAdapter } from './platform/PlatformAdapter';
9
10
  import type { ActionHandler, AppearanceConfig, RenderProps } from './render/types';
10
11
  import type { SmartCanvasRuntime } from './runtime';
11
12
  import { type SmartCanvasElement } from './SmartCanvasElement';
@@ -45,6 +46,8 @@ export interface SmartCanvasConfig {
45
46
  actionHandlers?: ActionHandler;
46
47
  /** Workspace-level theme for 3-layer inheritance (defaults → workspace → config) */
47
48
  workspaceTheme?: CanvasThemeConfig;
49
+ /** Platform adapter for host-platform-specific integrations (Shopify, WordPress, etc.) */
50
+ platformAdapter?: PlatformAdapter;
48
51
  }
49
52
  /**
50
53
  * Handle for interacting with a SmartCanvas instance.
@@ -4,6 +4,8 @@
4
4
  */
5
5
  /**
6
6
  * Get environment variable, supporting both Vite and Next.js patterns.
7
+ * CSP-safe: no eval() is used. Vite env access is resolved at build time
8
+ * via the __VITE_IMPORT_META_ENV__ define.
7
9
  */
8
10
  export declare function getEnvVar(name: string): string | undefined;
9
11
  /**
@@ -3640,7 +3640,7 @@ function getAntiFlickerSnippet(config = {}) {
3640
3640
  }
3641
3641
 
3642
3642
  // src/version.ts
3643
- var SDK_VERSION = "2.15.0";
3643
+ var SDK_VERSION = "2.16.0";
3644
3644
 
3645
3645
  // src/types.ts
3646
3646
  var SDK_SCHEMA_VERSION = "2.0";
@@ -6164,7 +6164,8 @@ function SmartCanvasApp({
6164
6164
  launcherLabel,
6165
6165
  canvasHost,
6166
6166
  initialBatchHandle,
6167
- workspaceTheme
6167
+ workspaceTheme,
6168
+ platformAdapter
6168
6169
  }) {
6169
6170
  if (runtime3) {
6170
6171
  return /* @__PURE__ */ jsx8(RuntimeProvider, { runtime: runtime3, children: /* @__PURE__ */ jsx8(
@@ -6188,7 +6189,8 @@ function SmartCanvasApp({
6188
6189
  launcherLabel,
6189
6190
  canvasHost,
6190
6191
  initialBatchHandle,
6191
- workspaceTheme
6192
+ workspaceTheme,
6193
+ platformAdapter
6192
6194
  }
6193
6195
  ) });
6194
6196
  }
@@ -6212,7 +6214,8 @@ function SmartCanvasApp({
6212
6214
  launcherLabel,
6213
6215
  canvasHost,
6214
6216
  initialBatchHandle,
6215
- workspaceTheme
6217
+ workspaceTheme,
6218
+ platformAdapter
6216
6219
  }
6217
6220
  );
6218
6221
  }
@@ -6235,7 +6238,8 @@ function SmartCanvasAppInner({
6235
6238
  launcherLabel,
6236
6239
  canvasHost: _canvasHost,
6237
6240
  initialBatchHandle,
6238
- workspaceTheme
6241
+ workspaceTheme,
6242
+ platformAdapter
6239
6243
  }) {
6240
6244
  var _a2, _b, _c, _d, _e, _f;
6241
6245
  const [open, setOpen] = useState7(controller.getState().open);
@@ -6243,6 +6247,7 @@ function SmartCanvasAppInner({
6243
6247
  const [localUrl, setLocalUrl] = useState7(
6244
6248
  () => typeof window !== "undefined" ? window.location.href : "/"
6245
6249
  );
6250
+ const [reapplyTick, setReapplyTick] = useState7(0);
6246
6251
  const pageUrl = (_a2 = pageContext == null ? void 0 : pageContext.url) != null ? _a2 : localUrl;
6247
6252
  useEffect8(() => {
6248
6253
  if (runtime3) return;
@@ -6334,7 +6339,7 @@ function SmartCanvasAppInner({
6334
6339
  batchHandleRef.current = null;
6335
6340
  }
6336
6341
  };
6337
- }, [runtime3, configState.actions, pageUrl]);
6342
+ }, [runtime3, configState.actions, pageUrl, reapplyTick]);
6338
6343
  useEffect8(() => {
6339
6344
  if (!runtime3) return;
6340
6345
  return runtime3.events.subscribe(
@@ -6342,6 +6347,14 @@ function SmartCanvasAppInner({
6342
6347
  () => controller.setOpen(true)
6343
6348
  );
6344
6349
  }, [runtime3, controller]);
6350
+ useEffect8(() => {
6351
+ if (!platformAdapter || !(runtime3 == null ? void 0 : runtime3.actions)) return;
6352
+ const unsub = platformAdapter.onRegionDidLoad((regionId) => {
6353
+ console.log(`[SmartCanvasApp] Platform region reloaded: ${regionId}, re-applying actions`);
6354
+ setReapplyTick((t) => t + 1);
6355
+ });
6356
+ return unsub;
6357
+ }, [platformAdapter, runtime3]);
6345
6358
  const { shadowRoot } = useShadowRoot();
6346
6359
  const themeConfig = configState.theme;
6347
6360
  return /* @__PURE__ */ jsx8(
@@ -7150,7 +7163,8 @@ var createSmartCanvas = async (config = {}) => {
7150
7163
  configUriFeatureKey: config.configUriFeatureKey,
7151
7164
  fetchCredentials: config.fetchCredentials,
7152
7165
  initialBatchHandle: currentBatchHandle,
7153
- workspaceTheme: config.workspaceTheme
7166
+ workspaceTheme: config.workspaceTheme,
7167
+ platformAdapter: config.platformAdapter
7154
7168
  };
7155
7169
  host.mountReactApp(appProps);
7156
7170
  if (config.defaultOpen) {
@@ -10172,6 +10186,258 @@ var NavigationMonitor = class {
10172
10186
  }
10173
10187
  };
10174
10188
 
10189
+ // src/platform/ShopifyAntiFlicker.ts
10190
+ var ShopifyAntiFlicker = class {
10191
+ constructor(adapter) {
10192
+ __publicField(this, "adapter");
10193
+ __publicField(this, "unsubUnload", null);
10194
+ __publicField(this, "unsubLoad", null);
10195
+ __publicField(this, "destroyed", false);
10196
+ this.adapter = adapter;
10197
+ }
10198
+ activate() {
10199
+ if (this.destroyed) return;
10200
+ this.unsubUnload = this.adapter.onRegionWillUnload((sectionId) => {
10201
+ this.hideContentInSection(sectionId);
10202
+ });
10203
+ this.unsubLoad = this.adapter.onRegionDidLoad((sectionId) => {
10204
+ this.revealContentInSection(sectionId);
10205
+ });
10206
+ }
10207
+ destroy() {
10208
+ var _a2, _b;
10209
+ this.destroyed = true;
10210
+ (_a2 = this.unsubUnload) == null ? void 0 : _a2.call(this);
10211
+ (_b = this.unsubLoad) == null ? void 0 : _b.call(this);
10212
+ this.unsubUnload = null;
10213
+ this.unsubLoad = null;
10214
+ }
10215
+ hideContentInSection(sectionId) {
10216
+ const selector = this.sectionSelector(sectionId);
10217
+ const elements = document.querySelectorAll(`${selector} [data-syntro-action-id]`);
10218
+ for (const el of elements) {
10219
+ el.style.opacity = "0";
10220
+ el.style.transition = "none";
10221
+ }
10222
+ }
10223
+ revealContentInSection(sectionId) {
10224
+ const selector = this.sectionSelector(sectionId);
10225
+ requestAnimationFrame(() => {
10226
+ if (this.destroyed) return;
10227
+ const elements = document.querySelectorAll(
10228
+ `${selector} [data-syntro-action-id]`
10229
+ );
10230
+ for (const el of elements) {
10231
+ el.style.transition = "opacity 120ms ease-in";
10232
+ el.style.opacity = "1";
10233
+ }
10234
+ });
10235
+ }
10236
+ sectionSelector(sectionId) {
10237
+ const escaped = typeof CSS !== "undefined" ? CSS.escape(sectionId) : sectionId;
10238
+ const byId = document.getElementById(`shopify-section-${sectionId}`);
10239
+ if (byId) return `#shopify-section-${escaped}`;
10240
+ return `.shopify-section[id$="-${escaped}"]`;
10241
+ }
10242
+ };
10243
+
10244
+ // src/platform/ShopifyAdapter.ts
10245
+ var ShopifyAdapter = class {
10246
+ constructor(options) {
10247
+ __publicField(this, "name", "shopify");
10248
+ __publicField(this, "loadCallbacks", /* @__PURE__ */ new Set());
10249
+ __publicField(this, "unloadCallbacks", /* @__PURE__ */ new Set());
10250
+ __publicField(this, "abortController", null);
10251
+ __publicField(this, "antiFlicker", null);
10252
+ __publicField(this, "initTimeoutMs");
10253
+ var _a2;
10254
+ this.initTimeoutMs = (_a2 = options == null ? void 0 : options.initTimeoutMs) != null ? _a2 : 3e3;
10255
+ }
10256
+ // --------------------------------------------------------------------------
10257
+ // Detection
10258
+ // --------------------------------------------------------------------------
10259
+ detect() {
10260
+ if (typeof window === "undefined" || typeof document === "undefined") {
10261
+ return false;
10262
+ }
10263
+ if ("Shopify" in window && window.Shopify != null) {
10264
+ return true;
10265
+ }
10266
+ if (document.querySelector('meta[name="shopify-checkout-api-token"]')) {
10267
+ return true;
10268
+ }
10269
+ return false;
10270
+ }
10271
+ // --------------------------------------------------------------------------
10272
+ // Initialization
10273
+ // --------------------------------------------------------------------------
10274
+ /**
10275
+ * Wait for Shopify sections to be ready, then attach lifecycle listeners.
10276
+ *
10277
+ * Resolution order:
10278
+ * 1. `.shopify-section` already in DOM -> resolve immediately
10279
+ * 2. `shopify:section:load` fires -> resolve
10280
+ * 3. Timeout (default 3000ms) -> resolve anyway (graceful degradation)
10281
+ */
10282
+ async onInit() {
10283
+ this.abortController = new AbortController();
10284
+ const { signal } = this.abortController;
10285
+ this.attachSectionListeners(signal);
10286
+ this.antiFlicker = new ShopifyAntiFlicker(this);
10287
+ this.antiFlicker.activate();
10288
+ await this.waitForInitialSections(this.initTimeoutMs, signal);
10289
+ }
10290
+ // --------------------------------------------------------------------------
10291
+ // Region lifecycle subscriptions
10292
+ // --------------------------------------------------------------------------
10293
+ onRegionDidLoad(callback) {
10294
+ this.loadCallbacks.add(callback);
10295
+ return () => {
10296
+ this.loadCallbacks.delete(callback);
10297
+ };
10298
+ }
10299
+ onRegionWillUnload(callback) {
10300
+ this.unloadCallbacks.add(callback);
10301
+ return () => {
10302
+ this.unloadCallbacks.delete(callback);
10303
+ };
10304
+ }
10305
+ onRegionMutated(_regionId) {
10306
+ }
10307
+ // --------------------------------------------------------------------------
10308
+ // Anchor scope
10309
+ // --------------------------------------------------------------------------
10310
+ getAnchorScope(anchor) {
10311
+ const section = anchor.closest(".shopify-section");
10312
+ if (section == null ? void 0 : section.id) {
10313
+ const escaped = typeof CSS !== "undefined" ? CSS.escape(section.id) : section.id;
10314
+ return `#${escaped} `;
10315
+ }
10316
+ return "";
10317
+ }
10318
+ // --------------------------------------------------------------------------
10319
+ // Teardown
10320
+ // --------------------------------------------------------------------------
10321
+ destroy() {
10322
+ var _a2;
10323
+ (_a2 = this.antiFlicker) == null ? void 0 : _a2.destroy();
10324
+ this.antiFlicker = null;
10325
+ if (this.abortController) {
10326
+ this.abortController.abort();
10327
+ this.abortController = null;
10328
+ }
10329
+ this.loadCallbacks.clear();
10330
+ this.unloadCallbacks.clear();
10331
+ }
10332
+ // --------------------------------------------------------------------------
10333
+ // Private
10334
+ // --------------------------------------------------------------------------
10335
+ attachSectionListeners(signal) {
10336
+ document.addEventListener(
10337
+ "shopify:section:load",
10338
+ (event) => {
10339
+ var _a2;
10340
+ const sectionId = (_a2 = event.detail) == null ? void 0 : _a2.sectionId;
10341
+ if (sectionId) {
10342
+ for (const cb of this.loadCallbacks) {
10343
+ try {
10344
+ cb(sectionId);
10345
+ } catch {
10346
+ }
10347
+ }
10348
+ }
10349
+ },
10350
+ { signal }
10351
+ );
10352
+ document.addEventListener(
10353
+ "shopify:section:unload",
10354
+ (event) => {
10355
+ var _a2;
10356
+ const sectionId = (_a2 = event.detail) == null ? void 0 : _a2.sectionId;
10357
+ if (sectionId) {
10358
+ for (const cb of this.unloadCallbacks) {
10359
+ try {
10360
+ cb(sectionId);
10361
+ } catch {
10362
+ }
10363
+ }
10364
+ }
10365
+ },
10366
+ { signal }
10367
+ );
10368
+ }
10369
+ waitForInitialSections(timeoutMs, signal) {
10370
+ return new Promise((resolve) => {
10371
+ if (document.querySelector(".shopify-section")) {
10372
+ resolve();
10373
+ return;
10374
+ }
10375
+ let resolved = false;
10376
+ const done = () => {
10377
+ if (resolved) return;
10378
+ resolved = true;
10379
+ resolve();
10380
+ };
10381
+ document.addEventListener("shopify:section:load", () => done(), { once: true, signal });
10382
+ const timer = setTimeout(done, timeoutMs);
10383
+ signal.addEventListener(
10384
+ "abort",
10385
+ () => {
10386
+ clearTimeout(timer);
10387
+ done();
10388
+ },
10389
+ { once: true }
10390
+ );
10391
+ });
10392
+ }
10393
+ };
10394
+
10395
+ // src/platform/detect.ts
10396
+ var ADAPTERS = [() => new ShopifyAdapter()];
10397
+ function detectPlatform() {
10398
+ for (const create of ADAPTERS) {
10399
+ const adapter = create();
10400
+ if (adapter.detect()) {
10401
+ return adapter;
10402
+ }
10403
+ }
10404
+ return null;
10405
+ }
10406
+
10407
+ // src/platform/shopify-cookie-contract.ts
10408
+ var COOKIE_NAME = "syntro_experiments";
10409
+ var COOKIE_VERSION = 1;
10410
+
10411
+ // src/platform/ShopifyPixelBridge.ts
10412
+ var MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
10413
+ var ShopifyPixelBridge = class {
10414
+ constructor(context) {
10415
+ __publicField(this, "context");
10416
+ this.context = { ...context, telemetryHost: context.telemetryHost.replace(/\/$/, "") };
10417
+ this.writeCookie();
10418
+ }
10419
+ /** Update the telemetry context (e.g., after consent is granted and
10420
+ * PostHog finally initializes and a real distinct_id becomes available). */
10421
+ updateContext(context) {
10422
+ this.context = { ...context, telemetryHost: context.telemetryHost.replace(/\/$/, "") };
10423
+ this.writeCookie();
10424
+ }
10425
+ destroy() {
10426
+ document.cookie = `${COOKIE_NAME}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Lax`;
10427
+ }
10428
+ writeCookie() {
10429
+ const payload = {
10430
+ version: COOKIE_VERSION,
10431
+ distinct_id: this.context.distinctId,
10432
+ telemetry_host: this.context.telemetryHost,
10433
+ telemetry_key: this.context.telemetryKey
10434
+ };
10435
+ const value = encodeURIComponent(JSON.stringify(payload));
10436
+ const cookieString = `${COOKIE_NAME}=${value}; max-age=${MAX_AGE_SECONDS}; path=/; SameSite=Lax`;
10437
+ document.cookie = cookieString;
10438
+ }
10439
+ };
10440
+
10175
10441
  // src/state/helpers/cooldowns.ts
10176
10442
  var COOLDOWN_PREFIX = "cooldown:";
10177
10443
  function createCooldownStore(storage) {
@@ -11424,16 +11690,13 @@ function encodeToken(payload) {
11424
11690
  }
11425
11691
 
11426
11692
  // src/bootstrap-init.ts
11693
+ var import_meta = {};
11427
11694
  function getEnvVar(name) {
11428
11695
  if (typeof process !== "undefined" && process.env) {
11429
11696
  return process.env[name];
11430
11697
  }
11431
- try {
11432
- const meta = (0, eval)("import.meta");
11433
- if (meta == null ? void 0 : meta.env) {
11434
- return meta.env[name];
11435
- }
11436
- } catch {
11698
+ if (typeof import_meta.env !== "undefined" && import_meta.env) {
11699
+ return import_meta.env[name];
11437
11700
  }
11438
11701
  return void 0;
11439
11702
  }
@@ -11826,7 +12089,7 @@ function createTelemetryClient(provider, config) {
11826
12089
 
11827
12090
  // src/bootstrap-runtime.ts
11828
12091
  async function _initCore(options) {
11829
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
12092
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
11830
12093
  initLogger();
11831
12094
  debug("Syntro Bootstrap", "====== INIT ======");
11832
12095
  debug("Syntro Bootstrap", "Options:", {
@@ -11980,6 +12243,8 @@ async function _initCore(options) {
11980
12243
  true
11981
12244
  );
11982
12245
  }
12246
+ const platformAdapter = detectPlatform();
12247
+ let shopifyPixelBridge;
11983
12248
  const onFeatureFlagsLoaded = (allFlags) => {
11984
12249
  var _a3, _b2, _c2;
11985
12250
  debug("Syntro Bootstrap", "Phase 2: PostHog feature flags loaded");
@@ -11997,6 +12262,16 @@ async function _initCore(options) {
11997
12262
  debug("Syntro Bootstrap", "Updating GrowthBook with attributes:", updatedAttrs);
11998
12263
  (_c2 = experiments.setAttributes) == null ? void 0 : _c2.call(experiments, updatedAttrs);
11999
12264
  }
12265
+ if (shopifyPixelBridge && (telemetry == null ? void 0 : telemetry.getDistinctId)) {
12266
+ const distinctId = telemetry.getDistinctId();
12267
+ if (distinctId && telemetryHost && (payload == null ? void 0 : payload.t)) {
12268
+ shopifyPixelBridge.updateContext({
12269
+ distinctId,
12270
+ telemetryHost,
12271
+ telemetryKey: payload.t
12272
+ });
12273
+ }
12274
+ }
12000
12275
  };
12001
12276
  let telemetry;
12002
12277
  if (payload == null ? void 0 : payload.t) {
@@ -12029,6 +12304,18 @@ async function _initCore(options) {
12029
12304
  var _a3;
12030
12305
  (_a3 = telemetryForCapture.track) == null ? void 0 : _a3.call(telemetryForCapture, name, props);
12031
12306
  });
12307
+ if ((platformAdapter == null ? void 0 : platformAdapter.name) === "shopify" && telemetryHost) {
12308
+ try {
12309
+ shopifyPixelBridge = new ShopifyPixelBridge({
12310
+ distinctId: (_f = (_e = telemetry.getDistinctId) == null ? void 0 : _e.call(telemetry)) != null ? _f : "",
12311
+ telemetryHost,
12312
+ telemetryKey: payload.t
12313
+ });
12314
+ debug("Syntro Bootstrap", "ShopifyPixelBridge initialized for checkout attribution");
12315
+ } catch (err) {
12316
+ warn("Syntro Bootstrap", "ShopifyPixelBridge init failed", err);
12317
+ }
12318
+ }
12032
12319
  }
12033
12320
  let sessionMetrics;
12034
12321
  if (payload == null ? void 0 : payload.e) {
@@ -12038,7 +12325,11 @@ async function _initCore(options) {
12038
12325
  // undefined falls back to adapter default
12039
12326
  // Phase 1: Use browser metadata + cached segment attributes for instant evaluation
12040
12327
  attributes: phaseOneAttrs,
12041
- // Wire experiment tracking to telemetry provider
12328
+ // Wire experiment tracking to telemetry provider. PostHog registers
12329
+ // the assignment as a super-property + fires `$experiment_started`;
12330
+ // every future event from this distinct_id (including checkout events
12331
+ // posted by the Shopify Web Pixel) is then auto-attributed to the
12332
+ // variant server-side, so the pixel doesn't need to re-transmit.
12042
12333
  onExperimentViewed: (telemetry == null ? void 0 : telemetry.trackExperiment) ? (key, variationId, variationName) => {
12043
12334
  telemetry.trackExperiment(key, variationId, variationName);
12044
12335
  } : void 0
@@ -12094,7 +12385,7 @@ async function _initCore(options) {
12094
12385
  };
12095
12386
  debug("Syntro Bootstrap", "Global SynOS object exposed");
12096
12387
  }
12097
- const registeredApps = (_g = (_f = (_e = runtime3.apps).list) == null ? void 0 : _f.call(_e)) != null ? _g : [];
12388
+ const registeredApps = (_i = (_h = (_g = runtime3.apps).list) == null ? void 0 : _h.call(_g)) != null ? _i : [];
12098
12389
  console.log(
12099
12390
  `[DIAG] Activation loop: ${registeredApps.length} apps in registry:`,
12100
12391
  registeredApps.map((a) => `${a.manifest.id}(${a.state})`).join(", ")
@@ -12125,20 +12416,20 @@ async function _initCore(options) {
12125
12416
  if (experiments && Object.keys(geoData).length > 0) {
12126
12417
  const mergedAttrs = { ...browserMetadata, ...geoData, ...appSignalsInit };
12127
12418
  debug("Syntro Bootstrap", "Merging geo data into GrowthBook attributes:", geoData);
12128
- (_h = experiments.setAttributes) == null ? void 0 : _h.call(experiments, mergedAttrs);
12419
+ (_j = experiments.setAttributes) == null ? void 0 : _j.call(experiments, mergedAttrs);
12129
12420
  }
12130
12421
  const mcpHost = await mcpPromise;
12131
12422
  if (mcpHost && experiments) {
12132
12423
  browserMetadata.surface_type = "mcp-app";
12133
12424
  browserMetadata.surface_host = mcpHost.name;
12134
- (_i = experiments.setAttributes) == null ? void 0 : _i.call(experiments, { ...browserMetadata, ...geoData });
12425
+ (_k = experiments.setAttributes) == null ? void 0 : _k.call(experiments, { ...browserMetadata, ...geoData });
12135
12426
  debug("Syntro Bootstrap", "MCP App detected:", mcpHost.name);
12136
12427
  }
12137
12428
  let baseFetcher;
12138
12429
  if (options.fetcher) {
12139
12430
  baseFetcher = options.fetcher;
12140
12431
  } else if (payload == null ? void 0 : payload.f) {
12141
- const configFetcher = createConfigFetcher(payload.f, (_j = payload.o) != null ? _j : {});
12432
+ const configFetcher = createConfigFetcher(payload.f, (_l = payload.o) != null ? _l : {});
12142
12433
  baseFetcher = async () => {
12143
12434
  var _a3;
12144
12435
  const result = await configFetcher.fetch();
@@ -12152,7 +12443,7 @@ async function _initCore(options) {
12152
12443
  }
12153
12444
  const warnedAppFailures = /* @__PURE__ */ new Set();
12154
12445
  const appLoadingFetcher = baseFetcher ? async () => {
12155
- var _a3, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k, _l;
12446
+ var _a3, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2;
12156
12447
  const config = await baseFetcher();
12157
12448
  const tileCount = (_b2 = (_a3 = config.tiles) == null ? void 0 : _a3.length) != null ? _b2 : 0;
12158
12449
  const actionCount = (_d2 = (_c2 = config.actions) == null ? void 0 : _c2.length) != null ? _d2 : 0;
@@ -12178,9 +12469,9 @@ async function _initCore(options) {
12178
12469
  "[Syntro Bootstrap] Config fetched:",
12179
12470
  `tiles=${(_g2 = (_f2 = config.tiles) == null ? void 0 : _f2.length) != null ? _g2 : 0},`,
12180
12471
  `actions=${(_i2 = (_h2 = config.actions) == null ? void 0 : _h2.length) != null ? _i2 : 0},`,
12181
- `theme=${(_k = (_j2 = config.theme) == null ? void 0 : _j2.name) != null ? _k : "none"}`
12472
+ `theme=${(_k2 = (_j2 = config.theme) == null ? void 0 : _j2.name) != null ? _k2 : "none"}`
12182
12473
  );
12183
- if (((_l = config.actions) == null ? void 0 : _l.length) > 0) {
12474
+ if (((_l2 = config.actions) == null ? void 0 : _l2.length) > 0) {
12184
12475
  console.log(
12185
12476
  "[Syntro Bootstrap] Actions in config:",
12186
12477
  config.actions.map(
@@ -12233,13 +12524,23 @@ async function _initCore(options) {
12233
12524
  }
12234
12525
  return config;
12235
12526
  } : void 0;
12527
+ if (platformAdapter) {
12528
+ debug("Syntro Bootstrap", `Detected platform: ${platformAdapter.name}`);
12529
+ try {
12530
+ await platformAdapter.onInit();
12531
+ debug("Syntro Bootstrap", `Platform adapter initialized: ${platformAdapter.name}`);
12532
+ } catch (err) {
12533
+ warn("Syntro Bootstrap", `Platform adapter init failed: ${platformAdapter.name}`, err);
12534
+ }
12535
+ }
12236
12536
  const canvas = await createSmartCanvas({
12237
12537
  ...options.canvas,
12238
12538
  fetcher: appLoadingFetcher,
12239
12539
  integrations: { experiments, telemetry },
12240
12540
  editorUrl,
12241
- runtime: runtime3
12541
+ runtime: runtime3,
12242
12542
  // Pass runtime so actions can be applied
12543
+ platformAdapter: platformAdapter != null ? platformAdapter : void 0
12243
12544
  });
12244
12545
  return { canvas, runtime: runtime3, experiments, telemetry, sessionMetrics, appLoader };
12245
12546
  }
@@ -12356,6 +12657,11 @@ export {
12356
12657
  createEventBus,
12357
12658
  EventHistory,
12358
12659
  NavigationMonitor,
12660
+ ShopifyAntiFlicker,
12661
+ ShopifyAdapter,
12662
+ detectPlatform,
12663
+ COOKIE_NAME,
12664
+ ShopifyPixelBridge,
12359
12665
  StateStore,
12360
12666
  createStateStore,
12361
12667
  getSlotType,
@@ -12378,4 +12684,4 @@ export {
12378
12684
  encodeToken,
12379
12685
  Syntro
12380
12686
  };
12381
- //# sourceMappingURL=chunk-CVMZW3II.js.map
12687
+ //# sourceMappingURL=chunk-NVV7IWJC.js.map