@paykit-sdk/paystack 1.2.1 → 1.3.1

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/dist/index.js CHANGED
@@ -4121,20 +4121,10 @@ var Checkout$inboundSchema = (init, transaction) => {
4121
4121
  type: core.billingModeSchema.optional()
4122
4122
  })
4123
4123
  );
4124
- if (paykitMeta && typeof paykitMeta === "string") {
4125
- const parsed = core.parseJSON(
4126
- paykitMeta,
4127
- core.Schema.object({
4128
- item_id: core.Schema.string().optional(),
4129
- quantity: core.Schema.number().optional(),
4130
- type: core.billingModeSchema.optional()
4131
- })
4132
- );
4133
- if (parsed) {
4134
- itemId = parsed.item_id ?? "";
4135
- quantity = parsed.quantity ?? 1;
4136
- type = parsed.type ?? null;
4137
- }
4124
+ if (paykitMeta) {
4125
+ itemId = paykitMeta.item_id ?? "";
4126
+ quantity = paykitMeta.quantity ?? 1;
4127
+ type = paykitMeta.type ?? null;
4138
4128
  }
4139
4129
  let customer = null;
4140
4130
  if (transaction.customer?.email) {
@@ -4145,7 +4135,7 @@ var Checkout$inboundSchema = (init, transaction) => {
4145
4135
  return {
4146
4136
  id: init.reference,
4147
4137
  customer,
4148
- payment_url: init.authorization_url,
4138
+ payment_url: init.authorizationUrl,
4149
4139
  metadata: Object.keys(metadata).length > 0 ? metadata : null,
4150
4140
  session_type: type ?? "one_time",
4151
4141
  products: [{ id: itemId, quantity }],
@@ -4276,6 +4266,19 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4276
4266
  }
4277
4267
  return this._toCamel(result.value.data);
4278
4268
  }
4269
+ async initializeTransaction(params) {
4270
+ const body = {
4271
+ ...params.providerMetadata,
4272
+ email: params.email,
4273
+ amount: params.amount,
4274
+ currency: params.currency.toUpperCase(),
4275
+ reference: crypto.randomUUID(),
4276
+ ...params.callbackUrl && { callback_url: params.callbackUrl },
4277
+ metadata: core.stringifyMetadataValues(params.metadata)
4278
+ };
4279
+ const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4280
+ return this.unwrap(response, "initializeTransaction");
4281
+ }
4279
4282
  createCheckout = async (params) => {
4280
4283
  const { error, data } = core.createCheckoutSchema.safeParse(params);
4281
4284
  if (error) {
@@ -4293,7 +4296,11 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4293
4296
  { provider: this.providerName, method: "createCheckout" }
4294
4297
  );
4295
4298
  }
4296
- const { amount, currency = "NGN" } = data.provider_metadata ?? {};
4299
+ const { amount, currency = "NGN" } = core.validateRequiredKeys(
4300
+ ["amount", "currency"],
4301
+ data.provider_metadata ?? {},
4302
+ "Missing required provider metadata: {keys}"
4303
+ );
4297
4304
  const metadata = {
4298
4305
  ...core.stringifyMetadataValues(data.metadata ?? {}),
4299
4306
  [core.PAYKIT_METADATA_KEY]: JSON.stringify({
@@ -4302,21 +4309,20 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4302
4309
  type: data.session_type
4303
4310
  })
4304
4311
  };
4305
- const body = {
4312
+ const parsedAmount = parseInt(amount, 10);
4313
+ const upperCurrency = currency.toUpperCase();
4314
+ const initData = await this.initializeTransaction({
4306
4315
  email: data.customer.email,
4307
- amount: amount ?? 0,
4308
- currency,
4309
- reference: crypto.randomUUID(),
4310
- callback_url: data.success_url,
4311
- metadata: core.stringifyMetadataValues(metadata),
4312
- ...data.provider_metadata
4313
- };
4314
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4315
- const initData = await this.unwrap(response, "createCheckout");
4316
+ amount: parsedAmount,
4317
+ currency: upperCurrency,
4318
+ metadata,
4319
+ callbackUrl: data.success_url,
4320
+ providerMetadata: data.provider_metadata
4321
+ });
4316
4322
  const rawCustomer = await this._client.get(`/customer/${encodeURIComponent(data.customer.email)}`);
4317
4323
  return Checkout$inboundSchema(initData, {
4318
- amount: body.amount,
4319
- currency: body.currency,
4324
+ amount: parsedAmount,
4325
+ currency: upperCurrency,
4320
4326
  customer: await this.unwrap(rawCustomer, "createCheckout"),
4321
4327
  metadata: JSON.stringify(metadata)
4322
4328
  });
@@ -4327,7 +4333,7 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4327
4333
  const txn = response.value.data;
4328
4334
  return Checkout$inboundSchema(
4329
4335
  {
4330
- authorization_url: "",
4336
+ authorizationUrl: "",
4331
4337
  reference: txn.reference
4332
4338
  },
4333
4339
  txn
@@ -4523,23 +4529,19 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4523
4529
  item_id: data.item_id
4524
4530
  })
4525
4531
  };
4526
- const reference = crypto.randomUUID();
4527
- const body = {
4528
- email,
4529
- amount: data.amount,
4530
- currency: data.currency,
4531
- reference,
4532
- metadata,
4533
- ...data.provider_metadata
4534
- };
4535
4532
  if (this.opts.debug) {
4536
4533
  console.info("[Paystack] Initializing transaction", {
4537
4534
  email,
4538
4535
  amount: data.amount
4539
4536
  });
4540
4537
  }
4541
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4542
- const initData = await this.unwrap(response, "createPayment");
4538
+ const initData = await this.initializeTransaction({
4539
+ email,
4540
+ amount: data.amount,
4541
+ currency: data.currency,
4542
+ metadata,
4543
+ providerMetadata: data.provider_metadata
4544
+ });
4543
4545
  return {
4544
4546
  id: initData.reference,
4545
4547
  amount: data.amount,
@@ -4551,7 +4553,7 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4551
4553
  ),
4552
4554
  item_id: data.item_id ?? null,
4553
4555
  requires_action: true,
4554
- payment_url: initData.authorization_url
4556
+ payment_url: initData.authorizationUrl
4555
4557
  };
4556
4558
  };
4557
4559
  retrievePayment = async (id) => {
@@ -4617,7 +4619,9 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4617
4619
  });
4618
4620
  }
4619
4621
  const expectedSignature = crypto$1.createHmac("sha512", webhookSecret).update(body).digest("hex");
4620
- if (expectedSignature !== signature) {
4622
+ const expectedBuf = Buffer.from(expectedSignature, "hex");
4623
+ const receivedBuf = Buffer.from(signature, "hex");
4624
+ if (expectedBuf.length !== receivedBuf.length || !crypto$1.timingSafeEqual(expectedBuf, receivedBuf)) {
4621
4625
  throw new core.WebhookError("Invalid Paystack webhook signature", {
4622
4626
  provider: this.providerName
4623
4627
  });
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, validateRequiredKeys, parseJSON, Schema, omitInternalMetadata, billingModeSchema } from '@paykit-sdk/core';
2
- import { createHmac } from 'crypto';
1
+ import { schema, AbstractPayKitProvider, HTTPClient, OperationFailedError, stringifyMetadataValues, createCheckoutSchema, ValidationError, isEmailCustomer, InvalidTypeError, validateRequiredKeys, PAYKIT_METADATA_KEY, 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) => {
@@ -4119,20 +4119,10 @@ var Checkout$inboundSchema = (init, transaction) => {
4119
4119
  type: billingModeSchema.optional()
4120
4120
  })
4121
4121
  );
4122
- if (paykitMeta && typeof paykitMeta === "string") {
4123
- const parsed = parseJSON(
4124
- paykitMeta,
4125
- Schema.object({
4126
- item_id: Schema.string().optional(),
4127
- quantity: Schema.number().optional(),
4128
- type: billingModeSchema.optional()
4129
- })
4130
- );
4131
- if (parsed) {
4132
- itemId = parsed.item_id ?? "";
4133
- quantity = parsed.quantity ?? 1;
4134
- type = parsed.type ?? null;
4135
- }
4122
+ if (paykitMeta) {
4123
+ itemId = paykitMeta.item_id ?? "";
4124
+ quantity = paykitMeta.quantity ?? 1;
4125
+ type = paykitMeta.type ?? null;
4136
4126
  }
4137
4127
  let customer = null;
4138
4128
  if (transaction.customer?.email) {
@@ -4143,7 +4133,7 @@ var Checkout$inboundSchema = (init, transaction) => {
4143
4133
  return {
4144
4134
  id: init.reference,
4145
4135
  customer,
4146
- payment_url: init.authorization_url,
4136
+ payment_url: init.authorizationUrl,
4147
4137
  metadata: Object.keys(metadata).length > 0 ? metadata : null,
4148
4138
  session_type: type ?? "one_time",
4149
4139
  products: [{ id: itemId, quantity }],
@@ -4274,6 +4264,19 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4274
4264
  }
4275
4265
  return this._toCamel(result.value.data);
4276
4266
  }
4267
+ async initializeTransaction(params) {
4268
+ const body = {
4269
+ ...params.providerMetadata,
4270
+ email: params.email,
4271
+ amount: params.amount,
4272
+ currency: params.currency.toUpperCase(),
4273
+ reference: crypto.randomUUID(),
4274
+ ...params.callbackUrl && { callback_url: params.callbackUrl },
4275
+ metadata: stringifyMetadataValues(params.metadata)
4276
+ };
4277
+ const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4278
+ return this.unwrap(response, "initializeTransaction");
4279
+ }
4277
4280
  createCheckout = async (params) => {
4278
4281
  const { error, data } = createCheckoutSchema.safeParse(params);
4279
4282
  if (error) {
@@ -4291,7 +4294,11 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4291
4294
  { provider: this.providerName, method: "createCheckout" }
4292
4295
  );
4293
4296
  }
4294
- const { amount, currency = "NGN" } = data.provider_metadata ?? {};
4297
+ const { amount, currency = "NGN" } = validateRequiredKeys(
4298
+ ["amount", "currency"],
4299
+ data.provider_metadata ?? {},
4300
+ "Missing required provider metadata: {keys}"
4301
+ );
4295
4302
  const metadata = {
4296
4303
  ...stringifyMetadataValues(data.metadata ?? {}),
4297
4304
  [PAYKIT_METADATA_KEY]: JSON.stringify({
@@ -4300,21 +4307,20 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4300
4307
  type: data.session_type
4301
4308
  })
4302
4309
  };
4303
- const body = {
4310
+ const parsedAmount = parseInt(amount, 10);
4311
+ const upperCurrency = currency.toUpperCase();
4312
+ const initData = await this.initializeTransaction({
4304
4313
  email: data.customer.email,
4305
- amount: amount ?? 0,
4306
- currency,
4307
- reference: crypto.randomUUID(),
4308
- callback_url: data.success_url,
4309
- metadata: stringifyMetadataValues(metadata),
4310
- ...data.provider_metadata
4311
- };
4312
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4313
- const initData = await this.unwrap(response, "createCheckout");
4314
+ amount: parsedAmount,
4315
+ currency: upperCurrency,
4316
+ metadata,
4317
+ callbackUrl: data.success_url,
4318
+ providerMetadata: data.provider_metadata
4319
+ });
4314
4320
  const rawCustomer = await this._client.get(`/customer/${encodeURIComponent(data.customer.email)}`);
4315
4321
  return Checkout$inboundSchema(initData, {
4316
- amount: body.amount,
4317
- currency: body.currency,
4322
+ amount: parsedAmount,
4323
+ currency: upperCurrency,
4318
4324
  customer: await this.unwrap(rawCustomer, "createCheckout"),
4319
4325
  metadata: JSON.stringify(metadata)
4320
4326
  });
@@ -4325,7 +4331,7 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4325
4331
  const txn = response.value.data;
4326
4332
  return Checkout$inboundSchema(
4327
4333
  {
4328
- authorization_url: "",
4334
+ authorizationUrl: "",
4329
4335
  reference: txn.reference
4330
4336
  },
4331
4337
  txn
@@ -4521,23 +4527,19 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4521
4527
  item_id: data.item_id
4522
4528
  })
4523
4529
  };
4524
- const reference = crypto.randomUUID();
4525
- const body = {
4526
- email,
4527
- amount: data.amount,
4528
- currency: data.currency,
4529
- reference,
4530
- metadata,
4531
- ...data.provider_metadata
4532
- };
4533
4530
  if (this.opts.debug) {
4534
4531
  console.info("[Paystack] Initializing transaction", {
4535
4532
  email,
4536
4533
  amount: data.amount
4537
4534
  });
4538
4535
  }
4539
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4540
- const initData = await this.unwrap(response, "createPayment");
4536
+ const initData = await this.initializeTransaction({
4537
+ email,
4538
+ amount: data.amount,
4539
+ currency: data.currency,
4540
+ metadata,
4541
+ providerMetadata: data.provider_metadata
4542
+ });
4541
4543
  return {
4542
4544
  id: initData.reference,
4543
4545
  amount: data.amount,
@@ -4549,7 +4551,7 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4549
4551
  ),
4550
4552
  item_id: data.item_id ?? null,
4551
4553
  requires_action: true,
4552
- payment_url: initData.authorization_url
4554
+ payment_url: initData.authorizationUrl
4553
4555
  };
4554
4556
  };
4555
4557
  retrievePayment = async (id) => {
@@ -4615,7 +4617,9 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4615
4617
  });
4616
4618
  }
4617
4619
  const expectedSignature = createHmac("sha512", webhookSecret).update(body).digest("hex");
4618
- if (expectedSignature !== signature) {
4620
+ const expectedBuf = Buffer.from(expectedSignature, "hex");
4621
+ const receivedBuf = Buffer.from(signature, "hex");
4622
+ if (expectedBuf.length !== receivedBuf.length || !timingSafeEqual(expectedBuf, receivedBuf)) {
4619
4623
  throw new WebhookError("Invalid Paystack webhook signature", {
4620
4624
  provider: this.providerName
4621
4625
  });
@@ -26,6 +26,7 @@ declare class PaystackProvider extends AbstractPayKitProvider implements PayKitP
26
26
  get _native(): null;
27
27
  private _toCamel;
28
28
  private unwrap;
29
+ private initializeTransaction;
29
30
  createCheckout: (params: CreateCheckoutSchema<PaystackMetadata["checkout"]>) => Promise<Checkout>;
30
31
  retrieveCheckout: (id: string) => Promise<Checkout | null>;
31
32
  updateCheckout: (_id: string, _params: UpdateCheckoutSchema<PaystackMetadata["checkout"]>) => Promise<Checkout>;
@@ -26,6 +26,7 @@ declare class PaystackProvider extends AbstractPayKitProvider implements PayKitP
26
26
  get _native(): null;
27
27
  private _toCamel;
28
28
  private unwrap;
29
+ private initializeTransaction;
29
30
  createCheckout: (params: CreateCheckoutSchema<PaystackMetadata["checkout"]>) => Promise<Checkout>;
30
31
  retrieveCheckout: (id: string) => Promise<Checkout | null>;
31
32
  updateCheckout: (_id: string, _params: UpdateCheckoutSchema<PaystackMetadata["checkout"]>) => Promise<Checkout>;
@@ -4121,20 +4121,10 @@ var Checkout$inboundSchema = (init, transaction) => {
4121
4121
  type: core.billingModeSchema.optional()
4122
4122
  })
4123
4123
  );
4124
- if (paykitMeta && typeof paykitMeta === "string") {
4125
- const parsed = core.parseJSON(
4126
- paykitMeta,
4127
- core.Schema.object({
4128
- item_id: core.Schema.string().optional(),
4129
- quantity: core.Schema.number().optional(),
4130
- type: core.billingModeSchema.optional()
4131
- })
4132
- );
4133
- if (parsed) {
4134
- itemId = parsed.item_id ?? "";
4135
- quantity = parsed.quantity ?? 1;
4136
- type = parsed.type ?? null;
4137
- }
4124
+ if (paykitMeta) {
4125
+ itemId = paykitMeta.item_id ?? "";
4126
+ quantity = paykitMeta.quantity ?? 1;
4127
+ type = paykitMeta.type ?? null;
4138
4128
  }
4139
4129
  let customer = null;
4140
4130
  if (transaction.customer?.email) {
@@ -4145,7 +4135,7 @@ var Checkout$inboundSchema = (init, transaction) => {
4145
4135
  return {
4146
4136
  id: init.reference,
4147
4137
  customer,
4148
- payment_url: init.authorization_url,
4138
+ payment_url: init.authorizationUrl,
4149
4139
  metadata: Object.keys(metadata).length > 0 ? metadata : null,
4150
4140
  session_type: type ?? "one_time",
4151
4141
  products: [{ id: itemId, quantity }],
@@ -4276,6 +4266,19 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4276
4266
  }
4277
4267
  return this._toCamel(result.value.data);
4278
4268
  }
4269
+ async initializeTransaction(params) {
4270
+ const body = {
4271
+ ...params.providerMetadata,
4272
+ email: params.email,
4273
+ amount: params.amount,
4274
+ currency: params.currency.toUpperCase(),
4275
+ reference: crypto.randomUUID(),
4276
+ ...params.callbackUrl && { callback_url: params.callbackUrl },
4277
+ metadata: core.stringifyMetadataValues(params.metadata)
4278
+ };
4279
+ const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4280
+ return this.unwrap(response, "initializeTransaction");
4281
+ }
4279
4282
  createCheckout = async (params) => {
4280
4283
  const { error, data } = core.createCheckoutSchema.safeParse(params);
4281
4284
  if (error) {
@@ -4293,7 +4296,11 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4293
4296
  { provider: this.providerName, method: "createCheckout" }
4294
4297
  );
4295
4298
  }
4296
- const { amount, currency = "NGN" } = data.provider_metadata ?? {};
4299
+ const { amount, currency = "NGN" } = core.validateRequiredKeys(
4300
+ ["amount", "currency"],
4301
+ data.provider_metadata ?? {},
4302
+ "Missing required provider metadata: {keys}"
4303
+ );
4297
4304
  const metadata = {
4298
4305
  ...core.stringifyMetadataValues(data.metadata ?? {}),
4299
4306
  [core.PAYKIT_METADATA_KEY]: JSON.stringify({
@@ -4302,21 +4309,20 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4302
4309
  type: data.session_type
4303
4310
  })
4304
4311
  };
4305
- const body = {
4312
+ const parsedAmount = parseInt(amount, 10);
4313
+ const upperCurrency = currency.toUpperCase();
4314
+ const initData = await this.initializeTransaction({
4306
4315
  email: data.customer.email,
4307
- amount: amount ?? 0,
4308
- currency,
4309
- reference: crypto.randomUUID(),
4310
- callback_url: data.success_url,
4311
- metadata: core.stringifyMetadataValues(metadata),
4312
- ...data.provider_metadata
4313
- };
4314
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4315
- const initData = await this.unwrap(response, "createCheckout");
4316
+ amount: parsedAmount,
4317
+ currency: upperCurrency,
4318
+ metadata,
4319
+ callbackUrl: data.success_url,
4320
+ providerMetadata: data.provider_metadata
4321
+ });
4316
4322
  const rawCustomer = await this._client.get(`/customer/${encodeURIComponent(data.customer.email)}`);
4317
4323
  return Checkout$inboundSchema(initData, {
4318
- amount: body.amount,
4319
- currency: body.currency,
4324
+ amount: parsedAmount,
4325
+ currency: upperCurrency,
4320
4326
  customer: await this.unwrap(rawCustomer, "createCheckout"),
4321
4327
  metadata: JSON.stringify(metadata)
4322
4328
  });
@@ -4327,7 +4333,7 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4327
4333
  const txn = response.value.data;
4328
4334
  return Checkout$inboundSchema(
4329
4335
  {
4330
- authorization_url: "",
4336
+ authorizationUrl: "",
4331
4337
  reference: txn.reference
4332
4338
  },
4333
4339
  txn
@@ -4523,23 +4529,19 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4523
4529
  item_id: data.item_id
4524
4530
  })
4525
4531
  };
4526
- const reference = crypto.randomUUID();
4527
- const body = {
4528
- email,
4529
- amount: data.amount,
4530
- currency: data.currency,
4531
- reference,
4532
- metadata,
4533
- ...data.provider_metadata
4534
- };
4535
4532
  if (this.opts.debug) {
4536
4533
  console.info("[Paystack] Initializing transaction", {
4537
4534
  email,
4538
4535
  amount: data.amount
4539
4536
  });
4540
4537
  }
4541
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4542
- const initData = await this.unwrap(response, "createPayment");
4538
+ const initData = await this.initializeTransaction({
4539
+ email,
4540
+ amount: data.amount,
4541
+ currency: data.currency,
4542
+ metadata,
4543
+ providerMetadata: data.provider_metadata
4544
+ });
4543
4545
  return {
4544
4546
  id: initData.reference,
4545
4547
  amount: data.amount,
@@ -4551,7 +4553,7 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4551
4553
  ),
4552
4554
  item_id: data.item_id ?? null,
4553
4555
  requires_action: true,
4554
- payment_url: initData.authorization_url
4556
+ payment_url: initData.authorizationUrl
4555
4557
  };
4556
4558
  };
4557
4559
  retrievePayment = async (id) => {
@@ -4617,7 +4619,9 @@ var PaystackProvider = class extends core.AbstractPayKitProvider {
4617
4619
  });
4618
4620
  }
4619
4621
  const expectedSignature = crypto$1.createHmac("sha512", webhookSecret).update(body).digest("hex");
4620
- if (expectedSignature !== signature) {
4622
+ const expectedBuf = Buffer.from(expectedSignature, "hex");
4623
+ const receivedBuf = Buffer.from(signature, "hex");
4624
+ if (expectedBuf.length !== receivedBuf.length || !crypto$1.timingSafeEqual(expectedBuf, receivedBuf)) {
4621
4625
  throw new core.WebhookError("Invalid Paystack webhook signature", {
4622
4626
  provider: this.providerName
4623
4627
  });
@@ -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, stringifyMetadataValues, createCheckoutSchema, ValidationError, isEmailCustomer, InvalidTypeError, validateRequiredKeys, PAYKIT_METADATA_KEY, 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) => {
@@ -4119,20 +4119,10 @@ var Checkout$inboundSchema = (init, transaction) => {
4119
4119
  type: billingModeSchema.optional()
4120
4120
  })
4121
4121
  );
4122
- if (paykitMeta && typeof paykitMeta === "string") {
4123
- const parsed = parseJSON(
4124
- paykitMeta,
4125
- Schema.object({
4126
- item_id: Schema.string().optional(),
4127
- quantity: Schema.number().optional(),
4128
- type: billingModeSchema.optional()
4129
- })
4130
- );
4131
- if (parsed) {
4132
- itemId = parsed.item_id ?? "";
4133
- quantity = parsed.quantity ?? 1;
4134
- type = parsed.type ?? null;
4135
- }
4122
+ if (paykitMeta) {
4123
+ itemId = paykitMeta.item_id ?? "";
4124
+ quantity = paykitMeta.quantity ?? 1;
4125
+ type = paykitMeta.type ?? null;
4136
4126
  }
4137
4127
  let customer = null;
4138
4128
  if (transaction.customer?.email) {
@@ -4143,7 +4133,7 @@ var Checkout$inboundSchema = (init, transaction) => {
4143
4133
  return {
4144
4134
  id: init.reference,
4145
4135
  customer,
4146
- payment_url: init.authorization_url,
4136
+ payment_url: init.authorizationUrl,
4147
4137
  metadata: Object.keys(metadata).length > 0 ? metadata : null,
4148
4138
  session_type: type ?? "one_time",
4149
4139
  products: [{ id: itemId, quantity }],
@@ -4274,6 +4264,19 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4274
4264
  }
4275
4265
  return this._toCamel(result.value.data);
4276
4266
  }
4267
+ async initializeTransaction(params) {
4268
+ const body = {
4269
+ ...params.providerMetadata,
4270
+ email: params.email,
4271
+ amount: params.amount,
4272
+ currency: params.currency.toUpperCase(),
4273
+ reference: crypto.randomUUID(),
4274
+ ...params.callbackUrl && { callback_url: params.callbackUrl },
4275
+ metadata: stringifyMetadataValues(params.metadata)
4276
+ };
4277
+ const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4278
+ return this.unwrap(response, "initializeTransaction");
4279
+ }
4277
4280
  createCheckout = async (params) => {
4278
4281
  const { error, data } = createCheckoutSchema.safeParse(params);
4279
4282
  if (error) {
@@ -4291,7 +4294,11 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4291
4294
  { provider: this.providerName, method: "createCheckout" }
4292
4295
  );
4293
4296
  }
4294
- const { amount, currency = "NGN" } = data.provider_metadata ?? {};
4297
+ const { amount, currency = "NGN" } = validateRequiredKeys(
4298
+ ["amount", "currency"],
4299
+ data.provider_metadata ?? {},
4300
+ "Missing required provider metadata: {keys}"
4301
+ );
4295
4302
  const metadata = {
4296
4303
  ...stringifyMetadataValues(data.metadata ?? {}),
4297
4304
  [PAYKIT_METADATA_KEY]: JSON.stringify({
@@ -4300,21 +4307,20 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4300
4307
  type: data.session_type
4301
4308
  })
4302
4309
  };
4303
- const body = {
4310
+ const parsedAmount = parseInt(amount, 10);
4311
+ const upperCurrency = currency.toUpperCase();
4312
+ const initData = await this.initializeTransaction({
4304
4313
  email: data.customer.email,
4305
- amount: amount ?? 0,
4306
- currency,
4307
- reference: crypto.randomUUID(),
4308
- callback_url: data.success_url,
4309
- metadata: stringifyMetadataValues(metadata),
4310
- ...data.provider_metadata
4311
- };
4312
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4313
- const initData = await this.unwrap(response, "createCheckout");
4314
+ amount: parsedAmount,
4315
+ currency: upperCurrency,
4316
+ metadata,
4317
+ callbackUrl: data.success_url,
4318
+ providerMetadata: data.provider_metadata
4319
+ });
4314
4320
  const rawCustomer = await this._client.get(`/customer/${encodeURIComponent(data.customer.email)}`);
4315
4321
  return Checkout$inboundSchema(initData, {
4316
- amount: body.amount,
4317
- currency: body.currency,
4322
+ amount: parsedAmount,
4323
+ currency: upperCurrency,
4318
4324
  customer: await this.unwrap(rawCustomer, "createCheckout"),
4319
4325
  metadata: JSON.stringify(metadata)
4320
4326
  });
@@ -4325,7 +4331,7 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4325
4331
  const txn = response.value.data;
4326
4332
  return Checkout$inboundSchema(
4327
4333
  {
4328
- authorization_url: "",
4334
+ authorizationUrl: "",
4329
4335
  reference: txn.reference
4330
4336
  },
4331
4337
  txn
@@ -4521,23 +4527,19 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4521
4527
  item_id: data.item_id
4522
4528
  })
4523
4529
  };
4524
- const reference = crypto.randomUUID();
4525
- const body = {
4526
- email,
4527
- amount: data.amount,
4528
- currency: data.currency,
4529
- reference,
4530
- metadata,
4531
- ...data.provider_metadata
4532
- };
4533
4530
  if (this.opts.debug) {
4534
4531
  console.info("[Paystack] Initializing transaction", {
4535
4532
  email,
4536
4533
  amount: data.amount
4537
4534
  });
4538
4535
  }
4539
- const response = await this._client.post("/transaction/initialize", { body: JSON.stringify(body) });
4540
- const initData = await this.unwrap(response, "createPayment");
4536
+ const initData = await this.initializeTransaction({
4537
+ email,
4538
+ amount: data.amount,
4539
+ currency: data.currency,
4540
+ metadata,
4541
+ providerMetadata: data.provider_metadata
4542
+ });
4541
4543
  return {
4542
4544
  id: initData.reference,
4543
4545
  amount: data.amount,
@@ -4549,7 +4551,7 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4549
4551
  ),
4550
4552
  item_id: data.item_id ?? null,
4551
4553
  requires_action: true,
4552
- payment_url: initData.authorization_url
4554
+ payment_url: initData.authorizationUrl
4553
4555
  };
4554
4556
  };
4555
4557
  retrievePayment = async (id) => {
@@ -4615,7 +4617,9 @@ var PaystackProvider = class extends AbstractPayKitProvider {
4615
4617
  });
4616
4618
  }
4617
4619
  const expectedSignature = createHmac("sha512", webhookSecret).update(body).digest("hex");
4618
- if (expectedSignature !== signature) {
4620
+ const expectedBuf = Buffer.from(expectedSignature, "hex");
4621
+ const receivedBuf = Buffer.from(signature, "hex");
4622
+ if (expectedBuf.length !== receivedBuf.length || !timingSafeEqual(expectedBuf, receivedBuf)) {
4619
4623
  throw new WebhookError("Invalid Paystack webhook signature", {
4620
4624
  provider: this.providerName
4621
4625
  });
package/dist/schema.d.mts CHANGED
@@ -202,15 +202,19 @@ interface PaystackTransaction {
202
202
  */
203
203
  subaccount?: Record<string, unknown> | null;
204
204
  }
205
+ /**
206
+ * Shape as returned by `unwrap()`, i.e. *after* `_toCamel` has run on
207
+ * Paystack's raw (snake_case) `/transaction/initialize` response.
208
+ */
205
209
  interface PaystackInitializeResponse {
206
210
  /**
207
211
  * The authorization URL of the transaction
208
212
  */
209
- authorization_url: string;
213
+ authorizationUrl: string;
210
214
  /**
211
215
  * The access code of the transaction
212
216
  */
213
- access_code: string;
217
+ accessCode: string;
214
218
  /**
215
219
  * The reference of the transaction
216
220
  */
package/dist/schema.d.ts CHANGED
@@ -202,15 +202,19 @@ interface PaystackTransaction {
202
202
  */
203
203
  subaccount?: Record<string, unknown> | null;
204
204
  }
205
+ /**
206
+ * Shape as returned by `unwrap()`, i.e. *after* `_toCamel` has run on
207
+ * Paystack's raw (snake_case) `/transaction/initialize` response.
208
+ */
205
209
  interface PaystackInitializeResponse {
206
210
  /**
207
211
  * The authorization URL of the transaction
208
212
  */
209
- authorization_url: string;
213
+ authorizationUrl: string;
210
214
  /**
211
215
  * The access code of the transaction
212
216
  */
213
- access_code: string;
217
+ accessCode: string;
214
218
  /**
215
219
  * The reference of the transaction
216
220
  */
@@ -76,20 +76,10 @@ var Checkout$inboundSchema = (init, transaction) => {
76
76
  type: core.billingModeSchema.optional()
77
77
  })
78
78
  );
79
- if (paykitMeta && typeof paykitMeta === "string") {
80
- const parsed = core.parseJSON(
81
- paykitMeta,
82
- core.Schema.object({
83
- item_id: core.Schema.string().optional(),
84
- quantity: core.Schema.number().optional(),
85
- type: core.billingModeSchema.optional()
86
- })
87
- );
88
- if (parsed) {
89
- itemId = parsed.item_id ?? "";
90
- quantity = parsed.quantity ?? 1;
91
- type = parsed.type ?? null;
92
- }
79
+ if (paykitMeta) {
80
+ itemId = paykitMeta.item_id ?? "";
81
+ quantity = paykitMeta.quantity ?? 1;
82
+ type = paykitMeta.type ?? null;
93
83
  }
94
84
  let customer = null;
95
85
  if (transaction.customer?.email) {
@@ -100,7 +90,7 @@ var Checkout$inboundSchema = (init, transaction) => {
100
90
  return {
101
91
  id: init.reference,
102
92
  customer,
103
- payment_url: init.authorization_url,
93
+ payment_url: init.authorizationUrl,
104
94
  metadata: Object.keys(metadata).length > 0 ? metadata : null,
105
95
  session_type: type ?? "one_time",
106
96
  products: [{ id: itemId, quantity }],
@@ -74,20 +74,10 @@ var Checkout$inboundSchema = (init, transaction) => {
74
74
  type: billingModeSchema.optional()
75
75
  })
76
76
  );
77
- if (paykitMeta && typeof paykitMeta === "string") {
78
- const parsed = parseJSON(
79
- paykitMeta,
80
- Schema.object({
81
- item_id: Schema.string().optional(),
82
- quantity: Schema.number().optional(),
83
- type: billingModeSchema.optional()
84
- })
85
- );
86
- if (parsed) {
87
- itemId = parsed.item_id ?? "";
88
- quantity = parsed.quantity ?? 1;
89
- type = parsed.type ?? null;
90
- }
77
+ if (paykitMeta) {
78
+ itemId = paykitMeta.item_id ?? "";
79
+ quantity = paykitMeta.quantity ?? 1;
80
+ type = paykitMeta.type ?? null;
91
81
  }
92
82
  let customer = null;
93
83
  if (transaction.customer?.email) {
@@ -98,7 +88,7 @@ var Checkout$inboundSchema = (init, transaction) => {
98
88
  return {
99
89
  id: init.reference,
100
90
  customer,
101
- payment_url: init.authorization_url,
91
+ payment_url: init.authorizationUrl,
102
92
  metadata: Object.keys(metadata).length > 0 ? metadata : null,
103
93
  session_type: type ?? "one_time",
104
94
  products: [{ id: itemId, quantity }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paykit-sdk/paystack",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
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": ">=1.2.2"
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.1"
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
+ }