@alexasomba/better-auth-paystack 0.1.0 → 0.2.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/README.md +94 -66
- package/dist/client.d.mts +5 -12
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +4 -1
- package/dist/client.mjs.map +1 -1
- package/dist/{index-DWhjFOp2.d.mts → index-Bz5N0iP1.d.mts} +139 -52
- package/dist/index-Bz5N0iP1.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +266 -349
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -13
- package/dist/index-DWhjFOp2.d.mts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,296 +1,11 @@
|
|
|
1
|
+
import { defineErrorCodes } from "@better-auth/core/utils";
|
|
1
2
|
import { defu } from "defu";
|
|
2
|
-
import {
|
|
3
|
+
import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
|
|
3
4
|
import { HIDE_METADATA, logger } from "better-auth";
|
|
4
5
|
import { APIError, getSessionFromCtx, originCheck, sessionMiddleware } from "better-auth/api";
|
|
5
6
|
import * as z from "zod/v4";
|
|
6
7
|
import { mergeSchema } from "better-auth/db";
|
|
7
8
|
|
|
8
|
-
//#region node_modules/.pnpm/@better-auth+core@1.4.7_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.21_better-call_d24665956e428978271bbb947eda0893/node_modules/@better-auth/core/dist/env-DbssmzoK.mjs
|
|
9
|
-
const _envShim = Object.create(null);
|
|
10
|
-
const _getEnv = (useShim) => globalThis.process?.env || globalThis.Deno?.env.toObject() || globalThis.__env__ || (useShim ? _envShim : globalThis);
|
|
11
|
-
const env = new Proxy(_envShim, {
|
|
12
|
-
get(_, prop) {
|
|
13
|
-
return _getEnv()[prop] ?? _envShim[prop];
|
|
14
|
-
},
|
|
15
|
-
has(_, prop) {
|
|
16
|
-
return prop in _getEnv() || prop in _envShim;
|
|
17
|
-
},
|
|
18
|
-
set(_, prop, value) {
|
|
19
|
-
const env$1 = _getEnv(true);
|
|
20
|
-
env$1[prop] = value;
|
|
21
|
-
return true;
|
|
22
|
-
},
|
|
23
|
-
deleteProperty(_, prop) {
|
|
24
|
-
if (!prop) return false;
|
|
25
|
-
const env$1 = _getEnv(true);
|
|
26
|
-
delete env$1[prop];
|
|
27
|
-
return true;
|
|
28
|
-
},
|
|
29
|
-
ownKeys() {
|
|
30
|
-
const env$1 = _getEnv(true);
|
|
31
|
-
return Object.keys(env$1);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
const nodeENV = typeof process !== "undefined" && process.env && process.env.NODE_ENV || "";
|
|
35
|
-
/**
|
|
36
|
-
* Get environment variable with fallback
|
|
37
|
-
*/
|
|
38
|
-
function getEnvVar(key, fallback) {
|
|
39
|
-
if (typeof process !== "undefined" && process.env) return process.env[key] ?? fallback;
|
|
40
|
-
if (typeof Deno !== "undefined") return Deno.env.get(key) ?? fallback;
|
|
41
|
-
if (typeof Bun !== "undefined") return Bun.env[key] ?? fallback;
|
|
42
|
-
return fallback;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Common environment variables used in Better Auth
|
|
46
|
-
*/
|
|
47
|
-
const ENV = Object.freeze({
|
|
48
|
-
get BETTER_AUTH_SECRET() {
|
|
49
|
-
return getEnvVar("BETTER_AUTH_SECRET");
|
|
50
|
-
},
|
|
51
|
-
get AUTH_SECRET() {
|
|
52
|
-
return getEnvVar("AUTH_SECRET");
|
|
53
|
-
},
|
|
54
|
-
get BETTER_AUTH_TELEMETRY() {
|
|
55
|
-
return getEnvVar("BETTER_AUTH_TELEMETRY");
|
|
56
|
-
},
|
|
57
|
-
get BETTER_AUTH_TELEMETRY_ID() {
|
|
58
|
-
return getEnvVar("BETTER_AUTH_TELEMETRY_ID");
|
|
59
|
-
},
|
|
60
|
-
get NODE_ENV() {
|
|
61
|
-
return getEnvVar("NODE_ENV", "development");
|
|
62
|
-
},
|
|
63
|
-
get PACKAGE_VERSION() {
|
|
64
|
-
return getEnvVar("PACKAGE_VERSION", "0.0.0");
|
|
65
|
-
},
|
|
66
|
-
get BETTER_AUTH_TELEMETRY_ENDPOINT() {
|
|
67
|
-
return getEnvVar("BETTER_AUTH_TELEMETRY_ENDPOINT", "https://telemetry.better-auth.com/v1/track");
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
const COLORS_2 = 1;
|
|
71
|
-
const COLORS_16 = 4;
|
|
72
|
-
const COLORS_256 = 8;
|
|
73
|
-
const COLORS_16m = 24;
|
|
74
|
-
const TERM_ENVS = {
|
|
75
|
-
eterm: COLORS_16,
|
|
76
|
-
cons25: COLORS_16,
|
|
77
|
-
console: COLORS_16,
|
|
78
|
-
cygwin: COLORS_16,
|
|
79
|
-
dtterm: COLORS_16,
|
|
80
|
-
gnome: COLORS_16,
|
|
81
|
-
hurd: COLORS_16,
|
|
82
|
-
jfbterm: COLORS_16,
|
|
83
|
-
konsole: COLORS_16,
|
|
84
|
-
kterm: COLORS_16,
|
|
85
|
-
mlterm: COLORS_16,
|
|
86
|
-
mosh: COLORS_16m,
|
|
87
|
-
putty: COLORS_16,
|
|
88
|
-
st: COLORS_16,
|
|
89
|
-
"rxvt-unicode-24bit": COLORS_16m,
|
|
90
|
-
terminator: COLORS_16m,
|
|
91
|
-
"xterm-kitty": COLORS_16m
|
|
92
|
-
};
|
|
93
|
-
const CI_ENVS_MAP = new Map(Object.entries({
|
|
94
|
-
APPVEYOR: COLORS_256,
|
|
95
|
-
BUILDKITE: COLORS_256,
|
|
96
|
-
CIRCLECI: COLORS_16m,
|
|
97
|
-
DRONE: COLORS_256,
|
|
98
|
-
GITEA_ACTIONS: COLORS_16m,
|
|
99
|
-
GITHUB_ACTIONS: COLORS_16m,
|
|
100
|
-
GITLAB_CI: COLORS_256,
|
|
101
|
-
TRAVIS: COLORS_256
|
|
102
|
-
}));
|
|
103
|
-
const TERM_ENVS_REG_EXP = [
|
|
104
|
-
/ansi/,
|
|
105
|
-
/color/,
|
|
106
|
-
/linux/,
|
|
107
|
-
/direct/,
|
|
108
|
-
/^con[0-9]*x[0-9]/,
|
|
109
|
-
/^rxvt/,
|
|
110
|
-
/^screen/,
|
|
111
|
-
/^xterm/,
|
|
112
|
-
/^vt100/,
|
|
113
|
-
/^vt220/
|
|
114
|
-
];
|
|
115
|
-
function getColorDepth() {
|
|
116
|
-
if (getEnvVar("FORCE_COLOR") !== void 0) switch (getEnvVar("FORCE_COLOR")) {
|
|
117
|
-
case "":
|
|
118
|
-
case "1":
|
|
119
|
-
case "true": return COLORS_16;
|
|
120
|
-
case "2": return COLORS_256;
|
|
121
|
-
case "3": return COLORS_16m;
|
|
122
|
-
default: return COLORS_2;
|
|
123
|
-
}
|
|
124
|
-
if (getEnvVar("NODE_DISABLE_COLORS") !== void 0 && getEnvVar("NODE_DISABLE_COLORS") !== "" || getEnvVar("NO_COLOR") !== void 0 && getEnvVar("NO_COLOR") !== "" || getEnvVar("TERM") === "dumb") return COLORS_2;
|
|
125
|
-
if (getEnvVar("TMUX")) return COLORS_16m;
|
|
126
|
-
if ("TF_BUILD" in env && "AGENT_NAME" in env) return COLORS_16;
|
|
127
|
-
if ("CI" in env) {
|
|
128
|
-
for (const { 0: envName, 1: colors } of CI_ENVS_MAP) if (envName in env) return colors;
|
|
129
|
-
if (getEnvVar("CI_NAME") === "codeship") return COLORS_256;
|
|
130
|
-
return COLORS_2;
|
|
131
|
-
}
|
|
132
|
-
if ("TEAMCITY_VERSION" in env) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.exec(getEnvVar("TEAMCITY_VERSION")) !== null ? COLORS_16 : COLORS_2;
|
|
133
|
-
switch (getEnvVar("TERM_PROGRAM")) {
|
|
134
|
-
case "iTerm.app":
|
|
135
|
-
if (!getEnvVar("TERM_PROGRAM_VERSION") || /^[0-2]\./.exec(getEnvVar("TERM_PROGRAM_VERSION")) !== null) return COLORS_256;
|
|
136
|
-
return COLORS_16m;
|
|
137
|
-
case "HyperTerm":
|
|
138
|
-
case "MacTerm": return COLORS_16m;
|
|
139
|
-
case "Apple_Terminal": return COLORS_256;
|
|
140
|
-
}
|
|
141
|
-
if (getEnvVar("COLORTERM") === "truecolor" || getEnvVar("COLORTERM") === "24bit") return COLORS_16m;
|
|
142
|
-
if (getEnvVar("TERM")) {
|
|
143
|
-
if (/truecolor/.exec(getEnvVar("TERM")) !== null) return COLORS_16m;
|
|
144
|
-
if (/^xterm-256/.exec(getEnvVar("TERM")) !== null) return COLORS_256;
|
|
145
|
-
const termEnv = getEnvVar("TERM").toLowerCase();
|
|
146
|
-
if (TERM_ENVS[termEnv]) return TERM_ENVS[termEnv];
|
|
147
|
-
if (TERM_ENVS_REG_EXP.some((term) => term.exec(termEnv) !== null)) return COLORS_16;
|
|
148
|
-
}
|
|
149
|
-
if (getEnvVar("COLORTERM")) return COLORS_16;
|
|
150
|
-
return COLORS_2;
|
|
151
|
-
}
|
|
152
|
-
const TTY_COLORS = {
|
|
153
|
-
reset: "\x1B[0m",
|
|
154
|
-
bright: "\x1B[1m",
|
|
155
|
-
dim: "\x1B[2m",
|
|
156
|
-
undim: "\x1B[22m",
|
|
157
|
-
underscore: "\x1B[4m",
|
|
158
|
-
blink: "\x1B[5m",
|
|
159
|
-
reverse: "\x1B[7m",
|
|
160
|
-
hidden: "\x1B[8m",
|
|
161
|
-
fg: {
|
|
162
|
-
black: "\x1B[30m",
|
|
163
|
-
red: "\x1B[31m",
|
|
164
|
-
green: "\x1B[32m",
|
|
165
|
-
yellow: "\x1B[33m",
|
|
166
|
-
blue: "\x1B[34m",
|
|
167
|
-
magenta: "\x1B[35m",
|
|
168
|
-
cyan: "\x1B[36m",
|
|
169
|
-
white: "\x1B[37m"
|
|
170
|
-
},
|
|
171
|
-
bg: {
|
|
172
|
-
black: "\x1B[40m",
|
|
173
|
-
red: "\x1B[41m",
|
|
174
|
-
green: "\x1B[42m",
|
|
175
|
-
yellow: "\x1B[43m",
|
|
176
|
-
blue: "\x1B[44m",
|
|
177
|
-
magenta: "\x1B[45m",
|
|
178
|
-
cyan: "\x1B[46m",
|
|
179
|
-
white: "\x1B[47m"
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
const levels = [
|
|
183
|
-
"debug",
|
|
184
|
-
"info",
|
|
185
|
-
"success",
|
|
186
|
-
"warn",
|
|
187
|
-
"error"
|
|
188
|
-
];
|
|
189
|
-
function shouldPublishLog(currentLogLevel, logLevel) {
|
|
190
|
-
return levels.indexOf(logLevel) >= levels.indexOf(currentLogLevel);
|
|
191
|
-
}
|
|
192
|
-
const levelColors = {
|
|
193
|
-
info: TTY_COLORS.fg.blue,
|
|
194
|
-
success: TTY_COLORS.fg.green,
|
|
195
|
-
warn: TTY_COLORS.fg.yellow,
|
|
196
|
-
error: TTY_COLORS.fg.red,
|
|
197
|
-
debug: TTY_COLORS.fg.magenta
|
|
198
|
-
};
|
|
199
|
-
const formatMessage = (level, message, colorsEnabled) => {
|
|
200
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
201
|
-
if (colorsEnabled) return `${TTY_COLORS.dim}${timestamp}${TTY_COLORS.reset} ${levelColors[level]}${level.toUpperCase()}${TTY_COLORS.reset} ${TTY_COLORS.bright}[Better Auth]:${TTY_COLORS.reset} ${message}`;
|
|
202
|
-
return `${timestamp} ${level.toUpperCase()} [Better Auth]: ${message}`;
|
|
203
|
-
};
|
|
204
|
-
const createLogger = (options) => {
|
|
205
|
-
const enabled = options?.disabled !== true;
|
|
206
|
-
const logLevel = options?.level ?? "error";
|
|
207
|
-
const colorsEnabled = options?.disableColors !== void 0 ? !options.disableColors : getColorDepth() !== 1;
|
|
208
|
-
const LogFunc = (level, message, args = []) => {
|
|
209
|
-
if (!enabled || !shouldPublishLog(logLevel, level)) return;
|
|
210
|
-
const formattedMessage = formatMessage(level, message, colorsEnabled);
|
|
211
|
-
if (!options || typeof options.log !== "function") {
|
|
212
|
-
if (level === "error") console.error(formattedMessage, ...args);
|
|
213
|
-
else if (level === "warn") console.warn(formattedMessage, ...args);
|
|
214
|
-
else console.log(formattedMessage, ...args);
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
options.log(level === "success" ? "info" : level, message, ...args);
|
|
218
|
-
};
|
|
219
|
-
return {
|
|
220
|
-
...Object.fromEntries(levels.map((level) => [level, (...[message, ...args]) => LogFunc(level, message, args)])),
|
|
221
|
-
get level() {
|
|
222
|
-
return logLevel;
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
};
|
|
226
|
-
const logger$1 = createLogger();
|
|
227
|
-
|
|
228
|
-
//#endregion
|
|
229
|
-
//#region node_modules/.pnpm/@better-auth+core@1.4.7_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.21_better-call_d24665956e428978271bbb947eda0893/node_modules/@better-auth/core/dist/utils-NloIXYE0.mjs
|
|
230
|
-
function defineErrorCodes(codes) {
|
|
231
|
-
return codes;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
//#endregion
|
|
235
|
-
//#region node_modules/.pnpm/@better-auth+core@1.4.7_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.21_better-call_d24665956e428978271bbb947eda0893/node_modules/@better-auth/core/dist/async_hooks/index.mjs
|
|
236
|
-
const AsyncLocalStoragePromise = import(
|
|
237
|
-
/* @vite-ignore */
|
|
238
|
-
/* webpackIgnore: true */
|
|
239
|
-
"node:async_hooks"
|
|
240
|
-
).then((mod) => mod.AsyncLocalStorage).catch((err) => {
|
|
241
|
-
if ("AsyncLocalStorage" in globalThis) return globalThis.AsyncLocalStorage;
|
|
242
|
-
if (typeof window !== "undefined") return null;
|
|
243
|
-
console.warn("[better-auth] Warning: AsyncLocalStorage is not available in this environment. Some features may not work as expected.");
|
|
244
|
-
console.warn("[better-auth] Please read more about this warning at https://better-auth.com/docs/installation#mount-handler");
|
|
245
|
-
console.warn("[better-auth] If you are using Cloudflare Workers, please see: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag");
|
|
246
|
-
throw err;
|
|
247
|
-
});
|
|
248
|
-
async function getAsyncLocalStorage() {
|
|
249
|
-
const mod = await AsyncLocalStoragePromise;
|
|
250
|
-
if (mod === null) throw new Error("getAsyncLocalStorage is only available in server code");
|
|
251
|
-
else return mod;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
//#endregion
|
|
255
|
-
//#region node_modules/.pnpm/@better-auth+core@1.4.7_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.21_better-call_d24665956e428978271bbb947eda0893/node_modules/@better-auth/core/dist/context-DblZrIwO.mjs
|
|
256
|
-
let currentContextAsyncStorage = null;
|
|
257
|
-
const ensureAsyncStorage$2 = async () => {
|
|
258
|
-
if (!currentContextAsyncStorage) currentContextAsyncStorage = new (await (getAsyncLocalStorage()))();
|
|
259
|
-
return currentContextAsyncStorage;
|
|
260
|
-
};
|
|
261
|
-
async function runWithEndpointContext(context, fn) {
|
|
262
|
-
return (await ensureAsyncStorage$2()).run(context, fn);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
//#endregion
|
|
266
|
-
//#region node_modules/.pnpm/@better-auth+core@1.4.7_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.21_better-call_d24665956e428978271bbb947eda0893/node_modules/@better-auth/core/dist/api/index.mjs
|
|
267
|
-
const optionsMiddleware = createMiddleware(async () => {
|
|
268
|
-
/**
|
|
269
|
-
* This will be passed on the instance of
|
|
270
|
-
* the context. Used to infer the type
|
|
271
|
-
* here.
|
|
272
|
-
*/
|
|
273
|
-
return {};
|
|
274
|
-
});
|
|
275
|
-
const createAuthMiddleware = createMiddleware.create({ use: [optionsMiddleware, createMiddleware(async () => {
|
|
276
|
-
return {};
|
|
277
|
-
})] });
|
|
278
|
-
const use = [optionsMiddleware];
|
|
279
|
-
function createAuthEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
|
|
280
|
-
const path = typeof pathOrOptions === "string" ? pathOrOptions : void 0;
|
|
281
|
-
const options = typeof handlerOrOptions === "object" ? handlerOrOptions : pathOrOptions;
|
|
282
|
-
const handler = typeof handlerOrOptions === "function" ? handlerOrOptions : handlerOrNever;
|
|
283
|
-
if (path) return createEndpoint(path, {
|
|
284
|
-
...options,
|
|
285
|
-
use: [...options?.use || [], ...use]
|
|
286
|
-
}, async (ctx) => runWithEndpointContext(ctx, () => handler(ctx)));
|
|
287
|
-
return createEndpoint({
|
|
288
|
-
...options,
|
|
289
|
-
use: [...options?.use || [], ...use]
|
|
290
|
-
}, async (ctx) => runWithEndpointContext(ctx, () => handler(ctx)));
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
//#endregion
|
|
294
9
|
//#region src/utils.ts
|
|
295
10
|
async function getPlans(subscriptionOptions) {
|
|
296
11
|
if (subscriptionOptions?.enabled) return typeof subscriptionOptions.plans === "function" ? await subscriptionOptions.plans() : subscriptionOptions.plans;
|
|
@@ -299,6 +14,13 @@ async function getPlans(subscriptionOptions) {
|
|
|
299
14
|
async function getPlanByName(options, name) {
|
|
300
15
|
return await getPlans(options.subscription).then((plans) => plans?.find((plan) => plan.name.toLowerCase() === name.toLowerCase()));
|
|
301
16
|
}
|
|
17
|
+
async function getProducts(productOptions) {
|
|
18
|
+
if (productOptions?.products) return typeof productOptions.products === "function" ? await productOptions.products() : productOptions.products;
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
async function getProductByName(options, name) {
|
|
22
|
+
return await getProducts(options.products).then((products) => products?.find((product) => product.name.toLowerCase() === name.toLowerCase()));
|
|
23
|
+
}
|
|
302
24
|
|
|
303
25
|
//#endregion
|
|
304
26
|
//#region src/middleware.ts
|
|
@@ -423,6 +145,22 @@ const paystackWebhook = (options) => {
|
|
|
423
145
|
const eventName = String(event?.event ?? "");
|
|
424
146
|
const data = event?.data;
|
|
425
147
|
try {
|
|
148
|
+
if (eventName === "charge.success") {
|
|
149
|
+
const reference = data?.reference;
|
|
150
|
+
const paystackId = data?.id ? String(data.id) : void 0;
|
|
151
|
+
if (reference) await ctx.context.adapter.update({
|
|
152
|
+
model: "paystackTransaction",
|
|
153
|
+
update: {
|
|
154
|
+
status: "success",
|
|
155
|
+
paystackId,
|
|
156
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
157
|
+
},
|
|
158
|
+
where: [{
|
|
159
|
+
field: "reference",
|
|
160
|
+
value: reference
|
|
161
|
+
}]
|
|
162
|
+
});
|
|
163
|
+
}
|
|
426
164
|
if (eventName === "subscription.create") {
|
|
427
165
|
const subscriptionCode = data?.subscription_code ?? data?.subscription?.subscription_code ?? data?.code;
|
|
428
166
|
const customerCode = data?.customer?.customer_code ?? data?.customer_code ?? data?.customer?.code;
|
|
@@ -506,7 +244,12 @@ const paystackWebhook = (options) => {
|
|
|
506
244
|
});
|
|
507
245
|
};
|
|
508
246
|
const initializeTransactionBodySchema = z.object({
|
|
509
|
-
plan: z.string(),
|
|
247
|
+
plan: z.string().optional(),
|
|
248
|
+
product: z.string().optional(),
|
|
249
|
+
amount: z.number().optional(),
|
|
250
|
+
currency: z.string().optional(),
|
|
251
|
+
email: z.string().optional(),
|
|
252
|
+
metadata: z.record(z.string(), z.any()).optional(),
|
|
510
253
|
referenceId: z.string().optional(),
|
|
511
254
|
callbackURL: z.string().optional()
|
|
512
255
|
});
|
|
@@ -521,60 +264,78 @@ const initializeTransaction = (options) => {
|
|
|
521
264
|
referenceMiddleware(subscriptionOptions, "initialize-transaction")
|
|
522
265
|
] : [sessionMiddleware, originCheck]
|
|
523
266
|
}, async (ctx) => {
|
|
524
|
-
const paystack
|
|
525
|
-
|
|
526
|
-
if (
|
|
527
|
-
const
|
|
528
|
-
if (!(isTrustedOriginFn ? isTrustedOriginFn(ctx.body.callbackURL, { allowRelativePaths: true }) : (() => {
|
|
267
|
+
const paystack = getPaystackOps(options.paystackClient);
|
|
268
|
+
const { plan: planName, product: productName, amount: bodyAmount, currency, email, metadata: extraMetadata, callbackURL } = ctx.body;
|
|
269
|
+
if (callbackURL) {
|
|
270
|
+
const checkTrusted = () => {
|
|
529
271
|
try {
|
|
530
|
-
if (
|
|
272
|
+
if (!callbackURL) return false;
|
|
273
|
+
if (callbackURL.startsWith("/")) return true;
|
|
531
274
|
const baseUrl = ctx.context?.baseURL ?? ctx.request?.url ?? "";
|
|
532
275
|
if (!baseUrl) return false;
|
|
533
276
|
const baseOrigin = new URL(baseUrl).origin;
|
|
534
|
-
return new URL(
|
|
277
|
+
return new URL(callbackURL).origin === baseOrigin;
|
|
535
278
|
} catch {
|
|
536
279
|
return false;
|
|
537
280
|
}
|
|
538
|
-
}
|
|
281
|
+
};
|
|
282
|
+
if (!checkTrusted()) throw new APIError("FORBIDDEN", {
|
|
539
283
|
message: "callbackURL is not a trusted origin.",
|
|
540
284
|
status: 403
|
|
541
285
|
});
|
|
542
286
|
}
|
|
543
287
|
const session = await getSessionFromCtx(ctx);
|
|
544
288
|
if (!session) throw new APIError("UNAUTHORIZED");
|
|
545
|
-
const user
|
|
546
|
-
|
|
547
|
-
const referenceId = ctx.body.referenceId || referenceIdFromCtx || session.user.id;
|
|
548
|
-
if (subscriptionOptions.requireEmailVerification && !user$1.emailVerified) throw new APIError("BAD_REQUEST", {
|
|
289
|
+
const user = session.user;
|
|
290
|
+
if (subscriptionOptions?.enabled && subscriptionOptions.requireEmailVerification && !user.emailVerified) throw new APIError("BAD_REQUEST", {
|
|
549
291
|
code: "EMAIL_VERIFICATION_REQUIRED",
|
|
550
292
|
message: PAYSTACK_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED
|
|
551
293
|
});
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
message:
|
|
556
|
-
|
|
557
|
-
|
|
294
|
+
let plan;
|
|
295
|
+
let product;
|
|
296
|
+
if (planName) {
|
|
297
|
+
if (!subscriptionOptions?.enabled) throw new APIError("BAD_REQUEST", { message: "Subscriptions are not enabled." });
|
|
298
|
+
plan = await getPlanByName(options, planName);
|
|
299
|
+
if (!plan) throw new APIError("BAD_REQUEST", {
|
|
300
|
+
code: "SUBSCRIPTION_PLAN_NOT_FOUND",
|
|
301
|
+
message: PAYSTACK_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND
|
|
302
|
+
});
|
|
303
|
+
} else if (productName) {
|
|
304
|
+
product = await getProductByName(options, productName);
|
|
305
|
+
if (!product) throw new APIError("BAD_REQUEST", { message: `Product '${productName}' not found.` });
|
|
306
|
+
} else if (!bodyAmount) throw new APIError("BAD_REQUEST", { message: "Either 'plan', 'product', or 'amount' is required to initialize a transaction." });
|
|
307
|
+
const amount = bodyAmount || product?.amount;
|
|
308
|
+
const finalCurrency = currency || product?.currency || plan?.currency || "NGN";
|
|
309
|
+
const referenceIdFromCtx = ctx.context.referenceId;
|
|
310
|
+
const referenceId = ctx.body.referenceId || referenceIdFromCtx || session.user.id;
|
|
558
311
|
let url;
|
|
559
312
|
let reference;
|
|
560
313
|
let accessCode;
|
|
561
314
|
try {
|
|
562
315
|
const metadata = JSON.stringify({
|
|
563
316
|
referenceId,
|
|
564
|
-
userId: user
|
|
565
|
-
plan: plan
|
|
317
|
+
userId: user.id,
|
|
318
|
+
plan: plan?.name.toLowerCase(),
|
|
319
|
+
product: product?.name.toLowerCase(),
|
|
320
|
+
...extraMetadata
|
|
566
321
|
});
|
|
567
322
|
const initBody = {
|
|
568
|
-
email: user
|
|
569
|
-
callback_url:
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
invoice_limit: plan.invoiceLimit,
|
|
573
|
-
metadata
|
|
323
|
+
email: email || user.email,
|
|
324
|
+
callback_url: callbackURL,
|
|
325
|
+
metadata,
|
|
326
|
+
currency: finalCurrency
|
|
574
327
|
};
|
|
575
|
-
if (
|
|
576
|
-
|
|
577
|
-
|
|
328
|
+
if (plan) {
|
|
329
|
+
initBody.plan = plan.planCode;
|
|
330
|
+
initBody.invoice_limit = plan.invoiceLimit;
|
|
331
|
+
if (!plan.planCode && plan.amount) initBody.amount = plan.amount;
|
|
332
|
+
} else {
|
|
333
|
+
if (!amount) throw new Error("Amount is required for one-time payments");
|
|
334
|
+
initBody.amount = amount;
|
|
335
|
+
}
|
|
336
|
+
const initRes = unwrapSdkResult(await paystack.transactionInitialize(initBody));
|
|
337
|
+
let data = initRes && typeof initRes === "object" && "status" in initRes && "data" in initRes ? initRes.data : initRes?.data ?? initRes;
|
|
338
|
+
if (data && typeof data === "object" && "status" in data && "data" in data) data = data.data;
|
|
578
339
|
url = data?.authorization_url;
|
|
579
340
|
reference = data?.reference;
|
|
580
341
|
accessCode = data?.access_code;
|
|
@@ -585,8 +346,23 @@ const initializeTransaction = (options) => {
|
|
|
585
346
|
message: error?.message || PAYSTACK_ERROR_CODES.FAILED_TO_INITIALIZE_TRANSACTION
|
|
586
347
|
});
|
|
587
348
|
}
|
|
588
|
-
const paystackCustomerCode = user
|
|
349
|
+
const paystackCustomerCode = user.paystackCustomerCode;
|
|
589
350
|
await ctx.context.adapter.create({
|
|
351
|
+
model: "paystackTransaction",
|
|
352
|
+
data: {
|
|
353
|
+
reference,
|
|
354
|
+
referenceId,
|
|
355
|
+
userId: user.id,
|
|
356
|
+
amount: plan?.amount || amount,
|
|
357
|
+
currency: plan?.currency || currency || "NGN",
|
|
358
|
+
status: "pending",
|
|
359
|
+
plan: plan?.name.toLowerCase(),
|
|
360
|
+
metadata: extraMetadata ? JSON.stringify(extraMetadata) : void 0,
|
|
361
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
362
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
if (plan) await ctx.context.adapter.create({
|
|
590
366
|
model: "subscription",
|
|
591
367
|
data: {
|
|
592
368
|
plan: plan.name.toLowerCase(),
|
|
@@ -616,10 +392,10 @@ const verifyTransaction = (options) => {
|
|
|
616
392
|
referenceMiddleware(subscriptionOptions, "verify-transaction")
|
|
617
393
|
] : [sessionMiddleware, originCheck]
|
|
618
394
|
}, async (ctx) => {
|
|
619
|
-
const paystack
|
|
395
|
+
const paystack = getPaystackOps(options.paystackClient);
|
|
620
396
|
let verifyRes;
|
|
621
397
|
try {
|
|
622
|
-
verifyRes = unwrapSdkResult(await paystack
|
|
398
|
+
verifyRes = unwrapSdkResult(await paystack.transactionVerify(ctx.body.reference));
|
|
623
399
|
} catch (error) {
|
|
624
400
|
ctx.context.logger.error("Failed to verify Paystack transaction", error);
|
|
625
401
|
throw new APIError("BAD_REQUEST", {
|
|
@@ -627,12 +403,26 @@ const verifyTransaction = (options) => {
|
|
|
627
403
|
message: error?.message || PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION
|
|
628
404
|
});
|
|
629
405
|
}
|
|
630
|
-
|
|
406
|
+
let data = verifyRes && typeof verifyRes === "object" && "status" in verifyRes && "data" in verifyRes ? verifyRes.data : verifyRes?.data ?? verifyRes;
|
|
407
|
+
if (data && typeof data === "object" && "status" in data && "data" in data) data = data.data;
|
|
631
408
|
const status = data?.status;
|
|
632
409
|
const reference = data?.reference ?? ctx.body.reference;
|
|
410
|
+
const paystackId = data?.id ? String(data.id) : void 0;
|
|
633
411
|
if (status === "success") try {
|
|
634
412
|
const session = await getSessionFromCtx(ctx);
|
|
635
413
|
const referenceId = ctx.context.referenceId ?? (session?.user)?.id;
|
|
414
|
+
await ctx.context.adapter.update({
|
|
415
|
+
model: "paystackTransaction",
|
|
416
|
+
update: {
|
|
417
|
+
status: "success",
|
|
418
|
+
paystackId,
|
|
419
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
420
|
+
},
|
|
421
|
+
where: [{
|
|
422
|
+
field: "reference",
|
|
423
|
+
value: reference
|
|
424
|
+
}]
|
|
425
|
+
});
|
|
636
426
|
await ctx.context.adapter.update({
|
|
637
427
|
model: "subscription",
|
|
638
428
|
update: {
|
|
@@ -649,7 +439,22 @@ const verifyTransaction = (options) => {
|
|
|
649
439
|
}] : []]
|
|
650
440
|
});
|
|
651
441
|
} catch (e) {
|
|
652
|
-
ctx.context.logger.error("Failed to update subscription after
|
|
442
|
+
ctx.context.logger.error("Failed to update transaction/subscription after verification", e);
|
|
443
|
+
}
|
|
444
|
+
else if (status === "failed" || status === "abandoned") try {
|
|
445
|
+
await ctx.context.adapter.update({
|
|
446
|
+
model: "paystackTransaction",
|
|
447
|
+
update: {
|
|
448
|
+
status,
|
|
449
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
450
|
+
},
|
|
451
|
+
where: [{
|
|
452
|
+
field: "reference",
|
|
453
|
+
value: reference
|
|
454
|
+
}]
|
|
455
|
+
});
|
|
456
|
+
} catch (e) {
|
|
457
|
+
ctx.context.logger.error("Failed to update transaction status", e);
|
|
653
458
|
}
|
|
654
459
|
return ctx.json({
|
|
655
460
|
status,
|
|
@@ -684,6 +489,31 @@ const listSubscriptions = (options) => {
|
|
|
684
489
|
return ctx.json({ subscriptions: res });
|
|
685
490
|
});
|
|
686
491
|
};
|
|
492
|
+
const listTransactions = (options) => {
|
|
493
|
+
const listQuerySchema = z.object({ referenceId: z.string().optional() });
|
|
494
|
+
const subscriptionOptions = options.subscription;
|
|
495
|
+
return createAuthEndpoint("/paystack/transaction/list", {
|
|
496
|
+
method: "GET",
|
|
497
|
+
query: listQuerySchema,
|
|
498
|
+
use: subscriptionOptions?.enabled ? [
|
|
499
|
+
sessionMiddleware,
|
|
500
|
+
originCheck,
|
|
501
|
+
referenceMiddleware(subscriptionOptions, "list-transactions")
|
|
502
|
+
] : [sessionMiddleware, originCheck]
|
|
503
|
+
}, async (ctx) => {
|
|
504
|
+
const session = await getSessionFromCtx(ctx);
|
|
505
|
+
if (!session) throw new APIError("UNAUTHORIZED");
|
|
506
|
+
const referenceId = ctx.context.referenceId ?? ctx.query?.referenceId ?? session.user.id;
|
|
507
|
+
const sorted = (await ctx.context.adapter.findMany({
|
|
508
|
+
model: "paystackTransaction",
|
|
509
|
+
where: [{
|
|
510
|
+
field: "referenceId",
|
|
511
|
+
value: referenceId
|
|
512
|
+
}]
|
|
513
|
+
})).sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
514
|
+
return ctx.json({ transactions: sorted });
|
|
515
|
+
});
|
|
516
|
+
};
|
|
687
517
|
const enableDisableBodySchema = z.object({
|
|
688
518
|
referenceId: z.string().optional(),
|
|
689
519
|
subscriptionCode: z.string(),
|
|
@@ -720,20 +550,20 @@ const disablePaystackSubscription = (options) => {
|
|
|
720
550
|
] : [sessionMiddleware, originCheck]
|
|
721
551
|
}, async (ctx) => {
|
|
722
552
|
const { subscriptionCode } = ctx.body;
|
|
723
|
-
const paystack
|
|
553
|
+
const paystack = getPaystackOps(options.paystackClient);
|
|
724
554
|
try {
|
|
725
555
|
let emailToken = ctx.body.emailToken;
|
|
726
556
|
if (!emailToken) try {
|
|
727
|
-
const fetchRes = unwrapSdkResult(await paystack
|
|
557
|
+
const fetchRes = unwrapSdkResult(await paystack.subscriptionFetch(subscriptionCode));
|
|
728
558
|
emailToken = (fetchRes && typeof fetchRes === "object" && "status" in fetchRes && "data" in fetchRes ? fetchRes.data : fetchRes?.data ?? fetchRes)?.email_token;
|
|
729
559
|
} catch {}
|
|
730
560
|
if (!emailToken) try {
|
|
731
|
-
const linkRes = unwrapSdkResult(await paystack
|
|
561
|
+
const linkRes = unwrapSdkResult(await paystack.subscriptionManageLink(subscriptionCode));
|
|
732
562
|
const link = (linkRes && typeof linkRes === "object" && "status" in linkRes && "data" in linkRes ? linkRes.data : linkRes?.data ?? linkRes)?.link;
|
|
733
563
|
if (typeof link === "string") emailToken = tryGetEmailTokenFromSubscriptionManageLink(link);
|
|
734
564
|
} catch {}
|
|
735
565
|
if (!emailToken) throw new APIError("BAD_REQUEST", { message: "Missing emailToken. Provide it explicitly or ensure your server can fetch it from Paystack using the subscription code." });
|
|
736
|
-
const result = unwrapSdkResult(await paystack
|
|
566
|
+
const result = unwrapSdkResult(await paystack.subscriptionDisable({
|
|
737
567
|
code: subscriptionCode,
|
|
738
568
|
token: emailToken
|
|
739
569
|
}));
|
|
@@ -759,20 +589,20 @@ const enablePaystackSubscription = (options) => {
|
|
|
759
589
|
] : [sessionMiddleware, originCheck]
|
|
760
590
|
}, async (ctx) => {
|
|
761
591
|
const { subscriptionCode } = ctx.body;
|
|
762
|
-
const paystack
|
|
592
|
+
const paystack = getPaystackOps(options.paystackClient);
|
|
763
593
|
try {
|
|
764
594
|
let emailToken = ctx.body.emailToken;
|
|
765
595
|
if (!emailToken) try {
|
|
766
|
-
const fetchRes = unwrapSdkResult(await paystack
|
|
596
|
+
const fetchRes = unwrapSdkResult(await paystack.subscriptionFetch(subscriptionCode));
|
|
767
597
|
emailToken = (fetchRes && typeof fetchRes === "object" && "status" in fetchRes && "data" in fetchRes ? fetchRes.data : fetchRes?.data ?? fetchRes)?.email_token;
|
|
768
598
|
} catch {}
|
|
769
599
|
if (!emailToken) try {
|
|
770
|
-
const linkRes = unwrapSdkResult(await paystack
|
|
600
|
+
const linkRes = unwrapSdkResult(await paystack.subscriptionManageLink(subscriptionCode));
|
|
771
601
|
const link = (linkRes && typeof linkRes === "object" && "status" in linkRes && "data" in linkRes ? linkRes.data : linkRes?.data ?? linkRes)?.link;
|
|
772
602
|
if (typeof link === "string") emailToken = tryGetEmailTokenFromSubscriptionManageLink(link);
|
|
773
603
|
} catch {}
|
|
774
604
|
if (!emailToken) throw new APIError("BAD_REQUEST", { message: "Missing emailToken. Provide it explicitly or ensure your server can fetch it from Paystack using the subscription code." });
|
|
775
|
-
const result = unwrapSdkResult(await paystack
|
|
605
|
+
const result = unwrapSdkResult(await paystack.subscriptionEnable({
|
|
776
606
|
code: subscriptionCode,
|
|
777
607
|
token: emailToken
|
|
778
608
|
}));
|
|
@@ -786,9 +616,91 @@ const enablePaystackSubscription = (options) => {
|
|
|
786
616
|
}
|
|
787
617
|
});
|
|
788
618
|
};
|
|
619
|
+
const subscriptionCodeSchema = z.object({ subscriptionCode: z.string() });
|
|
620
|
+
const getSubscriptionManageLink = (options) => {
|
|
621
|
+
const subscriptionOptions = options.subscription;
|
|
622
|
+
return createAuthEndpoint("/paystack/subscription/manage-link", {
|
|
623
|
+
method: "GET",
|
|
624
|
+
query: subscriptionCodeSchema,
|
|
625
|
+
use: subscriptionOptions?.enabled ? [
|
|
626
|
+
sessionMiddleware,
|
|
627
|
+
originCheck,
|
|
628
|
+
referenceMiddleware(subscriptionOptions, "get-subscription-manage-link")
|
|
629
|
+
] : [sessionMiddleware, originCheck]
|
|
630
|
+
}, async (ctx) => {
|
|
631
|
+
const { subscriptionCode } = ctx.query;
|
|
632
|
+
const paystack = getPaystackOps(options.paystackClient);
|
|
633
|
+
try {
|
|
634
|
+
const linkRes = unwrapSdkResult(await paystack.subscriptionManageLink(subscriptionCode));
|
|
635
|
+
const data = linkRes && typeof linkRes === "object" && "status" in linkRes && "data" in linkRes ? linkRes.data : linkRes?.data ?? linkRes;
|
|
636
|
+
return ctx.json({ link: data?.link });
|
|
637
|
+
} catch (error) {
|
|
638
|
+
ctx.context.logger.error("Failed to get Paystack subscription manage link", error);
|
|
639
|
+
throw new APIError("BAD_REQUEST", { message: error?.message || "Failed to fetch subscription management link" });
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
};
|
|
643
|
+
const getConfig = (options) => {
|
|
644
|
+
return createAuthEndpoint("/paystack/get-config", {
|
|
645
|
+
method: "GET",
|
|
646
|
+
metadata: { openapi: { operationId: "getPaystackConfig" } }
|
|
647
|
+
}, async (ctx) => {
|
|
648
|
+
const [plans, products] = await Promise.all([options.subscription?.enabled ? getPlans(options.subscription) : Promise.resolve([]), getProducts(options.products)]);
|
|
649
|
+
return ctx.json({
|
|
650
|
+
plans,
|
|
651
|
+
products
|
|
652
|
+
});
|
|
653
|
+
});
|
|
654
|
+
};
|
|
789
655
|
|
|
790
656
|
//#endregion
|
|
791
657
|
//#region src/schema.ts
|
|
658
|
+
const transactions = { paystackTransaction: { fields: {
|
|
659
|
+
reference: {
|
|
660
|
+
type: "string",
|
|
661
|
+
required: true
|
|
662
|
+
},
|
|
663
|
+
paystackId: {
|
|
664
|
+
type: "string",
|
|
665
|
+
required: false
|
|
666
|
+
},
|
|
667
|
+
referenceId: {
|
|
668
|
+
type: "string",
|
|
669
|
+
required: true
|
|
670
|
+
},
|
|
671
|
+
userId: {
|
|
672
|
+
type: "string",
|
|
673
|
+
required: true
|
|
674
|
+
},
|
|
675
|
+
amount: {
|
|
676
|
+
type: "number",
|
|
677
|
+
required: true
|
|
678
|
+
},
|
|
679
|
+
currency: {
|
|
680
|
+
type: "string",
|
|
681
|
+
required: true
|
|
682
|
+
},
|
|
683
|
+
status: {
|
|
684
|
+
type: "string",
|
|
685
|
+
required: true
|
|
686
|
+
},
|
|
687
|
+
plan: {
|
|
688
|
+
type: "string",
|
|
689
|
+
required: false
|
|
690
|
+
},
|
|
691
|
+
metadata: {
|
|
692
|
+
type: "string",
|
|
693
|
+
required: false
|
|
694
|
+
},
|
|
695
|
+
createdAt: {
|
|
696
|
+
type: "date",
|
|
697
|
+
required: true
|
|
698
|
+
},
|
|
699
|
+
updatedAt: {
|
|
700
|
+
type: "date",
|
|
701
|
+
required: true
|
|
702
|
+
}
|
|
703
|
+
} } };
|
|
792
704
|
const subscriptions = { subscription: { fields: {
|
|
793
705
|
plan: {
|
|
794
706
|
type: "string",
|
|
@@ -852,9 +764,13 @@ const getSchema = (options) => {
|
|
|
852
764
|
let baseSchema;
|
|
853
765
|
if (options.subscription?.enabled) baseSchema = {
|
|
854
766
|
...subscriptions,
|
|
767
|
+
...transactions,
|
|
855
768
|
...user
|
|
856
769
|
};
|
|
857
|
-
else baseSchema = {
|
|
770
|
+
else baseSchema = {
|
|
771
|
+
...user,
|
|
772
|
+
...transactions
|
|
773
|
+
};
|
|
858
774
|
if (options.schema && !options.subscription?.enabled && "subscription" in options.schema) {
|
|
859
775
|
const { subscription: _subscription, ...restSchema } = options.schema;
|
|
860
776
|
return mergeSchema(baseSchema, restSchema);
|
|
@@ -866,40 +782,41 @@ const getSchema = (options) => {
|
|
|
866
782
|
//#region src/index.ts
|
|
867
783
|
const INTERNAL_ERROR_CODES = defineErrorCodes({ ...PAYSTACK_ERROR_CODES });
|
|
868
784
|
const paystack = (options) => {
|
|
869
|
-
const baseEndpoints = { paystackWebhook: paystackWebhook(options) };
|
|
870
|
-
const subscriptionEnabledEndpoints = {
|
|
871
|
-
...baseEndpoints,
|
|
872
|
-
initializeTransaction: initializeTransaction(options),
|
|
873
|
-
verifyTransaction: verifyTransaction(options),
|
|
874
|
-
listSubscriptions: listSubscriptions(options),
|
|
875
|
-
disablePaystackSubscription: disablePaystackSubscription(options),
|
|
876
|
-
enablePaystackSubscription: enablePaystackSubscription(options)
|
|
877
|
-
};
|
|
878
785
|
return {
|
|
879
786
|
id: "paystack",
|
|
880
|
-
endpoints:
|
|
787
|
+
endpoints: {
|
|
788
|
+
paystackWebhook: paystackWebhook(options),
|
|
789
|
+
listTransactions: listTransactions(options),
|
|
790
|
+
getConfig: getConfig(options),
|
|
791
|
+
initializeTransaction: initializeTransaction(options),
|
|
792
|
+
verifyTransaction: verifyTransaction(options),
|
|
793
|
+
listSubscriptions: listSubscriptions(options),
|
|
794
|
+
disablePaystackSubscription: disablePaystackSubscription(options),
|
|
795
|
+
enablePaystackSubscription: enablePaystackSubscription(options),
|
|
796
|
+
getSubscriptionManageLink: getSubscriptionManageLink(options)
|
|
797
|
+
},
|
|
881
798
|
init(ctx) {
|
|
882
|
-
return { options: { databaseHooks: { user: { create: { async after(user
|
|
799
|
+
return { options: { databaseHooks: { user: { create: { async after(user, hookCtx) {
|
|
883
800
|
if (!hookCtx || !options.createCustomerOnSignUp) return;
|
|
884
801
|
try {
|
|
885
|
-
const firstName = user
|
|
886
|
-
const lastName = user
|
|
887
|
-
const extraCreateParams = options.getCustomerCreateParams ? await options.getCustomerCreateParams(user
|
|
802
|
+
const firstName = user.name?.split(" ")[0];
|
|
803
|
+
const lastName = user.name?.split(" ").slice(1).join(" ") || void 0;
|
|
804
|
+
const extraCreateParams = options.getCustomerCreateParams ? await options.getCustomerCreateParams(user, hookCtx) : {};
|
|
888
805
|
const params = defu({
|
|
889
|
-
email: user
|
|
806
|
+
email: user.email,
|
|
890
807
|
first_name: firstName,
|
|
891
808
|
last_name: lastName,
|
|
892
|
-
metadata: { userId: user
|
|
809
|
+
metadata: { userId: user.id }
|
|
893
810
|
}, extraCreateParams);
|
|
894
811
|
const res = unwrapSdkResult(await getPaystackOps(options.paystackClient).customerCreate(params));
|
|
895
812
|
const paystackCustomer = res && typeof res === "object" && "status" in res && "data" in res ? res.data : res?.data ?? res;
|
|
896
813
|
const customerCode = paystackCustomer?.customer_code;
|
|
897
814
|
if (!customerCode) return;
|
|
898
|
-
await hookCtx.context.internalAdapter.updateUser(user
|
|
815
|
+
await hookCtx.context.internalAdapter.updateUser(user.id, { paystackCustomerCode: customerCode });
|
|
899
816
|
await options.onCustomerCreate?.({
|
|
900
817
|
paystackCustomer,
|
|
901
818
|
user: {
|
|
902
|
-
...user
|
|
819
|
+
...user,
|
|
903
820
|
paystackCustomerCode: customerCode
|
|
904
821
|
}
|
|
905
822
|
}, hookCtx);
|