@solvapay/react 1.0.9-preview.1 → 1.0.9
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 +209 -0
- package/CONTRIBUTING.md +117 -0
- package/README.md +426 -24
- package/dist/adapters/auth.d.cts +13 -0
- package/dist/adapters/auth.d.ts +13 -0
- package/dist/adapters/auth.js +1 -0
- package/dist/chunk-37R5NZGF.js +4824 -0
- package/dist/chunk-HWVJL5X6.js +429 -0
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-R2ZPZ7VM.js +597 -0
- package/dist/chunk-ZAV7CQ4G.js +361 -0
- package/dist/index-WBjulQHf.d.cts +3656 -0
- package/dist/index-onWNU7iT.d.ts +3656 -0
- package/dist/index.cjs +5556 -1143
- package/dist/index.d.cts +618 -708
- package/dist/index.d.ts +618 -708
- package/dist/index.js +597 -1664
- package/dist/mcp/index.cjs +8096 -0
- package/dist/mcp/index.d.cts +1013 -0
- package/dist/mcp/index.d.ts +1013 -0
- package/dist/mcp/index.js +2724 -0
- package/dist/mcp/styles.css +1020 -0
- package/dist/primitives/index.cjs +5316 -0
- package/dist/primitives/index.d.cts +721 -0
- package/dist/primitives/index.d.ts +721 -0
- package/dist/primitives/index.js +232 -0
- package/dist/styles.css +1115 -0
- package/dist/useUsage-BmOYXxgG.d.cts +413 -0
- package/dist/useUsage-nD7zwSbG.d.ts +413 -0
- package/dist/webapi-K5XBCEO6.js +3775 -0
- package/package.json +37 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# @solvapay/react changelog
|
|
2
|
+
|
|
3
|
+
From `1.0.10` onwards this changelog is generated by
|
|
4
|
+
[changesets](https://github.com/changesets/changesets) — prior entries
|
|
5
|
+
are maintained by hand and are grouped by the first preview / stable
|
|
6
|
+
release that contains them.
|
|
7
|
+
|
|
8
|
+
## Unreleased
|
|
9
|
+
|
|
10
|
+
## 1.0.9 — peer-dep rename: `@solvapay/mcp` → `@solvapay/mcp-core`
|
|
11
|
+
|
|
12
|
+
The optional peer dependency that guards `@solvapay/react/mcp` types was
|
|
13
|
+
renamed from `@solvapay/mcp` → `@solvapay/mcp-core` to match the
|
|
14
|
+
reshuffled SolvaPay MCP package layout (framework-neutral contracts
|
|
15
|
+
now live in `@solvapay/mcp-core`; the official
|
|
16
|
+
`@modelcontextprotocol/sdk` adapter is `@solvapay/mcp`). No source
|
|
17
|
+
changes — this is a rename of the `peerDependencies` /
|
|
18
|
+
`peerDependenciesMeta` contract line only.
|
|
19
|
+
|
|
20
|
+
Integrators who install the optional peer explicitly:
|
|
21
|
+
|
|
22
|
+
```diff
|
|
23
|
+
- pnpm add @solvapay/mcp
|
|
24
|
+
+ pnpm add @solvapay/mcp-core
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Integrators who don't use `@solvapay/react/mcp` are unaffected.
|
|
28
|
+
|
|
29
|
+
### `@solvapay/react/mcp` — per-view primitives + `<McpApp>` compound (minor, additive)
|
|
30
|
+
|
|
31
|
+
The MCP App reference views (`checkout`, `account`, `topup`, `activate`) that
|
|
32
|
+
previously lived in `examples/mcp-checkout-app` have been lifted into
|
|
33
|
+
`@solvapay/react/mcp` as four composable primitives plus a thin compound
|
|
34
|
+
wrapper:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import '@solvapay/react/styles.css'
|
|
38
|
+
import '@solvapay/react/mcp/styles.css'
|
|
39
|
+
import { App } from '@modelcontextprotocol/ext-apps'
|
|
40
|
+
import { McpApp } from '@solvapay/react/mcp'
|
|
41
|
+
|
|
42
|
+
const app = new App({ name: 'my-mcp-app', version: '1.0.0' })
|
|
43
|
+
createRoot(rootEl).render(<McpApp app={app} />)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Integrators who want a custom shell compose the primitives directly:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import {
|
|
50
|
+
McpCheckoutView,
|
|
51
|
+
McpAccountView,
|
|
52
|
+
McpTopupView,
|
|
53
|
+
McpActivateView,
|
|
54
|
+
McpViewRouter,
|
|
55
|
+
fetchMcpBootstrap,
|
|
56
|
+
createMcpFetch,
|
|
57
|
+
createMcpAppAdapter,
|
|
58
|
+
useStripeProbe,
|
|
59
|
+
} from '@solvapay/react/mcp'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Each view accepts a `classNames?: McpViewClassNames` partial for per-slot
|
|
63
|
+
overrides; defaults render the `solvapay-mcp-*` classes from the new
|
|
64
|
+
`@solvapay/react/mcp/styles.css` stylesheet. `<McpApp>` also takes a `views`
|
|
65
|
+
map for per-screen component overrides without losing routing.
|
|
66
|
+
|
|
67
|
+
### Seam fixes on primitives that the MCP views needed
|
|
68
|
+
|
|
69
|
+
Three additive primitive changes landed alongside the lift:
|
|
70
|
+
|
|
71
|
+
- **`<AmountPicker.Root emit="minor">`** — when set, `onChange` and
|
|
72
|
+
`Confirm.onConfirm` deliver the amount in minor units (respects
|
|
73
|
+
zero-decimal currencies like JPY). Default stays `'major'` for
|
|
74
|
+
back-compat. `useAmountPicker().resolvedAmountMinor` is a new sibling to
|
|
75
|
+
`resolvedAmount` for custom layouts. A new
|
|
76
|
+
`getMinorUnitsPerMajor(currency)` util is exported from
|
|
77
|
+
`@solvapay/react` for integrators doing conversions outside the picker.
|
|
78
|
+
- **`<AmountPicker.Root selector={…}>`** — accepts an externally-owned
|
|
79
|
+
`UseTopupAmountSelectorReturn`, letting parent flows share state with
|
|
80
|
+
the inner picker. `ActivationFlow.AmountPicker` now threads the flow's
|
|
81
|
+
selector through this prop, so amounts picked in the sub-picker feed
|
|
82
|
+
straight into `useActivation().retry()` without the old workaround.
|
|
83
|
+
- **`<LaunchCustomerPortalButton asChild>`** — renders the ready-state
|
|
84
|
+
anchor via `Slot` so consumers can substitute a real `<button>` inside
|
|
85
|
+
an anchor wrapper (matches the `ActivationFlow.ActivateButton`
|
|
86
|
+
convention). Loading / error fallback buttons are untouched.
|
|
87
|
+
|
|
88
|
+
All three are additive — no consumer API moves or renames.
|
|
89
|
+
|
|
90
|
+
### Plans vs balance transactions (minor, behavioural filtering)
|
|
91
|
+
|
|
92
|
+
Credit top-ups now surface as balance transactions, not plans. `PurchaseInfo`
|
|
93
|
+
gains a `metadata?: Record<string, unknown>` field, and two new utilities —
|
|
94
|
+
`isPlanPurchase` / `isTopupPurchase` — classify structurally from
|
|
95
|
+
`planSnapshot`. The classification is applied inside `usePurchase()` so every
|
|
96
|
+
plan-shaped accessor is consistent:
|
|
97
|
+
|
|
98
|
+
- `activePurchase`, `activePaidPurchase`, `hasPaidPurchase`, `hasProduct`,
|
|
99
|
+
and `cancelledPurchase` / `shouldShowCancelledNotice` (on
|
|
100
|
+
`usePurchaseStatus`) all skip balance transactions.
|
|
101
|
+
- A new `balanceTransactions: PurchaseInfo[]` accessor on `usePurchase()`
|
|
102
|
+
returns the complement.
|
|
103
|
+
- `purchases` (raw) is unchanged — the full ordering is still available for
|
|
104
|
+
integrators that classify themselves.
|
|
105
|
+
|
|
106
|
+
`PurchaseInfo.planSnapshot.name` is now surfaced as a first-class field so
|
|
107
|
+
`<CurrentPlanCard>` renders a real plan name ("Pro Monthly") instead of the
|
|
108
|
+
opaque `planRef`. Legacy purchases without a snapshot name fall back to
|
|
109
|
+
`productName`. The `planRef` is retained only as `data-solvapay-current-plan-ref`
|
|
110
|
+
on the card root for QA hooks.
|
|
111
|
+
|
|
112
|
+
`<CurrentPlanCard>` also uses `copy.currentPlan.cycleUnit` to render
|
|
113
|
+
"500 kr / month" rather than "500 kr / monthly". Override any of
|
|
114
|
+
`weekly` / `monthly` / `quarterly` / `yearly` in your copy bundle to localise
|
|
115
|
+
the interval label.
|
|
116
|
+
|
|
117
|
+
Behavioural note for integrators who previously relied on top-ups surfacing on
|
|
118
|
+
`activePurchase`: drop to `purchases` (raw) to restore the old most-recent
|
|
119
|
+
ordering, or read from `balanceTransactions` directly.
|
|
120
|
+
|
|
121
|
+
### BREAKING: Unified `transport` replaces per-method provider overrides
|
|
122
|
+
|
|
123
|
+
`SolvaPayProvider` now takes a single `config.transport: SolvaPayTransport`
|
|
124
|
+
prop. The old per-method `SolvaPayProviderProps` overrides have been removed:
|
|
125
|
+
|
|
126
|
+
- `checkPurchase`
|
|
127
|
+
- `createPayment`
|
|
128
|
+
- `processPayment`
|
|
129
|
+
- `createTopupPayment`
|
|
130
|
+
|
|
131
|
+
Consumers passing any of those props must migrate to `config.transport`.
|
|
132
|
+
|
|
133
|
+
**Before:**
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
<SolvaPayProvider
|
|
137
|
+
checkPurchase={myCheckPurchase}
|
|
138
|
+
createPayment={myCreatePayment}
|
|
139
|
+
processPayment={myProcessPayment}
|
|
140
|
+
createTopupPayment={myCreateTopupPayment}
|
|
141
|
+
>
|
|
142
|
+
{children}
|
|
143
|
+
</SolvaPayProvider>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**After:**
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
const transport: SolvaPayTransport = {
|
|
150
|
+
checkPurchase: myCheckPurchase,
|
|
151
|
+
createPayment: myCreatePayment,
|
|
152
|
+
processPayment: myProcessPayment,
|
|
153
|
+
createTopupPayment: myCreateTopupPayment,
|
|
154
|
+
// ...plus every other required method; see types/transport.ts
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
<SolvaPayProvider config={{ transport }}>{children}</SolvaPayProvider>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
HTTP consumers who never set those overrides are unaffected — the provider
|
|
161
|
+
falls back to `createHttpTransport(config)` automatically.
|
|
162
|
+
|
|
163
|
+
### Added: `@solvapay/react/mcp` subpath
|
|
164
|
+
|
|
165
|
+
Ships `createMcpAppAdapter(app)` which returns a `SolvaPayTransport` that
|
|
166
|
+
tunnels every data call through `app.callServerTool` instead of HTTP. Use it
|
|
167
|
+
when hosting the React tree inside an MCP App, where direct HTTP to your
|
|
168
|
+
backend is blocked by the host sandbox:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import { createMcpAppAdapter } from '@solvapay/react/mcp'
|
|
172
|
+
<SolvaPayProvider config={{ transport: createMcpAppAdapter(app) }}>
|
|
173
|
+
{children}
|
|
174
|
+
</SolvaPayProvider>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
See the [MCP App integration guide](https://docs.solvapay.com/sdks/typescript/guides/mcp-app)
|
|
178
|
+
for the full walkthrough. Re-exports `MCP_TOOL_NAMES` so client and server
|
|
179
|
+
share a single source of truth for tool names.
|
|
180
|
+
|
|
181
|
+
### Added: account management components
|
|
182
|
+
|
|
183
|
+
- `<CurrentPlanCard>` — plan-type-aware summary card (recurring / one-time /
|
|
184
|
+
usage-based), payment-method display, Update card + Cancel plan actions.
|
|
185
|
+
Returns `null` when there is no active purchase.
|
|
186
|
+
- `<LaunchCustomerPortalButton>` — pre-fetches `createCustomerSession` on
|
|
187
|
+
mount and renders a real `<a target="_blank">` anchor (MCP sandbox-safe).
|
|
188
|
+
- `<UpdatePaymentMethodButton mode="portal">` — thin wrapper around
|
|
189
|
+
`<LaunchCustomerPortalButton>`. The `mode` prop reserves space for a
|
|
190
|
+
future `"inline"` value without breaking the API.
|
|
191
|
+
|
|
192
|
+
### Added: `usePaymentMethod` hook
|
|
193
|
+
|
|
194
|
+
Fetches the customer's default payment method through
|
|
195
|
+
`transport.getPaymentMethod()`. Transport-keyed single-flight cache, mirrors
|
|
196
|
+
the `useMerchant` pattern. Returns `null` on error (graceful hide, no
|
|
197
|
+
`onError` re-emit — the HTTP transport already invokes `config.onError`
|
|
198
|
+
before throwing).
|
|
199
|
+
|
|
200
|
+
### Fixed
|
|
201
|
+
|
|
202
|
+
- `SolvaPayProvider` no longer flips `loading: true` for polling refetches
|
|
203
|
+
when the customer has no purchases yet. `usePurchase` now exposes a
|
|
204
|
+
separate `isRefetching` flag for background polls; gate initial skeletons
|
|
205
|
+
on `loading` and render subtle refresh indicators on `isRefetching`.
|
|
206
|
+
- `LaunchCustomerPortalButton` captures `onError` via ref so parents passing
|
|
207
|
+
an inline arrow no longer re-fire the pre-fetch effect on every render.
|
|
208
|
+
- `useMerchant`, `useProduct`, and `usePaymentMethod` no longer double-call
|
|
209
|
+
`config.onError` — the HTTP transport already calls it before throwing.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Contributing to @solvapay/react
|
|
2
|
+
|
|
3
|
+
This package ships two tiers:
|
|
4
|
+
|
|
5
|
+
- **`@solvapay/react`** — default tree. Drop-in components (`CheckoutLayout`, `PaymentForm`, …) that render a golden-path UI. Internally, they are thin shims over the primitives.
|
|
6
|
+
- **`@solvapay/react/primitives`** — unstyled compound primitives. Consumers compose these to build fully custom UIs.
|
|
7
|
+
|
|
8
|
+
This file is the canonical contract for primitives until the cross-repo Mintlify docs land. Every primitive you add or edit MUST follow these rules.
|
|
9
|
+
|
|
10
|
+
## Primitive contract
|
|
11
|
+
|
|
12
|
+
### Compound API
|
|
13
|
+
|
|
14
|
+
Every primitive is a compound: a `Root` plus named subcomponents.
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
<PlanSelector.Root>
|
|
18
|
+
<PlanSelector.Heading />
|
|
19
|
+
<PlanSelector.Grid>
|
|
20
|
+
<PlanSelector.Card>
|
|
21
|
+
<PlanSelector.CardName />
|
|
22
|
+
<PlanSelector.CardPrice />
|
|
23
|
+
</PlanSelector.Card>
|
|
24
|
+
</PlanSelector.Grid>
|
|
25
|
+
</PlanSelector.Root>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Export subcomponents as properties on the `Root` (`PlanSelector.Card`) **and** as named exports from `./primitives` for tree-shake-friendly use.
|
|
29
|
+
- No render-prop children. No `classNames` prop. No `unstyled` flag.
|
|
30
|
+
|
|
31
|
+
### `asChild`
|
|
32
|
+
|
|
33
|
+
Every leaf subcomponent accepts `asChild?: boolean`. When `true`, it renders its single child via `<Slot>` and merges props/ref onto the child.
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<PlanSelector.Card asChild>
|
|
37
|
+
<Card>{/* shadcn/ui card */}</Card>
|
|
38
|
+
</PlanSelector.Card>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Use `Slot` from `./primitives/slot`. Refs are merged via `composeRefs`; event handlers are chained via `composeEventHandlers` (consumer runs first; `preventDefault()` skips the primitive handler).
|
|
42
|
+
|
|
43
|
+
### `data-state` vocabulary
|
|
44
|
+
|
|
45
|
+
Every stateful subcomponent emits a `data-state` attribute from a fixed, documented vocabulary. States are driven by context (`PlanSelectionContext`, `PaymentFormContext`), never by subcomponent-local state.
|
|
46
|
+
|
|
47
|
+
| Primitive | `data-state` values |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `PlanSelector.Card` | `idle` \| `selected` \| `current` \| `disabled` |
|
|
50
|
+
| `PaymentForm.SubmitButton` | `idle` \| `processing` \| `disabled` |
|
|
51
|
+
| `ActivationFlow.Root` | `summary` \| `activating` \| `selectAmount` \| `topupPayment` \| `retrying` \| `activated` \| `error` |
|
|
52
|
+
| `CreditGate.Root` | `allowed` \| `blocked` \| `loading` |
|
|
53
|
+
| `PurchaseGate.Root` | `allowed` \| `blocked` \| `loading` |
|
|
54
|
+
| `CancelledPlanNotice.Root` | `active` \| `expired` |
|
|
55
|
+
| `CancelPlanButton` | `idle` \| `cancelling` |
|
|
56
|
+
| `BalanceBadge` | `loading` \| `zero` \| `low` \| `ok` |
|
|
57
|
+
| `AmountPicker.Option` | `idle` \| `selected` \| `disabled` |
|
|
58
|
+
|
|
59
|
+
Secondary flags use `data-<flag>` (e.g. `data-free`, `data-popular`, `data-has-reason`).
|
|
60
|
+
|
|
61
|
+
### Opaque selectors
|
|
62
|
+
|
|
63
|
+
Every primitive root emits `data-solvapay-<primitive>` (and subcomponents emit `data-solvapay-<primitive>-<part>` when they need to be targetable). Do not rely on internal class names; those are not a public API.
|
|
64
|
+
|
|
65
|
+
### `.Loading` and `.Error`
|
|
66
|
+
|
|
67
|
+
Every async primitive exposes `.Loading` and `.Error` subcomponents that render when the context reports loading/error. They render `null` otherwise. Always provide a fallback UI path — don't rely on consumers remembering to add them.
|
|
68
|
+
|
|
69
|
+
### Errors self-heal
|
|
70
|
+
|
|
71
|
+
Throw structured errors from `src/utils/errors.ts` for wiring mistakes:
|
|
72
|
+
|
|
73
|
+
- `MissingProviderError` — primitive rendered outside `<SolvaPayProvider>`.
|
|
74
|
+
- `MissingEnvVarError` — required env var not set.
|
|
75
|
+
- `MissingApiRouteError` — backend route not installed.
|
|
76
|
+
- `MissingProductRefError` — primitive needs `productRef` and none was provided.
|
|
77
|
+
|
|
78
|
+
Each error includes `code`, `message` (fix + docs URL), and `docsUrl`.
|
|
79
|
+
|
|
80
|
+
## Prohibited patterns
|
|
81
|
+
|
|
82
|
+
When touching a primitive, these must stay gone:
|
|
83
|
+
|
|
84
|
+
- `classNames` prop, `unstyled` prop, `RenderArgs` / function-child overloads.
|
|
85
|
+
- Inline `style={{ ... }}` inside `src/primitives/**`.
|
|
86
|
+
- `next/*` imports (the package must bundle on Vite/Remix).
|
|
87
|
+
- `as any`, `as unknown as ...` except when unavoidable; justify with a comment.
|
|
88
|
+
- Implicit `enum`; use union types.
|
|
89
|
+
|
|
90
|
+
## TDD checklist per primitive
|
|
91
|
+
|
|
92
|
+
Write the primitive and its test file in the same commit. Every primitive test covers:
|
|
93
|
+
|
|
94
|
+
1. **Default render** — subcomponents render the expected DOM.
|
|
95
|
+
2. **`asChild` composition** — refs merge, handlers chain, `data-*` + `aria-*` forward to the child element.
|
|
96
|
+
3. **`data-state` transitions** — context-driven state flips the attribute correctly.
|
|
97
|
+
4. **`.Loading` / `.Error`** — rendered when context signals loading/error.
|
|
98
|
+
5. **Provider-missing + env-missing** — the correct structured error class is thrown with its docs URL.
|
|
99
|
+
|
|
100
|
+
Delete legacy tests that assert on `classNames` / function-child / `RenderArgs` **before** landing the rewrite.
|
|
101
|
+
|
|
102
|
+
## Adding a new primitive (checklist)
|
|
103
|
+
|
|
104
|
+
1. Write the test file following the TDD checklist above.
|
|
105
|
+
2. Create `src/primitives/<Name>.tsx` with `Root` + subcomponents + `asChild` + `data-state`.
|
|
106
|
+
3. Re-export from `src/primitives/index.ts`.
|
|
107
|
+
4. If the primitive is part of the default tree, update the shim in `src/components/<Name>.tsx` to render it with the golden-path children.
|
|
108
|
+
5. Update the `data-state` table in this file if you introduce a new state.
|
|
109
|
+
6. Keep the package-local README cheat sheet in sync.
|
|
110
|
+
|
|
111
|
+
## Commands
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pnpm --filter @solvapay/react test # run the primitive + component tests
|
|
115
|
+
pnpm --filter @solvapay/react build # tsup build (top-level + primitives entry)
|
|
116
|
+
pnpm --filter @solvapay/react lint # eslint
|
|
117
|
+
```
|