@paykit-sdk/paystack 1.2.0 → 1.3.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 +154 -0
- package/dist/index.js +28 -20
- package/dist/index.mjs +30 -22
- package/dist/paystack-provider.js +28 -20
- package/dist/paystack-provider.mjs +30 -22
- package/dist/utils/mapper.js +18 -16
- package/dist/utils/mapper.mjs +18 -16
- package/package.json +10 -8
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# @paykit-sdk/paystack
|
|
2
|
+
|
|
3
|
+
Paystack provider for PayKit.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @paykit-sdk/paystack
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @paykit-sdk/paystack
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createEndpointHandlers, PayKit } from '@paykit-sdk/core';
|
|
17
|
+
import { paystack } from '@paykit-sdk/paystack';
|
|
18
|
+
|
|
19
|
+
export const paykit = new PayKit(paystack());
|
|
20
|
+
export const endpoints = createEndpointHandlers(paykit);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or with direct config:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { PayKit } from '@paykit-sdk/core';
|
|
27
|
+
import { createPaystack } from '@paykit-sdk/paystack';
|
|
28
|
+
|
|
29
|
+
export const paykit = new PayKit(
|
|
30
|
+
createPaystack({
|
|
31
|
+
secretKey: 'sk_test_...',
|
|
32
|
+
isSandbox: true,
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Environment Variables
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
PAYSTACK_SECRET_KEY=sk_test_...
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`isSandbox` is inferred from `NODE_ENV` — set `NODE_ENV=production` for live mode.
|
|
44
|
+
|
|
45
|
+
## Next.js API Route
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// app/api/paykit/[...endpoint]/route.ts
|
|
49
|
+
import { endpoints } from '@/lib/paykit';
|
|
50
|
+
import { EndpointPath } from '@paykit-sdk/core';
|
|
51
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
52
|
+
|
|
53
|
+
export async function POST(
|
|
54
|
+
request: NextRequest,
|
|
55
|
+
{ params }: { params: Promise<{ endpoint: string[] }> },
|
|
56
|
+
) {
|
|
57
|
+
const { endpoint: endpointArray } = await params;
|
|
58
|
+
const endpoint = ('/' + endpointArray.join('/')) as EndpointPath;
|
|
59
|
+
const handler = endpoints[endpoint];
|
|
60
|
+
|
|
61
|
+
if (!handler) {
|
|
62
|
+
return NextResponse.json(
|
|
63
|
+
{ message: 'Not found' },
|
|
64
|
+
{ status: 404 },
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { args } = await request.json();
|
|
69
|
+
const result = await handler(...args);
|
|
70
|
+
return NextResponse.json({ result });
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Webhooks
|
|
75
|
+
|
|
76
|
+
Paystack sends signed POST requests. Pass your webhook secret to verify signatures.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// app/api/paykit/webhooks/route.ts
|
|
80
|
+
import { paykit } from '@/lib/paykit';
|
|
81
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
82
|
+
|
|
83
|
+
export async function POST(request: NextRequest) {
|
|
84
|
+
const body = await request.text();
|
|
85
|
+
|
|
86
|
+
const webhook = paykit.webhooks
|
|
87
|
+
.setup({ webhookSecret: process.env.PAYSTACK_SECRET_KEY! })
|
|
88
|
+
.on('payment.created', async event => {
|
|
89
|
+
/* charge.success — pending authorization */
|
|
90
|
+
})
|
|
91
|
+
.on('payment.updated', async event => {
|
|
92
|
+
/* charge.dispute.create — pre-auth hold updated */
|
|
93
|
+
})
|
|
94
|
+
.on('payment.failed', async event => {
|
|
95
|
+
/* charge.failed */
|
|
96
|
+
})
|
|
97
|
+
.on('invoice.generated', async event => {
|
|
98
|
+
/* invoice.payment_failed or invoice.update */
|
|
99
|
+
})
|
|
100
|
+
.on('customer.created', async event => {
|
|
101
|
+
/* customeridentification.success */
|
|
102
|
+
})
|
|
103
|
+
.on('customer.updated', async event => {
|
|
104
|
+
/* customeridentification.failed */
|
|
105
|
+
})
|
|
106
|
+
.on('subscription.created', async event => {
|
|
107
|
+
/* subscription.create */
|
|
108
|
+
})
|
|
109
|
+
.on('subscription.canceled', async event => {
|
|
110
|
+
/* subscription.disable */
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await webhook.handle({
|
|
114
|
+
body,
|
|
115
|
+
headersAsObject: Object.fromEntries(request.headers),
|
|
116
|
+
fullUrl: request.url,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return NextResponse.json({ received: true });
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Checkout
|
|
124
|
+
|
|
125
|
+
Paystack requires an email customer and amount/currency in `provider_metadata`:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const checkout = await paykit.checkouts.create({
|
|
129
|
+
customer: { email: 'user@example.com' },
|
|
130
|
+
item_id: 'plan_pro',
|
|
131
|
+
session_type: 'one_time',
|
|
132
|
+
quantity: 1,
|
|
133
|
+
success_url: 'https://example.com/success',
|
|
134
|
+
provider_metadata: {
|
|
135
|
+
amount: 50000, // in kobo (NGN) or smallest currency unit
|
|
136
|
+
currency: 'NGN',
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Redirect user to checkout.payment_url
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Documentation
|
|
144
|
+
|
|
145
|
+
Full docs at [docs.usepaykit.com/providers/paystack](https://docs.usepaykit.com/providers/paystack).
|
|
146
|
+
|
|
147
|
+
## Support
|
|
148
|
+
|
|
149
|
+
- [Paystack Documentation](https://paystack.com/docs)
|
|
150
|
+
- [PayKit Issues](https://github.com/usepaykit/paykit-sdk/issues)
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
ISC
|
package/dist/index.js
CHANGED
|
@@ -4086,11 +4086,17 @@ var Payment$inboundSchema = (data, overridePaymentUrl) => {
|
|
|
4086
4086
|
itemId = paykitMeta.item_id ?? null;
|
|
4087
4087
|
}
|
|
4088
4088
|
const status = paystackStatusMap[data.status] ?? "pending";
|
|
4089
|
+
let customer = null;
|
|
4090
|
+
if (data.customer?.email) {
|
|
4091
|
+
customer = { email: data.customer.email };
|
|
4092
|
+
} else if (data.customer?.id) {
|
|
4093
|
+
customer = { id: data.customer.id };
|
|
4094
|
+
}
|
|
4089
4095
|
return {
|
|
4090
4096
|
id: data.reference,
|
|
4091
4097
|
amount: data.amount,
|
|
4092
4098
|
currency: data.currency,
|
|
4093
|
-
customer
|
|
4099
|
+
customer,
|
|
4094
4100
|
status,
|
|
4095
4101
|
metadata,
|
|
4096
4102
|
item_id: itemId,
|
|
@@ -4115,24 +4121,20 @@ var Checkout$inboundSchema = (init, transaction) => {
|
|
|
4115
4121
|
type: core.billingModeSchema.optional()
|
|
4116
4122
|
})
|
|
4117
4123
|
);
|
|
4118
|
-
if (paykitMeta
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
itemId = parsed.item_id ?? "";
|
|
4129
|
-
quantity = parsed.quantity ?? 1;
|
|
4130
|
-
type = parsed.type ?? null;
|
|
4131
|
-
}
|
|
4124
|
+
if (paykitMeta) {
|
|
4125
|
+
itemId = paykitMeta.item_id ?? "";
|
|
4126
|
+
quantity = paykitMeta.quantity ?? 1;
|
|
4127
|
+
type = paykitMeta.type ?? null;
|
|
4128
|
+
}
|
|
4129
|
+
let customer = null;
|
|
4130
|
+
if (transaction.customer?.email) {
|
|
4131
|
+
customer = { email: transaction.customer.email };
|
|
4132
|
+
} else if (transaction.customer?.id) {
|
|
4133
|
+
customer = { id: transaction.customer.id };
|
|
4132
4134
|
}
|
|
4133
4135
|
return {
|
|
4134
4136
|
id: init.reference,
|
|
4135
|
-
customer
|
|
4137
|
+
customer,
|
|
4136
4138
|
payment_url: init.authorization_url,
|
|
4137
4139
|
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
4138
4140
|
session_type: type ?? "one_time",
|
|
@@ -4281,7 +4283,11 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
|
|
|
4281
4283
|
{ provider: this.providerName, method: "createCheckout" }
|
|
4282
4284
|
);
|
|
4283
4285
|
}
|
|
4284
|
-
const { amount, currency = "NGN" } =
|
|
4286
|
+
const { amount, currency = "NGN" } = core.validateRequiredKeys(
|
|
4287
|
+
["amount", "currency"],
|
|
4288
|
+
data.provider_metadata ?? {},
|
|
4289
|
+
"Missing required provider metadata: {keys}"
|
|
4290
|
+
);
|
|
4285
4291
|
const metadata = {
|
|
4286
4292
|
...core.stringifyMetadataValues(data.metadata ?? {}),
|
|
4287
4293
|
[core.PAYKIT_METADATA_KEY]: JSON.stringify({
|
|
@@ -4292,8 +4298,8 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
|
|
|
4292
4298
|
};
|
|
4293
4299
|
const body = {
|
|
4294
4300
|
email: data.customer.email,
|
|
4295
|
-
amount: amount
|
|
4296
|
-
currency,
|
|
4301
|
+
amount: parseInt(amount, 10),
|
|
4302
|
+
currency: currency.toUpperCase(),
|
|
4297
4303
|
reference: crypto.randomUUID(),
|
|
4298
4304
|
callback_url: data.success_url,
|
|
4299
4305
|
metadata: core.stringifyMetadataValues(metadata),
|
|
@@ -4605,7 +4611,9 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
|
|
|
4605
4611
|
});
|
|
4606
4612
|
}
|
|
4607
4613
|
const expectedSignature = crypto$1.createHmac("sha512", webhookSecret).update(body).digest("hex");
|
|
4608
|
-
|
|
4614
|
+
const expectedBuf = Buffer.from(expectedSignature, "hex");
|
|
4615
|
+
const receivedBuf = Buffer.from(signature, "hex");
|
|
4616
|
+
if (expectedBuf.length !== receivedBuf.length || !crypto$1.timingSafeEqual(expectedBuf, receivedBuf)) {
|
|
4609
4617
|
throw new core.WebhookError("Invalid Paystack webhook signature", {
|
|
4610
4618
|
provider: this.providerName
|
|
4611
4619
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { schema, AbstractPayKitProvider, HTTPClient, OperationFailedError, createCheckoutSchema, ValidationError, isEmailCustomer, InvalidTypeError, PAYKIT_METADATA_KEY, stringifyMetadataValues, ProviderNotSupportedError, createCustomerSchema, parseCustomerName, isIdCustomer, ResourceNotFoundError, createPaymentSchema, createRefundSchema, WebhookError, paykitEvent$InboundSchema,
|
|
2
|
-
import { createHmac } from 'crypto';
|
|
1
|
+
import { schema, AbstractPayKitProvider, HTTPClient, OperationFailedError, createCheckoutSchema, ValidationError, isEmailCustomer, InvalidTypeError, validateRequiredKeys, PAYKIT_METADATA_KEY, stringifyMetadataValues, ProviderNotSupportedError, createCustomerSchema, parseCustomerName, isIdCustomer, ResourceNotFoundError, createPaymentSchema, createRefundSchema, WebhookError, paykitEvent$InboundSchema, parseJSON, Schema, omitInternalMetadata, billingModeSchema } from '@paykit-sdk/core';
|
|
2
|
+
import { createHmac, timingSafeEqual } from 'crypto';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __export = (target, all) => {
|
|
@@ -4084,11 +4084,17 @@ var Payment$inboundSchema = (data, overridePaymentUrl) => {
|
|
|
4084
4084
|
itemId = paykitMeta.item_id ?? null;
|
|
4085
4085
|
}
|
|
4086
4086
|
const status = paystackStatusMap[data.status] ?? "pending";
|
|
4087
|
+
let customer = null;
|
|
4088
|
+
if (data.customer?.email) {
|
|
4089
|
+
customer = { email: data.customer.email };
|
|
4090
|
+
} else if (data.customer?.id) {
|
|
4091
|
+
customer = { id: data.customer.id };
|
|
4092
|
+
}
|
|
4087
4093
|
return {
|
|
4088
4094
|
id: data.reference,
|
|
4089
4095
|
amount: data.amount,
|
|
4090
4096
|
currency: data.currency,
|
|
4091
|
-
customer
|
|
4097
|
+
customer,
|
|
4092
4098
|
status,
|
|
4093
4099
|
metadata,
|
|
4094
4100
|
item_id: itemId,
|
|
@@ -4113,24 +4119,20 @@ var Checkout$inboundSchema = (init, transaction) => {
|
|
|
4113
4119
|
type: billingModeSchema.optional()
|
|
4114
4120
|
})
|
|
4115
4121
|
);
|
|
4116
|
-
if (paykitMeta
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
itemId = parsed.item_id ?? "";
|
|
4127
|
-
quantity = parsed.quantity ?? 1;
|
|
4128
|
-
type = parsed.type ?? null;
|
|
4129
|
-
}
|
|
4122
|
+
if (paykitMeta) {
|
|
4123
|
+
itemId = paykitMeta.item_id ?? "";
|
|
4124
|
+
quantity = paykitMeta.quantity ?? 1;
|
|
4125
|
+
type = paykitMeta.type ?? null;
|
|
4126
|
+
}
|
|
4127
|
+
let customer = null;
|
|
4128
|
+
if (transaction.customer?.email) {
|
|
4129
|
+
customer = { email: transaction.customer.email };
|
|
4130
|
+
} else if (transaction.customer?.id) {
|
|
4131
|
+
customer = { id: transaction.customer.id };
|
|
4130
4132
|
}
|
|
4131
4133
|
return {
|
|
4132
4134
|
id: init.reference,
|
|
4133
|
-
customer
|
|
4135
|
+
customer,
|
|
4134
4136
|
payment_url: init.authorization_url,
|
|
4135
4137
|
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
4136
4138
|
session_type: type ?? "one_time",
|
|
@@ -4279,7 +4281,11 @@ var PaystackProvider = class extends AbstractPayKitProvider {
|
|
|
4279
4281
|
{ provider: this.providerName, method: "createCheckout" }
|
|
4280
4282
|
);
|
|
4281
4283
|
}
|
|
4282
|
-
const { amount, currency = "NGN" } =
|
|
4284
|
+
const { amount, currency = "NGN" } = validateRequiredKeys(
|
|
4285
|
+
["amount", "currency"],
|
|
4286
|
+
data.provider_metadata ?? {},
|
|
4287
|
+
"Missing required provider metadata: {keys}"
|
|
4288
|
+
);
|
|
4283
4289
|
const metadata = {
|
|
4284
4290
|
...stringifyMetadataValues(data.metadata ?? {}),
|
|
4285
4291
|
[PAYKIT_METADATA_KEY]: JSON.stringify({
|
|
@@ -4290,8 +4296,8 @@ var PaystackProvider = class extends AbstractPayKitProvider {
|
|
|
4290
4296
|
};
|
|
4291
4297
|
const body = {
|
|
4292
4298
|
email: data.customer.email,
|
|
4293
|
-
amount: amount
|
|
4294
|
-
currency,
|
|
4299
|
+
amount: parseInt(amount, 10),
|
|
4300
|
+
currency: currency.toUpperCase(),
|
|
4295
4301
|
reference: crypto.randomUUID(),
|
|
4296
4302
|
callback_url: data.success_url,
|
|
4297
4303
|
metadata: stringifyMetadataValues(metadata),
|
|
@@ -4603,7 +4609,9 @@ var PaystackProvider = class extends AbstractPayKitProvider {
|
|
|
4603
4609
|
});
|
|
4604
4610
|
}
|
|
4605
4611
|
const expectedSignature = createHmac("sha512", webhookSecret).update(body).digest("hex");
|
|
4606
|
-
|
|
4612
|
+
const expectedBuf = Buffer.from(expectedSignature, "hex");
|
|
4613
|
+
const receivedBuf = Buffer.from(signature, "hex");
|
|
4614
|
+
if (expectedBuf.length !== receivedBuf.length || !timingSafeEqual(expectedBuf, receivedBuf)) {
|
|
4607
4615
|
throw new WebhookError("Invalid Paystack webhook signature", {
|
|
4608
4616
|
provider: this.providerName
|
|
4609
4617
|
});
|
|
@@ -4086,11 +4086,17 @@ var Payment$inboundSchema = (data, overridePaymentUrl) => {
|
|
|
4086
4086
|
itemId = paykitMeta.item_id ?? null;
|
|
4087
4087
|
}
|
|
4088
4088
|
const status = paystackStatusMap[data.status] ?? "pending";
|
|
4089
|
+
let customer = null;
|
|
4090
|
+
if (data.customer?.email) {
|
|
4091
|
+
customer = { email: data.customer.email };
|
|
4092
|
+
} else if (data.customer?.id) {
|
|
4093
|
+
customer = { id: data.customer.id };
|
|
4094
|
+
}
|
|
4089
4095
|
return {
|
|
4090
4096
|
id: data.reference,
|
|
4091
4097
|
amount: data.amount,
|
|
4092
4098
|
currency: data.currency,
|
|
4093
|
-
customer
|
|
4099
|
+
customer,
|
|
4094
4100
|
status,
|
|
4095
4101
|
metadata,
|
|
4096
4102
|
item_id: itemId,
|
|
@@ -4115,24 +4121,20 @@ var Checkout$inboundSchema = (init, transaction) => {
|
|
|
4115
4121
|
type: core.billingModeSchema.optional()
|
|
4116
4122
|
})
|
|
4117
4123
|
);
|
|
4118
|
-
if (paykitMeta
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
itemId = parsed.item_id ?? "";
|
|
4129
|
-
quantity = parsed.quantity ?? 1;
|
|
4130
|
-
type = parsed.type ?? null;
|
|
4131
|
-
}
|
|
4124
|
+
if (paykitMeta) {
|
|
4125
|
+
itemId = paykitMeta.item_id ?? "";
|
|
4126
|
+
quantity = paykitMeta.quantity ?? 1;
|
|
4127
|
+
type = paykitMeta.type ?? null;
|
|
4128
|
+
}
|
|
4129
|
+
let customer = null;
|
|
4130
|
+
if (transaction.customer?.email) {
|
|
4131
|
+
customer = { email: transaction.customer.email };
|
|
4132
|
+
} else if (transaction.customer?.id) {
|
|
4133
|
+
customer = { id: transaction.customer.id };
|
|
4132
4134
|
}
|
|
4133
4135
|
return {
|
|
4134
4136
|
id: init.reference,
|
|
4135
|
-
customer
|
|
4137
|
+
customer,
|
|
4136
4138
|
payment_url: init.authorization_url,
|
|
4137
4139
|
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
4138
4140
|
session_type: type ?? "one_time",
|
|
@@ -4281,7 +4283,11 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
|
|
|
4281
4283
|
{ provider: this.providerName, method: "createCheckout" }
|
|
4282
4284
|
);
|
|
4283
4285
|
}
|
|
4284
|
-
const { amount, currency = "NGN" } =
|
|
4286
|
+
const { amount, currency = "NGN" } = core.validateRequiredKeys(
|
|
4287
|
+
["amount", "currency"],
|
|
4288
|
+
data.provider_metadata ?? {},
|
|
4289
|
+
"Missing required provider metadata: {keys}"
|
|
4290
|
+
);
|
|
4285
4291
|
const metadata = {
|
|
4286
4292
|
...core.stringifyMetadataValues(data.metadata ?? {}),
|
|
4287
4293
|
[core.PAYKIT_METADATA_KEY]: JSON.stringify({
|
|
@@ -4292,8 +4298,8 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
|
|
|
4292
4298
|
};
|
|
4293
4299
|
const body = {
|
|
4294
4300
|
email: data.customer.email,
|
|
4295
|
-
amount: amount
|
|
4296
|
-
currency,
|
|
4301
|
+
amount: parseInt(amount, 10),
|
|
4302
|
+
currency: currency.toUpperCase(),
|
|
4297
4303
|
reference: crypto.randomUUID(),
|
|
4298
4304
|
callback_url: data.success_url,
|
|
4299
4305
|
metadata: core.stringifyMetadataValues(metadata),
|
|
@@ -4605,7 +4611,9 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
|
|
|
4605
4611
|
});
|
|
4606
4612
|
}
|
|
4607
4613
|
const expectedSignature = crypto$1.createHmac("sha512", webhookSecret).update(body).digest("hex");
|
|
4608
|
-
|
|
4614
|
+
const expectedBuf = Buffer.from(expectedSignature, "hex");
|
|
4615
|
+
const receivedBuf = Buffer.from(signature, "hex");
|
|
4616
|
+
if (expectedBuf.length !== receivedBuf.length || !crypto$1.timingSafeEqual(expectedBuf, receivedBuf)) {
|
|
4609
4617
|
throw new core.WebhookError("Invalid Paystack webhook signature", {
|
|
4610
4618
|
provider: this.providerName
|
|
4611
4619
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { schema, AbstractPayKitProvider, HTTPClient, OperationFailedError, createCheckoutSchema, ValidationError, isEmailCustomer, InvalidTypeError, PAYKIT_METADATA_KEY, stringifyMetadataValues, ProviderNotSupportedError, createCustomerSchema, parseCustomerName, isIdCustomer, ResourceNotFoundError, createPaymentSchema, createRefundSchema, WebhookError, paykitEvent$InboundSchema, parseJSON, Schema, omitInternalMetadata, billingModeSchema } from '@paykit-sdk/core';
|
|
2
|
-
import { createHmac } from 'crypto';
|
|
1
|
+
import { schema, AbstractPayKitProvider, HTTPClient, OperationFailedError, createCheckoutSchema, ValidationError, isEmailCustomer, InvalidTypeError, validateRequiredKeys, PAYKIT_METADATA_KEY, stringifyMetadataValues, ProviderNotSupportedError, createCustomerSchema, parseCustomerName, isIdCustomer, ResourceNotFoundError, createPaymentSchema, createRefundSchema, WebhookError, paykitEvent$InboundSchema, parseJSON, Schema, omitInternalMetadata, billingModeSchema } from '@paykit-sdk/core';
|
|
2
|
+
import { createHmac, timingSafeEqual } from 'crypto';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __export = (target, all) => {
|
|
@@ -4084,11 +4084,17 @@ var Payment$inboundSchema = (data, overridePaymentUrl) => {
|
|
|
4084
4084
|
itemId = paykitMeta.item_id ?? null;
|
|
4085
4085
|
}
|
|
4086
4086
|
const status = paystackStatusMap[data.status] ?? "pending";
|
|
4087
|
+
let customer = null;
|
|
4088
|
+
if (data.customer?.email) {
|
|
4089
|
+
customer = { email: data.customer.email };
|
|
4090
|
+
} else if (data.customer?.id) {
|
|
4091
|
+
customer = { id: data.customer.id };
|
|
4092
|
+
}
|
|
4087
4093
|
return {
|
|
4088
4094
|
id: data.reference,
|
|
4089
4095
|
amount: data.amount,
|
|
4090
4096
|
currency: data.currency,
|
|
4091
|
-
customer
|
|
4097
|
+
customer,
|
|
4092
4098
|
status,
|
|
4093
4099
|
metadata,
|
|
4094
4100
|
item_id: itemId,
|
|
@@ -4113,24 +4119,20 @@ var Checkout$inboundSchema = (init, transaction) => {
|
|
|
4113
4119
|
type: billingModeSchema.optional()
|
|
4114
4120
|
})
|
|
4115
4121
|
);
|
|
4116
|
-
if (paykitMeta
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
itemId = parsed.item_id ?? "";
|
|
4127
|
-
quantity = parsed.quantity ?? 1;
|
|
4128
|
-
type = parsed.type ?? null;
|
|
4129
|
-
}
|
|
4122
|
+
if (paykitMeta) {
|
|
4123
|
+
itemId = paykitMeta.item_id ?? "";
|
|
4124
|
+
quantity = paykitMeta.quantity ?? 1;
|
|
4125
|
+
type = paykitMeta.type ?? null;
|
|
4126
|
+
}
|
|
4127
|
+
let customer = null;
|
|
4128
|
+
if (transaction.customer?.email) {
|
|
4129
|
+
customer = { email: transaction.customer.email };
|
|
4130
|
+
} else if (transaction.customer?.id) {
|
|
4131
|
+
customer = { id: transaction.customer.id };
|
|
4130
4132
|
}
|
|
4131
4133
|
return {
|
|
4132
4134
|
id: init.reference,
|
|
4133
|
-
customer
|
|
4135
|
+
customer,
|
|
4134
4136
|
payment_url: init.authorization_url,
|
|
4135
4137
|
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
4136
4138
|
session_type: type ?? "one_time",
|
|
@@ -4279,7 +4281,11 @@ var PaystackProvider = class extends AbstractPayKitProvider {
|
|
|
4279
4281
|
{ provider: this.providerName, method: "createCheckout" }
|
|
4280
4282
|
);
|
|
4281
4283
|
}
|
|
4282
|
-
const { amount, currency = "NGN" } =
|
|
4284
|
+
const { amount, currency = "NGN" } = validateRequiredKeys(
|
|
4285
|
+
["amount", "currency"],
|
|
4286
|
+
data.provider_metadata ?? {},
|
|
4287
|
+
"Missing required provider metadata: {keys}"
|
|
4288
|
+
);
|
|
4283
4289
|
const metadata = {
|
|
4284
4290
|
...stringifyMetadataValues(data.metadata ?? {}),
|
|
4285
4291
|
[PAYKIT_METADATA_KEY]: JSON.stringify({
|
|
@@ -4290,8 +4296,8 @@ var PaystackProvider = class extends AbstractPayKitProvider {
|
|
|
4290
4296
|
};
|
|
4291
4297
|
const body = {
|
|
4292
4298
|
email: data.customer.email,
|
|
4293
|
-
amount: amount
|
|
4294
|
-
currency,
|
|
4299
|
+
amount: parseInt(amount, 10),
|
|
4300
|
+
currency: currency.toUpperCase(),
|
|
4295
4301
|
reference: crypto.randomUUID(),
|
|
4296
4302
|
callback_url: data.success_url,
|
|
4297
4303
|
metadata: stringifyMetadataValues(metadata),
|
|
@@ -4603,7 +4609,9 @@ var PaystackProvider = class extends AbstractPayKitProvider {
|
|
|
4603
4609
|
});
|
|
4604
4610
|
}
|
|
4605
4611
|
const expectedSignature = createHmac("sha512", webhookSecret).update(body).digest("hex");
|
|
4606
|
-
|
|
4612
|
+
const expectedBuf = Buffer.from(expectedSignature, "hex");
|
|
4613
|
+
const receivedBuf = Buffer.from(signature, "hex");
|
|
4614
|
+
if (expectedBuf.length !== receivedBuf.length || !timingSafeEqual(expectedBuf, receivedBuf)) {
|
|
4607
4615
|
throw new WebhookError("Invalid Paystack webhook signature", {
|
|
4608
4616
|
provider: this.providerName
|
|
4609
4617
|
});
|
package/dist/utils/mapper.js
CHANGED
|
@@ -41,11 +41,17 @@ var Payment$inboundSchema = (data, overridePaymentUrl) => {
|
|
|
41
41
|
itemId = paykitMeta.item_id ?? null;
|
|
42
42
|
}
|
|
43
43
|
const status = paystackStatusMap[data.status] ?? "pending";
|
|
44
|
+
let customer = null;
|
|
45
|
+
if (data.customer?.email) {
|
|
46
|
+
customer = { email: data.customer.email };
|
|
47
|
+
} else if (data.customer?.id) {
|
|
48
|
+
customer = { id: data.customer.id };
|
|
49
|
+
}
|
|
44
50
|
return {
|
|
45
51
|
id: data.reference,
|
|
46
52
|
amount: data.amount,
|
|
47
53
|
currency: data.currency,
|
|
48
|
-
customer
|
|
54
|
+
customer,
|
|
49
55
|
status,
|
|
50
56
|
metadata,
|
|
51
57
|
item_id: itemId,
|
|
@@ -70,24 +76,20 @@ var Checkout$inboundSchema = (init, transaction) => {
|
|
|
70
76
|
type: core.billingModeSchema.optional()
|
|
71
77
|
})
|
|
72
78
|
);
|
|
73
|
-
if (paykitMeta
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
itemId = parsed.item_id ?? "";
|
|
84
|
-
quantity = parsed.quantity ?? 1;
|
|
85
|
-
type = parsed.type ?? null;
|
|
86
|
-
}
|
|
79
|
+
if (paykitMeta) {
|
|
80
|
+
itemId = paykitMeta.item_id ?? "";
|
|
81
|
+
quantity = paykitMeta.quantity ?? 1;
|
|
82
|
+
type = paykitMeta.type ?? null;
|
|
83
|
+
}
|
|
84
|
+
let customer = null;
|
|
85
|
+
if (transaction.customer?.email) {
|
|
86
|
+
customer = { email: transaction.customer.email };
|
|
87
|
+
} else if (transaction.customer?.id) {
|
|
88
|
+
customer = { id: transaction.customer.id };
|
|
87
89
|
}
|
|
88
90
|
return {
|
|
89
91
|
id: init.reference,
|
|
90
|
-
customer
|
|
92
|
+
customer,
|
|
91
93
|
payment_url: init.authorization_url,
|
|
92
94
|
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
93
95
|
session_type: type ?? "one_time",
|
package/dist/utils/mapper.mjs
CHANGED
|
@@ -39,11 +39,17 @@ var Payment$inboundSchema = (data, overridePaymentUrl) => {
|
|
|
39
39
|
itemId = paykitMeta.item_id ?? null;
|
|
40
40
|
}
|
|
41
41
|
const status = paystackStatusMap[data.status] ?? "pending";
|
|
42
|
+
let customer = null;
|
|
43
|
+
if (data.customer?.email) {
|
|
44
|
+
customer = { email: data.customer.email };
|
|
45
|
+
} else if (data.customer?.id) {
|
|
46
|
+
customer = { id: data.customer.id };
|
|
47
|
+
}
|
|
42
48
|
return {
|
|
43
49
|
id: data.reference,
|
|
44
50
|
amount: data.amount,
|
|
45
51
|
currency: data.currency,
|
|
46
|
-
customer
|
|
52
|
+
customer,
|
|
47
53
|
status,
|
|
48
54
|
metadata,
|
|
49
55
|
item_id: itemId,
|
|
@@ -68,24 +74,20 @@ var Checkout$inboundSchema = (init, transaction) => {
|
|
|
68
74
|
type: billingModeSchema.optional()
|
|
69
75
|
})
|
|
70
76
|
);
|
|
71
|
-
if (paykitMeta
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
itemId = parsed.item_id ?? "";
|
|
82
|
-
quantity = parsed.quantity ?? 1;
|
|
83
|
-
type = parsed.type ?? null;
|
|
84
|
-
}
|
|
77
|
+
if (paykitMeta) {
|
|
78
|
+
itemId = paykitMeta.item_id ?? "";
|
|
79
|
+
quantity = paykitMeta.quantity ?? 1;
|
|
80
|
+
type = paykitMeta.type ?? null;
|
|
81
|
+
}
|
|
82
|
+
let customer = null;
|
|
83
|
+
if (transaction.customer?.email) {
|
|
84
|
+
customer = { email: transaction.customer.email };
|
|
85
|
+
} else if (transaction.customer?.id) {
|
|
86
|
+
customer = { id: transaction.customer.id };
|
|
85
87
|
}
|
|
86
88
|
return {
|
|
87
89
|
id: init.reference,
|
|
88
|
-
customer
|
|
90
|
+
customer,
|
|
89
91
|
payment_url: init.authorization_url,
|
|
90
92
|
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
91
93
|
session_type: type ?? "one_time",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paykit-sdk/paystack",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Paystack provider for PayKit",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -11,9 +11,6 @@
|
|
|
11
11
|
"paykit": {
|
|
12
12
|
"type": "provider"
|
|
13
13
|
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "tsup"
|
|
16
|
-
},
|
|
17
14
|
"keywords": [
|
|
18
15
|
"paystack",
|
|
19
16
|
"paykit",
|
|
@@ -23,13 +20,13 @@
|
|
|
23
20
|
"author": "Emmanuel Odii",
|
|
24
21
|
"license": "ISC",
|
|
25
22
|
"peerDependencies": {
|
|
26
|
-
"@paykit-sdk/core": "
|
|
23
|
+
"@paykit-sdk/core": "^1.2.3"
|
|
27
24
|
},
|
|
28
25
|
"devDependencies": {
|
|
29
|
-
"@paykit-sdk/core": "workspace:*",
|
|
30
26
|
"tsup": "^8.5.0",
|
|
31
27
|
"typescript": "^5.9.2",
|
|
32
|
-
"zod": "^3.24.2"
|
|
28
|
+
"zod": "^3.24.2",
|
|
29
|
+
"@paykit-sdk/core": "1.3.0"
|
|
33
30
|
},
|
|
34
31
|
"publishConfig": {
|
|
35
32
|
"access": "public"
|
|
@@ -40,5 +37,10 @@
|
|
|
40
37
|
},
|
|
41
38
|
"bugs": {
|
|
42
39
|
"url": "https://github.com/usepaykit/paykit-sdk/issues"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"test": "vitest run --config ../../vitest.config.ts packages/paystack/src",
|
|
44
|
+
"typecheck": "tsc --noEmit"
|
|
43
45
|
}
|
|
44
|
-
}
|
|
46
|
+
}
|