@monetize.software/sdk-react 3.0.0-alpha.4 → 3.0.0-alpha.5
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/README.md +65 -38
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
# @monetize.software/sdk-react
|
|
2
2
|
|
|
3
|
-
React bindings
|
|
3
|
+
React bindings for [`@monetize.software/sdk`](../sdk) — Provider, hooks and
|
|
4
|
+
declarative paywall components. Works with the web SDK and the extension SDK
|
|
5
|
+
(any drop-in-compatible `PaywallUI`).
|
|
4
6
|
|
|
5
|
-
- **Bundle**: < 2 KB gzip (
|
|
6
|
-
- **React**: >= 18,
|
|
7
|
-
- **SSR**:
|
|
8
|
-
|
|
7
|
+
- **Bundle**: < 2 KB gzip (bindings only — the UI lives inside the SDK).
|
|
8
|
+
- **React**: >= 18, uses `useSyncExternalStore` for concurrent-safe snapshot reads.
|
|
9
|
+
- **SSR**: safe out of the box. On the server, hooks return `null` /
|
|
10
|
+
`{ status: 'loading' }`; the `PaywallUI` instance is created only on the client.
|
|
11
|
+
- **TypeScript**: full type-level contract ([`src/contract.ts`](src/contract.ts)) —
|
|
12
|
+
if the public surface of the SDK shifts, the `sdk-react` build fails at `tsc`.
|
|
9
13
|
|
|
10
|
-
##
|
|
14
|
+
## Installation
|
|
11
15
|
|
|
12
16
|
```bash
|
|
13
17
|
pnpm add @monetize.software/sdk-react @monetize.software/sdk react
|
|
@@ -25,7 +29,13 @@ import {
|
|
|
25
29
|
|
|
26
30
|
function App() {
|
|
27
31
|
return (
|
|
28
|
-
<PaywallProvider
|
|
32
|
+
<PaywallProvider
|
|
33
|
+
options={{
|
|
34
|
+
paywallId: 'YOUR_ID',
|
|
35
|
+
apiOrigin: 'https://your-paywall-domain.com',
|
|
36
|
+
auth: true
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
29
39
|
<PaywallGate fallback={<UpgradeCTA />}>
|
|
30
40
|
<PremiumFeature />
|
|
31
41
|
</PaywallGate>
|
|
@@ -37,53 +47,59 @@ function App() {
|
|
|
37
47
|
|
|
38
48
|
function UpgradeCTA() {
|
|
39
49
|
const user = usePaywallUser();
|
|
40
|
-
return <p
|
|
50
|
+
return <p>Hi, {user?.email ?? 'guest'}! Unlock full access.</p>;
|
|
41
51
|
}
|
|
42
52
|
```
|
|
43
53
|
|
|
54
|
+
`apiOrigin` must match the `custom_domain` configured for your paywall in the
|
|
55
|
+
platform.
|
|
56
|
+
|
|
44
57
|
## Provider
|
|
45
58
|
|
|
46
|
-
`<PaywallProvider>`
|
|
59
|
+
`<PaywallProvider>` accepts one of two props:
|
|
47
60
|
|
|
48
61
|
```tsx
|
|
49
|
-
//
|
|
62
|
+
// Option 1 — Provider creates the instance itself
|
|
50
63
|
<PaywallProvider options={{ paywallId, apiOrigin, auth: true }}>
|
|
51
64
|
|
|
52
|
-
//
|
|
65
|
+
// Option 2 — host supplies a ready instance (extension / shared singleton / tests)
|
|
53
66
|
import { createPaywallUI } from '@monetize.software/sdk-extension';
|
|
54
|
-
const paywall = createPaywallUI({ paywallId });
|
|
67
|
+
const paywall = createPaywallUI({ paywallId, apiOrigin });
|
|
55
68
|
|
|
56
69
|
<PaywallProvider instance={paywall}>
|
|
57
70
|
```
|
|
58
71
|
|
|
59
|
-
|
|
72
|
+
If `paywallId` changes dynamically, remount the Provider via
|
|
73
|
+
`<PaywallProvider key={paywallId} options={...}>` — reactive option rebuilds are
|
|
74
|
+
intentionally not performed.
|
|
60
75
|
|
|
61
|
-
##
|
|
76
|
+
## Hooks
|
|
62
77
|
|
|
63
|
-
|
|
|
78
|
+
| Hook | Returns | When it triggers a rerender |
|
|
64
79
|
|---|---|---|
|
|
65
|
-
| `usePaywall()` | `PaywallUI \| null` |
|
|
66
|
-
| `usePaywallState()` | `{ open, view, error }` |
|
|
67
|
-
| `usePaywallUser()` | `PaywallUser \| null` |
|
|
80
|
+
| `usePaywall()` | `PaywallUI \| null` | instance change (rare) |
|
|
81
|
+
| `usePaywallState()` | `{ open, view, error }` | any state-machine change |
|
|
82
|
+
| `usePaywallUser()` | `PaywallUser \| null` | `userChange` event |
|
|
68
83
|
| `usePaywallAccess(opts?)` | `{ status, result }` | `userChange` / `purchase_completed` |
|
|
69
84
|
| `usePaywallPrices()` | `{ prices, loading, error }` | bootstrap refresh |
|
|
70
85
|
| `usePaywallTrial()` | `TrialStatus \| null` | `trial_blocked` / `trial_expired` |
|
|
71
86
|
| `usePaywallVisibility()` | `VisibilityStatus \| null` | `ready` / `visibility_blocked` |
|
|
72
|
-
| `usePaywallEvent(event, handler)` | — |
|
|
87
|
+
| `usePaywallEvent(event, handler)` | — | subscribes with a stable handler ref |
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
All hooks are safe before the Provider mounts (they return `null` / loading) —
|
|
90
|
+
you can use them in SSR without `'use client'` wrappers on the consuming subtree.
|
|
75
91
|
|
|
76
|
-
##
|
|
92
|
+
## Components
|
|
77
93
|
|
|
78
94
|
### `<PaywallGate>`
|
|
79
95
|
|
|
80
|
-
|
|
96
|
+
Declarative gate: loading → fallback → children.
|
|
81
97
|
|
|
82
98
|
```tsx
|
|
83
99
|
<PaywallGate
|
|
84
100
|
loading={<Skeleton />}
|
|
85
101
|
fallback={({ open }) => <button onClick={open}>Upgrade</button>}
|
|
86
|
-
openOnBlocked={false} //
|
|
102
|
+
openOnBlocked={false} // if true — calls paywall.open() automatically
|
|
87
103
|
>
|
|
88
104
|
<PremiumFeature />
|
|
89
105
|
</PaywallGate>
|
|
@@ -91,7 +107,9 @@ const paywall = createPaywallUI({ paywallId });
|
|
|
91
107
|
|
|
92
108
|
### `<PaywallButton>` / `<PaywallSupportButton>`
|
|
93
109
|
|
|
94
|
-
|
|
110
|
+
Sugar over `paywall.open()`. By default renders a native `<button>` with all
|
|
111
|
+
your `className`/`disabled`/`aria-*` props forwarded. For a custom element use
|
|
112
|
+
the render prop:
|
|
95
113
|
|
|
96
114
|
```tsx
|
|
97
115
|
<PaywallButton render={({ open, ready }) => (
|
|
@@ -99,7 +117,7 @@ const paywall = createPaywallUI({ paywallId });
|
|
|
99
117
|
)} />
|
|
100
118
|
```
|
|
101
119
|
|
|
102
|
-
`mode`
|
|
120
|
+
`mode` switches between `open()` / `openSupport()` / `openAuth()` / `openAnonGate()`:
|
|
103
121
|
|
|
104
122
|
```tsx
|
|
105
123
|
<PaywallButton mode="support">Need help?</PaywallButton>
|
|
@@ -109,48 +127,57 @@ const paywall = createPaywallUI({ paywallId });
|
|
|
109
127
|
## SSR / Next.js
|
|
110
128
|
|
|
111
129
|
```tsx
|
|
112
|
-
'use client'; //
|
|
130
|
+
'use client'; // on the Provider, not on the consumer subtree
|
|
113
131
|
|
|
114
132
|
import { PaywallProvider } from '@monetize.software/sdk-react';
|
|
115
133
|
|
|
116
134
|
export function PaywallProviders({ children }) {
|
|
117
135
|
return (
|
|
118
|
-
<PaywallProvider
|
|
136
|
+
<PaywallProvider
|
|
137
|
+
options={{
|
|
138
|
+
paywallId: process.env.NEXT_PUBLIC_PAYWALL_ID!,
|
|
139
|
+
apiOrigin: process.env.NEXT_PUBLIC_PAYWALL_ORIGIN!
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
119
142
|
{children}
|
|
120
143
|
</PaywallProvider>
|
|
121
144
|
);
|
|
122
145
|
}
|
|
123
146
|
```
|
|
124
147
|
|
|
125
|
-
|
|
148
|
+
Hooks can be called from server components in typed-null scenarios (they'll
|
|
149
|
+
return `null` / loading anyway). The recommendation is to keep hook logic in a
|
|
150
|
+
client component.
|
|
126
151
|
|
|
127
|
-
##
|
|
152
|
+
## SDK contract guard
|
|
128
153
|
|
|
129
|
-
`pnpm typecheck`
|
|
154
|
+
`pnpm typecheck` validates [`src/contract.ts`](src/contract.ts) — it lists every
|
|
155
|
+
point of contact with the public SDK API (`PaywallUI` methods, snapshot fields,
|
|
156
|
+
event names). Any drift in `../sdk` is caught here before it hits production.
|
|
130
157
|
|
|
131
|
-
|
|
158
|
+
After SDK changes, refresh the dist for type resolution:
|
|
132
159
|
|
|
133
160
|
```bash
|
|
134
161
|
cd ../sdk && pnpm build
|
|
135
162
|
cd ../sdk-react && pnpm typecheck
|
|
136
163
|
```
|
|
137
164
|
|
|
138
|
-
##
|
|
165
|
+
## Development
|
|
139
166
|
|
|
140
167
|
```bash
|
|
141
168
|
pnpm install
|
|
142
169
|
pnpm dev # → http://localhost:5080/demo/
|
|
143
|
-
pnpm typecheck # TS
|
|
170
|
+
pnpm typecheck # TS validation + contract guard
|
|
144
171
|
pnpm test # vitest + @testing-library/react
|
|
145
|
-
pnpm test:e2e # playwright
|
|
172
|
+
pnpm test:e2e # playwright against the demo
|
|
146
173
|
pnpm build # ESM + CJS + d.ts → dist/
|
|
147
174
|
```
|
|
148
175
|
|
|
149
176
|
## API reference
|
|
150
177
|
|
|
151
|
-
|
|
178
|
+
Full JSDoc comments on every public export are inline in the sources:
|
|
152
179
|
|
|
153
180
|
- [`src/PaywallProvider.tsx`](src/PaywallProvider.tsx) — Provider, lifecycle
|
|
154
|
-
- [`src/hooks/`](src/hooks/) —
|
|
155
|
-
- [`src/components/`](src/components/) —
|
|
156
|
-
- [`src/contract.ts`](src/contract.ts) —
|
|
181
|
+
- [`src/hooks/`](src/hooks/) — all hooks
|
|
182
|
+
- [`src/components/`](src/components/) — declarative components
|
|
183
|
+
- [`src/contract.ts`](src/contract.ts) — SDK contact points
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monetize.software/sdk-react",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.5",
|
|
4
4
|
"description": "React bindings for @monetize.software/sdk — Provider, hooks and declarative components. Works with the web SDK and the extension SDK (any drop-in compatible PaywallUI).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": ">=18",
|
|
29
|
-
"@monetize.software/sdk": "3.0.0-alpha.
|
|
29
|
+
"@monetize.software/sdk": "3.0.0-alpha.7"
|
|
30
30
|
},
|
|
31
31
|
"peerDependenciesMeta": {
|
|
32
32
|
"@monetize.software/sdk": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"vite": "^6.0.5",
|
|
49
49
|
"vite-plugin-dts": "^4.3.0",
|
|
50
50
|
"vitest": "^2.1.8",
|
|
51
|
-
"@monetize.software/sdk": "3.0.0-alpha.
|
|
51
|
+
"@monetize.software/sdk": "3.0.0-alpha.7"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"dev": "vite",
|