Spaces:
Running
Running
Download apps/api/dist/billing/paystack.service.js from Benaah/MicProtocol: direct link, hf CLI and curl.
- Browser
- Download file 13.2 kB
-
https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/apps/api/dist/billing/paystack.service.js
- Command line
-
hf download hf://spaces/Benaah/MicProtocol/apps/api/dist/billing/paystack.service.js
-
curl -L -o paystack.service.js https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/apps/api/dist/billing/paystack.service.js
13.2 kB
| ; | |
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | |
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | |
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | |
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | |
| return c > 3 && r && Object.defineProperty(target, key, r), r; | |
| }; | |
| var __metadata = (this && this.__metadata) || function (k, v) { | |
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | |
| }; | |
| var PaystackService_1; | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.PaystackService = void 0; | |
| const common_1 = require("@nestjs/common"); | |
| const config_1 = require("@nestjs/config"); | |
| let PaystackService = PaystackService_1 = class PaystackService { | |
| configService; | |
| logger = new common_1.Logger(PaystackService_1.name); | |
| secretKey; | |
| publicKey; | |
| baseUrl = 'https://api.paystack.co'; | |
| callbackUrl; | |
| constructor(configService) { | |
| this.configService = configService; | |
| this.secretKey = this.configService.get('PAYSTACK_SECRET_KEY') || ''; | |
| this.publicKey = this.configService.get('PAYSTACK_PUBLIC_KEY') || ''; | |
| this.callbackUrl = this.configService.get('PAYSTACK_CALLBACK_URL') || ''; | |
| if (!this.secretKey) { | |
| this.logger.warn('PAYSTACK_SECRET_KEY is not configured'); | |
| } | |
| } | |
| isConfigured() { | |
| return Boolean(this.secretKey); | |
| } | |
| getPublicKey() { | |
| return this.publicKey; | |
| } | |
| getHeaders() { | |
| return { | |
| Authorization: `Bearer ${this.secretKey}`, | |
| 'Content-Type': 'application/json', | |
| }; | |
| } | |
| async initializeTransaction(input) { | |
| if (!this.secretKey) { | |
| throw new Error('Paystack is not configured'); | |
| } | |
| const body = { | |
| email: input.email, | |
| amount: Math.round(input.amount), | |
| reference: input.reference, | |
| }; | |
| if (input.currency) | |
| body.currency = input.currency; | |
| if (input.callbackUrl) | |
| body.callback_url = input.callbackUrl; | |
| if (input.metadata) | |
| body.metadata = JSON.stringify(input.metadata); | |
| if (input.channels?.length) | |
| body.channels = input.channels; | |
| const response = await fetch(`${this.baseUrl}/transaction/initialize`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify(body), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack initialize failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to initialize Paystack transaction'); | |
| } | |
| return { | |
| authorizationUrl: payload.data.authorization_url, | |
| accessCode: payload.data.access_code, | |
| reference: payload.data.reference, | |
| }; | |
| } | |
| async createMobileMoneyCharge(input) { | |
| if (!this.secretKey) { | |
| throw new Error('Paystack is not configured'); | |
| } | |
| const body = { | |
| email: input.email, | |
| amount: Math.round(input.amount), | |
| reference: input.reference, | |
| mobile_money: { | |
| phone: this.normalizeMobileMoneyPhone(input.mobileMoney.phone), | |
| provider: input.mobileMoney.provider, | |
| }, | |
| }; | |
| if (input.currency) | |
| body.currency = input.currency; | |
| if (input.callbackUrl) | |
| body.callback_url = input.callbackUrl; | |
| if (input.metadata) | |
| body.metadata = JSON.stringify(input.metadata); | |
| const response = await fetch(`${this.baseUrl}/charge`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify(body), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack mobile money charge failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to initiate Paystack mobile money charge'); | |
| } | |
| return { | |
| status: payload.data.status, | |
| reference: payload.data.reference, | |
| displayMessage: payload.data.display_message, | |
| providerReference: payload.data.provider_reference, | |
| }; | |
| } | |
| async verifyTransaction(reference) { | |
| if (!this.secretKey) { | |
| throw new Error('Paystack is not configured'); | |
| } | |
| const response = await fetch(`${this.baseUrl}/transaction/verify/${encodeURIComponent(reference)}`, { method: 'GET', headers: this.getHeaders() }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack verify failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to verify Paystack transaction'); | |
| } | |
| return { | |
| status: payload.data.status, | |
| amount: payload.data.amount, | |
| currency: payload.data.currency, | |
| reference: payload.data.reference, | |
| channel: payload.data.channel, | |
| paidAt: payload.data.paid_at ?? null, | |
| gatewayResponse: payload.data.gateway_response, | |
| authorizationCode: payload.data.authorization?.authorization_code, | |
| }; | |
| } | |
| verifyWebhookSignature(rawBody, signatureHeader) { | |
| if (!this.secretKey || !signatureHeader) | |
| return false; | |
| const { createHmac } = require('crypto'); | |
| const expected = createHmac('sha512', this.secretKey).update(rawBody).digest('hex'); | |
| if (expected.length !== signatureHeader.length) | |
| return false; | |
| let mismatch = 0; | |
| for (let i = 0; i < expected.length; i++) { | |
| mismatch |= expected.charCodeAt(i) ^ signatureHeader.charCodeAt(i); | |
| } | |
| return mismatch === 0; | |
| } | |
| async createPlan(input) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const body = { | |
| name: input.name, | |
| amount: Math.round(input.amount), | |
| interval: input.interval, | |
| }; | |
| if (input.currency) | |
| body.currency = input.currency; | |
| if (input.description) | |
| body.description = input.description; | |
| if (input.planCode) | |
| body.plan_code = input.planCode; | |
| const response = await fetch(`${this.baseUrl}/plan`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify(body), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack plan creation failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to create Paystack plan'); | |
| } | |
| return payload.data; | |
| } | |
| async fetchPlan(idOrCode) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const response = await fetch(`${this.baseUrl}/plan/${encodeURIComponent(idOrCode)}`, { method: 'GET', headers: this.getHeaders() }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) | |
| return null; | |
| return payload.data; | |
| } | |
| async createSubscription(input) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const body = { | |
| customer: input.customerCode, | |
| plan: input.planCode, | |
| }; | |
| if (input.authorizationCode) | |
| body.authorization = input.authorizationCode; | |
| if (input.startDate) | |
| body.start_date = input.startDate; | |
| const response = await fetch(`${this.baseUrl}/subscription`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify(body), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack subscription creation failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to create Paystack subscription'); | |
| } | |
| return payload.data; | |
| } | |
| async fetchSubscription(idOrCode) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const response = await fetch(`${this.baseUrl}/subscription/${encodeURIComponent(idOrCode)}`, { method: 'GET', headers: this.getHeaders() }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) | |
| return null; | |
| return payload.data; | |
| } | |
| async disableSubscription(subscriptionCode, token) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const response = await fetch(`${this.baseUrl}/subscription/disable`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify({ | |
| code: subscriptionCode, | |
| token, | |
| }), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack subscription disable failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to disable Paystack subscription'); | |
| } | |
| return payload.data; | |
| } | |
| async enableSubscription(subscriptionCode, token) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const response = await fetch(`${this.baseUrl}/subscription/enable`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify({ | |
| code: subscriptionCode, | |
| token, | |
| }), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack subscription enable failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to enable Paystack subscription'); | |
| } | |
| return payload.data; | |
| } | |
| async refundTransaction(reference, amountInSubunits) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const body = { transaction: reference }; | |
| if (typeof amountInSubunits === 'number') | |
| body.amount = amountInSubunits; | |
| const response = await fetch(`${this.baseUrl}/refund`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify(body), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack refund failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to refund Paystack transaction'); | |
| } | |
| return payload.data; | |
| } | |
| async createCustomer(input) { | |
| if (!this.secretKey) | |
| throw new Error('Paystack is not configured'); | |
| const body = { email: input.email }; | |
| if (input.firstName) | |
| body.first_name = input.firstName; | |
| if (input.lastName) | |
| body.last_name = input.lastName; | |
| if (input.phone) | |
| body.phone = input.phone; | |
| if (input.metadata) | |
| body.metadata = input.metadata; | |
| const response = await fetch(`${this.baseUrl}/customer`, { | |
| method: 'POST', | |
| headers: this.getHeaders(), | |
| body: JSON.stringify(body), | |
| }); | |
| const payload = (await response.json()); | |
| if (!response.ok || !payload.status || !payload.data) { | |
| this.logger.error(`Paystack customer creation failed: ${JSON.stringify(payload)}`); | |
| throw new Error(payload.message || 'Failed to create Paystack customer'); | |
| } | |
| return payload.data; | |
| } | |
| normalizeMobileMoneyPhone(phone) { | |
| const digits = phone.replace(/\D/g, ''); | |
| if (digits.startsWith('254') && digits.length === 12) { | |
| return `0${digits.slice(3)}`; | |
| } | |
| if (digits.startsWith('0') && digits.length === 10) { | |
| return digits; | |
| } | |
| if (digits.length === 9) { | |
| return `0${digits}`; | |
| } | |
| throw new Error('Invalid phone number. Use 07XX, 01XX, or 2547XXXXXXXX format.'); | |
| } | |
| }; | |
| exports.PaystackService = PaystackService; | |
| exports.PaystackService = PaystackService = PaystackService_1 = __decorate([ | |
| (0, common_1.Injectable)(), | |
| __metadata("design:paramtypes", [config_1.ConfigService]) | |
| ], PaystackService); | |
| //# sourceMappingURL=paystack.service.js.map |