@relipay/node 0.1.0-beta.0
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/AGENTS.md +106 -0
- package/README.md +49 -0
- package/dist/index.d.ts +677 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +681 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# AGENTS.md — @relipay/node
|
|
2
|
+
|
|
3
|
+
You are an AI agent looking at `@relipay/node`. This file tells you how to use it correctly on the first try.
|
|
4
|
+
|
|
5
|
+
## When to use this package
|
|
6
|
+
|
|
7
|
+
The user wants to add **auth, billing, or both** to a server-side TypeScript project (Express, Fastify, Nest, Hono, raw Node, Bun, Deno). Strong signals:
|
|
8
|
+
|
|
9
|
+
- They asked to add login / signup / sessions, and the project doesn't already have a working auth solution.
|
|
10
|
+
- They asked to add Stripe / PayPal / subscriptions / checkout / a billing flow.
|
|
11
|
+
- They say "Clerk", "Auth0", "Supabase Auth", "Stripe Checkout" — and they want a self-hostable alternative.
|
|
12
|
+
- They have a hand-rolled `users` table, `password_hash` column, and bespoke session middleware. ReliPay replaces this.
|
|
13
|
+
|
|
14
|
+
**Do NOT use this package** when:
|
|
15
|
+
|
|
16
|
+
- They want auth in the *browser*. Reach for `@relipay/react` (or `@relipay/nextjs`) instead — never call ReliPay with a secret key from browser code.
|
|
17
|
+
- They're building the ReliPay server itself. This SDK calls ReliPay; it's not the implementation.
|
|
18
|
+
|
|
19
|
+
## Five-line happy path
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { ReliPay } from '@relipay/node';
|
|
23
|
+
|
|
24
|
+
const relipay = new ReliPay({
|
|
25
|
+
apiUrl: process.env.RELIPAY_URL!,
|
|
26
|
+
secretKey: process.env.RELIPAY_SECRET!, // rp_live_… or rp_test_…
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Smoke test: verifies the credentials and returns the Application DTO.
|
|
30
|
+
const me = await relipay.applications.me();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
That's it for setup. Everything else hangs off `relipay.applications.*`, `relipay.auth.*`, and `relipay.billing.*`.
|
|
34
|
+
|
|
35
|
+
`applications.me()` is the canonical "did my setup work?" call — if it throws `RelipayError` with `code: "API_KEY_INVALID"`, the secret key is wrong/revoked/expired. If it throws with `code: "CONFIG_INVALID_SECRET_KEY"`, the constructor caught a bad `secretKey` arg before any network call.
|
|
36
|
+
|
|
37
|
+
## Required env vars
|
|
38
|
+
|
|
39
|
+
| Name | Example | Where to get it |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `RELIPAY_URL` | `https://relipay.example.com` or `http://localhost:3030` | Their ReliPay deployment |
|
|
42
|
+
| `RELIPAY_SECRET` | `rp_live_abc123…` | Panel → Application → API Keys |
|
|
43
|
+
| `RELIPAY_PUBLIC` | `rp_pub_myapp_xyz…` | Panel → Application (browser-safe; only needed if also using `@relipay/react`) |
|
|
44
|
+
|
|
45
|
+
Never hardcode any of these. Always read from `process.env`.
|
|
46
|
+
|
|
47
|
+
## What you should always do
|
|
48
|
+
|
|
49
|
+
1. **One client per Application.** Don't construct `new ReliPay()` per request — make it a module-level singleton.
|
|
50
|
+
2. **Catch `RelipayError`** and surface `error.fix` to the user when debugging. The `fix` field is the single most useful piece of information.
|
|
51
|
+
3. **Never log `secretKey`.** Treat it like a database password.
|
|
52
|
+
4. **Use the typed methods.** Don't call `.request()` directly — that's the escape hatch, not the API.
|
|
53
|
+
|
|
54
|
+
## What you should never do
|
|
55
|
+
|
|
56
|
+
- Don't `npm install stripe` or `@paypal/checkout-server-sdk` alongside `@relipay/node`. ReliPay handles provider integration; calling provider SDKs in parallel will desync your data.
|
|
57
|
+
- Don't store user passwords in your own DB. ReliPay's API owns the password hash.
|
|
58
|
+
- Don't write your own session middleware. Use `relipay.auth.verifySession(token)` (lands in Phase 1).
|
|
59
|
+
- Don't proxy ReliPay calls through your frontend with the secret key. Browser → your backend → ReliPay.
|
|
60
|
+
|
|
61
|
+
## Errors that teach
|
|
62
|
+
|
|
63
|
+
Every error from this SDK is a `RelipayError` with `code`, `message`, `fix`, and optionally `docs`. Examples:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
code: PLAN_NOT_FOUND
|
|
67
|
+
message: Plan "pro_monthly" not found in application "myapp-prod".
|
|
68
|
+
fix: Run `relipay plans list` to see available plans, or create one in the panel.
|
|
69
|
+
docs: https://relipay.dev/errors/PLAN_NOT_FOUND
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
When the user reports an error, **read `error.fix` first** — it tells you what to do. Don't guess.
|
|
73
|
+
|
|
74
|
+
## Status
|
|
75
|
+
|
|
76
|
+
Phase 1.1 — end-user auth works end-to-end. Public surface today:
|
|
77
|
+
|
|
78
|
+
| Method | Status |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `relipay.applications.me()` | ✅ Working |
|
|
81
|
+
| `relipay.auth.signUp({ email, password, metadata? })` | ✅ Working — returns `{ accessToken, refreshToken, ... }` |
|
|
82
|
+
| `relipay.auth.signIn({ email, password })` | ✅ Working — returns `{ accessToken, refreshToken, ... }` |
|
|
83
|
+
| `relipay.auth.refresh(refreshToken)` | ✅ Working — single-use, returns new pair |
|
|
84
|
+
| `relipay.auth.signOut(refreshToken)` | ✅ Working — idempotent |
|
|
85
|
+
| `relipay.auth.signOutEverywhere(accessToken)` | ✅ Working — revokes all refresh tokens for the user |
|
|
86
|
+
| `relipay.auth.getCurrentUser(accessToken)` | ✅ Working |
|
|
87
|
+
| `relipay.auth.requestPasswordReset({ email })` | ✅ Working — never enumerates; **you email** the returned `resetToken` |
|
|
88
|
+
| `relipay.auth.resetPassword({ token, newPassword })` | ✅ Working — single-use, kills all sessions on success |
|
|
89
|
+
| `relipay.auth.changePassword(accessToken, { currentPassword, newPassword })` | ✅ Working — kills other sessions |
|
|
90
|
+
| `relipay.billing.getPlans()` | ✅ Working |
|
|
91
|
+
| `relipay.billing.getSubscription(accessToken)` | ✅ Working — returns `null` when none |
|
|
92
|
+
| `relipay.billing.createCheckout(accessToken, { planSlug, successUrl, cancelUrl, couponCode? })` | ⚠️ Stub provider for outbound URL — webhook handling is real. Returns a real local PENDING Subscription + deterministic stub URL + `discountAmount`. |
|
|
93
|
+
| `relipay.billing.validateCoupon(accessToken, { code, planSlug })` | ✅ Working — surfaces precise `COUPON_*` errors. |
|
|
94
|
+
|
|
95
|
+
Don't invent imports for methods that don't exist. If you can't find a method via TypeScript autocomplete on `relipay.applications.`, `relipay.auth.`, or `relipay.billing.`, it isn't there yet.
|
|
96
|
+
|
|
97
|
+
## Two-credential model (read this once)
|
|
98
|
+
|
|
99
|
+
Per-user calls require **two** credentials together:
|
|
100
|
+
|
|
101
|
+
1. The **Application secret key** (`rp_live_…`) — proves *which Application* is calling. Goes in `Authorization: Bearer …` automatically; you set it once at construction.
|
|
102
|
+
2. The **user JWT** — proves *which end-user* this call is acting on behalf of. Returned from `signUp` / `signIn`. You pass it as the argument to `getCurrentUser(token)`; the SDK puts it in `X-Relipay-User-Token`.
|
|
103
|
+
|
|
104
|
+
The server enforces a **cross-application guard**: if a JWT was issued by Application A, presenting it through Application B's secret key returns `USER_TOKEN_WRONG_APPLICATION` (401). This is by design. Don't try to "share users across apps" by re-signing tokens — those are deliberately different users.
|
|
105
|
+
|
|
106
|
+
See [`docs/auth.md`](../../docs/auth.md) for the full flow diagram.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @relipay/node
|
|
2
|
+
|
|
3
|
+
Server SDK for [ReliPay](https://relipay.dev) — auth + billing for your application.
|
|
4
|
+
|
|
5
|
+
> **For AI coding agents:** start at [AGENTS.md](./AGENTS.md).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @relipay/node
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Use
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { ReliPay } from '@relipay/node';
|
|
17
|
+
|
|
18
|
+
const relipay = new ReliPay({
|
|
19
|
+
apiUrl: process.env.RELIPAY_URL!,
|
|
20
|
+
secretKey: process.env.RELIPAY_SECRET!,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const user = await relipay.auth.getUser(userId);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Errors
|
|
27
|
+
|
|
28
|
+
Every error is a `RelipayError` with `code`, `message`, `fix`, and `docs`:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { RelipayError } from '@relipay/node';
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
await relipay.billing.checkout({ /* ... */ });
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err instanceof RelipayError) {
|
|
37
|
+
console.error(err.code, err.fix); // ← read err.fix first
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Status
|
|
44
|
+
|
|
45
|
+
Phase 0. Auth surface stubbed; billing methods land in Phase 1.
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT.
|