@alexasomba/better-auth-paystack 2.4.1 → 2.4.4
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 +2 -1
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +518 -491
- package/dist/index.mjs.map +1 -1
- package/dist/{types-CNI2ur0p.d.mts → types-DHZSS1K6.d.mts} +5 -4
- package/dist/types-DHZSS1K6.d.mts.map +1 -0
- package/dist/version-LjwMcXaE.mjs +6 -0
- package/dist/version-LjwMcXaE.mjs.map +1 -0
- package/package.json +2 -2
- package/skills/billing-catalog-and-limits/SKILL.md +3 -1
- package/skills/client-api-contract/SKILL.md +117 -0
- package/skills/local-subscription-lifecycle/SKILL.md +97 -0
- package/skills/organization-billing/SKILL.md +3 -1
- package/skills/schema-and-migrations/SKILL.md +94 -0
- package/skills/setup/SKILL.md +3 -1
- package/skills/subscriptions-and-transactions/SKILL.md +3 -1
- package/skills/tanstack-start/SKILL.md +3 -1
- package/skills/testing-and-fixtures/SKILL.md +95 -0
- package/skills/webhooks-and-event-processing/SKILL.md +94 -0
- package/dist/types-CNI2ur0p.d.mts.map +0 -1
- package/dist/version-DpVME9MV.mjs +0 -6
- package/dist/version-DpVME9MV.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GenericEndpointContext, InferOptionSchema, Session, User } from "better-auth";
|
|
2
|
-
import { PaystackCustomerClient, PaystackPlanClient, PaystackProductClient, PaystackSubscriptionClient, PaystackTransactionClient, PaystackWebhookEvent,
|
|
2
|
+
import { PaystackCustomerClient, PaystackPlanClient, PaystackProductClient, PaystackSubscriptionClient, PaystackTransactionClient, PaystackWebhookEvent, TransactionChargeAuthorizationResponseData, TransactionVerifyResponseData } from "@alexasomba/paystack-node";
|
|
3
3
|
import { BetterAuthPluginDBSchema, DBFieldAttribute } from "better-auth/db";
|
|
4
4
|
//#region src/schema.d.ts
|
|
5
5
|
type PluginSchemaTable<TableName extends string, FieldName extends string> = Record<TableName, {
|
|
@@ -85,7 +85,8 @@ type PaystackWebhookPayload = PaystackWebhookEvent;
|
|
|
85
85
|
/**
|
|
86
86
|
* Paystack SDK Result types
|
|
87
87
|
*/
|
|
88
|
-
type PaystackTransactionResponse =
|
|
88
|
+
type PaystackTransactionResponse = TransactionVerifyResponseData;
|
|
89
|
+
type PaystackChargeAuthorizationResponse = TransactionChargeAuthorizationResponseData;
|
|
89
90
|
interface SubscriptionOptions {
|
|
90
91
|
/**
|
|
91
92
|
* Enable subscriptions
|
|
@@ -248,7 +249,7 @@ interface ChargeRecurringSubscriptionInput {
|
|
|
248
249
|
}
|
|
249
250
|
interface ChargeRecurringSubscriptionResult {
|
|
250
251
|
status: "success" | "failed";
|
|
251
|
-
data:
|
|
252
|
+
data: PaystackChargeAuthorizationResponse;
|
|
252
253
|
}
|
|
253
254
|
interface PaystackSyncResult {
|
|
254
255
|
status: "success";
|
|
@@ -268,4 +269,4 @@ interface PaystackClientLike {
|
|
|
268
269
|
}
|
|
269
270
|
//#endregion
|
|
270
271
|
export { PaystackOptions as a, PaystackSyncResult as c, Subscription as d, SubscriptionOptions as f, PaystackClientLike as i, PaystackTransaction as l, ChargeRecurringSubscriptionInput as n, PaystackPlan as o, getSchema as p, ChargeRecurringSubscriptionResult as r, PaystackProduct as s, AnyPaystackOptions as t, PaystackTransactionResponse as u };
|
|
271
|
-
//# sourceMappingURL=types-
|
|
272
|
+
//# sourceMappingURL=types-DHZSS1K6.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-DHZSS1K6.d.mts","names":["GenericEndpointContext","InferOptionSchema","Session","User","Organization","Member","PaystackPaths","PaystackResponse","PaystackWebhookEvent","PaystackClient","PaystackCustomerClient","PaystackPlanClient","PaystackProductClient","PaystackSubscriptionClient","PaystackTransactionClient","TransactionChargeAuthorizationResponseData","TransactionVerifyResponseData","PlanListResponseData","CustomerCreateResponseData","SubscriptionListResponseData","ProductFetchResponseData","components","PaystackPluginSchema","PaystackCurrency","PaystackCheckoutChannel","PaystackTransaction","Date","id","reference","paystackId","referenceId","userId","amount","currency","status","plan","product","metadata","createdAt","updatedAt","PaystackProduct","name","description","price","quantity","unlimited","slug","InputPaystackProduct","PaystackUser","paystackCustomerCode","PaystackOrganization","PaystackPlan","Subscription","Promise","Record","interval","planCode","seatAmount","seatPriceId","seatPlanCode","invoiceLimit","freeTrial","days","onTrialStart","subscription","limits","features","PaystackWebhookPayload","PaystackTransactionResponse","PaystackChargeAuthorizationResponse","PaystackPlanResponse","PaystackCustomerResponse","PaystackSubscriptionResponse","PaystackProductResponse","SubscriptionOptions","enabled","plans","autoSyncQuantity","cancelBehavior","onSubscriptionComplete","event","data","ctx","onSubscriptionCreated","onSubscriptionCancel","authorizeReference","user","session","action","requireEmailVerification","allowedPaymentChannels","PaystackOptions","TPaystackClient","PaystackClientLike","secretKey","paystackWebhookSecret","paystackClient","webhook","secret","verifyIP","trustedIPs","billingPattern","onEvent","organization","getCustomerCreateParams","email","org","onCustomerCreate","paystackCustomer","products","createCustomerOnSignUp","schema","organizationId","pendingPlan","paystackSubscriptionCode","paystackPlanCode","paystackAuthorizationCode","paystackTransactionReference","paystackEmailToken","seats","periodStart","periodEnd","cancelAtPeriodEnd","trialStart","trialEnd","groupId","ChargeRecurringSubscriptionInput","subscriptionId","ChargeRecurringSubscriptionResult","PaystackSyncResult","count","AnyPaystackOptions","Pick","transaction","customer"],"sources":["../src/schema.ts","../src/types.d.ts"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-LjwMcXaE.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["export const PACKAGE_VERSION = \"2.4.4\"; // x-release-please-version\n"],"mappings":";AAAA,MAAa,kBAAkB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexasomba/better-auth-paystack",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.4",
|
|
4
4
|
"description": "Production-ready Paystack billing plugin for Better Auth. Supports subscriptions, one-time payments, organization billing, secure webhooks and more",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"africa",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"access": "public"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@alexasomba/paystack-node": "^1.
|
|
70
|
+
"@alexasomba/paystack-node": "^1.10.1",
|
|
71
71
|
"better-call": "~1.3.5",
|
|
72
72
|
"defu": "^6.1.7",
|
|
73
73
|
"zod": "^4.4.3"
|
|
@@ -4,7 +4,9 @@ description: >
|
|
|
4
4
|
Configure products, Paystack-native plans, local-managed plans, free trials, seat billing, resource limits, and catalog sync in @alexasomba/better-auth-paystack. Use when tasks mention planCode, freeTrial, trial eligibility, seatAmount, seatPlanCode, limits, products, syncPaystackProducts, or syncPaystackPlans.
|
|
5
5
|
type: core
|
|
6
6
|
library: "@alexasomba/better-auth-paystack"
|
|
7
|
-
library_version: "2.4.
|
|
7
|
+
library_version: "2.4.4" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
8
10
|
sources:
|
|
9
11
|
- "alexasomba/better-auth-paystack:README.md"
|
|
10
12
|
- "alexasomba/better-auth-paystack:src/types.ts"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: client-api-contract
|
|
3
|
+
description: >
|
|
4
|
+
Modify or use the @alexasomba/better-auth-paystack browser client API. Use for paystackClient(), authClient.paystack, authClient.transaction, authClient.subscription, initializeTransaction, verifyTransaction, listTransactions, listSubscriptions, listProducts, listPlans, subscription billingPortal/manageLink, cancel/restore aliases, BetterFetch throw option return types, and deprecated disable/enable behavior.
|
|
5
|
+
type: core
|
|
6
|
+
library: "@alexasomba/better-auth-paystack"
|
|
7
|
+
library_version: "2.4.3" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
10
|
+
sources:
|
|
11
|
+
- "alexasomba/better-auth-paystack:src/client.ts"
|
|
12
|
+
- "alexasomba/better-auth-paystack:src/routes.ts"
|
|
13
|
+
- "alexasomba/better-auth-paystack:test/typesafety.test.ts"
|
|
14
|
+
- "alexasomba/better-auth-paystack:examples/tanstack/src/lib/paystack-client.ts"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Client Contract
|
|
18
|
+
|
|
19
|
+
Install the browser plugin from the client entrypoint:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { createAuthClient } from "better-auth/client";
|
|
23
|
+
import { paystackClient } from "@alexasomba/better-auth-paystack/client";
|
|
24
|
+
|
|
25
|
+
export const authClient = createAuthClient({
|
|
26
|
+
plugins: [paystackClient({ subscription: true })],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The plugin exposes three public surfaces:
|
|
31
|
+
|
|
32
|
+
- `authClient.paystack`: top-level Paystack actions
|
|
33
|
+
- `authClient.transaction`: transaction namespace
|
|
34
|
+
- `authClient.subscription`: subscription namespace
|
|
35
|
+
|
|
36
|
+
`authClient.paystack.paystack` points back to the same actions object for compatibility.
|
|
37
|
+
|
|
38
|
+
## Core Patterns
|
|
39
|
+
|
|
40
|
+
### Prefer stable names in examples
|
|
41
|
+
|
|
42
|
+
Use these methods in new examples and application code:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
await authClient.paystack.config();
|
|
46
|
+
await authClient.paystack.listProducts();
|
|
47
|
+
await authClient.paystack.listPlans();
|
|
48
|
+
await authClient.paystack.initializeTransaction({ amount: 500_000 });
|
|
49
|
+
await authClient.paystack.verifyTransaction({ reference: "REF" });
|
|
50
|
+
await authClient.paystack.listTransactions();
|
|
51
|
+
|
|
52
|
+
await authClient.transaction.initialize({ amount: 500_000 });
|
|
53
|
+
await authClient.transaction.verify({ reference: "REF" });
|
|
54
|
+
await authClient.transaction.list();
|
|
55
|
+
|
|
56
|
+
await authClient.subscription.create({ plan: "starter" });
|
|
57
|
+
await authClient.subscription.upgrade({ plan: "team" });
|
|
58
|
+
await authClient.subscription.list();
|
|
59
|
+
await authClient.subscription.billingPortal({ subscriptionCode: "SUB_code" });
|
|
60
|
+
await authClient.subscription.cancel({ subscriptionCode: "SUB_code", atPeriodEnd: true });
|
|
61
|
+
await authClient.subscription.restore({ subscriptionCode: "SUB_code" });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`subscription.manageLink` is an alias for `subscription.billingPortal`.
|
|
65
|
+
|
|
66
|
+
### Preserve deprecated aliases
|
|
67
|
+
|
|
68
|
+
`subscription.disable` maps to `subscription.cancel`.
|
|
69
|
+
`subscription.enable` maps to `subscription.restore`.
|
|
70
|
+
|
|
71
|
+
Keep these aliases in the 2.x line for compatibility, but do not introduce them in new examples.
|
|
72
|
+
|
|
73
|
+
### Respect BetterFetch return typing
|
|
74
|
+
|
|
75
|
+
Methods use `FetchResult<T, O>`:
|
|
76
|
+
|
|
77
|
+
- with `{ throw: true }`, the promise resolves to `T`
|
|
78
|
+
- without `{ throw: true }`, the promise resolves to `BetterFetchResponse<T>`
|
|
79
|
+
|
|
80
|
+
When changing method signatures, update both the interface and implementation, then run type tests.
|
|
81
|
+
|
|
82
|
+
## Common Mistakes
|
|
83
|
+
|
|
84
|
+
### Using old `getConfig`
|
|
85
|
+
|
|
86
|
+
The stable method is `authClient.paystack.config()`. Do not add new examples that call
|
|
87
|
+
`authClient.paystack.getConfig()`.
|
|
88
|
+
|
|
89
|
+
### Passing query data in the body for list endpoints
|
|
90
|
+
|
|
91
|
+
List endpoints use GET with query data:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
await authClient.subscription.list({ query: { referenceId: "org_123" } });
|
|
95
|
+
await authClient.transaction.list({ query: { referenceId: "org_123" } });
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Importing the server package in browser code
|
|
99
|
+
|
|
100
|
+
Browser code should import only `@alexasomba/better-auth-paystack/client`. Server helpers such as
|
|
101
|
+
`syncPaystackPlans` and `chargeSubscriptionRenewal` belong in server functions, cron jobs, or trusted
|
|
102
|
+
routes.
|
|
103
|
+
|
|
104
|
+
## Verification
|
|
105
|
+
|
|
106
|
+
Run these after client API changes:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
vp test test/typesafety.test.ts
|
|
110
|
+
vp test test/paystack.test.ts
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Run TanStack example tests when examples or client usage are changed:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pnpm --filter ./examples/tanstack test
|
|
117
|
+
```
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: local-subscription-lifecycle
|
|
3
|
+
description: >
|
|
4
|
+
Implement, debug, or test local-managed subscription behavior in @alexasomba/better-auth-paystack. Use for local plans without planCode, saved authorization renewal, chargeSubscriptionRenewal, seat billing, prorateAndCharge, pendingPlan, LOC_ subscription codes, trial transitions, schedule-at-period-end upgrades, and Paystack-managed vs local-managed behavior.
|
|
5
|
+
type: core
|
|
6
|
+
library: "@alexasomba/better-auth-paystack"
|
|
7
|
+
library_version: "2.4.3" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
10
|
+
sources:
|
|
11
|
+
- "alexasomba/better-auth-paystack:src/subscription-lifecycle.ts"
|
|
12
|
+
- "alexasomba/better-auth-paystack:src/operations.ts"
|
|
13
|
+
- "alexasomba/better-auth-paystack:src/routes.ts"
|
|
14
|
+
- "alexasomba/better-auth-paystack:src/utils.ts"
|
|
15
|
+
- "alexasomba/better-auth-paystack:test/local_subscription.test.ts"
|
|
16
|
+
- "alexasomba/better-auth-paystack:test/seat_billing.test.ts"
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Local Subscription Model
|
|
20
|
+
|
|
21
|
+
A plan without `planCode` is locally managed. The plugin stores subscription state in the Better Auth
|
|
22
|
+
database and charges future renewals with a saved Paystack authorization code.
|
|
23
|
+
|
|
24
|
+
Local-managed subscriptions are required for:
|
|
25
|
+
|
|
26
|
+
- seat-based local billing
|
|
27
|
+
- prorated mid-cycle seat or plan upgrades
|
|
28
|
+
- trusted backend renewal jobs through `chargeSubscriptionRenewal`
|
|
29
|
+
- local trial and pending plan transitions
|
|
30
|
+
|
|
31
|
+
Use Paystack-native `planCode` plans for simple fixed recurring billing.
|
|
32
|
+
|
|
33
|
+
## Core Patterns
|
|
34
|
+
|
|
35
|
+
### Capture reusable authorization during verification
|
|
36
|
+
|
|
37
|
+
Local subscriptions become renewable after transaction verification or webhook reconciliation stores
|
|
38
|
+
`authorization.authorization_code` on the subscription. If the authorization is absent, renewal must
|
|
39
|
+
fail with a clear error instead of inventing a charge path.
|
|
40
|
+
|
|
41
|
+
### Use server-only renewal helpers
|
|
42
|
+
|
|
43
|
+
`chargeSubscriptionRenewal(ctx, options, { subscriptionId })` is for cron jobs, admin server
|
|
44
|
+
functions, or trusted server routes. Never expose it directly as a browser action.
|
|
45
|
+
|
|
46
|
+
Before charging, verify the caller can manage the subscription reference. For organization billing,
|
|
47
|
+
only owners/admins should trigger renewals.
|
|
48
|
+
|
|
49
|
+
### Prorate only local active subscriptions
|
|
50
|
+
|
|
51
|
+
`prorateAndCharge` is handled by `handleProratedUpgrade`.
|
|
52
|
+
|
|
53
|
+
The existing active subscription must have:
|
|
54
|
+
|
|
55
|
+
- status `active`
|
|
56
|
+
- a Paystack or local subscription code
|
|
57
|
+
- `periodStart` and `periodEnd`
|
|
58
|
+
- local-management compatibility for plan or seat changes
|
|
59
|
+
|
|
60
|
+
If a saved authorization exists, the prorated amount is charged immediately. If not, the code creates
|
|
61
|
+
a checkout transaction and applies the upgrade after the reference is verified.
|
|
62
|
+
|
|
63
|
+
Paystack minimum charge behavior matters. If the prorated amount is below the supported minimum,
|
|
64
|
+
surface a BAD_REQUEST and advise scheduling the change for period end.
|
|
65
|
+
|
|
66
|
+
### Preserve pending plan semantics
|
|
67
|
+
|
|
68
|
+
Scheduled changes should use `pendingPlan` rather than silently changing the active plan. Immediate
|
|
69
|
+
local changes should update `plan`, `seats`, and transaction reference consistently.
|
|
70
|
+
|
|
71
|
+
## Common Mistakes
|
|
72
|
+
|
|
73
|
+
### Adding `planCode` to a local billing plan
|
|
74
|
+
|
|
75
|
+
Do not add `planCode` to a plan that needs local seat billing, prorated upgrades, or local renewals.
|
|
76
|
+
That turns the plan into a Paystack-managed subscription path.
|
|
77
|
+
|
|
78
|
+
### Updating seats for Paystack-managed subscriptions
|
|
79
|
+
|
|
80
|
+
Seat and proration helpers intentionally reject Paystack-managed subscriptions. Use local-managed
|
|
81
|
+
plans for seat-aware billing.
|
|
82
|
+
|
|
83
|
+
### Charging renewals from client components
|
|
84
|
+
|
|
85
|
+
The client may trigger checkout. Renewal jobs require trusted server code and a validated session or
|
|
86
|
+
job context.
|
|
87
|
+
|
|
88
|
+
## Verification
|
|
89
|
+
|
|
90
|
+
Run focused tests after lifecycle changes:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
vp test test/local_subscription.test.ts
|
|
94
|
+
vp test test/seat_billing.test.ts
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Run `vp test test/paystack.test.ts` when route behavior, trials, or organization billing are touched.
|
|
@@ -4,7 +4,9 @@ description: >
|
|
|
4
4
|
Configure organization billing in @alexasomba/better-auth-paystack. Use for organization.enabled, Better Auth organization plugin setup, owner/admin default billing authorization, subscription.authorizeReference, organization Paystack customers, seats, invitations, members, and team limits.
|
|
5
5
|
type: core
|
|
6
6
|
library: "@alexasomba/better-auth-paystack"
|
|
7
|
-
library_version: "2.4.
|
|
7
|
+
library_version: "2.4.4" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
8
10
|
sources:
|
|
9
11
|
- "alexasomba/better-auth-paystack:README.md"
|
|
10
12
|
- "alexasomba/better-auth-paystack:src/index.ts"
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: schema-and-migrations
|
|
3
|
+
description: >
|
|
4
|
+
Modify or review @alexasomba/better-auth-paystack database schema behavior. Use for paystackProduct, paystackPlan, paystackTransaction, subscription, user.paystackCustomerCode, organization.paystackCustomerCode/email, Better Auth schema overrides, mergeSchema behavior, migrations, indexes, unique fields, and backward-compatible table or field changes.
|
|
5
|
+
type: core
|
|
6
|
+
library: "@alexasomba/better-auth-paystack"
|
|
7
|
+
library_version: "2.4.3" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
10
|
+
sources:
|
|
11
|
+
- "alexasomba/better-auth-paystack:src/schema.ts"
|
|
12
|
+
- "alexasomba/better-auth-paystack:src/types.ts"
|
|
13
|
+
- "alexasomba/better-auth-paystack:test/paystack.test.ts"
|
|
14
|
+
- "alexasomba/better-auth-paystack:test/typesafety.test.ts"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Schema Contract
|
|
18
|
+
|
|
19
|
+
The plugin contributes Better Auth schema through `getSchema(options)`.
|
|
20
|
+
|
|
21
|
+
Always included:
|
|
22
|
+
|
|
23
|
+
- `user.paystackCustomerCode`
|
|
24
|
+
- `paystackTransaction`
|
|
25
|
+
- `paystackProduct`
|
|
26
|
+
- `paystackPlan`
|
|
27
|
+
|
|
28
|
+
Included when `subscription.enabled` is true:
|
|
29
|
+
|
|
30
|
+
- `subscription`
|
|
31
|
+
|
|
32
|
+
Included when `organization.enabled` is true:
|
|
33
|
+
|
|
34
|
+
- `organization.paystackCustomerCode`
|
|
35
|
+
- `organization.email`
|
|
36
|
+
|
|
37
|
+
Product and plan tables are intentionally always present. Do not make them optional in a
|
|
38
|
+
compatibility-preserving release.
|
|
39
|
+
|
|
40
|
+
## Core Patterns
|
|
41
|
+
|
|
42
|
+
### Use schema overrides only for Better Auth-supported customization
|
|
43
|
+
|
|
44
|
+
Consumers can pass `options.schema` and the plugin merges it with the default schema via
|
|
45
|
+
`mergeSchema`. Use this for model/field naming and migration metadata, not for removing core billing
|
|
46
|
+
state.
|
|
47
|
+
|
|
48
|
+
When subscriptions are disabled, `getSchema` strips a user-provided `subscription` override before
|
|
49
|
+
merging so the subscription model is not reintroduced accidentally.
|
|
50
|
+
|
|
51
|
+
### Preserve field compatibility
|
|
52
|
+
|
|
53
|
+
Schema changes affect persisted billing state. Treat these as migration-sensitive:
|
|
54
|
+
|
|
55
|
+
- changing required fields
|
|
56
|
+
- changing uniqueness or indexes
|
|
57
|
+
- renaming `paystack*` identity fields
|
|
58
|
+
- changing transaction `reference` uniqueness
|
|
59
|
+
- changing subscription `paystackSubscriptionCode` uniqueness
|
|
60
|
+
- changing product/plan `paystackId` or `planCode` uniqueness
|
|
61
|
+
|
|
62
|
+
Prefer additive optional fields in minor releases. Required field changes need clear migrations and
|
|
63
|
+
major-version scrutiny.
|
|
64
|
+
|
|
65
|
+
### Keep TypeScript schema exports aligned
|
|
66
|
+
|
|
67
|
+
`PaystackPluginSchema`, individual schema exports, and `PaystackOptions["schema"]` should stay in
|
|
68
|
+
sync. If a field is added to a schema table, update the corresponding TypeScript table type in
|
|
69
|
+
`src/schema.ts`.
|
|
70
|
+
|
|
71
|
+
## Common Mistakes
|
|
72
|
+
|
|
73
|
+
### Removing catalog tables when products are unused
|
|
74
|
+
|
|
75
|
+
The package supports catalog sync and discovery. `paystackProduct` and `paystackPlan` remain part of
|
|
76
|
+
the plugin schema even if a specific app only uses subscriptions or only uses transactions.
|
|
77
|
+
|
|
78
|
+
### Reintroducing subscription schema when subscriptions are disabled
|
|
79
|
+
|
|
80
|
+
Keep the guard in `getSchema` that removes `options.schema.subscription` unless
|
|
81
|
+
`subscription.enabled` is true.
|
|
82
|
+
|
|
83
|
+
### Forgetting organization schema conditions
|
|
84
|
+
|
|
85
|
+
Organization billing fields should only be added when `organization.enabled` is true.
|
|
86
|
+
|
|
87
|
+
## Verification
|
|
88
|
+
|
|
89
|
+
Run schema and type tests after schema changes:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
vp test test/paystack.test.ts test/typesafety.test.ts
|
|
93
|
+
vp check
|
|
94
|
+
```
|
package/skills/setup/SKILL.md
CHANGED
|
@@ -4,7 +4,9 @@ description: >
|
|
|
4
4
|
Configure @alexasomba/better-auth-paystack with Better Auth. Use when adding the paystack() server plugin, paystackClient() client plugin, schema overrides, products/plans, webhook secrets, or canonical authClient.paystack/subscription/transaction actions.
|
|
5
5
|
type: core
|
|
6
6
|
library: "@alexasomba/better-auth-paystack"
|
|
7
|
-
library_version: "2.4.
|
|
7
|
+
library_version: "2.4.4" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
8
10
|
sources:
|
|
9
11
|
- "alexasomba/better-auth-paystack:README.md"
|
|
10
12
|
- "alexasomba/better-auth-paystack:src/index.ts"
|
|
@@ -4,7 +4,9 @@ description: >
|
|
|
4
4
|
Build Paystack transaction and subscription flows with @alexasomba/better-auth-paystack. Use for initialize/verify transaction, create/upgrade/cancel/restore/list subscriptions, products/plans, billing portal links, webhooks, chargeSubscriptionRenewal, syncPaystackProducts, and syncPaystackPlans.
|
|
5
5
|
type: core
|
|
6
6
|
library: "@alexasomba/better-auth-paystack"
|
|
7
|
-
library_version: "2.4.
|
|
7
|
+
library_version: "2.4.4" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
8
10
|
sources:
|
|
9
11
|
- "alexasomba/better-auth-paystack:README.md"
|
|
10
12
|
- "alexasomba/better-auth-paystack:src/routes.ts"
|
|
@@ -4,7 +4,9 @@ description: >
|
|
|
4
4
|
Integrate @alexasomba/better-auth-paystack in TanStack Start. Use for Better Auth API routes, tanstackStartCookies(), server functions, getRequestHeaders(), authClient Paystack actions, admin billing server functions, and Cloudflare Workers deployment.
|
|
5
5
|
type: composition
|
|
6
6
|
library: "@alexasomba/better-auth-paystack"
|
|
7
|
-
library_version: "2.4.
|
|
7
|
+
library_version: "2.4.4" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
8
10
|
sources:
|
|
9
11
|
- "alexasomba/better-auth-paystack:examples/tanstack/README.md"
|
|
10
12
|
- "alexasomba/better-auth-paystack:examples/tanstack/src/lib/auth.ts"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-and-fixtures
|
|
3
|
+
description: >
|
|
4
|
+
Test @alexasomba/better-auth-paystack changes. Use for choosing focused vp test commands, Better Auth test clients, in-memory adapters, mocked Paystack SDK responses, webhook signatures, TanStack example tests, integration tests, type-safety tests, and verification before landing changes.
|
|
5
|
+
type: core
|
|
6
|
+
library: "@alexasomba/better-auth-paystack"
|
|
7
|
+
library_version: "2.4.3" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
10
|
+
sources:
|
|
11
|
+
- "alexasomba/better-auth-paystack:test/paystack.test.ts"
|
|
12
|
+
- "alexasomba/better-auth-paystack:test/local_subscription.test.ts"
|
|
13
|
+
- "alexasomba/better-auth-paystack:test/seat_billing.test.ts"
|
|
14
|
+
- "alexasomba/better-auth-paystack:test/typesafety.test.ts"
|
|
15
|
+
- "alexasomba/better-auth-paystack:examples/tanstack/src/__tests__"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Test Selection
|
|
19
|
+
|
|
20
|
+
Use `vp test` instead of invoking Vitest directly.
|
|
21
|
+
|
|
22
|
+
Focused suites:
|
|
23
|
+
|
|
24
|
+
- core plugin routes, schema, webhooks, products, org billing: `vp test test/paystack.test.ts`
|
|
25
|
+
- local-managed subscriptions and authorization capture: `vp test test/local_subscription.test.ts`
|
|
26
|
+
- seat billing, proration, local renewal UI paths: `vp test test/seat_billing.test.ts`
|
|
27
|
+
- planCode and organization integration regressions: `vp test test/plancode-and-org.integration.test.ts`
|
|
28
|
+
- package type contracts: `vp test test/typesafety.test.ts`
|
|
29
|
+
- TanStack example components/routes: `pnpm --filter ./examples/tanstack test`
|
|
30
|
+
|
|
31
|
+
Broad gates before landing:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
vp check
|
|
35
|
+
vp test
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Run integration tests only when needed and credentials/environment are available:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
RUN_INTEGRATION_TESTS=1 vp test
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Fixture Patterns
|
|
45
|
+
|
|
46
|
+
### Mock Paystack SDK at the adapter boundary
|
|
47
|
+
|
|
48
|
+
Mocks should resemble `@alexasomba/paystack-node` grouped operations:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
const paystackClient = {
|
|
52
|
+
transaction: {
|
|
53
|
+
initialize: vi.fn().mockResolvedValue({ data: { reference: "REF", authorization_url: "..." } }),
|
|
54
|
+
verify: vi.fn().mockResolvedValue({ data: { status: "success", reference: "REF" } }),
|
|
55
|
+
chargeAuthorization: vi.fn(),
|
|
56
|
+
},
|
|
57
|
+
subscription: {
|
|
58
|
+
create: vi.fn(),
|
|
59
|
+
fetch: vi.fn(),
|
|
60
|
+
disable: vi.fn(),
|
|
61
|
+
enable: vi.fn(),
|
|
62
|
+
manageLink: vi.fn(),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The package supports SDK `PaystackResponse` objects and legacy/custom nested `{ data }` test shapes.
|
|
68
|
+
Do not overfit tests to only one response wrapper unless the change is specifically about
|
|
69
|
+
`unwrapSdkResult`.
|
|
70
|
+
|
|
71
|
+
### Sign webhooks like Paystack
|
|
72
|
+
|
|
73
|
+
Webhook tests should create the exact JSON payload string, sign it with HMAC SHA-512, and send the
|
|
74
|
+
signature in `x-paystack-signature`.
|
|
75
|
+
|
|
76
|
+
### Use Better Auth client behavior realistically
|
|
77
|
+
|
|
78
|
+
For browser-style flows, sign up/sign in and pass cookies into the auth client. Use `{ throw: true }`
|
|
79
|
+
when the test should fail immediately on Better Auth errors.
|
|
80
|
+
|
|
81
|
+
## Common Mistakes
|
|
82
|
+
|
|
83
|
+
### Only testing the root package after example changes
|
|
84
|
+
|
|
85
|
+
The TanStack example has its own component and route tests. Run its test/build command when touching
|
|
86
|
+
`examples/tanstack`.
|
|
87
|
+
|
|
88
|
+
### Skipping type tests for client API changes
|
|
89
|
+
|
|
90
|
+
Any change to `src/client.ts`, route return shapes, or public exports should run
|
|
91
|
+
`test/typesafety.test.ts`.
|
|
92
|
+
|
|
93
|
+
### Assuming live Paystack is available
|
|
94
|
+
|
|
95
|
+
Most tests should use mocked SDK operations. Keep live/integration tests opt-in.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webhooks-and-event-processing
|
|
3
|
+
description: >
|
|
4
|
+
Implement, debug, or test @alexasomba/better-auth-paystack webhook handling. Use for Paystack webhook signatures, trusted IP checks, webhook.secret/paystackWebhookSecret behavior, charge.success, subscription.create, subscription.disable, subscription.enable, product quantity updates, subscription status changes, metadata parsing, and event hooks.
|
|
5
|
+
type: core
|
|
6
|
+
library: "@alexasomba/better-auth-paystack"
|
|
7
|
+
library_version: "2.4.3" # x-release-please-version
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "Node.js >=24.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=2.4.2 <3.0.0"
|
|
10
|
+
sources:
|
|
11
|
+
- "alexasomba/better-auth-paystack:src/routes.ts"
|
|
12
|
+
- "alexasomba/better-auth-paystack:src/types.ts"
|
|
13
|
+
- "alexasomba/better-auth-paystack:src/utils.ts"
|
|
14
|
+
- "alexasomba/better-auth-paystack:test/paystack.test.ts"
|
|
15
|
+
- "alexasomba/better-auth-paystack:test/seat_billing.test.ts"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Webhook Contract
|
|
19
|
+
|
|
20
|
+
The Better Auth endpoint is registered as `auth.api.paystackWebhook` and mounted under
|
|
21
|
+
`/api/auth/paystack/webhook` by the plugin. Always send the raw JSON body that Paystack signed.
|
|
22
|
+
|
|
23
|
+
Signature verification uses HMAC SHA-512 over the raw request body. Secret precedence is:
|
|
24
|
+
|
|
25
|
+
1. `webhook.secret`
|
|
26
|
+
2. `paystackWebhookSecret`
|
|
27
|
+
3. `secretKey`
|
|
28
|
+
|
|
29
|
+
Prefer `webhook.secret` in new code. Keep `paystackWebhookSecret` only for compatibility.
|
|
30
|
+
|
|
31
|
+
## Core Patterns
|
|
32
|
+
|
|
33
|
+
### Verify before processing
|
|
34
|
+
|
|
35
|
+
Webhook code must reject invalid signatures before parsing business effects:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const signature = createHmac("sha512", webhookSecret).update(payload).digest("hex");
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If `webhook.verifyIP` is true, the request must come from `webhook.trustedIPs` or the built-in
|
|
42
|
+
Paystack IP allowlist. Preserve support for common forwarded IP headers when changing this path.
|
|
43
|
+
|
|
44
|
+
### Treat `charge.success` as reconciliation
|
|
45
|
+
|
|
46
|
+
`charge.success` can update multiple local records:
|
|
47
|
+
|
|
48
|
+
- mark a pending transaction as `success`
|
|
49
|
+
- finalize local subscription checkout when metadata identifies a plan
|
|
50
|
+
- apply checkout-based proration metadata with `type: "proration"`
|
|
51
|
+
- capture `authorization.authorization_code` for local renewals
|
|
52
|
+
- decrement one-time product quantity when product metadata is present
|
|
53
|
+
|
|
54
|
+
Do not grant paid access from a redirect alone. The callback should verify the transaction and
|
|
55
|
+
webhooks should reconcile persisted state.
|
|
56
|
+
|
|
57
|
+
### Handle subscription events idempotently
|
|
58
|
+
|
|
59
|
+
Paystack subscription events should update matching subscriptions without assuming one delivery:
|
|
60
|
+
|
|
61
|
+
- `subscription.create`: activate or update the subscription and call creation hooks
|
|
62
|
+
- `subscription.disable`: mark cancellation/non-renewal and call cancel hooks
|
|
63
|
+
- `subscription.enable`: restore active state when Paystack re-enables a subscription
|
|
64
|
+
|
|
65
|
+
Match by known Paystack identifiers first, then metadata such as `referenceId` and plan when needed.
|
|
66
|
+
Avoid creating duplicate subscriptions on repeated webhook delivery.
|
|
67
|
+
|
|
68
|
+
## Common Mistakes
|
|
69
|
+
|
|
70
|
+
### Parsing body before signature verification
|
|
71
|
+
|
|
72
|
+
Do not route Paystack webhooks through a generic JSON handler that loses the exact signed payload.
|
|
73
|
+
The signature must be checked against the same raw string Paystack sent.
|
|
74
|
+
|
|
75
|
+
### Assuming all metadata is an object
|
|
76
|
+
|
|
77
|
+
Paystack metadata may arrive as an object or a JSON string. Existing route code handles both forms.
|
|
78
|
+
Keep that tolerance when changing metadata handling.
|
|
79
|
+
|
|
80
|
+
### Forgetting product side effects
|
|
81
|
+
|
|
82
|
+
Webhook work is not subscription-only. Successful product purchases must update transaction state and
|
|
83
|
+
respect product quantity/unlimited settings.
|
|
84
|
+
|
|
85
|
+
## Verification
|
|
86
|
+
|
|
87
|
+
Run focused tests after webhook changes:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
vp test test/paystack.test.ts
|
|
91
|
+
vp test test/seat_billing.test.ts
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Also run `vp check` before landing broad route or type changes.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-CNI2ur0p.d.mts","names":["GenericEndpointContext","InferOptionSchema","Session","User","Organization","Member","PaystackPaths","PaystackResponse","PaystackWebhookEvent","PaystackClient","PaystackCustomerClient","PaystackPlanClient","PaystackProductClient","PaystackSubscriptionClient","PaystackTransactionClient","components","PaystackPluginSchema","PaystackCurrency","PaystackCheckoutChannel","PaystackTransaction","Date","id","reference","paystackId","referenceId","userId","amount","currency","status","plan","product","metadata","createdAt","updatedAt","PaystackProduct","name","description","price","quantity","unlimited","slug","InputPaystackProduct","PaystackUser","paystackCustomerCode","PaystackOrganization","PaystackPlan","Subscription","Promise","Record","interval","planCode","seatAmount","seatPriceId","seatPlanCode","invoiceLimit","freeTrial","days","onTrialStart","subscription","limits","features","PaystackWebhookPayload","PaystackTransactionResponse","PaystackPlanResponse","PaystackCustomerResponse","PaystackSubscriptionResponse","PaystackProductResponse","SubscriptionOptions","enabled","plans","autoSyncQuantity","cancelBehavior","onSubscriptionComplete","event","data","ctx","onSubscriptionCreated","onSubscriptionCancel","authorizeReference","user","session","action","requireEmailVerification","allowedPaymentChannels","PaystackOptions","TPaystackClient","PaystackClientLike","secretKey","paystackWebhookSecret","paystackClient","webhook","secret","verifyIP","trustedIPs","billingPattern","onEvent","organization","getCustomerCreateParams","email","org","onCustomerCreate","paystackCustomer","products","createCustomerOnSignUp","schema","organizationId","pendingPlan","paystackSubscriptionCode","paystackPlanCode","paystackAuthorizationCode","paystackTransactionReference","paystackEmailToken","seats","periodStart","periodEnd","cancelAtPeriodEnd","trialStart","trialEnd","groupId","ChargeRecurringSubscriptionInput","subscriptionId","ChargeRecurringSubscriptionResult","PaystackSyncResult","count","AnyPaystackOptions","Pick","transaction","customer"],"sources":["../src/schema.ts","../src/types.d.ts"],"mappings":"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"}
|