@syntrologie/runtime-sdk 2.14.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.
- package/README.md +1 -0
- package/dist/SmartCanvasApp.d.ts +4 -1
- package/dist/SmartCanvasElementLit.d.ts +166 -0
- package/dist/actions/schema.js +4 -3
- package/dist/actions/types.d.ts +8 -2
- package/dist/anchor/AnchorResolver.d.ts +1 -0
- package/dist/api-lit.d.ts +84 -0
- package/dist/api.d.ts +3 -0
- package/dist/apps/builtinRuntimeModules-lit.d.ts +20 -0
- package/dist/bootstrap-init.d.ts +2 -0
- package/dist/bootstrap-types.d.ts +10 -0
- package/dist/chunk-2IQ2PTLJ.js +871 -0
- package/dist/chunk-2IQ2PTLJ.js.map +7 -0
- package/dist/{chunk-YLLWLUQX.js → chunk-4HXPGXUC.js} +1 -16
- package/dist/{chunk-YLLWLUQX.js.map → chunk-4HXPGXUC.js.map} +1 -1
- package/dist/{chunk-IR6UOR63.js → chunk-GX7BBYX6.js} +2 -2
- package/dist/chunk-JMHRHAEL.js +18 -0
- package/dist/chunk-JMHRHAEL.js.map +7 -0
- package/dist/{chunk-JCDCANR7.js → chunk-NVV7IWJC.js} +1301 -1084
- package/dist/chunk-NVV7IWJC.js.map +7 -0
- package/dist/{chunk-77TNZ66J.js → chunk-XVRDKBYF.js} +3 -3
- package/dist/components/SyntroCanvasOverlay.d.ts +100 -0
- package/dist/components/SyntroDrawer.d.ts +110 -0
- package/dist/components/SyntroLauncher.d.ts +105 -0
- package/dist/components/SyntroTileCard.d.ts +74 -0
- package/dist/components/SyntroTileWheel.d.ts +51 -0
- package/dist/config/schema.js +3 -2
- package/dist/controllers/DecisionController.d.ts +48 -0
- package/dist/controllers/NotificationsController.d.ts +59 -0
- package/dist/controllers/RuntimeController.d.ts +52 -0
- package/dist/controllers/RuntimeEventsController.d.ts +42 -0
- package/dist/controllers/ThemeController.d.ts +110 -0
- package/dist/controllers/index.d.ts +13 -0
- package/dist/decisions/schema.js +2 -1
- package/dist/decisions/types.d.ts +4 -0
- package/dist/editorLoader.d.ts +5 -0
- package/dist/index-lit.d.ts +40 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1338 -19
- package/dist/index.js.map +4 -4
- package/dist/interop/LitInReact.d.ts +27 -0
- package/dist/interop/ReactInLit.d.ts +42 -0
- package/dist/interop/index.d.ts +7 -0
- package/dist/metrics/sessionMetrics.d.ts +4 -0
- package/dist/notifications/SyntroToastStack.d.ts +43 -0
- package/dist/platform/PlatformAdapter.d.ts +46 -0
- package/dist/platform/ShopifyAdapter.d.ts +36 -0
- package/dist/platform/ShopifyAnchorResolver.d.ts +31 -0
- package/dist/platform/ShopifyAntiFlicker.d.ts +21 -0
- package/dist/platform/ShopifyPixelBridge.d.ts +37 -0
- package/dist/platform/detect.d.ts +9 -0
- package/dist/platform/index.d.ts +10 -0
- package/dist/platform/shopify-cookie-contract.d.ts +39 -0
- package/dist/react-compat.d.ts +114 -0
- package/dist/react.js +6 -4
- package/dist/react.js.map +1 -1
- package/dist/shopify-pixel-entry.d.ts +68 -0
- package/dist/shopify-pixel.js +77 -0
- package/dist/shopify-pixel.js.map +7 -0
- package/dist/shopify-pixel.min.js +2 -0
- package/dist/shopify-pixel.min.js.map +7 -0
- package/dist/smart-canvas.esm.js +856 -240
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +28769 -37080
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +855 -240
- package/dist/smart-canvas.min.js.map +4 -4
- package/dist/theme/index.js +30 -0
- package/dist/theme/index.js.map +7 -0
- package/dist/version.d.ts +1 -1
- package/package.json +10 -1
- package/dist/chunk-JCDCANR7.js.map +0 -7
- /package/dist/{chunk-IR6UOR63.js.map → chunk-GX7BBYX6.js.map} +0 -0
- /package/dist/{chunk-77TNZ66J.js.map → chunk-XVRDKBYF.js.map} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
// src/platform/shopify-cookie-contract.ts
|
|
3
|
+
var COOKIE_NAME = "syntro_experiments";
|
|
4
|
+
var COOKIE_VERSION = 1;
|
|
5
|
+
|
|
6
|
+
// src/shopify-pixel-entry.ts
|
|
7
|
+
async function readCookie(browser) {
|
|
8
|
+
try {
|
|
9
|
+
const raw = await browser.cookie.get(COOKIE_NAME);
|
|
10
|
+
if (!raw) return null;
|
|
11
|
+
const parsed = JSON.parse(raw);
|
|
12
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
13
|
+
if (parsed.version !== COOKIE_VERSION) return null;
|
|
14
|
+
if (typeof parsed.distinct_id !== "string" || parsed.distinct_id.length === 0) return null;
|
|
15
|
+
if (typeof parsed.telemetry_host !== "string" || !parsed.telemetry_host.startsWith("https://"))
|
|
16
|
+
return null;
|
|
17
|
+
if (typeof parsed.telemetry_key !== "string" || parsed.telemetry_key.length === 0) return null;
|
|
18
|
+
return parsed;
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function capture(cookie, eventName, properties) {
|
|
24
|
+
try {
|
|
25
|
+
const url = `${cookie.telemetry_host}/t/${cookie.telemetry_key}/e/`;
|
|
26
|
+
await fetch(url, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: { "Content-Type": "application/json" },
|
|
29
|
+
keepalive: true,
|
|
30
|
+
// survive page unload on checkout_completed
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
api_key: cookie.telemetry_key,
|
|
33
|
+
// PostHog's capture body field is always `api_key`
|
|
34
|
+
event: eventName,
|
|
35
|
+
distinct_id: cookie.distinct_id,
|
|
36
|
+
properties: {
|
|
37
|
+
$lib: "syntrologie-shopify-pixel",
|
|
38
|
+
$lib_version: "1.0.0",
|
|
39
|
+
...properties
|
|
40
|
+
},
|
|
41
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function register({
|
|
48
|
+
analytics,
|
|
49
|
+
browser
|
|
50
|
+
}) {
|
|
51
|
+
analytics.subscribe("checkout_completed", async (event) => {
|
|
52
|
+
const cookie = await readCookie(browser);
|
|
53
|
+
if (!cookie || !event.data.checkout) return;
|
|
54
|
+
const { checkout } = event.data;
|
|
55
|
+
await capture(cookie, "checkout_completed", {
|
|
56
|
+
order_value: checkout.totalPrice.amount,
|
|
57
|
+
currency: checkout.totalPrice.currencyCode,
|
|
58
|
+
order_id: checkout.order?.id
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
analytics.subscribe("product_added_to_cart", async (event) => {
|
|
62
|
+
const cookie = await readCookie(browser);
|
|
63
|
+
if (!cookie) return;
|
|
64
|
+
const cartLine = event.data.cartLine;
|
|
65
|
+
if (!cartLine) return;
|
|
66
|
+
await capture(cookie, "product_added_to_cart", {
|
|
67
|
+
product_id: cartLine.merchandise.product.id,
|
|
68
|
+
variant_id: cartLine.merchandise.id,
|
|
69
|
+
quantity: cartLine.quantity
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (typeof window !== "undefined") {
|
|
74
|
+
window.__SyntroShopifyPixel = { register };
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
//# sourceMappingURL=shopify-pixel.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/platform/shopify-cookie-contract.ts", "../src/shopify-pixel-entry.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared cookie contract between ShopifyPixelBridge (SDK) and the\n * Shopify Web Pixel extension. Both sides must agree on this format.\n *\n * Cookie name: syntro_experiments (legacy name \u2014 kept for backward compat;\n * the cookie carries telemetry identity, not experiment assignments)\n * Cookie value: JSON-encoded ShopifyPixelCookie\n *\n * The storefront SDK writes a snapshot of its telemetry context \u2014 the\n * PostHog distinct_id, the telemetry proxy host, and the public PostHog\n * project key. The Web Pixel extension runs in Shopify's sandboxed\n * checkout (which cannot reach the SDK), reads this cookie, and posts\n * PostHog-shaped checkout events with the same distinct_id so that\n * checkout events JOIN to the storefront session. PostHog already knows\n * which experiments that shopper is in (via `$experiment_started` events\n * fired from the storefront), so attribution happens server-side without\n * the pixel having to re-transmit assignments.\n *\n * Naming note: the fields are `telemetry_host` / `telemetry_key` \u2014 not\n * `api_host` / `api_key` \u2014 to disambiguate from the other `apiHost`\n * fields in the codebase. This cookie is strictly about telemetry.\n *\n * Forward compat: pixel code must check `version` and reject unknown\n * shapes. Bump `version` when fields are removed or semantics change.\n */\n\nexport interface ShopifyPixelCookie {\n /** Schema version \u2014 pixel rejects unknown versions. Bump on breaking changes. */\n version: 1;\n /** PostHog distinct_id from the storefront SDK, used so checkout events\n * join onto the pre-checkout session. Required \u2014 without it the pixel\n * would create a new anonymous user at checkout and the funnel breaks. */\n distinct_id: string;\n /** Telemetry proxy host (e.g., `https://telemetry.syntrologie.com`). No trailing slash. */\n telemetry_host: string;\n /** Public write-only PostHog key (embedded in the client). */\n telemetry_key: string;\n}\n\nexport const COOKIE_NAME = 'syntro_experiments';\nexport const COOKIE_VERSION = 1 as const;\n", "/**\n * CDN-hosted Shopify Web Pixel \u2014 bundled to `dist/shopify-pixel.min.js` and\n * served from `cdn.syntrologie.com/runtime-sdk/v2/latest/shopify-pixel.min.js`.\n *\n * Merchants install this by pasting a small loader snippet into Shopify admin\n * under Settings \u2192 Customer events \u2192 Add custom pixel. The loader dynamically\n * loads this file, then calls `window.__SyntroShopifyPixel.register({ analytics, browser })`\n * to wire up subscribers. The indirection means we ship updates to every\n * merchant's pixel by redeploying the CDN file \u2014 merchants never re-paste.\n *\n * The pixel's only job is to forward Shopify checkout events to the\n * Syntrologie PostHog proxy with the shopper's distinct_id attached.\n * Experiment attribution is handled server-side by PostHog \u2014 once the\n * storefront SDK has fired `$experiment_started` for a distinct_id, PostHog\n * associates all future events from that user (including checkout events\n * this pixel posts) with the correct variant.\n *\n * Shopify custom pixels run in a \"lax sandbox\" iframe. Script tag injection\n * works (verified by PostHog, Sentry, GTM following the same pattern). Cookie\n * access is via the async `browser.cookie.get()` API which proxies to the\n * top frame (merchant storefront domain), so the `syntro_experiments` cookie\n * written by `ShopifyPixelBridge` on the storefront is readable here.\n *\n * All errors swallowed \u2014 a pixel failure must never disturb checkout.\n */\n\nimport { COOKIE_NAME, COOKIE_VERSION } from './platform/shopify-cookie-contract';\n\ninterface ShopifyAnalytics {\n subscribe(eventName: string, handler: (event: ShopifyPixelEvent) => void | Promise<void>): void;\n}\n\ninterface ShopifyBrowserCookie {\n get(name: string): Promise<string | undefined>;\n}\n\ninterface ShopifyBrowser {\n cookie: ShopifyBrowserCookie;\n}\n\ninterface ShopifyPixelEvent {\n data: {\n checkout?: {\n totalPrice: { amount: string | number; currencyCode: string };\n order?: { id: string };\n };\n cartLine?: {\n merchandise: { id: string; product: { id: string } };\n quantity: number;\n };\n };\n}\n\ninterface PixelCookie {\n version: number;\n distinct_id: string;\n telemetry_host: string;\n telemetry_key: string;\n}\n\nasync function readCookie(browser: ShopifyBrowser): Promise<PixelCookie | null> {\n try {\n const raw = await browser.cookie.get(COOKIE_NAME);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object') return null;\n if (parsed.version !== COOKIE_VERSION) return null;\n if (typeof parsed.distinct_id !== 'string' || parsed.distinct_id.length === 0) return null;\n if (typeof parsed.telemetry_host !== 'string' || !parsed.telemetry_host.startsWith('https://'))\n return null;\n if (typeof parsed.telemetry_key !== 'string' || parsed.telemetry_key.length === 0) return null;\n return parsed as PixelCookie;\n } catch {\n return null;\n }\n}\n\n/**\n * POST an event to the PostHog capture endpoint via the Syntrologie proxy.\n * URL shape: `{telemetry_host}/t/{telemetry_key}/e/` \u2014 see\n * `packages/runtime-sdk/src/telemetry/adapters/posthog.ts` for the convention.\n */\nasync function capture(\n cookie: PixelCookie,\n eventName: string,\n properties: Record<string, unknown>\n): Promise<void> {\n try {\n const url = `${cookie.telemetry_host}/t/${cookie.telemetry_key}/e/`;\n await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n keepalive: true, // survive page unload on checkout_completed\n body: JSON.stringify({\n api_key: cookie.telemetry_key, // PostHog's capture body field is always `api_key`\n event: eventName,\n distinct_id: cookie.distinct_id,\n properties: {\n $lib: 'syntrologie-shopify-pixel',\n $lib_version: '1.0.0',\n ...properties,\n },\n timestamp: new Date().toISOString(),\n }),\n });\n } catch {\n // Swallow \u2014 pixel errors must never affect checkout.\n }\n}\n\nexport function register({\n analytics,\n browser,\n}: {\n analytics: ShopifyAnalytics;\n browser: ShopifyBrowser;\n}): void {\n analytics.subscribe('checkout_completed', async (event) => {\n const cookie = await readCookie(browser);\n if (!cookie || !event.data.checkout) return;\n const { checkout } = event.data;\n\n await capture(cookie, 'checkout_completed', {\n order_value: checkout.totalPrice.amount,\n currency: checkout.totalPrice.currencyCode,\n order_id: checkout.order?.id,\n });\n });\n\n analytics.subscribe('product_added_to_cart', async (event) => {\n const cookie = await readCookie(browser);\n if (!cookie) return;\n const cartLine = event.data.cartLine;\n if (!cartLine) return;\n\n await capture(cookie, 'product_added_to_cart', {\n product_id: cartLine.merchandise.product.id,\n variant_id: cartLine.merchandise.id,\n quantity: cartLine.quantity,\n });\n });\n}\n\n// Expose on window so the loader snippet can find us after script load.\n// Shopify's lax-sandbox iframe has a real `window`; this is safe.\ndeclare global {\n interface Window {\n __SyntroShopifyPixel?: { register: typeof register };\n }\n}\nif (typeof window !== 'undefined') {\n window.__SyntroShopifyPixel = { register };\n}\n"],
|
|
5
|
+
"mappings": ";;AAuCO,MAAM,cAAc;AACpB,MAAM,iBAAiB;;;ACoB9B,iBAAe,WAAW,SAAsD;AAC9E,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,OAAO,IAAI,WAAW;AAChD,UAAI,CAAC,IAAK,QAAO;AACjB,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,UAAI,OAAO,YAAY,eAAgB,QAAO;AAC9C,UAAI,OAAO,OAAO,gBAAgB,YAAY,OAAO,YAAY,WAAW,EAAG,QAAO;AACtF,UAAI,OAAO,OAAO,mBAAmB,YAAY,CAAC,OAAO,eAAe,WAAW,UAAU;AAC3F,eAAO;AACT,UAAI,OAAO,OAAO,kBAAkB,YAAY,OAAO,cAAc,WAAW,EAAG,QAAO;AAC1F,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAOA,iBAAe,QACb,QACA,WACA,YACe;AACf,QAAI;AACF,YAAM,MAAM,GAAG,OAAO,cAAc,MAAM,OAAO,aAAa;AAC9D,YAAM,MAAM,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,WAAW;AAAA;AAAA,QACX,MAAM,KAAK,UAAU;AAAA,UACnB,SAAS,OAAO;AAAA;AAAA,UAChB,OAAO;AAAA,UACP,aAAa,OAAO;AAAA,UACpB,YAAY;AAAA,YACV,MAAM;AAAA,YACN,cAAc;AAAA,YACd,GAAG;AAAA,UACL;AAAA,UACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAAA,MACH,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAEO,WAAS,SAAS;AAAA,IACvB;AAAA,IACA;AAAA,EACF,GAGS;AACP,cAAU,UAAU,sBAAsB,OAAO,UAAU;AACzD,YAAM,SAAS,MAAM,WAAW,OAAO;AACvC,UAAI,CAAC,UAAU,CAAC,MAAM,KAAK,SAAU;AACrC,YAAM,EAAE,SAAS,IAAI,MAAM;AAE3B,YAAM,QAAQ,QAAQ,sBAAsB;AAAA,QAC1C,aAAa,SAAS,WAAW;AAAA,QACjC,UAAU,SAAS,WAAW;AAAA,QAC9B,UAAU,SAAS,OAAO;AAAA,MAC5B,CAAC;AAAA,IACH,CAAC;AAED,cAAU,UAAU,yBAAyB,OAAO,UAAU;AAC5D,YAAM,SAAS,MAAM,WAAW,OAAO;AACvC,UAAI,CAAC,OAAQ;AACb,YAAM,WAAW,MAAM,KAAK;AAC5B,UAAI,CAAC,SAAU;AAEf,YAAM,QAAQ,QAAQ,yBAAyB;AAAA,QAC7C,YAAY,SAAS,YAAY,QAAQ;AAAA,QACzC,YAAY,SAAS,YAAY;AAAA,QACjC,UAAU,SAAS;AAAA,MACrB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AASA,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,uBAAuB,EAAE,SAAS;AAAA,EAC3C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(()=>{var o="syntro_experiments";async function s(t){try{let r=await t.cookie.get(o);if(!r)return null;let e=JSON.parse(r);return!e||typeof e!="object"||e.version!==1||typeof e.distinct_id!="string"||e.distinct_id.length===0||typeof e.telemetry_host!="string"||!e.telemetry_host.startsWith("https://")||typeof e.telemetry_key!="string"||e.telemetry_key.length===0?null:e}catch{return null}}async function c(t,r,e){try{let n=`${t.telemetry_host}/t/${t.telemetry_key}/e/`;await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},keepalive:!0,body:JSON.stringify({api_key:t.telemetry_key,event:r,distinct_id:t.distinct_id,properties:{$lib:"syntrologie-shopify-pixel",$lib_version:"1.0.0",...e},timestamp:new Date().toISOString()})})}catch{}}function d({analytics:t,browser:r}){t.subscribe("checkout_completed",async e=>{let n=await s(r);if(!n||!e.data.checkout)return;let{checkout:i}=e.data;await c(n,"checkout_completed",{order_value:i.totalPrice.amount,currency:i.totalPrice.currencyCode,order_id:i.order?.id})}),t.subscribe("product_added_to_cart",async e=>{let n=await s(r);if(!n)return;let i=e.data.cartLine;i&&await c(n,"product_added_to_cart",{product_id:i.merchandise.product.id,variant_id:i.merchandise.id,quantity:i.quantity})})}typeof window<"u"&&(window.__SyntroShopifyPixel={register:d});})();
|
|
2
|
+
//# sourceMappingURL=shopify-pixel.min.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/platform/shopify-cookie-contract.ts", "../src/shopify-pixel-entry.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared cookie contract between ShopifyPixelBridge (SDK) and the\n * Shopify Web Pixel extension. Both sides must agree on this format.\n *\n * Cookie name: syntro_experiments (legacy name \u2014 kept for backward compat;\n * the cookie carries telemetry identity, not experiment assignments)\n * Cookie value: JSON-encoded ShopifyPixelCookie\n *\n * The storefront SDK writes a snapshot of its telemetry context \u2014 the\n * PostHog distinct_id, the telemetry proxy host, and the public PostHog\n * project key. The Web Pixel extension runs in Shopify's sandboxed\n * checkout (which cannot reach the SDK), reads this cookie, and posts\n * PostHog-shaped checkout events with the same distinct_id so that\n * checkout events JOIN to the storefront session. PostHog already knows\n * which experiments that shopper is in (via `$experiment_started` events\n * fired from the storefront), so attribution happens server-side without\n * the pixel having to re-transmit assignments.\n *\n * Naming note: the fields are `telemetry_host` / `telemetry_key` \u2014 not\n * `api_host` / `api_key` \u2014 to disambiguate from the other `apiHost`\n * fields in the codebase. This cookie is strictly about telemetry.\n *\n * Forward compat: pixel code must check `version` and reject unknown\n * shapes. Bump `version` when fields are removed or semantics change.\n */\n\nexport interface ShopifyPixelCookie {\n /** Schema version \u2014 pixel rejects unknown versions. Bump on breaking changes. */\n version: 1;\n /** PostHog distinct_id from the storefront SDK, used so checkout events\n * join onto the pre-checkout session. Required \u2014 without it the pixel\n * would create a new anonymous user at checkout and the funnel breaks. */\n distinct_id: string;\n /** Telemetry proxy host (e.g., `https://telemetry.syntrologie.com`). No trailing slash. */\n telemetry_host: string;\n /** Public write-only PostHog key (embedded in the client). */\n telemetry_key: string;\n}\n\nexport const COOKIE_NAME = 'syntro_experiments';\nexport const COOKIE_VERSION = 1 as const;\n", "/**\n * CDN-hosted Shopify Web Pixel \u2014 bundled to `dist/shopify-pixel.min.js` and\n * served from `cdn.syntrologie.com/runtime-sdk/v2/latest/shopify-pixel.min.js`.\n *\n * Merchants install this by pasting a small loader snippet into Shopify admin\n * under Settings \u2192 Customer events \u2192 Add custom pixel. The loader dynamically\n * loads this file, then calls `window.__SyntroShopifyPixel.register({ analytics, browser })`\n * to wire up subscribers. The indirection means we ship updates to every\n * merchant's pixel by redeploying the CDN file \u2014 merchants never re-paste.\n *\n * The pixel's only job is to forward Shopify checkout events to the\n * Syntrologie PostHog proxy with the shopper's distinct_id attached.\n * Experiment attribution is handled server-side by PostHog \u2014 once the\n * storefront SDK has fired `$experiment_started` for a distinct_id, PostHog\n * associates all future events from that user (including checkout events\n * this pixel posts) with the correct variant.\n *\n * Shopify custom pixels run in a \"lax sandbox\" iframe. Script tag injection\n * works (verified by PostHog, Sentry, GTM following the same pattern). Cookie\n * access is via the async `browser.cookie.get()` API which proxies to the\n * top frame (merchant storefront domain), so the `syntro_experiments` cookie\n * written by `ShopifyPixelBridge` on the storefront is readable here.\n *\n * All errors swallowed \u2014 a pixel failure must never disturb checkout.\n */\n\nimport { COOKIE_NAME, COOKIE_VERSION } from './platform/shopify-cookie-contract';\n\ninterface ShopifyAnalytics {\n subscribe(eventName: string, handler: (event: ShopifyPixelEvent) => void | Promise<void>): void;\n}\n\ninterface ShopifyBrowserCookie {\n get(name: string): Promise<string | undefined>;\n}\n\ninterface ShopifyBrowser {\n cookie: ShopifyBrowserCookie;\n}\n\ninterface ShopifyPixelEvent {\n data: {\n checkout?: {\n totalPrice: { amount: string | number; currencyCode: string };\n order?: { id: string };\n };\n cartLine?: {\n merchandise: { id: string; product: { id: string } };\n quantity: number;\n };\n };\n}\n\ninterface PixelCookie {\n version: number;\n distinct_id: string;\n telemetry_host: string;\n telemetry_key: string;\n}\n\nasync function readCookie(browser: ShopifyBrowser): Promise<PixelCookie | null> {\n try {\n const raw = await browser.cookie.get(COOKIE_NAME);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object') return null;\n if (parsed.version !== COOKIE_VERSION) return null;\n if (typeof parsed.distinct_id !== 'string' || parsed.distinct_id.length === 0) return null;\n if (typeof parsed.telemetry_host !== 'string' || !parsed.telemetry_host.startsWith('https://'))\n return null;\n if (typeof parsed.telemetry_key !== 'string' || parsed.telemetry_key.length === 0) return null;\n return parsed as PixelCookie;\n } catch {\n return null;\n }\n}\n\n/**\n * POST an event to the PostHog capture endpoint via the Syntrologie proxy.\n * URL shape: `{telemetry_host}/t/{telemetry_key}/e/` \u2014 see\n * `packages/runtime-sdk/src/telemetry/adapters/posthog.ts` for the convention.\n */\nasync function capture(\n cookie: PixelCookie,\n eventName: string,\n properties: Record<string, unknown>\n): Promise<void> {\n try {\n const url = `${cookie.telemetry_host}/t/${cookie.telemetry_key}/e/`;\n await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n keepalive: true, // survive page unload on checkout_completed\n body: JSON.stringify({\n api_key: cookie.telemetry_key, // PostHog's capture body field is always `api_key`\n event: eventName,\n distinct_id: cookie.distinct_id,\n properties: {\n $lib: 'syntrologie-shopify-pixel',\n $lib_version: '1.0.0',\n ...properties,\n },\n timestamp: new Date().toISOString(),\n }),\n });\n } catch {\n // Swallow \u2014 pixel errors must never affect checkout.\n }\n}\n\nexport function register({\n analytics,\n browser,\n}: {\n analytics: ShopifyAnalytics;\n browser: ShopifyBrowser;\n}): void {\n analytics.subscribe('checkout_completed', async (event) => {\n const cookie = await readCookie(browser);\n if (!cookie || !event.data.checkout) return;\n const { checkout } = event.data;\n\n await capture(cookie, 'checkout_completed', {\n order_value: checkout.totalPrice.amount,\n currency: checkout.totalPrice.currencyCode,\n order_id: checkout.order?.id,\n });\n });\n\n analytics.subscribe('product_added_to_cart', async (event) => {\n const cookie = await readCookie(browser);\n if (!cookie) return;\n const cartLine = event.data.cartLine;\n if (!cartLine) return;\n\n await capture(cookie, 'product_added_to_cart', {\n product_id: cartLine.merchandise.product.id,\n variant_id: cartLine.merchandise.id,\n quantity: cartLine.quantity,\n });\n });\n}\n\n// Expose on window so the loader snippet can find us after script load.\n// Shopify's lax-sandbox iframe has a real `window`; this is safe.\ndeclare global {\n interface Window {\n __SyntroShopifyPixel?: { register: typeof register };\n }\n}\nif (typeof window !== 'undefined') {\n window.__SyntroShopifyPixel = { register };\n}\n"],
|
|
5
|
+
"mappings": "MAuCO,IAAMA,EAAc,qBCqB3B,eAAeC,EAAWC,EAAsD,CAC9E,GAAI,CACF,IAAMC,EAAM,MAAMD,EAAQ,OAAO,IAAIE,CAAW,EAChD,GAAI,CAACD,EAAK,OAAO,KACjB,IAAME,EAAS,KAAK,MAAMF,CAAG,EAM7B,MALI,CAACE,GAAU,OAAOA,GAAW,UAC7BA,EAAO,UAAY,GACnB,OAAOA,EAAO,aAAgB,UAAYA,EAAO,YAAY,SAAW,GACxE,OAAOA,EAAO,gBAAmB,UAAY,CAACA,EAAO,eAAe,WAAW,UAAU,GAEzF,OAAOA,EAAO,eAAkB,UAAYA,EAAO,cAAc,SAAW,EAAU,KACnFA,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAOA,eAAeC,EACbC,EACAC,EACAC,EACe,CACf,GAAI,CACF,IAAMC,EAAM,GAAGH,EAAO,cAAc,MAAMA,EAAO,aAAa,MAC9D,MAAM,MAAMG,EAAK,CACf,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,UAAW,GACX,KAAM,KAAK,UAAU,CACnB,QAASH,EAAO,cAChB,MAAOC,EACP,YAAaD,EAAO,YACpB,WAAY,CACV,KAAM,4BACN,aAAc,QACd,GAAGE,CACL,EACA,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,CAAC,CACH,CAAC,CACH,MAAQ,CAER,CACF,CAEO,SAASE,EAAS,CACvB,UAAAC,EACA,QAAAV,CACF,EAGS,CACPU,EAAU,UAAU,qBAAsB,MAAOC,GAAU,CACzD,IAAMN,EAAS,MAAMN,EAAWC,CAAO,EACvC,GAAI,CAACK,GAAU,CAACM,EAAM,KAAK,SAAU,OACrC,GAAM,CAAE,SAAAC,CAAS,EAAID,EAAM,KAE3B,MAAMP,EAAQC,EAAQ,qBAAsB,CAC1C,YAAaO,EAAS,WAAW,OACjC,SAAUA,EAAS,WAAW,aAC9B,SAAUA,EAAS,OAAO,EAC5B,CAAC,CACH,CAAC,EAEDF,EAAU,UAAU,wBAAyB,MAAOC,GAAU,CAC5D,IAAMN,EAAS,MAAMN,EAAWC,CAAO,EACvC,GAAI,CAACK,EAAQ,OACb,IAAMQ,EAAWF,EAAM,KAAK,SACvBE,GAEL,MAAMT,EAAQC,EAAQ,wBAAyB,CAC7C,WAAYQ,EAAS,YAAY,QAAQ,GACzC,WAAYA,EAAS,YAAY,GACjC,SAAUA,EAAS,QACrB,CAAC,CACH,CAAC,CACH,CASI,OAAO,OAAW,MACpB,OAAO,qBAAuB,CAAE,SAAAJ,CAAS",
|
|
6
|
+
"names": ["COOKIE_NAME", "readCookie", "browser", "raw", "COOKIE_NAME", "parsed", "capture", "cookie", "eventName", "properties", "url", "register", "analytics", "event", "checkout", "cartLine"]
|
|
7
|
+
}
|