@aforoai/storefront-widgets 1.0.6 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,114 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.0.12] — 2026-08-30
12
+
13
+ ### Fixed
14
+
15
+ - **SC-Ticket-22: Usage Meter showed "Couldn't load usage data. We'll retry
16
+ shortly." on every genuinely successful usage fetch.** `fetchUsage()` read
17
+ `subscriptionId`/`periodStart`/`metrics`/etc. directly off the top-level
18
+ JSON body instead of unwrapping `{success, data, meta}` — same bug class
19
+ as 1.0.7/1.0.9/1.0.10/1.0.11, just never applied here. Pattern #18
20
+ fail-soft (returns `null`, not a throw), so this never surfaced as a
21
+ distinct error message — every real 200 response from
22
+ `GET /subscriptions/{id}/usage` silently failed to parse. Reproduced live
23
+ against a real subscription on the isopacai tenant: Network tab showed a
24
+ clean 200, widget showed the generic retry banner anyway.
25
+
26
+ ## [1.0.11] — 2026-08-30
27
+
28
+ ### Fixed
29
+
30
+ - **SC-Ticket-10: Checkout Flow's `createCart`/`getCart`/`updateCustomerDetails`/
31
+ `initiatePayment`/`confirmCart` threw "Malformed \<method\> response
32
+ (missing required fields)" on every genuinely successful backend
33
+ response.** `parseCartResponse()` (shared by the first four) and
34
+ `confirmCart()`'s own inline parser both read `cartId`/`cartType`/
35
+ `status`/`targetId` directly off the top-level JSON body instead of
36
+ unwrapping `{success, data, meta}` — same bug class as 1.0.7/1.0.9/1.0.10,
37
+ just never applied to the checkout-cart family. Live-verified against the
38
+ isopacai tenant with a real ACTIVE offering: `exchange()` itself (and the
39
+ rest of the bootstrap path) already worked fine — the reported ticket
40
+ title ("Malformed bridge exchange response") was a misdiagnosis one call
41
+ later in the same flow, exactly like SC-Ticket-5.
42
+
43
+ ## [1.0.10] — 2026-08-29
44
+
45
+ ### Fixed
46
+
47
+ - **SC-Ticket-5: Payment Method widget's initial load silently showed 0
48
+ payment methods for every customer, even ones with real saved cards.**
49
+ `fetchPaymentMethods()` and `createPaymentMethodSetupIntent()` read
50
+ response fields directly off the top-level JSON body instead of
51
+ unwrapping `{success, data, meta}` — same bug class fixed for
52
+ `fetchInvoices()` (1.0.7) and the cancel/upgrade responses (1.0.9), never
53
+ applied here. `fetchPaymentMethods()` is Pattern #18 fail-soft, so this
54
+ never threw a visible error — it just silently returned an empty list
55
+ regardless of how many cards the customer actually had on file.
56
+ (Live-verified `exchange()` itself, and the widget bundle's own deployed
57
+ copy of it, are both already correct — the ticket's reported "Malformed
58
+ bridge exchange response" text is a misdiagnosis of this unwrap bug one
59
+ call later in the same load path.)
60
+
61
+ ## [1.0.9] — 2026-08-29
62
+
63
+ ### Fixed
64
+
65
+ - **SC-Ticket-4 continued: cancellation succeeded server-side but the widget
66
+ still showed "Could not cancel."** After the 1.0.8 idempotencyKey fix,
67
+ live testing surfaced two more bugs in the same response path:
68
+ `cancelSubscription()`/`upgradeSubscription()` read fields directly off
69
+ the top-level response body instead of unwrapping `{success, data, meta}`
70
+ (same class of bug fixed for `fetchInvoices()` in 1.0.7, never applied
71
+ here), and `cancelSubscription()` additionally required `feedbackId` to
72
+ be present even though storefront-service's `/cancel` endpoint
73
+ deliberately omits it today (documented follow-up to read the V50 audit
74
+ row id back from pricing-service). Together these rejected every
75
+ genuinely successful cancellation as "malformed." `CancelResponse.feedbackId`
76
+ is now `string | null`. Live-verified: a real subscription
77
+ (`1b3af07f-d248-4860-a02b-9e3ee5601200`) was cancelled server-side
78
+ (confirmed `status: CANCELLED` in the raw API response) but the widget
79
+ still errored before this fix; re-tested after deploying 1.0.9.
80
+
81
+ ## [1.0.8] — 2026-08-29
82
+
83
+ ### Fixed
84
+
85
+ - **SC-Ticket-4: Upgrade/Cancel widget's Confirm step always failed** — the
86
+ ticket's reported symptom ("Malformed bridge exchange response") turned
87
+ out to be a misdiagnosis of a different, real bug one step later:
88
+ `cancelSubscription()` and `upgradeSubscription()` sent `idempotencyKey`
89
+ only via the `Idempotency-Key` header, but storefront-service's
90
+ `EmbedCancelRequest`/`EmbedUpgradeRequest` DTOs require it as a
91
+ `@NotBlank` BODY field too. Every real cancellation or upgrade 400'd with
92
+ "idempotencyKey is required" (or, before a separate backend fix shipped
93
+ the same day, "Invalid value 'DISCOUNT_20_PCT' for field
94
+ 'retentionOfferShown'" — the backend enum never matched the widget's own
95
+ documented `RetentionOfferShown` values). Both methods now include
96
+ `idempotencyKey` in the serialized body as well as the header.
97
+ Live-verified: a real subscription was successfully cancelled end-to-end
98
+ through this exact code path after the fix.
99
+
100
+ ## [1.0.7] — 2026-08-29
101
+
102
+ ### Fixed
103
+
104
+ - **SC-Ticket-3: Invoice List widget always showed "0 invoices" even when
105
+ the customer had real, finalized invoices.** `BridgeClient.fetchInvoices()`
106
+ read `content`/`totalElements`/`totalPages` directly off the top-level
107
+ parsed JSON body, but `GET /api/v1/portal/embed/invoices` (like every
108
+ other Aforo endpoint) wraps its payload in `{success, data, meta}` via the
109
+ platform's global `ApiResponseAdvice`. `body.content` was therefore always
110
+ `undefined`, silently falling back to an empty page — same failure mode
111
+ as the pricing-card `offerings` bug fixed in 1.0.5, just never applied
112
+ here. Live-verified: the API correctly returned 3 real invoices
113
+ (confirmed via direct backend testing) while the widget rendered "No
114
+ invoices yet." `fetchInvoicePdfUrl()` and `initiateInvoicePayment()` had
115
+ the identical bug and are fixed the same way (`raw.data ?? raw` unwrap,
116
+ matching the existing pattern already used in `exchange()` /
117
+ `fetchHeadlessConfig()` / `initiateCheckout()`).
118
+
11
119
  ## [1.0.6] — 2026-08-26
12
120
 
13
121
  ### Fixed
@@ -1,4 +1,4 @@
1
- import { aD as WidgetMountConfig, Q as AforoEventType, N as AforoEventPayload, aC as WidgetId } from './types-BbQw2_32.cjs';
1
+ import { aD as WidgetMountConfig, Q as AforoEventType, N as AforoEventPayload, aC as WidgetId } from './types-RMTEXoGw.cjs';
2
2
 
3
3
  /**
4
4
  * AforoEmbed — vanilla-JS + script-tag mount API.
@@ -1,4 +1,4 @@
1
- import { aD as WidgetMountConfig, Q as AforoEventType, N as AforoEventPayload, aC as WidgetId } from './types-BbQw2_32.js';
1
+ import { aD as WidgetMountConfig, Q as AforoEventType, N as AforoEventPayload, aC as WidgetId } from './types-RMTEXoGw.js';
2
2
 
3
3
  /**
4
4
  * AforoEmbed — vanilla-JS + script-tag mount API.
package/dist/index.cjs CHANGED
@@ -510,8 +510,9 @@ var _BridgeClient = class _BridgeClient {
510
510
  }
511
511
  if (!resp.ok) return emptyPage;
512
512
  try {
513
- const body = await resp.json();
514
- if (!body || typeof body !== "object") return emptyPage;
513
+ const raw = await resp.json();
514
+ if (!raw || typeof raw !== "object") return emptyPage;
515
+ const body = raw.data ?? raw;
515
516
  return {
516
517
  content: Array.isArray(body.content) ? body.content : [],
517
518
  totalElements: typeof body.totalElements === "number" && Number.isFinite(body.totalElements) ? body.totalElements : 0,
@@ -554,7 +555,8 @@ var _BridgeClient = class _BridgeClient {
554
555
  }
555
556
  if (!resp.ok) return null;
556
557
  try {
557
- const body = await resp.json();
558
+ const raw = await resp.json();
559
+ const body = raw ? raw.data ?? raw : null;
558
560
  if (!body || typeof body.downloadUrl !== "string" || body.downloadUrl.length === 0) {
559
561
  return null;
560
562
  }
@@ -643,7 +645,8 @@ var _BridgeClient = class _BridgeClient {
643
645
  }
644
646
  let body;
645
647
  try {
646
- body = await resp.json();
648
+ const raw = await resp.json();
649
+ body = raw?.data ?? raw;
647
650
  } catch {
648
651
  throw new BridgeClientError(
649
652
  "Malformed invoice-payment-initiate response (not JSON)",
@@ -954,9 +957,9 @@ var _BridgeClient = class _BridgeClient {
954
957
  if (!resp.ok) {
955
958
  throw await this.parseError(resp);
956
959
  }
957
- let body;
960
+ let raw;
958
961
  try {
959
- body = await resp.json();
962
+ raw = await resp.json();
960
963
  } catch {
961
964
  throw new BridgeClientError(
962
965
  "Malformed confirmCart response (not JSON)",
@@ -965,6 +968,7 @@ var _BridgeClient = class _BridgeClient {
965
968
  false
966
969
  );
967
970
  }
971
+ const body = raw?.data ?? raw ?? {};
968
972
  if (!body.cartId || !body.status) {
969
973
  throw new BridgeClientError(
970
974
  "Malformed confirmCart response (missing required fields)",
@@ -1029,9 +1033,9 @@ var _BridgeClient = class _BridgeClient {
1029
1033
  * undefined access.
1030
1034
  */
1031
1035
  async parseCartResponse(resp, methodName) {
1032
- let body;
1036
+ let raw;
1033
1037
  try {
1034
- body = await resp.json();
1038
+ raw = await resp.json();
1035
1039
  } catch {
1036
1040
  throw new BridgeClientError(
1037
1041
  `Malformed ${methodName} response (not JSON)`,
@@ -1040,7 +1044,8 @@ var _BridgeClient = class _BridgeClient {
1040
1044
  false
1041
1045
  );
1042
1046
  }
1043
- if (!body.cartId || !body.cartType || !body.status || !body.targetId) {
1047
+ const data = raw?.data ?? raw ?? {};
1048
+ if (!data.cartId || !data.cartType || !data.status || !data.targetId) {
1044
1049
  throw new BridgeClientError(
1045
1050
  `Malformed ${methodName} response (missing required fields)`,
1046
1051
  500,
@@ -1049,21 +1054,21 @@ var _BridgeClient = class _BridgeClient {
1049
1054
  );
1050
1055
  }
1051
1056
  return {
1052
- cartId: body.cartId,
1053
- cartType: body.cartType,
1054
- targetId: body.targetId,
1055
- status: body.status,
1056
- totalCents: typeof body.totalCents === "number" && Number.isFinite(body.totalCents) ? body.totalCents : 0,
1057
- currency: typeof body.currency === "string" ? body.currency : "USD",
1058
- gatewayProvider: body.gatewayProvider ?? null,
1059
- gatewayClientSecret: body.gatewayClientSecret ?? null,
1060
- gatewayOrderId: body.gatewayOrderId ?? null,
1061
- gatewayApprovalUrl: body.gatewayApprovalUrl ?? null,
1062
- gatewaySandboxMode: body.gatewaySandboxMode ?? null,
1063
- subscriptionId: body.subscriptionId ?? null,
1064
- invoiceId: body.invoiceId ?? null,
1065
- expiresAt: typeof body.expiresAt === "string" ? body.expiresAt : (/* @__PURE__ */ new Date(0)).toISOString(),
1066
- completedAt: body.completedAt ?? null
1057
+ cartId: data.cartId,
1058
+ cartType: data.cartType,
1059
+ targetId: data.targetId,
1060
+ status: data.status,
1061
+ totalCents: typeof data.totalCents === "number" && Number.isFinite(data.totalCents) ? data.totalCents : 0,
1062
+ currency: typeof data.currency === "string" ? data.currency : "USD",
1063
+ gatewayProvider: data.gatewayProvider ?? null,
1064
+ gatewayClientSecret: data.gatewayClientSecret ?? null,
1065
+ gatewayOrderId: data.gatewayOrderId ?? null,
1066
+ gatewayApprovalUrl: data.gatewayApprovalUrl ?? null,
1067
+ gatewaySandboxMode: data.gatewaySandboxMode ?? null,
1068
+ subscriptionId: data.subscriptionId ?? null,
1069
+ invoiceId: data.invoiceId ?? null,
1070
+ expiresAt: typeof data.expiresAt === "string" ? data.expiresAt : (/* @__PURE__ */ new Date(0)).toISOString(),
1071
+ completedAt: data.completedAt ?? null
1067
1072
  };
1068
1073
  }
1069
1074
  /** Public liveness probe. Returns null on failure (not an error). */
@@ -1295,7 +1300,8 @@ var _BridgeClient = class _BridgeClient {
1295
1300
  }
1296
1301
  if (!resp.ok) return null;
1297
1302
  try {
1298
- const body = await resp.json();
1303
+ const raw = await resp.json();
1304
+ const body = raw?.data ?? raw ?? {};
1299
1305
  if (!body || typeof body !== "object" || !body.subscriptionId) {
1300
1306
  return null;
1301
1307
  }
@@ -1424,14 +1430,17 @@ var _BridgeClient = class _BridgeClient {
1424
1430
  idempotencyKey,
1425
1431
  sessionJwt
1426
1432
  }),
1427
- body: JSON.stringify(request)
1433
+ // 2026-08-29 fix: same bug as cancelSubscription() below — EmbedUpgradeRequest
1434
+ // requires idempotencyKey as a @NotBlank BODY field, but this only ever sent
1435
+ // it via the Idempotency-Key header.
1436
+ body: JSON.stringify({ ...request, idempotencyKey })
1428
1437
  });
1429
1438
  if (!resp.ok) {
1430
1439
  throw await this.parseError(resp);
1431
1440
  }
1432
- let body;
1441
+ let raw;
1433
1442
  try {
1434
- body = await resp.json();
1443
+ raw = await resp.json();
1435
1444
  } catch {
1436
1445
  throw new BridgeClientError(
1437
1446
  "Malformed upgrade response (not JSON)",
@@ -1440,6 +1449,7 @@ var _BridgeClient = class _BridgeClient {
1440
1449
  false
1441
1450
  );
1442
1451
  }
1452
+ const body = raw ? raw.data ?? raw : {};
1443
1453
  if (!body.subscriptionId || !body.previousOfferingId || !body.newOfferingId || !body.status) {
1444
1454
  throw new BridgeClientError(
1445
1455
  "Malformed upgrade response (missing required fields)",
@@ -1503,14 +1513,19 @@ var _BridgeClient = class _BridgeClient {
1503
1513
  idempotencyKey,
1504
1514
  sessionJwt
1505
1515
  }),
1506
- body: JSON.stringify(request)
1516
+ // 2026-08-29 fix: EmbedCancelRequest (storefront-service) requires
1517
+ // idempotencyKey as a @NotBlank BODY field — this only ever sent it
1518
+ // via the Idempotency-Key header, so every real cancellation 400'd
1519
+ // with "idempotencyKey is required" regardless of any other field.
1520
+ // Confirmed live against production.
1521
+ body: JSON.stringify({ ...request, idempotencyKey })
1507
1522
  });
1508
1523
  if (!resp.ok) {
1509
1524
  throw await this.parseError(resp);
1510
1525
  }
1511
- let body;
1526
+ let raw;
1512
1527
  try {
1513
- body = await resp.json();
1528
+ raw = await resp.json();
1514
1529
  } catch {
1515
1530
  throw new BridgeClientError(
1516
1531
  "Malformed cancel response (not JSON)",
@@ -1519,7 +1534,8 @@ var _BridgeClient = class _BridgeClient {
1519
1534
  false
1520
1535
  );
1521
1536
  }
1522
- if (!body.subscriptionId || !body.status || !body.effectiveAt || !body.feedbackId) {
1537
+ const body = raw ? raw.data ?? raw : null;
1538
+ if (!body || !body.subscriptionId || !body.status || !body.effectiveAt) {
1523
1539
  throw new BridgeClientError(
1524
1540
  "Malformed cancel response (missing required fields)",
1525
1541
  500,
@@ -1532,7 +1548,7 @@ var _BridgeClient = class _BridgeClient {
1532
1548
  status: body.status,
1533
1549
  cancelledAt: body.cancelledAt ?? null,
1534
1550
  effectiveAt: body.effectiveAt,
1535
- feedbackId: body.feedbackId,
1551
+ feedbackId: body.feedbackId ?? null,
1536
1552
  creditNoteId: body.creditNoteId ?? null
1537
1553
  };
1538
1554
  }
@@ -1562,7 +1578,8 @@ var _BridgeClient = class _BridgeClient {
1562
1578
  if (!resp.ok) {
1563
1579
  return { methods: [], defaultMethodId: null };
1564
1580
  }
1565
- const body = await resp.json();
1581
+ const raw = await resp.json();
1582
+ const body = raw ? raw.data ?? raw : {};
1566
1583
  return {
1567
1584
  methods: Array.isArray(body.methods) ? body.methods : [],
1568
1585
  defaultMethodId: body.defaultMethodId ?? null
@@ -1592,7 +1609,8 @@ var _BridgeClient = class _BridgeClient {
1592
1609
  body: JSON.stringify({})
1593
1610
  });
1594
1611
  if (!resp.ok) return null;
1595
- const body = await resp.json();
1612
+ const raw = await resp.json();
1613
+ const body = raw ? raw.data ?? raw : {};
1596
1614
  if (!body.clientSecret) return null;
1597
1615
  return {
1598
1616
  clientSecret: body.clientSecret,
@@ -12208,7 +12226,7 @@ function ResultPanel({
12208
12226
  }
12209
12227
 
12210
12228
  // src/core/version.ts
12211
- var VERSION = "1.0.6";
12229
+ var VERSION = "1.0.12";
12212
12230
 
12213
12231
  // src/core/AforoEmbed.ts
12214
12232
  var mountedElements = /* @__PURE__ */ new WeakMap();
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
- import { T as ThemeTokenOverrides, O as OfferingPayload, H as HeadlessConfigResponse, S as SubscriptionPayload, W as WidgetErrorPayload, a as SubscriptionForOfferingResponse, C as CheckoutCartType, b as CheckoutConfirmedPayload, c as CheckoutCancelledPayload, d as CheckoutCartResponse, e as SubscriptionStatusFilter, f as SubscriptionPayloadV2, g as SubscriptionPageResponse, I as InvoiceStatusFilter, h as InvoicePayload, i as InvoicePageResponse, U as UsageMetricPayload, j as UsageThreshold, k as UsageResponse, P as PaymentMethodListResponse, A as ApplyAt, l as UpgradeCancelResultPayload, D as DemoModeBridgeProvider, m as TenantBrandKit, n as InitiateCheckoutRequest, o as InitiateCheckoutResponse, p as InvoiceListFilter, q as InvoicePdfUrlResponse, r as InitiateInvoicePaymentRequest, s as InitiateInvoicePaymentResponse, t as CreateCartRequest, u as UpdateCustomerDetailsRequest, v as InitiateCartPaymentRequest, w as ConfirmCartResponse, R as RequestMagicLinkRequest, x as RequestMagicLinkResponse, V as VerifyMagicLinkResponse, y as SubscriptionListFilter, z as PreviewChangeRequest, B as PreviewChangeResponse, E as UpgradeRequest, F as UpgradeResponse, G as CancelWithFeedbackRequest, J as CancelResponse, K as SetupIntentResponse, L as SessionConfig, M as SessionState } from './types-BbQw2_32.cjs';
3
- export { N as AforoEventPayload, Q as AforoEventType, X as CancelReason, Y as CheckoutBillingAddress, Z as CheckoutCartErrorResponse, _ as CheckoutCartStatus, $ as CheckoutCustomerDetailsSubmittedPayload, a0 as CheckoutExpiredPayload, a1 as CheckoutFlowPhase, a2 as CheckoutPaymentCompletedPayload, a3 as CheckoutPaymentInitiatedPayload, a4 as CheckoutPaymentProvider, a5 as CheckoutStepChangedPayload, a6 as ConsentState, a7 as FeaturePayload, a8 as HeadlessBrandingPayload, a9 as InvoiceDownloadedPayload, aa as InvoiceExpandedPayload, ab as InvoiceFilterChangedPayload, ac as InvoicePaidPayload, ad as InvoicePayRequestedPayload, ae as InvoiceSearchChangedPayload, af as InvoiceStatus, ag as InvoiceTypeKind, ah as LiveSubscriptionStatus, ai as MagicLinkFailureCode, aj as OfferingSummary, ak as RatePlanPayload, al as RetentionOfferShown, am as RetentionOutcome, an as SubscriptionCancelRequestedPayload, ao as SubscriptionChangeType, ap as SubscriptionClickedPayload, aq as SubscriptionFilterChangedPayload, ar as SubscriptionStatus, as as SubscriptionUpgradeRequestedPayload, at as ThemeTokens, au as UpgradeCancelAbandonedPayload, av as UpgradeCancelCompletedPayload, aw as UpgradeCancelDeflectionOfferAcceptedPayload, ax as UpgradeCancelDeflectionOfferShownPayload, ay as UpgradeCancelPreviewFetchedPayload, az as UpgradeCancelStepChangedPayload, aA as UsageMetricClickedPayload, aB as UsageThresholdReachedPayload, aC as WidgetId, aD as WidgetMountConfig } from './types-BbQw2_32.cjs';
4
- export { A as AforoEmbed } from './AforoEmbed-VYb6_GXB.cjs';
2
+ import { T as ThemeTokenOverrides, O as OfferingPayload, H as HeadlessConfigResponse, S as SubscriptionPayload, W as WidgetErrorPayload, a as SubscriptionForOfferingResponse, C as CheckoutCartType, b as CheckoutConfirmedPayload, c as CheckoutCancelledPayload, d as CheckoutCartResponse, e as SubscriptionStatusFilter, f as SubscriptionPayloadV2, g as SubscriptionPageResponse, I as InvoiceStatusFilter, h as InvoicePayload, i as InvoicePageResponse, U as UsageMetricPayload, j as UsageThreshold, k as UsageResponse, P as PaymentMethodListResponse, A as ApplyAt, l as UpgradeCancelResultPayload, D as DemoModeBridgeProvider, m as TenantBrandKit, n as InitiateCheckoutRequest, o as InitiateCheckoutResponse, p as InvoiceListFilter, q as InvoicePdfUrlResponse, r as InitiateInvoicePaymentRequest, s as InitiateInvoicePaymentResponse, t as CreateCartRequest, u as UpdateCustomerDetailsRequest, v as InitiateCartPaymentRequest, w as ConfirmCartResponse, R as RequestMagicLinkRequest, x as RequestMagicLinkResponse, V as VerifyMagicLinkResponse, y as SubscriptionListFilter, z as PreviewChangeRequest, B as PreviewChangeResponse, E as UpgradeRequest, F as UpgradeResponse, G as CancelWithFeedbackRequest, J as CancelResponse, K as SetupIntentResponse, L as SessionConfig, M as SessionState } from './types-RMTEXoGw.cjs';
3
+ export { N as AforoEventPayload, Q as AforoEventType, X as CancelReason, Y as CheckoutBillingAddress, Z as CheckoutCartErrorResponse, _ as CheckoutCartStatus, $ as CheckoutCustomerDetailsSubmittedPayload, a0 as CheckoutExpiredPayload, a1 as CheckoutFlowPhase, a2 as CheckoutPaymentCompletedPayload, a3 as CheckoutPaymentInitiatedPayload, a4 as CheckoutPaymentProvider, a5 as CheckoutStepChangedPayload, a6 as ConsentState, a7 as FeaturePayload, a8 as HeadlessBrandingPayload, a9 as InvoiceDownloadedPayload, aa as InvoiceExpandedPayload, ab as InvoiceFilterChangedPayload, ac as InvoicePaidPayload, ad as InvoicePayRequestedPayload, ae as InvoiceSearchChangedPayload, af as InvoiceStatus, ag as InvoiceTypeKind, ah as LiveSubscriptionStatus, ai as MagicLinkFailureCode, aj as OfferingSummary, ak as RatePlanPayload, al as RetentionOfferShown, am as RetentionOutcome, an as SubscriptionCancelRequestedPayload, ao as SubscriptionChangeType, ap as SubscriptionClickedPayload, aq as SubscriptionFilterChangedPayload, ar as SubscriptionStatus, as as SubscriptionUpgradeRequestedPayload, at as ThemeTokens, au as UpgradeCancelAbandonedPayload, av as UpgradeCancelCompletedPayload, aw as UpgradeCancelDeflectionOfferAcceptedPayload, ax as UpgradeCancelDeflectionOfferShownPayload, ay as UpgradeCancelPreviewFetchedPayload, az as UpgradeCancelStepChangedPayload, aA as UsageMetricClickedPayload, aB as UsageThresholdReachedPayload, aC as WidgetId, aD as WidgetMountConfig } from './types-RMTEXoGw.cjs';
4
+ export { A as AforoEmbed } from './AforoEmbed-BX2HPXWT.cjs';
5
5
  export { EmbedEnvironment, EmbedKey } from '@aforoai/types';
6
6
 
7
7
  /**
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
- import { T as ThemeTokenOverrides, O as OfferingPayload, H as HeadlessConfigResponse, S as SubscriptionPayload, W as WidgetErrorPayload, a as SubscriptionForOfferingResponse, C as CheckoutCartType, b as CheckoutConfirmedPayload, c as CheckoutCancelledPayload, d as CheckoutCartResponse, e as SubscriptionStatusFilter, f as SubscriptionPayloadV2, g as SubscriptionPageResponse, I as InvoiceStatusFilter, h as InvoicePayload, i as InvoicePageResponse, U as UsageMetricPayload, j as UsageThreshold, k as UsageResponse, P as PaymentMethodListResponse, A as ApplyAt, l as UpgradeCancelResultPayload, D as DemoModeBridgeProvider, m as TenantBrandKit, n as InitiateCheckoutRequest, o as InitiateCheckoutResponse, p as InvoiceListFilter, q as InvoicePdfUrlResponse, r as InitiateInvoicePaymentRequest, s as InitiateInvoicePaymentResponse, t as CreateCartRequest, u as UpdateCustomerDetailsRequest, v as InitiateCartPaymentRequest, w as ConfirmCartResponse, R as RequestMagicLinkRequest, x as RequestMagicLinkResponse, V as VerifyMagicLinkResponse, y as SubscriptionListFilter, z as PreviewChangeRequest, B as PreviewChangeResponse, E as UpgradeRequest, F as UpgradeResponse, G as CancelWithFeedbackRequest, J as CancelResponse, K as SetupIntentResponse, L as SessionConfig, M as SessionState } from './types-BbQw2_32.js';
3
- export { N as AforoEventPayload, Q as AforoEventType, X as CancelReason, Y as CheckoutBillingAddress, Z as CheckoutCartErrorResponse, _ as CheckoutCartStatus, $ as CheckoutCustomerDetailsSubmittedPayload, a0 as CheckoutExpiredPayload, a1 as CheckoutFlowPhase, a2 as CheckoutPaymentCompletedPayload, a3 as CheckoutPaymentInitiatedPayload, a4 as CheckoutPaymentProvider, a5 as CheckoutStepChangedPayload, a6 as ConsentState, a7 as FeaturePayload, a8 as HeadlessBrandingPayload, a9 as InvoiceDownloadedPayload, aa as InvoiceExpandedPayload, ab as InvoiceFilterChangedPayload, ac as InvoicePaidPayload, ad as InvoicePayRequestedPayload, ae as InvoiceSearchChangedPayload, af as InvoiceStatus, ag as InvoiceTypeKind, ah as LiveSubscriptionStatus, ai as MagicLinkFailureCode, aj as OfferingSummary, ak as RatePlanPayload, al as RetentionOfferShown, am as RetentionOutcome, an as SubscriptionCancelRequestedPayload, ao as SubscriptionChangeType, ap as SubscriptionClickedPayload, aq as SubscriptionFilterChangedPayload, ar as SubscriptionStatus, as as SubscriptionUpgradeRequestedPayload, at as ThemeTokens, au as UpgradeCancelAbandonedPayload, av as UpgradeCancelCompletedPayload, aw as UpgradeCancelDeflectionOfferAcceptedPayload, ax as UpgradeCancelDeflectionOfferShownPayload, ay as UpgradeCancelPreviewFetchedPayload, az as UpgradeCancelStepChangedPayload, aA as UsageMetricClickedPayload, aB as UsageThresholdReachedPayload, aC as WidgetId, aD as WidgetMountConfig } from './types-BbQw2_32.js';
4
- export { A as AforoEmbed } from './AforoEmbed-BkJF1hAN.js';
2
+ import { T as ThemeTokenOverrides, O as OfferingPayload, H as HeadlessConfigResponse, S as SubscriptionPayload, W as WidgetErrorPayload, a as SubscriptionForOfferingResponse, C as CheckoutCartType, b as CheckoutConfirmedPayload, c as CheckoutCancelledPayload, d as CheckoutCartResponse, e as SubscriptionStatusFilter, f as SubscriptionPayloadV2, g as SubscriptionPageResponse, I as InvoiceStatusFilter, h as InvoicePayload, i as InvoicePageResponse, U as UsageMetricPayload, j as UsageThreshold, k as UsageResponse, P as PaymentMethodListResponse, A as ApplyAt, l as UpgradeCancelResultPayload, D as DemoModeBridgeProvider, m as TenantBrandKit, n as InitiateCheckoutRequest, o as InitiateCheckoutResponse, p as InvoiceListFilter, q as InvoicePdfUrlResponse, r as InitiateInvoicePaymentRequest, s as InitiateInvoicePaymentResponse, t as CreateCartRequest, u as UpdateCustomerDetailsRequest, v as InitiateCartPaymentRequest, w as ConfirmCartResponse, R as RequestMagicLinkRequest, x as RequestMagicLinkResponse, V as VerifyMagicLinkResponse, y as SubscriptionListFilter, z as PreviewChangeRequest, B as PreviewChangeResponse, E as UpgradeRequest, F as UpgradeResponse, G as CancelWithFeedbackRequest, J as CancelResponse, K as SetupIntentResponse, L as SessionConfig, M as SessionState } from './types-RMTEXoGw.js';
3
+ export { N as AforoEventPayload, Q as AforoEventType, X as CancelReason, Y as CheckoutBillingAddress, Z as CheckoutCartErrorResponse, _ as CheckoutCartStatus, $ as CheckoutCustomerDetailsSubmittedPayload, a0 as CheckoutExpiredPayload, a1 as CheckoutFlowPhase, a2 as CheckoutPaymentCompletedPayload, a3 as CheckoutPaymentInitiatedPayload, a4 as CheckoutPaymentProvider, a5 as CheckoutStepChangedPayload, a6 as ConsentState, a7 as FeaturePayload, a8 as HeadlessBrandingPayload, a9 as InvoiceDownloadedPayload, aa as InvoiceExpandedPayload, ab as InvoiceFilterChangedPayload, ac as InvoicePaidPayload, ad as InvoicePayRequestedPayload, ae as InvoiceSearchChangedPayload, af as InvoiceStatus, ag as InvoiceTypeKind, ah as LiveSubscriptionStatus, ai as MagicLinkFailureCode, aj as OfferingSummary, ak as RatePlanPayload, al as RetentionOfferShown, am as RetentionOutcome, an as SubscriptionCancelRequestedPayload, ao as SubscriptionChangeType, ap as SubscriptionClickedPayload, aq as SubscriptionFilterChangedPayload, ar as SubscriptionStatus, as as SubscriptionUpgradeRequestedPayload, at as ThemeTokens, au as UpgradeCancelAbandonedPayload, av as UpgradeCancelCompletedPayload, aw as UpgradeCancelDeflectionOfferAcceptedPayload, ax as UpgradeCancelDeflectionOfferShownPayload, ay as UpgradeCancelPreviewFetchedPayload, az as UpgradeCancelStepChangedPayload, aA as UsageMetricClickedPayload, aB as UsageThresholdReachedPayload, aC as WidgetId, aD as WidgetMountConfig } from './types-RMTEXoGw.js';
4
+ export { A as AforoEmbed } from './AforoEmbed-PsTY7zh0.js';
5
5
  export { EmbedEnvironment, EmbedKey } from '@aforoai/types';
6
6
 
7
7
  /**
package/dist/index.mjs CHANGED
@@ -488,8 +488,9 @@ var _BridgeClient = class _BridgeClient {
488
488
  }
489
489
  if (!resp.ok) return emptyPage;
490
490
  try {
491
- const body = await resp.json();
492
- if (!body || typeof body !== "object") return emptyPage;
491
+ const raw = await resp.json();
492
+ if (!raw || typeof raw !== "object") return emptyPage;
493
+ const body = raw.data ?? raw;
493
494
  return {
494
495
  content: Array.isArray(body.content) ? body.content : [],
495
496
  totalElements: typeof body.totalElements === "number" && Number.isFinite(body.totalElements) ? body.totalElements : 0,
@@ -532,7 +533,8 @@ var _BridgeClient = class _BridgeClient {
532
533
  }
533
534
  if (!resp.ok) return null;
534
535
  try {
535
- const body = await resp.json();
536
+ const raw = await resp.json();
537
+ const body = raw ? raw.data ?? raw : null;
536
538
  if (!body || typeof body.downloadUrl !== "string" || body.downloadUrl.length === 0) {
537
539
  return null;
538
540
  }
@@ -621,7 +623,8 @@ var _BridgeClient = class _BridgeClient {
621
623
  }
622
624
  let body;
623
625
  try {
624
- body = await resp.json();
626
+ const raw = await resp.json();
627
+ body = raw?.data ?? raw;
625
628
  } catch {
626
629
  throw new BridgeClientError(
627
630
  "Malformed invoice-payment-initiate response (not JSON)",
@@ -932,9 +935,9 @@ var _BridgeClient = class _BridgeClient {
932
935
  if (!resp.ok) {
933
936
  throw await this.parseError(resp);
934
937
  }
935
- let body;
938
+ let raw;
936
939
  try {
937
- body = await resp.json();
940
+ raw = await resp.json();
938
941
  } catch {
939
942
  throw new BridgeClientError(
940
943
  "Malformed confirmCart response (not JSON)",
@@ -943,6 +946,7 @@ var _BridgeClient = class _BridgeClient {
943
946
  false
944
947
  );
945
948
  }
949
+ const body = raw?.data ?? raw ?? {};
946
950
  if (!body.cartId || !body.status) {
947
951
  throw new BridgeClientError(
948
952
  "Malformed confirmCart response (missing required fields)",
@@ -1007,9 +1011,9 @@ var _BridgeClient = class _BridgeClient {
1007
1011
  * undefined access.
1008
1012
  */
1009
1013
  async parseCartResponse(resp, methodName) {
1010
- let body;
1014
+ let raw;
1011
1015
  try {
1012
- body = await resp.json();
1016
+ raw = await resp.json();
1013
1017
  } catch {
1014
1018
  throw new BridgeClientError(
1015
1019
  `Malformed ${methodName} response (not JSON)`,
@@ -1018,7 +1022,8 @@ var _BridgeClient = class _BridgeClient {
1018
1022
  false
1019
1023
  );
1020
1024
  }
1021
- if (!body.cartId || !body.cartType || !body.status || !body.targetId) {
1025
+ const data = raw?.data ?? raw ?? {};
1026
+ if (!data.cartId || !data.cartType || !data.status || !data.targetId) {
1022
1027
  throw new BridgeClientError(
1023
1028
  `Malformed ${methodName} response (missing required fields)`,
1024
1029
  500,
@@ -1027,21 +1032,21 @@ var _BridgeClient = class _BridgeClient {
1027
1032
  );
1028
1033
  }
1029
1034
  return {
1030
- cartId: body.cartId,
1031
- cartType: body.cartType,
1032
- targetId: body.targetId,
1033
- status: body.status,
1034
- totalCents: typeof body.totalCents === "number" && Number.isFinite(body.totalCents) ? body.totalCents : 0,
1035
- currency: typeof body.currency === "string" ? body.currency : "USD",
1036
- gatewayProvider: body.gatewayProvider ?? null,
1037
- gatewayClientSecret: body.gatewayClientSecret ?? null,
1038
- gatewayOrderId: body.gatewayOrderId ?? null,
1039
- gatewayApprovalUrl: body.gatewayApprovalUrl ?? null,
1040
- gatewaySandboxMode: body.gatewaySandboxMode ?? null,
1041
- subscriptionId: body.subscriptionId ?? null,
1042
- invoiceId: body.invoiceId ?? null,
1043
- expiresAt: typeof body.expiresAt === "string" ? body.expiresAt : (/* @__PURE__ */ new Date(0)).toISOString(),
1044
- completedAt: body.completedAt ?? null
1035
+ cartId: data.cartId,
1036
+ cartType: data.cartType,
1037
+ targetId: data.targetId,
1038
+ status: data.status,
1039
+ totalCents: typeof data.totalCents === "number" && Number.isFinite(data.totalCents) ? data.totalCents : 0,
1040
+ currency: typeof data.currency === "string" ? data.currency : "USD",
1041
+ gatewayProvider: data.gatewayProvider ?? null,
1042
+ gatewayClientSecret: data.gatewayClientSecret ?? null,
1043
+ gatewayOrderId: data.gatewayOrderId ?? null,
1044
+ gatewayApprovalUrl: data.gatewayApprovalUrl ?? null,
1045
+ gatewaySandboxMode: data.gatewaySandboxMode ?? null,
1046
+ subscriptionId: data.subscriptionId ?? null,
1047
+ invoiceId: data.invoiceId ?? null,
1048
+ expiresAt: typeof data.expiresAt === "string" ? data.expiresAt : (/* @__PURE__ */ new Date(0)).toISOString(),
1049
+ completedAt: data.completedAt ?? null
1045
1050
  };
1046
1051
  }
1047
1052
  /** Public liveness probe. Returns null on failure (not an error). */
@@ -1273,7 +1278,8 @@ var _BridgeClient = class _BridgeClient {
1273
1278
  }
1274
1279
  if (!resp.ok) return null;
1275
1280
  try {
1276
- const body = await resp.json();
1281
+ const raw = await resp.json();
1282
+ const body = raw?.data ?? raw ?? {};
1277
1283
  if (!body || typeof body !== "object" || !body.subscriptionId) {
1278
1284
  return null;
1279
1285
  }
@@ -1402,14 +1408,17 @@ var _BridgeClient = class _BridgeClient {
1402
1408
  idempotencyKey,
1403
1409
  sessionJwt
1404
1410
  }),
1405
- body: JSON.stringify(request)
1411
+ // 2026-08-29 fix: same bug as cancelSubscription() below — EmbedUpgradeRequest
1412
+ // requires idempotencyKey as a @NotBlank BODY field, but this only ever sent
1413
+ // it via the Idempotency-Key header.
1414
+ body: JSON.stringify({ ...request, idempotencyKey })
1406
1415
  });
1407
1416
  if (!resp.ok) {
1408
1417
  throw await this.parseError(resp);
1409
1418
  }
1410
- let body;
1419
+ let raw;
1411
1420
  try {
1412
- body = await resp.json();
1421
+ raw = await resp.json();
1413
1422
  } catch {
1414
1423
  throw new BridgeClientError(
1415
1424
  "Malformed upgrade response (not JSON)",
@@ -1418,6 +1427,7 @@ var _BridgeClient = class _BridgeClient {
1418
1427
  false
1419
1428
  );
1420
1429
  }
1430
+ const body = raw ? raw.data ?? raw : {};
1421
1431
  if (!body.subscriptionId || !body.previousOfferingId || !body.newOfferingId || !body.status) {
1422
1432
  throw new BridgeClientError(
1423
1433
  "Malformed upgrade response (missing required fields)",
@@ -1481,14 +1491,19 @@ var _BridgeClient = class _BridgeClient {
1481
1491
  idempotencyKey,
1482
1492
  sessionJwt
1483
1493
  }),
1484
- body: JSON.stringify(request)
1494
+ // 2026-08-29 fix: EmbedCancelRequest (storefront-service) requires
1495
+ // idempotencyKey as a @NotBlank BODY field — this only ever sent it
1496
+ // via the Idempotency-Key header, so every real cancellation 400'd
1497
+ // with "idempotencyKey is required" regardless of any other field.
1498
+ // Confirmed live against production.
1499
+ body: JSON.stringify({ ...request, idempotencyKey })
1485
1500
  });
1486
1501
  if (!resp.ok) {
1487
1502
  throw await this.parseError(resp);
1488
1503
  }
1489
- let body;
1504
+ let raw;
1490
1505
  try {
1491
- body = await resp.json();
1506
+ raw = await resp.json();
1492
1507
  } catch {
1493
1508
  throw new BridgeClientError(
1494
1509
  "Malformed cancel response (not JSON)",
@@ -1497,7 +1512,8 @@ var _BridgeClient = class _BridgeClient {
1497
1512
  false
1498
1513
  );
1499
1514
  }
1500
- if (!body.subscriptionId || !body.status || !body.effectiveAt || !body.feedbackId) {
1515
+ const body = raw ? raw.data ?? raw : null;
1516
+ if (!body || !body.subscriptionId || !body.status || !body.effectiveAt) {
1501
1517
  throw new BridgeClientError(
1502
1518
  "Malformed cancel response (missing required fields)",
1503
1519
  500,
@@ -1510,7 +1526,7 @@ var _BridgeClient = class _BridgeClient {
1510
1526
  status: body.status,
1511
1527
  cancelledAt: body.cancelledAt ?? null,
1512
1528
  effectiveAt: body.effectiveAt,
1513
- feedbackId: body.feedbackId,
1529
+ feedbackId: body.feedbackId ?? null,
1514
1530
  creditNoteId: body.creditNoteId ?? null
1515
1531
  };
1516
1532
  }
@@ -1540,7 +1556,8 @@ var _BridgeClient = class _BridgeClient {
1540
1556
  if (!resp.ok) {
1541
1557
  return { methods: [], defaultMethodId: null };
1542
1558
  }
1543
- const body = await resp.json();
1559
+ const raw = await resp.json();
1560
+ const body = raw ? raw.data ?? raw : {};
1544
1561
  return {
1545
1562
  methods: Array.isArray(body.methods) ? body.methods : [],
1546
1563
  defaultMethodId: body.defaultMethodId ?? null
@@ -1570,7 +1587,8 @@ var _BridgeClient = class _BridgeClient {
1570
1587
  body: JSON.stringify({})
1571
1588
  });
1572
1589
  if (!resp.ok) return null;
1573
- const body = await resp.json();
1590
+ const raw = await resp.json();
1591
+ const body = raw ? raw.data ?? raw : {};
1574
1592
  if (!body.clientSecret) return null;
1575
1593
  return {
1576
1594
  clientSecret: body.clientSecret,
@@ -12186,7 +12204,7 @@ function ResultPanel({
12186
12204
  }
12187
12205
 
12188
12206
  // src/core/version.ts
12189
- var VERSION = "1.0.6";
12207
+ var VERSION = "1.0.12";
12190
12208
 
12191
12209
  // src/core/AforoEmbed.ts
12192
12210
  var mountedElements = /* @__PURE__ */ new WeakMap();
package/dist/loader.js CHANGED
@@ -1,3 +1,3 @@
1
- var AforoEmbedLoader=(function(exports){'use strict';var T="1.0.6";var y=new WeakMap,c=new Map,f={},A=false;function h(){A||typeof window!="undefined"&&(window.addEventListener("message",e=>{let t=e.data;!t||typeof t!="object"||typeof t.type!="string"||t.type.startsWith("aforo.")&&$(t);}),A=true);}function $(e){let t=c.get(e.type);if(t)for(let o of t)try{o(e);}catch(i){}let n=c.get("*");if(n)for(let o of n)try{o(e);}catch(i){}}var p=new Map;function N(e,t){p.set(e,t);}function w(e){return typeof e=="object"&&e!==null&&typeof e.tagName=="string"}var b={version:T,configure(e){f={...f,...e};},getConfig(){return {...f}},mount(e,t){var r,l,u,s,d;if(!w(e)||y.has(e))return false;let n=t.widget,o=p.get(n);if(!o)return typeof console!="undefined"&&console.warn(`[aforo:embed] No mount handler registered for widget "${n}". Loader bundle may not have finished loading.`),false;let i={widget:n,tenantSlug:(l=(r=t.tenantSlug)!=null?r:f.tenantSlug)!=null?l:"",embedKey:(s=(u=t.embedKey)!=null?u:f.embedKey)!=null?s:"",bridgeToken:(d=t.bridgeToken)!=null?d:f.bridgeToken,layout:t.layout,themeOverrides:t.themeOverrides,config:t.config};if(!i.tenantSlug||!i.embedKey)return typeof console!="undefined"&&console.error(`[aforo:embed] Widget "${n}" requires tenantSlug + embedKey. Provide via AforoEmbed.configure() or data-* attributes.`),false;h();let a=o(e,i);return y.set(e,{element:e,widget:n,teardown:a}),true},unmount(e){if(!w(e))return false;let t=y.get(e);if(!t)return false;try{t.teardown();}catch(n){}return y.delete(e),true},on(e,t){h();let n=c.get(e);return n||(n=new Set,c.set(e,n)),n.add(t),()=>{let o=c.get(e);o&&(o.delete(t),o.size===0&&c.delete(e));}},_registerWidget:N,_registeredWidgetsForTesting(){return Array.from(p.keys())},_resetForTesting(){p.clear(),c.clear(),f={};}};function k(e){if(!e)return {};try{let t=JSON.parse(e);if(t&&typeof t=="object"&&!Array.isArray(t)){let n={},o=["primary","primaryContrast","text","textMuted","bg","border","radius","fontFamily"],i=t;for(let a of o){let r=i[a];typeof r=="string"&&r.length>0&&(n[a]=r);}return n}}catch(t){}return {}}var U=new Set(["pricing-card","subscribe-button","checkout-flow","subscription-manager","invoice-list","usage-meter","payment-method","upgrade-cancel"]),B="https://embed.aforo.ai/v1/widgets",g="[aforo:loader]";function D(){let e=typeof document!="undefined"?document.currentScript:null;if(e&&e.tagName==="SCRIPT")return e;if(typeof document!="undefined"){let t=document.getElementsByTagName("script");for(let n=t.length-1;n>=0;n--){let o=t[n];if(!o)continue;let i=o.getAttribute("src")||"";if(/(\/v1)?\/loader(\.umd)?\.js$/.test(i))return o}}return null}function G(e){let t=e==null?void 0:e.getAttribute("src");if(!t)return null;try{let n=typeof location!="undefined"?location.href:void 0,o=new URL(t,n),i=o.pathname.replace(/\/loader(\.umd)?\.js$/,"");return `${o.origin}${i}/widgets`}catch(n){return null}}function v(e,t){let n=e.getAttribute(t);if(n==null||n.trim()==="")return;let o=Number(n);return Number.isFinite(o)?o:void 0}function j(e,t){let n=e.getAttribute(t);if(n==null)return;let o=n.trim().toLowerCase();if(o==="true")return true;if(o==="false")return false}function V(e){let t=(e.getAttribute("data-aforo-widget")||"").trim(),n=e.getAttribute("data-tenant-slug")||e.getAttribute("data-tenant")||"",o=e.getAttribute("data-embed-key")||"",i=e.getAttribute("data-bridge-token")||void 0,a=e.getAttribute("data-layout")||void 0,r=k(e.getAttribute("data-theme-overrides")),l=e.getAttribute("data-offering-id")||void 0,u=e.getAttribute("data-subscription-id")||void 0,s=e.getAttribute("data-metric")||void 0,d=e.getAttribute("data-featured-offering-id")||void 0,m=e.getAttribute("data-mode")||void 0,M=e.getAttribute("data-return-url")||void 0,S=e.getAttribute("data-default-status")||void 0,F=e.getAttribute("data-render-mode")||void 0,_=e.getAttribute("data-locale")||void 0,C=v(e,"data-page-size"),O=v(e,"data-poll-interval-ms"),I=e.getAttribute("data-theme")||void 0,R=e.getAttribute("data-cart-type")||void 0,W=e.getAttribute("data-target-id")||void 0,H=e.getAttribute("data-cta-text")||void 0,x=e.getAttribute("data-cta-url")||void 0,P=v(e,"data-max-plans"),K=j(e,"data-show-features");return {widget:t,tenantSlug:n,embedKey:o,bridgeToken:i,layout:a,themeOverrides:r,config:{offeringId:l,subscriptionId:u,metricName:s,featuredOfferingId:d,mode:m,returnUrl:M,defaultStatus:S,renderMode:F,locale:_,pageSize:C,pollIntervalMs:O,theme:I,cartType:R,targetId:W,ctaText:H,ctaUrl:x,maxPlans:P,showFeatures:K}}}function z(e,t,n){return new Promise((o,i)=>{if(typeof document=="undefined")return i(new Error("no document"));let a=document.querySelector(`script[data-aforo-bundle="${e}"]`);if(a){if(a.dataset.aforoLoaded==="1")return o();a.addEventListener("load",()=>o()),a.addEventListener("error",()=>i(new Error(`bundle load failed: ${e}`)));return}let r=document.createElement("script");r.src=`${t}/${e}.js`,r.async=true,r.crossOrigin="anonymous",r.dataset.aforoBundle=e,n&&r.setAttribute("nonce",n),r.addEventListener("load",()=>{r.dataset.aforoLoaded="1",o();}),r.addEventListener("error",()=>i(new Error(`bundle load failed: ${e}`))),document.head.appendChild(r);})}function L(e){if(!e.__aforoEmbedReadyFired){e.__aforoEmbedReadyFired=true;try{typeof e.aforoEmbedReady=="function"&&e.aforoEmbedReady();}catch(t){typeof console!="undefined"&&console.error(`${g} aforoEmbedReady callback threw`,t);}if(typeof document!="undefined"&&typeof CustomEvent!="undefined")try{document.dispatchEvent(new CustomEvent("aforoEmbedReady"));}catch(t){}}}async function E(e){if(typeof window=="undefined"||typeof document=="undefined")return;let t=window;if(window.location.protocol!=="https:"&&window.location.hostname!=="localhost"){typeof console!="undefined"&&console.error(`${g} Refusing to mount Aforo widgets on a non-HTTPS page. Embed Plugin requires HTTPS (FR-TIER-12). Current origin: ${window.location.origin}`);return}if(t.__aforoEmbedLoaderInitialized){typeof console!="undefined"&&console.warn(`${g} Loader already initialised on this page \u2014 skipping duplicate run.`);return}t.__aforoEmbedLoaderInitialized=true,t.aforoEmbed||(t.aforoEmbed=b);let n=D(),o=(n==null?void 0:n.getAttribute("nonce"))||null,i=(e==null?void 0:e.bundleBaseUrl)||G(n)||B,a=Array.from(document.querySelectorAll("[data-aforo-widget]"));if(a.length===0){L(t);return}let r=new Map;for(let u of a){let s=(u.getAttribute("data-aforo-widget")||"").trim();if(!U.has(s)){typeof console!="undefined"&&console.warn(`${g} Unknown widget id "${s}" \u2014 skipping`);continue}let d=r.get(s);d||(d=[],r.set(s,d)),d.push(u);}let l=Array.from(r.entries()).map(async([u,s])=>{try{await z(u,i,o);for(let d of s){let m=V(d);if(!m.widget||!m.tenantSlug||!m.embedKey){typeof console!="undefined"&&console.error(`${g} Placeholder missing required attributes (data-tenant-slug + data-embed-key). Skipping element.`,d);continue}b.mount(d,m);}}catch(d){typeof console!="undefined"&&console.error(`${g} Failed to load bundle for "${u}"`,d);}});await Promise.all(l).catch(()=>{}),L(t);}typeof document!="undefined"&&document.readyState!=="loading"?Promise.resolve().then(()=>{E();}):typeof document!="undefined"&&document.addEventListener("DOMContentLoaded",()=>{E();});b._loader={bootstrap:E};
1
+ var AforoEmbedLoader=(function(exports){'use strict';var T="1.0.12";var y=new WeakMap,c=new Map,f={},A=false;function h(){A||typeof window!="undefined"&&(window.addEventListener("message",e=>{let t=e.data;!t||typeof t!="object"||typeof t.type!="string"||t.type.startsWith("aforo.")&&$(t);}),A=true);}function $(e){let t=c.get(e.type);if(t)for(let o of t)try{o(e);}catch(i){}let n=c.get("*");if(n)for(let o of n)try{o(e);}catch(i){}}var p=new Map;function N(e,t){p.set(e,t);}function w(e){return typeof e=="object"&&e!==null&&typeof e.tagName=="string"}var b={version:T,configure(e){f={...f,...e};},getConfig(){return {...f}},mount(e,t){var r,l,u,s,d;if(!w(e)||y.has(e))return false;let n=t.widget,o=p.get(n);if(!o)return typeof console!="undefined"&&console.warn(`[aforo:embed] No mount handler registered for widget "${n}". Loader bundle may not have finished loading.`),false;let i={widget:n,tenantSlug:(l=(r=t.tenantSlug)!=null?r:f.tenantSlug)!=null?l:"",embedKey:(s=(u=t.embedKey)!=null?u:f.embedKey)!=null?s:"",bridgeToken:(d=t.bridgeToken)!=null?d:f.bridgeToken,layout:t.layout,themeOverrides:t.themeOverrides,config:t.config};if(!i.tenantSlug||!i.embedKey)return typeof console!="undefined"&&console.error(`[aforo:embed] Widget "${n}" requires tenantSlug + embedKey. Provide via AforoEmbed.configure() or data-* attributes.`),false;h();let a=o(e,i);return y.set(e,{element:e,widget:n,teardown:a}),true},unmount(e){if(!w(e))return false;let t=y.get(e);if(!t)return false;try{t.teardown();}catch(n){}return y.delete(e),true},on(e,t){h();let n=c.get(e);return n||(n=new Set,c.set(e,n)),n.add(t),()=>{let o=c.get(e);o&&(o.delete(t),o.size===0&&c.delete(e));}},_registerWidget:N,_registeredWidgetsForTesting(){return Array.from(p.keys())},_resetForTesting(){p.clear(),c.clear(),f={};}};function k(e){if(!e)return {};try{let t=JSON.parse(e);if(t&&typeof t=="object"&&!Array.isArray(t)){let n={},o=["primary","primaryContrast","text","textMuted","bg","border","radius","fontFamily"],i=t;for(let a of o){let r=i[a];typeof r=="string"&&r.length>0&&(n[a]=r);}return n}}catch(t){}return {}}var U=new Set(["pricing-card","subscribe-button","checkout-flow","subscription-manager","invoice-list","usage-meter","payment-method","upgrade-cancel"]),B="https://embed.aforo.ai/v1/widgets",g="[aforo:loader]";function D(){let e=typeof document!="undefined"?document.currentScript:null;if(e&&e.tagName==="SCRIPT")return e;if(typeof document!="undefined"){let t=document.getElementsByTagName("script");for(let n=t.length-1;n>=0;n--){let o=t[n];if(!o)continue;let i=o.getAttribute("src")||"";if(/(\/v1)?\/loader(\.umd)?\.js$/.test(i))return o}}return null}function G(e){let t=e==null?void 0:e.getAttribute("src");if(!t)return null;try{let n=typeof location!="undefined"?location.href:void 0,o=new URL(t,n),i=o.pathname.replace(/\/loader(\.umd)?\.js$/,"");return `${o.origin}${i}/widgets`}catch(n){return null}}function v(e,t){let n=e.getAttribute(t);if(n==null||n.trim()==="")return;let o=Number(n);return Number.isFinite(o)?o:void 0}function j(e,t){let n=e.getAttribute(t);if(n==null)return;let o=n.trim().toLowerCase();if(o==="true")return true;if(o==="false")return false}function V(e){let t=(e.getAttribute("data-aforo-widget")||"").trim(),n=e.getAttribute("data-tenant-slug")||e.getAttribute("data-tenant")||"",o=e.getAttribute("data-embed-key")||"",i=e.getAttribute("data-bridge-token")||void 0,a=e.getAttribute("data-layout")||void 0,r=k(e.getAttribute("data-theme-overrides")),l=e.getAttribute("data-offering-id")||void 0,u=e.getAttribute("data-subscription-id")||void 0,s=e.getAttribute("data-metric")||void 0,d=e.getAttribute("data-featured-offering-id")||void 0,m=e.getAttribute("data-mode")||void 0,M=e.getAttribute("data-return-url")||void 0,S=e.getAttribute("data-default-status")||void 0,F=e.getAttribute("data-render-mode")||void 0,_=e.getAttribute("data-locale")||void 0,C=v(e,"data-page-size"),O=v(e,"data-poll-interval-ms"),I=e.getAttribute("data-theme")||void 0,R=e.getAttribute("data-cart-type")||void 0,W=e.getAttribute("data-target-id")||void 0,H=e.getAttribute("data-cta-text")||void 0,x=e.getAttribute("data-cta-url")||void 0,P=v(e,"data-max-plans"),K=j(e,"data-show-features");return {widget:t,tenantSlug:n,embedKey:o,bridgeToken:i,layout:a,themeOverrides:r,config:{offeringId:l,subscriptionId:u,metricName:s,featuredOfferingId:d,mode:m,returnUrl:M,defaultStatus:S,renderMode:F,locale:_,pageSize:C,pollIntervalMs:O,theme:I,cartType:R,targetId:W,ctaText:H,ctaUrl:x,maxPlans:P,showFeatures:K}}}function z(e,t,n){return new Promise((o,i)=>{if(typeof document=="undefined")return i(new Error("no document"));let a=document.querySelector(`script[data-aforo-bundle="${e}"]`);if(a){if(a.dataset.aforoLoaded==="1")return o();a.addEventListener("load",()=>o()),a.addEventListener("error",()=>i(new Error(`bundle load failed: ${e}`)));return}let r=document.createElement("script");r.src=`${t}/${e}.js`,r.async=true,r.crossOrigin="anonymous",r.dataset.aforoBundle=e,n&&r.setAttribute("nonce",n),r.addEventListener("load",()=>{r.dataset.aforoLoaded="1",o();}),r.addEventListener("error",()=>i(new Error(`bundle load failed: ${e}`))),document.head.appendChild(r);})}function L(e){if(!e.__aforoEmbedReadyFired){e.__aforoEmbedReadyFired=true;try{typeof e.aforoEmbedReady=="function"&&e.aforoEmbedReady();}catch(t){typeof console!="undefined"&&console.error(`${g} aforoEmbedReady callback threw`,t);}if(typeof document!="undefined"&&typeof CustomEvent!="undefined")try{document.dispatchEvent(new CustomEvent("aforoEmbedReady"));}catch(t){}}}async function E(e){if(typeof window=="undefined"||typeof document=="undefined")return;let t=window;if(window.location.protocol!=="https:"&&window.location.hostname!=="localhost"){typeof console!="undefined"&&console.error(`${g} Refusing to mount Aforo widgets on a non-HTTPS page. Embed Plugin requires HTTPS (FR-TIER-12). Current origin: ${window.location.origin}`);return}if(t.__aforoEmbedLoaderInitialized){typeof console!="undefined"&&console.warn(`${g} Loader already initialised on this page \u2014 skipping duplicate run.`);return}t.__aforoEmbedLoaderInitialized=true,t.aforoEmbed||(t.aforoEmbed=b);let n=D(),o=(n==null?void 0:n.getAttribute("nonce"))||null,i=(e==null?void 0:e.bundleBaseUrl)||G(n)||B,a=Array.from(document.querySelectorAll("[data-aforo-widget]"));if(a.length===0){L(t);return}let r=new Map;for(let u of a){let s=(u.getAttribute("data-aforo-widget")||"").trim();if(!U.has(s)){typeof console!="undefined"&&console.warn(`${g} Unknown widget id "${s}" \u2014 skipping`);continue}let d=r.get(s);d||(d=[],r.set(s,d)),d.push(u);}let l=Array.from(r.entries()).map(async([u,s])=>{try{await z(u,i,o);for(let d of s){let m=V(d);if(!m.widget||!m.tenantSlug||!m.embedKey){typeof console!="undefined"&&console.error(`${g} Placeholder missing required attributes (data-tenant-slug + data-embed-key). Skipping element.`,d);continue}b.mount(d,m);}}catch(d){typeof console!="undefined"&&console.error(`${g} Failed to load bundle for "${u}"`,d);}});await Promise.all(l).catch(()=>{}),L(t);}typeof document!="undefined"&&document.readyState!=="loading"?Promise.resolve().then(()=>{E();}):typeof document!="undefined"&&document.addEventListener("DOMContentLoaded",()=>{E();});b._loader={bootstrap:E};
2
2
  exports.AforoEmbed=b;exports.bootstrap=E;return exports;})({});//# sourceMappingURL=loader.js.map
3
3
  //# sourceMappingURL=loader.js.map