@appfunnel-dev/sdk 2.0.0-canary.1 → 2.0.0-canary.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/capabilities-7_hy5f5G.d.cts +114 -0
  2. package/dist/capabilities-7_hy5f5G.d.ts +114 -0
  3. package/dist/checkout-7Dy6IedP.d.ts +320 -0
  4. package/dist/checkout-Dz8cGkB_.d.cts +320 -0
  5. package/dist/chunk-AKO6XKXP.js +466 -0
  6. package/dist/chunk-AKO6XKXP.js.map +1 -0
  7. package/dist/chunk-CY4VBSMX.cjs +106 -0
  8. package/dist/chunk-CY4VBSMX.cjs.map +1 -0
  9. package/dist/chunk-JSRKA375.cjs +497 -0
  10. package/dist/chunk-JSRKA375.cjs.map +1 -0
  11. package/dist/chunk-LJYLGLFS.cjs +153 -0
  12. package/dist/chunk-LJYLGLFS.cjs.map +1 -0
  13. package/dist/chunk-M6U3FNRW.js +99 -0
  14. package/dist/chunk-M6U3FNRW.js.map +1 -0
  15. package/dist/chunk-YY375F2B.js +140 -0
  16. package/dist/chunk-YY375F2B.js.map +1 -0
  17. package/dist/driver-paddle.cjs +814 -0
  18. package/dist/driver-paddle.cjs.map +1 -0
  19. package/dist/driver-paddle.d.cts +10 -0
  20. package/dist/driver-paddle.d.ts +10 -0
  21. package/dist/driver-paddle.js +811 -0
  22. package/dist/driver-paddle.js.map +1 -0
  23. package/dist/driver-stripe.cjs +2253 -0
  24. package/dist/driver-stripe.cjs.map +1 -0
  25. package/dist/driver-stripe.d.cts +8 -0
  26. package/dist/driver-stripe.d.ts +8 -0
  27. package/dist/driver-stripe.js +2247 -0
  28. package/dist/driver-stripe.js.map +1 -0
  29. package/dist/index.cjs +1962 -811
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +183 -933
  32. package/dist/index.d.ts +183 -933
  33. package/dist/index.js +1683 -653
  34. package/dist/index.js.map +1 -1
  35. package/dist/manifest-Cr2y1op6.d.cts +814 -0
  36. package/dist/manifest-Cr2y1op6.d.ts +814 -0
  37. package/dist/manifest-entry.cjs +312 -0
  38. package/dist/manifest-entry.cjs.map +1 -0
  39. package/dist/manifest-entry.d.cts +209 -0
  40. package/dist/manifest-entry.d.ts +209 -0
  41. package/dist/manifest-entry.js +198 -0
  42. package/dist/manifest-entry.js.map +1 -0
  43. package/package.json +37 -4
package/dist/index.cjs CHANGED
@@ -1,10 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
4
- var reactDom = require('react-dom');
5
- var sonner = require('sonner');
3
+ var chunkJSRKA375_cjs = require('./chunk-JSRKA375.cjs');
4
+ var chunkLJYLGLFS_cjs = require('./chunk-LJYLGLFS.cjs');
5
+ var React = require('react');
6
+ var ReactDOM = require('react-dom');
7
+ var jsxRuntime = require('react/jsx-runtime');
6
8
 
7
- // src/state/namespaces.ts
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var React__default = /*#__PURE__*/_interopDefault(React);
12
+ var ReactDOM__default = /*#__PURE__*/_interopDefault(ReactDOM);
8
13
 
9
14
  // src/state/variableStore.ts
10
15
  var VariableStore = class {
@@ -258,8 +263,12 @@ function collectClickIds() {
258
263
  }
259
264
  function readCookie(name) {
260
265
  if (typeof document === "undefined") return void 0;
261
- const m = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
262
- return m ? decodeURIComponent(m[1]) : void 0;
266
+ try {
267
+ const m = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
268
+ return m ? decodeURIComponent(m[1]) : void 0;
269
+ } catch {
270
+ return void 0;
271
+ }
263
272
  }
264
273
  function buildAcquisition(context) {
265
274
  return {
@@ -272,41 +281,44 @@ function buildAcquisition(context) {
272
281
  }
273
282
  function buildContext(opts = {}) {
274
283
  const raw = detect();
275
- const now = opts.now ?? 0;
284
+ const now2 = opts.now ?? 0;
276
285
  const referrer = typeof document !== "undefined" ? document.referrer : "";
277
- const base2 = {
286
+ const base = {
278
287
  device: raw.device,
279
288
  browser: raw.browser,
280
289
  os: raw.os,
281
290
  locale: raw.locale,
282
291
  utm: collectUtm(),
283
292
  clickIds: collectClickIds(),
284
- page: { key: "", slug: "", index: 0, total: 0, progressPercentage: 0, startedAt: now },
285
- session: { id: opts.sessionId ?? null, startedAt: now, referrer },
293
+ page: { key: "", slug: "", index: 0, total: 0, progressPercentage: 0, startedAt: now2 },
294
+ session: { id: opts.sessionId ?? null, startedAt: now2, referrer },
286
295
  identity: { customerId: opts.customerId ?? null, visitorId: opts.visitorId ?? null },
287
296
  system: {
288
297
  funnelId: opts.funnelId ?? "",
289
298
  campaignId: opts.campaignId ?? "",
290
299
  mode: opts.mode ?? "live",
291
- now
300
+ now: now2
292
301
  }
293
302
  };
294
- if (!opts.overrides) return base2;
303
+ if (!opts.overrides) return base;
295
304
  return {
296
- ...base2,
305
+ ...base,
297
306
  ...opts.overrides,
298
- device: { ...base2.device, ...opts.overrides.device },
299
- browser: { ...base2.browser, ...opts.overrides.browser },
300
- os: { ...base2.os, ...opts.overrides.os },
301
- locale: { ...base2.locale, ...opts.overrides.locale },
302
- utm: { ...base2.utm, ...opts.overrides.utm },
303
- clickIds: { ...base2.clickIds, ...opts.overrides.clickIds },
304
- page: { ...base2.page, ...opts.overrides.page },
305
- session: { ...base2.session, ...opts.overrides.session },
306
- identity: { ...base2.identity, ...opts.overrides.identity },
307
- system: { ...base2.system, ...opts.overrides.system }
307
+ device: { ...base.device, ...opts.overrides.device },
308
+ browser: { ...base.browser, ...opts.overrides.browser },
309
+ os: { ...base.os, ...opts.overrides.os },
310
+ locale: { ...base.locale, ...opts.overrides.locale },
311
+ utm: { ...base.utm, ...opts.overrides.utm },
312
+ clickIds: { ...base.clickIds, ...opts.overrides.clickIds },
313
+ page: { ...base.page, ...opts.overrides.page },
314
+ session: { ...base.session, ...opts.overrides.session },
315
+ identity: { ...base.identity, ...opts.overrides.identity },
316
+ system: { ...base.system, ...opts.overrides.system }
308
317
  };
309
318
  }
319
+ function exposurePayload(experimentId, variant, version) {
320
+ return { experimentId, variant, ...version !== void 0 ? { version } : {} };
321
+ }
310
322
  var _eventIdCounter = 0;
311
323
  function newEventId() {
312
324
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
@@ -323,20 +335,20 @@ function createConsoleTracker(opts = {}) {
323
335
  setAcquisition: (acq) => log("acquisition", acq)
324
336
  };
325
337
  }
326
- var TrackerContext = react.createContext(null);
338
+ var TrackerContext = React.createContext(null);
327
339
  function TrackerProvider({
328
340
  tracker,
329
341
  children
330
342
  }) {
331
- return react.createElement(TrackerContext.Provider, { value: tracker }, children);
343
+ return React.createElement(TrackerContext.Provider, { value: tracker }, children);
332
344
  }
333
345
  function useTrackerRef() {
334
- return react.useContext(TrackerContext) ?? FALLBACK;
346
+ return React.useContext(TrackerContext) ?? FALLBACK;
335
347
  }
336
348
  var FALLBACK = createConsoleTracker({ silent: true });
337
349
  function useTracker() {
338
350
  const tracker = useTrackerRef();
339
- const track = react.useCallback(
351
+ const track = React.useCallback(
340
352
  (event, data, userData) => tracker.track(event, data, userData),
341
353
  [tracker]
342
354
  );
@@ -345,7 +357,7 @@ function useTracker() {
345
357
 
346
358
  // src/tracking/bus.ts
347
359
  var MAX_HISTORY = 250;
348
- function createBus(accessors, now = () => Date.now()) {
360
+ function createBus(accessors, now2 = () => Date.now()) {
349
361
  const listeners = /* @__PURE__ */ new Map();
350
362
  const events = [];
351
363
  const on = (event, cb) => {
@@ -358,7 +370,7 @@ function createBus(accessors, now = () => Date.now()) {
358
370
  listeners.get(event)?.delete(cb);
359
371
  };
360
372
  const emit = (event, data) => {
361
- events.push({ event, data, ts: now() });
373
+ events.push({ event, data, ts: now2() });
362
374
  if (events.length > MAX_HISTORY) events.shift();
363
375
  for (const cb of listeners.get(event) ?? []) {
364
376
  try {
@@ -413,21 +425,6 @@ function attachBus(bus) {
413
425
  if (window.appfunnel === api) delete window.appfunnel;
414
426
  };
415
427
  }
416
- var RTL_LANGS = /* @__PURE__ */ new Set(["ar", "he", "fa", "ur", "ps", "sd", "dv", "yi"]);
417
- function isRtl(locale) {
418
- return RTL_LANGS.has(locale.split("-")[0]);
419
- }
420
- var base = (l) => l?.split("-")[0];
421
- function resolveLocale(config, detected, override) {
422
- const supported = config?.supported ?? (config?.default ? [config.default] : ["en"]);
423
- const def = config?.default ?? supported[0] ?? "en";
424
- const pick = (l) => {
425
- if (!l) return void 0;
426
- if (supported.includes(l)) return l;
427
- return supported.find((s) => base(s) === base(l));
428
- };
429
- return pick(override) ?? pick(detected) ?? def;
430
- }
431
428
  function interpolate(str, params) {
432
429
  if (!params) return str;
433
430
  return str.replace(/\{\{(\w+)\}\}/g, (_, k) => k in params ? String(params[k]) : `{{${k}}}`);
@@ -447,7 +444,7 @@ function devWarn(message) {
447
444
  } catch {
448
445
  }
449
446
  }
450
- var LocaleContext = react.createContext(null);
447
+ var LocaleContext = React.createContext(null);
451
448
  function LocaleProvider({
452
449
  config,
453
450
  catalog = {},
@@ -455,26 +452,29 @@ function LocaleProvider({
455
452
  override,
456
453
  children
457
454
  }) {
458
- const [locale, setLocale] = react.useState(() => resolveLocale(config, detected, override));
459
- const value = react.useMemo(
455
+ const [locale, setLocale] = React.useState(() => chunkJSRKA375_cjs.resolveLocale(config, detected, override));
456
+ React.useEffect(() => {
457
+ setLocale(chunkJSRKA375_cjs.resolveLocale(config, detected, override));
458
+ }, [config, detected, override]);
459
+ const value = React.useMemo(
460
460
  () => ({ locale, setLocale, config, catalog }),
461
461
  [locale, config, catalog]
462
462
  );
463
- return react.createElement(LocaleContext.Provider, { value }, children);
463
+ return React.createElement(LocaleContext.Provider, { value }, children);
464
464
  }
465
465
  function useActiveLocale() {
466
- return react.useContext(LocaleContext)?.locale ?? "en";
466
+ return React.useContext(LocaleContext)?.locale ?? "en";
467
467
  }
468
468
  function useTranslation() {
469
- const ctx = react.useContext(LocaleContext);
469
+ const ctx = React.useContext(LocaleContext);
470
470
  if (!ctx) throw new Error("useTranslation must be used inside <FunnelProvider>");
471
471
  const { locale, setLocale, config, catalog } = ctx;
472
- const chain = react.useMemo(() => {
472
+ const chain = React.useMemo(() => {
473
473
  const def = config?.default;
474
474
  const fb = config?.fallback;
475
475
  return Array.from(new Set([locale, fb, def].filter(Boolean)));
476
476
  }, [locale, config]);
477
- const t = react.useMemo(() => {
477
+ const t = React.useMemo(() => {
478
478
  const fn = ((key, params) => {
479
479
  const raw = lookup(catalog, chain, key);
480
480
  if (raw === void 0) {
@@ -484,17 +484,40 @@ function useTranslation() {
484
484
  return interpolate(raw, params);
485
485
  });
486
486
  fn.plural = (n, forms, params) => {
487
- const rule = new Intl.PluralRules(locale).select(n);
487
+ let rule;
488
+ try {
489
+ rule = new Intl.PluralRules(locale).select(n);
490
+ } catch {
491
+ rule = "other";
492
+ }
488
493
  const form = forms[rule] ?? forms.other ?? "";
489
494
  return interpolate(form.replace(/#/g, String(n)), params);
490
495
  };
491
496
  return fn;
492
497
  }, [catalog, chain, locale]);
493
- const fmt = react.useMemo(
498
+ const fmt = React.useMemo(
494
499
  () => ({
495
- number: (n, opts) => new Intl.NumberFormat(locale, opts).format(n),
496
- date: (d, opts) => new Intl.DateTimeFormat(locale, opts).format(d),
497
- percent: (n, opts) => new Intl.NumberFormat(locale, { style: "percent", ...opts }).format(n)
500
+ number: (n, opts) => {
501
+ try {
502
+ return new Intl.NumberFormat(locale, opts).format(n);
503
+ } catch {
504
+ return String(n);
505
+ }
506
+ },
507
+ date: (d, opts) => {
508
+ try {
509
+ return new Intl.DateTimeFormat(locale, opts).format(d);
510
+ } catch {
511
+ return String(d instanceof Date ? d.toISOString() : d);
512
+ }
513
+ },
514
+ percent: (n, opts) => {
515
+ try {
516
+ return new Intl.NumberFormat(locale, { style: "percent", ...opts }).format(n);
517
+ } catch {
518
+ return `${(n * 100).toFixed(0)}%`;
519
+ }
520
+ }
498
521
  }),
499
522
  [locale]
500
523
  );
@@ -503,336 +526,41 @@ function useTranslation() {
503
526
  fmt,
504
527
  locale,
505
528
  setLocale,
506
- dir: isRtl(locale) ? "rtl" : "ltr",
529
+ dir: chunkJSRKA375_cjs.isRtl(locale) ? "rtl" : "ltr",
507
530
  locales: config?.supported ?? [locale]
508
531
  };
509
532
  }
510
533
 
511
534
  // src/commerce/catalog.ts
512
- var PERIOD_DAYS = {
513
- day: 1,
514
- week: 7,
515
- month: 30,
516
- year: 365,
517
- one_time: 0
518
- };
519
- function periodDays(interval, count) {
520
- return PERIOD_DAYS[interval] * count;
521
- }
522
- function intervalLabel(interval, count) {
523
- if (interval === "one_time") return { period: "one-time", periodly: "one-time" };
524
- if (interval === "month" && count === 3) return { period: "quarter", periodly: "quarterly" };
525
- if (interval === "month" && count === 6) return { period: "6 months", periodly: "semiannually" };
526
- if (interval === "week" && count === 2) return { period: "2 weeks", periodly: "biweekly" };
527
- if (count === 1) {
528
- const periodly = { day: "daily", week: "weekly", month: "monthly", year: "yearly" }[interval];
529
- return { period: interval, periodly };
530
- }
531
- return { period: `${count} ${interval}s`, periodly: `every ${count} ${interval}s` };
532
- }
533
- function resolveProduct(input) {
534
- const interval = input.interval ?? "one_time";
535
- const count = input.intervalCount ?? 1;
536
- const days = periodDays(interval, count);
537
- const perDayMinor = days > 0 ? input.amount / days : input.amount;
538
- const label = intervalLabel(interval, count);
539
- return {
540
- id: input.id,
541
- name: input.name ?? input.id,
542
- displayName: input.displayName ?? input.name ?? input.id,
543
- provider: input.provider ?? "stripe",
544
- currency: input.currency,
545
- priceMinor: input.amount,
546
- perDayMinor,
547
- perWeekMinor: perDayMinor * 7,
548
- perMonthMinor: perDayMinor * 30,
549
- perYearMinor: perDayMinor * 365,
550
- period: label.period,
551
- periodly: label.periodly,
552
- hasTrial: (input.trialDays ?? 0) > 0,
553
- trialDays: input.trialDays ?? 0,
554
- trialMinor: input.trialAmount ?? 0
555
- };
556
- }
557
- function buildCatalog(inputs) {
558
- return new Map(inputs.map((i) => [i.id, resolveProduct(i)]));
559
- }
560
- function formatMoney(minor, currency, locale) {
561
- const amount = minor / 100;
562
- const code = currency.toUpperCase();
563
- let formatted;
564
- try {
565
- formatted = new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(amount);
566
- } catch {
567
- formatted = `${code} ${amount.toFixed(2)}`;
568
- }
569
- return { amount, minor, currency: code, formatted };
570
- }
571
- function formatProduct(r, locale) {
572
- const m = (minor) => formatMoney(minor, r.currency, locale);
573
- return {
574
- id: r.id,
575
- name: r.name,
576
- displayName: r.displayName,
577
- provider: r.provider,
578
- price: m(r.priceMinor),
579
- period: r.period,
580
- periodly: r.periodly,
581
- perDay: m(r.perDayMinor),
582
- perWeek: m(r.perWeekMinor),
583
- perMonth: m(r.perMonthMinor),
584
- perYear: m(r.perYearMinor),
585
- hasTrial: r.hasTrial,
586
- trialDays: r.trialDays,
587
- trialPrice: r.hasTrial ? m(r.trialMinor) : null
588
- };
589
- }
590
- var CatalogContext = react.createContext(null);
535
+ var CatalogContext = React.createContext(null);
591
536
  function CatalogProvider({
592
537
  catalog,
593
538
  children
594
539
  }) {
595
- return react.createElement(CatalogContext.Provider, { value: catalog }, children);
540
+ return React.createElement(CatalogContext.Provider, { value: catalog }, children);
596
541
  }
597
542
  function useCatalog() {
598
- return react.useContext(CatalogContext) ?? EMPTY;
543
+ return React.useContext(CatalogContext) ?? EMPTY;
599
544
  }
600
545
  var EMPTY = /* @__PURE__ */ new Map();
601
546
  function useProduct(id) {
602
547
  const catalog = useCatalog();
603
548
  const locale = useActiveLocale();
604
549
  const resolved = id ? catalog.get(id) : void 0;
605
- return react.useMemo(() => resolved ? formatProduct(resolved, locale) : void 0, [resolved, locale]);
550
+ return React.useMemo(() => resolved ? chunkJSRKA375_cjs.formatProduct(resolved, locale) : void 0, [resolved, locale]);
606
551
  }
607
552
  function useProducts() {
608
553
  const catalog = useCatalog();
609
554
  const locale = useActiveLocale();
610
- return react.useMemo(
611
- () => Array.from(catalog.values()).map((r) => formatProduct(r, locale)),
555
+ return React.useMemo(
556
+ () => Array.from(catalog.values()).map((r) => chunkJSRKA375_cjs.formatProduct(r, locale)),
612
557
  [catalog, locale]
613
558
  );
614
559
  }
615
-
616
- // src/flow/spine.ts
617
- function readField(s, field) {
618
- let cur = s;
619
- for (const part of field.split(".")) {
620
- if (cur == null) return void 0;
621
- cur = cur[part];
622
- }
623
- return cur;
624
- }
625
- function evaluateCondition(cond, s) {
626
- const val = readField(s, cond.field);
627
- const { op, value } = cond;
628
- switch (op) {
629
- case "eq":
630
- return val === value;
631
- case "neq":
632
- return val !== value;
633
- case "in":
634
- return Array.isArray(value) && value.includes(val);
635
- case "gt":
636
- return typeof val === "number" && typeof value === "number" && val > value;
637
- case "gte":
638
- return typeof val === "number" && typeof value === "number" && val >= value;
639
- case "lt":
640
- return typeof val === "number" && typeof value === "number" && val < value;
641
- case "lte":
642
- return typeof val === "number" && typeof value === "number" && val <= value;
643
- case "contains":
644
- if (typeof val === "string") return val.includes(String(value));
645
- if (Array.isArray(val)) return val.includes(value);
646
- return false;
647
- case "exists":
648
- return val !== void 0 && val !== null && val !== "";
649
- case "empty":
650
- return val === void 0 || val === null || val === "" || Array.isArray(val) && val.length === 0;
651
- default:
652
- return false;
653
- }
654
- }
655
- function evaluateGate(gate, s) {
656
- return typeof gate === "function" ? gate(s) : evaluateCondition(gate, s);
657
- }
658
- function resolveRoute(routes, s) {
659
- if (!routes) return void 0;
660
- for (const route of routes) {
661
- if (!route.when || evaluateGate(route.when, s)) return route.to;
662
- }
663
- return void 0;
664
- }
665
- function pageMeta(meta) {
666
- return meta;
667
- }
668
- var TYPE_GUARDS = {
669
- paywall: { field: "user.email", op: "exists" },
670
- upsell: { field: "user.email", op: "exists" }
671
- };
672
- function entryGuard(meta) {
673
- return meta?.guard ?? (meta?.type ? TYPE_GUARDS[meta.type] : void 0);
674
- }
675
- function definePage(component) {
676
- return component;
677
- }
678
- function nextPage(pages, currentKey, s) {
679
- const idx = pages.findIndex((p) => p.key === currentKey);
680
- if (idx === -1) return void 0;
681
- const routed = resolveRoute(pages[idx].meta?.next, s);
682
- if (routed) return routed;
683
- return pages[idx + 1]?.key;
684
- }
685
- function outgoingKeys(pages, currentKey) {
686
- const idx = pages.findIndex((p) => p.key === currentKey);
687
- if (idx === -1) return [];
688
- const out = /* @__PURE__ */ new Set();
689
- for (const route of pages[idx].meta?.next ?? []) out.add(route.to);
690
- const linear = pages[idx + 1]?.key;
691
- if (linear) out.add(linear);
692
- return [...out];
693
- }
694
- function expectedPathLength(pages, startKey, s) {
695
- const seen = /* @__PURE__ */ new Set();
696
- let key = startKey;
697
- let count = 0;
698
- while (key && !seen.has(key)) {
699
- seen.add(key);
700
- count++;
701
- if (pages.find((p) => p.key === key)?.meta?.type === "finish") break;
702
- key = nextPage(pages, key, s);
703
- }
704
- return count;
705
- }
706
- function defineFunnel(def) {
707
- return def;
708
- }
709
-
710
- // src/flow/experiments.ts
711
- function fnv1a(input) {
712
- let h = 2166136261;
713
- for (let i = 0; i < input.length; i++) {
714
- h ^= input.charCodeAt(i);
715
- h = h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) >>> 0;
716
- }
717
- return h >>> 0;
718
- }
719
- function hashToUnit(seed) {
720
- return fnv1a(seed) / 4294967296;
721
- }
722
- function pickByWeight(weights, u) {
723
- const entries = Object.entries(weights).filter(([, w]) => w > 0);
724
- if (entries.length === 0) return Object.keys(weights)[0] ?? "";
725
- const total = entries.reduce((sum, [, w]) => sum + w, 0);
726
- const target = u * total;
727
- let acc = 0;
728
- for (const [key, w] of entries) {
729
- acc += w;
730
- if (target < acc) return key;
731
- }
732
- return entries[entries.length - 1][0];
733
- }
734
- function assignVariant(experimentId, seed, weights) {
735
- return pickByWeight(weights, hashToUnit(`${experimentId}:${seed}`));
736
- }
737
- function bucketingSeed(context) {
738
- return context.identity.customerId ?? context.identity.visitorId ?? null;
739
- }
740
- function parseSlotKey(key) {
741
- const at = key.indexOf("@");
742
- return at === -1 ? { slot: key } : { slot: key.slice(0, at), variant: key.slice(at + 1) };
743
- }
744
- function isVariantKey(key) {
745
- return parseSlotKey(key).variant !== void 0;
746
- }
747
- function weightsOf(exp) {
748
- const out = {};
749
- for (const [label, v] of Object.entries(exp.variants)) out[label] = v.weight;
750
- return out;
751
- }
752
- function resolveExperiments(pages, experiments, seed) {
753
- const assignments = {};
754
- const render = {};
755
- const experimentOf = {};
756
- for (const exp of experiments) {
757
- const status = exp.status ?? "running";
758
- let label;
759
- if (status === "stopped" && exp.winner) label = exp.winner;
760
- else if (status === "running" && seed) label = assignVariant(exp.id, seed, weightsOf(exp));
761
- else continue;
762
- const arm = exp.variants[label];
763
- if (!arm) continue;
764
- assignments[exp.id] = label;
765
- experimentOf[exp.slot] = exp.id;
766
- if (arm.page !== exp.slot) render[exp.slot] = arm.page;
767
- }
768
- const slotOf = {};
769
- const activeKeys = [];
770
- for (const p of pages) {
771
- const { slot, variant } = parseSlotKey(p.key);
772
- if (variant !== void 0) slotOf[p.key] = slot;
773
- else activeKeys.push(p.key);
774
- }
775
- return { assignments, activeKeys, render, slotOf, experimentOf };
776
- }
777
- function validateExperiments(experiments, pages) {
778
- const errors = [];
779
- const warnings = [];
780
- const pageKeys = new Set(pages.map((p) => p.key));
781
- const seenIds = /* @__PURE__ */ new Set();
782
- const slotOwner = /* @__PURE__ */ new Map();
783
- const renderedVariantPages = /* @__PURE__ */ new Set();
784
- for (const exp of experiments) {
785
- const err = (code, message) => errors.push({ experimentId: exp.id, code, message });
786
- const warn = (code, message) => warnings.push({ experimentId: exp.id, code, message });
787
- if (seenIds.has(exp.id)) err("duplicate_id", `Experiment id "${exp.id}" is used more than once.`);
788
- seenIds.add(exp.id);
789
- if (!pageKeys.has(exp.slot)) err("slot_missing", `Slot "${exp.slot}" is not a page in the funnel.`);
790
- if (isVariantKey(exp.slot)) err("slot_is_variant", `Slot "${exp.slot}" is a variant page; a slot must be a real flow page.`);
791
- if (slotOwner.has(exp.slot)) {
792
- err("slot_conflict", `Slot "${exp.slot}" is already targeted by experiment "${slotOwner.get(exp.slot)}".`);
793
- } else {
794
- slotOwner.set(exp.slot, exp.id);
795
- }
796
- const arms = Object.entries(exp.variants);
797
- if (arms.length < 2) warn("single_arm", `Experiment "${exp.id}" has fewer than two variants \u2014 nothing to test.`);
798
- let hasControl = false;
799
- let totalWeight = 0;
800
- for (const [label, arm] of arms) {
801
- if (!pageKeys.has(arm.page)) {
802
- err("variant_page_missing", `Variant "${label}" references page "${arm.page}", which doesn't exist.`);
803
- }
804
- if (arm.page === exp.slot) hasControl = true;
805
- else if (isVariantKey(arm.page)) {
806
- renderedVariantPages.add(arm.page);
807
- if (parseSlotKey(arm.page).slot !== exp.slot) {
808
- err("variant_slot_mismatch", `Variant "${label}" page "${arm.page}" belongs to a different slot than "${exp.slot}".`);
809
- }
810
- }
811
- if (arm.weight < 0) err("negative_weight", `Variant "${label}" has a negative weight (${arm.weight}).`);
812
- totalWeight += arm.weight;
813
- }
814
- if (!hasControl) err("no_control", `No variant of "${exp.id}" renders the slot "${exp.slot}" itself (the control/baseline).`);
815
- if (totalWeight <= 0) err("no_traffic", `Experiment "${exp.id}" has no positive weight \u2014 no traffic would enter it.`);
816
- if (exp.status === "stopped" && exp.winner && !exp.variants[exp.winner]) {
817
- err("bad_winner", `Stopped experiment "${exp.id}" names winner "${exp.winner}", which isn't one of its variants.`);
818
- }
819
- }
820
- const running = new Set(experiments.filter((e) => (e.status ?? "running") === "running").flatMap(
821
- (e) => Object.values(e.variants).map((v) => v.page)
822
- ));
823
- for (const p of pages) {
824
- if (isVariantKey(p.key) && !running.has(p.key)) {
825
- warnings.push({ experimentId: "*", code: "orphan_variant", message: `Variant page "${p.key}" is rendered by no running experiment.` });
826
- }
827
- }
828
- return { ok: errors.length === 0, errors, warnings };
829
- }
830
-
831
- // src/flow/flow.tsx
832
- var NavContext = react.createContext(null);
833
- var ExperimentContext = react.createContext({});
560
+ var NavContext = React.createContext(null);
561
+ var ExperimentContext = React.createContext({});
834
562
  function useExperiment(id) {
835
- return react.useContext(ExperimentContext)[id];
563
+ return React.useContext(ExperimentContext)[id];
836
564
  }
837
565
  function pageContextFor(currentKey, slug, index, total, startedAt) {
838
566
  const denom = Math.max(total, index + 1);
@@ -845,6 +573,39 @@ function pageContextFor(currentKey, slug, index, total, startedAt) {
845
573
  startedAt
846
574
  };
847
575
  }
576
+ var now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
577
+ function usePageExitTimer(tracker, currentKey) {
578
+ const timer = React.useRef(null);
579
+ const emitExit = React.useCallback(() => {
580
+ const t = timer.current;
581
+ if (!t) return;
582
+ const at = now();
583
+ const hidden = t.hidden + (t.hiddenSince != null ? at - t.hiddenSince : 0);
584
+ const durationMs = Math.round(at - t.enteredAt);
585
+ tracker.track("page.exit", { pageId: t.key, durationMs, activeMs: Math.max(0, Math.round(durationMs - hidden)) });
586
+ }, [tracker]);
587
+ React.useEffect(() => {
588
+ if (typeof document === "undefined") return;
589
+ const onVis = () => {
590
+ const t = timer.current;
591
+ if (!t) return;
592
+ if (document.visibilityState === "hidden") t.hiddenSince = now();
593
+ else if (t.hiddenSince != null) {
594
+ t.hidden += now() - t.hiddenSince;
595
+ t.hiddenSince = null;
596
+ }
597
+ };
598
+ document.addEventListener("visibilitychange", onVis);
599
+ return () => document.removeEventListener("visibilitychange", onVis);
600
+ }, []);
601
+ React.useEffect(() => {
602
+ if (!currentKey) return;
603
+ if (timer.current && timer.current.key !== currentKey) emitExit();
604
+ const hidden = typeof document !== "undefined" && document.visibilityState === "hidden";
605
+ timer.current = { key: currentKey, enteredAt: now(), hidden: 0, hiddenSince: hidden ? now() : null };
606
+ }, [currentKey, emitExit]);
607
+ React.useEffect(() => () => emitExit(), [emitExit]);
608
+ }
848
609
  function FunnelView({
849
610
  pages,
850
611
  initialKey,
@@ -855,141 +616,118 @@ function FunnelView({
855
616
  }) {
856
617
  const funnel = useFunnel();
857
618
  const tracker = useTrackerRef();
858
- const components = react.useMemo(() => {
619
+ const components = React.useMemo(() => {
859
620
  const map = /* @__PURE__ */ new Map();
860
621
  for (const p of pages) {
861
622
  if (p.Component) map.set(p.key, p.Component);
862
623
  else if (p.load) {
863
624
  const load = p.load;
864
- map.set(p.key, react.lazy(() => Promise.resolve(load()).then(
625
+ map.set(p.key, React.lazy(() => Promise.resolve(load()).then(
865
626
  (m) => typeof m === "function" ? { default: m } : m
866
627
  )));
867
628
  }
868
629
  }
869
630
  return map;
870
631
  }, [pages]);
871
- const loaders = react.useMemo(
632
+ const loaders = React.useMemo(
872
633
  () => new Map(pages.filter((p) => p.load).map((p) => [p.key, p.load])),
873
634
  [pages]
874
635
  );
875
- const seed = bucketingSeed(funnel.context);
876
- const experiments = react.useMemo(
877
- () => resolveExperiments(pages, funnel.experiments, seed),
636
+ const seedRef = React.useRef(null);
637
+ if (seedRef.current === null) seedRef.current = chunkJSRKA375_cjs.bucketingSeed(funnel.context);
638
+ const seed = seedRef.current;
639
+ const experiments = React.useMemo(
640
+ () => chunkJSRKA375_cjs.resolveExperiments(pages, funnel.experiments, seed),
878
641
  [pages, funnel.experiments, seed]
879
642
  );
880
- const pageByKey = react.useMemo(() => new Map(pages.map((p) => [p.key, p])), [pages]);
881
- const flowPages = react.useMemo(
882
- () => experiments.activeKeys.map((k) => pageByKey.get(k)).filter(Boolean),
643
+ const toSlot = React.useCallback((k) => experiments.slotOf[k] ?? k, [experiments]);
644
+ const toRenderKey = React.useCallback((k) => experiments.render[k] ?? k, [experiments]);
645
+ const pageByKey = React.useMemo(() => new Map(pages.map((p) => [p.key, p])), [pages]);
646
+ const flowPages = React.useMemo(
647
+ () => experiments.activeKeys.map((k) => pageByKey.get(k)).filter((p) => p !== void 0),
883
648
  [experiments, pageByKey]
884
649
  );
885
- const flow = react.useMemo(
650
+ const flow = React.useMemo(
886
651
  () => flowPages.map((p) => ({ key: p.key, meta: p.meta })),
887
652
  [flowPages]
888
653
  );
889
- const [history, setHistory] = react.useState(() => {
654
+ const [history, setHistory] = React.useState(() => {
890
655
  const start = flowPages[0]?.key;
891
- if (!initialKey || initialKey === start) return [start].filter(Boolean);
892
- const target = experiments.slotOf[initialKey] ?? initialKey;
656
+ if (!initialKey || initialKey === start) return start ? [start] : [];
657
+ const target = toSlot(initialKey);
893
658
  const page2 = flowPages.find((p) => p.key === target);
894
- const guard = entryGuard(page2?.meta);
895
- const ok = page2 && (!guard || evaluateGate(guard, funnel.snapshot()));
896
- return [ok ? target : start].filter(Boolean);
659
+ const guard = chunkJSRKA375_cjs.entryGuard(page2?.meta);
660
+ const ok = page2 && (!guard || chunkJSRKA375_cjs.evaluateGate(guard, funnel.snapshot()));
661
+ const first = ok ? target : start;
662
+ return first ? [first] : [];
897
663
  });
898
664
  const currentKey = history[history.length - 1];
899
665
  const index = history.length - 1;
900
666
  const startKey = history[0];
901
- const total = react.useMemo(
902
- () => expectedPathLength(flow, startKey, funnel.snapshot()),
667
+ const total = React.useMemo(
668
+ () => chunkJSRKA375_cjs.expectedPathLength(flow, startKey, funnel.snapshot()),
903
669
  // currentKey in deps: re-trace as each step's answers settle the branch.
904
670
  [flow, startKey, currentKey, funnel]
905
671
  );
906
672
  const slug = pageByKey.get(currentKey)?.meta?.slug ?? currentKey;
907
- const page = react.useMemo(
673
+ const page = React.useMemo(
908
674
  () => pageContextFor(currentKey, slug, index, total, funnel.context.system.now),
909
675
  [currentKey, slug, index, total, funnel.context.system.now]
910
676
  );
911
- funnel.context.page = page;
912
- const started = react.useRef(false);
913
- react.useEffect(() => {
677
+ React.useEffect(() => {
678
+ funnel.context.page = page;
679
+ }, [funnel, page]);
680
+ const started = React.useRef(false);
681
+ React.useEffect(() => {
914
682
  if (started.current) return;
915
683
  started.current = true;
916
684
  tracker.track("funnel.start", {});
917
685
  }, [tracker]);
918
- react.useEffect(() => {
686
+ React.useEffect(() => {
919
687
  if (!currentKey) return;
920
688
  tracker.track("page.view", { pageId: currentKey, pageKey: currentKey, isInitial: index === 0, eventId: newEventId() });
921
689
  }, [tracker, currentKey, index]);
922
- react.useEffect(() => {
690
+ React.useEffect(() => {
923
691
  if (currentKey && onNavigate) onNavigate(currentKey, slug);
924
692
  }, [onNavigate, currentKey, slug]);
925
- const exposed = react.useRef(/* @__PURE__ */ new Set());
926
- react.useEffect(() => {
693
+ const exposed = React.useRef(/* @__PURE__ */ new Set());
694
+ React.useEffect(() => {
927
695
  const expId = experiments.experimentOf[currentKey];
928
696
  if (!expId || exposed.current.has(expId)) return;
929
697
  exposed.current.add(expId);
930
- tracker.track("experiment.exposure", { experimentId: expId, variant: experiments.assignments[expId] });
698
+ tracker.track("experiment.exposure", exposurePayload(expId, experiments.assignments[expId], experiments.versionOf[expId]));
931
699
  }, [tracker, currentKey, experiments]);
932
- const timer = react.useRef(null);
933
- const now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
934
- const emitExit = react.useCallback(() => {
935
- const t = timer.current;
936
- if (!t) return;
937
- const at = now();
938
- const hidden = t.hidden + (t.hiddenSince != null ? at - t.hiddenSince : 0);
939
- const durationMs = Math.round(at - t.enteredAt);
940
- tracker.track("page.exit", { pageId: t.key, durationMs, activeMs: Math.max(0, Math.round(durationMs - hidden)) });
941
- }, [tracker]);
942
- react.useEffect(() => {
943
- if (typeof document === "undefined") return;
944
- const onVis = () => {
945
- const t = timer.current;
946
- if (!t) return;
947
- if (document.visibilityState === "hidden") t.hiddenSince = now();
948
- else if (t.hiddenSince != null) {
949
- t.hidden += now() - t.hiddenSince;
950
- t.hiddenSince = null;
951
- }
952
- };
953
- document.addEventListener("visibilitychange", onVis);
954
- return () => document.removeEventListener("visibilitychange", onVis);
955
- }, []);
956
- react.useEffect(() => {
957
- if (!currentKey) return;
958
- if (timer.current && timer.current.key !== currentKey) emitExit();
959
- const hidden = typeof document !== "undefined" && document.visibilityState === "hidden";
960
- timer.current = { key: currentKey, enteredAt: now(), hidden: 0, hiddenSince: hidden ? now() : null };
961
- }, [currentKey, emitExit]);
962
- react.useEffect(() => () => emitExit(), [emitExit]);
963
- const [isNavigating, startNav] = react.useTransition();
964
- const next = react.useCallback(() => {
965
- const target = nextPage(flow, currentKey, funnel.snapshot());
966
- const resolved = target ? experiments.slotOf[target] ?? target : target;
700
+ usePageExitTimer(tracker, currentKey);
701
+ const [isNavigating, startNav] = React.useTransition();
702
+ const next = React.useCallback(() => {
703
+ const target = chunkJSRKA375_cjs.nextPage(flow, currentKey, funnel.snapshot());
704
+ const resolved = target ? toSlot(target) : target;
967
705
  if (resolved) startNav(() => setHistory((h) => [...h, resolved]));
968
- }, [flow, currentKey, funnel, experiments]);
969
- const back = react.useCallback(
706
+ }, [flow, currentKey, funnel, toSlot]);
707
+ const back = React.useCallback(
970
708
  () => startNav(() => setHistory((h) => h.length > 1 ? h.slice(0, -1) : h)),
971
709
  []
972
710
  );
973
- const go = react.useCallback(
974
- (key) => startNav(() => setHistory((h) => [...h, experiments.slotOf[key] ?? key])),
975
- [experiments]
711
+ const go = React.useCallback(
712
+ (key) => startNav(() => setHistory((h) => [...h, toSlot(key)])),
713
+ [toSlot]
976
714
  );
977
- const prefetched = react.useRef(/* @__PURE__ */ new Set());
978
- const prefetch = react.useCallback(
715
+ const prefetched = React.useRef(/* @__PURE__ */ new Set());
716
+ const prefetch = React.useCallback(
979
717
  (key) => {
980
- const target = experiments.render[key] ?? key;
718
+ const target = toRenderKey(key);
981
719
  const load = loaders.get(target);
982
720
  if (!load || prefetched.current.has(target)) return;
983
721
  prefetched.current.add(target);
984
722
  load().catch(() => prefetched.current.delete(target));
985
723
  },
986
- [loaders, experiments]
724
+ [loaders, toRenderKey]
987
725
  );
988
- const nextCandidates = react.useMemo(
989
- () => [...new Set(outgoingKeys(flow, currentKey).map((k) => experiments.render[k] ?? k))],
990
- [flow, currentKey, experiments]
726
+ const nextCandidates = React.useMemo(
727
+ () => [...new Set(chunkJSRKA375_cjs.outgoingKeys(flow, currentKey).map(toRenderKey))],
728
+ [flow, currentKey, toRenderKey]
991
729
  );
992
- react.useEffect(() => {
730
+ React.useEffect(() => {
993
731
  if (prefetchMode !== "auto") return;
994
732
  for (const key of nextCandidates) prefetch(key);
995
733
  }, [prefetchMode, nextCandidates, prefetch]);
@@ -1003,18 +741,18 @@ function FunnelView({
1003
741
  canGoBack: history.length > 1,
1004
742
  isNavigating
1005
743
  };
1006
- const renderKey = experiments.render[currentKey] ?? currentKey;
744
+ const renderKey = toRenderKey(currentKey);
1007
745
  const Current = components.get(renderKey);
1008
- const pageEl = react.createElement(react.Suspense, { fallback: fallback ?? null }, Current ? react.createElement(Current) : null);
1009
- const content = layout ? react.createElement(layout, null, pageEl) : pageEl;
1010
- return react.createElement(
746
+ const pageEl = React.createElement(React.Suspense, { fallback: fallback ?? null }, Current ? React.createElement(Current) : null);
747
+ const content = layout ? React.createElement(layout, null, pageEl) : pageEl;
748
+ return React.createElement(
1011
749
  ExperimentContext.Provider,
1012
750
  { value: experiments.assignments },
1013
- react.createElement(NavContext.Provider, { value }, content)
751
+ React.createElement(NavContext.Provider, { value }, content)
1014
752
  );
1015
753
  }
1016
754
  function useNavigation() {
1017
- const ctx = react.useContext(NavContext);
755
+ const ctx = React.useContext(NavContext);
1018
756
  if (!ctx) throw new Error("useNavigation must be used inside <FunnelView>");
1019
757
  return ctx;
1020
758
  }
@@ -1023,16 +761,22 @@ function usePage() {
1023
761
  }
1024
762
  var symModalId = /* @__PURE__ */ Symbol("AppFunnelModalId");
1025
763
  var initialState = {};
1026
- var ModalStateContext = react.createContext(initialState);
1027
- var ModalIdContext = react.createContext(null);
764
+ var ModalStateContext = React.createContext(initialState);
765
+ var ModalIdContext = React.createContext(null);
766
+ var ModalDispatchContext = React.createContext(null);
1028
767
  var REGISTRY = {};
1029
768
  var ALREADY_MOUNTED = {};
1030
769
  var modalCallbacks = {};
1031
770
  var hideCallbacks = {};
1032
771
  var uid = 0;
1033
772
  var getUid = () => `_af_modal_${uid++}`;
1034
- var dispatch = () => {
1035
- throw new Error("No modal dispatch \u2014 render inside <FunnelProvider> (which mounts the modal runtime).");
773
+ var runtimeStack = [];
774
+ var dispatch = (action) => {
775
+ const top = runtimeStack[runtimeStack.length - 1];
776
+ if (!top) {
777
+ throw new Error("No modal dispatch \u2014 render inside <FunnelProvider> (which mounts the modal runtime).");
778
+ }
779
+ top(action);
1036
780
  };
1037
781
  var modalReducer = (state = initialState, action) => {
1038
782
  const { modalId, args, flags } = action.payload;
@@ -1075,10 +819,10 @@ function registerModal(id, comp, props) {
1075
819
  function unregisterModal(id) {
1076
820
  delete REGISTRY[id];
1077
821
  }
1078
- function showModal(modal, args) {
822
+ function showModalVia(d, modal, args) {
1079
823
  const id = idOf(modal);
1080
824
  if (typeof modal !== "string" && !REGISTRY[id]) registerModal(id, modal);
1081
- dispatch({ type: "show", payload: { modalId: id, args } });
825
+ d({ type: "show", payload: { modalId: id, args } });
1082
826
  if (!modalCallbacks[id]) {
1083
827
  let res;
1084
828
  let rej;
@@ -1090,9 +834,12 @@ function showModal(modal, args) {
1090
834
  }
1091
835
  return modalCallbacks[id].promise;
1092
836
  }
1093
- function hideModal(modal) {
837
+ function showModal(modal, args) {
838
+ return showModalVia(dispatch, modal, args);
839
+ }
840
+ function hideModalVia(d, modal) {
1094
841
  const id = idOf(modal);
1095
- dispatch({ type: "hide", payload: { modalId: id } });
842
+ d({ type: "hide", payload: { modalId: id } });
1096
843
  delete modalCallbacks[id];
1097
844
  if (!hideCallbacks[id]) {
1098
845
  let res;
@@ -1105,41 +852,48 @@ function hideModal(modal) {
1105
852
  }
1106
853
  return hideCallbacks[id].promise;
1107
854
  }
1108
- function removeModal(modal) {
855
+ function hideModal(modal) {
856
+ return hideModalVia(dispatch, modal);
857
+ }
858
+ function removeModalVia(d, modal) {
1109
859
  const id = idOf(modal);
1110
- dispatch({ type: "remove", payload: { modalId: id } });
860
+ d({ type: "remove", payload: { modalId: id } });
1111
861
  delete modalCallbacks[id];
1112
862
  delete hideCallbacks[id];
1113
863
  }
1114
- function setFlags(id, flags) {
1115
- dispatch({ type: "set-flags", payload: { modalId: id, flags } });
864
+ function removeModal(modal) {
865
+ removeModalVia(dispatch, modal);
866
+ }
867
+ function setFlags(d, id, flags) {
868
+ d({ type: "set-flags", payload: { modalId: id, flags } });
1116
869
  }
1117
870
  function useModal(modal, args) {
1118
- const modals = react.useContext(ModalStateContext);
1119
- const contextId = react.useContext(ModalIdContext);
871
+ const modals = React.useContext(ModalStateContext);
872
+ const contextId = React.useContext(ModalIdContext);
873
+ const d = React.useContext(ModalDispatchContext) ?? dispatch;
1120
874
  const isComponent = !!modal && typeof modal !== "string";
1121
875
  const id = modal ? idOf(modal) : contextId;
1122
876
  if (!id) throw new Error("useModal: no modal id (call inside a defineModal component, or pass an id/component).");
1123
- react.useEffect(() => {
877
+ React.useEffect(() => {
1124
878
  if (isComponent && !REGISTRY[id]) registerModal(id, modal, args);
1125
879
  }, [isComponent, id, modal, args]);
1126
880
  const info = modals[id];
1127
- const show = react.useCallback((a) => showModal(id, a), [id]);
1128
- const hide = react.useCallback(() => hideModal(id), [id]);
1129
- const remove = react.useCallback(() => removeModal(id), [id]);
1130
- const resolve = react.useCallback((v) => {
881
+ const show = React.useCallback((a) => showModalVia(d, id, a), [d, id]);
882
+ const hide = React.useCallback(() => hideModalVia(d, id), [d, id]);
883
+ const remove = React.useCallback(() => removeModalVia(d, id), [d, id]);
884
+ const resolve = React.useCallback((v) => {
1131
885
  modalCallbacks[id]?.resolve(v);
1132
886
  delete modalCallbacks[id];
1133
887
  }, [id]);
1134
- const reject = react.useCallback((v) => {
888
+ const reject = React.useCallback((v) => {
1135
889
  modalCallbacks[id]?.reject(v);
1136
890
  delete modalCallbacks[id];
1137
891
  }, [id]);
1138
- const resolveHide = react.useCallback((v) => {
892
+ const resolveHide = React.useCallback((v) => {
1139
893
  hideCallbacks[id]?.resolve(v);
1140
894
  delete hideCallbacks[id];
1141
895
  }, [id]);
1142
- return react.useMemo(
896
+ return React.useMemo(
1143
897
  () => ({
1144
898
  id,
1145
899
  args: info?.args,
@@ -1158,47 +912,66 @@ function useModal(modal, args) {
1158
912
  function defineModal(Comp) {
1159
913
  return function Wrapped({ id, defaultVisible, keepMounted, ...props }) {
1160
914
  const { args, show } = useModal(id);
1161
- const modals = react.useContext(ModalStateContext);
915
+ const modals = React.useContext(ModalStateContext);
916
+ const d = React.useContext(ModalDispatchContext) ?? dispatch;
1162
917
  const shouldMount = !!modals[id];
1163
- react.useEffect(() => {
918
+ React.useEffect(() => {
1164
919
  if (defaultVisible) show();
1165
920
  ALREADY_MOUNTED[id] = true;
1166
921
  return () => {
1167
922
  delete ALREADY_MOUNTED[id];
1168
923
  };
1169
924
  }, [id, show, defaultVisible]);
1170
- react.useEffect(() => {
1171
- if (keepMounted) setFlags(id, { keepMounted: true });
1172
- }, [id, keepMounted]);
925
+ React.useEffect(() => {
926
+ if (keepMounted) setFlags(d, id, { keepMounted: true });
927
+ }, [d, id, keepMounted]);
1173
928
  const delayVisible = modals[id]?.delayVisible;
1174
- react.useEffect(() => {
929
+ React.useEffect(() => {
1175
930
  if (delayVisible) show(args);
1176
931
  }, [delayVisible, args, show]);
1177
932
  if (!shouldMount) return null;
1178
- return react.createElement(
933
+ return React.createElement(
1179
934
  ModalIdContext.Provider,
1180
935
  { value: id },
1181
- react.createElement(Comp, { ...props, ...args })
936
+ React.createElement(Comp, { ...props, ...args })
1182
937
  );
1183
938
  };
1184
939
  }
1185
940
  function ModalRoot() {
1186
- const modals = react.useContext(ModalStateContext);
941
+ const modals = React.useContext(ModalStateContext);
1187
942
  const toRender = Object.keys(modals).filter((id) => REGISTRY[id]).map((id) => ({ id, ...REGISTRY[id] }));
1188
- return react.createElement(
943
+ return React.createElement(
1189
944
  "div",
1190
945
  { "data-appfunnel-modal-root": "" },
1191
- ...toRender.map((t) => react.createElement(t.comp, { key: t.id, id: t.id, ...t.props }))
946
+ ...toRender.map((t) => React.createElement(t.comp, { key: t.id, id: t.id, ...t.props }))
1192
947
  );
1193
948
  }
1194
949
  function ModalRuntime({ children }) {
1195
- const [state, localDispatch] = react.useReducer(modalReducer, initialState);
1196
- dispatch = localDispatch;
1197
- return react.createElement(
1198
- ModalStateContext.Provider,
1199
- { value: state },
1200
- children,
1201
- react.createElement(ModalRoot, null)
950
+ const [state, localDispatch] = React.useReducer(modalReducer, initialState);
951
+ React.useEffect(() => {
952
+ runtimeStack.push(localDispatch);
953
+ if (runtimeStack.length > 1) {
954
+ try {
955
+ console.warn(
956
+ `[appfunnel] ${runtimeStack.length} modal runtimes are mounted \u2014 the imperative showModal()/hideModal() API binds to the most recent one. Use the useModal() hook inside each tree instead.`
957
+ );
958
+ } catch {
959
+ }
960
+ }
961
+ return () => {
962
+ const i = runtimeStack.indexOf(localDispatch);
963
+ if (i !== -1) runtimeStack.splice(i, 1);
964
+ };
965
+ }, []);
966
+ return React.createElement(
967
+ ModalDispatchContext.Provider,
968
+ { value: localDispatch },
969
+ React.createElement(
970
+ ModalStateContext.Provider,
971
+ { value: state },
972
+ children,
973
+ React.createElement(ModalRoot, null)
974
+ )
1202
975
  );
1203
976
  }
1204
977
 
@@ -1225,7 +998,7 @@ function OverlayShell({
1225
998
  panel,
1226
999
  children
1227
1000
  }) {
1228
- react.useEffect(() => {
1001
+ React.useEffect(() => {
1229
1002
  if (!open || typeof document === "undefined") return;
1230
1003
  const onKey = (e) => {
1231
1004
  if (e.key === "Escape") onClose();
@@ -1239,7 +1012,7 @@ function OverlayShell({
1239
1012
  };
1240
1013
  }, [open, onClose]);
1241
1014
  if (!open || typeof document === "undefined") return null;
1242
- const overlay = react.createElement(
1015
+ const overlay = React.createElement(
1243
1016
  "div",
1244
1017
  {
1245
1018
  role: "dialog",
@@ -1248,19 +1021,19 @@ function OverlayShell({
1248
1021
  "data-appfunnel-overlay": "",
1249
1022
  style: { position: "fixed", inset: 0, zIndex: 1e3, display: "flex", ...container }
1250
1023
  },
1251
- react.createElement("div", {
1024
+ React.createElement("div", {
1252
1025
  "data-appfunnel-overlay-backdrop": "",
1253
1026
  className: backdropClassName,
1254
1027
  onClick: dismissOnBackdrop ? onClose : void 0,
1255
1028
  style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" }
1256
1029
  }),
1257
- react.createElement(
1030
+ React.createElement(
1258
1031
  "div",
1259
1032
  { "data-appfunnel-overlay-panel": "", className, style: { position: "relative", background: "#fff", ...panel } },
1260
1033
  children
1261
1034
  )
1262
1035
  );
1263
- return reactDom.createPortal(overlay, document.body);
1036
+ return ReactDOM.createPortal(overlay, document.body);
1264
1037
  }
1265
1038
  var SHEET_LAYOUT = {
1266
1039
  bottom: { container: { justifyContent: "flex-end", alignItems: "stretch" }, panel: { borderTopLeftRadius: 16, borderTopRightRadius: 16, padding: 16, maxHeight: "90vh", overflow: "auto" } },
@@ -1271,7 +1044,7 @@ var SHEET_LAYOUT = {
1271
1044
  function Sheet(props) {
1272
1045
  const control = useModalControl();
1273
1046
  const layout = SHEET_LAYOUT[props.side ?? "bottom"];
1274
- return react.createElement(OverlayShell, {
1047
+ return React.createElement(OverlayShell, {
1275
1048
  ...control,
1276
1049
  className: props.className,
1277
1050
  backdropClassName: props.backdropClassName,
@@ -1284,7 +1057,7 @@ function Sheet(props) {
1284
1057
  }
1285
1058
  function Modal(props) {
1286
1059
  const control = useModalControl();
1287
- return react.createElement(OverlayShell, {
1060
+ return React.createElement(OverlayShell, {
1288
1061
  ...control,
1289
1062
  className: props.className,
1290
1063
  backdropClassName: props.backdropClassName,
@@ -1297,144 +1070,74 @@ function Modal(props) {
1297
1070
  }
1298
1071
 
1299
1072
  // src/commerce/checkout.tsx
1300
- var INLINE_SURFACES = /* @__PURE__ */ new Set([
1301
- "express",
1302
- "element",
1303
- "embedded"
1304
- ]);
1305
- function isInlineSurface(surface) {
1306
- return INLINE_SURFACES.has(surface);
1307
- }
1308
- var ON = { purchase: true, wallets: true, offSession: "reliable" };
1309
- var MANAGED = { purchase: true, wallets: true, offSession: "conditional" };
1310
- var ALL_UPSELLS = ["subscription", "one-time", "upgrade"];
1311
- var PROVIDER_PROFILES = {
1312
- // PSP; you hold the PaymentMethod and fire your own off-session PaymentIntent on
1313
- // the Elements surfaces (reliable). **Managed** Checkout (`embedded`/`redirect`)
1314
- // upsells too, but as a direct charge against Stripe's vaulted card → conditional.
1315
- // No provider "popup" surface.
1316
- stripe: {
1317
- isMoR: false,
1318
- offSessionUpsells: ALL_UPSELLS,
1319
- tokenModel: "merchant",
1320
- orchestrator: false,
1321
- surfaces: { express: ON, element: ON, sheet: ON, embedded: MANAGED, redirect: MANAGED }
1322
- },
1323
- // Merchant-of-Record; card entry is always Paddle's frame → no own element/sheet/
1324
- // express. Off-session via subscription one-time charge / collection_mode, but
1325
- // **no 2nd concurrent subscription** (upgrade + one-time only), provider-initiated.
1326
- paddle: {
1327
- isMoR: true,
1328
- offSessionUpsells: ["one-time", "upgrade"],
1329
- tokenModel: "provider",
1330
- orchestrator: false,
1331
- surfaces: { embedded: ON, popup: ON, redirect: ON }
1332
- },
1333
- // Merchant-of-Record; iframe-only (no raw card field). Off-session works
1334
- // (provider-initiated, async via webhooks). `sheet` = our chrome hosting their embed.
1335
- whop: {
1336
- isMoR: true,
1337
- offSessionUpsells: ALL_UPSELLS,
1338
- tokenModel: "provider",
1339
- orchestrator: false,
1340
- surfaces: { embedded: ON, redirect: ON, sheet: ON }
1341
- },
1342
- // Pure orchestrator (PSP-side); Headless renders express/element/sheet/embedded.
1343
- // No hosted redirect page, no popup checkout. Off-session is PSP-conditional.
1344
- primer: {
1345
- isMoR: false,
1346
- offSessionUpsells: ALL_UPSELLS,
1347
- tokenModel: "merchant",
1348
- orchestrator: true,
1349
- surfaces: { express: ON, element: ON, sheet: ON, embedded: ON }
1350
- },
1351
- // PSP **and** orchestrator (own acquiring + connectors routing across Stripe/Adyen/
1352
- // PayPal). One Payment Form (element/sheet/embedded) + hosted page + wallet button.
1353
- // Strong native off-session (Recurring API). No popup.
1354
- solidgate: {
1355
- isMoR: false,
1356
- offSessionUpsells: ALL_UPSELLS,
1357
- tokenModel: "merchant",
1358
- orchestrator: true,
1359
- surfaces: { express: ON, element: ON, sheet: ON, embedded: ON, redirect: ON }
1360
- }
1361
- };
1362
- function surfacesFor(provider) {
1363
- return Object.keys(PROVIDER_PROFILES[provider]?.surfaces ?? {});
1364
- }
1365
- function isMerchantOfRecord(provider) {
1366
- return PROVIDER_PROFILES[provider]?.isMoR ?? false;
1367
- }
1368
- function isOrchestrator(provider) {
1369
- return PROVIDER_PROFILES[provider]?.orchestrator ?? false;
1370
- }
1371
- function validateCheckout(provider, surface) {
1372
- const cap = PROVIDER_PROFILES[provider]?.surfaces[surface];
1373
- if (!cap) return { ok: false, reason: `${provider} has no '${surface}' surface` };
1374
- return cap.purchase ? { ok: true } : { ok: false, reason: `'${surface}' can't take a purchase on ${provider}` };
1375
- }
1376
- function validateUpsell(provider, paywallSurface, kind = "subscription") {
1377
- const profile = PROVIDER_PROFILES[provider];
1378
- if (!profile) return { ok: false, reason: `unknown provider '${provider}'` };
1379
- if (!profile.offSessionUpsells.includes(kind)) {
1380
- const can = profile.offSessionUpsells.length ? ` (it supports: ${profile.offSessionUpsells.join(", ")})` : "";
1381
- return { ok: false, reason: `${provider} can't charge a '${kind}' upsell off-session${can}` };
1382
- }
1383
- const cap = profile.surfaces[paywallSurface];
1384
- if (!cap) return { ok: false, reason: `${provider} has no '${paywallSurface}' surface to upsell after` };
1385
- if (cap.offSession === "none") {
1386
- return { ok: false, reason: `a purchase on '${paywallSurface}' retains no chargeable method for an upsell` };
1387
- }
1388
- if (cap.offSession === "conditional") {
1389
- return { ok: true, note: `off-session upsell after ${provider} '${paywallSurface}' (managed checkout) may decline \u2014 prefer element/sheet/express` };
1390
- }
1391
- return { ok: true };
1392
- }
1393
- function checkoutError(category, message, extra = {}) {
1394
- const retryable = extra.retryable ?? (category === "authentication_required" || category === "requires_payment_method" || category === "processing_error");
1395
- return { category, message, declineCode: extra.declineCode, retryable };
1396
- }
1397
1073
  function createMockDriver(provider = "stripe", options = {}) {
1398
1074
  const success = options.result ?? { ok: true, amountMinor: 0, currency: "USD" };
1399
- const offError = typeof options.failOffSession === "object" ? options.failOffSession : checkoutError("authentication_required", "off-session charge declined (mock)");
1075
+ const offError = typeof options.failOffSession === "object" ? options.failOffSession : chunkLJYLGLFS_cjs.checkoutError("authentication_required", "off-session charge declined (mock)");
1400
1076
  return {
1401
1077
  provider,
1402
1078
  start: (req) => {
1403
1079
  if (options.failOffSession && !req.surface) return Promise.resolve({ ok: false, error: offError });
1404
1080
  return Promise.resolve(success);
1405
1081
  },
1406
- renderInline: (req, cb) => react.createElement(
1082
+ renderInline: (req, cb) => React.createElement(
1407
1083
  "button",
1408
1084
  {
1409
1085
  type: "button",
1410
1086
  "data-mock-surface": req.surface,
1411
- onClick: () => success.ok ? cb.onSuccess(success) : cb.onError(success.error ?? checkoutError("processing_error", "failed (mock)"))
1087
+ onClick: () => {
1088
+ cb.onStart?.();
1089
+ if (success.ok) cb.onSuccess(success);
1090
+ else cb.onError(success.error ?? chunkLJYLGLFS_cjs.checkoutError("processing_error", "failed (mock)"));
1091
+ }
1412
1092
  },
1413
1093
  `Pay (mock ${req.surface})`
1414
- )
1094
+ ),
1095
+ resume: () => Promise.resolve(success)
1096
+ };
1097
+ }
1098
+ function driverWithEmail(driver, getEmail) {
1099
+ const enrich = (req) => req.email !== void 0 ? req : { ...req, email: getEmail() };
1100
+ return {
1101
+ ...driver,
1102
+ start: (req) => driver.start(enrich(req)),
1103
+ renderInline: driver.renderInline ? (req, cb) => driver.renderInline(enrich(req), cb) : void 0
1415
1104
  };
1416
1105
  }
1417
- var DriverContext = react.createContext(null);
1106
+ function driverWithCatalog(driver, catalog) {
1107
+ const enrich = (req) => req.catalogKey !== void 0 ? req : { ...req, catalogKey: catalog.get(req.product)?.catalogKey };
1108
+ return {
1109
+ ...driver,
1110
+ start: (req) => driver.start(enrich(req)),
1111
+ renderInline: driver.renderInline ? (req, cb) => driver.renderInline(enrich(req), cb) : void 0
1112
+ };
1113
+ }
1114
+ var DriverContext = React.createContext(null);
1418
1115
  function CheckoutDriverProvider({
1419
1116
  driver,
1420
1117
  children
1421
1118
  }) {
1422
- return react.createElement(DriverContext.Provider, { value: driver }, children);
1119
+ return React.createElement(DriverContext.Provider, { value: driver }, children);
1423
1120
  }
1424
1121
  function useDriver() {
1425
- return react.useContext(DriverContext) ?? FALLBACK_DRIVER;
1122
+ return React.useContext(DriverContext) ?? FALLBACK_DRIVER;
1426
1123
  }
1427
1124
  var FALLBACK_DRIVER = createMockDriver();
1428
1125
  function useCheckout(opts = {}) {
1429
1126
  const driver = useDriver();
1430
1127
  const tracker = useTrackerRef();
1431
1128
  const nav = useNavigation();
1432
- const [status, setStatus] = react.useState("idle");
1433
- const [error, setError] = react.useState(null);
1129
+ const [status, setStatus] = React.useState("idle");
1130
+ const [error, setError] = React.useState(null);
1434
1131
  const intent = opts.intent ?? "purchase";
1435
1132
  const kind = opts.kind;
1436
1133
  const advance = opts.advanceOnSuccess ?? true;
1437
- const succeed = react.useCallback(
1134
+ const recovering = React.useRef(false);
1135
+ const failRef = React.useRef(() => {
1136
+ });
1137
+ const attemptRef = React.useRef(
1138
+ async () => ({ ok: false })
1139
+ );
1140
+ const succeed = React.useCallback(
1438
1141
  (result) => {
1439
1142
  setStatus("success");
1440
1143
  tracker.track("purchase.complete", {
@@ -1448,21 +1151,9 @@ function useCheckout(opts = {}) {
1448
1151
  },
1449
1152
  [tracker, nav, advance, opts]
1450
1153
  );
1451
- const fail = react.useCallback(
1452
- (err, product) => {
1453
- setStatus(err.category === "authentication_required" ? "requires_action" : "error");
1454
- setError(err);
1455
- tracker.track("checkout.failed", {
1456
- category: err.category,
1457
- declineCode: err.declineCode,
1458
- productId: product,
1459
- intent
1460
- });
1461
- opts.onError?.(err);
1462
- },
1463
- [tracker, intent, opts]
1464
- );
1465
- const begin = react.useCallback(
1154
+ const succeedRef = React.useRef(succeed);
1155
+ succeedRef.current = succeed;
1156
+ const begin = React.useCallback(
1466
1157
  (product, surface) => {
1467
1158
  setStatus("loading");
1468
1159
  setError(null);
@@ -1470,64 +1161,157 @@ function useCheckout(opts = {}) {
1470
1161
  },
1471
1162
  [tracker]
1472
1163
  );
1473
- const paymentAdded = react.useCallback(() => tracker.track("checkout.payment_added", {}), [tracker]);
1474
- const open = react.useCallback(
1475
- async (product, surface) => {
1476
- begin(product, surface);
1477
- try {
1478
- const result = await driver.start({ product, intent, surface, kind });
1479
- if (result.ok) succeed(result);
1480
- else fail(result.error ?? checkoutError("unknown", "Checkout failed"), product);
1481
- return result;
1482
- } catch (e) {
1483
- const err = checkoutError("processing_error", e instanceof Error ? e.message : "Checkout failed");
1484
- fail(err, product);
1485
- return { ok: false, error: err };
1486
- }
1487
- },
1488
- [driver, intent, kind, begin, succeed, fail]
1489
- );
1490
- const callbacksFor = react.useCallback(
1164
+ const paymentAdded = React.useCallback(() => tracker.track("checkout.payment_added", {}), [tracker]);
1165
+ const hostInSheet = (surface) => surface === "sheet" || chunkLJYLGLFS_cjs.isInlineSurface(surface) && !!chunkLJYLGLFS_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet;
1166
+ const startRecovery = (product, surface) => {
1167
+ recovering.current = true;
1168
+ if (hostInSheet(surface)) {
1169
+ begin(product, "sheet");
1170
+ void showModal(CheckoutSheet, {
1171
+ product,
1172
+ surface: "sheet",
1173
+ intent,
1174
+ kind,
1175
+ onSuccess: (r) => succeedRef.current(r),
1176
+ onError: (e) => failRef.current(e, product),
1177
+ onPaymentAdded: () => paymentAdded()
1178
+ });
1179
+ } else {
1180
+ void attemptRef.current(product, surface);
1181
+ }
1182
+ };
1183
+ failRef.current = (err, product) => {
1184
+ setStatus(err.category === "authentication_required" ? "requires_action" : "error");
1185
+ setError(err);
1186
+ tracker.track("checkout.failed", {
1187
+ category: err.category,
1188
+ declineCode: err.declineCode,
1189
+ productId: product,
1190
+ intent
1191
+ });
1192
+ opts.onError?.(err);
1193
+ if (err.category === "canceled" && !opts.onFailed?.canceled) return;
1194
+ if (product && !recovering.current && opts.recoverySurface && err.category !== "canceled") {
1195
+ startRecovery(product, opts.recoverySurface);
1196
+ return;
1197
+ }
1198
+ let route = opts.onFailed?.[err.category] ?? (err.category === "canceled" ? void 0 : opts.onFailed?.default);
1199
+ if (route && typeof route === "object" && "fallback" in route && recovering.current) {
1200
+ const dflt = opts.onFailed?.default;
1201
+ route = dflt && dflt !== route && !(typeof dflt === "object" && "fallback" in dflt) ? dflt : void 0;
1202
+ }
1203
+ if (!route) return;
1204
+ if (typeof route === "function") route(err);
1205
+ else if ("go" in route) nav.go(route.go);
1206
+ else if ("modal" in route) {
1207
+ const props = {
1208
+ error: err,
1209
+ product,
1210
+ go: (pageKey) => nav.go(pageKey),
1211
+ retry: (surface) => {
1212
+ if (!product) return;
1213
+ recovering.current = true;
1214
+ if (!surface) {
1215
+ if (intent === "upsell") void attemptRef.current(product);
1216
+ else startRecovery(product, chunkLJYLGLFS_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet ? "sheet" : "popup");
1217
+ return;
1218
+ }
1219
+ startRecovery(product, surface);
1220
+ }
1221
+ };
1222
+ void showModal(route.modal, props);
1223
+ } else if ("fallback" in route) {
1224
+ if (product && !recovering.current) startRecovery(product, route.fallback);
1225
+ }
1226
+ };
1227
+ attemptRef.current = async (product, surface) => {
1228
+ begin(product, surface);
1229
+ try {
1230
+ const result = await driver.start({ product, intent, surface, kind });
1231
+ if (result.ok) succeedRef.current(result);
1232
+ else failRef.current(result.error ?? chunkLJYLGLFS_cjs.checkoutError("unknown", "Checkout failed"), product);
1233
+ return result;
1234
+ } catch (e) {
1235
+ const err = chunkLJYLGLFS_cjs.checkoutError("processing_error", e instanceof Error ? e.message : "Checkout failed");
1236
+ failRef.current(err, product);
1237
+ return { ok: false, error: err };
1238
+ }
1239
+ };
1240
+ const open = React.useCallback(async (product, surface) => {
1241
+ recovering.current = false;
1242
+ return attemptRef.current(product, surface);
1243
+ }, []);
1244
+ const callbacksFor = React.useCallback(
1491
1245
  (product, surface) => ({
1492
- onStart: () => begin(product, surface),
1493
- onSuccess: (result) => succeed(result),
1494
- onError: (err) => fail(err, product),
1246
+ onStart: () => {
1247
+ recovering.current = false;
1248
+ begin(product, surface);
1249
+ },
1250
+ onSuccess: (result) => succeedRef.current(result),
1251
+ onError: (err) => failRef.current(err, product),
1495
1252
  onPaymentAdded: () => paymentAdded()
1496
1253
  }),
1497
- [begin, succeed, fail, paymentAdded]
1254
+ [begin, paymentAdded]
1498
1255
  );
1499
- const reset = react.useCallback(() => {
1256
+ const reset = React.useCallback(() => {
1257
+ recovering.current = false;
1500
1258
  setStatus("idle");
1501
1259
  setError(null);
1502
1260
  }, []);
1503
1261
  return { open, status, error, isLoading: status === "loading", reset, callbacksFor };
1504
1262
  }
1505
- var CheckoutSheet = defineModal(({ product, surface, intent, onSuccess, onError }) => {
1263
+ var CheckoutSheet = defineModal(({ product, surface, intent, kind, onSuccess, onError, onPaymentAdded }) => {
1506
1264
  const driver = useDriver();
1507
1265
  const modal = useModal();
1266
+ const resolved = React.useRef(false);
1267
+ const onErrorRef = React.useRef(onError);
1268
+ onErrorRef.current = onError;
1269
+ const hostable = !!driver.renderInline;
1270
+ React.useEffect(() => {
1271
+ if (!hostable) {
1272
+ resolved.current = true;
1273
+ onErrorRef.current(
1274
+ chunkLJYLGLFS_cjs.checkoutError("processing_error", "This checkout driver has no inline surface to host in the sheet")
1275
+ );
1276
+ void modal.hide();
1277
+ modal.remove();
1278
+ return;
1279
+ }
1280
+ return () => {
1281
+ if (!resolved.current) {
1282
+ onErrorRef.current(chunkLJYLGLFS_cjs.checkoutError("canceled", "Checkout was dismissed before completing"));
1283
+ }
1284
+ };
1285
+ }, []);
1508
1286
  if (!driver.renderInline) return null;
1509
- return react.createElement(Sheet, {
1287
+ const close = () => {
1288
+ resolved.current = true;
1289
+ void modal.hide();
1290
+ modal.remove();
1291
+ };
1292
+ return React.createElement(Sheet, {
1510
1293
  children: driver.renderInline(
1511
- { product, intent, surface },
1294
+ { product, intent, surface, kind },
1512
1295
  {
1513
1296
  onSuccess: (r) => {
1514
- modal.hide();
1297
+ close();
1515
1298
  onSuccess(r);
1516
1299
  },
1517
1300
  onError: (e) => {
1518
- modal.hide();
1301
+ close();
1519
1302
  onError(e);
1520
- }
1303
+ },
1304
+ onPaymentAdded
1521
1305
  }
1522
1306
  )
1523
1307
  });
1524
1308
  });
1525
1309
  function trigger(onClick, { asChild, children, className, disabled }) {
1526
- if (asChild && react.isValidElement(children)) {
1310
+ if (asChild && React.isValidElement(children)) {
1527
1311
  const child = children;
1528
- return react.cloneElement(child, { onClick });
1312
+ return React.cloneElement(child, { onClick });
1529
1313
  }
1530
- return react.createElement("button", { type: "button", className, disabled, onClick }, children ?? "Continue");
1314
+ return React.createElement("button", { type: "button", className, disabled, onClick }, children ?? "Continue");
1531
1315
  }
1532
1316
  function Checkout({
1533
1317
  product,
@@ -1540,8 +1324,8 @@ function Checkout({
1540
1324
  const driver = useDriver();
1541
1325
  const checkout = useCheckout(options);
1542
1326
  const intent = options.intent ?? "purchase";
1543
- if (isInlineSurface(surface)) {
1544
- return driver.renderInline ? react.createElement(
1327
+ if (chunkLJYLGLFS_cjs.isInlineSurface(surface)) {
1328
+ return driver.renderInline ? React.createElement(
1545
1329
  "div",
1546
1330
  { key: product, className },
1547
1331
  driver.renderInline({ product, intent, surface }, checkout.callbacksFor(product, surface))
@@ -1551,7 +1335,15 @@ function Checkout({
1551
1335
  const cb = checkout.callbacksFor(product, surface);
1552
1336
  const open = () => {
1553
1337
  cb.onStart();
1554
- showModal(CheckoutSheet, { product, surface, intent, onSuccess: cb.onSuccess, onError: cb.onError });
1338
+ showModal(CheckoutSheet, {
1339
+ product,
1340
+ surface,
1341
+ intent,
1342
+ kind: options.kind,
1343
+ onSuccess: cb.onSuccess,
1344
+ onError: cb.onError,
1345
+ onPaymentAdded: cb.onPaymentAdded
1346
+ });
1555
1347
  };
1556
1348
  return trigger(open, { asChild, children, className, disabled: checkout.isLoading });
1557
1349
  }
@@ -1563,31 +1355,1129 @@ function Checkout({
1563
1355
  });
1564
1356
  }
1565
1357
  function Upsell({ product, fallback, asChild, children, className, ...options }) {
1566
- const checkout = useCheckout({ ...options, intent: "upsell" });
1567
- const start = async () => {
1568
- const result = await checkout.open(product);
1569
- if (result.ok || !fallback) return;
1570
- const cb = checkout.callbacksFor(product, fallback);
1571
- if (fallback === "sheet") {
1572
- cb.onStart();
1573
- showModal(CheckoutSheet, { product, surface: "sheet", intent: "upsell", onSuccess: cb.onSuccess, onError: cb.onError });
1574
- } else {
1575
- await checkout.open(product, fallback);
1576
- }
1577
- };
1578
- return trigger(start, {
1358
+ const checkout = useCheckout({
1359
+ ...options,
1360
+ intent: "upsell",
1361
+ recoverySurface: fallback ?? options.recoverySurface
1362
+ });
1363
+ return trigger(() => void checkout.open(product), {
1579
1364
  asChild,
1580
1365
  children: children ?? "Add to my plan",
1581
1366
  className,
1582
1367
  disabled: checkout.isLoading
1583
1368
  });
1584
1369
  }
1370
+ var consumedResumes = /* @__PURE__ */ new Set();
1371
+ function CheckoutResume(options = {}) {
1372
+ const driver = useDriver();
1373
+ const checkout = useCheckout(options);
1374
+ const callbacksRef = React.useRef(checkout.callbacksFor);
1375
+ callbacksRef.current = checkout.callbacksFor;
1376
+ React.useEffect(() => {
1377
+ if (typeof window === "undefined" || !driver.resume) return;
1378
+ const url = new URL(window.location.href);
1379
+ const correlationId = url.searchParams.get("af_checkout");
1380
+ if (!correlationId || consumedResumes.has(correlationId)) return;
1381
+ consumedResumes.add(correlationId);
1382
+ void driver.resume(correlationId).then((result) => {
1383
+ const cb = callbacksRef.current();
1384
+ if (result.ok) {
1385
+ url.searchParams.delete("af_checkout");
1386
+ window.history.replaceState(window.history.state, "", url.toString());
1387
+ cb.onSuccess(result);
1388
+ } else {
1389
+ cb.onError(result.error ?? chunkLJYLGLFS_cjs.checkoutError("unknown", "The checkout could not be verified"));
1390
+ }
1391
+ });
1392
+ }, []);
1393
+ return null;
1394
+ }
1395
+ function __insertCSS(code) {
1396
+ if (typeof document == "undefined") return;
1397
+ let head = document.head || document.getElementsByTagName("head")[0];
1398
+ let style = document.createElement("style");
1399
+ style.type = "text/css";
1400
+ head.appendChild(style);
1401
+ style.styleSheet ? style.styleSheet.cssText = code : style.appendChild(document.createTextNode(code));
1402
+ }
1403
+ var getAsset = (type) => {
1404
+ switch (type) {
1405
+ case "success":
1406
+ return SuccessIcon;
1407
+ case "info":
1408
+ return InfoIcon;
1409
+ case "warning":
1410
+ return WarningIcon;
1411
+ case "error":
1412
+ return ErrorIcon;
1413
+ default:
1414
+ return null;
1415
+ }
1416
+ };
1417
+ var bars = Array(12).fill(0);
1418
+ var Loader = ({ visible, className }) => {
1419
+ return /* @__PURE__ */ React__default.default.createElement("div", {
1420
+ className: [
1421
+ "sonner-loading-wrapper",
1422
+ className
1423
+ ].filter(Boolean).join(" "),
1424
+ "data-visible": visible
1425
+ }, /* @__PURE__ */ React__default.default.createElement("div", {
1426
+ className: "sonner-spinner"
1427
+ }, bars.map((_, i) => /* @__PURE__ */ React__default.default.createElement("div", {
1428
+ className: "sonner-loading-bar",
1429
+ key: `spinner-bar-${i}`
1430
+ }))));
1431
+ };
1432
+ var SuccessIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
1433
+ xmlns: "http://www.w3.org/2000/svg",
1434
+ viewBox: "0 0 20 20",
1435
+ fill: "currentColor",
1436
+ height: "20",
1437
+ width: "20"
1438
+ }, /* @__PURE__ */ React__default.default.createElement("path", {
1439
+ fillRule: "evenodd",
1440
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",
1441
+ clipRule: "evenodd"
1442
+ }));
1443
+ var WarningIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
1444
+ xmlns: "http://www.w3.org/2000/svg",
1445
+ viewBox: "0 0 24 24",
1446
+ fill: "currentColor",
1447
+ height: "20",
1448
+ width: "20"
1449
+ }, /* @__PURE__ */ React__default.default.createElement("path", {
1450
+ fillRule: "evenodd",
1451
+ d: "M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z",
1452
+ clipRule: "evenodd"
1453
+ }));
1454
+ var InfoIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
1455
+ xmlns: "http://www.w3.org/2000/svg",
1456
+ viewBox: "0 0 20 20",
1457
+ fill: "currentColor",
1458
+ height: "20",
1459
+ width: "20"
1460
+ }, /* @__PURE__ */ React__default.default.createElement("path", {
1461
+ fillRule: "evenodd",
1462
+ d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",
1463
+ clipRule: "evenodd"
1464
+ }));
1465
+ var ErrorIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
1466
+ xmlns: "http://www.w3.org/2000/svg",
1467
+ viewBox: "0 0 20 20",
1468
+ fill: "currentColor",
1469
+ height: "20",
1470
+ width: "20"
1471
+ }, /* @__PURE__ */ React__default.default.createElement("path", {
1472
+ fillRule: "evenodd",
1473
+ d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",
1474
+ clipRule: "evenodd"
1475
+ }));
1476
+ var CloseIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
1477
+ xmlns: "http://www.w3.org/2000/svg",
1478
+ width: "12",
1479
+ height: "12",
1480
+ viewBox: "0 0 24 24",
1481
+ fill: "none",
1482
+ stroke: "currentColor",
1483
+ strokeWidth: "1.5",
1484
+ strokeLinecap: "round",
1485
+ strokeLinejoin: "round"
1486
+ }, /* @__PURE__ */ React__default.default.createElement("line", {
1487
+ x1: "18",
1488
+ y1: "6",
1489
+ x2: "6",
1490
+ y2: "18"
1491
+ }), /* @__PURE__ */ React__default.default.createElement("line", {
1492
+ x1: "6",
1493
+ y1: "6",
1494
+ x2: "18",
1495
+ y2: "18"
1496
+ }));
1497
+ var useIsDocumentHidden = () => {
1498
+ const [isDocumentHidden, setIsDocumentHidden] = React__default.default.useState(document.hidden);
1499
+ React__default.default.useEffect(() => {
1500
+ const callback = () => {
1501
+ setIsDocumentHidden(document.hidden);
1502
+ };
1503
+ document.addEventListener("visibilitychange", callback);
1504
+ return () => window.removeEventListener("visibilitychange", callback);
1505
+ }, []);
1506
+ return isDocumentHidden;
1507
+ };
1508
+ var toastsCounter = 1;
1509
+ var Observer = class {
1510
+ constructor() {
1511
+ this.subscribe = (subscriber) => {
1512
+ this.subscribers.push(subscriber);
1513
+ return () => {
1514
+ const index = this.subscribers.indexOf(subscriber);
1515
+ this.subscribers.splice(index, 1);
1516
+ };
1517
+ };
1518
+ this.publish = (data) => {
1519
+ this.subscribers.forEach((subscriber) => subscriber(data));
1520
+ };
1521
+ this.addToast = (data) => {
1522
+ this.publish(data);
1523
+ this.toasts = [
1524
+ ...this.toasts,
1525
+ data
1526
+ ];
1527
+ };
1528
+ this.create = (data) => {
1529
+ var _data_id;
1530
+ const { message, ...rest } = data;
1531
+ const id = typeof (data == null ? void 0 : data.id) === "number" || ((_data_id = data.id) == null ? void 0 : _data_id.length) > 0 ? data.id : toastsCounter++;
1532
+ const alreadyExists = this.toasts.find((toast2) => {
1533
+ return toast2.id === id;
1534
+ });
1535
+ const dismissible = data.dismissible === void 0 ? true : data.dismissible;
1536
+ if (this.dismissedToasts.has(id)) {
1537
+ this.dismissedToasts.delete(id);
1538
+ }
1539
+ if (alreadyExists) {
1540
+ this.toasts = this.toasts.map((toast2) => {
1541
+ if (toast2.id === id) {
1542
+ this.publish({
1543
+ ...toast2,
1544
+ ...data,
1545
+ id,
1546
+ title: message
1547
+ });
1548
+ return {
1549
+ ...toast2,
1550
+ ...data,
1551
+ id,
1552
+ dismissible,
1553
+ title: message
1554
+ };
1555
+ }
1556
+ return toast2;
1557
+ });
1558
+ } else {
1559
+ this.addToast({
1560
+ title: message,
1561
+ ...rest,
1562
+ dismissible,
1563
+ id
1564
+ });
1565
+ }
1566
+ return id;
1567
+ };
1568
+ this.dismiss = (id) => {
1569
+ if (id) {
1570
+ this.dismissedToasts.add(id);
1571
+ requestAnimationFrame(() => this.subscribers.forEach((subscriber) => subscriber({
1572
+ id,
1573
+ dismiss: true
1574
+ })));
1575
+ } else {
1576
+ this.toasts.forEach((toast2) => {
1577
+ this.subscribers.forEach((subscriber) => subscriber({
1578
+ id: toast2.id,
1579
+ dismiss: true
1580
+ }));
1581
+ });
1582
+ }
1583
+ return id;
1584
+ };
1585
+ this.message = (message, data) => {
1586
+ return this.create({
1587
+ ...data,
1588
+ message
1589
+ });
1590
+ };
1591
+ this.error = (message, data) => {
1592
+ return this.create({
1593
+ ...data,
1594
+ message,
1595
+ type: "error"
1596
+ });
1597
+ };
1598
+ this.success = (message, data) => {
1599
+ return this.create({
1600
+ ...data,
1601
+ type: "success",
1602
+ message
1603
+ });
1604
+ };
1605
+ this.info = (message, data) => {
1606
+ return this.create({
1607
+ ...data,
1608
+ type: "info",
1609
+ message
1610
+ });
1611
+ };
1612
+ this.warning = (message, data) => {
1613
+ return this.create({
1614
+ ...data,
1615
+ type: "warning",
1616
+ message
1617
+ });
1618
+ };
1619
+ this.loading = (message, data) => {
1620
+ return this.create({
1621
+ ...data,
1622
+ type: "loading",
1623
+ message
1624
+ });
1625
+ };
1626
+ this.promise = (promise, data) => {
1627
+ if (!data) {
1628
+ return;
1629
+ }
1630
+ let id = void 0;
1631
+ if (data.loading !== void 0) {
1632
+ id = this.create({
1633
+ ...data,
1634
+ promise,
1635
+ type: "loading",
1636
+ message: data.loading,
1637
+ description: typeof data.description !== "function" ? data.description : void 0
1638
+ });
1639
+ }
1640
+ const p = Promise.resolve(promise instanceof Function ? promise() : promise);
1641
+ let shouldDismiss = id !== void 0;
1642
+ let result;
1643
+ const originalPromise = p.then(async (response) => {
1644
+ result = [
1645
+ "resolve",
1646
+ response
1647
+ ];
1648
+ const isReactElementResponse = React__default.default.isValidElement(response);
1649
+ if (isReactElementResponse) {
1650
+ shouldDismiss = false;
1651
+ this.create({
1652
+ id,
1653
+ type: "default",
1654
+ message: response
1655
+ });
1656
+ } else if (isHttpResponse(response) && !response.ok) {
1657
+ shouldDismiss = false;
1658
+ const promiseData = typeof data.error === "function" ? await data.error(`HTTP error! status: ${response.status}`) : data.error;
1659
+ const description = typeof data.description === "function" ? await data.description(`HTTP error! status: ${response.status}`) : data.description;
1660
+ const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
1661
+ const toastSettings = isExtendedResult ? promiseData : {
1662
+ message: promiseData
1663
+ };
1664
+ this.create({
1665
+ id,
1666
+ type: "error",
1667
+ description,
1668
+ ...toastSettings
1669
+ });
1670
+ } else if (response instanceof Error) {
1671
+ shouldDismiss = false;
1672
+ const promiseData = typeof data.error === "function" ? await data.error(response) : data.error;
1673
+ const description = typeof data.description === "function" ? await data.description(response) : data.description;
1674
+ const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
1675
+ const toastSettings = isExtendedResult ? promiseData : {
1676
+ message: promiseData
1677
+ };
1678
+ this.create({
1679
+ id,
1680
+ type: "error",
1681
+ description,
1682
+ ...toastSettings
1683
+ });
1684
+ } else if (data.success !== void 0) {
1685
+ shouldDismiss = false;
1686
+ const promiseData = typeof data.success === "function" ? await data.success(response) : data.success;
1687
+ const description = typeof data.description === "function" ? await data.description(response) : data.description;
1688
+ const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
1689
+ const toastSettings = isExtendedResult ? promiseData : {
1690
+ message: promiseData
1691
+ };
1692
+ this.create({
1693
+ id,
1694
+ type: "success",
1695
+ description,
1696
+ ...toastSettings
1697
+ });
1698
+ }
1699
+ }).catch(async (error) => {
1700
+ result = [
1701
+ "reject",
1702
+ error
1703
+ ];
1704
+ if (data.error !== void 0) {
1705
+ shouldDismiss = false;
1706
+ const promiseData = typeof data.error === "function" ? await data.error(error) : data.error;
1707
+ const description = typeof data.description === "function" ? await data.description(error) : data.description;
1708
+ const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
1709
+ const toastSettings = isExtendedResult ? promiseData : {
1710
+ message: promiseData
1711
+ };
1712
+ this.create({
1713
+ id,
1714
+ type: "error",
1715
+ description,
1716
+ ...toastSettings
1717
+ });
1718
+ }
1719
+ }).finally(() => {
1720
+ if (shouldDismiss) {
1721
+ this.dismiss(id);
1722
+ id = void 0;
1723
+ }
1724
+ data.finally == null ? void 0 : data.finally.call(data);
1725
+ });
1726
+ const unwrap = () => new Promise((resolve, reject) => originalPromise.then(() => result[0] === "reject" ? reject(result[1]) : resolve(result[1])).catch(reject));
1727
+ if (typeof id !== "string" && typeof id !== "number") {
1728
+ return {
1729
+ unwrap
1730
+ };
1731
+ } else {
1732
+ return Object.assign(id, {
1733
+ unwrap
1734
+ });
1735
+ }
1736
+ };
1737
+ this.custom = (jsx2, data) => {
1738
+ const id = (data == null ? void 0 : data.id) || toastsCounter++;
1739
+ this.create({
1740
+ jsx: jsx2(id),
1741
+ id,
1742
+ ...data
1743
+ });
1744
+ return id;
1745
+ };
1746
+ this.getActiveToasts = () => {
1747
+ return this.toasts.filter((toast2) => !this.dismissedToasts.has(toast2.id));
1748
+ };
1749
+ this.subscribers = [];
1750
+ this.toasts = [];
1751
+ this.dismissedToasts = /* @__PURE__ */ new Set();
1752
+ }
1753
+ };
1754
+ var ToastState = new Observer();
1755
+ var toastFunction = (message, data) => {
1756
+ const id = (data == null ? void 0 : data.id) || toastsCounter++;
1757
+ ToastState.addToast({
1758
+ title: message,
1759
+ ...data,
1760
+ id
1761
+ });
1762
+ return id;
1763
+ };
1764
+ var isHttpResponse = (data) => {
1765
+ return data && typeof data === "object" && "ok" in data && typeof data.ok === "boolean" && "status" in data && typeof data.status === "number";
1766
+ };
1767
+ var basicToast = toastFunction;
1768
+ var getHistory = () => ToastState.toasts;
1769
+ var getToasts = () => ToastState.getActiveToasts();
1770
+ var toast = Object.assign(basicToast, {
1771
+ success: ToastState.success,
1772
+ info: ToastState.info,
1773
+ warning: ToastState.warning,
1774
+ error: ToastState.error,
1775
+ custom: ToastState.custom,
1776
+ message: ToastState.message,
1777
+ promise: ToastState.promise,
1778
+ dismiss: ToastState.dismiss,
1779
+ loading: ToastState.loading
1780
+ }, {
1781
+ getHistory,
1782
+ getToasts
1783
+ });
1784
+ __insertCSS("[data-sonner-toaster][dir=ltr],html[dir=ltr]{--toast-icon-margin-start:-3px;--toast-icon-margin-end:4px;--toast-svg-margin-start:-1px;--toast-svg-margin-end:0px;--toast-button-margin-start:auto;--toast-button-margin-end:0;--toast-close-button-start:0;--toast-close-button-end:unset;--toast-close-button-transform:translate(-35%, -35%)}[data-sonner-toaster][dir=rtl],html[dir=rtl]{--toast-icon-margin-start:4px;--toast-icon-margin-end:-3px;--toast-svg-margin-start:0px;--toast-svg-margin-end:-1px;--toast-button-margin-start:0;--toast-button-margin-end:auto;--toast-close-button-start:unset;--toast-close-button-end:0;--toast-close-button-transform:translate(35%, -35%)}[data-sonner-toaster]{position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1:hsl(0, 0%, 99%);--gray2:hsl(0, 0%, 97.3%);--gray3:hsl(0, 0%, 95.1%);--gray4:hsl(0, 0%, 93%);--gray5:hsl(0, 0%, 90.9%);--gray6:hsl(0, 0%, 88.7%);--gray7:hsl(0, 0%, 85.8%);--gray8:hsl(0, 0%, 78%);--gray9:hsl(0, 0%, 56.1%);--gray10:hsl(0, 0%, 52.3%);--gray11:hsl(0, 0%, 43.5%);--gray12:hsl(0, 0%, 9%);--border-radius:8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:0;z-index:999999999;transition:transform .4s ease}@media (hover:none) and (pointer:coarse){[data-sonner-toaster][data-lifted=true]{transform:none}}[data-sonner-toaster][data-x-position=right]{right:var(--offset-right)}[data-sonner-toaster][data-x-position=left]{left:var(--offset-left)}[data-sonner-toaster][data-x-position=center]{left:50%;transform:translateX(-50%)}[data-sonner-toaster][data-y-position=top]{top:var(--offset-top)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--offset-bottom)}[data-sonner-toast]{--y:translateY(100%);--lift-amount:calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:0;overflow-wrap:anywhere}[data-sonner-toast][data-styled=true]{padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px rgba(0,0,0,.1);width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}[data-sonner-toast]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-y-position=top]{top:0;--y:translateY(-100%);--lift:1;--lift-amount:calc(1 * var(--gap))}[data-sonner-toast][data-y-position=bottom]{bottom:0;--y:translateY(100%);--lift:-1;--lift-amount:calc(var(--lift) * var(--gap))}[data-sonner-toast][data-styled=true] [data-description]{font-weight:400;line-height:1.4;color:#3f3f3f}[data-rich-colors=true][data-sonner-toast][data-styled=true] [data-description]{color:inherit}[data-sonner-toaster][data-sonner-theme=dark] [data-description]{color:#e8e8e8}[data-sonner-toast][data-styled=true] [data-title]{font-weight:500;line-height:1.5;color:inherit}[data-sonner-toast][data-styled=true] [data-icon]{display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}[data-sonner-toast][data-promise=true] [data-icon]>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}[data-sonner-toast][data-styled=true] [data-icon]>*{flex-shrink:0}[data-sonner-toast][data-styled=true] [data-icon] svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}[data-sonner-toast][data-styled=true] [data-content]{display:flex;flex-direction:column;gap:2px}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;font-weight:500;cursor:pointer;outline:0;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}[data-sonner-toast][data-styled=true] [data-button]:focus-visible{box-shadow:0 0 0 2px rgba(0,0,0,.4)}[data-sonner-toast][data-styled=true] [data-button]:first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}[data-sonner-toast][data-styled=true] [data-cancel]{color:var(--normal-text);background:rgba(0,0,0,.08)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-styled=true] [data-cancel]{background:rgba(255,255,255,.3)}[data-sonner-toast][data-styled=true] [data-close-button]{position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--gray12);background:var(--normal-bg);border:1px solid var(--gray4);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast][data-styled=true] [data-close-button]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-styled=true] [data-disabled=true]{cursor:not-allowed}[data-sonner-toast][data-styled=true]:hover [data-close-button]:hover{background:var(--gray2);border-color:var(--gray5)}[data-sonner-toast][data-swiping=true]::before{content:'';position:absolute;left:-100%;right:-100%;height:100%;z-index:-1}[data-sonner-toast][data-y-position=top][data-swiping=true]::before{bottom:50%;transform:scaleY(3) translateY(50%)}[data-sonner-toast][data-y-position=bottom][data-swiping=true]::before{top:50%;transform:scaleY(3) translateY(-50%)}[data-sonner-toast][data-swiping=false][data-removed=true]::before{content:'';position:absolute;inset:0;transform:scaleY(2)}[data-sonner-toast][data-expanded=true]::after{content:'';position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}[data-sonner-toast][data-mounted=true]{--y:translateY(0);opacity:1}[data-sonner-toast][data-expanded=false][data-front=false]{--scale:var(--toasts-before) * 0.05 + 1;--y:translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}[data-sonner-toast]>*{transition:opacity .4s}[data-sonner-toast][data-x-position=right]{right:0}[data-sonner-toast][data-x-position=left]{left:0}[data-sonner-toast][data-expanded=false][data-front=false][data-styled=true]>*{opacity:0}[data-sonner-toast][data-visible=false]{opacity:0;pointer-events:none}[data-sonner-toast][data-mounted=true][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}[data-sonner-toast][data-removed=true][data-front=true][data-swipe-out=false]{--y:translateY(calc(var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=false]{--y:translateY(40%);opacity:0;transition:transform .5s,opacity .2s}[data-sonner-toast][data-removed=true][data-front=false]::before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y,0)) translateX(var(--swipe-amount-x,0));transition:none}[data-sonner-toast][data-swiped=true]{user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width:600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-sonner-theme=light]{--normal-bg:#fff;--normal-border:var(--gray4);--normal-text:var(--gray12);--success-bg:hsl(143, 85%, 96%);--success-border:hsl(145, 92%, 87%);--success-text:hsl(140, 100%, 27%);--info-bg:hsl(208, 100%, 97%);--info-border:hsl(221, 91%, 93%);--info-text:hsl(210, 92%, 45%);--warning-bg:hsl(49, 100%, 97%);--warning-border:hsl(49, 91%, 84%);--warning-text:hsl(31, 92%, 45%);--error-bg:hsl(359, 100%, 97%);--error-border:hsl(359, 100%, 94%);--error-text:hsl(360, 100%, 45%)}[data-sonner-toaster][data-sonner-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg:#000;--normal-border:hsl(0, 0%, 20%);--normal-text:var(--gray1)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg:#fff;--normal-border:var(--gray3);--normal-text:var(--gray12)}[data-sonner-toaster][data-sonner-theme=dark]{--normal-bg:#000;--normal-bg-hover:hsl(0, 0%, 12%);--normal-border:hsl(0, 0%, 20%);--normal-border-hover:hsl(0, 0%, 25%);--normal-text:var(--gray1);--success-bg:hsl(150, 100%, 6%);--success-border:hsl(147, 100%, 12%);--success-text:hsl(150, 86%, 65%);--info-bg:hsl(215, 100%, 6%);--info-border:hsl(223, 43%, 17%);--info-text:hsl(216, 87%, 65%);--warning-bg:hsl(64, 100%, 6%);--warning-border:hsl(60, 100%, 9%);--warning-text:hsl(46, 87%, 65%);--error-bg:hsl(358, 76%, 10%);--error-border:hsl(357, 89%, 16%);--error-text:hsl(358, 100%, 81%)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size:16px;height:var(--size);width:var(--size);position:absolute;inset:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:first-child{animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}100%{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}100%{opacity:.15}}@media (prefers-reduced-motion){.sonner-loading-bar,[data-sonner-toast],[data-sonner-toast]>*{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)}");
1785
+ function isAction(action) {
1786
+ return action.label !== void 0;
1787
+ }
1788
+ var VISIBLE_TOASTS_AMOUNT = 3;
1789
+ var VIEWPORT_OFFSET = "24px";
1790
+ var MOBILE_VIEWPORT_OFFSET = "16px";
1791
+ var TOAST_LIFETIME = 4e3;
1792
+ var TOAST_WIDTH = 356;
1793
+ var GAP = 14;
1794
+ var SWIPE_THRESHOLD = 45;
1795
+ var TIME_BEFORE_UNMOUNT = 200;
1796
+ function cn(...classes) {
1797
+ return classes.filter(Boolean).join(" ");
1798
+ }
1799
+ function getDefaultSwipeDirections(position) {
1800
+ const [y, x] = position.split("-");
1801
+ const directions = [];
1802
+ if (y) {
1803
+ directions.push(y);
1804
+ }
1805
+ if (x) {
1806
+ directions.push(x);
1807
+ }
1808
+ return directions;
1809
+ }
1810
+ var Toast = (props) => {
1811
+ var _toast_classNames, _toast_classNames1, _toast_classNames2, _toast_classNames3, _toast_classNames4, _toast_classNames5, _toast_classNames6, _toast_classNames7, _toast_classNames8;
1812
+ const { invert: ToasterInvert, toast: toast2, unstyled, interacting, setHeights, visibleToasts, heights, index, toasts, expanded, removeToast, defaultRichColors, closeButton: closeButtonFromToaster, style, cancelButtonStyle, actionButtonStyle, className = "", descriptionClassName = "", duration: durationFromToaster, position, gap, expandByDefault, classNames, icons, closeButtonAriaLabel = "Close toast" } = props;
1813
+ const [swipeDirection, setSwipeDirection] = React__default.default.useState(null);
1814
+ const [swipeOutDirection, setSwipeOutDirection] = React__default.default.useState(null);
1815
+ const [mounted, setMounted] = React__default.default.useState(false);
1816
+ const [removed, setRemoved] = React__default.default.useState(false);
1817
+ const [swiping, setSwiping] = React__default.default.useState(false);
1818
+ const [swipeOut, setSwipeOut] = React__default.default.useState(false);
1819
+ const [isSwiped, setIsSwiped] = React__default.default.useState(false);
1820
+ const [offsetBeforeRemove, setOffsetBeforeRemove] = React__default.default.useState(0);
1821
+ const [initialHeight, setInitialHeight] = React__default.default.useState(0);
1822
+ const remainingTime = React__default.default.useRef(toast2.duration || durationFromToaster || TOAST_LIFETIME);
1823
+ const dragStartTime = React__default.default.useRef(null);
1824
+ const toastRef = React__default.default.useRef(null);
1825
+ const isFront = index === 0;
1826
+ const isVisible = index + 1 <= visibleToasts;
1827
+ const toastType = toast2.type;
1828
+ const dismissible = toast2.dismissible !== false;
1829
+ const toastClassname = toast2.className || "";
1830
+ const toastDescriptionClassname = toast2.descriptionClassName || "";
1831
+ const heightIndex = React__default.default.useMemo(() => heights.findIndex((height) => height.toastId === toast2.id) || 0, [
1832
+ heights,
1833
+ toast2.id
1834
+ ]);
1835
+ const closeButton = React__default.default.useMemo(() => {
1836
+ var _toast_closeButton;
1837
+ return (_toast_closeButton = toast2.closeButton) != null ? _toast_closeButton : closeButtonFromToaster;
1838
+ }, [
1839
+ toast2.closeButton,
1840
+ closeButtonFromToaster
1841
+ ]);
1842
+ const duration = React__default.default.useMemo(() => toast2.duration || durationFromToaster || TOAST_LIFETIME, [
1843
+ toast2.duration,
1844
+ durationFromToaster
1845
+ ]);
1846
+ const closeTimerStartTimeRef = React__default.default.useRef(0);
1847
+ const offset = React__default.default.useRef(0);
1848
+ const lastCloseTimerStartTimeRef = React__default.default.useRef(0);
1849
+ const pointerStartRef = React__default.default.useRef(null);
1850
+ const [y, x] = position.split("-");
1851
+ const toastsHeightBefore = React__default.default.useMemo(() => {
1852
+ return heights.reduce((prev, curr, reducerIndex) => {
1853
+ if (reducerIndex >= heightIndex) {
1854
+ return prev;
1855
+ }
1856
+ return prev + curr.height;
1857
+ }, 0);
1858
+ }, [
1859
+ heights,
1860
+ heightIndex
1861
+ ]);
1862
+ const isDocumentHidden = useIsDocumentHidden();
1863
+ const invert = toast2.invert || ToasterInvert;
1864
+ const disabled = toastType === "loading";
1865
+ offset.current = React__default.default.useMemo(() => heightIndex * gap + toastsHeightBefore, [
1866
+ heightIndex,
1867
+ toastsHeightBefore
1868
+ ]);
1869
+ React__default.default.useEffect(() => {
1870
+ remainingTime.current = duration;
1871
+ }, [
1872
+ duration
1873
+ ]);
1874
+ React__default.default.useEffect(() => {
1875
+ setMounted(true);
1876
+ }, []);
1877
+ React__default.default.useEffect(() => {
1878
+ const toastNode = toastRef.current;
1879
+ if (toastNode) {
1880
+ const height = toastNode.getBoundingClientRect().height;
1881
+ setInitialHeight(height);
1882
+ setHeights((h) => [
1883
+ {
1884
+ toastId: toast2.id,
1885
+ height,
1886
+ position: toast2.position
1887
+ },
1888
+ ...h
1889
+ ]);
1890
+ return () => setHeights((h) => h.filter((height2) => height2.toastId !== toast2.id));
1891
+ }
1892
+ }, [
1893
+ setHeights,
1894
+ toast2.id
1895
+ ]);
1896
+ React__default.default.useLayoutEffect(() => {
1897
+ if (!mounted) return;
1898
+ const toastNode = toastRef.current;
1899
+ const originalHeight = toastNode.style.height;
1900
+ toastNode.style.height = "auto";
1901
+ const newHeight = toastNode.getBoundingClientRect().height;
1902
+ toastNode.style.height = originalHeight;
1903
+ setInitialHeight(newHeight);
1904
+ setHeights((heights2) => {
1905
+ const alreadyExists = heights2.find((height) => height.toastId === toast2.id);
1906
+ if (!alreadyExists) {
1907
+ return [
1908
+ {
1909
+ toastId: toast2.id,
1910
+ height: newHeight,
1911
+ position: toast2.position
1912
+ },
1913
+ ...heights2
1914
+ ];
1915
+ } else {
1916
+ return heights2.map((height) => height.toastId === toast2.id ? {
1917
+ ...height,
1918
+ height: newHeight
1919
+ } : height);
1920
+ }
1921
+ });
1922
+ }, [
1923
+ mounted,
1924
+ toast2.title,
1925
+ toast2.description,
1926
+ setHeights,
1927
+ toast2.id,
1928
+ toast2.jsx,
1929
+ toast2.action,
1930
+ toast2.cancel
1931
+ ]);
1932
+ const deleteToast = React__default.default.useCallback(() => {
1933
+ setRemoved(true);
1934
+ setOffsetBeforeRemove(offset.current);
1935
+ setHeights((h) => h.filter((height) => height.toastId !== toast2.id));
1936
+ setTimeout(() => {
1937
+ removeToast(toast2);
1938
+ }, TIME_BEFORE_UNMOUNT);
1939
+ }, [
1940
+ toast2,
1941
+ removeToast,
1942
+ setHeights,
1943
+ offset
1944
+ ]);
1945
+ React__default.default.useEffect(() => {
1946
+ if (toast2.promise && toastType === "loading" || toast2.duration === Infinity || toast2.type === "loading") return;
1947
+ let timeoutId;
1948
+ const pauseTimer = () => {
1949
+ if (lastCloseTimerStartTimeRef.current < closeTimerStartTimeRef.current) {
1950
+ const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - closeTimerStartTimeRef.current;
1951
+ remainingTime.current = remainingTime.current - elapsedTime;
1952
+ }
1953
+ lastCloseTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
1954
+ };
1955
+ const startTimer = () => {
1956
+ if (remainingTime.current === Infinity) return;
1957
+ closeTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
1958
+ timeoutId = setTimeout(() => {
1959
+ toast2.onAutoClose == null ? void 0 : toast2.onAutoClose.call(toast2, toast2);
1960
+ deleteToast();
1961
+ }, remainingTime.current);
1962
+ };
1963
+ if (expanded || interacting || isDocumentHidden) {
1964
+ pauseTimer();
1965
+ } else {
1966
+ startTimer();
1967
+ }
1968
+ return () => clearTimeout(timeoutId);
1969
+ }, [
1970
+ expanded,
1971
+ interacting,
1972
+ toast2,
1973
+ toastType,
1974
+ isDocumentHidden,
1975
+ deleteToast
1976
+ ]);
1977
+ React__default.default.useEffect(() => {
1978
+ if (toast2.delete) {
1979
+ deleteToast();
1980
+ toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
1981
+ }
1982
+ }, [
1983
+ deleteToast,
1984
+ toast2.delete
1985
+ ]);
1986
+ function getLoadingIcon() {
1987
+ var _toast_classNames9;
1988
+ if (icons == null ? void 0 : icons.loading) {
1989
+ var _toast_classNames12;
1990
+ return /* @__PURE__ */ React__default.default.createElement("div", {
1991
+ className: cn(classNames == null ? void 0 : classNames.loader, toast2 == null ? void 0 : (_toast_classNames12 = toast2.classNames) == null ? void 0 : _toast_classNames12.loader, "sonner-loader"),
1992
+ "data-visible": toastType === "loading"
1993
+ }, icons.loading);
1994
+ }
1995
+ return /* @__PURE__ */ React__default.default.createElement(Loader, {
1996
+ className: cn(classNames == null ? void 0 : classNames.loader, toast2 == null ? void 0 : (_toast_classNames9 = toast2.classNames) == null ? void 0 : _toast_classNames9.loader),
1997
+ visible: toastType === "loading"
1998
+ });
1999
+ }
2000
+ const icon = toast2.icon || (icons == null ? void 0 : icons[toastType]) || getAsset(toastType);
2001
+ var _toast_richColors, _icons_close;
2002
+ return /* @__PURE__ */ React__default.default.createElement("li", {
2003
+ tabIndex: 0,
2004
+ ref: toastRef,
2005
+ className: cn(className, toastClassname, classNames == null ? void 0 : classNames.toast, toast2 == null ? void 0 : (_toast_classNames = toast2.classNames) == null ? void 0 : _toast_classNames.toast, classNames == null ? void 0 : classNames.default, classNames == null ? void 0 : classNames[toastType], toast2 == null ? void 0 : (_toast_classNames1 = toast2.classNames) == null ? void 0 : _toast_classNames1[toastType]),
2006
+ "data-sonner-toast": "",
2007
+ "data-rich-colors": (_toast_richColors = toast2.richColors) != null ? _toast_richColors : defaultRichColors,
2008
+ "data-styled": !Boolean(toast2.jsx || toast2.unstyled || unstyled),
2009
+ "data-mounted": mounted,
2010
+ "data-promise": Boolean(toast2.promise),
2011
+ "data-swiped": isSwiped,
2012
+ "data-removed": removed,
2013
+ "data-visible": isVisible,
2014
+ "data-y-position": y,
2015
+ "data-x-position": x,
2016
+ "data-index": index,
2017
+ "data-front": isFront,
2018
+ "data-swiping": swiping,
2019
+ "data-dismissible": dismissible,
2020
+ "data-type": toastType,
2021
+ "data-invert": invert,
2022
+ "data-swipe-out": swipeOut,
2023
+ "data-swipe-direction": swipeOutDirection,
2024
+ "data-expanded": Boolean(expanded || expandByDefault && mounted),
2025
+ "data-testid": toast2.testId,
2026
+ style: {
2027
+ "--index": index,
2028
+ "--toasts-before": index,
2029
+ "--z-index": toasts.length - index,
2030
+ "--offset": `${removed ? offsetBeforeRemove : offset.current}px`,
2031
+ "--initial-height": expandByDefault ? "auto" : `${initialHeight}px`,
2032
+ ...style,
2033
+ ...toast2.style
2034
+ },
2035
+ onDragEnd: () => {
2036
+ setSwiping(false);
2037
+ setSwipeDirection(null);
2038
+ pointerStartRef.current = null;
2039
+ },
2040
+ onPointerDown: (event) => {
2041
+ if (event.button === 2) return;
2042
+ if (disabled || !dismissible) return;
2043
+ dragStartTime.current = /* @__PURE__ */ new Date();
2044
+ setOffsetBeforeRemove(offset.current);
2045
+ event.target.setPointerCapture(event.pointerId);
2046
+ if (event.target.tagName === "BUTTON") return;
2047
+ setSwiping(true);
2048
+ pointerStartRef.current = {
2049
+ x: event.clientX,
2050
+ y: event.clientY
2051
+ };
2052
+ },
2053
+ onPointerUp: () => {
2054
+ var _toastRef_current, _toastRef_current1, _dragStartTime_current;
2055
+ if (swipeOut || !dismissible) return;
2056
+ pointerStartRef.current = null;
2057
+ const swipeAmountX = Number(((_toastRef_current = toastRef.current) == null ? void 0 : _toastRef_current.style.getPropertyValue("--swipe-amount-x").replace("px", "")) || 0);
2058
+ const swipeAmountY = Number(((_toastRef_current1 = toastRef.current) == null ? void 0 : _toastRef_current1.style.getPropertyValue("--swipe-amount-y").replace("px", "")) || 0);
2059
+ const timeTaken = (/* @__PURE__ */ new Date()).getTime() - ((_dragStartTime_current = dragStartTime.current) == null ? void 0 : _dragStartTime_current.getTime());
2060
+ const swipeAmount = swipeDirection === "x" ? swipeAmountX : swipeAmountY;
2061
+ const velocity = Math.abs(swipeAmount) / timeTaken;
2062
+ if (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11) {
2063
+ setOffsetBeforeRemove(offset.current);
2064
+ toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
2065
+ if (swipeDirection === "x") {
2066
+ setSwipeOutDirection(swipeAmountX > 0 ? "right" : "left");
2067
+ } else {
2068
+ setSwipeOutDirection(swipeAmountY > 0 ? "down" : "up");
2069
+ }
2070
+ deleteToast();
2071
+ setSwipeOut(true);
2072
+ return;
2073
+ } else {
2074
+ var _toastRef_current2, _toastRef_current3;
2075
+ (_toastRef_current2 = toastRef.current) == null ? void 0 : _toastRef_current2.style.setProperty("--swipe-amount-x", `0px`);
2076
+ (_toastRef_current3 = toastRef.current) == null ? void 0 : _toastRef_current3.style.setProperty("--swipe-amount-y", `0px`);
2077
+ }
2078
+ setIsSwiped(false);
2079
+ setSwiping(false);
2080
+ setSwipeDirection(null);
2081
+ },
2082
+ onPointerMove: (event) => {
2083
+ var _window_getSelection, _toastRef_current, _toastRef_current1;
2084
+ if (!pointerStartRef.current || !dismissible) return;
2085
+ const isHighlighted = ((_window_getSelection = window.getSelection()) == null ? void 0 : _window_getSelection.toString().length) > 0;
2086
+ if (isHighlighted) return;
2087
+ const yDelta = event.clientY - pointerStartRef.current.y;
2088
+ const xDelta = event.clientX - pointerStartRef.current.x;
2089
+ var _props_swipeDirections;
2090
+ const swipeDirections = (_props_swipeDirections = props.swipeDirections) != null ? _props_swipeDirections : getDefaultSwipeDirections(position);
2091
+ if (!swipeDirection && (Math.abs(xDelta) > 1 || Math.abs(yDelta) > 1)) {
2092
+ setSwipeDirection(Math.abs(xDelta) > Math.abs(yDelta) ? "x" : "y");
2093
+ }
2094
+ let swipeAmount = {
2095
+ x: 0,
2096
+ y: 0
2097
+ };
2098
+ const getDampening = (delta) => {
2099
+ const factor = Math.abs(delta) / 20;
2100
+ return 1 / (1.5 + factor);
2101
+ };
2102
+ if (swipeDirection === "y") {
2103
+ if (swipeDirections.includes("top") || swipeDirections.includes("bottom")) {
2104
+ if (swipeDirections.includes("top") && yDelta < 0 || swipeDirections.includes("bottom") && yDelta > 0) {
2105
+ swipeAmount.y = yDelta;
2106
+ } else {
2107
+ const dampenedDelta = yDelta * getDampening(yDelta);
2108
+ swipeAmount.y = Math.abs(dampenedDelta) < Math.abs(yDelta) ? dampenedDelta : yDelta;
2109
+ }
2110
+ }
2111
+ } else if (swipeDirection === "x") {
2112
+ if (swipeDirections.includes("left") || swipeDirections.includes("right")) {
2113
+ if (swipeDirections.includes("left") && xDelta < 0 || swipeDirections.includes("right") && xDelta > 0) {
2114
+ swipeAmount.x = xDelta;
2115
+ } else {
2116
+ const dampenedDelta = xDelta * getDampening(xDelta);
2117
+ swipeAmount.x = Math.abs(dampenedDelta) < Math.abs(xDelta) ? dampenedDelta : xDelta;
2118
+ }
2119
+ }
2120
+ }
2121
+ if (Math.abs(swipeAmount.x) > 0 || Math.abs(swipeAmount.y) > 0) {
2122
+ setIsSwiped(true);
2123
+ }
2124
+ (_toastRef_current = toastRef.current) == null ? void 0 : _toastRef_current.style.setProperty("--swipe-amount-x", `${swipeAmount.x}px`);
2125
+ (_toastRef_current1 = toastRef.current) == null ? void 0 : _toastRef_current1.style.setProperty("--swipe-amount-y", `${swipeAmount.y}px`);
2126
+ }
2127
+ }, closeButton && !toast2.jsx && toastType !== "loading" ? /* @__PURE__ */ React__default.default.createElement("button", {
2128
+ "aria-label": closeButtonAriaLabel,
2129
+ "data-disabled": disabled,
2130
+ "data-close-button": true,
2131
+ onClick: disabled || !dismissible ? () => {
2132
+ } : () => {
2133
+ deleteToast();
2134
+ toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
2135
+ },
2136
+ className: cn(classNames == null ? void 0 : classNames.closeButton, toast2 == null ? void 0 : (_toast_classNames2 = toast2.classNames) == null ? void 0 : _toast_classNames2.closeButton)
2137
+ }, (_icons_close = icons == null ? void 0 : icons.close) != null ? _icons_close : CloseIcon) : null, (toastType || toast2.icon || toast2.promise) && toast2.icon !== null && ((icons == null ? void 0 : icons[toastType]) !== null || toast2.icon) ? /* @__PURE__ */ React__default.default.createElement("div", {
2138
+ "data-icon": "",
2139
+ className: cn(classNames == null ? void 0 : classNames.icon, toast2 == null ? void 0 : (_toast_classNames3 = toast2.classNames) == null ? void 0 : _toast_classNames3.icon)
2140
+ }, toast2.promise || toast2.type === "loading" && !toast2.icon ? toast2.icon || getLoadingIcon() : null, toast2.type !== "loading" ? icon : null) : null, /* @__PURE__ */ React__default.default.createElement("div", {
2141
+ "data-content": "",
2142
+ className: cn(classNames == null ? void 0 : classNames.content, toast2 == null ? void 0 : (_toast_classNames4 = toast2.classNames) == null ? void 0 : _toast_classNames4.content)
2143
+ }, /* @__PURE__ */ React__default.default.createElement("div", {
2144
+ "data-title": "",
2145
+ className: cn(classNames == null ? void 0 : classNames.title, toast2 == null ? void 0 : (_toast_classNames5 = toast2.classNames) == null ? void 0 : _toast_classNames5.title)
2146
+ }, toast2.jsx ? toast2.jsx : typeof toast2.title === "function" ? toast2.title() : toast2.title), toast2.description ? /* @__PURE__ */ React__default.default.createElement("div", {
2147
+ "data-description": "",
2148
+ className: cn(descriptionClassName, toastDescriptionClassname, classNames == null ? void 0 : classNames.description, toast2 == null ? void 0 : (_toast_classNames6 = toast2.classNames) == null ? void 0 : _toast_classNames6.description)
2149
+ }, typeof toast2.description === "function" ? toast2.description() : toast2.description) : null), /* @__PURE__ */ React__default.default.isValidElement(toast2.cancel) ? toast2.cancel : toast2.cancel && isAction(toast2.cancel) ? /* @__PURE__ */ React__default.default.createElement("button", {
2150
+ "data-button": true,
2151
+ "data-cancel": true,
2152
+ style: toast2.cancelButtonStyle || cancelButtonStyle,
2153
+ onClick: (event) => {
2154
+ if (!isAction(toast2.cancel)) return;
2155
+ if (!dismissible) return;
2156
+ toast2.cancel.onClick == null ? void 0 : toast2.cancel.onClick.call(toast2.cancel, event);
2157
+ deleteToast();
2158
+ },
2159
+ className: cn(classNames == null ? void 0 : classNames.cancelButton, toast2 == null ? void 0 : (_toast_classNames7 = toast2.classNames) == null ? void 0 : _toast_classNames7.cancelButton)
2160
+ }, toast2.cancel.label) : null, /* @__PURE__ */ React__default.default.isValidElement(toast2.action) ? toast2.action : toast2.action && isAction(toast2.action) ? /* @__PURE__ */ React__default.default.createElement("button", {
2161
+ "data-button": true,
2162
+ "data-action": true,
2163
+ style: toast2.actionButtonStyle || actionButtonStyle,
2164
+ onClick: (event) => {
2165
+ if (!isAction(toast2.action)) return;
2166
+ toast2.action.onClick == null ? void 0 : toast2.action.onClick.call(toast2.action, event);
2167
+ if (event.defaultPrevented) return;
2168
+ deleteToast();
2169
+ },
2170
+ className: cn(classNames == null ? void 0 : classNames.actionButton, toast2 == null ? void 0 : (_toast_classNames8 = toast2.classNames) == null ? void 0 : _toast_classNames8.actionButton)
2171
+ }, toast2.action.label) : null);
2172
+ };
2173
+ function getDocumentDirection() {
2174
+ if (typeof window === "undefined") return "ltr";
2175
+ if (typeof document === "undefined") return "ltr";
2176
+ const dirAttribute = document.documentElement.getAttribute("dir");
2177
+ if (dirAttribute === "auto" || !dirAttribute) {
2178
+ return window.getComputedStyle(document.documentElement).direction;
2179
+ }
2180
+ return dirAttribute;
2181
+ }
2182
+ function assignOffset(defaultOffset, mobileOffset) {
2183
+ const styles = {};
2184
+ [
2185
+ defaultOffset,
2186
+ mobileOffset
2187
+ ].forEach((offset, index) => {
2188
+ const isMobile = index === 1;
2189
+ const prefix = isMobile ? "--mobile-offset" : "--offset";
2190
+ const defaultValue = isMobile ? MOBILE_VIEWPORT_OFFSET : VIEWPORT_OFFSET;
2191
+ function assignAll(offset2) {
2192
+ [
2193
+ "top",
2194
+ "right",
2195
+ "bottom",
2196
+ "left"
2197
+ ].forEach((key) => {
2198
+ styles[`${prefix}-${key}`] = typeof offset2 === "number" ? `${offset2}px` : offset2;
2199
+ });
2200
+ }
2201
+ if (typeof offset === "number" || typeof offset === "string") {
2202
+ assignAll(offset);
2203
+ } else if (typeof offset === "object") {
2204
+ [
2205
+ "top",
2206
+ "right",
2207
+ "bottom",
2208
+ "left"
2209
+ ].forEach((key) => {
2210
+ if (offset[key] === void 0) {
2211
+ styles[`${prefix}-${key}`] = defaultValue;
2212
+ } else {
2213
+ styles[`${prefix}-${key}`] = typeof offset[key] === "number" ? `${offset[key]}px` : offset[key];
2214
+ }
2215
+ });
2216
+ } else {
2217
+ assignAll(defaultValue);
2218
+ }
2219
+ });
2220
+ return styles;
2221
+ }
2222
+ var Toaster = /* @__PURE__ */ React__default.default.forwardRef(function Toaster2(props, ref) {
2223
+ const { id, invert, position = "bottom-right", hotkey = [
2224
+ "altKey",
2225
+ "KeyT"
2226
+ ], expand, closeButton, className, offset, mobileOffset, theme = "light", richColors, duration, style, visibleToasts = VISIBLE_TOASTS_AMOUNT, toastOptions, dir = getDocumentDirection(), gap = GAP, icons, containerAriaLabel = "Notifications" } = props;
2227
+ const [toasts, setToasts] = React__default.default.useState([]);
2228
+ const filteredToasts = React__default.default.useMemo(() => {
2229
+ if (id) {
2230
+ return toasts.filter((toast2) => toast2.toasterId === id);
2231
+ }
2232
+ return toasts.filter((toast2) => !toast2.toasterId);
2233
+ }, [
2234
+ toasts,
2235
+ id
2236
+ ]);
2237
+ const possiblePositions = React__default.default.useMemo(() => {
2238
+ return Array.from(new Set([
2239
+ position
2240
+ ].concat(filteredToasts.filter((toast2) => toast2.position).map((toast2) => toast2.position))));
2241
+ }, [
2242
+ filteredToasts,
2243
+ position
2244
+ ]);
2245
+ const [heights, setHeights] = React__default.default.useState([]);
2246
+ const [expanded, setExpanded] = React__default.default.useState(false);
2247
+ const [interacting, setInteracting] = React__default.default.useState(false);
2248
+ const [actualTheme, setActualTheme] = React__default.default.useState(theme !== "system" ? theme : typeof window !== "undefined" ? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : "light");
2249
+ const listRef = React__default.default.useRef(null);
2250
+ const hotkeyLabel = hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, "");
2251
+ const lastFocusedElementRef = React__default.default.useRef(null);
2252
+ const isFocusWithinRef = React__default.default.useRef(false);
2253
+ const removeToast = React__default.default.useCallback((toastToRemove) => {
2254
+ setToasts((toasts2) => {
2255
+ var _toasts_find;
2256
+ if (!((_toasts_find = toasts2.find((toast2) => toast2.id === toastToRemove.id)) == null ? void 0 : _toasts_find.delete)) {
2257
+ ToastState.dismiss(toastToRemove.id);
2258
+ }
2259
+ return toasts2.filter(({ id: id2 }) => id2 !== toastToRemove.id);
2260
+ });
2261
+ }, []);
2262
+ React__default.default.useEffect(() => {
2263
+ return ToastState.subscribe((toast2) => {
2264
+ if (toast2.dismiss) {
2265
+ requestAnimationFrame(() => {
2266
+ setToasts((toasts2) => toasts2.map((t) => t.id === toast2.id ? {
2267
+ ...t,
2268
+ delete: true
2269
+ } : t));
2270
+ });
2271
+ return;
2272
+ }
2273
+ setTimeout(() => {
2274
+ ReactDOM__default.default.flushSync(() => {
2275
+ setToasts((toasts2) => {
2276
+ const indexOfExistingToast = toasts2.findIndex((t) => t.id === toast2.id);
2277
+ if (indexOfExistingToast !== -1) {
2278
+ return [
2279
+ ...toasts2.slice(0, indexOfExistingToast),
2280
+ {
2281
+ ...toasts2[indexOfExistingToast],
2282
+ ...toast2
2283
+ },
2284
+ ...toasts2.slice(indexOfExistingToast + 1)
2285
+ ];
2286
+ }
2287
+ return [
2288
+ toast2,
2289
+ ...toasts2
2290
+ ];
2291
+ });
2292
+ });
2293
+ });
2294
+ });
2295
+ }, [
2296
+ toasts
2297
+ ]);
2298
+ React__default.default.useEffect(() => {
2299
+ if (theme !== "system") {
2300
+ setActualTheme(theme);
2301
+ return;
2302
+ }
2303
+ if (theme === "system") {
2304
+ if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
2305
+ setActualTheme("dark");
2306
+ } else {
2307
+ setActualTheme("light");
2308
+ }
2309
+ }
2310
+ if (typeof window === "undefined") return;
2311
+ const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
2312
+ try {
2313
+ darkMediaQuery.addEventListener("change", ({ matches }) => {
2314
+ if (matches) {
2315
+ setActualTheme("dark");
2316
+ } else {
2317
+ setActualTheme("light");
2318
+ }
2319
+ });
2320
+ } catch (error) {
2321
+ darkMediaQuery.addListener(({ matches }) => {
2322
+ try {
2323
+ if (matches) {
2324
+ setActualTheme("dark");
2325
+ } else {
2326
+ setActualTheme("light");
2327
+ }
2328
+ } catch (e) {
2329
+ console.error(e);
2330
+ }
2331
+ });
2332
+ }
2333
+ }, [
2334
+ theme
2335
+ ]);
2336
+ React__default.default.useEffect(() => {
2337
+ if (toasts.length <= 1) {
2338
+ setExpanded(false);
2339
+ }
2340
+ }, [
2341
+ toasts
2342
+ ]);
2343
+ React__default.default.useEffect(() => {
2344
+ const handleKeyDown = (event) => {
2345
+ var _listRef_current;
2346
+ const isHotkeyPressed = hotkey.every((key) => event[key] || event.code === key);
2347
+ if (isHotkeyPressed) {
2348
+ var _listRef_current1;
2349
+ setExpanded(true);
2350
+ (_listRef_current1 = listRef.current) == null ? void 0 : _listRef_current1.focus();
2351
+ }
2352
+ if (event.code === "Escape" && (document.activeElement === listRef.current || ((_listRef_current = listRef.current) == null ? void 0 : _listRef_current.contains(document.activeElement)))) {
2353
+ setExpanded(false);
2354
+ }
2355
+ };
2356
+ document.addEventListener("keydown", handleKeyDown);
2357
+ return () => document.removeEventListener("keydown", handleKeyDown);
2358
+ }, [
2359
+ hotkey
2360
+ ]);
2361
+ React__default.default.useEffect(() => {
2362
+ if (listRef.current) {
2363
+ return () => {
2364
+ if (lastFocusedElementRef.current) {
2365
+ lastFocusedElementRef.current.focus({
2366
+ preventScroll: true
2367
+ });
2368
+ lastFocusedElementRef.current = null;
2369
+ isFocusWithinRef.current = false;
2370
+ }
2371
+ };
2372
+ }
2373
+ }, [
2374
+ listRef.current
2375
+ ]);
2376
+ return (
2377
+ // Remove item from normal navigation flow, only available via hotkey
2378
+ /* @__PURE__ */ React__default.default.createElement("section", {
2379
+ ref,
2380
+ "aria-label": `${containerAriaLabel} ${hotkeyLabel}`,
2381
+ tabIndex: -1,
2382
+ "aria-live": "polite",
2383
+ "aria-relevant": "additions text",
2384
+ "aria-atomic": "false",
2385
+ suppressHydrationWarning: true
2386
+ }, possiblePositions.map((position2, index) => {
2387
+ var _heights_;
2388
+ const [y, x] = position2.split("-");
2389
+ if (!filteredToasts.length) return null;
2390
+ return /* @__PURE__ */ React__default.default.createElement("ol", {
2391
+ key: position2,
2392
+ dir: dir === "auto" ? getDocumentDirection() : dir,
2393
+ tabIndex: -1,
2394
+ ref: listRef,
2395
+ className,
2396
+ "data-sonner-toaster": true,
2397
+ "data-sonner-theme": actualTheme,
2398
+ "data-y-position": y,
2399
+ "data-x-position": x,
2400
+ style: {
2401
+ "--front-toast-height": `${((_heights_ = heights[0]) == null ? void 0 : _heights_.height) || 0}px`,
2402
+ "--width": `${TOAST_WIDTH}px`,
2403
+ "--gap": `${gap}px`,
2404
+ ...style,
2405
+ ...assignOffset(offset, mobileOffset)
2406
+ },
2407
+ onBlur: (event) => {
2408
+ if (isFocusWithinRef.current && !event.currentTarget.contains(event.relatedTarget)) {
2409
+ isFocusWithinRef.current = false;
2410
+ if (lastFocusedElementRef.current) {
2411
+ lastFocusedElementRef.current.focus({
2412
+ preventScroll: true
2413
+ });
2414
+ lastFocusedElementRef.current = null;
2415
+ }
2416
+ }
2417
+ },
2418
+ onFocus: (event) => {
2419
+ const isNotDismissible = event.target instanceof HTMLElement && event.target.dataset.dismissible === "false";
2420
+ if (isNotDismissible) return;
2421
+ if (!isFocusWithinRef.current) {
2422
+ isFocusWithinRef.current = true;
2423
+ lastFocusedElementRef.current = event.relatedTarget;
2424
+ }
2425
+ },
2426
+ onMouseEnter: () => setExpanded(true),
2427
+ onMouseMove: () => setExpanded(true),
2428
+ onMouseLeave: () => {
2429
+ if (!interacting) {
2430
+ setExpanded(false);
2431
+ }
2432
+ },
2433
+ onDragEnd: () => setExpanded(false),
2434
+ onPointerDown: (event) => {
2435
+ const isNotDismissible = event.target instanceof HTMLElement && event.target.dataset.dismissible === "false";
2436
+ if (isNotDismissible) return;
2437
+ setInteracting(true);
2438
+ },
2439
+ onPointerUp: () => setInteracting(false)
2440
+ }, filteredToasts.filter((toast2) => !toast2.position && index === 0 || toast2.position === position2).map((toast2, index2) => {
2441
+ var _toastOptions_duration, _toastOptions_closeButton;
2442
+ return /* @__PURE__ */ React__default.default.createElement(Toast, {
2443
+ key: toast2.id,
2444
+ icons,
2445
+ index: index2,
2446
+ toast: toast2,
2447
+ defaultRichColors: richColors,
2448
+ duration: (_toastOptions_duration = toastOptions == null ? void 0 : toastOptions.duration) != null ? _toastOptions_duration : duration,
2449
+ className: toastOptions == null ? void 0 : toastOptions.className,
2450
+ descriptionClassName: toastOptions == null ? void 0 : toastOptions.descriptionClassName,
2451
+ invert,
2452
+ visibleToasts,
2453
+ closeButton: (_toastOptions_closeButton = toastOptions == null ? void 0 : toastOptions.closeButton) != null ? _toastOptions_closeButton : closeButton,
2454
+ interacting,
2455
+ position: position2,
2456
+ style: toastOptions == null ? void 0 : toastOptions.style,
2457
+ unstyled: toastOptions == null ? void 0 : toastOptions.unstyled,
2458
+ classNames: toastOptions == null ? void 0 : toastOptions.classNames,
2459
+ cancelButtonStyle: toastOptions == null ? void 0 : toastOptions.cancelButtonStyle,
2460
+ actionButtonStyle: toastOptions == null ? void 0 : toastOptions.actionButtonStyle,
2461
+ closeButtonAriaLabel: toastOptions == null ? void 0 : toastOptions.closeButtonAriaLabel,
2462
+ removeToast,
2463
+ toasts: filteredToasts.filter((t) => t.position == toast2.position),
2464
+ heights: heights.filter((h) => h.position == toast2.position),
2465
+ setHeights,
2466
+ expandByDefault: expand,
2467
+ gap,
2468
+ expanded,
2469
+ swipeDirections: props.swipeDirections
2470
+ });
2471
+ }));
2472
+ }))
2473
+ );
2474
+ });
1585
2475
  function FunnelToaster(props = {}) {
1586
- return react.createElement(sonner.Toaster, { position: "top-center", ...props });
2476
+ return React.createElement(Toaster, { position: "top-center", ...props });
1587
2477
  }
1588
2478
  function renderToaster(toaster) {
1589
2479
  if (toaster === false) return null;
1590
- return react.createElement(sonner.Toaster, { position: "top-center", ...toaster === true ? {} : toaster });
2480
+ return /* @__PURE__ */ jsxRuntime.jsx(FunnelToaster, { ...toaster === true ? {} : toaster });
1591
2481
  }
1592
2482
 
1593
2483
  // src/state/namespaces.ts
@@ -1653,7 +2543,7 @@ function createFunnel(store, context, tracker, experiments = []) {
1653
2543
  })
1654
2544
  };
1655
2545
  }
1656
- var FunnelCtx = react.createContext(null);
2546
+ var FunnelCtx = React.createContext(null);
1657
2547
  function FunnelProvider({
1658
2548
  config,
1659
2549
  sessionValues,
@@ -1669,7 +2559,7 @@ function FunnelProvider({
1669
2559
  children
1670
2560
  }) {
1671
2561
  const resolvedTracker = tracker ?? FALLBACK_TRACKER;
1672
- const [value] = react.useState(() => {
2562
+ const [value] = React.useState(() => {
1673
2563
  const s = store ?? createFunnelStore(
1674
2564
  { responses: config?.responses, data: config?.data },
1675
2565
  sessionValues
@@ -1686,44 +2576,51 @@ function FunnelProvider({
1686
2576
  getVisitorId: () => ctx.identity.visitorId
1687
2577
  });
1688
2578
  const busTracker = withBus(resolvedTracker, bus);
2579
+ const emailForCheckout = () => {
2580
+ const value2 = s.get("user.email");
2581
+ return typeof value2 === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(value2) ? value2 : void 0;
2582
+ };
2583
+ const catalog = chunkJSRKA375_cjs.buildCatalog(products ?? []);
1689
2584
  return {
1690
2585
  funnel: createFunnel(s, ctx, busTracker, experiments ?? []),
1691
2586
  store: s,
1692
2587
  context: ctx,
1693
- catalog: buildCatalog(products ?? []),
1694
- driver: checkout ?? createMockDriver(),
2588
+ catalog,
2589
+ // Slot → catalog-key resolution wraps the email-enriching driver, so the wire charges the real
2590
+ // catalog key while pages + analytics keep the durable SLOT identity (req.product).
2591
+ driver: driverWithCatalog(driverWithEmail(checkout ?? createMockDriver(), emailForCheckout), catalog),
1695
2592
  tracker: busTracker,
1696
2593
  bus
1697
2594
  };
1698
2595
  });
1699
- react.useEffect(() => attachBus(value.bus), [value.bus]);
1700
- react.useEffect(() => {
2596
+ React.useEffect(() => attachBus(value.bus), [value.bus]);
2597
+ React.useEffect(() => {
1701
2598
  value.tracker.setAcquisition?.(buildAcquisition(value.context));
1702
2599
  }, [value]);
1703
- const tree = react.createElement(TrackerProvider, {
2600
+ const tree = React.createElement(TrackerProvider, {
1704
2601
  tracker: value.tracker,
1705
- children: react.createElement(CheckoutDriverProvider, {
2602
+ children: React.createElement(CheckoutDriverProvider, {
1706
2603
  driver: value.driver,
1707
- children: react.createElement(CatalogProvider, {
2604
+ children: React.createElement(CatalogProvider, {
1708
2605
  catalog: value.catalog,
1709
- children: react.createElement(FunnelCtx.Provider, {
2606
+ children: React.createElement(FunnelCtx.Provider, {
1710
2607
  value,
1711
- children: react.createElement(LocaleProvider, {
2608
+ children: React.createElement(LocaleProvider, {
1712
2609
  config: config?.locales,
1713
2610
  catalog: messages,
1714
2611
  detected: value.context.locale.locale,
1715
2612
  override: localeOverride,
1716
- children: react.createElement(ModalRuntime, { children })
2613
+ children: React.createElement(ModalRuntime, { children })
1717
2614
  })
1718
2615
  })
1719
2616
  })
1720
2617
  })
1721
2618
  });
1722
- return react.createElement(react.Fragment, null, tree, renderToaster(toaster));
2619
+ return React.createElement(React.Fragment, null, tree, renderToaster(toaster));
1723
2620
  }
1724
2621
  var FALLBACK_TRACKER = createConsoleTracker({ silent: true });
1725
2622
  function useFunnelCtx() {
1726
- const ctx = react.useContext(FunnelCtx);
2623
+ const ctx = React.useContext(FunnelCtx);
1727
2624
  if (!ctx) {
1728
2625
  throw new Error("useFunnel/useResponse/\u2026 must be used inside <FunnelProvider>");
1729
2626
  }
@@ -1733,18 +2630,18 @@ function useFunnel() {
1733
2630
  return useFunnelCtx().funnel;
1734
2631
  }
1735
2632
  function useStoreKey(store, key) {
1736
- const subscribe = react.useCallback(
2633
+ const subscribe = React.useCallback(
1737
2634
  (cb) => store.subscribe(cb, { keys: [key] }),
1738
2635
  [store, key]
1739
2636
  );
1740
- const getSnapshot = react.useCallback(() => store.get(key), [store, key]);
1741
- return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
2637
+ const getSnapshot = React.useCallback(() => store.get(key), [store, key]);
2638
+ return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
1742
2639
  }
1743
2640
  function makeFieldHook(ns) {
1744
2641
  return function useNamespaceField(key) {
1745
2642
  const { funnel, store } = useFunnelCtx();
1746
2643
  const value = useStoreKey(store, `${NAMESPACE_PREFIX[ns]}.${key}`);
1747
- const set = react.useCallback(
2644
+ const set = React.useCallback(
1748
2645
  (v) => funnel[ns].set({ [key]: v }),
1749
2646
  [funnel, key]
1750
2647
  );
@@ -1763,7 +2660,7 @@ function useField(path) {
1763
2660
  throw new Error(`useField: "${path}" is not a writable namespace (user/responses/data)`);
1764
2661
  }
1765
2662
  const value = useStoreKey(store, `${NAMESPACE_PREFIX[ns]}.${key}`);
1766
- const set = react.useCallback(
2663
+ const set = React.useCallback(
1767
2664
  (v) => funnel[ns].set({ [key]: v }),
1768
2665
  [funnel, ns, key]
1769
2666
  );
@@ -1789,11 +2686,237 @@ function useSystem() {
1789
2686
  }
1790
2687
  function useContextValue(path) {
1791
2688
  const ctx = useContextObject();
1792
- return react.useMemo(
2689
+ return React.useMemo(
1793
2690
  () => path.split(".").reduce((acc, k) => acc?.[k], ctx),
1794
2691
  [ctx, path]
1795
2692
  );
1796
2693
  }
2694
+
2695
+ // src/tracking/platformTracker.ts
2696
+ function validClickIds(acq) {
2697
+ return Object.entries(acq.clickIds ?? {}).filter(
2698
+ (e) => typeof e[1] === "string" && e[1] !== ""
2699
+ );
2700
+ }
2701
+ function acquisitionQueryBag(acq) {
2702
+ const q = {};
2703
+ const utm = acq.utm ?? {};
2704
+ for (const [k, v] of Object.entries({
2705
+ utm_source: utm.source,
2706
+ utm_medium: utm.medium,
2707
+ utm_campaign: utm.campaign,
2708
+ utm_term: utm.term,
2709
+ utm_content: utm.content
2710
+ })) if (v) q[k] = v;
2711
+ for (const [k, v] of validClickIds(acq)) q[k] = v;
2712
+ if (acq.cookies?.fbp) q._fbp = acq.cookies.fbp;
2713
+ if (acq.cookies?.fbc) q._fbc = acq.cookies.fbc;
2714
+ return q;
2715
+ }
2716
+ function acquisitionAdAttribution(acq) {
2717
+ const a = {};
2718
+ for (const [k, v] of validClickIds(acq)) a[k] = v;
2719
+ if (acq.cookies?.fbp) a.fbp = acq.cookies.fbp;
2720
+ if (acq.cookies?.fbc) a.fbc = acq.cookies.fbc;
2721
+ else if (acq.clickIds?.fbclid) a.fbc = `fb.1.${Date.now()}.${acq.clickIds.fbclid}`;
2722
+ return a;
2723
+ }
2724
+ function createPlatformTracker(cfg) {
2725
+ if (typeof window === "undefined" || cfg.mode === "test") return createConsoleTracker();
2726
+ const base = cfg.apiBase.replace(/\/+$/, "");
2727
+ const url = `${base}/campaign/${encodeURIComponent(cfg.campaignId)}/event`;
2728
+ const sidKey = `af_sid:${cfg.campaignId}`;
2729
+ let sessionId = null;
2730
+ try {
2731
+ sessionId = window.sessionStorage.getItem(sidKey);
2732
+ } catch {
2733
+ }
2734
+ if (!sessionId && cfg.sessionId) sessionId = cfg.sessionId;
2735
+ let acquisition = null;
2736
+ let acquisitionSent = false;
2737
+ let chain = Promise.resolve();
2738
+ const send = async (event, data, userData) => {
2739
+ let mergedUserData = userData;
2740
+ let adAttribution;
2741
+ let attachingAcquisition = false;
2742
+ if (acquisition && !acquisitionSent) {
2743
+ attachingAcquisition = true;
2744
+ const query = acquisitionQueryBag(acquisition);
2745
+ mergedUserData = Object.keys(query).length ? { ...userData, query } : userData;
2746
+ const ad = acquisitionAdAttribution(acquisition);
2747
+ if (Object.keys(ad).length) adAttribution = ad;
2748
+ }
2749
+ const body = {
2750
+ campaignId: cfg.campaignId,
2751
+ funnelId: cfg.funnelId,
2752
+ event,
2753
+ sessionId: sessionId ?? void 0,
2754
+ visitorId: cfg.visitorId ?? void 0,
2755
+ eventId: typeof data?.eventId === "string" ? data.eventId : void 0,
2756
+ data: data ?? {},
2757
+ metadata: {
2758
+ language: typeof navigator !== "undefined" ? navigator.language : void 0,
2759
+ screen: typeof window.screen !== "undefined" ? `${window.screen.width}x${window.screen.height}` : void 0,
2760
+ timezone: (() => {
2761
+ try {
2762
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
2763
+ } catch {
2764
+ return void 0;
2765
+ }
2766
+ })(),
2767
+ referrer: typeof document !== "undefined" && document.referrer ? document.referrer : void 0
2768
+ },
2769
+ ...mergedUserData ? { userData: mergedUserData } : {},
2770
+ ...adAttribution ? { adAttribution } : {}
2771
+ };
2772
+ const res = await fetch(url, {
2773
+ method: "POST",
2774
+ headers: { "content-type": "application/json" },
2775
+ body: JSON.stringify(body),
2776
+ keepalive: true
2777
+ // survives page.exit / unload
2778
+ });
2779
+ if (attachingAcquisition) acquisitionSent = true;
2780
+ const json = await res.json().catch(() => null);
2781
+ if (json?.sessionId && json.sessionId !== sessionId) {
2782
+ sessionId = json.sessionId;
2783
+ try {
2784
+ window.sessionStorage.setItem(sidKey, sessionId);
2785
+ } catch {
2786
+ }
2787
+ }
2788
+ };
2789
+ const enqueue = (event, data, userData) => {
2790
+ const task = () => send(event, data, userData).catch((e) => {
2791
+ if (process.env.NODE_ENV !== "production") console.warn(`[appfunnel] track failed (${event}):`, e);
2792
+ });
2793
+ if (!sessionId) {
2794
+ chain = chain.then(task);
2795
+ } else {
2796
+ void task();
2797
+ }
2798
+ };
2799
+ const VARS_DEBOUNCE_MS = 800;
2800
+ let pendingVars = null;
2801
+ let varsTimer = null;
2802
+ const flushVars = () => {
2803
+ if (varsTimer) {
2804
+ clearTimeout(varsTimer);
2805
+ varsTimer = null;
2806
+ }
2807
+ if (!pendingVars) return;
2808
+ const doPost = () => {
2809
+ if (!pendingVars || !sessionId) return;
2810
+ const userData = pendingVars;
2811
+ pendingVars = null;
2812
+ void fetch(`${base}/campaign/${encodeURIComponent(cfg.campaignId)}/event/session/data`, {
2813
+ method: "POST",
2814
+ headers: { "content-type": "application/json" },
2815
+ body: JSON.stringify({ sessionId, userData }),
2816
+ keepalive: true
2817
+ }).catch((e) => {
2818
+ if (process.env.NODE_ENV !== "production") console.warn("[appfunnel] variable persist failed:", e);
2819
+ });
2820
+ };
2821
+ if (sessionId) doPost();
2822
+ else chain = chain.then(doPost);
2823
+ };
2824
+ try {
2825
+ window.addEventListener("pagehide", flushVars);
2826
+ } catch {
2827
+ }
2828
+ if (cfg.experiment?.id && cfg.experiment.variant) {
2829
+ enqueue("experiment.exposure", exposurePayload(cfg.experiment.id, cfg.experiment.variant, cfg.experiment.version));
2830
+ }
2831
+ return {
2832
+ track: (event, data, userData) => enqueue(event, data, userData),
2833
+ identify: (email, eventId) => enqueue("user.registered", { email, ...eventId ? { eventId } : {} }),
2834
+ setVariables: (variables) => {
2835
+ pendingVars = variables;
2836
+ if (varsTimer) clearTimeout(varsTimer);
2837
+ varsTimer = setTimeout(flushVars, VARS_DEBOUNCE_MS);
2838
+ },
2839
+ setAcquisition: (acq) => {
2840
+ acquisition = acq;
2841
+ }
2842
+ };
2843
+ }
2844
+
2845
+ // src/flow/mount.tsx
2846
+ var AssetsContext = React.createContext({});
2847
+ function AssetsProvider({
2848
+ assets,
2849
+ children
2850
+ }) {
2851
+ return React.createElement(AssetsContext.Provider, { value: assets ?? {} }, children);
2852
+ }
2853
+ function useAssets() {
2854
+ return React.useContext(AssetsContext);
2855
+ }
2856
+ function useAsset(name) {
2857
+ return React.useContext(AssetsContext)[name];
2858
+ }
2859
+ function createFunnelTree({
2860
+ config,
2861
+ pages,
2862
+ layout,
2863
+ checkoutDriver,
2864
+ messages
2865
+ }) {
2866
+ return function tree(opts) {
2867
+ const mode = opts.mode ?? "live";
2868
+ const tracker = opts.tracking ? createPlatformTracker({
2869
+ ...opts.tracking,
2870
+ visitorId: opts.visitorId,
2871
+ sessionId: opts.sessionId,
2872
+ mode
2873
+ }) : void 0;
2874
+ const checkout = checkoutDriver && opts.tracking ? checkoutDriver({
2875
+ apiBase: opts.tracking.apiBase,
2876
+ campaignId: opts.tracking.campaignId,
2877
+ funnelId: opts.tracking.funnelId,
2878
+ mode,
2879
+ sessionId: opts.sessionId,
2880
+ visitorId: opts.visitorId
2881
+ }) : void 0;
2882
+ const layoutWithResume = function LayoutWithCheckoutResume({
2883
+ children
2884
+ }) {
2885
+ return React.createElement(
2886
+ React.Fragment,
2887
+ null,
2888
+ React.createElement(CheckoutResume, null),
2889
+ layout ? React.createElement(layout, null, children) : children
2890
+ );
2891
+ };
2892
+ return React.createElement(AssetsProvider, {
2893
+ assets: opts.assets,
2894
+ children: React.createElement(FunnelProvider, {
2895
+ config,
2896
+ products: opts.products ?? [],
2897
+ messages: opts.messages ?? messages,
2898
+ locale: opts.locale,
2899
+ tracker,
2900
+ checkout,
2901
+ sessionValues: opts.sessionValues,
2902
+ experiments: opts.experiments,
2903
+ context: {
2904
+ mode,
2905
+ visitorId: opts.visitorId ?? null,
2906
+ customerId: opts.customerId ?? null,
2907
+ sessionId: opts.sessionId ?? null
2908
+ },
2909
+ children: React.createElement(FunnelView, {
2910
+ pages,
2911
+ layout: layoutWithResume,
2912
+ initialKey: opts.initialKey,
2913
+ prefetch: "off"
2914
+ // renderer background-modulepreloads all chunks
2915
+ })
2916
+ })
2917
+ });
2918
+ };
2919
+ }
1797
2920
  function Choice({
1798
2921
  bind,
1799
2922
  options,
@@ -1806,7 +2929,7 @@ function Choice({
1806
2929
  return options.map((opt) => {
1807
2930
  const o = typeof opt === "string" ? { value: opt } : opt;
1808
2931
  const selected = value === o.value;
1809
- return react.createElement(
2932
+ return React.createElement(
1810
2933
  "button",
1811
2934
  {
1812
2935
  key: o.value,
@@ -1825,7 +2948,7 @@ function Choice({
1825
2948
  }
1826
2949
  function Next({ children, onClick, ...rest }) {
1827
2950
  const { next } = useNavigation();
1828
- return react.createElement(
2951
+ return React.createElement(
1829
2952
  "button",
1830
2953
  {
1831
2954
  type: "button",
@@ -1841,7 +2964,7 @@ function Next({ children, onClick, ...rest }) {
1841
2964
  function Back({ children, onClick, ...rest }) {
1842
2965
  const { back, canGoBack } = useNavigation();
1843
2966
  if (!canGoBack) return null;
1844
- return react.createElement(
2967
+ return React.createElement(
1845
2968
  "button",
1846
2969
  {
1847
2970
  type: "button",
@@ -1894,7 +3017,7 @@ function Script({
1894
3017
  onLoad,
1895
3018
  onError
1896
3019
  }) {
1897
- react.useEffect(() => {
3020
+ React.useEffect(() => {
1898
3021
  if (typeof document === "undefined") return;
1899
3022
  const key = id ?? src;
1900
3023
  if (injected.has(key)) {
@@ -1933,159 +3056,190 @@ function Script({
1933
3056
  return null;
1934
3057
  }
1935
3058
 
1936
- // src/manifest/manifest.ts
1937
- function isVariantNode(page) {
1938
- return isVariantKey(page.key);
1939
- }
1940
- function serializeGate(when) {
1941
- if (!when) return void 0;
1942
- if (typeof when === "function") return { kind: "predicate" };
1943
- return { kind: "declarative", condition: when };
1944
- }
1945
- function compileManifest(input) {
1946
- const { funnel, pages } = input;
1947
- const keys = new Set(pages.map((p) => p.key));
1948
- const manifestPages = pages.map((p, index) => ({
1949
- id: p.key,
1950
- key: p.key,
1951
- type: p.meta?.type ?? "default",
1952
- slug: p.meta?.slug ?? p.key,
1953
- index,
1954
- variantOf: isVariantKey(p.key) ? parseSlotKey(p.key).slot : void 0
1955
- }));
1956
- const edges = [];
1957
- const badTargets = [];
1958
- const nextAnchor = (from) => {
1959
- for (let j = from + 1; j < pages.length; j++) {
1960
- if (!isVariantNode(pages[j])) return pages[j];
1961
- }
1962
- return void 0;
1963
- };
1964
- pages.forEach((p, i) => {
1965
- if (isVariantNode(p)) return;
1966
- const routes = p.meta?.next ?? [];
1967
- let hasUnconditional = false;
1968
- for (const route of routes) {
1969
- if (!keys.has(route.to)) {
1970
- badTargets.push({ from: p.key, to: route.to });
1971
- continue;
1972
- }
1973
- edges.push({ from: p.key, to: route.to, kind: "branch", condition: serializeGate(route.when) });
1974
- if (!route.when) hasUnconditional = true;
1975
- }
1976
- const next = nextAnchor(i);
1977
- if (!hasUnconditional && next && p.meta?.type !== "finish") {
1978
- edges.push({ from: p.key, to: next.key, kind: "linear" });
1979
- }
1980
- });
1981
- const startPage = pages.find((p) => !isVariantNode(p));
1982
- const start = startPage?.key ?? null;
1983
- const variantKeys = new Set(pages.filter(isVariantNode).map((p) => p.key));
1984
- const validation = validate(manifestPages, edges, badTargets, start, variantKeys);
1985
- return {
1986
- id: funnel.id,
1987
- pages: manifestPages,
1988
- flow: { start, nodes: manifestPages.map((p) => p.id), edges },
1989
- products: funnel.products ?? [],
1990
- locales: funnel.locales,
1991
- validation
1992
- };
1993
- }
1994
- function validate(pages, edges, badTargets, start, variantKeys) {
1995
- const outgoing = /* @__PURE__ */ new Map();
1996
- for (const e of edges) outgoing.set(e.from, (outgoing.get(e.from) ?? 0) + 1);
1997
- const deadEnds = pages.filter((p) => p.type !== "finish" && !variantKeys.has(p.id) && !(outgoing.get(p.id) > 0)).map((p) => p.id);
1998
- const reachable = /* @__PURE__ */ new Set();
1999
- if (start) {
2000
- const adj = /* @__PURE__ */ new Map();
2001
- for (const e of edges) {
2002
- const list = adj.get(e.from);
2003
- if (list) list.push(e.to);
2004
- else adj.set(e.from, [e.to]);
2005
- }
2006
- const stack = [start];
2007
- while (stack.length) {
2008
- const id = stack.pop();
2009
- if (reachable.has(id)) continue;
2010
- reachable.add(id);
2011
- for (const to of adj.get(id) ?? []) stack.push(to);
2012
- }
2013
- }
2014
- const unreachable = pages.filter((p) => !variantKeys.has(p.id) && !reachable.has(p.id)).map((p) => p.id);
2015
- const missingEmailCapture = !pages.some((p) => p.type === "email-capture");
2016
- return {
2017
- ok: deadEnds.length === 0 && unreachable.length === 0 && badTargets.length === 0 && !missingEmailCapture,
2018
- deadEnds,
2019
- unreachable,
2020
- badTargets,
2021
- missingEmailCapture
2022
- };
2023
- }
2024
-
2025
- Object.defineProperty(exports, "toast", {
3059
+ Object.defineProperty(exports, "assignVariant", {
3060
+ enumerable: true,
3061
+ get: function () { return chunkJSRKA375_cjs.assignVariant; }
3062
+ });
3063
+ Object.defineProperty(exports, "bucketingSeed", {
3064
+ enumerable: true,
3065
+ get: function () { return chunkJSRKA375_cjs.bucketingSeed; }
3066
+ });
3067
+ Object.defineProperty(exports, "buildCatalog", {
3068
+ enumerable: true,
3069
+ get: function () { return chunkJSRKA375_cjs.buildCatalog; }
3070
+ });
3071
+ Object.defineProperty(exports, "compileManifest", {
3072
+ enumerable: true,
3073
+ get: function () { return chunkJSRKA375_cjs.compileManifest; }
3074
+ });
3075
+ Object.defineProperty(exports, "currencyExponent", {
3076
+ enumerable: true,
3077
+ get: function () { return chunkJSRKA375_cjs.currencyExponent; }
3078
+ });
3079
+ Object.defineProperty(exports, "defineFunnel", {
3080
+ enumerable: true,
3081
+ get: function () { return chunkJSRKA375_cjs.defineFunnel; }
3082
+ });
3083
+ Object.defineProperty(exports, "definePage", {
3084
+ enumerable: true,
3085
+ get: function () { return chunkJSRKA375_cjs.definePage; }
3086
+ });
3087
+ Object.defineProperty(exports, "entryGuard", {
3088
+ enumerable: true,
3089
+ get: function () { return chunkJSRKA375_cjs.entryGuard; }
3090
+ });
3091
+ Object.defineProperty(exports, "evaluateCondition", {
3092
+ enumerable: true,
3093
+ get: function () { return chunkJSRKA375_cjs.evaluateCondition; }
3094
+ });
3095
+ Object.defineProperty(exports, "evaluateGate", {
3096
+ enumerable: true,
3097
+ get: function () { return chunkJSRKA375_cjs.evaluateGate; }
3098
+ });
3099
+ Object.defineProperty(exports, "expectedPathLength", {
3100
+ enumerable: true,
3101
+ get: function () { return chunkJSRKA375_cjs.expectedPathLength; }
3102
+ });
3103
+ Object.defineProperty(exports, "fnv1a", {
3104
+ enumerable: true,
3105
+ get: function () { return chunkJSRKA375_cjs.fnv1a; }
3106
+ });
3107
+ Object.defineProperty(exports, "formatMoney", {
3108
+ enumerable: true,
3109
+ get: function () { return chunkJSRKA375_cjs.formatMoney; }
3110
+ });
3111
+ Object.defineProperty(exports, "formatProduct", {
3112
+ enumerable: true,
3113
+ get: function () { return chunkJSRKA375_cjs.formatProduct; }
3114
+ });
3115
+ Object.defineProperty(exports, "hashToUnit", {
3116
+ enumerable: true,
3117
+ get: function () { return chunkJSRKA375_cjs.hashToUnit; }
3118
+ });
3119
+ Object.defineProperty(exports, "isRtl", {
3120
+ enumerable: true,
3121
+ get: function () { return chunkJSRKA375_cjs.isRtl; }
3122
+ });
3123
+ Object.defineProperty(exports, "isVariantKey", {
3124
+ enumerable: true,
3125
+ get: function () { return chunkJSRKA375_cjs.isVariantKey; }
3126
+ });
3127
+ Object.defineProperty(exports, "nextPage", {
3128
+ enumerable: true,
3129
+ get: function () { return chunkJSRKA375_cjs.nextPage; }
3130
+ });
3131
+ Object.defineProperty(exports, "outgoingKeys", {
3132
+ enumerable: true,
3133
+ get: function () { return chunkJSRKA375_cjs.outgoingKeys; }
3134
+ });
3135
+ Object.defineProperty(exports, "pageMeta", {
3136
+ enumerable: true,
3137
+ get: function () { return chunkJSRKA375_cjs.pageMeta; }
3138
+ });
3139
+ Object.defineProperty(exports, "parseSlotKey", {
3140
+ enumerable: true,
3141
+ get: function () { return chunkJSRKA375_cjs.parseSlotKey; }
3142
+ });
3143
+ Object.defineProperty(exports, "pickByWeight", {
3144
+ enumerable: true,
3145
+ get: function () { return chunkJSRKA375_cjs.pickByWeight; }
3146
+ });
3147
+ Object.defineProperty(exports, "resolveExperiments", {
3148
+ enumerable: true,
3149
+ get: function () { return chunkJSRKA375_cjs.resolveExperiments; }
3150
+ });
3151
+ Object.defineProperty(exports, "resolveLocale", {
3152
+ enumerable: true,
3153
+ get: function () { return chunkJSRKA375_cjs.resolveLocale; }
3154
+ });
3155
+ Object.defineProperty(exports, "resolveProduct", {
3156
+ enumerable: true,
3157
+ get: function () { return chunkJSRKA375_cjs.resolveProduct; }
3158
+ });
3159
+ Object.defineProperty(exports, "resolveRoute", {
3160
+ enumerable: true,
3161
+ get: function () { return chunkJSRKA375_cjs.resolveRoute; }
3162
+ });
3163
+ Object.defineProperty(exports, "validateExperiments", {
3164
+ enumerable: true,
3165
+ get: function () { return chunkJSRKA375_cjs.validateExperiments; }
3166
+ });
3167
+ Object.defineProperty(exports, "INLINE_SURFACES", {
3168
+ enumerable: true,
3169
+ get: function () { return chunkLJYLGLFS_cjs.INLINE_SURFACES; }
3170
+ });
3171
+ Object.defineProperty(exports, "PROVIDER_PROFILES", {
3172
+ enumerable: true,
3173
+ get: function () { return chunkLJYLGLFS_cjs.PROVIDER_PROFILES; }
3174
+ });
3175
+ Object.defineProperty(exports, "checkoutError", {
3176
+ enumerable: true,
3177
+ get: function () { return chunkLJYLGLFS_cjs.checkoutError; }
3178
+ });
3179
+ Object.defineProperty(exports, "isInlineSurface", {
3180
+ enumerable: true,
3181
+ get: function () { return chunkLJYLGLFS_cjs.isInlineSurface; }
3182
+ });
3183
+ Object.defineProperty(exports, "isMerchantOfRecord", {
3184
+ enumerable: true,
3185
+ get: function () { return chunkLJYLGLFS_cjs.isMerchantOfRecord; }
3186
+ });
3187
+ Object.defineProperty(exports, "isOrchestrator", {
3188
+ enumerable: true,
3189
+ get: function () { return chunkLJYLGLFS_cjs.isOrchestrator; }
3190
+ });
3191
+ Object.defineProperty(exports, "surfacesFor", {
3192
+ enumerable: true,
3193
+ get: function () { return chunkLJYLGLFS_cjs.surfacesFor; }
3194
+ });
3195
+ Object.defineProperty(exports, "validateCheckout", {
3196
+ enumerable: true,
3197
+ get: function () { return chunkLJYLGLFS_cjs.validateCheckout; }
3198
+ });
3199
+ Object.defineProperty(exports, "validateUpsell", {
2026
3200
  enumerable: true,
2027
- get: function () { return sonner.toast; }
3201
+ get: function () { return chunkLJYLGLFS_cjs.validateUpsell; }
2028
3202
  });
3203
+ exports.AssetsContext = AssetsContext;
3204
+ exports.AssetsProvider = AssetsProvider;
2029
3205
  exports.Back = Back;
2030
3206
  exports.Checkout = Checkout;
3207
+ exports.CheckoutResume = CheckoutResume;
2031
3208
  exports.Choice = Choice;
2032
3209
  exports.EVENT_CATALOG = EVENT_CATALOG;
2033
3210
  exports.FunnelProvider = FunnelProvider;
2034
3211
  exports.FunnelToaster = FunnelToaster;
2035
3212
  exports.FunnelView = FunnelView;
2036
- exports.INLINE_SURFACES = INLINE_SURFACES;
2037
3213
  exports.Modal = Modal;
2038
3214
  exports.Next = Next;
2039
- exports.PROVIDER_PROFILES = PROVIDER_PROFILES;
2040
3215
  exports.Script = Script;
2041
3216
  exports.Sheet = Sheet;
2042
3217
  exports.Upsell = Upsell;
2043
3218
  exports.VariableStore = VariableStore;
2044
- exports.assignVariant = assignVariant;
2045
3219
  exports.attachBus = attachBus;
2046
- exports.bucketingSeed = bucketingSeed;
2047
3220
  exports.buildAcquisition = buildAcquisition;
2048
- exports.buildCatalog = buildCatalog;
2049
- exports.checkoutError = checkoutError;
2050
- exports.compileManifest = compileManifest;
3221
+ exports.buildContext = buildContext;
2051
3222
  exports.createBus = createBus;
2052
3223
  exports.createConsoleTracker = createConsoleTracker;
2053
3224
  exports.createFunnelStore = createFunnelStore;
3225
+ exports.createFunnelTree = createFunnelTree;
2054
3226
  exports.createMockDriver = createMockDriver;
2055
- exports.defineFunnel = defineFunnel;
3227
+ exports.createPlatformTracker = createPlatformTracker;
2056
3228
  exports.defineModal = defineModal;
2057
- exports.definePage = definePage;
2058
- exports.entryGuard = entryGuard;
2059
- exports.evaluateCondition = evaluateCondition;
2060
- exports.evaluateGate = evaluateGate;
2061
- exports.expectedPathLength = expectedPathLength;
2062
- exports.fnv1a = fnv1a;
2063
- exports.formatProduct = formatProduct;
2064
- exports.hashToUnit = hashToUnit;
3229
+ exports.driverWithEmail = driverWithEmail;
2065
3230
  exports.hideModal = hideModal;
2066
3231
  exports.integrationEvents = integrationEvents;
2067
- exports.isInlineSurface = isInlineSurface;
2068
3232
  exports.isIntegrationEvent = isIntegrationEvent;
2069
- exports.isMerchantOfRecord = isMerchantOfRecord;
2070
- exports.isOrchestrator = isOrchestrator;
2071
- exports.isRtl = isRtl;
2072
3233
  exports.isTrackableEvent = isTrackableEvent;
2073
- exports.isVariantKey = isVariantKey;
2074
3234
  exports.newEventId = newEventId;
2075
- exports.nextPage = nextPage;
2076
- exports.outgoingKeys = outgoingKeys;
2077
- exports.pageMeta = pageMeta;
2078
- exports.parseSlotKey = parseSlotKey;
2079
- exports.pickByWeight = pickByWeight;
2080
3235
  exports.registerModal = registerModal;
2081
3236
  exports.removeModal = removeModal;
2082
- exports.resolveExperiments = resolveExperiments;
2083
- exports.resolveLocale = resolveLocale;
2084
- exports.resolveProduct = resolveProduct;
2085
- exports.resolveRoute = resolveRoute;
2086
3237
  exports.showModal = showModal;
2087
- exports.surfacesFor = surfacesFor;
3238
+ exports.toast = toast;
2088
3239
  exports.unregisterModal = unregisterModal;
3240
+ exports.useActiveLocale = useActiveLocale;
3241
+ exports.useAsset = useAsset;
3242
+ exports.useAssets = useAssets;
2089
3243
  exports.useCheckout = useCheckout;
2090
3244
  exports.useClickIds = useClickIds;
2091
3245
  exports.useContextValue = useContextValue;
@@ -2106,9 +3260,6 @@ exports.useTracker = useTracker;
2106
3260
  exports.useTranslation = useTranslation;
2107
3261
  exports.useUserAttribute = useUserAttribute;
2108
3262
  exports.useUtm = useUtm;
2109
- exports.validateCheckout = validateCheckout;
2110
- exports.validateExperiments = validateExperiments;
2111
- exports.validateUpsell = validateUpsell;
2112
3263
  exports.withBus = withBus;
2113
3264
  //# sourceMappingURL=index.cjs.map
2114
3265
  //# sourceMappingURL=index.cjs.map