@aforoai/storefront-widgets 1.0.1
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 +327 -0
- package/LICENSE +21 -0
- package/README.md +249 -0
- package/SECURITY.md +138 -0
- package/dist/AforoEmbed-BqQOFsl3.d.cts +67 -0
- package/dist/AforoEmbed-CmqjlYlt.d.ts +67 -0
- package/dist/index.cjs +12320 -0
- package/dist/index.d.cts +1228 -0
- package/dist/index.d.ts +1228 -0
- package/dist/index.mjs +12286 -0
- package/dist/loader.js +3 -0
- package/dist/loader.mjs +3 -0
- package/dist/sri.json +15 -0
- package/dist/types-Dm6cp_Cc.d.cts +1185 -0
- package/dist/types-Dm6cp_Cc.d.ts +1185 -0
- package/dist/vanilla/index.cjs +12567 -0
- package/dist/vanilla/index.d.cts +22 -0
- package/dist/vanilla/index.d.ts +22 -0
- package/dist/vanilla/index.mjs +12543 -0
- package/dist/vue/index.cjs +12634 -0
- package/dist/vue/index.d.cts +157 -0
- package/dist/vue/index.d.ts +157 -0
- package/dist/vue/index.mjs +12605 -0
- package/dist/widgets/checkout-flow.js +55 -0
- package/dist/widgets/invoice-list.js +60 -0
- package/dist/widgets/payment-method.js +55 -0
- package/dist/widgets/pricing-card.js +60 -0
- package/dist/widgets/subscribe-button.js +61 -0
- package/dist/widgets/subscription-manager.js +55 -0
- package/dist/widgets/upgrade-cancel.js +55 -0
- package/dist/widgets/usage-meter.js +55 -0
- package/loader.sri.txt +1 -0
- package/package.json +118 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@aforoai/storefront-widgets` will be documented in
|
|
4
|
+
this file.
|
|
5
|
+
|
|
6
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
7
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Script-tag loader now parses the PricingCard presentation attributes
|
|
14
|
+
`data-cta-text`, `data-cta-url`, `data-max-plans`, and
|
|
15
|
+
`data-show-features`.** `pricingCardConfigToProps` reads all four
|
|
16
|
+
(`ctaText`/`ctaUrl`/`maxPlans`/`showFeatures`), and the operator Embed
|
|
17
|
+
Studio snippet (`EmbeddableWidgetTab`) emits `data-cta-text`,
|
|
18
|
+
`data-max-plans`, and `data-show-features` — but `readDataAttrs` never
|
|
19
|
+
parsed them, so those per-mount overrides silently did nothing on a
|
|
20
|
+
customer's page. Added a `readBooleanAttr` coercion helper for
|
|
21
|
+
`data-show-features` (data attributes are strings; the mapper guards on
|
|
22
|
+
`typeof === 'boolean'`). This brings PricingCard's script-tag tier to
|
|
23
|
+
parity with its React/JSX props. Regression coverage in
|
|
24
|
+
`tests/loader-config-attrs.test.ts`. Purely additive on the parse side.
|
|
25
|
+
|
|
26
|
+
- **Script-tag loader now parses `data-theme`, `data-cart-type`, and
|
|
27
|
+
`data-target-id`.** The shared config→props mappers
|
|
28
|
+
(`src/core/widgetConfigMaps.ts`) already read `config.config.theme`
|
|
29
|
+
(every widget), `config.config.cartType`, and `config.config.targetId`
|
|
30
|
+
(CheckoutFlow), but `readDataAttrs` in `loader/loader.ts` never parsed
|
|
31
|
+
those three `data-*` attributes — so a script-tag placeholder's theme
|
|
32
|
+
selection was ignored (always `auto`) and an embedded checkout always
|
|
33
|
+
fell back to `SUBSCRIBE` with an empty target. This completes the
|
|
34
|
+
parse↔consume contract for the documented attribute surface. Regression
|
|
35
|
+
coverage added in `tests/loader-config-attrs.test.ts`. No public API
|
|
36
|
+
change; purely additive on the loader's parse side.
|
|
37
|
+
|
|
38
|
+
- **`subscription-manager` `data-default-status` pre-filter now works.**
|
|
39
|
+
`subscriptionManagerConfigToProps` narrowed the value against a **lowercase**
|
|
40
|
+
allow-list (`active`, `trialing`, …) while `SubscriptionStatusFilter`, the
|
|
41
|
+
widget's `STATUS_CHIPS`, its `sub.status` comparisons, and the list-request
|
|
42
|
+
`status` param are all **UPPERCASE**. Every non-`all` selection (e.g.
|
|
43
|
+
`data-default-status="ACTIVE"`) was therefore rejected and silently fell
|
|
44
|
+
back to `all`, so the initial status filter never applied. The allow-list is
|
|
45
|
+
now the exact `SubscriptionStatusFilter` members (adds the previously-missing
|
|
46
|
+
`EXPIRING_SOON`). Regression test locks the accept-uppercase / reject-
|
|
47
|
+
lowercase-fallback contract.
|
|
48
|
+
|
|
49
|
+
## [1.0.1] — 2026-05-29
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **`BridgeClient` PaymentMethod methods now honour the demo-mode
|
|
54
|
+
provider.** All other `BridgeClient` methods (`exchange`,
|
|
55
|
+
`fetchHeadlessConfig`, `fetchSubscriptions`, `fetchUsage`,
|
|
56
|
+
`previewSubscriptionChange`, etc.) short-circuit via
|
|
57
|
+
`if (BridgeClient.demoModeProvider) return ...` at the top of the
|
|
58
|
+
method, so `installDemoModeProvider()` routes every call to the
|
|
59
|
+
registered mock. The four PaymentMethod methods shipped in v1.0.0
|
|
60
|
+
(`fetchPaymentMethods`, `createPaymentMethodSetupIntent`,
|
|
61
|
+
`setDefaultPaymentMethod`, `deletePaymentMethod`) were missing this
|
|
62
|
+
delegate — they always hit the real network path.
|
|
63
|
+
|
|
64
|
+
Symptom: any consumer that installed a demo-mode provider for testing
|
|
65
|
+
saw "No payment method on file" (empty list) from `AforoPaymentMethod`
|
|
66
|
+
even though the mock provider's `fetchPaymentMethods` returned cards.
|
|
67
|
+
The four methods now match the rest of the interface.
|
|
68
|
+
|
|
69
|
+
Discovered during the `@aforoai/storefront-widgets-sandbox` build-out
|
|
70
|
+
pass (sandbox v0.0.1 → live mounts). All other widgets render their
|
|
71
|
+
synthetic fixtures correctly; only PaymentMethod was returning empty.
|
|
72
|
+
|
|
73
|
+
No public API change — bug fix only. Customers on v1.0.0 should
|
|
74
|
+
upgrade if they rely on demo mode for PaymentMethod widget testing
|
|
75
|
+
(Embed Studio's operator preview pane is unaffected because it
|
|
76
|
+
bypasses BridgeClient via the `_mockPaymentMethods` internal prop).
|
|
77
|
+
|
|
78
|
+
## [1.0.0] — 2026-05-29
|
|
79
|
+
|
|
80
|
+
### General availability — all 8 widgets shipped, public API surface frozen.
|
|
81
|
+
|
|
82
|
+
This is the first generally-available release of `@aforoai/storefront-widgets`.
|
|
83
|
+
The public API is now stable per semver — breaking changes will require a major
|
|
84
|
+
bump and follow a 90-day deprecation period (see
|
|
85
|
+
[Versioning docs](https://docs.aforo.ai/docs/embed-versioning)).
|
|
86
|
+
|
|
87
|
+
### Widgets (8 — all with full implementations, no placeholders)
|
|
88
|
+
|
|
89
|
+
| Widget | Purpose | Gzipped bundle |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| **`AforoPricingCard`** | Anonymous pricing display (3 layouts: horizontal cards, vertical list, comparison table) | 59.15 KB |
|
|
92
|
+
| **`AforoSubscribeButton`** | Authenticated subscribe CTA with anti-double-subscribe lookup + 3 modes (redirect / event-only / embedded-flow) | 64.23 KB |
|
|
93
|
+
| **`AforoInvoiceList`** | Paginated customer invoice browser with status filter, PDF download, Pay Now | 69.93 KB |
|
|
94
|
+
| **`AforoCheckoutFlow`** | Multi-step embedded checkout (4-phase state machine) — Stripe Elements / Razorpay Drop-in / PayPal Smart Buttons | 60.86 KB |
|
|
95
|
+
| **`AforoSubscriptionManager`** | Customer-portal subscription detail view (read-only state machine surface, upgrade/cancel events delegated to parent) | 60.23 KB |
|
|
96
|
+
| **`AforoUsageMeter`** | Per-subscription real-time usage display with quota progress + threshold-reached alerts | 58.85 KB |
|
|
97
|
+
| **`AforoPaymentMethod`** | Add / update / remove payment method via provider iframes (Stripe SetupIntent, Razorpay tokenize, PayPal Vault) | 57.89 KB |
|
|
98
|
+
| **`AforoUpgradeCancel`** | Multi-step upgrade + cancellation deflection wizard (V50 CancellationFeedback reuse) | 61.51 KB |
|
|
99
|
+
|
|
100
|
+
All bundles within FR-TIER-7 (loader ≤ 15 KB gz) and FR-TIER-8 (per-widget ≤ 80 KB gz) budgets defined in the spec.
|
|
101
|
+
|
|
102
|
+
### Foundation locked
|
|
103
|
+
|
|
104
|
+
- **AforoSession singleton** — N widgets on the same page perform exactly 1 bridge exchange (FR-§17.16). Verified by `tests/integration/all-widgets-singleton.test.tsx` (deferred to follow-up).
|
|
105
|
+
- **Three distribution tiers** — Script-tag loader (2.42 KB gz), npm ESM / CJS (peer-dep React 18+), Vue 3 adapter at `@aforoai/storefront-widgets/vue`.
|
|
106
|
+
- **Real-time push via SSE** — Backend `SseEmitter` + Redis pub/sub fan-out, exponential-backoff reconnect (capped at 60s), 100ms event dedup.
|
|
107
|
+
- **Magic-link auth** — Anti-enumeration 200-always pattern + 15-minute single-use tokens + 10/min per-IP + 5/hour per-email rate limits.
|
|
108
|
+
- **SRI hash publication** — Manifest at `embed.aforo.ai/v1/sri.json` for per-bundle integrity pinning.
|
|
109
|
+
- **Theme inheritance** — 4-layer cascade (overrides → CSS custom properties → brand kit → neutral default).
|
|
110
|
+
|
|
111
|
+
### Security
|
|
112
|
+
|
|
113
|
+
- Embed-key auth + bridge-token JWT exchange + per-widget signature verification (FR-SEC-9).
|
|
114
|
+
- Origin allowlist enforcement on all postMessage events (FR-EVT-6) — `targetOrigin` is never `*`.
|
|
115
|
+
- HTTPS-only enforcement at loader (rejects `http://` pages with clear console error, FR-TIER-12).
|
|
116
|
+
- CSP `nonce` propagation from loader script to dynamically-injected widget scripts (FR-SEC-16).
|
|
117
|
+
- Webhook-authoritative rule (FR-SEC-23) — backend webhooks are canonical; postMessage events are informational.
|
|
118
|
+
- In-memory tokens only — session JWTs never written to `localStorage`, `sessionStorage`, or cookies. Cleared on tab close.
|
|
119
|
+
- No `eval()`, no `Function()`, no dynamic `import()` of untrusted URLs.
|
|
120
|
+
|
|
121
|
+
### Operator surface
|
|
122
|
+
|
|
123
|
+
- Embed Studio tab in aforo-product UI with 4 sub-tabs: Widgets / Keys / Auth Bridge / Telemetry.
|
|
124
|
+
- Inline preview pane for all 8 widgets with mock-mode short-circuit via underscore-prefixed props.
|
|
125
|
+
- One-time plaintext reveal on key mint with 10-minute auto-clear.
|
|
126
|
+
- Telemetry CSV / JSON export with formula-injection guard.
|
|
127
|
+
|
|
128
|
+
### Public docs
|
|
129
|
+
|
|
130
|
+
- 12 docs pages at `docs.aforo.ai/docs/embed-*` — Quick Start, all 8 widget references, Authentication, Theming, Events, Integration Patterns, Security, Versioning.
|
|
131
|
+
|
|
132
|
+
### Bundle sizes (gzipped)
|
|
133
|
+
|
|
134
|
+
| Bundle | Size | Budget |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| `dist/loader.umd.js` | 2.42 KB | 15 KB |
|
|
137
|
+
| `dist/widgets/pricing-card.js` | 59.15 KB | 80 KB |
|
|
138
|
+
| `dist/widgets/subscribe-button.js` | 64.23 KB | 80 KB |
|
|
139
|
+
| `dist/widgets/invoice-list.js` | 69.93 KB | 80 KB |
|
|
140
|
+
| `dist/widgets/checkout-flow.js` | 60.86 KB | 80 KB |
|
|
141
|
+
| `dist/widgets/subscription-manager.js` | 60.23 KB | 80 KB |
|
|
142
|
+
| `dist/widgets/usage-meter.js` | 58.85 KB | 80 KB |
|
|
143
|
+
| `dist/widgets/payment-method.js` | 57.89 KB | 80 KB |
|
|
144
|
+
| `dist/widgets/upgrade-cancel.js` | 61.51 KB | 80 KB |
|
|
145
|
+
|
|
146
|
+
### Quality gates (status at 1.0.0 ship)
|
|
147
|
+
|
|
148
|
+
- **393 unit tests pass** across 41 test files. Public surface contract locked
|
|
149
|
+
by `sdk-contract.test.ts`; BridgeClient fail-soft on read paths + propagates
|
|
150
|
+
on mutation paths; AforoSession multi-tenant isolation + magic-link verify;
|
|
151
|
+
EventBus origin allowlist + dedup + non-`*` targetOrigin; ThemeReader
|
|
152
|
+
cascade; TelemetryReporter consent gating; per-widget unit + a11y + events +
|
|
153
|
+
session + loader tests.
|
|
154
|
+
- **Axe-core WCAG 2.1 AA** verified zero violations across all 8 widgets in
|
|
155
|
+
default + loading + error + has-data + empty states.
|
|
156
|
+
|
|
157
|
+
### Deferred to Phase 1 (explicitly out of scope for v1.0.0)
|
|
158
|
+
|
|
159
|
+
- iframe tier rendering — current ship is script-tag + npm + Vue 3 only
|
|
160
|
+
- OAuth / OIDC tenant-managed auth
|
|
161
|
+
- Multi-subject sessions
|
|
162
|
+
- Last-Event-ID SSE replay
|
|
163
|
+
- DNS ownership challenge for custom domains
|
|
164
|
+
- Enterprise self-hosted bundle assets
|
|
165
|
+
- Web Components tier
|
|
166
|
+
- Subscription pause flow within `AforoUpgradeCancel`
|
|
167
|
+
- Per-tenant custom deflection offers in cancel flow
|
|
168
|
+
- Sortable columns on `AforoInvoiceList`
|
|
169
|
+
- Inline 3DS modal (currently falls back to provider-hosted challenge page in new tab)
|
|
170
|
+
- Full Storybook config + Chromatic CI integration (`.stories.tsx` files
|
|
171
|
+
shipped; mounting via Storybook is a separate ship)
|
|
172
|
+
- Sandbox playground at `embed.aforo.ai/sandbox`
|
|
173
|
+
- Cross-browser matrix execution + Lighthouse audit runbooks (Prompt 15
|
|
174
|
+
formal gauntlet documents — `v1.0.0` ships with the artifact verified to
|
|
175
|
+
build + test green and bundle sizes within budget; the formal matrix
|
|
176
|
+
runbook is a follow-up)
|
|
177
|
+
- i18n — UI strings are English-only at v1.0.0; locale-aware currency + date
|
|
178
|
+
formatting via `Intl` works today
|
|
179
|
+
|
|
180
|
+
### Known limitations
|
|
181
|
+
|
|
182
|
+
Same as the Phase 1 deferral list above. None of these block v1.0.0 customer
|
|
183
|
+
rollout for tenants on Chrome / Edge / Firefox / Safari modern channels and
|
|
184
|
+
standard payment providers.
|
|
185
|
+
|
|
186
|
+
## [0.1.0] — 2026-05-29
|
|
187
|
+
|
|
188
|
+
### Initial public release.
|
|
189
|
+
|
|
190
|
+
This is the first release published to public npm. The SDK was previously
|
|
191
|
+
private (workspace-internal) while widget bodies were built out. The public
|
|
192
|
+
surface is locked by [`sdk-contract.test.ts`](https://github.com/aforoai/aforo-nextgen-UI/blob/main/packages/storefront-widgets/tests/sdk-contract.test.ts) —
|
|
193
|
+
adding or removing an export is a deliberate test update.
|
|
194
|
+
|
|
195
|
+
### Widgets shipped (4 of 8)
|
|
196
|
+
|
|
197
|
+
- **`AforoPricingCard`** — anonymous pricing display with three layouts
|
|
198
|
+
(horizontal cards, vertical list, comparison table). Auto-fetches the
|
|
199
|
+
tenant's published offerings from the headless config endpoint and
|
|
200
|
+
inherits brand kit colors via the theme cascade.
|
|
201
|
+
- **`AforoSubscribeButton`** — authenticated subscribe CTA. Exchanges a
|
|
202
|
+
bridge token for a session JWT, checks for an existing subscription to
|
|
203
|
+
avoid double-subscribing, and routes to checkout in redirect, event-only,
|
|
204
|
+
or embedded-flow mode.
|
|
205
|
+
- **`AforoInvoiceList`** — paginated customer invoice table with status
|
|
206
|
+
filtering (UNPAID/PAID/OVERDUE/VOID), search, PDF download, and Pay Now
|
|
207
|
+
action. 30s in-widget client cache for responsive filter/page scrubbing.
|
|
208
|
+
- **`AforoCheckoutFlow`** — multi-step embedded checkout. 4-phase state
|
|
209
|
+
machine (customer details → payment → confirming → completed), with
|
|
210
|
+
Stripe Payment Element, Razorpay Drop-in, and PayPal Smart Buttons via
|
|
211
|
+
postMessage-bridged iframes. Supports both SUBSCRIBE and INVOICE_PAYMENT
|
|
212
|
+
cart types.
|
|
213
|
+
|
|
214
|
+
### Widgets stubbed (placeholder bodies; full implementations in subsequent releases)
|
|
215
|
+
|
|
216
|
+
- `AforoSubscriptionManager`, `AforoUsageMeter`, `AforoPaymentMethod`,
|
|
217
|
+
`AforoUpgradeCancel` — these render an accessible loading placeholder
|
|
218
|
+
with their final prop interface locked. Drop-in replacement once their
|
|
219
|
+
bodies ship; the public API will not change.
|
|
220
|
+
|
|
221
|
+
### Infrastructure
|
|
222
|
+
|
|
223
|
+
#### Three embed tiers
|
|
224
|
+
|
|
225
|
+
- **Script tag.** Drop one `<script>` plus `<div data-aforo-widget="…">`
|
|
226
|
+
placeholders. The loader (~2.5 KB gzipped) discovers placeholders,
|
|
227
|
+
lazy-fetches per-widget bundles, and mounts. Works in Webflow, WordPress,
|
|
228
|
+
plain HTML — no build toolchain required.
|
|
229
|
+
- **npm / React.** `npm install @aforoai/storefront-widgets` then
|
|
230
|
+
`import { AforoPricingCard } from '@aforoai/storefront-widgets'`.
|
|
231
|
+
React 18+ peer dependency.
|
|
232
|
+
- **Vue 3 + vanilla JS.** Wrappers shipped at
|
|
233
|
+
`@aforoai/storefront-widgets/vue` and
|
|
234
|
+
`@aforoai/storefront-widgets/vanilla`.
|
|
235
|
+
|
|
236
|
+
#### Authentication
|
|
237
|
+
|
|
238
|
+
- **Anonymous** — pricing display only; embed key + domain allowlist.
|
|
239
|
+
- **Bridge token** — customer backend mints a short-lived signed token;
|
|
240
|
+
SDK exchanges it for an in-memory session JWT.
|
|
241
|
+
- **Magic link** — for portals without their own session: SDK posts the
|
|
242
|
+
customer's email to Aforo, customer clicks the emailed link, returns to
|
|
243
|
+
the host page with a session JWT. Anti-enumeration: identical 202
|
|
244
|
+
response regardless of whether the email is registered. Rate-limited per
|
|
245
|
+
IP (10/min) and per email (5/hour). 15-minute one-time-use tokens.
|
|
246
|
+
|
|
247
|
+
#### Real-time push (SSE)
|
|
248
|
+
|
|
249
|
+
- Server-Sent-Events stream pushes lifecycle events
|
|
250
|
+
(`invoice.paid`, `subscription.status_changed`, `payment.failed`,
|
|
251
|
+
`usage.threshold_breached`, `invoice.created`) to mounted widgets in
|
|
252
|
+
real time. Automatic exponential-backoff reconnect (capped at 60s), per-
|
|
253
|
+
tab connection cap, 30s grace-close after last subscriber unsubscribes.
|
|
254
|
+
|
|
255
|
+
#### Theming
|
|
256
|
+
|
|
257
|
+
- Three-layer cascade: tenant brand-kit fallback → CSS variables on the
|
|
258
|
+
customer's page → per-widget `themeOverrides` prop. Dark mode via
|
|
259
|
+
`theme="dark"`, RTL via 100% logical CSS properties, namespaced classes
|
|
260
|
+
(`aforo-w-pc-*`, `aforo-w-sb-*`, etc.).
|
|
261
|
+
|
|
262
|
+
#### Events
|
|
263
|
+
|
|
264
|
+
- Outbound: every widget emits a typed
|
|
265
|
+
`aforo.<widget>.<event>` postMessage. Origin is always the resolved
|
|
266
|
+
parent origin — never `*`. 100ms dedup window per `(type, payload-hash)`.
|
|
267
|
+
- Inbound: 5-type allowlist (`aforo:checkout-completed`,
|
|
268
|
+
`aforo:checkout-cancelled`, `aforo:invoice-paid`,
|
|
269
|
+
`aforo:refresh-requested`, `aforo:payment-challenge-completed`).
|
|
270
|
+
Origin allowlist enforced against the embed key's registered domains.
|
|
271
|
+
|
|
272
|
+
### Security
|
|
273
|
+
|
|
274
|
+
- **Subresource Integrity (SRI).** Per-version SHA-384 hashes published at
|
|
275
|
+
`https://embed.aforo.ai/v1/sri.json`. Customers pin via `integrity=`
|
|
276
|
+
attribute on the loader `<script>`.
|
|
277
|
+
- **Dedicated origin.** All bundles served from `embed.aforo.ai` so CORS,
|
|
278
|
+
CSP, and SRI policies isolate the embed surface from the rest of Aforo.
|
|
279
|
+
- **No dynamic code.** No `eval()`, no `Function()`, no dynamic
|
|
280
|
+
`import()` of untrusted URLs.
|
|
281
|
+
- **HTTPS-only loader.** Bootstrap refuses to run on `http://` pages.
|
|
282
|
+
- **In-memory tokens.** Session JWTs are never written to `localStorage`,
|
|
283
|
+
`sessionStorage`, or cookies. Cleared on tab close.
|
|
284
|
+
|
|
285
|
+
### Test coverage
|
|
286
|
+
|
|
287
|
+
- 313 unit tests covering: public surface contract, BridgeClient (with
|
|
288
|
+
fail-soft semantics on all read paths), AforoSession multi-tenant
|
|
289
|
+
isolation + magic-link verify flow, EventBus origin allowlist + dedup
|
|
290
|
+
+ outbound non-`*` targetOrigin, ThemeReader cascade, TelemetryReporter
|
|
291
|
+
consent gating, all 4 shipped widgets (unit + a11y + events + SSE).
|
|
292
|
+
- Axe-core WCAG 2.1 AA verified zero violations across all shipped
|
|
293
|
+
widgets in default + loading + error + has-data states.
|
|
294
|
+
|
|
295
|
+
### Bundle sizes (gzipped)
|
|
296
|
+
|
|
297
|
+
| Bundle | Size | Budget |
|
|
298
|
+
|---------------------------------|-----------|-----------|
|
|
299
|
+
| `dist/loader.umd.js` | 2.42 KB | 15 KB |
|
|
300
|
+
| `dist/widgets/pricing-card.js` | 56.28 KB | 80 KB |
|
|
301
|
+
| `dist/widgets/subscribe-button.js` | 62.80 KB | 80 KB |
|
|
302
|
+
| `dist/widgets/invoice-list.js` | 68.49 KB | 80 KB |
|
|
303
|
+
| `dist/widgets/checkout-flow.js` | 59.43 KB | 80 KB |
|
|
304
|
+
|
|
305
|
+
All within FR-TIER-7 (loader 15 KB) and FR-TIER-8 (per-widget 80 KB)
|
|
306
|
+
budgets defined in the spec.
|
|
307
|
+
|
|
308
|
+
### Known limitations
|
|
309
|
+
|
|
310
|
+
- **Iframe tier rendering deferred to Phase 1.** v0.1.x ships script-tag
|
|
311
|
+
and npm tiers only. The iframe wrapper (for tenants requiring strict
|
|
312
|
+
origin isolation) lands in a future release.
|
|
313
|
+
- **3DS challenge falls back to redirect.** Inline 3DS modal coming in
|
|
314
|
+
Phase 1; v0.1.x customers requiring 3DS see the gateway's hosted
|
|
315
|
+
challenge page in a new tab.
|
|
316
|
+
- **4 widget shells still render placeholder.** SubscriptionManager,
|
|
317
|
+
UsageMeter, PaymentMethod, UpgradeCancel will receive full bodies in
|
|
318
|
+
subsequent minor releases. Their public API surface (props + events)
|
|
319
|
+
is locked so dropping in the new bundle does not require code changes.
|
|
320
|
+
- **Sandbox playground at embed.aforo.ai/sandbox coming.** Lets developers
|
|
321
|
+
try widgets against synthetic data without setting up an account.
|
|
322
|
+
- **No i18n yet.** All copy is English. Locale-aware currency + date
|
|
323
|
+
formatting via `Intl` works today, but UI strings are not externalised.
|
|
324
|
+
|
|
325
|
+
[1.0.1]: https://github.com/aforoai/aforo-nextgen-UI/releases/tag/storefront-widgets-v1.0.1
|
|
326
|
+
[1.0.0]: https://github.com/aforoai/aforo-nextgen-UI/releases/tag/storefront-widgets-v1.0.0
|
|
327
|
+
[0.1.0]: https://github.com/aforoai/aforo-nextgen-UI/releases/tag/storefront-widgets-v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aforo AI Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# @aforoai/storefront-widgets
|
|
2
|
+
|
|
3
|
+
> Drop-in embeddable widgets for Aforo's storefront — pricing cards, subscribe
|
|
4
|
+
> buttons, invoice lists, and embedded checkout. Brand them yours, ship in
|
|
5
|
+
> minutes.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@aforoai/storefront-widgets)
|
|
8
|
+
[](./LICENSE)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @aforoai/storefront-widgets
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Full developer docs:** <https://docs.aforo.ai/docs/embed-quickstart>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## What you get
|
|
19
|
+
|
|
20
|
+
Eight widgets covering the customer billing surface. v0.1.0 ships four real
|
|
21
|
+
widget bodies — the other four render an accessible loading placeholder while
|
|
22
|
+
their bodies are being built. Their public API is locked, so dropping in the
|
|
23
|
+
new bundle later requires no code changes on your side.
|
|
24
|
+
|
|
25
|
+
| Widget | Status | What it does |
|
|
26
|
+
|-----------------------------|-----------------|---------------------------------------------------|
|
|
27
|
+
| `AforoPricingCard` | ✅ Shipped | Anonymous pricing display (horizontal / vertical / table) |
|
|
28
|
+
| `AforoSubscribeButton` | ✅ Shipped | Authenticated subscribe CTA with anti-double-subscribe check |
|
|
29
|
+
| `AforoInvoiceList` | ✅ Shipped | Paginated invoice list with status filter, search, PDF, Pay Now |
|
|
30
|
+
| `AforoCheckoutFlow` | ✅ Shipped | Multi-step embedded checkout (Stripe / Razorpay / PayPal) |
|
|
31
|
+
| `AforoSubscriptionManager` | 🔜 Coming soon | Customer-facing subscription summary + lifecycle actions |
|
|
32
|
+
| `AforoUsageMeter` | 🔜 Coming soon | Real-time per-metric usage gauges with quota visualization |
|
|
33
|
+
| `AforoPaymentMethod` | 🔜 Coming soon | Saved payment methods table + add/remove flow |
|
|
34
|
+
| `AforoUpgradeCancel` | 🔜 Coming soon | Plan upgrade / downgrade / cancel flow with deflection |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Three ways to embed
|
|
39
|
+
|
|
40
|
+
### 1. Script tag (no build needed)
|
|
41
|
+
|
|
42
|
+
For Webflow, WordPress, Squarespace, and plain HTML pages. The loader is
|
|
43
|
+
~2.5 KB gzipped and lazy-fetches per-widget bundles only when their
|
|
44
|
+
placeholders are on the page.
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<script
|
|
48
|
+
src="https://embed.aforo.ai/v1/loader.js"
|
|
49
|
+
integrity="sha384-…"
|
|
50
|
+
crossorigin="anonymous"
|
|
51
|
+
async
|
|
52
|
+
></script>
|
|
53
|
+
|
|
54
|
+
<div
|
|
55
|
+
data-aforo-widget="pricing-card"
|
|
56
|
+
data-tenant-slug="acme"
|
|
57
|
+
data-embed-key="embk_live_…"
|
|
58
|
+
data-layout="horizontal"
|
|
59
|
+
></div>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The current SRI hash for `loader.js` is at
|
|
63
|
+
<https://embed.aforo.ai/v1/sri.json>. Copy it into the `integrity=`
|
|
64
|
+
attribute on the `<script>` tag so the browser refuses to execute a
|
|
65
|
+
tampered bundle.
|
|
66
|
+
|
|
67
|
+
### 2. React / Next.js
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { AforoPricingCard } from '@aforoai/storefront-widgets';
|
|
71
|
+
|
|
72
|
+
export function PricingSection() {
|
|
73
|
+
return (
|
|
74
|
+
<AforoPricingCard
|
|
75
|
+
tenantSlug="acme"
|
|
76
|
+
embedKey="embk_live_…"
|
|
77
|
+
layout="horizontal"
|
|
78
|
+
ctaUrlByOffering={{ off_pro: '/checkout/pro' }}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Vue 3
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<script setup>
|
|
88
|
+
import { AforoPricingCard } from '@aforoai/storefront-widgets/vue';
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<template>
|
|
92
|
+
<AforoPricingCard
|
|
93
|
+
tenant-slug="acme"
|
|
94
|
+
embed-key="embk_live_…"
|
|
95
|
+
layout="horizontal"
|
|
96
|
+
/>
|
|
97
|
+
</template>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Vanilla JS consumers (Svelte, Solid, Lit, etc.) import from
|
|
101
|
+
`@aforoai/storefront-widgets/vanilla` — the same mount/unmount API the
|
|
102
|
+
loader script uses internally.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Authentication modes
|
|
107
|
+
|
|
108
|
+
The plugin tier supports three auth modes depending on what your portal
|
|
109
|
+
already has:
|
|
110
|
+
|
|
111
|
+
1. **Anonymous** — pricing display only, no customer context. Use this for
|
|
112
|
+
marketing pages where you want to show your live offerings without
|
|
113
|
+
asking visitors to sign in.
|
|
114
|
+
|
|
115
|
+
2. **Bridge token** — your backend mints a short-lived signed token that
|
|
116
|
+
identifies your customer to Aforo. The widget exchanges it for an
|
|
117
|
+
in-memory session JWT — your signing key never reaches the browser.
|
|
118
|
+
Use this when your portal already has its own authenticated session.
|
|
119
|
+
|
|
120
|
+
3. **Magic link** — for portals that don't have their own session yet.
|
|
121
|
+
The customer types their email, gets an Aforo-branded email, clicks
|
|
122
|
+
the link, and lands back on your page with a session JWT. Rate-limited
|
|
123
|
+
and anti-enumeration-defended out of the box.
|
|
124
|
+
|
|
125
|
+
Full guide with sequence diagrams + code samples for Node.js / Python / Go
|
|
126
|
+
bridge-token signing: <https://docs.aforo.ai/docs/embed-authentication>.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Theming
|
|
131
|
+
|
|
132
|
+
Three-layer cascade — each layer overrides the previous:
|
|
133
|
+
|
|
134
|
+
1. **Tenant brand kit** (logo + colors) configured in Aforo's Storefront →
|
|
135
|
+
Customize, fetched once when the widget mounts.
|
|
136
|
+
2. **CSS variables** on your page (e.g. `--aforo-color-primary: #1A73E8;`)
|
|
137
|
+
override the brand kit for fine-grained theming.
|
|
138
|
+
3. **Per-widget `themeOverrides` prop** for in-React/Vue customization at
|
|
139
|
+
the component level.
|
|
140
|
+
|
|
141
|
+
Dark mode is opt-in via `theme="dark"`. The widgets are RTL-safe (100%
|
|
142
|
+
logical CSS properties) and namespace every class
|
|
143
|
+
(`aforo-w-pc-*`, `aforo-w-sb-*`, etc.) to avoid colliding with your CSS.
|
|
144
|
+
|
|
145
|
+
Full theming docs: <https://docs.aforo.ai/docs/embed-theming>.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Events
|
|
150
|
+
|
|
151
|
+
Every widget emits typed `postMessage` events you can listen to from the
|
|
152
|
+
parent page. Origin is always the resolved parent origin — never `*`.
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
window.aforoEmbed?.on('aforo.subscribe.checkout_requested', (payload) => {
|
|
156
|
+
console.log('Customer clicked subscribe', payload);
|
|
157
|
+
// payload = { offeringId, planName, priceCents, currency, billingCycle, ratePlanId }
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Common events:
|
|
162
|
+
|
|
163
|
+
| Event | When |
|
|
164
|
+
|--------------------------------------|-----------------------------------------------|
|
|
165
|
+
| `aforo.<widget>.ready` | Widget mounted and first paint complete |
|
|
166
|
+
| `aforo.subscribe.checkout_requested` | Customer clicked Subscribe |
|
|
167
|
+
| `aforo.subscription.created` | Subscribe checkout completed (advisory only) |
|
|
168
|
+
| `aforo.invoice-list.invoice.paid` | Invoice marked paid via SSE push |
|
|
169
|
+
| `aforo.checkout.confirmed` | Embedded checkout completed |
|
|
170
|
+
| `aforo.<widget>.error` | Any error path (typed `code`, no PII) |
|
|
171
|
+
|
|
172
|
+
> **⚠ Webhook is authoritative.** postMessage events fired into your page
|
|
173
|
+
> are **advisory only**. Always validate state changes via Aforo's signed
|
|
174
|
+
> webhooks before mutating your own database. We surface this prominently
|
|
175
|
+
> because it's the most common source of integration bugs.
|
|
176
|
+
|
|
177
|
+
Full event catalog: <https://docs.aforo.ai/docs/embed-events>.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Browser support
|
|
182
|
+
|
|
183
|
+
We test against the latest two stable versions of every major browser. The
|
|
184
|
+
SDK runs anywhere modern JavaScript runs.
|
|
185
|
+
|
|
186
|
+
| Browser | Minimum version | Notes |
|
|
187
|
+
|--------------------|-----------------|-------|
|
|
188
|
+
| Chrome | N-2 (latest 2) | Desktop and Android |
|
|
189
|
+
| Firefox | N-2 | Desktop |
|
|
190
|
+
| Safari | 16+ | macOS |
|
|
191
|
+
| Mobile Safari | iOS 16+ | iPhone + iPad |
|
|
192
|
+
| Mobile Chrome | Android 12+ | Most devices |
|
|
193
|
+
| Edge | Latest | Chromium-based |
|
|
194
|
+
|
|
195
|
+
The loader refuses to bootstrap on `http://` pages — HTTPS is mandatory.
|
|
196
|
+
We do not support IE11 or pre-Chromium Edge.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Security
|
|
201
|
+
|
|
202
|
+
- **SRI hashes published per release** at
|
|
203
|
+
<https://embed.aforo.ai/v1/sri.json>. Pin them via `integrity=` on the
|
|
204
|
+
`<script>` tag.
|
|
205
|
+
- **Customer CSP guidance.** Add `script-src https://embed.aforo.ai` and
|
|
206
|
+
`connect-src https://api.aforo.ai` to your Content-Security-Policy. No
|
|
207
|
+
`unsafe-inline` or `unsafe-eval` required.
|
|
208
|
+
- **In-memory session JWTs.** Never written to `localStorage`,
|
|
209
|
+
`sessionStorage`, or cookies. Cleared on tab close.
|
|
210
|
+
- **Anti-enumeration on magic-link.** Identical 202 response regardless of
|
|
211
|
+
whether the email is registered. Rate-limited per IP and per email.
|
|
212
|
+
- **No dynamic code.** No `eval()`, no `Function()`, no dynamic `import()`
|
|
213
|
+
of untrusted URLs.
|
|
214
|
+
|
|
215
|
+
Full security model + how to report vulnerabilities: see
|
|
216
|
+
[`SECURITY.md`](./SECURITY.md).
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Versioning
|
|
221
|
+
|
|
222
|
+
We follow [Semantic Versioning](https://semver.org). Pre-1.0:
|
|
223
|
+
|
|
224
|
+
- `0.x.y` — frequent additions, occasional breaking changes documented in
|
|
225
|
+
[CHANGELOG.md](./CHANGELOG.md). Pin to a specific version in production.
|
|
226
|
+
|
|
227
|
+
Post-1.0:
|
|
228
|
+
|
|
229
|
+
- `1.x.y` — strict semver. Additions and bug fixes only.
|
|
230
|
+
- `2.x.y` — breaking changes with a 90-day deprecation period announced
|
|
231
|
+
via the changelog. The loader URL is pinned at `/v1/` and stays
|
|
232
|
+
backward-compatible within v1.
|
|
233
|
+
|
|
234
|
+
Full versioning policy: <https://docs.aforo.ai/docs/embed-versioning>.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT — see [LICENSE](./LICENSE).
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Support
|
|
245
|
+
|
|
246
|
+
- 📖 Docs: <https://docs.aforo.ai/docs/embed-quickstart>
|
|
247
|
+
- 🐛 Issues: <https://github.com/aforoai/aforo-nextgen-UI/issues>
|
|
248
|
+
- 🔒 Security: `security@aforo.ai`
|
|
249
|
+
- 💬 Email: `support@aforo.ai`
|