UNPKG

@jokoor/sdk

Version:

Official Jokoor API SDK for JavaScript/TypeScript - SMS, Payments, and more

1,799 lines (1,778 loc) 86.3 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all2) => { for (var name in all2) __defProp(target, name, { get: all2[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { Jokoor: () => Jokoor, JokoorAPIError: () => JokoorAPIError, JokoorAuthenticationError: () => JokoorAuthenticationError, JokoorError: () => JokoorError, JokoorNetworkError: () => JokoorNetworkError, JokoorNotFoundError: () => JokoorNotFoundError, JokoorPermissionError: () => JokoorPermissionError, JokoorRateLimitError: () => JokoorRateLimitError, JokoorTimeoutError: () => JokoorTimeoutError, JokoorValidationError: () => JokoorValidationError, all: () => all, chain: () => chain, createClient: () => createClient, default: () => index_default, err: () => err, fromPromise: () => fromPromise, isErr: () => isErr, isJokoorError: () => isJokoorError, isOk: () => isOk, map: () => map, ok: () => ok, unwrap: () => unwrap, unwrapOr: () => unwrapOr }); module.exports = __toCommonJS(index_exports); // src/http-client.ts var import_axios = __toESM(require("axios")); var import_axios_retry = __toESM(require("axios-retry")); // src/types/result.ts function ok(data) { return { data, error: null }; } function err(error) { return { data: null, error }; } function isOk(result) { return result.error === null; } function isErr(result) { return result.error !== null; } function unwrap(result) { if (isErr(result)) { throw new Error(result.error); } return result.data; } function unwrapOr(result, defaultValue) { if (isErr(result)) { return defaultValue; } return result.data; } function map(result, fn) { if (isErr(result)) { return result; } return ok(fn(result.data)); } function chain(result, fn) { if (isErr(result)) { return result; } return fn(result.data); } async function fromPromise(promise) { try { const data = await promise; return ok(data); } catch (error) { const message = error instanceof Error ? error.message : String(error); return err(message); } } function all(results) { const data = []; for (const result of results) { if (isErr(result)) { return result; } data.push(result.data); } return ok(data); } // src/utils/case-converter.ts function toSnakeCase(str) { return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`); } function toCamelCase(str) { return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()); } function keysToSnakeCase(obj) { if (obj === null || obj === void 0) { return obj; } if (Array.isArray(obj)) { return obj.map((item) => keysToSnakeCase(item)); } if (typeof obj === "object" && obj !== null) { const converted = {}; for (const [key, value] of Object.entries(obj)) { const snakeKey = toSnakeCase(key); converted[snakeKey] = keysToSnakeCase(value); } return converted; } return obj; } function keysToCamelCase(obj) { if (obj === null || obj === void 0) { return obj; } if (Array.isArray(obj)) { return obj.map((item) => keysToCamelCase(item)); } if (typeof obj === "object" && obj !== null) { const converted = {}; for (const [key, value] of Object.entries(obj)) { const camelKey = toCamelCase(key); converted[camelKey] = keysToCamelCase(value); } return converted; } return obj; } // src/http-client.ts var DEFAULT_BASE_URL = "https://api.jokoor.com/v1"; var DEFAULT_TIMEOUT = 3e4; var DEFAULT_MAX_RETRIES = 3; var HttpClient = class { client; debug; constructor(config) { this.debug = config.debug || false; this.client = import_axios.default.create({ baseURL: config.baseURL || DEFAULT_BASE_URL, timeout: config.timeout || DEFAULT_TIMEOUT, headers: { Authorization: `Bearer ${config.apiKey}`, "Content-Type": "application/json", "User-Agent": "@jokoor/sdk/1.0.0", "X-SDK-Version": "1.0.0", "X-SDK-Language": "typescript" } }); (0, import_axios_retry.default)(this.client, { retries: config.maxRetries || DEFAULT_MAX_RETRIES, retryDelay: import_axios_retry.default.exponentialDelay, retryCondition: (error) => { return import_axios_retry.default.isNetworkOrIdempotentRequestError(error) || error.response?.status !== void 0 && error.response.status >= 500; }, onRetry: (retryCount, error) => { if (this.debug) { console.warn(`Retry attempt ${retryCount} for ${error.config?.url}`); } } }); this.client.interceptors.request.use( (config2) => { if (config2.data && typeof config2.data === "object" && !(config2.data instanceof FormData)) { config2.data = keysToSnakeCase(config2.data); } if (this.debug) { console.log( `[Request] ${config2.method?.toUpperCase()} ${config2.url}` ); if (config2.data && !(config2.data instanceof FormData)) { console.log("[Request Body]", JSON.stringify(config2.data, null, 2)); } else if (config2.data instanceof FormData) { console.log("[Request Body] FormData (file upload)"); } } return config2; }, (error) => { if (this.debug) { console.error("[Request Error]", error); } return Promise.reject(error); } ); if (this.debug) { this.client.interceptors.response.use( (response) => { console.log(`[Response] ${response.status} ${response.config.url}`); if (response.data) { console.log( "[Response Body]", JSON.stringify(response.data, null, 2) ); } return response; }, (error) => { if (error.response) { console.error( `[Response Error] ${error.response.status} ${error.config?.url}` ); console.error("[Error Body]", error.response.data); } else { console.error("[Network Error]", error.message); } return Promise.reject(error); } ); } } /** * Make a GET request */ async get(url, config) { return this.request({ method: "GET", url, ...config }); } /** * Make a POST request */ async post(url, data, config) { return this.request({ method: "POST", url, data, ...config }); } /** * Make a PUT request */ async put(url, data, config) { return this.request({ method: "PUT", url, data, ...config }); } /** * Make a DELETE request */ async delete(url, config) { return this.request({ method: "DELETE", url, ...config }); } /** * Generic request method with error handling */ async request(config) { try { const response = await this.client.request(config); if (response.data.error) { return err(response.data.error); } if (response.data.data !== void 0) { const camelCaseData2 = keysToCamelCase(response.data.data); return ok(camelCaseData2); } const camelCaseData = keysToCamelCase(response.data); return ok(camelCaseData); } catch (error) { return err(this.extractErrorMessage(error)); } } /** * Extract error message from axios error */ extractErrorMessage(error) { if (import_axios.default.isAxiosError(error)) { const axiosError = error; if (axiosError.response?.data?.error) { return String(axiosError.response.data.error); } const status = axiosError.response?.status; if (status === 404) { return "Resource not found"; } else if (status === 401) { return "Authentication failed - invalid API key"; } else if (status === 403) { return "Permission denied"; } else if (status === 429) { return "Rate limit exceeded"; } else if (status === 400) { return axiosError.response?.data?.error || "Bad request - invalid parameters"; } else if (status === 500) { return "Internal server error"; } else if (status === 502 || status === 503 || status === 504) { return "Service temporarily unavailable"; } else if (status) { const statusText = axiosError.response?.statusText || "Unknown error"; return `API Error: ${status} ${statusText}`; } if (axiosError.code === "ECONNREFUSED") { return "Unable to connect to API server"; } else if (axiosError.code === "ENOTFOUND") { return "API server not found"; } else if (axiosError.code === "ETIMEDOUT") { return "Request timed out"; } else if (axiosError.code === "ECONNRESET") { return "Connection was reset"; } return axiosError.message || "An unexpected error occurred"; } if (error instanceof Error) { return error.message; } return String(error); } }; // src/errors.ts var JokoorError = class _JokoorError extends Error { constructor(message) { super(message); this.name = "JokoorError"; if (Error.captureStackTrace) { Error.captureStackTrace(this, _JokoorError); } } }; var JokoorAPIError = class extends JokoorError { statusCode; code; response; constructor(message, statusCode, code, response) { super(message); this.name = "JokoorAPIError"; this.statusCode = statusCode; this.code = code; this.response = response; } }; var JokoorAuthenticationError = class extends JokoorError { constructor(message = "Authentication failed") { super(message); this.name = "JokoorAuthenticationError"; } }; var JokoorPermissionError = class extends JokoorError { constructor(message = "Permission denied") { super(message); this.name = "JokoorPermissionError"; } }; var JokoorNotFoundError = class extends JokoorError { constructor(message = "Resource not found") { super(message); this.name = "JokoorNotFoundError"; } }; var JokoorRateLimitError = class extends JokoorError { constructor(message = "Rate limit exceeded") { super(message); this.name = "JokoorRateLimitError"; } }; var JokoorValidationError = class extends JokoorError { errors; constructor(message = "Validation failed", errors) { super(message); this.name = "JokoorValidationError"; this.errors = errors; } }; var JokoorNetworkError = class extends JokoorError { constructor(message = "Network error occurred") { super(message); this.name = "JokoorNetworkError"; } }; var JokoorTimeoutError = class extends JokoorError { constructor(message = "Request timed out") { super(message); this.name = "JokoorTimeoutError"; } }; function isJokoorError(error) { return error instanceof JokoorError; } // src/resources/base.ts var BaseResource = class { client; constructor(client) { this.client = client; } /** * Extract paginated data from API response */ extractPaginatedData(result) { if (result.error) { return { data: null, error: result.error }; } const data = result.data; return { data: { items: data.items || [], count: data.count || 0, offset: data.offset || 0, limit: data.limit || 20 }, error: null }; } }; // src/resources/sms.ts var SMS = class extends BaseResource { /** * Send an SMS message * * @param params - SMS parameters * @returns SMS message details * * @example * ```typescript * const { data, error } = await jokoor.sms.send({ * recipientPhone: '+2207123456', * messageBody: 'Hello from Jokoor!' * }); * ``` */ async send(params) { if (!params.recipientPhone && !params.contactId) { return { data: null, error: "Either recipientPhone or contactId must be provided" }; } if (!params.messageBody && !params.templateId) { return { data: null, error: "Either messageBody or templateId must be provided" }; } return this.client.post("/sms", params); } /** * Get SMS message details * * @param id - SMS message ID * @returns SMS message details */ async get(id) { if (!id) { return { data: null, error: "SMS message ID is required" }; } return this.client.get(`/sms/${id}`); } /** * List SMS messages * * @param options - List options * @returns Paginated list of SMS messages */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); if (options?.contactId) params.set("contact_id", options.contactId); if (options?.startDate) params.set("start_date", options.startDate); if (options?.endDate) params.set("end_date", options.endDate); const query = params.toString(); const url = query ? `/sms?${query}` : "/sms"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Resend a failed SMS message * * @param id - SMS message ID * @returns Updated SMS message */ async resend(id) { if (!id) { return { data: null, error: "SMS message ID is required" }; } return this.client.post(`/sms/${id}/resend`); } /** * Send a draft SMS message * * @param id - Draft SMS message ID * @param scheduledAt - Optional scheduled time * @returns SMS message details */ async sendDraft(id, scheduledAt) { if (!id) { return { data: null, error: "SMS message ID is required" }; } const body = scheduledAt ? { scheduledAt } : void 0; return this.client.post(`/sms/${id}/send-draft`, body); } /** * Batch resend failed messages * * @param messageIds - Array of message IDs to resend * @returns Batch resend results */ async resendBatch(messageIds) { if (!messageIds || messageIds.length === 0) { return { data: null, error: "At least one message ID is required" }; } return this.client.post("/sms/resend-failed", { messageIds }); } }; // src/resources/templates.ts var SMSTemplates = class extends BaseResource { /** * Create a new SMS template * * @param params - Template parameters * @returns Created template * * @example * ```typescript * const { data, error } = await jokoor.smsTemplates.create({ * name: 'Welcome Message', * body: 'Hello {{name}}, welcome to our service!', * description: 'Welcome message for new users' * }); * ``` */ async create(params) { if (!params.name) { return { data: null, error: "Template name is required" }; } if (!params.body) { return { data: null, error: "Template body is required" }; } return this.client.post("/sms/templates", params); } /** * Get template details * * @param id - Template ID * @returns Template details */ async get(id) { if (!id) { return { data: null, error: "Template ID is required" }; } return this.client.get(`/sms/templates/${id}`); } /** * List SMS templates * * @param options - List options * @returns Paginated list of templates */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); const query = params.toString(); const url = query ? `/sms/templates?${query}` : "/sms/templates"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a template * * @param id - Template ID * @param params - Update parameters * @returns Updated template */ async update(id, params) { if (!id) { return { data: null, error: "Template ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/sms/templates/${id}`, params); } /** * Delete a template * * @param id - Template ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Template ID is required" }; } return this.client.delete(`/sms/templates/${id}`); } }; // src/resources/contacts.ts var SMSContacts = class extends BaseResource { /** * Create a new contact * * @param params - Contact parameters * @returns Created contact * * @example * ```typescript * const { data, error } = await jokoor.smsContacts.create({ * phoneNumber: '+2207123456', * firstName: 'John', * lastName: 'Doe', * email: 'john@example.com' * }); * ``` */ async create(params) { if (!params.phoneNumber) { return { data: null, error: "Phone number is required" }; } return this.client.post("/sms/contacts", params); } /** * Get contact details * * @param id - Contact ID * @returns Contact details */ async get(id) { if (!id) { return { data: null, error: "Contact ID is required" }; } return this.client.get(`/sms/contacts/${id}`); } /** * List contacts * * @param options - List options * @returns Paginated list of contacts */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.groupId) params.set("group_id", options.groupId); const query = params.toString(); const url = query ? `/sms/contacts?${query}` : "/sms/contacts"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a contact * * @param id - Contact ID * @param params - Update parameters * @returns Updated contact */ async update(id, params) { if (!id) { return { data: null, error: "Contact ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/sms/contacts/${id}`, params); } /** * Delete a contact * * @param id - Contact ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Contact ID is required" }; } return this.client.delete(`/sms/contacts/${id}`); } }; // src/resources/contact-groups.ts var SMSContactGroups = class extends BaseResource { /** * Create a new contact group * * @param params - Group parameters * @returns Created group * * @example * ```typescript * const { data, error } = await jokoor.smsContactGroups.create({ * name: 'VIP Customers', * description: 'High-value customers' * }); * ``` */ async create(params) { if (!params.name) { return { data: null, error: "Group name is required" }; } return this.client.post("/sms/groups", params); } /** * Get group details * * @param id - Group ID * @returns Group details */ async get(id) { if (!id) { return { data: null, error: "Group ID is required" }; } return this.client.get(`/sms/groups/${id}`); } /** * List contact groups * * @param options - List options * @returns Paginated list of groups */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); const query = params.toString(); const url = query ? `/sms/groups?${query}` : "/sms/groups"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a group * * @param id - Group ID * @param params - Update parameters * @returns Updated group */ async update(id, params) { if (!id) { return { data: null, error: "Group ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/sms/groups/${id}`, params); } /** * Delete a group * * @param id - Group ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Group ID is required" }; } return this.client.delete(`/sms/groups/${id}`); } /** * Add contacts to a group * * @param groupId - Group ID * @param contactIds - Array of contact IDs to add * @returns Success result */ async addContacts(groupId, contactIds) { if (!groupId) { return { data: null, error: "Group ID is required" }; } if (!contactIds || contactIds.length === 0) { return { data: null, error: "At least one contact ID is required" }; } return this.client.post(`/sms/groups/${groupId}/contacts`, { contactIds }); } /** * Remove contacts from a group * * @param groupId - Group ID * @param contactIds - Array of contact IDs to remove * @returns Success result */ async removeContacts(groupId, contactIds) { if (!groupId) { return { data: null, error: "Group ID is required" }; } if (!contactIds || contactIds.length === 0) { return { data: null, error: "At least one contact ID is required" }; } return this.client.delete(`/sms/groups/${groupId}/contacts`, { data: { contactIds } }); } }; // src/resources/sender-ids.ts var SMSSenderIDs = class extends BaseResource { /** * Apply for a custom sender ID * * @param params - Sender ID parameters * @returns Created sender ID application * * @example * ```typescript * const { data, error } = await jokoor.smsSenderIds.create({ * senderId: 'MYCOMPANY', * purpose: 'Business notifications', * useCase: 'Sending transaction alerts to customers' * }); * ``` */ async create(params) { if (!params.senderId) { return { data: null, error: "Sender ID is required" }; } if (params.senderId.length < 3 || params.senderId.length > 11) { return { data: null, error: "Sender ID must be between 3 and 11 characters" }; } return this.client.post("/sms/senders", params); } /** * Get sender ID details * * @param id - Sender ID record ID * @returns Sender ID details */ async get(id) { if (!id) { return { data: null, error: "Sender ID is required" }; } return this.client.get(`/sms/senders/${id}`); } /** * List sender IDs * * @param options - List options * @returns Paginated list of sender IDs */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); const query = params.toString(); const url = query ? `/sms/senders?${query}` : "/sms/senders"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a sender ID application * * @param id - Sender ID record ID * @param params - Update parameters * @returns Updated sender ID */ async update(id, params) { if (!id) { return { data: null, error: "Sender ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/sms/senders/${id}`, params); } /** * Delete a sender ID * * @param id - Sender ID record ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Sender ID is required" }; } return this.client.delete(`/sms/senders/${id}`); } /** * Set a sender ID as default * * @param id - Sender ID record ID * @returns Success result */ async setDefault(id) { if (!id) { return { data: null, error: "Sender ID is required" }; } return this.client.post(`/sms/senders/${id}/set-default`); } }; // src/resources/campaigns.ts var SMSCampaigns = class extends BaseResource { /** * Create a new SMS campaign * * @param params - Campaign parameters * @returns Created campaign * * @example * ```typescript * const { data, error } = await jokoor.smsCampaigns.create({ * name: 'Flash Sale Alert', * messageBody: 'Flash sale! 50% off everything today only!', * groupIds: ['grp_123', 'grp_456'] * }); * ``` */ async create(params) { if (!params.name) { return { data: null, error: "Campaign name is required" }; } if (!params.messageBody && !params.templateId) { return { data: null, error: "Either messageBody or templateId must be provided" }; } return this.client.post("/sms/campaigns", params); } /** * Get campaign details * * @param id - Campaign ID * @returns Campaign details */ async get(id) { if (!id) { return { data: null, error: "Campaign ID is required" }; } return this.client.get(`/sms/campaigns/${id}`); } /** * List campaigns * * @param options - List options * @returns Paginated list of campaigns */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); const query = params.toString(); const url = query ? `/sms/campaigns?${query}` : "/sms/campaigns"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a campaign (only draft campaigns can be updated) * * @param id - Campaign ID * @param params - Update parameters * @returns Updated campaign */ async update(id, params) { if (!id) { return { data: null, error: "Campaign ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/sms/campaigns/${id}`, params); } /** * Delete a campaign (only draft campaigns can be deleted) * * @param id - Campaign ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Campaign ID is required" }; } return this.client.delete(`/sms/campaigns/${id}`); } /** * Send a campaign immediately or schedule it * * @param id - Campaign ID * @param scheduledAt - Optional scheduled time * @returns Updated campaign */ async send(id, scheduledAt) { if (!id) { return { data: null, error: "Campaign ID is required" }; } const body = scheduledAt ? { scheduledAt } : void 0; return this.client.post(`/sms/campaigns/${id}/send`, body); } /** * Send a draft campaign * * @param id - Campaign ID * @param scheduledAt - Optional scheduled time * @returns Updated campaign */ async sendDraft(id, scheduledAt) { if (!id) { return { data: null, error: "Campaign ID is required" }; } const body = scheduledAt ? { scheduledAt } : void 0; return this.client.post( `/sms/campaigns/${id}/send-draft`, body ); } /** * Send campaign asynchronously (for large campaigns) * * @param id - Campaign ID * @param scheduledAt - Optional scheduled time * @returns Accepted response */ async sendAsync(id, scheduledAt) { if (!id) { return { data: null, error: "Campaign ID is required" }; } const body = scheduledAt ? { scheduledAt } : void 0; return this.client.post(`/sms/campaigns/${id}/send-async`, body); } /** * Get campaign messages * * @param id - Campaign ID * @param options - List options * @returns Paginated list of campaign messages */ async getMessages(id, options) { if (!id) { return { data: null, error: "Campaign ID is required" }; } const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); const query = params.toString(); const url = query ? `/sms/campaigns/${id}/messages?${query}` : `/sms/campaigns/${id}/messages`; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Get campaign statistics * * @param id - Campaign ID * @returns Campaign statistics */ async getStatistics(id) { if (!id) { return { data: null, error: "Campaign ID is required" }; } return this.client.get(`/sms/campaigns/${id}/statistics`); } /** * Resend failed campaign messages * * @param id - Campaign ID * @returns Batch resend results */ async resendFailed(id) { if (!id) { return { data: null, error: "Campaign ID is required" }; } return this.client.post(`/sms/campaigns/${id}/resend-failed`); } }; // src/resources/payment-links.ts var PaymentLinks = class extends BaseResource { /** * Create a new payment link * * @param params - Payment link parameters * @returns Created payment link * * @example * ```typescript * const { data, error } = await jokoor.paymentLinks.create({ * title: 'Product Purchase', * description: 'Premium subscription', * amount: '50.00', * currency: 'GMD', * paymentMethods: ['wave', 'card'] * }); * ``` */ async create(params) { if (!params.title) { return { data: null, error: "Title is required" }; } if (!params.amount) { return { data: null, error: "Amount is required" }; } return this.client.post("/pay/payment-links", params); } /** * Get payment link details * * @param id - Payment link ID * @returns Payment link details */ async get(id) { if (!id) { return { data: null, error: "Payment link ID is required" }; } return this.client.get(`/pay/payment-links/${id}`); } /** * List payment links * * @param options - List options * @returns Paginated list of payment links */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); const query = params.toString(); const url = query ? `/pay/payment-links?${query}` : "/pay/payment-links"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a payment link * * @param id - Payment link ID * @param params - Update parameters * @returns Updated payment link */ async update(id, params) { if (!id) { return { data: null, error: "Payment link ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/pay/payment-links/${id}`, params); } /** * Delete a payment link * * @param id - Payment link ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Payment link ID is required" }; } return this.client.delete(`/pay/payment-links/${id}`); } }; // src/resources/invoices.ts var Invoices = class extends BaseResource { /** * Create a new invoice * * @param params - Invoice parameters * @returns Created invoice * * @example * ```typescript * const { data, error } = await jokoor.invoices.create({ * customerEmail: 'customer@example.com', * customerName: 'John Doe', * items: [ * { description: 'Consulting Services', quantity: 10, unitPrice: '50.00', amount: '500.00' }, * { description: 'Setup Fee', quantity: 1, unitPrice: '100.00', amount: '100.00' } * ], * currency: 'GMD', * dueDate: '2024-12-31' * }); * ``` */ async create(params) { if (!params.items || params.items.length === 0) { return { data: null, error: "At least one invoice item is required" }; } return this.client.post("/pay/invoices", params); } /** * Get invoice details * * @param id - Invoice ID * @returns Invoice details */ async get(id) { if (!id) { return { data: null, error: "Invoice ID is required" }; } return this.client.get(`/pay/invoices/${id}`); } /** * List invoices * * @param options - List options * @returns Paginated list of invoices */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); const query = params.toString(); const url = query ? `/pay/invoices?${query}` : "/pay/invoices"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update an invoice (only draft invoices can be updated) * * @param id - Invoice ID * @param params - Update parameters * @returns Updated invoice */ async update(id, params) { if (!id) { return { data: null, error: "Invoice ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/pay/invoices/${id}`, params); } /** * Finalize an invoice (makes it ready to send) * * @param id - Invoice ID * @returns Finalized invoice */ async finalize(id) { if (!id) { return { data: null, error: "Invoice ID is required" }; } return this.client.post(`/pay/invoices/${id}/finalize`); } /** * Send an invoice to the customer * * @param id - Invoice ID * @returns Success result */ async send(id) { if (!id) { return { data: null, error: "Invoice ID is required" }; } return this.client.post(`/pay/invoices/${id}/send`); } /** * Cancel an invoice * * @param id - Invoice ID * @returns Cancelled invoice */ async cancel(id) { if (!id) { return { data: null, error: "Invoice ID is required" }; } return this.client.post(`/pay/invoices/${id}/cancel`); } /** * Download invoice PDF * * @param id - Invoice ID * @returns PDF binary data */ async downloadPDF(id) { if (!id) { return { data: null, error: "Invoice ID is required" }; } return this.client.get(`/pay/invoices/${id}/pdf`); } /** * Record a payment against an invoice * * @param id - Invoice ID * @param params - Payment recording parameters * @returns Updated invoice with payment recorded * * @example * ```typescript * const { data, error } = await jokoor.invoices.recordPayment('inv_123', { * amount: '500.00', * paymentMethod: 'bank_transfer', * transactionId: 'TXN123456', * notes: 'Payment received via bank transfer' * }); * ``` */ async recordPayment(id, params) { if (!id) { return { data: null, error: "Invoice ID is required" }; } if (!params.amount) { return { data: null, error: "Payment amount is required" }; } if (!params.paymentMethod) { return { data: null, error: "Payment method is required" }; } return this.client.post(`/pay/invoices/${id}/payments`, params); } /** * List all payments recorded against an invoice * * @param id - Invoice ID * @returns List of invoice payments * * @example * ```typescript * const { data, error } = await jokoor.invoices.listPayments('inv_123'); * ``` */ async listPayments(id) { if (!id) { return { data: null, error: "Invoice ID is required" }; } const result = await this.client.get(`/pay/invoices/${id}/payments`); if (result.data && Array.isArray(result.data)) { return { data: result.data, error: null }; } return result; } /** * Get all payment receipts associated with an invoice * * @param id - Invoice ID * @returns List of receipts for the invoice * * @example * ```typescript * const { data, error } = await jokoor.invoices.getReceipts('inv_123'); * ``` */ async getReceipts(id) { if (!id) { return { data: null, error: "Invoice ID is required" }; } const result = await this.client.get(`/pay/invoices/${id}/receipts`); if (result.data && Array.isArray(result.data)) { return { data: result.data, error: null }; } return result; } }; // src/resources/checkouts.ts var Checkouts = class extends BaseResource { /** * Create a new checkout session * * @param params - Checkout parameters * @returns Created checkout session * * @example * ```typescript * // Basic checkout (customer selects payment method) * const { data, error } = await jokoor.checkouts.create({ * amount: '100.00', * currency: 'GMD', * metadata: { orderId: '12345' } * }); * * // Checkout with pre-selected payment method (one-step flow) * const { data, error } = await jokoor.checkouts.create({ * amount: '100.00', * payment_method: 'wave', * customer_phone: '+2207654321' * }); * // data.payment_url will be ready for payment immediately * ``` */ async create(params) { if (!params.amount) { return { data: null, error: "Amount is required" }; } return this.client.post("/checkouts", params); } /** * Get checkout session details * * @param id - Checkout session ID * @returns Checkout details */ async get(id) { if (!id) { return { data: null, error: "Checkout ID is required" }; } return this.client.get(`/checkouts/${id}`); } /** * Cancel a checkout session * * @param id - Checkout session ID * @returns Success result */ async cancel(id) { if (!id) { return { data: null, error: "Checkout ID is required" }; } return this.client.post(`/checkouts/${id}/cancel`); } }; // src/resources/products.ts var Products = class extends BaseResource { /** * Create a new product * * @param params - Product parameters * @returns Created product * * @example * ```typescript * const { data, error } = await jokoor.products.create({ * name: 'Premium Subscription', * description: 'Monthly premium features', * price: '29.99', * currency: 'GMD', * active: true * }); * ``` */ async create(params) { if (!params.name) { return { data: null, error: "Product name is required" }; } if (!params.price) { return { data: null, error: "Price is required" }; } return this.client.post("/pay/products", params); } /** * Get product details * * @param id - Product ID * @returns Product details */ async get(id) { if (!id) { return { data: null, error: "Product ID is required" }; } return this.client.get(`/pay/products/${id}`); } /** * List products * * @param options - List options * @returns Paginated list of products */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.active !== void 0) params.set("active", String(options.active)); const query = params.toString(); const url = query ? `/pay/products?${query}` : "/pay/products"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a product * * @param id - Product ID * @param params - Update parameters * @returns Updated product */ async update(id, params) { if (!id) { return { data: null, error: "Product ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/pay/products/${id}`, params); } /** * Delete a product * * @param id - Product ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Product ID is required" }; } return this.client.delete(`/pay/products/${id}`); } }; // src/resources/customers.ts var Customers = class extends BaseResource { /** * Create or retrieve a customer * * @param params - Customer parameters * @returns Customer details * * @example * ```typescript * const { data, error } = await jokoor.customers.create({ * email: 'customer@example.com', * phone: '+2207123456', * name: 'John Doe' * }); * ``` */ async create(params) { if (!params.email && !params.phone) { return { data: null, error: "Either email or phone must be provided" }; } return this.client.post("/pay/customers", params); } /** * Get customer details * * @param id - Customer ID * @returns Customer details */ async get(id) { if (!id) { return { data: null, error: "Customer ID is required" }; } return this.client.get(`/pay/customers/${id}`); } /** * List customers * * @param options - List options * @returns Paginated list of customers */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); const query = params.toString(); const url = query ? `/pay/customers?${query}` : "/pay/customers"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a customer * * @param id - Customer ID * @param params - Update parameters * @returns Updated customer */ async update(id, params) { if (!id) { return { data: null, error: "Customer ID is required" }; } if (Object.keys(params).length === 0) { return { data: null, error: "At least one field must be provided for update" }; } return this.client.put(`/pay/customers/${id}`, params); } /** * Delete a customer * * @param id - Customer ID * @returns Success result */ async delete(id) { if (!id) { return { data: null, error: "Customer ID is required" }; } return this.client.delete(`/pay/customers/${id}`); } }; // src/resources/transactions.ts var Transactions = class extends BaseResource { /** * Get transaction details * * @param id - Transaction ID * @returns Transaction details */ async get(id) { if (!id) { return { data: null, error: "Transaction ID is required" }; } return this.client.get(`/pay/transactions/${id}`); } /** * List transactions * * @param options - List options * @returns Paginated list of transactions */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); if (options?.startDate) params.set("start_date", options.startDate); if (options?.endDate) params.set("end_date", options.endDate); const query = params.toString(); const url = query ? `/pay/transactions?${query}` : "/pay/transactions"; const result = await this.client.get(url); return this.extractPaginatedData(result); } }; // src/resources/refunds.ts var Refunds = class extends BaseResource { /** * Create a refund for a transaction * * @param transactionId - Transaction ID to refund * @param params - Refund parameters * @returns Created refund * * @example * ```typescript * const { data, error } = await jokoor.refunds.create('txn_123', { * amount: '50.00', // Optional, defaults to full refund * reason: 'Customer request' * }); * ``` */ async create(transactionId, params) { if (!transactionId) { return { data: null, error: "Transaction ID is required" }; } return this.client.post(`/pay/transactions/${transactionId}/refund`, params); } /** * Get refund details * * @param id - Refund ID * @returns Refund details */ async get(id) { if (!id) { return { data: null, error: "Refund ID is required" }; } return this.client.get(`/pay/refunds/${id}`); } /** * List refunds * * @param options - List options * @returns Paginated list of refunds */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); const query = params.toString(); const url = query ? `/pay/refunds?${query}` : "/pay/refunds"; const result = await this.client.get(url); return this.extractPaginatedData(result); } }; // src/resources/subscriptions.ts var Subscriptions = class extends BaseResource { /** * Create a new subscription * * @param params - Subscription parameters * @returns Created subscription * * @example * ```typescript * const { data, error } = await jokoor.subscriptions.create({ * customerId: 'cus_123', * currency: 'GMD', * interval: 'month', * intervalCount: 1, * startDate: '2024-12-01', * items: [{ * description: 'Premium Subscription', * quantity: 1, * unitPrice: '29.99' * }] * }); * ``` */ async create(params) { if (!params.customerId && !params.customerEmail) { return { data: null, error: "Either customerId or customerEmail is required" }; } if (!params.currency) { return { data: null, error: "Currency is required" }; } if (!params.interval) { return { data: null, error: "Interval is required" }; } if (!params.intervalCount || params.intervalCount < 1) { return { data: null, error: "Interval count is required and must be at least 1" }; } if (!params.startDate) { return { data: null, error: "Start date is required" }; } if (!params.items || params.items.length === 0) { return { data: null, error: "At least one item is required" }; } return this.client.post("/pay/subscriptions", params); } /** * Get subscription details * * @param id - Subscription ID * @returns Subscription details */ async get(id) { if (!id) { return { data: null, error: "Subscription ID is required" }; } return this.client.get(`/pay/subscriptions/${id}`); } /** * List subscriptions * * @param options - List options * @returns Paginated list of subscriptions */ async list(options) { const params = new URLSearchParams(); if (options?.offset !== void 0) params.set("offset", String(options.offset)); if (options?.limit !== void 0) params.set("limit", String(options.limit)); if (options?.status) params.set("status", options.status); const query = params.toString(); const url = query ? `/pay/subscriptions?${query}` : "/pay/subscriptions"; const result = await this.client.get(url); return this.extractPaginatedData(result); } /** * Update a subscription * * @param id - Subscription ID * @param params - Update parameters * @returns Updated subscription */ async update(id, params)