@alexasomba/better-auth-paystack 2.4.3 → 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 CHANGED
@@ -17,11 +17,12 @@ A TypeScript-first plugin that integrates Paystack into [Better Auth](https://ww
17
17
 
18
18
  ## AI Agent Skills
19
19
 
20
- This package publishes [TanStack Intent](https://www.npmjs.com/package/@tanstack/intent) skills so AI coding agents can load package-specific guidance for setup, subscriptions, organization billing, and TanStack Start integration.
20
+ This package publishes [TanStack Intent](https://www.npmjs.com/package/@tanstack/intent) skills so AI coding agents can load package-specific guidance for setup, subscriptions, organization billing, TanStack Start integration, client APIs, webhooks, local subscription lifecycle, schema changes, and testing.
21
21
 
22
22
  ```bash
23
23
  npx @tanstack/intent@latest list
24
24
  npx @tanstack/intent@latest load @alexasomba/better-auth-paystack#setup
25
+ npx @tanstack/intent@latest load @alexasomba/better-auth-paystack#testing-and-fixtures
25
26
  ```
26
27
 
27
28
  If you use an AI agent, run `npx @tanstack/intent@latest install` in your project so the agent knows how to discover package skills.
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as PACKAGE_VERSION } from "./version-GQ15aLQo.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-LjwMcXaE.mjs";
2
2
  //#region src/client.ts
3
3
  /**
4
4
  * Better Auth Paystack Client Plugin
package/dist/index.d.mts CHANGED
@@ -329,7 +329,7 @@ declare const getConfig: <P extends string = "/get-config">(options: AnyPaystack
329
329
  }>;
330
330
  //#endregion
331
331
  //#region src/version.d.ts
332
- declare const PACKAGE_VERSION = "2.4.3";
332
+ declare const PACKAGE_VERSION = "2.4.4";
333
333
  //#endregion
334
334
  //#region src/operations.d.ts
335
335
  declare function syncPaystackProducts(ctx: GenericEndpointContext, options: AnyPaystackOptions): Promise<PaystackSyncResult>;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as PACKAGE_VERSION } from "./version-GQ15aLQo.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-LjwMcXaE.mjs";
2
2
  import { HIDE_METADATA, defineErrorCodes } from "better-auth";
3
3
  import { defu } from "defu";
4
4
  import { APIError, createAuthEndpoint, createAuthMiddleware, getSessionFromCtx, originCheck, sessionMiddleware } from "better-auth/api";
@@ -0,0 +1,6 @@
1
+ //#region src/version.ts
2
+ const PACKAGE_VERSION = "2.4.4";
3
+ //#endregion
4
+ export { PACKAGE_VERSION as t };
5
+
6
+ //# sourceMappingURL=version-LjwMcXaE.mjs.map
@@ -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",
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",
@@ -4,7 +4,7 @@ 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.3" # x-release-please-version
7
+ library_version: "2.4.4" # x-release-please-version
8
8
  license: "MIT"
9
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
10
  sources:
@@ -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,7 @@ 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.3" # x-release-please-version
7
+ library_version: "2.4.4" # x-release-please-version
8
8
  license: "MIT"
9
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
10
  sources:
@@ -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
+ ```
@@ -4,7 +4,7 @@ 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.3" # x-release-please-version
7
+ library_version: "2.4.4" # x-release-please-version
8
8
  license: "MIT"
9
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
10
  sources:
@@ -4,7 +4,7 @@ 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.3" # x-release-please-version
7
+ library_version: "2.4.4" # x-release-please-version
8
8
  license: "MIT"
9
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
10
  sources:
@@ -4,7 +4,7 @@ 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.3" # x-release-please-version
7
+ library_version: "2.4.4" # x-release-please-version
8
8
  license: "MIT"
9
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
10
  sources:
@@ -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,6 +0,0 @@
1
- //#region src/version.ts
2
- const PACKAGE_VERSION = "2.4.3";
3
- //#endregion
4
- export { PACKAGE_VERSION as t };
5
-
6
- //# sourceMappingURL=version-GQ15aLQo.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"version-GQ15aLQo.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["export const PACKAGE_VERSION = \"2.4.3\"; // x-release-please-version\n"],"mappings":";AAAA,MAAa,kBAAkB"}