@solvapay/server 1.0.0-preview.2 → 1.0.0-preview.21
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/LICENSE.md +21 -0
- package/README.md +97 -32
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/edge.d.ts +2723 -287
- package/dist/edge.js +1192 -251
- package/dist/{esm-5GYCIXIY.js → esm-UW7WCMEK.js} +1 -1
- package/dist/index.cjs +1269 -246
- package/dist/index.d.cts +2793 -287
- package/dist/index.d.ts +2793 -287
- package/dist/index.js +1255 -251
- package/package.json +16 -6
- package/dist/chunk-R5U7XKVJ.js +0 -16
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 SolvaPay 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
CHANGED
|
@@ -5,6 +5,7 @@ Universal server SDK for Node.js and edge runtimes. Includes API client, paywall
|
|
|
5
5
|
**Works in**: Node.js, Vercel Edge Functions, Cloudflare Workers, Deno, Supabase Edge Functions, and more.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
|
+
|
|
8
9
|
```bash
|
|
9
10
|
pnpm add @solvapay/server
|
|
10
11
|
```
|
|
@@ -16,39 +17,39 @@ pnpm add @solvapay/server
|
|
|
16
17
|
The same imports work in **Node.js and edge runtimes**. The correct implementation is automatically selected:
|
|
17
18
|
|
|
18
19
|
```ts
|
|
19
|
-
import { createSolvaPayClient, verifyWebhook } from '@solvapay/server'
|
|
20
|
+
import { createSolvaPayClient, verifyWebhook } from '@solvapay/server'
|
|
20
21
|
|
|
21
22
|
// Works in Node.js, Edge Functions, Cloudflare Workers, Deno, etc.
|
|
22
|
-
const apiClient = createSolvaPayClient({
|
|
23
|
-
apiKey: process.env.SOLVAPAY_SECRET_KEY
|
|
24
|
-
})
|
|
23
|
+
const apiClient = createSolvaPayClient({
|
|
24
|
+
apiKey: process.env.SOLVAPAY_SECRET_KEY!,
|
|
25
|
+
})
|
|
25
26
|
|
|
26
27
|
// Auto-selects Node crypto or Web Crypto based on runtime
|
|
27
|
-
const event = await verifyWebhook({
|
|
28
|
-
body,
|
|
29
|
-
signature,
|
|
30
|
-
secret: process.env.SOLVAPAY_WEBHOOK_SECRET
|
|
31
|
-
})
|
|
28
|
+
const event = await verifyWebhook({
|
|
29
|
+
body,
|
|
30
|
+
signature,
|
|
31
|
+
secret: process.env.SOLVAPAY_WEBHOOK_SECRET!,
|
|
32
|
+
})
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
**Edge Runtime Examples:**
|
|
35
36
|
|
|
36
37
|
```ts
|
|
37
38
|
// Supabase Edge Function
|
|
38
|
-
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
|
|
39
|
-
import { createSolvaPayClient, verifyWebhook } from 'https://esm.sh/@solvapay/server@latest'
|
|
39
|
+
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
|
|
40
|
+
import { createSolvaPayClient, verifyWebhook } from 'https://esm.sh/@solvapay/server@latest'
|
|
40
41
|
|
|
41
42
|
const solvapay = createSolvaPayClient({
|
|
42
43
|
apiKey: Deno.env.get('SOLVAPAY_SECRET_KEY')!,
|
|
43
|
-
})
|
|
44
|
+
})
|
|
44
45
|
|
|
45
46
|
// Vercel Edge Function
|
|
46
|
-
import { createSolvaPayClient } from '@solvapay/server'
|
|
47
|
+
import { createSolvaPayClient } from '@solvapay/server'
|
|
47
48
|
|
|
48
|
-
export const runtime = 'edge'
|
|
49
|
+
export const runtime = 'edge'
|
|
49
50
|
const solvapay = createSolvaPayClient({
|
|
50
51
|
apiKey: process.env.SOLVAPAY_SECRET_KEY!,
|
|
51
|
-
})
|
|
52
|
+
})
|
|
52
53
|
```
|
|
53
54
|
|
|
54
55
|
### Paywall Protection
|
|
@@ -59,12 +60,12 @@ Use the unified payable API to protect your endpoints and functions with usage l
|
|
|
59
60
|
import { createSolvaPay } from '@solvapay/server';
|
|
60
61
|
|
|
61
62
|
// Create SolvaPay instance with your API key
|
|
62
|
-
const solvaPay = createSolvaPay({
|
|
63
|
-
apiKey: process.env.SOLVAPAY_SECRET_KEY!
|
|
63
|
+
const solvaPay = createSolvaPay({
|
|
64
|
+
apiKey: process.env.SOLVAPAY_SECRET_KEY!
|
|
64
65
|
});
|
|
65
66
|
|
|
66
|
-
// Create a payable with your
|
|
67
|
-
const payable = solvaPay.payable({
|
|
67
|
+
// Create a payable with your product configuration
|
|
68
|
+
const payable = solvaPay.payable({ product: 'my-product' });
|
|
68
69
|
|
|
69
70
|
// Use the appropriate adapter for your context:
|
|
70
71
|
|
|
@@ -88,11 +89,67 @@ const protectedHandler = await payable.function(async (args) => {
|
|
|
88
89
|
return { result: 'success' };
|
|
89
90
|
});
|
|
90
91
|
|
|
91
|
-
const result = await protectedHandler({
|
|
92
|
-
auth: { customer_ref: 'customer_123' }
|
|
92
|
+
const result = await protectedHandler({
|
|
93
|
+
auth: { customer_ref: 'customer_123' }
|
|
93
94
|
});
|
|
94
95
|
```
|
|
95
96
|
|
|
97
|
+
### Authentication Integration
|
|
98
|
+
|
|
99
|
+
You can integrate authentication adapters from `@solvapay/auth` with the `getCustomerRef` option:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { createSolvaPay } from '@solvapay/server'
|
|
103
|
+
import { SupabaseAuthAdapter } from '@solvapay/auth/supabase'
|
|
104
|
+
|
|
105
|
+
const auth = new SupabaseAuthAdapter({
|
|
106
|
+
jwtSecret: process.env.SUPABASE_JWT_SECRET!,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const solvaPay = createSolvaPay({ apiKey: process.env.SOLVAPAY_SECRET_KEY! })
|
|
110
|
+
|
|
111
|
+
// Use with Next.js adapter
|
|
112
|
+
export const POST = solvaPay.payable({ product: 'my-api' }).next(
|
|
113
|
+
async args => {
|
|
114
|
+
return { result: 'success' }
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
getCustomerRef: async req => {
|
|
118
|
+
const userId = await auth.getUserIdFromRequest(req)
|
|
119
|
+
return userId ?? 'anonymous'
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
This automatically extracts the user ID from authentication tokens and uses it as the customer reference for paywall checks.
|
|
126
|
+
|
|
127
|
+
For MCP bearer-token flows, the SDK also exports helper utilities:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import {
|
|
131
|
+
getCustomerRefFromBearerAuthHeader,
|
|
132
|
+
McpBearerAuthError,
|
|
133
|
+
} from '@solvapay/server'
|
|
134
|
+
|
|
135
|
+
const handler = solvaPay.payable({ product: 'my-api' }).mcp(
|
|
136
|
+
async args => ({ ok: true }),
|
|
137
|
+
{
|
|
138
|
+
getCustomerRef: args => {
|
|
139
|
+
try {
|
|
140
|
+
return getCustomerRefFromBearerAuthHeader(args._authHeader as string | undefined)
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error instanceof McpBearerAuthError) return 'anonymous'
|
|
143
|
+
throw error
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`payable({ getCustomerRef })` is now supported as a default extractor across adapters. Adapter-level
|
|
151
|
+
`getCustomerRef` still takes precedence when both are provided.
|
|
152
|
+
|
|
96
153
|
### When to Use Each Adapter
|
|
97
154
|
|
|
98
155
|
Choose the adapter based on your context:
|
|
@@ -145,18 +202,20 @@ This will fetch the OpenAPI spec from `http://localhost:3001/v1/openapi.json` an
|
|
|
145
202
|
### Using Generated Types
|
|
146
203
|
|
|
147
204
|
```typescript
|
|
148
|
-
import type { paths, components } from './types/generated'
|
|
205
|
+
import type { paths, components } from './types/generated'
|
|
149
206
|
|
|
150
207
|
// Use path operation types
|
|
151
|
-
type CheckLimitsRequest =
|
|
152
|
-
|
|
208
|
+
type CheckLimitsRequest =
|
|
209
|
+
paths['/v1/sdk/limits']['post']['requestBody']['content']['application/json']
|
|
210
|
+
type CheckLimitsResponse =
|
|
211
|
+
paths['/v1/sdk/limits']['post']['responses']['200']['content']['application/json']
|
|
153
212
|
|
|
154
213
|
// Use component schemas
|
|
155
|
-
type Agent = components['schemas']['Agent']
|
|
156
|
-
type Plan = components['schemas']['Plan']
|
|
214
|
+
type Agent = components['schemas']['Agent']
|
|
215
|
+
type Plan = components['schemas']['Plan']
|
|
157
216
|
```
|
|
158
217
|
|
|
159
|
-
**Note:** The generated types complement the existing hand-written types in `src/types.ts`. Run `pnpm generate:types` whenever the backend API changes to keep types in sync.
|
|
218
|
+
**Note:** The generated types complement the existing hand-written types in `src/types/client.ts`. Run `pnpm generate:types` whenever the backend API changes to keep types in sync.
|
|
160
219
|
|
|
161
220
|
## Testing
|
|
162
221
|
|
|
@@ -183,18 +242,20 @@ pnpm test:watch
|
|
|
183
242
|
|
|
184
243
|
### Unit Tests
|
|
185
244
|
|
|
186
|
-
Unit tests (`__tests__/paywall.test.ts`) use a mock API client and test:
|
|
245
|
+
Unit tests (`__tests__/paywall.unit.test.ts`, `__tests__/mcp-auth.unit.test.ts`) use a mock API client and test:
|
|
246
|
+
|
|
187
247
|
- Paywall protection logic
|
|
188
248
|
- Handler creation (HTTP, Next.js, MCP)
|
|
189
249
|
- Error handling
|
|
190
250
|
- Authentication flows
|
|
191
|
-
-
|
|
251
|
+
- Product resolution
|
|
192
252
|
|
|
193
253
|
**No backend required** - runs fast and deterministically.
|
|
194
254
|
|
|
195
255
|
### Integration Tests
|
|
196
256
|
|
|
197
257
|
Integration tests (`__tests__/backend.integration.test.ts`) connect to a real SolvaPay backend and test:
|
|
258
|
+
|
|
198
259
|
- SDK API methods with real responses
|
|
199
260
|
- Actual limit enforcement
|
|
200
261
|
- Real usage tracking
|
|
@@ -221,6 +282,7 @@ USE_REAL_BACKEND=true SOLVAPAY_SECRET_KEY=your_key pnpm test:integration
|
|
|
221
282
|
### Payment Integration Tests (Stripe)
|
|
222
283
|
|
|
223
284
|
Payment tests (`__tests__/payment-stripe.integration.test.ts`) verify the complete payment flow with Stripe:
|
|
285
|
+
|
|
224
286
|
- Creating payment intents
|
|
225
287
|
- Confirming payments with test cards
|
|
226
288
|
- Webhook processing (optional)
|
|
@@ -240,24 +302,27 @@ export SOLVAPAY_API_BASE_URL=http://localhost:3001
|
|
|
240
302
|
The E2E webhook test is skipped by default because it requires Stripe webhooks to be forwarded to your local backend. To enable webhook testing:
|
|
241
303
|
|
|
242
304
|
1. **Install Stripe CLI:**
|
|
305
|
+
|
|
243
306
|
```bash
|
|
244
307
|
# macOS
|
|
245
308
|
brew install stripe/stripe-cli/stripe
|
|
246
|
-
|
|
309
|
+
|
|
247
310
|
# Linux / Windows - see https://stripe.com/docs/stripe-cli
|
|
248
311
|
```
|
|
249
312
|
|
|
250
313
|
2. **Login to Stripe:**
|
|
314
|
+
|
|
251
315
|
```bash
|
|
252
316
|
stripe login
|
|
253
317
|
```
|
|
254
318
|
|
|
255
319
|
3. **Forward webhooks to your local backend:**
|
|
320
|
+
|
|
256
321
|
```bash
|
|
257
322
|
# Terminal 1: Start your backend
|
|
258
323
|
cd path/to/solvapay-backend
|
|
259
324
|
pnpm dev
|
|
260
|
-
|
|
325
|
+
|
|
261
326
|
# Terminal 2: Forward Stripe webhooks
|
|
262
327
|
stripe listen --forward-to localhost:3001/webhooks/stripe
|
|
263
328
|
```
|
|
@@ -324,4 +389,4 @@ By default, both are **disabled** to keep test output clean and readable. Enable
|
|
|
324
389
|
run: pnpm test:integration
|
|
325
390
|
```
|
|
326
391
|
|
|
327
|
-
More: docs/architecture.md
|
|
392
|
+
More: [docs/guides/architecture.md](../../docs/guides/architecture.md)
|