@amboras-dev/snapchat-ads 2.0.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/dist/chunk-PK23QMZT.mjs +30 -0
- package/dist/chunk-PK23QMZT.mjs.map +1 -0
- package/dist/get-config-DmAUgsFJ.d.mts +108 -0
- package/dist/get-config-DmAUgsFJ.d.ts +108 -0
- package/dist/get-config.d.mts +1 -0
- package/dist/get-config.d.ts +1 -0
- package/dist/get-config.js +54 -0
- package/dist/get-config.js.map +1 -0
- package/dist/get-config.mjs +7 -0
- package/dist/get-config.mjs.map +1 -0
- package/dist/index.d.mts +113 -0
- package/dist/index.d.ts +113 -0
- package/dist/index.js +235 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +177 -0
- package/dist/index.mjs.map +1 -0
- package/dist/slot-components/index.d.mts +128 -0
- package/dist/slot-components/index.d.ts +128 -0
- package/dist/slot-components/index.js +657 -0
- package/dist/slot-components/index.js.map +1 -0
- package/dist/slot-components/index.mjs +627 -0
- package/dist/slot-components/index.mjs.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/slot-components/SnapPixelProvider.tsx","../../src/lib/consent.ts","../../src/lib/snap-pixel-loader.ts","../../src/lib/dedup.ts","../../src/slot-components/SnapViewContent.tsx","../../src/hooks/useSnapchatEvents.ts","../../src/lib/currency.ts","../../src/slot-components/SnapAddCart.tsx","../../src/lib/backend.ts","../../src/slot-components/SnapStartCheckout.tsx","../../src/slot-components/SnapPurchase.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, useState } from 'react'\nimport { usePathname, useSearchParams } from 'next/navigation'\nimport { hasAnalyticsConsent } from '../lib/consent'\nimport { installSnapPixelShim, safeSnaptr } from '../lib/snap-pixel-loader'\nimport { makeEventId, minuteBucketNow } from '../lib/dedup'\n\nexport interface SnapPixelProviderProps {\n /** Snap Pixel ID (`snap_pixel_id`). When absent, this component is a no-op. */\n pixelId?: string\n}\n\n/**\n * Null-rendering side-effect component for the `rootProviders` plugin\n * slot. Responsibilities:\n *\n * 1. Consent-gated install of the `snaptr` shim + injection of\n * `https://sc-static.net/scevent.min.js`. Snap does NOT ship an\n * npm-installable browser SDK (research memo Section 10) so we inline\n * the canonical IIFE via `installSnapPixelShim`.\n * 2. Consent-gated `snaptr('init', pixelId)` - runs at most once per\n * pixel id even across SPA nav (guarded by `initedForPixelId`).\n * 3. SPA PAGE_VIEW on every route change. `scevent.min.js` only fires\n * PAGE_VIEW automatically on full page loads; SPA navs need an\n * explicit `snaptr('track', 'PAGE_VIEW')`. Fires with an explicit\n * `client_dedup_id` derived from the pathname so a browser retry in\n * the same minute doesn't get counted twice.\n *\n * Everything is gated on `hasAnalyticsConsent()` and re-checked on the\n * `amboras-consent-changed` event.\n *\n * Deliberately does NOT relay PAGE_VIEW to CAPI - the storefront has no\n * server counterpart for a page view (no route handler dispatches it,\n * unlike PURCHASE / ADD_CART which the checkout / cart flow triggers).\n * Merchants who want server-side PAGE_VIEW attribution can call\n * `trackPageView` from their app; the default here is browser-only for\n * PAGE_VIEW parity with Snap's canonical install snippet.\n */\nexport function SnapPixelProvider({ pixelId }: SnapPixelProviderProps): null {\n const [consented, setConsented] = useState(false)\n const initedForPixelId = useRef<string | null>(null)\n const pathname = usePathname()\n const searchParams = useSearchParams()\n\n useEffect(() => {\n setConsented(hasAnalyticsConsent())\n const handler = () => setConsented(hasAnalyticsConsent())\n window.addEventListener('amboras-consent-changed', handler)\n return () => window.removeEventListener('amboras-consent-changed', handler)\n }, [])\n\n useEffect(() => {\n if (!pixelId || !consented) return\n installSnapPixelShim()\n\n if (initedForPixelId.current !== pixelId) {\n safeSnaptr('init', pixelId)\n initedForPixelId.current = pixelId\n }\n }, [pixelId, consented])\n\n useEffect(() => {\n if (!pixelId || !consented) return\n if (initedForPixelId.current === null) return\n const key = `${pathname ?? '/'}?${searchParams?.toString() ?? ''}`\n const eid = makeEventId('PAGE_VIEW', key, minuteBucketNow())\n safeSnaptr('track', 'PAGE_VIEW', { client_dedup_id: eid })\n }, [pathname, searchParams, pixelId, consented])\n\n return null\n}\n","/**\n * Centralised analytics-consent check. Reads the storefront's standard\n * `amboras_consent` cookie. Gates the BROWSER pixel init (scevent.min.js\n * load + `snaptr('init', ...)`) in `SnapPixelProvider` because that\n * touches Snap's own tracker and drops identifiable cookies, which\n * requires opt-in in most jurisdictions.\n *\n * Does NOT gate the CAPI relay (`sendSnapchatCapiEvent`). Server-to-server\n * events operate on a different legal basis (order-tracking legitimate\n * interest); the merchant owns that compliance call. Matches the\n * meta-ads and pinterest plugins.\n *\n * Falls back to `true` when the cookie is absent entirely - that path is\n * for storefronts that never wired a consent banner at all.\n */\nexport function hasAnalyticsConsent(): boolean {\n if (typeof document === 'undefined') return false\n const match = document.cookie.match(/(?:^|;\\s*)amboras_consent=([^;]*)/)\n if (!match) return true\n try {\n return JSON.parse(decodeURIComponent(match[1]))?.analytics === true\n } catch {\n return false\n }\n}\n","/**\n * Snap Pixel loader - installs the `snaptr` shim and injects\n * `https://sc-static.net/scevent.min.js`. Snap does NOT ship an\n * npm-installable browser SDK (research memo Section 10), so we inline\n * the same IIFE shape the official Snap install snippet emits. Once the\n * script loads, Snap reconciles the shim queue and subsequent calls\n * flow directly through.\n *\n * The shim mirrors Snap's canonical shape so their loaded pixel finds\n * the expected `handleRequest` / `queue` fields and picks up buffered\n * calls made before the network load completes.\n *\n * Idempotent: subsequent calls no-op if `window.snaptr` is already set,\n * so consent flips or SPA nav doesn't stack multiple scripts.\n */\n\ndeclare global {\n interface Window {\n snaptr?: SnaptrFunction\n }\n}\n\nexport type SnaptrFunction = ((...args: unknown[]) => void) & {\n handleRequest?: (...args: unknown[]) => void\n push?: (...args: unknown[]) => void\n queue?: unknown[][]\n version?: string\n loaded?: boolean\n}\n\nconst SCRIPT_SRC = 'https://sc-static.net/scevent.min.js'\n\n/**\n * Install the snaptr shim + inject `sc-static.net/scevent.min.js`.\n * Idempotent - safe to call multiple times.\n */\nexport function installSnapPixelShim(): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n if (window.snaptr) return\n\n const queue: unknown[][] = []\n const shim: SnaptrFunction = function (...args: unknown[]): void {\n if (typeof shim.handleRequest === 'function') {\n shim.handleRequest(...args)\n return\n }\n queue.push(args)\n } as SnaptrFunction\n shim.push = function (...args: unknown[]): void {\n queue.push(args)\n }\n shim.queue = queue\n shim.version = '1.0'\n shim.loaded = true\n window.snaptr = shim\n\n const script = document.createElement('script')\n script.async = true\n script.src = SCRIPT_SRC\n document.head.appendChild(script)\n}\n\n/**\n * Best-effort synchronous call. Returns whether snaptr was ready. Slot\n * components use this so events queued before `scevent.min.js` finishes\n * loading still land - Snap's script drains the shim queue on load.\n */\nexport function safeSnaptr(...args: unknown[]): boolean {\n if (typeof window === 'undefined') return false\n const fn = window.snaptr\n if (typeof fn !== 'function') return false\n try {\n fn(...args)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Poll `window.snaptr` on `requestAnimationFrame` up to `maxAttempts`\n * times, invoking the callback on the first tick where snaptr exists.\n * Escape hatch for callers that must run the moment snaptr becomes\n * ready. The standard slot components rely on the shim queue via\n * `safeSnaptr()`.\n */\nexport function whenSnaptrReady(cb: (fn: SnaptrFunction) => void, maxAttempts = 20): () => void {\n if (typeof window === 'undefined') return () => {}\n let cancelled = false\n let attempts = 0\n\n const tick = (): void => {\n if (cancelled) return\n attempts += 1\n const fn = window.snaptr\n if (typeof fn === 'function') {\n cb(fn)\n return\n }\n if (attempts >= maxAttempts) return\n if (typeof requestAnimationFrame === 'function') {\n requestAnimationFrame(tick)\n } else {\n setTimeout(tick, 50)\n }\n }\n\n tick()\n return () => {\n cancelled = true\n }\n}\n","import type { SnapEventName } from '../types'\n\n/**\n * Deterministic event-ID builder for Snap browser <-> CAPI dedup.\n *\n * Event ID contract (research memo Section 5, encoded verbatim):\n *\n * > For the 5 events (PAGE_VIEW, VIEW_CONTENT, ADD_CART, START_CHECKOUT,\n * > PURCHASE), the browser Pixel call and the CAPI server call MUST share a\n * > top-level `event_id` (Pixel side: `client_dedup_id`), matched by Snap\n * > within a 48-hour window. For PURCHASE ONLY, they MUST additionally share\n * > `custom_data.order_id` (CAPI) / `transaction_id` (Pixel), matched within\n * > a 30-day window. Reuse the Amboras cart/order id as both `order_id` and\n * > `transaction_id`; mint a deterministic UUID from `(event_name,\n * > cart_id_or_session_id, minute_bucket)` for `event_id`/`client_dedup_id`.\n * > Never let the Pixel SDK auto-mint `client_dedup_id` - it prefixes with\n * > `@-` and never matches CAPI (research memo Section 5).\n *\n * Determinism matters because the browser Pixel call and the CAPI relay\n * call happen in parallel from the same user action - if the IDs don't\n * match, Snap counts the event twice.\n *\n * Contract:\n * - Same `(eventName, primaryKey, minuteBucket)` always produces the\n * same ID.\n * - Different event names with the same primary key produce different\n * IDs (a `VIEW_CONTENT` and `ADD_CART` for the same product shouldn't\n * collide).\n * - The minute-bucket component keeps browser retries within the same\n * minute stable (both sides land on the same ID), but rotates the ID\n * for user actions in a subsequent minute so we don't accidentally\n * collapse two genuine events.\n */\n\nconst MS_PER_MINUTE = 60 * 1000\n\n/** Bucket a Unix millisecond timestamp into whole minutes. */\nexport function deriveMinuteBucket(nowMs: number): number {\n if (!Number.isFinite(nowMs)) return 0\n return Math.floor(nowMs / MS_PER_MINUTE)\n}\n\n/** Convenience wrapper for `deriveMinuteBucket(Date.now())`. */\nexport function minuteBucketNow(): number {\n return deriveMinuteBucket(Date.now())\n}\n\n/**\n * Sanitize a primary key for inclusion in an event id. Snap accepts\n * alphanumerics + `_` + `-`; anything else gets folded to `_` so a\n * merchant using URLs with query strings as page-view keys doesn't\n * produce malformed ids.\n */\nfunction safeKey(primaryKey: string): string {\n if (!primaryKey) return 'unknown'\n return primaryKey.replace(/[^a-zA-Z0-9_-]/g, '_')\n}\n\n/**\n * Mint a deterministic event id for `event_id` (CAPI) and\n * `client_dedup_id` (Pixel). See contract above.\n *\n * Callers that want a stable id across a longer window (e.g. tying two\n * page-view fires back to back to the same URL) can pin `minuteBucket` to\n * a well-known value; the default is `minuteBucketNow()`. For PURCHASE,\n * pin `minuteBucket` to a constant per order (recommend `0`) so a\n * failing browser fire that retries in a later minute still dedups\n * against the server event.\n */\nexport function makeEventId(\n eventName: SnapEventName,\n primaryKey: string,\n minuteBucket: number = minuteBucketNow(),\n): string {\n return `${eventName}_${safeKey(primaryKey)}_${minuteBucket}`\n}\n\n/**\n * Derivation helper for the PURCHASE event's 30-day dedup pair. Reuses\n * the Amboras order id as both `custom_data.order_id` (CAPI) and\n * `transaction_id` (Pixel) so Snap can dedup on the 30-day window even\n * if the 48h `event_id` window has expired.\n *\n * Returns `undefined` for non-PURCHASE events (encodes the \"PURCHASE\n * only\" leg of the dual-dedup scheme).\n */\nexport function deriveOrderIdForPurchase(\n eventName: SnapEventName,\n orderId: string | undefined,\n): string | undefined {\n if (eventName !== 'PURCHASE') return undefined\n if (typeof orderId !== 'string') return undefined\n const trimmed = orderId.trim()\n return trimmed ? trimmed : undefined\n}\n","'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { trackViewContent } from '../hooks/useSnapchatEvents'\nimport { normalizeCurrency, toSnapValue } from '../lib/currency'\n\nexport interface SnapViewContentProps {\n productId?: string\n productName?: string\n sku?: string\n /** Major-unit numeric price (already converted from Medusa's minor units by the slot host). */\n price?: number\n currency?: string\n}\n\n/**\n * Null-rendering component for the `pdpAnalytics` plugin slot.\n * Fires Snap `VIEW_CONTENT` on both browser (Pixel) and server (CAPI)\n * on PDP mount.\n *\n * Guarded by a productId ref so PDPs that swap variants without a full\n * remount don't fire once per prop tick - Snap counts double fires as\n * two events even when `client_dedup_id` matches (dedup is only across\n * browser vs server, not within the same channel).\n */\nexport function SnapViewContent({ productId, price, currency }: SnapViewContentProps): null {\n const lastProductId = useRef<string | null>(null)\n\n useEffect(() => {\n if (!productId || lastProductId.current === productId) return\n lastProductId.current = productId\n const normalizedCurrency = normalizeCurrency(currency)\n const value = toSnapValue(price, normalizedCurrency)\n trackViewContent(productId, {\n currency: normalizedCurrency,\n value,\n contentIds: [productId],\n numItems: 1,\n })\n }, [productId, price, currency])\n\n return null\n}\n","import type { SnapEventName, SnapEventPayload, SnapUserData, SnapCustomData } from '../types'\nimport { safeSnaptr } from '../lib/snap-pixel-loader'\nimport { makeEventId, minuteBucketNow, deriveOrderIdForPurchase } from '../lib/dedup'\n\n/**\n * Client-side dual-fire hooks for Snap. Every event flows two ways from\n * the same user action:\n *\n * 1. Browser pixel: `snaptr('track', <EVENT_NAME>, { ..., client_dedup_id })`\n * via the loaded `scevent.min.js`.\n * 2. Server-side CAPI: POST to the storefront proxy at\n * `/api/snapchat-ads/events` which enriches with\n * `client_ip_address` + `client_user_agent` and forwards to Medusa\n * `/store/snapchat-ads/capi`.\n *\n * Both sides carry the SAME `event_id` / `client_dedup_id` so Snap can\n * dedup within 48h. For PURCHASE only, both sides also share\n * `custom_data.order_id` / `transaction_id` for the 30-day dedup window\n * (research memo Section 5).\n *\n * Snap v3 wire caveats encoded here:\n * - Event names are UPPER_SNAKE_CASE (PAGE_VIEW / VIEW_CONTENT /\n * ADD_CART / START_CHECKOUT / PURCHASE).\n * - `value`, `item_price`, `quantity` are STRINGS in the CAPI payload.\n * The browser pixel is more lenient but we mirror the same string\n * serialization so the two sides stay symmetric and dedup diffs read\n * cleanly in logs.\n * - PII (`em`, `ph`, `madid`, `external_id`) is passed RAW from the\n * browser and hashed on the Medusa side by `sendSnapchatCapiEvent`.\n * The proxy strips raw PII before forwarding to Snap.\n *\n * All fires are non-throwing - a failed CAPI relay is logged, never\n * bubbled, so a merchant's storefront cannot break because Snap's edge\n * had a hiccup.\n */\n\nconst CAPI_PROXY_ENDPOINT = '/api/snapchat-ads/events'\n\nfunction currentUrl(): string {\n return typeof window !== 'undefined' ? window.location.href : ''\n}\n\n/**\n * Send a server-side Snap CAPI event via the storefront's proxy. Fire-\n * and-forget from the caller's perspective; internal errors are swallowed\n * because analytics loss is preferable to storefront breakage.\n *\n * Intentionally NOT gated on analytics consent - Snap CAPI operates on a\n * different legal basis (order-tracking legitimate interest) than the\n * browser pixel. The `SnapPixelProvider` handles browser-side consent\n * gating separately.\n */\nexport async function sendSnapchatCapiEvent(payload: SnapEventPayload): Promise<void> {\n try {\n await fetch(CAPI_PROXY_ENDPOINT, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch {\n // non-fatal\n }\n}\n\n/**\n * Fire PAGE_VIEW on both sides. The `SnapPixelProvider` already fires\n * this on mount + route change; this hook is exposed for callers that\n * want to trigger a page-view manually (e.g. modal opens counted as\n * page views).\n */\nexport function trackPageView(\n primaryKey: string,\n userData: SnapUserData = {},\n eventId?: string,\n): void {\n const eid = eventId ?? makeEventId('PAGE_VIEW', primaryKey, minuteBucketNow())\n safeSnaptr('track', 'PAGE_VIEW', { client_dedup_id: eid })\n void sendSnapchatCapiEvent({\n eventName: 'PAGE_VIEW',\n eventId: eid,\n eventSourceUrl: currentUrl(),\n userData,\n })\n}\n\nexport interface TrackViewContentOptions {\n currency?: string\n /** Major-unit value STRING (e.g. `\"10.50\"`). */\n value?: string\n /** Product / variant id passed to Snap as `content_ids`. */\n contentIds?: string[]\n /** Optional per-line breakdown. `item_price` + `quantity` are STRINGS. */\n contents?: Array<{ id: string; quantity: string; item_price?: string }>\n numItems?: number\n userData?: SnapUserData\n eventId?: string\n}\n\nexport function trackViewContent(productId: string, options: TrackViewContentOptions = {}): void {\n const eid = options.eventId ?? makeEventId('VIEW_CONTENT', productId, minuteBucketNow())\n const contentIds = options.contentIds ?? [productId]\n const customData: SnapCustomData = {\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n ...(contentIds.length ? { contentIds } : {}),\n ...(options.contents?.length ? { contents: options.contents } : {}),\n ...(typeof options.numItems === 'number' ? { numItems: options.numItems } : {}),\n }\n safeSnaptr('track', 'VIEW_CONTENT', {\n ...(contentIds.length ? { item_ids: contentIds } : {}),\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n client_dedup_id: eid,\n })\n void sendSnapchatCapiEvent({\n eventName: 'VIEW_CONTENT',\n eventId: eid,\n eventSourceUrl: currentUrl(),\n userData: options.userData ?? {},\n customData,\n })\n}\n\nexport interface TrackAddCartOptions {\n currency?: string\n /** Major-unit value STRING. */\n value?: string\n /** Product / variant ids. */\n contentIds?: string[]\n contents?: Array<{ id: string; quantity: string; item_price?: string }>\n /** Top-level `num_items` - number-typed per Snap docs. */\n numItems?: number\n userData?: SnapUserData\n eventId?: string\n}\n\nexport function trackAddCart(cartId: string, options: TrackAddCartOptions = {}): void {\n const eid = options.eventId ?? makeEventId('ADD_CART', cartId, minuteBucketNow())\n const customData: SnapCustomData = {\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n ...(options.contentIds?.length ? { contentIds: options.contentIds } : {}),\n ...(options.contents?.length ? { contents: options.contents } : {}),\n ...(typeof options.numItems === 'number' ? { numItems: options.numItems } : {}),\n }\n safeSnaptr('track', 'ADD_CART', {\n ...(options.contentIds?.length ? { item_ids: options.contentIds } : {}),\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n ...(typeof options.numItems === 'number' ? { number_items: options.numItems } : {}),\n client_dedup_id: eid,\n })\n void sendSnapchatCapiEvent({\n eventName: 'ADD_CART',\n eventId: eid,\n eventSourceUrl: currentUrl(),\n userData: options.userData ?? {},\n customData,\n })\n}\n\nexport interface TrackStartCheckoutOptions {\n currency?: string\n value?: string\n contentIds?: string[]\n contents?: Array<{ id: string; quantity: string; item_price?: string }>\n numItems?: number\n userData?: SnapUserData\n eventId?: string\n}\n\nexport function trackStartCheckout(cartId: string, options: TrackStartCheckoutOptions = {}): void {\n const eid = options.eventId ?? makeEventId('START_CHECKOUT', cartId, minuteBucketNow())\n const customData: SnapCustomData = {\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n ...(options.contentIds?.length ? { contentIds: options.contentIds } : {}),\n ...(options.contents?.length ? { contents: options.contents } : {}),\n ...(typeof options.numItems === 'number' ? { numItems: options.numItems } : {}),\n }\n safeSnaptr('track', 'START_CHECKOUT', {\n ...(options.contentIds?.length ? { item_ids: options.contentIds } : {}),\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n ...(typeof options.numItems === 'number' ? { number_items: options.numItems } : {}),\n client_dedup_id: eid,\n })\n void sendSnapchatCapiEvent({\n eventName: 'START_CHECKOUT',\n eventId: eid,\n eventSourceUrl: currentUrl(),\n userData: options.userData ?? {},\n customData,\n })\n}\n\nexport interface TrackPurchaseOptions {\n currency?: string\n value?: string\n contentIds?: string[]\n contents?: Array<{ id: string; quantity: string; item_price?: string }>\n numItems?: number\n userData?: SnapUserData\n /**\n * When present, pins `event_id` / `client_dedup_id` explicitly; otherwise\n * a stable id is derived from `(PURCHASE, orderId, 0)` - minute-bucket 0\n * so retries within a longer window still dedup against the server event.\n */\n eventId?: string\n}\n\n/**\n * PURCHASE gets the dual-dedup treatment:\n * - Top-level `event_id` / Pixel `client_dedup_id` shared for 48h window.\n * - `custom_data.order_id` / Pixel `transaction_id` shared for 30-day\n * window. Reuses the Amboras order id as both.\n */\nexport function trackPurchase(orderId: string, options: TrackPurchaseOptions = {}): void {\n // Pin minute-bucket to 0 for PURCHASE so a browser retry in a later\n // minute still lands on the same event_id as the initial server fire.\n const eid = options.eventId ?? makeEventId('PURCHASE', orderId, 0)\n const derivedOrderId = deriveOrderIdForPurchase('PURCHASE', orderId)\n const customData: SnapCustomData = {\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n ...(options.contentIds?.length ? { contentIds: options.contentIds } : {}),\n ...(options.contents?.length ? { contents: options.contents } : {}),\n ...(typeof options.numItems === 'number' ? { numItems: options.numItems } : {}),\n ...(derivedOrderId ? { orderId: derivedOrderId } : {}),\n }\n safeSnaptr('track', 'PURCHASE', {\n ...(options.contentIds?.length ? { item_ids: options.contentIds } : {}),\n ...(options.currency ? { currency: options.currency } : {}),\n ...(options.value !== undefined ? { value: options.value } : {}),\n ...(typeof options.numItems === 'number' ? { number_items: options.numItems } : {}),\n ...(derivedOrderId ? { transaction_id: derivedOrderId } : {}),\n client_dedup_id: eid,\n })\n void sendSnapchatCapiEvent({\n eventName: 'PURCHASE',\n eventId: eid,\n eventSourceUrl: currentUrl(),\n userData: options.userData ?? {},\n customData,\n })\n}\n","/**\n * Currency + amount serialization helpers for Snap Conversions API v3.\n *\n * The v3 wire spec types `value`, `item_price`, and `quantity` as STRINGS\n * (research memo caveat #3). Numeric-typed fields cause events to silently\n * drop or under-report - this was Pinterest T1's regression, don't repeat.\n * `num_items` is NUMBER-typed though; Snap's own docs are inconsistent here.\n *\n * Amounts are in MAJOR units (`\"10.50\"` INR, NOT `\"1050\"` paise). Snap does\n * NOT use Stripe's minor-unit convention.\n *\n * Medusa still stores amounts in minor units, so callers that source values\n * from Medusa need to divide before serializing. `toSnapValue` accepts a\n * major-unit number and returns the correctly-serialized string; the caller\n * owns the minor-to-major conversion (currency-aware). Amboras' upstream\n * slot components already do that conversion for meta-ads via `toMajorUnits`\n * from `../lib/currency`; the Snap slot components mirror that pattern and\n * call `toSnapValue` on the result.\n */\n\nconst ZERO_DECIMAL: readonly string[] = [\n 'BIF', 'CLP', 'DJF', 'GNF', 'ISK', 'JPY', 'KMF', 'KRW', 'PYG',\n 'RWF', 'UGX', 'UYI', 'VND', 'VUV', 'XAF', 'XOF', 'XPF',\n]\n\nconst THREE_DECIMAL: readonly string[] = ['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']\n\nfunction decimalsForCurrency(currency: string | undefined): number {\n if (!currency) return 2\n const code = currency.toUpperCase()\n if (ZERO_DECIMAL.includes(code)) return 0\n if (THREE_DECIMAL.includes(code)) return 3\n return 2\n}\n\n/**\n * Convert a raw Medusa minor-unit amount to the major-unit numeric value\n * (JPY-safe, KWD-safe). Returns `undefined` when the amount is not a finite\n * number so callers can decide whether to omit the field.\n */\nexport function toMajorUnits(minorAmount: number | undefined, currency: string | undefined): number | undefined {\n if (typeof minorAmount !== 'number' || !Number.isFinite(minorAmount)) return undefined\n const decimals = decimalsForCurrency(currency)\n if (decimals === 0) return minorAmount\n const factor = 10 ** decimals\n return minorAmount / factor\n}\n\n/**\n * Serialize a major-unit numeric value to the STRING shape Snap CAPI v3\n * expects. Currency-aware fixed-decimal formatting so we don't send\n * `\"10.5\"` when we mean `\"10.50\"` - Snap is lenient there but consistent\n * formatting makes dedup diffs easier to read in logs.\n *\n * Returns `undefined` for non-finite input so callers can omit the field.\n */\nexport function toSnapValue(majorAmount: number | undefined, currency: string | undefined): string | undefined {\n if (typeof majorAmount !== 'number' || !Number.isFinite(majorAmount)) return undefined\n const decimals = decimalsForCurrency(currency)\n return majorAmount.toFixed(decimals)\n}\n\n/**\n * Normalize a currency code to ISO 4217 3-letter uppercase. Returns\n * `undefined` when the input is falsy so callers can decide.\n */\nexport function normalizeCurrency(currency: string | undefined): string | undefined {\n if (!currency) return undefined\n const trimmed = currency.trim()\n if (!trimmed) return undefined\n return trimmed.toUpperCase()\n}\n\n/**\n * Quantity coercion for the v3 wire body. `quantity` per line item is\n * STRING-typed. `num_items` (top-level) is NUMBER-typed - use\n * `numItems` directly, this helper is for line items only.\n */\nexport function toSnapQuantity(quantity: number | undefined): string | undefined {\n if (typeof quantity !== 'number' || !Number.isFinite(quantity)) return undefined\n // Snap's docs show integer quantities; render without decimals.\n return String(Math.trunc(quantity))\n}\n","'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { trackAddCart } from '../hooks/useSnapchatEvents'\nimport { resolveBackendUrl, storeHeaders } from '../lib/backend'\nimport { normalizeCurrency, toMajorUnits, toSnapValue, toSnapQuantity } from '../lib/currency'\n\nexport interface SnapAddCartProps {\n cartId?: string\n itemCount?: number\n /** Kept for prop-shape compatibility with the plugin slot - not used directly. */\n total?: number\n currency?: string\n}\n\ninterface CartLineItem {\n variant_id?: string\n product_id?: string\n quantity?: number\n unit_price?: number\n}\n\ninterface FetchedCart {\n id?: string\n currency_code?: string\n items?: CartLineItem[]\n}\n\ninterface StoredSnapshot {\n cartId: string\n quantitiesByVariant: Record<string, number>\n}\n\nconst STORAGE_KEY = 'amboras_snap_cart_state_v1'\nconst DEDUPE_WINDOW_MS = 1500\n\n/**\n * Per-variant time-window dedup Map, pinned to `globalThis` so Next.js\n * Turbopack HMR reloads in dev preserve the state across module re-\n * imports. Prod has no HMR so this is a no-op there. Mirrors the\n * meta-ads pattern.\n */\nconst RECENT_FIRES: Map<string, number> = (() => {\n const KEY = '__amboras_snap_ads_recent_fires__'\n const g = globalThis as unknown as Record<string, unknown>\n const existing = g[KEY]\n if (existing instanceof Map) return existing as Map<string, number>\n const fresh = new Map<string, number>()\n g[KEY] = fresh\n return fresh\n})()\n\nfunction readStored(): StoredSnapshot | null {\n if (typeof window === 'undefined') return null\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY)\n return raw ? (JSON.parse(raw) as StoredSnapshot) : null\n } catch {\n return null\n }\n}\n\nfunction writeStored(snapshot: StoredSnapshot): void {\n if (typeof window === 'undefined') return\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(snapshot))\n } catch {\n // sessionStorage unavailable - non-fatal\n }\n}\n\nasync function fetchCart(cartId: string): Promise<FetchedCart | null> {\n const baseUrl = resolveBackendUrl()\n if (!baseUrl) return null\n try {\n const res = await fetch(\n `${baseUrl}/store/carts/${encodeURIComponent(cartId)}?fields=id,currency_code,*items`,\n { method: 'GET', headers: storeHeaders(), credentials: 'include' },\n )\n if (!res.ok) return null\n const json = (await res.json()) as { cart?: FetchedCart }\n return json.cart ?? null\n } catch {\n return null\n }\n}\n\nfunction withinDedupeWindow(variantId: string): boolean {\n const now = Date.now()\n const last = RECENT_FIRES.get(variantId)\n if (last && now - last < DEDUPE_WINDOW_MS) return true\n RECENT_FIRES.set(variantId, now)\n if (RECENT_FIRES.size > 50) {\n const cutoff = now - DEDUPE_WINDOW_MS * 4\n for (const [k, t] of RECENT_FIRES) {\n if (t < cutoff) RECENT_FIRES.delete(k)\n }\n }\n return false\n}\n\n/**\n * Null-rendering component for the `cartUpdate` plugin slot.\n * Fires Snap `ADD_CART` per newly-added variant, self-hydrating from\n * Medusa's `/store/carts/:id` so `value`/`currency` are always\n * authoritative. Per-variant sessionStorage baseline persists across\n * cart-drawer mount cycles; a 1.5s window dedup absorbs TanStack Query\n * refetch races.\n *\n * First-mount seed: on a fresh session with a hydrated cart (page\n * refresh loads a cart with N items already in it), the baseline is\n * seeded to the current cart state and NO events fire. Only subsequent\n * quantity increases fire events.\n *\n * Values are serialised to STRINGS per Snap v3 wire spec (research memo\n * caveat #3).\n */\nexport function SnapAddCart({ cartId, itemCount: _itemCount }: SnapAddCartProps): null {\n const previousCartId = useRef<string | null>(null)\n\n useEffect(() => {\n if (!cartId) return\n let cancelled = false\n\n void (async () => {\n const cart = await fetchCart(cartId)\n if (cancelled) return\n\n // Fetch failed - do NOT touch sessionStorage. Writing an empty\n // baseline here would cause the next successful fetch to fire\n // ADD_CART for every item in the cart.\n if (!cart) {\n previousCartId.current = cartId\n return\n }\n\n const items = Array.isArray(cart.items) ? cart.items : []\n const currency = normalizeCurrency(cart.currency_code)\n\n const currentMap: Record<string, number> = {}\n const unitPriceByVariant: Record<string, number | undefined> = {}\n const productIdByVariant: Record<string, string | undefined> = {}\n for (const it of items) {\n if (!it.variant_id) continue\n currentMap[it.variant_id] = (currentMap[it.variant_id] ?? 0) + (it.quantity ?? 0)\n unitPriceByVariant[it.variant_id] = it.unit_price ?? undefined\n productIdByVariant[it.variant_id] = it.product_id ?? undefined\n }\n\n // Baseline selection - three cases mirror meta-ads:\n // 1. sessionStorage has a snapshot for THIS cartId -> use it.\n // 2. Fresh session (previousCartId.current is null) and no\n // matching stored snapshot -> seed baseline = currentMap and\n // fire nothing.\n // 3. cartId changed mid-mount -> baseline is empty so the first\n // add on the new cart fires.\n const stored = readStored()\n const isFirstHydration = previousCartId.current === null\n let baseline: Record<string, number>\n if (stored && stored.cartId === cartId) {\n baseline = stored.quantitiesByVariant\n } else if (isFirstHydration) {\n baseline = currentMap\n } else {\n baseline = {}\n }\n previousCartId.current = cartId\n\n for (const [variantId, newQty] of Object.entries(currentMap)) {\n const oldQty = baseline[variantId] ?? 0\n const delta = newQty - oldQty\n if (delta <= 0) continue\n if (withinDedupeWindow(variantId)) continue\n\n const productId = productIdByVariant[variantId]\n const unitPriceMinor = unitPriceByVariant[variantId]\n const contentIds = productId ? [productId, variantId] : [variantId]\n const majorValue =\n typeof unitPriceMinor === 'number' && Number.isFinite(unitPriceMinor)\n ? toMajorUnits(unitPriceMinor * delta, currency)\n : undefined\n const valueStr = toSnapValue(majorValue, currency)\n const perItemMajor =\n typeof unitPriceMinor === 'number' && Number.isFinite(unitPriceMinor)\n ? toMajorUnits(unitPriceMinor, currency)\n : undefined\n const contents = productId\n ? [\n {\n id: productId,\n quantity: toSnapQuantity(delta) ?? String(delta),\n ...(perItemMajor !== undefined\n ? { item_price: toSnapValue(perItemMajor, currency) }\n : {}),\n },\n ]\n : []\n\n trackAddCart(cartId, {\n currency,\n value: valueStr,\n contentIds,\n contents: contents as Array<{ id: string; quantity: string; item_price?: string }>,\n numItems: delta,\n })\n }\n\n writeStored({ cartId, quantitiesByVariant: currentMap })\n })()\n\n return () => {\n cancelled = true\n }\n // `total` is intentionally NOT a dep - the effect self-fetches, so\n // recompute-only-total signals would trigger a wasted round-trip.\n }, [cartId, _itemCount])\n\n return null\n}\n","/**\n * Resolve the Medusa storefront base URL and publishable key from common\n * starter-template env shapes. Mirrors the pattern used by\n * @amboras-dev/meta-ads and @amboras-dev/pinterest so the plugin works\n * across storefront templates without a build-time config.\n */\nexport function resolveBackendUrl(): string {\n if (typeof process === 'undefined' || !process.env) return ''\n return (\n process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ??\n process.env.NEXT_PUBLIC_API_URL ??\n process.env.VITE_MEDUSA_BACKEND_URL ??\n ''\n )\n}\n\nexport function resolvePublishableKey(): string {\n if (typeof process === 'undefined' || !process.env) return ''\n return (\n process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ??\n process.env.NEXT_PUBLIC_PUBLISHABLE_KEY ??\n process.env.VITE_MEDUSA_PUBLISHABLE_KEY ??\n ''\n )\n}\n\nexport function resolveStoreEnvironmentId(): string {\n if (typeof process === 'undefined' || !process.env) return ''\n return process.env.NEXT_PUBLIC_STORE_ID ?? ''\n}\n\n/** Common headers for `/store/*` calls. Includes credentials-cookie support for auth reads. */\nexport function storeHeaders(): Record<string, string> {\n const key = resolvePublishableKey()\n const storeId = resolveStoreEnvironmentId()\n const headers: Record<string, string> = {}\n if (key) headers['x-publishable-api-key'] = key\n if (storeId) headers['X-Store-Environment-ID'] = storeId\n return headers\n}\n","'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { trackStartCheckout } from '../hooks/useSnapchatEvents'\nimport { resolveBackendUrl, storeHeaders } from '../lib/backend'\nimport { normalizeCurrency, toMajorUnits, toSnapValue, toSnapQuantity } from '../lib/currency'\n\nexport interface SnapStartCheckoutProps {\n cartId?: string\n itemCount?: number\n total?: number\n currency?: string\n}\n\ninterface CartLineItem {\n variant_id?: string\n product_id?: string\n quantity?: number\n unit_price?: number\n}\n\ninterface FetchedCart {\n id?: string\n currency_code?: string\n total?: number\n items?: CartLineItem[]\n}\n\nasync function fetchCart(cartId: string): Promise<FetchedCart | null> {\n const baseUrl = resolveBackendUrl()\n if (!baseUrl) return null\n try {\n const res = await fetch(\n `${baseUrl}/store/carts/${encodeURIComponent(cartId)}?fields=id,currency_code,total,*items`,\n { method: 'GET', headers: storeHeaders(), credentials: 'include' },\n )\n if (!res.ok) return null\n const json = (await res.json()) as { cart?: FetchedCart }\n return json.cart ?? null\n } catch {\n return null\n }\n}\n\nconst STORAGE_KEY = 'amboras_snap_start_checkout_seen'\n\nfunction readSeen(): Set<string> {\n if (typeof window === 'undefined') return new Set()\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY)\n if (!raw) return new Set()\n const parsed = JSON.parse(raw)\n return Array.isArray(parsed) ? new Set(parsed.filter((v) => typeof v === 'string')) : new Set()\n } catch {\n return new Set()\n }\n}\n\nfunction writeSeen(set: Set<string>): void {\n if (typeof window === 'undefined') return\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(Array.from(set).slice(-50)))\n } catch {\n // best-effort\n }\n}\n\n/**\n * Null-rendering component for the `checkoutStart` plugin slot.\n * Fires Snap `START_CHECKOUT` exactly once per cartId. SessionStorage\n * dedup so back-nav to the checkout page doesn't double-fire.\n *\n * Self-fetches the cart from Medusa so `value`/`currency` are correct\n * even when the merchant slot context is thin. The ref is set only\n * AFTER a successful dispatch so a StrictMode cleanup between effect-\n * run and fetch-complete does NOT poison the ref.\n */\nexport function SnapStartCheckout({ cartId, itemCount, total, currency }: SnapStartCheckoutProps): null {\n const fired = useRef<string | null>(null)\n\n useEffect(() => {\n if (!cartId) return\n if (fired.current === cartId) return\n const seen = readSeen()\n if (seen.has(cartId)) {\n fired.current = cartId\n return\n }\n\n let cancelled = false\n\n void (async () => {\n const cart = await fetchCart(cartId)\n if (cancelled) return\n\n let resolvedItems: CartLineItem[] = []\n let resolvedTotal = total\n let resolvedCurrency = currency\n let resolvedNumItems = itemCount ?? 0\n\n if (cart) {\n if (Array.isArray(cart.items)) resolvedItems = cart.items\n if (typeof cart.total === 'number' && resolvedTotal === undefined) resolvedTotal = cart.total\n if (typeof cart.currency_code === 'string' && !resolvedCurrency) resolvedCurrency = cart.currency_code\n resolvedNumItems = resolvedItems.reduce((sum, it) => sum + (it.quantity ?? 0), 0) || resolvedNumItems\n }\n\n const normalizedCurrency = normalizeCurrency(resolvedCurrency)\n const contentIds = resolvedItems\n .map((it) => it.product_id)\n .filter((id): id is string => typeof id === 'string' && id.length > 0)\n const contents = resolvedItems\n .filter((it) => it.product_id)\n .map((it) => ({\n id: it.product_id as string,\n quantity: toSnapQuantity(it.quantity ?? 1) ?? '1',\n ...(typeof it.unit_price === 'number'\n ? { item_price: toSnapValue(toMajorUnits(it.unit_price, normalizedCurrency), normalizedCurrency) }\n : {}),\n }))\n const majorValue = toMajorUnits(resolvedTotal, normalizedCurrency)\n const valueStr = toSnapValue(majorValue, normalizedCurrency)\n\n // Guard against garbage events - `num_items: 0` with empty\n // content_ids is worthless to Snap and would trip \"abnormal event\"\n // diagnostics.\n if (resolvedNumItems <= 0 && contentIds.length === 0) return\n\n trackStartCheckout(cartId, {\n currency: normalizedCurrency,\n value: valueStr,\n contentIds,\n contents: contents as Array<{ id: string; quantity: string; item_price?: string }>,\n numItems: resolvedNumItems,\n })\n\n fired.current = cartId\n seen.add(cartId)\n writeSeen(seen)\n })()\n\n return () => {\n cancelled = true\n }\n }, [cartId, itemCount, total, currency])\n\n return null\n}\n","'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { trackPurchase } from '../hooks/useSnapchatEvents'\nimport { resolveBackendUrl, storeHeaders } from '../lib/backend'\nimport { normalizeCurrency, toMajorUnits, toSnapValue, toSnapQuantity } from '../lib/currency'\nimport { makeEventId } from '../lib/dedup'\n\nexport interface SnapPurchaseProps {\n orderId?: string\n total?: number\n currency?: string\n itemCount?: number\n}\n\ninterface OrderLineItem {\n variant_id?: string\n product_id?: string\n quantity?: number\n unit_price?: number\n}\n\ninterface FetchedOrder {\n id?: string\n total?: number\n currency_code?: string\n items?: OrderLineItem[]\n}\n\nasync function fetchOrder(orderId: string): Promise<FetchedOrder | null> {\n const baseUrl = resolveBackendUrl()\n if (!baseUrl) return null\n try {\n const res = await fetch(\n `${baseUrl}/store/orders/${encodeURIComponent(orderId)}?fields=id,total,currency_code,*items`,\n { method: 'GET', headers: storeHeaders(), credentials: 'include' },\n )\n if (!res.ok) return null\n const json = (await res.json()) as { order?: FetchedOrder }\n return json.order ?? null\n } catch {\n return null\n }\n}\n\n/**\n * Null-rendering component for the `checkoutComplete` plugin slot.\n * Fires Snap `PURCHASE` exactly once per orderId. Dual-dedup semantics\n * per research memo Section 5:\n *\n * - Top-level `event_id` / Pixel `client_dedup_id` shared for 48h.\n * - `custom_data.order_id` / Pixel `transaction_id` shared for 30d.\n *\n * Both derive from the orderId directly so browser retries in a later\n * minute still line up with the server event.\n *\n * Primary path: self-fetch from `/store/orders/:id` and derive value +\n * currency + contentIds from the authoritative Medusa response\n * (currency-aware `toMajorUnits`, so JPY/KWD are correct).\n *\n * Fallback path (fetch failed): fire a MINIMAL browser PURCHASE using\n * the incoming `total` + `currency` props, log a dev warning, and rely\n * on Snap's dedup with the server-side `sendSnapchatCapiEvent` to\n * reconcile.\n *\n * Two-layer dedup mirrors meta-ads: `useRef` guards StrictMode double-\n * mount within the same instance; `sessionStorage` guards page refresh\n * + remount. Both are set only AFTER successful dispatch.\n */\nexport function SnapPurchase({ orderId, total, currency, itemCount: _itemCount }: SnapPurchaseProps): null {\n const fired = useRef<string | null>(null)\n\n useEffect(() => {\n if (!orderId) return\n if (fired.current === orderId) return\n const dedupeKey = `amboras_snap_purchase_${orderId}`\n try {\n if (typeof sessionStorage !== 'undefined' && sessionStorage.getItem(dedupeKey)) {\n fired.current = orderId\n return\n }\n } catch {\n // sessionStorage unavailable - proceed\n }\n\n let cancelled = false\n\n void (async () => {\n const order = await fetchOrder(orderId)\n if (cancelled) return\n\n const fetchSucceeded =\n !!order && typeof order.total === 'number' && !!order.currency_code\n\n let dispatched = false\n const eid = makeEventId('PURCHASE', orderId, 0)\n\n if (fetchSucceeded && order) {\n const normalizedCurrency = normalizeCurrency(order.currency_code)\n const resolvedItems = Array.isArray(order.items) ? order.items : []\n const contentIds = resolvedItems\n .map((it) => it.product_id)\n .filter((id): id is string => typeof id === 'string' && id.length > 0)\n const contents = resolvedItems\n .filter((it) => it.product_id)\n .map((it) => ({\n id: it.product_id as string,\n quantity: toSnapQuantity(it.quantity ?? 1) ?? '1',\n ...(typeof it.unit_price === 'number'\n ? { item_price: toSnapValue(toMajorUnits(it.unit_price, normalizedCurrency), normalizedCurrency) }\n : {}),\n }))\n\n const majorValue = toMajorUnits(order.total, normalizedCurrency)\n const valueStr = toSnapValue(majorValue, normalizedCurrency)\n if (valueStr !== undefined) {\n trackPurchase(orderId, {\n currency: normalizedCurrency,\n value: valueStr,\n contentIds,\n contents: contents as Array<{ id: string; quantity: string; item_price?: string }>,\n numItems: resolvedItems.reduce((sum, it) => sum + (it.quantity ?? 0), 0),\n eventId: eid,\n })\n dispatched = true\n }\n } else if (typeof total === 'number' && !!currency) {\n const normalizedCurrency = normalizeCurrency(currency)\n // Trust props as-is. Snap's server-side event from\n // `sendSnapchatCapiEvent` will supersede this during dedup if\n // the subscriber is healthy.\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line no-console\n console.warn(\n '[snapchat-ads] SnapPurchase: order fetch failed, firing minimal browser PURCHASE from merchant-supplied total/currency. content_ids unavailable in this branch. If your CAPI subscriber is healthy the server event will provide full attribution.',\n )\n }\n trackPurchase(orderId, {\n currency: normalizedCurrency,\n value: toSnapValue(total, normalizedCurrency),\n eventId: eid,\n })\n dispatched = true\n }\n\n if (!dispatched) return\n\n fired.current = orderId\n try {\n if (typeof sessionStorage !== 'undefined') sessionStorage.setItem(dedupeKey, '1')\n } catch {\n // best-effort\n }\n })()\n\n return () => {\n cancelled = true\n }\n }, [orderId, total, currency])\n\n return null\n}\n"],"mappings":"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","names":["useEffect","useRef","useRef","useEffect","useEffect","useRef","useRef","useEffect","useEffect","useRef","fetchCart","STORAGE_KEY","useRef","useEffect","useEffect","useRef","useRef","useEffect"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@amboras-dev/snapchat-ads",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Snap Pixel + Snap Conversions API v3 hooks for Amboras storefronts",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./slot-components": {
|
|
15
|
+
"types": "./dist/slot-components/index.d.ts",
|
|
16
|
+
"import": "./dist/slot-components/index.mjs",
|
|
17
|
+
"require": "./dist/slot-components/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./get-config": {
|
|
20
|
+
"types": "./dist/get-config.d.ts",
|
|
21
|
+
"import": "./dist/get-config.mjs",
|
|
22
|
+
"require": "./dist/get-config.js"
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"react": ">=18",
|
|
31
|
+
"next": ">=14"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"tsup": "^8.0.0",
|
|
35
|
+
"typescript": "^5.0.0",
|
|
36
|
+
"@types/react": "^18.0.0",
|
|
37
|
+
"@types/node": "^20.0.0"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"typecheck": "tsc --noEmit"
|
|
45
|
+
}
|
|
46
|
+
}
|