@aforoai/storefront-widgets 1.0.5 → 1.0.11

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,117 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.0.11] — 2026-08-30
12
+
13
+ ### Fixed
14
+
15
+ - **SC-Ticket-10: Checkout Flow's `createCart`/`getCart`/`updateCustomerDetails`/
16
+ `initiatePayment`/`confirmCart` threw "Malformed \<method\> response
17
+ (missing required fields)" on every genuinely successful backend
18
+ response.** `parseCartResponse()` (shared by the first four) and
19
+ `confirmCart()`'s own inline parser both read `cartId`/`cartType`/
20
+ `status`/`targetId` directly off the top-level JSON body instead of
21
+ unwrapping `{success, data, meta}` — same bug class as 1.0.7/1.0.9/1.0.10,
22
+ just never applied to the checkout-cart family. Live-verified against the
23
+ isopacai tenant with a real ACTIVE offering: `exchange()` itself (and the
24
+ rest of the bootstrap path) already worked fine — the reported ticket
25
+ title ("Malformed bridge exchange response") was a misdiagnosis one call
26
+ later in the same flow, exactly like SC-Ticket-5.
27
+
28
+ ## [1.0.10] — 2026-08-29
29
+
30
+ ### Fixed
31
+
32
+ - **SC-Ticket-5: Payment Method widget's initial load silently showed 0
33
+ payment methods for every customer, even ones with real saved cards.**
34
+ `fetchPaymentMethods()` and `createPaymentMethodSetupIntent()` read
35
+ response fields directly off the top-level JSON body instead of
36
+ unwrapping `{success, data, meta}` — same bug class fixed for
37
+ `fetchInvoices()` (1.0.7) and the cancel/upgrade responses (1.0.9), never
38
+ applied here. `fetchPaymentMethods()` is Pattern #18 fail-soft, so this
39
+ never threw a visible error — it just silently returned an empty list
40
+ regardless of how many cards the customer actually had on file.
41
+ (Live-verified `exchange()` itself, and the widget bundle's own deployed
42
+ copy of it, are both already correct — the ticket's reported "Malformed
43
+ bridge exchange response" text is a misdiagnosis of this unwrap bug one
44
+ call later in the same load path.)
45
+
46
+ ## [1.0.9] — 2026-08-29
47
+
48
+ ### Fixed
49
+
50
+ - **SC-Ticket-4 continued: cancellation succeeded server-side but the widget
51
+ still showed "Could not cancel."** After the 1.0.8 idempotencyKey fix,
52
+ live testing surfaced two more bugs in the same response path:
53
+ `cancelSubscription()`/`upgradeSubscription()` read fields directly off
54
+ the top-level response body instead of unwrapping `{success, data, meta}`
55
+ (same class of bug fixed for `fetchInvoices()` in 1.0.7, never applied
56
+ here), and `cancelSubscription()` additionally required `feedbackId` to
57
+ be present even though storefront-service's `/cancel` endpoint
58
+ deliberately omits it today (documented follow-up to read the V50 audit
59
+ row id back from pricing-service). Together these rejected every
60
+ genuinely successful cancellation as "malformed." `CancelResponse.feedbackId`
61
+ is now `string | null`. Live-verified: a real subscription
62
+ (`1b3af07f-d248-4860-a02b-9e3ee5601200`) was cancelled server-side
63
+ (confirmed `status: CANCELLED` in the raw API response) but the widget
64
+ still errored before this fix; re-tested after deploying 1.0.9.
65
+
66
+ ## [1.0.8] — 2026-08-29
67
+
68
+ ### Fixed
69
+
70
+ - **SC-Ticket-4: Upgrade/Cancel widget's Confirm step always failed** — the
71
+ ticket's reported symptom ("Malformed bridge exchange response") turned
72
+ out to be a misdiagnosis of a different, real bug one step later:
73
+ `cancelSubscription()` and `upgradeSubscription()` sent `idempotencyKey`
74
+ only via the `Idempotency-Key` header, but storefront-service's
75
+ `EmbedCancelRequest`/`EmbedUpgradeRequest` DTOs require it as a
76
+ `@NotBlank` BODY field too. Every real cancellation or upgrade 400'd with
77
+ "idempotencyKey is required" (or, before a separate backend fix shipped
78
+ the same day, "Invalid value 'DISCOUNT_20_PCT' for field
79
+ 'retentionOfferShown'" — the backend enum never matched the widget's own
80
+ documented `RetentionOfferShown` values). Both methods now include
81
+ `idempotencyKey` in the serialized body as well as the header.
82
+ Live-verified: a real subscription was successfully cancelled end-to-end
83
+ through this exact code path after the fix.
84
+
85
+ ## [1.0.7] — 2026-08-29
86
+
87
+ ### Fixed
88
+
89
+ - **SC-Ticket-3: Invoice List widget always showed "0 invoices" even when
90
+ the customer had real, finalized invoices.** `BridgeClient.fetchInvoices()`
91
+ read `content`/`totalElements`/`totalPages` directly off the top-level
92
+ parsed JSON body, but `GET /api/v1/portal/embed/invoices` (like every
93
+ other Aforo endpoint) wraps its payload in `{success, data, meta}` via the
94
+ platform's global `ApiResponseAdvice`. `body.content` was therefore always
95
+ `undefined`, silently falling back to an empty page — same failure mode
96
+ as the pricing-card `offerings` bug fixed in 1.0.5, just never applied
97
+ here. Live-verified: the API correctly returned 3 real invoices
98
+ (confirmed via direct backend testing) while the widget rendered "No
99
+ invoices yet." `fetchInvoicePdfUrl()` and `initiateInvoicePayment()` had
100
+ the identical bug and are fixed the same way (`raw.data ?? raw` unwrap,
101
+ matching the existing pattern already used in `exchange()` /
102
+ `fetchHeadlessConfig()` / `initiateCheckout()`).
103
+
104
+ ## [1.0.6] — 2026-08-26
105
+
106
+ ### Fixed
107
+
108
+ - **PricingCard's published "Card border radius" setting (Embed Studio →
109
+ Appearance) was never applied.** `borderRadius` is a valid field on the
110
+ fetched `embeddableWidget` tenant-defaults object — the tenant config API
111
+ correctly returned it — but `extractTenantDefaults()` only extracted its
112
+ sibling fields (`layout`, `theme`, `maxPlans`, `showFeatures`, `ctaText`)
113
+ and silently dropped `borderRadius`. The plan card's corner radius was
114
+ also hardcoded (`borderRadius: 12`) rather than reading any dynamic value.
115
+ `AforoPricingCardProps` now accepts an explicit `borderRadius` prop,
116
+ `extractTenantDefaults()` reads it from the tenant's published config, and
117
+ the resolved value (prop → tenant default → built-in 12px) is applied to
118
+ the plan card and its loading-skeleton twin. `pricingCardConfigToProps()`
119
+ also maps a `data-border-radius`/`borderRadius` mount-config override for
120
+ Script Tag integrations.
121
+
11
122
  ## [1.0.5] — 2026-08-26
12
123
 
13
124
  ### 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). */
@@ -1424,14 +1429,17 @@ var _BridgeClient = class _BridgeClient {
1424
1429
  idempotencyKey,
1425
1430
  sessionJwt
1426
1431
  }),
1427
- body: JSON.stringify(request)
1432
+ // 2026-08-29 fix: same bug as cancelSubscription() below — EmbedUpgradeRequest
1433
+ // requires idempotencyKey as a @NotBlank BODY field, but this only ever sent
1434
+ // it via the Idempotency-Key header.
1435
+ body: JSON.stringify({ ...request, idempotencyKey })
1428
1436
  });
1429
1437
  if (!resp.ok) {
1430
1438
  throw await this.parseError(resp);
1431
1439
  }
1432
- let body;
1440
+ let raw;
1433
1441
  try {
1434
- body = await resp.json();
1442
+ raw = await resp.json();
1435
1443
  } catch {
1436
1444
  throw new BridgeClientError(
1437
1445
  "Malformed upgrade response (not JSON)",
@@ -1440,6 +1448,7 @@ var _BridgeClient = class _BridgeClient {
1440
1448
  false
1441
1449
  );
1442
1450
  }
1451
+ const body = raw ? raw.data ?? raw : {};
1443
1452
  if (!body.subscriptionId || !body.previousOfferingId || !body.newOfferingId || !body.status) {
1444
1453
  throw new BridgeClientError(
1445
1454
  "Malformed upgrade response (missing required fields)",
@@ -1503,14 +1512,19 @@ var _BridgeClient = class _BridgeClient {
1503
1512
  idempotencyKey,
1504
1513
  sessionJwt
1505
1514
  }),
1506
- body: JSON.stringify(request)
1515
+ // 2026-08-29 fix: EmbedCancelRequest (storefront-service) requires
1516
+ // idempotencyKey as a @NotBlank BODY field — this only ever sent it
1517
+ // via the Idempotency-Key header, so every real cancellation 400'd
1518
+ // with "idempotencyKey is required" regardless of any other field.
1519
+ // Confirmed live against production.
1520
+ body: JSON.stringify({ ...request, idempotencyKey })
1507
1521
  });
1508
1522
  if (!resp.ok) {
1509
1523
  throw await this.parseError(resp);
1510
1524
  }
1511
- let body;
1525
+ let raw;
1512
1526
  try {
1513
- body = await resp.json();
1527
+ raw = await resp.json();
1514
1528
  } catch {
1515
1529
  throw new BridgeClientError(
1516
1530
  "Malformed cancel response (not JSON)",
@@ -1519,7 +1533,8 @@ var _BridgeClient = class _BridgeClient {
1519
1533
  false
1520
1534
  );
1521
1535
  }
1522
- if (!body.subscriptionId || !body.status || !body.effectiveAt || !body.feedbackId) {
1536
+ const body = raw ? raw.data ?? raw : null;
1537
+ if (!body || !body.subscriptionId || !body.status || !body.effectiveAt) {
1523
1538
  throw new BridgeClientError(
1524
1539
  "Malformed cancel response (missing required fields)",
1525
1540
  500,
@@ -1532,7 +1547,7 @@ var _BridgeClient = class _BridgeClient {
1532
1547
  status: body.status,
1533
1548
  cancelledAt: body.cancelledAt ?? null,
1534
1549
  effectiveAt: body.effectiveAt,
1535
- feedbackId: body.feedbackId,
1550
+ feedbackId: body.feedbackId ?? null,
1536
1551
  creditNoteId: body.creditNoteId ?? null
1537
1552
  };
1538
1553
  }
@@ -1562,7 +1577,8 @@ var _BridgeClient = class _BridgeClient {
1562
1577
  if (!resp.ok) {
1563
1578
  return { methods: [], defaultMethodId: null };
1564
1579
  }
1565
- const body = await resp.json();
1580
+ const raw = await resp.json();
1581
+ const body = raw ? raw.data ?? raw : {};
1566
1582
  return {
1567
1583
  methods: Array.isArray(body.methods) ? body.methods : [],
1568
1584
  defaultMethodId: body.defaultMethodId ?? null
@@ -1592,7 +1608,8 @@ var _BridgeClient = class _BridgeClient {
1592
1608
  body: JSON.stringify({})
1593
1609
  });
1594
1610
  if (!resp.ok) return null;
1595
- const body = await resp.json();
1611
+ const raw = await resp.json();
1612
+ const body = raw ? raw.data ?? raw : {};
1596
1613
  if (!body.clientSecret) return null;
1597
1614
  return {
1598
1615
  clientSecret: body.clientSecret,
@@ -2672,6 +2689,7 @@ function WidgetShell(props) {
2672
2689
  var DEFAULT_LAYOUT = "horizontal";
2673
2690
  var DEFAULT_MAX_PLANS = 4;
2674
2691
  var DEFAULT_CTA_TEXT = "Get Started";
2692
+ var DEFAULT_CARD_RADIUS = 12;
2675
2693
  function clampLayout(raw) {
2676
2694
  return raw === "horizontal" || raw === "vertical" || raw === "table" ? raw : void 0;
2677
2695
  }
@@ -2682,7 +2700,7 @@ function setTenantDefaultsIdempotent(setter, next) {
2682
2700
  setter((prev) => {
2683
2701
  if (prev === next) return prev;
2684
2702
  if (!prev && !next) return prev;
2685
- if (prev && next && prev.layout === next.layout && prev.theme === next.theme && prev.maxPlans === next.maxPlans && prev.showFeatures === next.showFeatures && prev.ctaText === next.ctaText) {
2703
+ if (prev && next && prev.layout === next.layout && prev.theme === next.theme && prev.maxPlans === next.maxPlans && prev.showFeatures === next.showFeatures && prev.ctaText === next.ctaText && prev.borderRadius === next.borderRadius) {
2686
2704
  return prev;
2687
2705
  }
2688
2706
  return next;
@@ -2697,7 +2715,8 @@ function extractTenantDefaults(config) {
2697
2715
  theme: typeof raw.theme === "string" ? raw.theme : void 0,
2698
2716
  maxPlans: typeof raw.maxPlans === "number" && Number.isFinite(raw.maxPlans) ? raw.maxPlans : void 0,
2699
2717
  showFeatures: typeof raw.showFeatures === "boolean" ? raw.showFeatures : void 0,
2700
- ctaText: typeof raw.ctaText === "string" && raw.ctaText.length > 0 ? raw.ctaText : void 0
2718
+ ctaText: typeof raw.ctaText === "string" && raw.ctaText.length > 0 ? raw.ctaText : void 0,
2719
+ borderRadius: typeof raw.borderRadius === "number" && Number.isFinite(raw.borderRadius) ? raw.borderRadius : void 0
2701
2720
  };
2702
2721
  }
2703
2722
  var DARK_TOKEN_OVERLAY = {
@@ -2819,6 +2838,7 @@ function PricingCardBody(props) {
2819
2838
  theme: themeProp,
2820
2839
  locale: localeProp,
2821
2840
  maxPlans: maxPlansProp,
2841
+ borderRadius: borderRadiusProp,
2822
2842
  showFeatures: showFeaturesProp,
2823
2843
  ctaText: ctaTextProp,
2824
2844
  ctaUrl: ctaUrlProp,
@@ -2832,6 +2852,7 @@ function PricingCardBody(props) {
2832
2852
  const maxPlans = typeof maxPlansProp === "number" && Number.isFinite(maxPlansProp) ? maxPlansProp : typeof tenantDefaults?.maxPlans === "number" && Number.isFinite(tenantDefaults.maxPlans) ? tenantDefaults.maxPlans : DEFAULT_MAX_PLANS;
2833
2853
  const showFeatures = typeof showFeaturesProp === "boolean" ? showFeaturesProp : typeof tenantDefaults?.showFeatures === "boolean" ? tenantDefaults.showFeatures : true;
2834
2854
  const ctaTextEffective = ctaTextProp ?? tenantDefaults?.ctaText ?? void 0;
2855
+ const cardRadius = typeof borderRadiusProp === "number" && Number.isFinite(borderRadiusProp) ? borderRadiusProp : typeof tenantDefaults?.borderRadius === "number" && Number.isFinite(tenantDefaults.borderRadius) ? tenantDefaults.borderRadius : DEFAULT_CARD_RADIUS;
2835
2856
  const shell = useWidgetShell();
2836
2857
  const { tokens: shellTokens, bridgeClient, telemetry, bus, tenantSlug } = shell;
2837
2858
  const isDark = React7__namespace.useMemo(() => {
@@ -3049,7 +3070,8 @@ function PricingCardBody(props) {
3049
3070
  {
3050
3071
  layout,
3051
3072
  tokens,
3052
- prefersReducedMotion
3073
+ prefersReducedMotion,
3074
+ cardRadius
3053
3075
  }
3054
3076
  )
3055
3077
  }
@@ -3121,7 +3143,8 @@ function PricingCardBody(props) {
3121
3143
  ctaTextProp: ctaTextEffective,
3122
3144
  featuredOverride: featuredOfferingId,
3123
3145
  onCtaClick: handleCtaClick,
3124
- intlOverride
3146
+ intlOverride,
3147
+ cardRadius
3125
3148
  }
3126
3149
  )
3127
3150
  }
@@ -3136,7 +3159,8 @@ function PlanGrid({
3136
3159
  ctaTextProp,
3137
3160
  featuredOverride,
3138
3161
  onCtaClick,
3139
- intlOverride
3162
+ intlOverride,
3163
+ cardRadius
3140
3164
  }) {
3141
3165
  const isHorizontal = layout === "horizontal";
3142
3166
  const gridStyle2 = isHorizontal ? {
@@ -3159,7 +3183,8 @@ function PlanGrid({
3159
3183
  ctaTextProp,
3160
3184
  featured: offeringIsFeatured(o, featuredOverride),
3161
3185
  onCtaClick,
3162
- intlOverride
3186
+ intlOverride,
3187
+ cardRadius
3163
3188
  },
3164
3189
  o.offeringId
3165
3190
  )) });
@@ -3172,7 +3197,8 @@ function PlanCard({
3172
3197
  ctaTextProp,
3173
3198
  featured,
3174
3199
  onCtaClick,
3175
- intlOverride
3200
+ intlOverride,
3201
+ cardRadius
3176
3202
  }) {
3177
3203
  const { text: price, unitSuffix } = resolveDisplayPrice(offering, locale, intlOverride);
3178
3204
  const isContactSales = price === "\u2014";
@@ -3183,7 +3209,7 @@ function PlanCard({
3183
3209
  display: "flex",
3184
3210
  flexDirection: "column",
3185
3211
  padding: 24,
3186
- borderRadius: 12,
3212
+ borderRadius: cardRadius,
3187
3213
  border: featured ? `2px solid ${tokens.primary}` : `1px solid ${tokens.border}`,
3188
3214
  background: tokens.bg,
3189
3215
  color: tokens.text,
@@ -3533,7 +3559,8 @@ function cellAria(label, feature) {
3533
3559
  function LoadingSkeleton({
3534
3560
  layout,
3535
3561
  tokens,
3536
- prefersReducedMotion
3562
+ prefersReducedMotion,
3563
+ cardRadius
3537
3564
  }) {
3538
3565
  const shimmerStyle = prefersReducedMotion ? { background: tokens.border, opacity: 0.6 } : {
3539
3566
  background: `linear-gradient(90deg, ${tokens.border} 0%, ${tokens.bg} 50%, ${tokens.border} 100%)`,
@@ -3566,7 +3593,7 @@ function LoadingSkeleton({
3566
3593
  "aria-hidden": "true",
3567
3594
  style: {
3568
3595
  padding: 24,
3569
- borderRadius: 12,
3596
+ borderRadius: cardRadius,
3570
3597
  border: `1px solid ${tokens.border}`,
3571
3598
  background: tokens.bg,
3572
3599
  minHeight: 280,
@@ -12198,7 +12225,7 @@ function ResultPanel({
12198
12225
  }
12199
12226
 
12200
12227
  // src/core/version.ts
12201
- var VERSION = "1.0.5";
12228
+ var VERSION = "1.0.11";
12202
12229
 
12203
12230
  // src/core/AforoEmbed.ts
12204
12231
  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
  /**
@@ -43,6 +43,8 @@ interface AforoPricingCardProps {
43
43
  locale?: string;
44
44
  /** Max plans to render — operator-set per FR-EMB-02. Default 4. */
45
45
  maxPlans?: number;
46
+ /** Card corner radius in px — operator-set per Embed Studio Appearance (0–32px). Default 12. */
47
+ borderRadius?: number;
46
48
  /** Whether to show the per-plan features list. Default `true`. */
47
49
  showFeatures?: boolean;
48
50
  /** Default CTA label when not overridden per-offering. Default `Get Started` (FR-EMB-03). */
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
  /**
@@ -43,6 +43,8 @@ interface AforoPricingCardProps {
43
43
  locale?: string;
44
44
  /** Max plans to render — operator-set per FR-EMB-02. Default 4. */
45
45
  maxPlans?: number;
46
+ /** Card corner radius in px — operator-set per Embed Studio Appearance (0–32px). Default 12. */
47
+ borderRadius?: number;
46
48
  /** Whether to show the per-plan features list. Default `true`. */
47
49
  showFeatures?: boolean;
48
50
  /** Default CTA label when not overridden per-offering. Default `Get Started` (FR-EMB-03). */