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.
- package/LICENSE +21 -0
- package/README.md +272 -0
- package/dist/_tsup-dts-rollup.d.ts +19470 -0
- package/dist/chunk-4R5OGOCC.js +94 -0
- package/dist/chunk-4R5OGOCC.js.map +1 -0
- package/dist/chunk-535Q3GUN.js +175 -0
- package/dist/chunk-535Q3GUN.js.map +1 -0
- package/dist/chunk-67NRYGRC.js +192 -0
- package/dist/chunk-67NRYGRC.js.map +1 -0
- package/dist/chunk-CGQ73I4I.js +568 -0
- package/dist/chunk-CGQ73I4I.js.map +1 -0
- package/dist/chunk-CJEYDHY6.js +18 -0
- package/dist/chunk-CJEYDHY6.js.map +1 -0
- package/dist/chunk-CR63JAAS.js +3 -0
- package/dist/chunk-CR63JAAS.js.map +1 -0
- package/dist/chunk-E633MKVX.js +1507 -0
- package/dist/chunk-E633MKVX.js.map +1 -0
- package/dist/chunk-FBPOCXRZ.js +1135 -0
- package/dist/chunk-FBPOCXRZ.js.map +1 -0
- package/dist/chunk-HTRGMZFH.js +267 -0
- package/dist/chunk-HTRGMZFH.js.map +1 -0
- package/dist/chunk-IUVGM3K7.js +765 -0
- package/dist/chunk-IUVGM3K7.js.map +1 -0
- package/dist/chunk-JD4OZHRI.js +326 -0
- package/dist/chunk-JD4OZHRI.js.map +1 -0
- package/dist/chunk-NV3MZF7L.js +139 -0
- package/dist/chunk-NV3MZF7L.js.map +1 -0
- package/dist/chunk-NXQBP35U.js +13 -0
- package/dist/chunk-NXQBP35U.js.map +1 -0
- package/dist/chunk-QJHXDZYC.js +412 -0
- package/dist/chunk-QJHXDZYC.js.map +1 -0
- package/dist/chunk-TWZK62TZ.js +83 -0
- package/dist/chunk-TWZK62TZ.js.map +1 -0
- package/dist/cli/index.js +35381 -0
- package/dist/core/index.d.ts +85 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/db/drizzle/index.d.ts +6 -0
- package/dist/db/drizzle/index.js +1532 -0
- package/dist/db/drizzle/index.js.map +1 -0
- package/dist/db/index.d.ts +43 -0
- package/dist/db/index.js +3 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/mongodb/index.d.ts +3 -0
- package/dist/db/mongodb/index.js +934 -0
- package/dist/db/mongodb/index.js.map +1 -0
- package/dist/db/mysql/index.d.ts +1 -0
- package/dist/db/mysql/index.js +12 -0
- package/dist/db/mysql/index.js.map +1 -0
- package/dist/db/postgres/index.d.ts +5 -0
- package/dist/db/postgres/index.js +791 -0
- package/dist/db/postgres/index.js.map +1 -0
- package/dist/db/prisma/index.d.ts +1 -0
- package/dist/db/prisma/index.js +12 -0
- package/dist/db/prisma/index.js.map +1 -0
- package/dist/db/sqlite/index.d.ts +5 -0
- package/dist/db/sqlite/index.js +750 -0
- package/dist/db/sqlite/index.js.map +1 -0
- package/dist/express/index.d.ts +1 -0
- package/dist/express/index.js +3 -0
- package/dist/express/index.js.map +1 -0
- package/dist/fastify/index.d.ts +1 -0
- package/dist/fastify/index.js +3 -0
- package/dist/fastify/index.js.map +1 -0
- package/dist/flutterwave/index.d.ts +27 -0
- package/dist/flutterwave/index.js +9 -0
- package/dist/flutterwave/index.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +3677 -0
- package/dist/index.js.map +1 -0
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.js +3 -0
- package/dist/next/index.js.map +1 -0
- package/dist/paystack/index.d.ts +33 -0
- package/dist/paystack/index.js +9 -0
- package/dist/paystack/index.js.map +1 -0
- package/dist/products/index.d.ts +22 -0
- package/dist/products/index.js +7 -0
- package/dist/products/index.js.map +1 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.js +69 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/unified/index.d.ts +41 -0
- package/dist/unified/index.js +6 -0
- package/dist/unified/index.js.map +1 -0
- package/dist/webhooks/index.d.ts +8 -0
- package/dist/webhooks/index.js +8 -0
- package/dist/webhooks/index.js.map +1 -0
- package/package.json +164 -0
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
import { resolvePlanPricing } from './chunk-535Q3GUN.js';
|
|
2
|
+
import { PayweaveConfigError, redact, PayweaveNetworkError, mapHttpError, PayweaveError, PayweaveAuthError } from './chunk-HTRGMZFH.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
var PAYSTACK_BASE_URL = "https://api.paystack.co";
|
|
6
|
+
var FLW_V3_BASE_URL = "https://api.flutterwave.com/v3";
|
|
7
|
+
var FLW_V4_BASE_URL = "https://api.flutterwave.cloud/f4bexperience";
|
|
8
|
+
var FLW_V4_SANDBOX_URL = "https://api.flutterwave.cloud/developersandbox";
|
|
9
|
+
var FLW_V4_TOKEN_URL = "https://idp.flutterwave.com/realms/flutterwave/protocol/openid-connect/token";
|
|
10
|
+
var STRIPE_BASE_URL = "https://api.stripe.com";
|
|
11
|
+
var STRIPE_API_VERSION = "2026-06-24.dahlia";
|
|
12
|
+
var commonFields = {
|
|
13
|
+
timeoutMs: z.number().int().positive().optional(),
|
|
14
|
+
maxRetries: z.number().int().nonnegative().optional(),
|
|
15
|
+
baseUrl: z.string().min(1).optional(),
|
|
16
|
+
fetch: z.custom((v) => typeof v === "function").optional(),
|
|
17
|
+
environment: z.enum(["test", "live"]).optional(),
|
|
18
|
+
logger: z.custom((v) => typeof v === "function").optional(),
|
|
19
|
+
allowInsecureBaseUrl: z.boolean().optional()
|
|
20
|
+
};
|
|
21
|
+
var paystackConfigSchema = z.object({
|
|
22
|
+
provider: z.literal("paystack"),
|
|
23
|
+
secretKey: z.string().min(1),
|
|
24
|
+
...commonFields
|
|
25
|
+
});
|
|
26
|
+
var flwV3ConfigSchema = z.object({
|
|
27
|
+
provider: z.literal("flutterwave"),
|
|
28
|
+
version: z.literal("v3").default("v3"),
|
|
29
|
+
secretKey: z.string().min(1),
|
|
30
|
+
encryptionKey: z.string().optional(),
|
|
31
|
+
webhookSecret: z.string().optional(),
|
|
32
|
+
...commonFields
|
|
33
|
+
});
|
|
34
|
+
var flwV4ConfigSchema = z.object({
|
|
35
|
+
provider: z.literal("flutterwave"),
|
|
36
|
+
version: z.literal("v4"),
|
|
37
|
+
clientId: z.string().min(1),
|
|
38
|
+
clientSecret: z.string().min(1),
|
|
39
|
+
encryptionKey: z.string().optional(),
|
|
40
|
+
webhookSecret: z.string().optional(),
|
|
41
|
+
...commonFields
|
|
42
|
+
});
|
|
43
|
+
var flutterwaveConfigSchema = z.discriminatedUnion("version", [
|
|
44
|
+
flwV3ConfigSchema,
|
|
45
|
+
flwV4ConfigSchema
|
|
46
|
+
]);
|
|
47
|
+
var sdkConfigSchema = z.preprocess((val) => {
|
|
48
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val) && val.provider === "flutterwave" && !("version" in val)) {
|
|
49
|
+
return { ...val, version: "v3" };
|
|
50
|
+
}
|
|
51
|
+
return val;
|
|
52
|
+
}, z.discriminatedUnion("provider", [paystackConfigSchema, flutterwaveConfigSchema]));
|
|
53
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
54
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
55
|
+
function inferEnvironment(provider, secretKey) {
|
|
56
|
+
if (provider === "paystack") {
|
|
57
|
+
if (secretKey.startsWith("sk_test_")) return "test";
|
|
58
|
+
if (secretKey.startsWith("sk_live_")) return "live";
|
|
59
|
+
throw new PayweaveConfigError(
|
|
60
|
+
"Unrecognized Paystack secret key \u2014 expected an 'sk_test_' or 'sk_live_' prefix.",
|
|
61
|
+
{ provider }
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (provider === "stripe") {
|
|
65
|
+
if (secretKey.startsWith("sk_test_") || secretKey.startsWith("rk_test_")) return "test";
|
|
66
|
+
if (secretKey.startsWith("sk_live_") || secretKey.startsWith("rk_live_")) return "live";
|
|
67
|
+
throw new PayweaveConfigError(
|
|
68
|
+
"Unrecognized Stripe secret key \u2014 expected an 'sk_test_', 'sk_live_', 'rk_test_', or 'rk_live_' prefix.",
|
|
69
|
+
{ provider }
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (secretKey.startsWith("FLWSECK_TEST-")) return "test";
|
|
73
|
+
if (secretKey.startsWith("FLWSECK-")) return "live";
|
|
74
|
+
throw new PayweaveConfigError(
|
|
75
|
+
"Unrecognized Flutterwave secret key \u2014 expected an 'FLWSECK_TEST-' or 'FLWSECK-' prefix.",
|
|
76
|
+
{ provider }
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
function toConfigError(err) {
|
|
80
|
+
if (err instanceof z.ZodError) {
|
|
81
|
+
const detail = err.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
82
|
+
return new PayweaveConfigError(`Invalid Payweave config \u2014 ${detail}`);
|
|
83
|
+
}
|
|
84
|
+
if (err instanceof PayweaveConfigError) return err;
|
|
85
|
+
return new PayweaveConfigError(
|
|
86
|
+
`Invalid Payweave config \u2014 ${err instanceof Error ? err.message : String(err)}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
function guardBaseUrl(baseUrl, allowInsecure, logger, provider) {
|
|
90
|
+
if (/^https:\/\//i.test(baseUrl)) return;
|
|
91
|
+
if (!allowInsecure) {
|
|
92
|
+
throw new PayweaveConfigError(
|
|
93
|
+
`Refusing non-HTTPS baseUrl "${baseUrl}". Set allowInsecureBaseUrl: true to override (testing only).`,
|
|
94
|
+
{ provider }
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
logger?.({
|
|
98
|
+
type: "warn",
|
|
99
|
+
message: `\u26A0\uFE0F INSECURE baseUrl "${baseUrl}" \u2014 credentials will be sent unencrypted. Never do this in production.`
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function resolveConfig(input) {
|
|
103
|
+
let parsed;
|
|
104
|
+
try {
|
|
105
|
+
parsed = sdkConfigSchema.parse(input);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
throw toConfigError(err);
|
|
108
|
+
}
|
|
109
|
+
const timeoutMs = parsed.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
110
|
+
const maxRetries = parsed.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
111
|
+
const allowInsecureBaseUrl = parsed.allowInsecureBaseUrl ?? false;
|
|
112
|
+
const logger = parsed.logger;
|
|
113
|
+
if (parsed.provider === "paystack") {
|
|
114
|
+
const environment2 = resolveKeyedEnvironment("paystack", parsed.secretKey, parsed.environment);
|
|
115
|
+
const baseUrl2 = parsed.baseUrl ?? PAYSTACK_BASE_URL;
|
|
116
|
+
guardBaseUrl(baseUrl2, allowInsecureBaseUrl, logger, "paystack");
|
|
117
|
+
return {
|
|
118
|
+
provider: "paystack",
|
|
119
|
+
version: void 0,
|
|
120
|
+
environment: environment2,
|
|
121
|
+
baseUrl: baseUrl2,
|
|
122
|
+
secretKey: parsed.secretKey,
|
|
123
|
+
clientId: void 0,
|
|
124
|
+
clientSecret: void 0,
|
|
125
|
+
encryptionKey: void 0,
|
|
126
|
+
webhookSecret: void 0,
|
|
127
|
+
timeoutMs,
|
|
128
|
+
maxRetries,
|
|
129
|
+
fetch: parsed.fetch,
|
|
130
|
+
logger,
|
|
131
|
+
allowInsecureBaseUrl,
|
|
132
|
+
tokenUrl: void 0
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (parsed.version === "v4") {
|
|
136
|
+
const environment2 = parsed.environment ?? "test";
|
|
137
|
+
const baseUrl2 = parsed.baseUrl ?? (environment2 === "test" ? FLW_V4_SANDBOX_URL : FLW_V4_BASE_URL);
|
|
138
|
+
guardBaseUrl(baseUrl2, allowInsecureBaseUrl, logger, "flutterwave");
|
|
139
|
+
return {
|
|
140
|
+
provider: "flutterwave",
|
|
141
|
+
version: "v4",
|
|
142
|
+
environment: environment2,
|
|
143
|
+
baseUrl: baseUrl2,
|
|
144
|
+
secretKey: void 0,
|
|
145
|
+
clientId: parsed.clientId,
|
|
146
|
+
clientSecret: parsed.clientSecret,
|
|
147
|
+
encryptionKey: parsed.encryptionKey,
|
|
148
|
+
webhookSecret: parsed.webhookSecret,
|
|
149
|
+
timeoutMs,
|
|
150
|
+
maxRetries,
|
|
151
|
+
fetch: parsed.fetch,
|
|
152
|
+
logger,
|
|
153
|
+
allowInsecureBaseUrl,
|
|
154
|
+
tokenUrl: FLW_V4_TOKEN_URL
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const environment = resolveKeyedEnvironment("flutterwave", parsed.secretKey, parsed.environment);
|
|
158
|
+
const baseUrl = parsed.baseUrl ?? FLW_V3_BASE_URL;
|
|
159
|
+
guardBaseUrl(baseUrl, allowInsecureBaseUrl, logger, "flutterwave");
|
|
160
|
+
return {
|
|
161
|
+
provider: "flutterwave",
|
|
162
|
+
version: "v3",
|
|
163
|
+
environment,
|
|
164
|
+
baseUrl,
|
|
165
|
+
secretKey: parsed.secretKey,
|
|
166
|
+
clientId: void 0,
|
|
167
|
+
clientSecret: void 0,
|
|
168
|
+
encryptionKey: parsed.encryptionKey,
|
|
169
|
+
webhookSecret: parsed.webhookSecret,
|
|
170
|
+
timeoutMs,
|
|
171
|
+
maxRetries,
|
|
172
|
+
fetch: parsed.fetch,
|
|
173
|
+
logger,
|
|
174
|
+
allowInsecureBaseUrl,
|
|
175
|
+
tokenUrl: void 0
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function resolveKeyedEnvironment(provider, secretKey, explicit) {
|
|
179
|
+
const inferred = inferEnvironment(provider, secretKey);
|
|
180
|
+
if (explicit && explicit !== inferred) {
|
|
181
|
+
throw new PayweaveConfigError(
|
|
182
|
+
`environment "${explicit}" conflicts with the ${provider} key prefix (which indicates "${inferred}"). Remove the explicit environment or use a matching key.`,
|
|
183
|
+
{ provider }
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
return inferred;
|
|
187
|
+
}
|
|
188
|
+
var PAYWEAVE_PROVIDER_KEYS = ["stripe", "paystack", "flutterwave"];
|
|
189
|
+
var providerKeySchema = z.enum(PAYWEAVE_PROVIDER_KEYS);
|
|
190
|
+
var stripeProviderConfigSchema = z.object({
|
|
191
|
+
secretKey: z.string().min(1),
|
|
192
|
+
/** `whsec_*` — REQUIRED before any `webhooks.*` call (fail closed); optional here. */
|
|
193
|
+
webhookSecret: z.string().optional(),
|
|
194
|
+
/** Pins the `Stripe-Version` header; defaults to {@link STRIPE_API_VERSION}. */
|
|
195
|
+
apiVersion: z.string().optional(),
|
|
196
|
+
/**
|
|
197
|
+
* Connect platforms only — a connected account id (`acct_*`) sent as the
|
|
198
|
+
* `Stripe-Account` header on every request so calls act on that account
|
|
199
|
+
* (https://docs.stripe.com/connect/authentication — verified 2026-07-12).
|
|
200
|
+
*/
|
|
201
|
+
accountId: z.string().min(1).optional(),
|
|
202
|
+
...commonFields
|
|
203
|
+
});
|
|
204
|
+
var paystackProviderConfigSchema = paystackConfigSchema.omit({ provider: true });
|
|
205
|
+
var flutterwaveProviderConfigSchema = z.preprocess((val) => {
|
|
206
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val)) {
|
|
207
|
+
const withDefaults = { ...val };
|
|
208
|
+
if (!("version" in withDefaults)) withDefaults.version = "v3";
|
|
209
|
+
withDefaults.provider = "flutterwave";
|
|
210
|
+
return withDefaults;
|
|
211
|
+
}
|
|
212
|
+
return val;
|
|
213
|
+
}, flutterwaveConfigSchema);
|
|
214
|
+
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
215
|
+
var storeHasMethod = (store, method) => isPlainObject(store) && typeof store[method] === "function";
|
|
216
|
+
var isDatabaseAdapter = (v) => isPlainObject(v) && typeof v.dialect === "string" && typeof v.transaction === "function" && storeHasMethod(v.customers, "upsert") && storeHasMethod(v.plans, "pushVersion") && storeHasMethod(v.subscriptions, "getActive") && storeHasMethod(v.balances, "consume") && storeHasMethod(v.webhookEvents, "claim") && storeHasMethod(v.migrations, "apply");
|
|
217
|
+
var databaseAdapterSchema = z.custom(
|
|
218
|
+
isDatabaseAdapter,
|
|
219
|
+
"expected a payweave/db/* database adapter object"
|
|
220
|
+
);
|
|
221
|
+
var isPlan = (v) => isPlainObject(v) && typeof v.id === "string" && typeof v.default === "boolean" && Array.isArray(v.includes);
|
|
222
|
+
var planSchema = z.custom(
|
|
223
|
+
isPlan,
|
|
224
|
+
"expected a plan() definition (see plans-and-features.md)"
|
|
225
|
+
);
|
|
226
|
+
var payweaveConfigSchema = z.strictObject({
|
|
227
|
+
// ── Providers (at least one — rule 2, enforced in the resolver) ──
|
|
228
|
+
stripe: stripeProviderConfigSchema.optional(),
|
|
229
|
+
paystack: paystackProviderConfigSchema.optional(),
|
|
230
|
+
flutterwave: flutterwaveProviderConfigSchema.optional(),
|
|
231
|
+
/** Routing target for unified/billing calls — must name a configured key (rule 3). */
|
|
232
|
+
defaultProvider: providerKeySchema.optional(),
|
|
233
|
+
// ── Billing platform (billing surface activates when present) ──
|
|
234
|
+
database: databaseAdapterSchema.optional(),
|
|
235
|
+
products: z.array(planSchema).optional(),
|
|
236
|
+
/** ISO 4217 — used by plan prices without an explicit currency. */
|
|
237
|
+
defaultCurrency: z.string().min(1).optional(),
|
|
238
|
+
// ── Common transport options (shared across providers) ──
|
|
239
|
+
timeoutMs: commonFields.timeoutMs,
|
|
240
|
+
maxRetries: commonFields.maxRetries,
|
|
241
|
+
fetch: commonFields.fetch,
|
|
242
|
+
logger: commonFields.logger,
|
|
243
|
+
/** Explicit env — per-provider key inference still applies; conflicts throw (rule 4). */
|
|
244
|
+
environment: commonFields.environment
|
|
245
|
+
});
|
|
246
|
+
var AT_LEAST_ONE_PROVIDER = "configure at least one provider \u2014 e.g. createPayweave({ stripe: { secretKey } })";
|
|
247
|
+
function compact(obj) {
|
|
248
|
+
const out = {};
|
|
249
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
250
|
+
if (value !== void 0) out[key] = value;
|
|
251
|
+
}
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
254
|
+
function rootTransport(parsed) {
|
|
255
|
+
return compact({
|
|
256
|
+
timeoutMs: parsed.timeoutMs,
|
|
257
|
+
maxRetries: parsed.maxRetries,
|
|
258
|
+
fetch: parsed.fetch,
|
|
259
|
+
logger: parsed.logger,
|
|
260
|
+
environment: parsed.environment
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function resolveStripeEntry(sub, parsed) {
|
|
264
|
+
const logger = sub.logger ?? parsed.logger;
|
|
265
|
+
const allowInsecureBaseUrl = sub.allowInsecureBaseUrl ?? false;
|
|
266
|
+
const environment = resolveKeyedEnvironment(
|
|
267
|
+
"stripe",
|
|
268
|
+
sub.secretKey,
|
|
269
|
+
sub.environment ?? parsed.environment
|
|
270
|
+
);
|
|
271
|
+
const baseUrl = sub.baseUrl ?? STRIPE_BASE_URL;
|
|
272
|
+
guardBaseUrl(baseUrl, allowInsecureBaseUrl, logger, "stripe");
|
|
273
|
+
return {
|
|
274
|
+
provider: "stripe",
|
|
275
|
+
version: void 0,
|
|
276
|
+
environment,
|
|
277
|
+
baseUrl,
|
|
278
|
+
secretKey: sub.secretKey,
|
|
279
|
+
clientId: void 0,
|
|
280
|
+
clientSecret: void 0,
|
|
281
|
+
encryptionKey: void 0,
|
|
282
|
+
webhookSecret: sub.webhookSecret,
|
|
283
|
+
timeoutMs: sub.timeoutMs ?? parsed.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
284
|
+
maxRetries: sub.maxRetries ?? parsed.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
285
|
+
fetch: sub.fetch ?? parsed.fetch,
|
|
286
|
+
logger,
|
|
287
|
+
allowInsecureBaseUrl,
|
|
288
|
+
tokenUrl: void 0,
|
|
289
|
+
apiVersion: sub.apiVersion,
|
|
290
|
+
accountId: sub.accountId
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function resolveLegacyEntry(key, sub, parsed) {
|
|
294
|
+
const merged = { ...rootTransport(parsed), ...compact({ ...sub }), provider: key };
|
|
295
|
+
return { ...resolveConfig(merged), apiVersion: void 0 };
|
|
296
|
+
}
|
|
297
|
+
function assertUniquePlanIds(products) {
|
|
298
|
+
const seen = /* @__PURE__ */ new Set();
|
|
299
|
+
for (const p of products) {
|
|
300
|
+
if (seen.has(p.id)) {
|
|
301
|
+
throw new PayweaveConfigError(
|
|
302
|
+
`duplicate plan id "${p.id}" \u2014 plan ids must be unique across products.`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
seen.add(p.id);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function assertOneDefaultPerGroup(products) {
|
|
309
|
+
const defaultPlanIdByGroup = /* @__PURE__ */ new Map();
|
|
310
|
+
for (const p of products) {
|
|
311
|
+
if (!p.default || p.group === void 0) continue;
|
|
312
|
+
const existing = defaultPlanIdByGroup.get(p.group);
|
|
313
|
+
if (existing !== void 0) {
|
|
314
|
+
throw new PayweaveConfigError(
|
|
315
|
+
`group "${p.group}" has more than one default plan ("${existing}" and "${p.id}") \u2014 only one plan per group can be default: true.`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
defaultPlanIdByGroup.set(p.group, p.id);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function assertNoConflictingFeatureTypes(products) {
|
|
322
|
+
const typeByFeatureId = /* @__PURE__ */ new Map();
|
|
323
|
+
for (const p of products) {
|
|
324
|
+
for (const inclusion of p.includes) {
|
|
325
|
+
const existing = typeByFeatureId.get(inclusion.featureId);
|
|
326
|
+
if (existing === void 0) {
|
|
327
|
+
typeByFeatureId.set(inclusion.featureId, { type: inclusion.type, planId: p.id });
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (existing.type !== inclusion.type) {
|
|
331
|
+
throw new PayweaveConfigError(
|
|
332
|
+
`feature "${inclusion.featureId}" is used as both "${existing.type}" (plan "${existing.planId}") and "${inclusion.type}" (plan "${p.id}") \u2014 a feature must have the same type everywhere.`
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function resolveProducts(products, defaultCurrency) {
|
|
339
|
+
if (products === void 0) return void 0;
|
|
340
|
+
assertUniquePlanIds(products);
|
|
341
|
+
assertOneDefaultPerGroup(products);
|
|
342
|
+
assertNoConflictingFeatureTypes(products);
|
|
343
|
+
return products.map((p) => {
|
|
344
|
+
if (p.price === void 0) {
|
|
345
|
+
return { ...p, price: void 0 };
|
|
346
|
+
}
|
|
347
|
+
const currency = p.price.currency ?? defaultCurrency;
|
|
348
|
+
if (currency === void 0) {
|
|
349
|
+
throw new PayweaveConfigError(
|
|
350
|
+
`plan "${p.id}": price has no currency \u2014 set price.currency or configure defaultCurrency.`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
return { ...p, price: resolvePlanPricing(p, currency) };
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
function resolvePayweaveConfig(input) {
|
|
357
|
+
let parsed;
|
|
358
|
+
try {
|
|
359
|
+
parsed = payweaveConfigSchema.parse(input);
|
|
360
|
+
} catch (err) {
|
|
361
|
+
throw toConfigError(err);
|
|
362
|
+
}
|
|
363
|
+
const providers = PAYWEAVE_PROVIDER_KEYS.filter((key) => parsed[key] !== void 0);
|
|
364
|
+
const [firstProvider] = providers;
|
|
365
|
+
if (firstProvider === void 0) {
|
|
366
|
+
throw new PayweaveConfigError(AT_LEAST_ONE_PROVIDER);
|
|
367
|
+
}
|
|
368
|
+
let defaultProvider;
|
|
369
|
+
if (parsed.defaultProvider !== void 0) {
|
|
370
|
+
if (!providers.includes(parsed.defaultProvider)) {
|
|
371
|
+
throw new PayweaveConfigError(
|
|
372
|
+
`defaultProvider "${parsed.defaultProvider}" is not a configured provider \u2014 configured: ${providers.join(", ")}.`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
defaultProvider = parsed.defaultProvider;
|
|
376
|
+
} else if (providers.length === 1) {
|
|
377
|
+
defaultProvider = firstProvider;
|
|
378
|
+
} else {
|
|
379
|
+
throw new PayweaveConfigError(
|
|
380
|
+
`multiple providers configured (${providers.join(", ")}) \u2014 set defaultProvider to one of them.`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
const providerConfigs = {};
|
|
384
|
+
const environments = [];
|
|
385
|
+
if (parsed.stripe !== void 0) {
|
|
386
|
+
const entry = resolveStripeEntry(parsed.stripe, parsed);
|
|
387
|
+
providerConfigs.stripe = entry;
|
|
388
|
+
environments.push(["stripe", entry.environment]);
|
|
389
|
+
}
|
|
390
|
+
if (parsed.paystack !== void 0) {
|
|
391
|
+
const entry = resolveLegacyEntry("paystack", parsed.paystack, parsed);
|
|
392
|
+
providerConfigs.paystack = entry;
|
|
393
|
+
environments.push(["paystack", entry.environment]);
|
|
394
|
+
}
|
|
395
|
+
if (parsed.flutterwave !== void 0) {
|
|
396
|
+
const entry = resolveLegacyEntry("flutterwave", parsed.flutterwave, parsed);
|
|
397
|
+
providerConfigs.flutterwave = entry;
|
|
398
|
+
environments.push(["flutterwave", entry.environment]);
|
|
399
|
+
}
|
|
400
|
+
if (parsed.environment !== void 0) {
|
|
401
|
+
for (const [key, env] of environments) {
|
|
402
|
+
if (env !== parsed.environment) {
|
|
403
|
+
throw new PayweaveConfigError(
|
|
404
|
+
`environment "${parsed.environment}" conflicts with the ${key} provider's resolved environment "${env}". Remove the explicit environment or align the ${key} config.`,
|
|
405
|
+
{ provider: key }
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const distinctEnvs = new Set(environments.map(([, env]) => env));
|
|
411
|
+
if (distinctEnvs.size > 1) {
|
|
412
|
+
const detail = environments.map(([key, env]) => `${key} is "${env}"`).join(", ");
|
|
413
|
+
throw new PayweaveConfigError(
|
|
414
|
+
`mixed environments across providers \u2014 ${detail}. One Payweave client must be all-test or all-live; use separate clients to mix.`
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
const firstEnvironment = environments[0];
|
|
418
|
+
if (firstEnvironment === void 0) {
|
|
419
|
+
throw new PayweaveConfigError(AT_LEAST_ONE_PROVIDER);
|
|
420
|
+
}
|
|
421
|
+
if (parsed.products !== void 0 && parsed.database === void 0) {
|
|
422
|
+
throw new PayweaveConfigError("plans need a database \u2014 pass a payweave/db/* adapter");
|
|
423
|
+
}
|
|
424
|
+
const products = resolveProducts(parsed.products, parsed.defaultCurrency);
|
|
425
|
+
return {
|
|
426
|
+
providers,
|
|
427
|
+
defaultProvider,
|
|
428
|
+
environment: firstEnvironment[1],
|
|
429
|
+
providerConfigs,
|
|
430
|
+
database: parsed.database,
|
|
431
|
+
products,
|
|
432
|
+
defaultCurrency: parsed.defaultCurrency,
|
|
433
|
+
timeoutMs: parsed.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
434
|
+
maxRetries: parsed.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
435
|
+
fetch: parsed.fetch,
|
|
436
|
+
logger: parsed.logger
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/core/retry.ts
|
|
441
|
+
var DEFAULT_RETRY_POLICY = {
|
|
442
|
+
maxRetries: 2,
|
|
443
|
+
baseMs: 250,
|
|
444
|
+
capMs: 8e3
|
|
445
|
+
};
|
|
446
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
447
|
+
var RETRY_AFTER_CAP_MS = 3e4;
|
|
448
|
+
function isRetryableStatus(status) {
|
|
449
|
+
return RETRYABLE_STATUSES.has(status);
|
|
450
|
+
}
|
|
451
|
+
function isRetryableRequest(method, idempotencyKey) {
|
|
452
|
+
return method.toUpperCase() === "GET" || idempotencyKey != null;
|
|
453
|
+
}
|
|
454
|
+
function backoffDelay(attempt, policy = DEFAULT_RETRY_POLICY, rng = Math.random) {
|
|
455
|
+
const ceiling = Math.min(policy.capMs, policy.baseMs * 2 ** attempt);
|
|
456
|
+
return Math.floor(rng() * ceiling);
|
|
457
|
+
}
|
|
458
|
+
function parseRetryAfter(headerValue, now = Date.now()) {
|
|
459
|
+
if (headerValue == null) return null;
|
|
460
|
+
const trimmed = headerValue.trim();
|
|
461
|
+
if (trimmed === "") return null;
|
|
462
|
+
if (/^\d+$/.test(trimmed)) {
|
|
463
|
+
const seconds = Number(trimmed);
|
|
464
|
+
return Math.min(seconds * 1e3, RETRY_AFTER_CAP_MS);
|
|
465
|
+
}
|
|
466
|
+
const when = Date.parse(trimmed);
|
|
467
|
+
if (!Number.isNaN(when)) {
|
|
468
|
+
return Math.min(Math.max(0, when - now), RETRY_AFTER_CAP_MS);
|
|
469
|
+
}
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/core/version.ts
|
|
474
|
+
var SDK_VERSION = "0.0.0";
|
|
475
|
+
|
|
476
|
+
// src/core/http.ts
|
|
477
|
+
function jsonBodyEncoder(body) {
|
|
478
|
+
return { contentType: "application/json", body: JSON.stringify(body) };
|
|
479
|
+
}
|
|
480
|
+
function bearer(secretKey) {
|
|
481
|
+
return {
|
|
482
|
+
async applyAuth(init) {
|
|
483
|
+
init.headers.set("Authorization", `Bearer ${secretKey}`);
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
function oauthClientCredentials(opts) {
|
|
488
|
+
const doFetch = opts.fetch ?? fetch;
|
|
489
|
+
let token = null;
|
|
490
|
+
let refreshAtMs = 0;
|
|
491
|
+
let inflight = null;
|
|
492
|
+
async function fetchToken() {
|
|
493
|
+
const body = new URLSearchParams({
|
|
494
|
+
grant_type: "client_credentials",
|
|
495
|
+
client_id: opts.clientId,
|
|
496
|
+
client_secret: opts.clientSecret
|
|
497
|
+
});
|
|
498
|
+
let res;
|
|
499
|
+
try {
|
|
500
|
+
res = await doFetch(opts.tokenUrl, {
|
|
501
|
+
method: "POST",
|
|
502
|
+
headers: {
|
|
503
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
504
|
+
Accept: "application/json"
|
|
505
|
+
},
|
|
506
|
+
body: body.toString()
|
|
507
|
+
});
|
|
508
|
+
} catch (err) {
|
|
509
|
+
throw new PayweaveNetworkError("Failed to reach the Flutterwave v4 token endpoint.", {
|
|
510
|
+
provider: "flutterwave",
|
|
511
|
+
cause: err
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
if (!res.ok) {
|
|
515
|
+
throw new PayweaveAuthError(
|
|
516
|
+
`Flutterwave v4 token request failed (${res.status}).`,
|
|
517
|
+
{ provider: "flutterwave", httpStatus: res.status }
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
const json = await res.json();
|
|
521
|
+
if (typeof json.access_token !== "string") {
|
|
522
|
+
throw new PayweaveAuthError("Flutterwave v4 token response had no access_token.", {
|
|
523
|
+
provider: "flutterwave"
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
const ttlSeconds = typeof json.expires_in === "number" ? json.expires_in : 600;
|
|
527
|
+
refreshAtMs = Date.now() + ttlSeconds * 1e3 * 0.8;
|
|
528
|
+
token = json.access_token;
|
|
529
|
+
return token;
|
|
530
|
+
}
|
|
531
|
+
async function getToken(force) {
|
|
532
|
+
if (!force && token !== null && Date.now() < refreshAtMs) return token;
|
|
533
|
+
if (inflight) return inflight;
|
|
534
|
+
inflight = fetchToken().finally(() => {
|
|
535
|
+
inflight = null;
|
|
536
|
+
});
|
|
537
|
+
return inflight;
|
|
538
|
+
}
|
|
539
|
+
return {
|
|
540
|
+
async applyAuth(init) {
|
|
541
|
+
const t = await getToken(false);
|
|
542
|
+
init.headers.set("Authorization", `Bearer ${t}`);
|
|
543
|
+
},
|
|
544
|
+
async refresh() {
|
|
545
|
+
await getToken(true);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function sleep(ms) {
|
|
550
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
551
|
+
}
|
|
552
|
+
function isAbortError(err) {
|
|
553
|
+
return err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
|
|
554
|
+
}
|
|
555
|
+
var HttpClient = class {
|
|
556
|
+
baseUrl;
|
|
557
|
+
auth;
|
|
558
|
+
provider;
|
|
559
|
+
timeoutMs;
|
|
560
|
+
policy;
|
|
561
|
+
doFetch;
|
|
562
|
+
logger;
|
|
563
|
+
userAgent;
|
|
564
|
+
encodeBody;
|
|
565
|
+
constructor(options) {
|
|
566
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
567
|
+
this.auth = options.auth;
|
|
568
|
+
this.provider = options.provider;
|
|
569
|
+
this.timeoutMs = options.timeoutMs ?? 3e4;
|
|
570
|
+
this.policy = {
|
|
571
|
+
...DEFAULT_RETRY_POLICY,
|
|
572
|
+
maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries
|
|
573
|
+
};
|
|
574
|
+
this.doFetch = options.fetch ?? fetch;
|
|
575
|
+
this.logger = options.logger;
|
|
576
|
+
this.userAgent = options.userAgent ?? `payweave/${SDK_VERSION} (${options.provider})`;
|
|
577
|
+
this.encodeBody = options.bodyEncoder ?? jsonBodyEncoder;
|
|
578
|
+
}
|
|
579
|
+
buildUrl(path, query) {
|
|
580
|
+
const rel = path.startsWith("/") ? path : `/${path}`;
|
|
581
|
+
const url = new URL(this.baseUrl + rel);
|
|
582
|
+
if (query) {
|
|
583
|
+
for (const [key, value] of Object.entries(query)) {
|
|
584
|
+
if (value === void 0 || value === null) continue;
|
|
585
|
+
url.searchParams.set(key, String(value));
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return url.toString();
|
|
589
|
+
}
|
|
590
|
+
log(event) {
|
|
591
|
+
this.logger?.(event);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Execute a request with auth, timeout, retry, and error mapping. On 2xx,
|
|
595
|
+
* JSON-parses and (if `schema` given) `safeParse`s — drift is logged and the
|
|
596
|
+
* raw JSON returned, never thrown.
|
|
597
|
+
*/
|
|
598
|
+
async request(opts) {
|
|
599
|
+
const method = opts.method.toUpperCase();
|
|
600
|
+
const url = this.buildUrl(opts.path, opts.query);
|
|
601
|
+
const eligible = isRetryableRequest(method, opts.idempotencyKey);
|
|
602
|
+
const encoded = opts.body !== void 0 ? this.encodeBody(opts.body) : void 0;
|
|
603
|
+
let attempt = 0;
|
|
604
|
+
let did401Refresh = false;
|
|
605
|
+
for (; ; ) {
|
|
606
|
+
const headers = new Headers();
|
|
607
|
+
headers.set("Accept", "application/json");
|
|
608
|
+
headers.set("User-Agent", this.userAgent);
|
|
609
|
+
if (encoded !== void 0) headers.set("Content-Type", encoded.contentType);
|
|
610
|
+
if (opts.idempotencyKey) headers.set("Idempotency-Key", opts.idempotencyKey);
|
|
611
|
+
const signal = AbortSignal.timeout(opts.timeoutMs ?? this.timeoutMs);
|
|
612
|
+
let res;
|
|
613
|
+
try {
|
|
614
|
+
await this.auth.applyAuth({ headers });
|
|
615
|
+
this.log({
|
|
616
|
+
type: "request",
|
|
617
|
+
provider: this.provider,
|
|
618
|
+
method,
|
|
619
|
+
url,
|
|
620
|
+
attempt,
|
|
621
|
+
headers: redact(headers),
|
|
622
|
+
body: redact(opts.body)
|
|
623
|
+
});
|
|
624
|
+
res = await this.doFetch(url, {
|
|
625
|
+
method,
|
|
626
|
+
headers,
|
|
627
|
+
...encoded !== void 0 ? { body: encoded.body } : {},
|
|
628
|
+
signal
|
|
629
|
+
});
|
|
630
|
+
} catch (err2) {
|
|
631
|
+
const known = err2 instanceof PayweaveError;
|
|
632
|
+
const finalErr = known ? err2 : new PayweaveNetworkError(
|
|
633
|
+
isAbortError(err2) ? `Request to ${this.provider} timed out after ${opts.timeoutMs ?? this.timeoutMs}ms.` : `Network error contacting ${this.provider}.`,
|
|
634
|
+
{ provider: this.provider, cause: err2 }
|
|
635
|
+
);
|
|
636
|
+
if (eligible && finalErr.isRetryable && attempt < this.policy.maxRetries) {
|
|
637
|
+
const delay = backoffDelay(attempt, this.policy);
|
|
638
|
+
this.log({
|
|
639
|
+
type: "retry",
|
|
640
|
+
provider: this.provider,
|
|
641
|
+
attempt,
|
|
642
|
+
reason: known ? "auth" : "network",
|
|
643
|
+
delay
|
|
644
|
+
});
|
|
645
|
+
await sleep(delay);
|
|
646
|
+
attempt += 1;
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
this.log({ type: "error", provider: this.provider, error: finalErr.toJSON() });
|
|
650
|
+
throw finalErr;
|
|
651
|
+
}
|
|
652
|
+
if (res.ok) {
|
|
653
|
+
const json = await this.readJson(res);
|
|
654
|
+
this.log({
|
|
655
|
+
type: "response",
|
|
656
|
+
provider: this.provider,
|
|
657
|
+
status: res.status,
|
|
658
|
+
body: redact(json)
|
|
659
|
+
});
|
|
660
|
+
if (opts.schema) {
|
|
661
|
+
const parsed = opts.schema.safeParse(json);
|
|
662
|
+
if (!parsed.success) {
|
|
663
|
+
this.log({
|
|
664
|
+
type: "schema_drift",
|
|
665
|
+
provider: this.provider,
|
|
666
|
+
path: opts.path,
|
|
667
|
+
issues: parsed.error.issues.map((i) => ({
|
|
668
|
+
path: i.path.join("."),
|
|
669
|
+
message: i.message
|
|
670
|
+
}))
|
|
671
|
+
});
|
|
672
|
+
return json;
|
|
673
|
+
}
|
|
674
|
+
return parsed.data;
|
|
675
|
+
}
|
|
676
|
+
return json;
|
|
677
|
+
}
|
|
678
|
+
const errorBody = await this.readJson(res);
|
|
679
|
+
const retryAfterMs = parseRetryAfter(res.headers.get("retry-after"));
|
|
680
|
+
const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-requestid") ?? res.headers.get("request-id") ?? void 0;
|
|
681
|
+
if (res.status === 401 && this.auth.refresh && !did401Refresh) {
|
|
682
|
+
did401Refresh = true;
|
|
683
|
+
this.log({ type: "retry", provider: this.provider, attempt, reason: "401-refresh" });
|
|
684
|
+
await this.auth.refresh();
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (isRetryableStatus(res.status) && eligible && attempt < this.policy.maxRetries) {
|
|
688
|
+
const delay = retryAfterMs ?? backoffDelay(attempt, this.policy);
|
|
689
|
+
this.log({
|
|
690
|
+
type: "retry",
|
|
691
|
+
provider: this.provider,
|
|
692
|
+
attempt,
|
|
693
|
+
reason: `status-${res.status}`,
|
|
694
|
+
delay
|
|
695
|
+
});
|
|
696
|
+
await sleep(delay);
|
|
697
|
+
attempt += 1;
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
const err = mapHttpError(this.provider, res.status, errorBody, {
|
|
701
|
+
...retryAfterMs !== null ? { retryAfterMs } : {},
|
|
702
|
+
...requestId !== void 0 ? { requestId } : {}
|
|
703
|
+
});
|
|
704
|
+
this.log({ type: "error", provider: this.provider, error: err.toJSON() });
|
|
705
|
+
throw err;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
async readJson(res) {
|
|
709
|
+
const text = await res.text();
|
|
710
|
+
if (text === "") return void 0;
|
|
711
|
+
try {
|
|
712
|
+
return JSON.parse(text);
|
|
713
|
+
} catch {
|
|
714
|
+
return text;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
function readHeader(headers, name) {
|
|
719
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
720
|
+
return headers.get(name) ?? void 0;
|
|
721
|
+
}
|
|
722
|
+
const lower = name.toLowerCase();
|
|
723
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
724
|
+
if (key.toLowerCase() === lower) {
|
|
725
|
+
return Array.isArray(value) ? value[0] : value;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return void 0;
|
|
729
|
+
}
|
|
730
|
+
var isFn = (v) => typeof v === "function";
|
|
731
|
+
var fnSchema = z.custom(isFn, {
|
|
732
|
+
message: "expected a function"
|
|
733
|
+
});
|
|
734
|
+
var envSpecSchema = z.object({ baseUrl: z.string().min(1) });
|
|
735
|
+
var zodSchemaSchema = z.custom((v) => v instanceof z.ZodType, {
|
|
736
|
+
message: "expected a zod schema"
|
|
737
|
+
});
|
|
738
|
+
var providerAdapterSchema = z.object({
|
|
739
|
+
id: z.string().min(1),
|
|
740
|
+
configKey: z.string().min(1),
|
|
741
|
+
configSchema: zodSchemaSchema,
|
|
742
|
+
environments: z.object({ test: envSpecSchema, live: envSpecSchema }),
|
|
743
|
+
inferEnvironment: fnSchema,
|
|
744
|
+
createHttp: fnSchema,
|
|
745
|
+
webhooks: z.object({
|
|
746
|
+
signatureHeader: z.string().min(1),
|
|
747
|
+
verify: fnSchema,
|
|
748
|
+
parse: fnSchema,
|
|
749
|
+
toUnified: fnSchema
|
|
750
|
+
}),
|
|
751
|
+
unified: z.record(z.string(), z.unknown()).optional(),
|
|
752
|
+
billing: z.record(z.string(), z.unknown()).optional()
|
|
753
|
+
});
|
|
754
|
+
function defineProvider(adapter) {
|
|
755
|
+
const result = providerAdapterSchema.safeParse(adapter);
|
|
756
|
+
if (!result.success) {
|
|
757
|
+
const detail = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
758
|
+
throw new PayweaveConfigError(`Invalid provider adapter \u2014 ${detail}`);
|
|
759
|
+
}
|
|
760
|
+
return adapter;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
export { DEFAULT_MAX_RETRIES, DEFAULT_RETRY_POLICY, DEFAULT_TIMEOUT_MS, FLW_V3_BASE_URL, FLW_V4_BASE_URL, FLW_V4_SANDBOX_URL, FLW_V4_TOKEN_URL, HttpClient, PAYSTACK_BASE_URL, PAYWEAVE_PROVIDER_KEYS, RETRYABLE_STATUSES, RETRY_AFTER_CAP_MS, SDK_VERSION, STRIPE_API_VERSION, STRIPE_BASE_URL, backoffDelay, bearer, defineProvider, flutterwaveProviderConfigSchema, inferEnvironment, isRetryableRequest, isRetryableStatus, oauthClientCredentials, parseRetryAfter, paystackProviderConfigSchema, payweaveConfigSchema, readHeader, resolveConfig, resolvePayweaveConfig, sdkConfigSchema, stripeProviderConfigSchema };
|
|
764
|
+
//# sourceMappingURL=chunk-IUVGM3K7.js.map
|
|
765
|
+
//# sourceMappingURL=chunk-IUVGM3K7.js.map
|