payweave 0.0.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.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +272 -0
  3. package/dist/_tsup-dts-rollup.d.ts +19470 -0
  4. package/dist/chunk-4R5OGOCC.js +94 -0
  5. package/dist/chunk-4R5OGOCC.js.map +1 -0
  6. package/dist/chunk-535Q3GUN.js +175 -0
  7. package/dist/chunk-535Q3GUN.js.map +1 -0
  8. package/dist/chunk-67NRYGRC.js +192 -0
  9. package/dist/chunk-67NRYGRC.js.map +1 -0
  10. package/dist/chunk-CGQ73I4I.js +568 -0
  11. package/dist/chunk-CGQ73I4I.js.map +1 -0
  12. package/dist/chunk-CJEYDHY6.js +18 -0
  13. package/dist/chunk-CJEYDHY6.js.map +1 -0
  14. package/dist/chunk-CR63JAAS.js +3 -0
  15. package/dist/chunk-CR63JAAS.js.map +1 -0
  16. package/dist/chunk-E633MKVX.js +1507 -0
  17. package/dist/chunk-E633MKVX.js.map +1 -0
  18. package/dist/chunk-FBPOCXRZ.js +1135 -0
  19. package/dist/chunk-FBPOCXRZ.js.map +1 -0
  20. package/dist/chunk-HTRGMZFH.js +267 -0
  21. package/dist/chunk-HTRGMZFH.js.map +1 -0
  22. package/dist/chunk-IUVGM3K7.js +765 -0
  23. package/dist/chunk-IUVGM3K7.js.map +1 -0
  24. package/dist/chunk-JD4OZHRI.js +326 -0
  25. package/dist/chunk-JD4OZHRI.js.map +1 -0
  26. package/dist/chunk-NV3MZF7L.js +139 -0
  27. package/dist/chunk-NV3MZF7L.js.map +1 -0
  28. package/dist/chunk-NXQBP35U.js +13 -0
  29. package/dist/chunk-NXQBP35U.js.map +1 -0
  30. package/dist/chunk-QJHXDZYC.js +412 -0
  31. package/dist/chunk-QJHXDZYC.js.map +1 -0
  32. package/dist/chunk-TWZK62TZ.js +83 -0
  33. package/dist/chunk-TWZK62TZ.js.map +1 -0
  34. package/dist/cli/index.js +35381 -0
  35. package/dist/core/index.d.ts +85 -0
  36. package/dist/core/index.js +6 -0
  37. package/dist/core/index.js.map +1 -0
  38. package/dist/db/drizzle/index.d.ts +6 -0
  39. package/dist/db/drizzle/index.js +1532 -0
  40. package/dist/db/drizzle/index.js.map +1 -0
  41. package/dist/db/index.d.ts +43 -0
  42. package/dist/db/index.js +3 -0
  43. package/dist/db/index.js.map +1 -0
  44. package/dist/db/mongodb/index.d.ts +3 -0
  45. package/dist/db/mongodb/index.js +934 -0
  46. package/dist/db/mongodb/index.js.map +1 -0
  47. package/dist/db/mysql/index.d.ts +1 -0
  48. package/dist/db/mysql/index.js +12 -0
  49. package/dist/db/mysql/index.js.map +1 -0
  50. package/dist/db/postgres/index.d.ts +5 -0
  51. package/dist/db/postgres/index.js +791 -0
  52. package/dist/db/postgres/index.js.map +1 -0
  53. package/dist/db/prisma/index.d.ts +1 -0
  54. package/dist/db/prisma/index.js +12 -0
  55. package/dist/db/prisma/index.js.map +1 -0
  56. package/dist/db/sqlite/index.d.ts +5 -0
  57. package/dist/db/sqlite/index.js +750 -0
  58. package/dist/db/sqlite/index.js.map +1 -0
  59. package/dist/express/index.d.ts +1 -0
  60. package/dist/express/index.js +3 -0
  61. package/dist/express/index.js.map +1 -0
  62. package/dist/fastify/index.d.ts +1 -0
  63. package/dist/fastify/index.js +3 -0
  64. package/dist/fastify/index.js.map +1 -0
  65. package/dist/flutterwave/index.d.ts +27 -0
  66. package/dist/flutterwave/index.js +9 -0
  67. package/dist/flutterwave/index.js.map +1 -0
  68. package/dist/index.d.ts +85 -0
  69. package/dist/index.js +3677 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/next/index.d.ts +1 -0
  72. package/dist/next/index.js +3 -0
  73. package/dist/next/index.js.map +1 -0
  74. package/dist/paystack/index.d.ts +33 -0
  75. package/dist/paystack/index.js +9 -0
  76. package/dist/paystack/index.js.map +1 -0
  77. package/dist/products/index.d.ts +22 -0
  78. package/dist/products/index.js +7 -0
  79. package/dist/products/index.js.map +1 -0
  80. package/dist/testing/index.d.ts +11 -0
  81. package/dist/testing/index.js +69 -0
  82. package/dist/testing/index.js.map +1 -0
  83. package/dist/unified/index.d.ts +41 -0
  84. package/dist/unified/index.js +6 -0
  85. package/dist/unified/index.js.map +1 -0
  86. package/dist/webhooks/index.d.ts +8 -0
  87. package/dist/webhooks/index.js +8 -0
  88. package/dist/webhooks/index.js.map +1 -0
  89. package/package.json +164 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Payweave contributors
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 ADDED
@@ -0,0 +1,272 @@
1
+ # payweave
2
+
3
+ > **One SDK, every provider — woven together.**
4
+
5
+ A unified, fully-typed TypeScript SDK for **Stripe**, **Paystack**, and **Flutterwave**,
6
+ with a database layer, plans/features, metered usage, and a CLI built in. One config,
7
+ one client, full endpoint coverage, and webhook verification done correctly out of the box.
8
+
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
10
+ ![Types: TypeScript](https://img.shields.io/badge/types-TypeScript-3178c6.svg)
11
+ ![Module: ESM only](https://img.shields.io/badge/module-ESM--only-f7df1e.svg)
12
+ ![Node](https://img.shields.io/badge/node-%E2%89%A520.19-339933.svg)
13
+
14
+ > **Status:** pre-release.
15
+
16
+ ---
17
+
18
+ ## Why Payweave
19
+
20
+ - **One config, any provider.** Pass the provider(s) you want as keys on the config object and get a fully-typed client back.
21
+ - **Compile-time provider narrowing.** Namespaces exist only for the providers you configured — enforced by the type system.
22
+ - **Two surfaces, no lock-in.** Provider-native calls when you want full control; a normalized unified layer when you want portability. Every response carries `raw`, so the abstraction never traps you.
23
+ - **Webhooks as a first-class, security-critical citizen.** Correct signature scheme per provider, raw-body verification, constant-time comparison, fail-closed, auto-detected across every configured provider.
24
+ - **Money that can't drift.** Always integer minor units in the unified layer; the adapters convert so you never fat-finger a decimal.
25
+ - **Typed errors that tell you whose fault it is** — yours (validation/auth), the customer's (declined), or transient (network/5xx).
26
+ - **Billing built in, optional.** Plans, features, metered usage, and a database layer (SQLite, Postgres, MySQL, MongoDB, Drizzle, Prisma) for when you need more than a payment call.
27
+ - **Tiny footprint.** ESM-only, `zod` as the *only* runtime dependency, Node ≥ 20.19.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ npm install payweave
33
+ # or: pnpm add payweave / yarn add payweave / bun add payweave
34
+ ```
35
+
36
+ > ESM-only. Requires Node ≥ 20.19 (native `require(esm)` interop); no CJS build is shipped.
37
+
38
+ ## Quickstart
39
+
40
+ ### 1. Initialize — providers are config keys, narrowed at compile time
41
+
42
+ ```ts
43
+ import { createPayweave } from "payweave";
44
+
45
+ const payweave = createPayweave({
46
+ paystack: { secretKey: process.env.PAYSTACK_SECRET_KEY! },
47
+ flutterwave: { secretKey: process.env.FLW_SECRET_KEY! }, // v3 by default
48
+ defaultProvider: "paystack",
49
+ });
50
+
51
+ payweave.providers; // ["paystack", "flutterwave"]
52
+ payweave.environment; // "test" | "live" — inferred from the key prefixes
53
+ // payweave.stripe; // ❌ compile-time error: not configured
54
+ ```
55
+
56
+ Test vs live is a **config change, not a code change** — it's inferred from the key prefix
57
+ (`sk_test_` / `sk_live_` for Paystack, `FLWSECK_TEST-` / `FLWSECK-` for Flutterwave v3,
58
+ `sk_test_` / `sk_live_` for Stripe).
59
+
60
+ ### 2. Surface A — provider-native, every endpoint 1:1
61
+
62
+ ```ts
63
+ // Paystack — amounts in kobo (its native minor units)
64
+ const tx = await payweave.paystack.transactions.initialize({
65
+ email: "ada@example.com",
66
+ amount: 500_000, // ₦5,000
67
+ currency: "NGN",
68
+ });
69
+ console.log(tx.authorization_url);
70
+
71
+ // Flutterwave v3 — amounts in naira (its native major units)
72
+ const link = await payweave.flutterwave.payments.create({
73
+ tx_ref: "order_8123",
74
+ amount: 5000, // ₦5,000
75
+ currency: "NGN",
76
+ redirect_url: "https://app.example.com/pay/callback",
77
+ customer: { email: "ada@example.com" },
78
+ });
79
+ ```
80
+
81
+ Pagination endpoints expose an async iterator:
82
+
83
+ ```ts
84
+ for await (const t of payweave.paystack.transactions.iterate({ perPage: 100 })) {
85
+ // ...
86
+ }
87
+ ```
88
+
89
+ ### 3. Surface B — the unified layer (portable, always minor units)
90
+
91
+ ```ts
92
+ const checkout = await payweave.checkout.create({
93
+ amount: { value: 500_000, currency: "NGN" }, // ALWAYS minor units; the adapter converts
94
+ customer: { email: "ada@example.com" },
95
+ reference: "order_8123", // → Paystack `reference` / Flutterwave `tx_ref`
96
+ redirectUrl: "https://app.example.com/pay/callback",
97
+ provider: "flutterwave", // optional per-call override of defaultProvider
98
+ });
99
+ // → { checkoutUrl, reference, providerRef, raw }
100
+
101
+ const result = await payweave.verify({ reference: "order_8123" });
102
+ // → { status: "success" | "failed" | "pending" | "abandoned" | "reversed",
103
+ // amount: { value, currency }, customer, paidAt, channel, raw }
104
+
105
+ await payweave.banks.list({ country: "NG" });
106
+ await payweave.banks.resolveAccount({ accountNumber: "0123456789", bankCode: "058" });
107
+ ```
108
+
109
+ `payweave.capabilities()` tells you which unified ops each configured provider supports
110
+ (e.g. Stripe doesn't support `transfers`/`banks` — calling them throws a typed error
111
+ before any request is sent).
112
+
113
+ ### 4. Webhooks — verified, typed, normalized, multi-provider
114
+
115
+ Verification **must** run on the exact raw bytes — never parse-then-re-stringify. One
116
+ handler works for every configured provider — the provider is auto-detected from the
117
+ signature header.
118
+
119
+ ```ts
120
+ import express from "express";
121
+
122
+ const app = express();
123
+
124
+ // Capture the RAW body for the webhook route only.
125
+ app.post("/webhooks/payments", express.raw({ type: "*/*" }), (req, res) => {
126
+ let event;
127
+ try {
128
+ event = payweave.webhooks.constructEvent({ rawBody: req.body, headers: req.headers });
129
+ } catch (err) {
130
+ return res.sendStatus(400); // bad signature → PayweaveWebhookVerificationError
131
+ }
132
+
133
+ res.sendStatus(200); // ack fast, then process asynchronously
134
+
135
+ // event.type → provider-native name, e.g. "charge.success"
136
+ // event.unifiedType → normalized, e.g. "payment.succeeded"
137
+ // event.dedupeKey → stable idempotency key (providers redeliver)
138
+ switch (event.unifiedType) {
139
+ case "payment.succeeded":
140
+ // Never grant value from the webhook alone — re-verify first:
141
+ // await payweave.verify({ reference }) and check amount + currency + status.
142
+ break;
143
+ }
144
+ });
145
+ ```
146
+
147
+ Signature schemes handled for you: Paystack `HMAC-SHA512` (`x-paystack-signature`),
148
+ Flutterwave v3 `verif-hash`, Flutterwave v4 `HMAC-SHA256` (`flutterwave-signature`),
149
+ Stripe `HMAC-SHA256` (`stripe-signature`). The Flutterwave dashboard **secret hash** is
150
+ not your API key — pass it as `webhookSecret`.
151
+
152
+ ## Error handling
153
+
154
+ Every failure is a typed subclass of `PayweaveError`, so you can branch on cause:
155
+
156
+ ```ts
157
+ import {
158
+ PayweaveValidationError, // 400/422 or local Zod validation (your fault)
159
+ PayweaveAuthError, // 401/403 (bad key)
160
+ PayweaveNotFoundError, // 404 (unknown reference/recipient)
161
+ PayweaveRateLimitError, // 429 (exposes retryAfterMs)
162
+ PayweaveProviderError, // 5xx / provider processing failure
163
+ PayweaveNetworkError, // timeout/DNS/reset (isRetryable = true)
164
+ } from "payweave";
165
+
166
+ try {
167
+ await payweave.verify({ reference: "unknown" });
168
+ } catch (err) {
169
+ if (err instanceof PayweaveNotFoundError) {
170
+ // handle a genuinely missing transaction
171
+ }
172
+ }
173
+ ```
174
+
175
+ `error.toJSON()` is always safe to log — secret keys, `Authorization`, PANs, CVV and
176
+ PINs are redacted. Bare `POST`s are **never** auto-retried (a charge is never silently
177
+ re-sent); GETs and idempotency-keyed requests retry with jittered backoff and honor
178
+ `Retry-After`.
179
+
180
+ ## Plans, features & metered usage (optional)
181
+
182
+ Configure a `database` adapter and a `products` array to get subscriptions and usage
183
+ tracking without hand-rolling billing state:
184
+
185
+ ```ts
186
+ import { createPayweave, feature, plan } from "payweave";
187
+ import { sqliteAdapter } from "payweave/db/sqlite";
188
+
189
+ const payweave = createPayweave({
190
+ stripe: { secretKey: process.env.STRIPE_SECRET_KEY! },
191
+ database: sqliteAdapter({ url: "file:./payweave.db" }),
192
+ products: [
193
+ plan("free", { includes: [feature("seats", { type: "boolean" })] }),
194
+ plan("pro", {
195
+ price: { amount: 29, currency: "USD", interval: "month" },
196
+ includes: [
197
+ feature("seats", { type: "boolean" }),
198
+ feature("api-calls", { type: "metered", limit: 10_000, resetInterval: "month" }),
199
+ ],
200
+ }),
201
+ ],
202
+ });
203
+
204
+ await payweave.sync(); // push plans/prices to Stripe
205
+ await payweave.subscribe({ customerId: "user_1", planId: "pro" });
206
+ await payweave.check({ customerId: "user_1", featureId: "api-calls", consume: true });
207
+ ```
208
+
209
+ Webhooks keep billing state in sync automatically via `event.apply()` inside
210
+ `constructEvent`. See `payweave/products` and `payweave/db/*` for the full surface.
211
+
212
+ ## Testing without the network
213
+
214
+ ```ts
215
+ import { signWebhook } from "payweave/testing";
216
+
217
+ // Produce a validly-signed body+headers pair for your handler tests:
218
+ const { rawBody, headers } = signWebhook("paystack", payload, webhookSecret);
219
+ ```
220
+
221
+ `payweave/testing` also ships fixture loaders and an MSW server helper so you can test
222
+ your integration entirely offline.
223
+
224
+ ## CLI
225
+
226
+ ```bash
227
+ npx payweave init # scaffold a payweave.ts config for your framework
228
+ npx payweave push # run migrations, then sync products/plans to your providers
229
+ npx payweave status # validate config, database connectivity, migration status
230
+ npx payweave listen # relay webhooks to your local dev server
231
+ ```
232
+
233
+ ## Subpath exports
234
+
235
+ | Import | Contents |
236
+ | --- | --- |
237
+ | `payweave` | Facade: `createPayweave`, `feature`, `plan`, error classes |
238
+ | `payweave/core` | `HttpClient`, errors, `Money`, config, retry, redaction |
239
+ | `payweave/paystack` | Paystack Surface A adapter |
240
+ | `payweave/flutterwave` | Flutterwave Surface A adapter (v3 + v4) |
241
+ | `payweave/unified` | Normalized cross-provider layer + event/status mappings |
242
+ | `payweave/webhooks` | Signature verification + `constructEvent` |
243
+ | `payweave/products` | `feature`, `plan`, period math, billing types |
244
+ | `payweave/db`, `payweave/db/{sqlite,postgres,mysql,mongodb,drizzle,prisma}` | Database adapters |
245
+ | `payweave/testing` | `signWebhook`, fixtures, MSW helpers |
246
+ | `payweave/express`, `payweave/next`, `payweave/fastify` | Framework adapters (in progress) |
247
+
248
+ Every subpath is independently tree-shakeable — importing `payweave/webhooks` in an edge
249
+ function does not pull in the resource modules or any database driver.
250
+
251
+ ## Development
252
+
253
+ This package lives in the Payweave Turborepo. Run everything from the repo root:
254
+
255
+ ```bash
256
+ pnpm install
257
+ pnpm turbo build --filter=payweave
258
+ pnpm --filter payweave test # vitest + coverage
259
+ pnpm --filter payweave test:types # compile-time type assertions
260
+ ```
261
+
262
+ See the root [`AGENTS.md`](../../AGENTS.md) for contribution rules.
263
+
264
+ ## Security
265
+
266
+ Webhook verification is timing-safe and fails closed. Secrets never appear in logs, errors,
267
+ or fixtures. Found a vulnerability? Please disclose it privately rather than opening a public
268
+ issue.
269
+
270
+ ## License
271
+
272
+ [MIT](./LICENSE)