@paykit-sdk/core
Version:
The Payment Toolkit for Typescript
611 lines (590 loc) • 18.6 kB
JavaScript
;
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, all) => {
for (var name in all)
__defProp(target, name, { get: all[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, {
AbortedError: () => AbortedError,
ConnectionError: () => ConnectionError,
ERR: () => ERR,
HTTPClient: () => HTTPClient,
HTTPError: () => HTTPError,
Logger: () => Logger,
OK: () => OK,
PayKit: () => PayKit,
TimeoutError: () => TimeoutError,
UnauthorizedError: () => UnauthorizedError,
UnknownError: () => UnknownError,
ValidationError: () => ValidationError,
Webhook: () => Webhook,
__IS_CLIENT__: () => __IS_CLIENT__,
billingModeSchema: () => billingModeSchema,
createCheckoutSchema: () => createCheckoutSchema,
createCustomerSchema: () => createCustomerSchema,
delay: () => delay,
headersExtractor: () => headersExtractor,
isAbortError: () => isAbortError,
isConnectionError: () => isConnectionError,
isTimeoutError: () => isTimeoutError,
isUnauthorizedError: () => isUnauthorizedError,
logger: () => logger,
metadataSchema: () => metadataSchema,
retrieveCheckoutSchema: () => retrieveCheckoutSchema,
retrieveCustomerSchema: () => retrieveCustomerSchema,
retrieveSubscriptionSchema: () => retrieveSubscriptionSchema,
safeDecode: () => safeDecode,
safeEncode: () => safeEncode,
safeParse: () => safeParse,
stringifyObjectValues: () => stringifyObjectValues,
toPaykitEvent: () => toPaykitEvent,
truncate: () => truncate,
tryCatchAsync: () => tryCatchAsync,
tryCatchSync: () => tryCatchSync,
unwrapAsync: () => unwrapAsync,
updateCustomerSchema: () => updateCustomerSchema,
updateSubscriptionSchema: () => updateSubscriptionSchema,
validateEnvVars: () => validateEnvVars
});
module.exports = __toCommonJS(index_exports);
// src/webhook-provider.ts
var Webhook = class {
handlers = /* @__PURE__ */ new Map();
config = null;
setup(config) {
this.config = config;
return this;
}
on(eventType, handler) {
if (!this.config) throw new Error("Webhook not configured. Call setup() first.");
if (!this.handlers.has(eventType)) this.handlers.set(eventType, []);
this.handlers.get(eventType)?.push(handler);
return this;
}
async handle(dto) {
if (!this.config) throw new Error("Webhook not configured. Call setup() first.");
const { webhookSecret, provider } = this.config;
const event = await provider.handleWebhook({ ...dto, webhookSecret });
const handlers = this.handlers.get(event.type);
if (handlers && handlers.length > 0) {
await Promise.all(handlers.map((handler) => handler(event)));
}
}
};
// src/resources/checkout.ts
var import_zod2 = require("zod");
// src/resources/metadata.ts
var import_zod = require("zod");
var metadataSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.string());
// src/resources/checkout.ts
var billingModeSchema = import_zod2.z.enum(["one_time", "recurring"]);
var createCheckoutSchema = import_zod2.z.object({
/**
* The ID of the customer.
*/
customer_id: import_zod2.z.string(),
/**
* The metadata of the checkout.
*/
metadata: metadataSchema,
/**
* The mode of the checkout.
*/
session_type: billingModeSchema,
/**
* The item ID of the checkout.
*/
item_id: import_zod2.z.string(),
/**
* Extra information to be sent to the provider e.g tax, trial days, etc.
*/
provider_metadata: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional()
});
var retrieveCheckoutSchema = import_zod2.z.object({
id: import_zod2.z.string()
});
// src/resources/customer.ts
var import_zod3 = require("zod");
var createCustomerSchema = import_zod3.z.object({
/**
* The email of the customer.
*/
email: import_zod3.z.string().email(),
/**
* The name of the customer.
*/
name: import_zod3.z.string().optional(),
/**
* The metadata of the customer.
*/
metadata: metadataSchema.optional()
});
var updateCustomerSchema = import_zod3.z.object({
/**
* The email of the customer.
*/
email: import_zod3.z.string().email().optional(),
/**
* The name of the customer.
*/
name: import_zod3.z.string().optional(),
/**
* The metadata of the customer.
*/
metadata: metadataSchema.optional()
});
var retrieveCustomerSchema = import_zod3.z.object({
id: import_zod3.z.string()
});
// src/resources/subscription.ts
var import_zod4 = require("zod");
var updateSubscriptionSchema = import_zod4.z.object({
metadata: metadataSchema.optional()
});
var retrieveSubscriptionSchema = import_zod4.z.object({
id: import_zod4.z.string()
});
// src/resources/webhook.ts
var toPaykitEvent = (event) => event;
// src/tools/error.ts
var HTTPError = class extends Error {
cause;
name = "HTTPError";
constructor(message, opts) {
let msg = message;
if (opts?.cause) {
msg += `: ${opts.cause}`;
}
super(msg, opts);
if (typeof this.cause === "undefined") {
this.cause = opts?.cause;
}
}
};
var UnauthorizedError = class extends HTTPError {
name = "PaykitUnauthorizedError";
};
var ConnectionError = class extends HTTPError {
name = "PaykitConnectionError";
};
var AbortedError = class extends HTTPError {
name = "PaykitAbortedError";
};
var TimeoutError = class extends HTTPError {
name = "PaykitTimeoutError";
};
var ValidationError = class extends HTTPError {
name = "PaykitValidationError";
};
var UnknownError = class extends HTTPError {
name = "PaykitUnknownError";
};
// src/tools/try-catch.ts
async function tryCatchAsync(promise) {
try {
const data = await promise;
return [data, void 0];
} catch (error) {
return [void 0, error];
}
}
function tryCatchSync(fn) {
try {
const data = fn();
return [data, void 0];
} catch (error) {
return [void 0, error];
}
}
// src/tools/fp.ts
var OK = (value) => ({ ok: true, value });
var ERR = (error) => ({ ok: false, error });
var unwrapAsync = async (pr) => {
const r = await pr;
if (!r.ok) throw r.error;
return r.value;
};
function safeParse(rawValue, fn, errorMessage) {
const [result, error] = tryCatchSync(() => fn(rawValue));
if (error) return ERR(new ValidationError(errorMessage, { cause: error }));
return OK(result);
}
var safeEncode = (value) => {
return safeParse(value, (value2) => Buffer.from(JSON.stringify(value2)).toString("base64"), "Failed to encode value");
};
var safeDecode = (value) => {
return safeParse(value, (value2) => JSON.parse(Buffer.from(value2, "base64").toString("utf-8")), "Failed to decode value");
};
// src/tools/http.ts
function isConnectionError(err) {
if (typeof err !== "object" || err == null) {
return false;
}
const isBrowserErr = err instanceof TypeError && err.message.toLowerCase().startsWith("failed to fetch");
const isNodeErr = err instanceof TypeError && err.message.toLowerCase().startsWith("fetch failed");
const isBunErr = "name" in err && err.name === "ConnectionError";
const isGenericErr = "code" in err && typeof err.code === "string" && err.code.toLowerCase() === "econnreset";
return isBrowserErr || isNodeErr || isGenericErr || isBunErr;
}
function isTimeoutError(err) {
if (typeof err !== "object" || err == null) {
return false;
}
const isNative = "name" in err && err.name === "TimeoutError";
const isLegacyNative = "code" in err && err.code === 23;
const isGenericErr = "code" in err && typeof err.code === "string" && err.code.toLowerCase() === "econnaborted";
return isNative || isLegacyNative || isGenericErr;
}
function isAbortError(err) {
if (typeof err !== "object" || err == null) {
return false;
}
const isNative = "name" in err && err.name === "AbortError";
const isLegacyNative = "code" in err && err.code === 20;
const isGenericErr = "code" in err && typeof err.code === "string" && err.code.toLowerCase() === "econnaborted";
return isNative || isLegacyNative || isGenericErr;
}
function isUnauthorizedError(err) {
if (typeof err !== "object" || err == null) {
return false;
}
return err instanceof Error && ["unauthorized", "401"].includes(err.message.toLowerCase());
}
// src/tools/webhook.ts
var headersExtractor = (headers, requiredHeaders) => {
const extractedHeaders = [];
for (const key of requiredHeaders) {
const value = headers[key] || headers[key.toLowerCase()];
if (value) {
extractedHeaders.push({ key, value: Array.isArray(value) ? value : [value] });
}
}
return extractedHeaders;
};
// src/tools/is-client.ts
var __IS_CLIENT__ = typeof window !== "undefined";
// src/tools/delay.ts
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// src/tools/string.ts
var truncate = (str, num, suffix = "...") => {
if (!str) return "";
if (str.length < num) return str;
return str.slice(0, num) + suffix;
};
var stringifyObjectValues = (obj) => {
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, JSON.stringify(value)]));
};
// src/tools/validate-env.ts
var validateEnvVars = (requiredKeys, source) => {
const missingKeys = [];
const result = {};
for (const key of requiredKeys) {
const value = source[key];
if (!value) {
missingKeys.push(key);
} else {
result[key] = value;
}
}
if (missingKeys.length > 0) {
const missingKeysList = missingKeys.join(", ");
throw new Error(`Missing required environment variables: ${missingKeysList}`);
}
return result;
};
// src/logger.ts
var import_chalk = __toESM(require("chalk"));
var Logger = class {
silent;
verbose;
spinnerInterval = null;
spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
currentSpinnerFrame = 0;
constructor(options = {}) {
this.silent = options.silent || false;
this.verbose = options.verbose || false;
}
/**
* Success messages (dark green)
*/
success(message) {
if (this.silent) return;
console.log(import_chalk.default.hex("#166534")(`\u2714 ${message}`));
}
/**
* Info messages (dark green)
*/
info(message) {
if (this.silent) return;
console.log(import_chalk.default.hex("#15803d")(`\u2139 ${message}`));
}
/**
* Warning messages (amber)
*/
warn(message) {
if (this.silent) return;
console.log(import_chalk.default.hex("#d97706")(`\u26A0 ${message}`));
}
/**
* Error messages (red)
*/
error(message) {
if (this.silent) return;
console.error(import_chalk.default.hex("#dc2626")(`\u2716 ${message}`));
}
/**
* Debug messages (gray, only in verbose mode)
*/
debug(message) {
if (this.silent || !this.verbose) return;
console.log(import_chalk.default.gray(`\u{1F50D} ${message}`));
}
/**
* Tip messages (dark green)
*/
tip(message) {
if (this.silent) return;
console.log(import_chalk.default.hex("#16a34a")(`\u{1F4A1} ${message}`));
}
/**
* Code block styling
*/
code(code) {
if (this.silent) return;
console.log(import_chalk.default.bgGray.white(` ${code} `));
}
/**
* Section headers
*/
section(title) {
if (this.silent) return;
console.log(import_chalk.default.hex("#166534").bold.underline(`
${title}`));
}
/**
* Progress indicator with spinning animation
*/
progress(message) {
if (this.silent) return;
this.stopSpinner();
this.startSpinner(message);
}
/**
* Start the spinner animation
*/
startSpinner(message) {
const updateSpinner = () => {
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
const spinner = this.spinnerFrames[this.currentSpinnerFrame];
process.stdout.write(import_chalk.default.hex("#15803d")(`${spinner} ${message}... `));
this.currentSpinnerFrame = (this.currentSpinnerFrame + 1) % this.spinnerFrames.length;
};
updateSpinner();
this.spinnerInterval = setInterval(updateSpinner, 80);
}
/**
* Stop the spinner animation
*/
stopSpinner() {
if (this.spinnerInterval) {
clearInterval(this.spinnerInterval);
this.spinnerInterval = null;
}
}
/**
* Clear progress line
*/
clearProgress() {
if (this.silent) return;
this.stopSpinner();
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
}
/**
* Table-like output for key-value pairs
*/
table(data) {
if (this.silent) return;
const maxKeyLength = Math.max(...Object.keys(data).map((k) => k.length));
Object.entries(data).forEach(([key, value]) => {
const paddedKey = key.padEnd(maxKeyLength);
console.log(import_chalk.default.gray(`${paddedKey}: `) + import_chalk.default.white(value));
});
}
/**
* List items
*/
list(items, bullet = "\u2022") {
if (this.silent) return;
items.forEach((item) => {
console.log(import_chalk.default.hex("#16a34a")(`${bullet} `) + import_chalk.default.white(item));
});
}
/**
* Divider line
*/
divider(char = "\u2500", length = 50) {
if (this.silent) return;
console.log(import_chalk.default.hex("#16a34a")(char.repeat(length)));
}
/**
* Spacer
*/
spacer(lines = 1) {
if (this.silent) return;
for (let i = 0; i < lines; i++) {
console.log("");
}
}
/**
* Brand header
*/
brand() {
if (this.silent) return;
console.log(import_chalk.default.hex("#166534").bold("PayKit CLI"));
this.divider();
}
};
var logger = new Logger();
// src/http.ts
var HTTPClient = class {
constructor(config) {
this.config = config;
}
errorHandler = (err) => {
switch (true) {
case isUnauthorizedError(err):
return ERR(new UnauthorizedError("Unauthorized", { cause: err }));
case isConnectionError(err):
return ERR(new ConnectionError("Connection error", { cause: err }));
case isTimeoutError(err):
return ERR(new TimeoutError("Timeout error", { cause: err }));
case isAbortError(err):
return ERR(new AbortedError("Aborted error", { cause: err }));
default:
return ERR(new UnknownError("Unknown error", { cause: err }));
}
};
getFullUrl(endpoint) {
const cleanEndpoint = endpoint.startsWith("/") ? endpoint.slice(1) : endpoint;
return `${this.config.baseUrl}/${cleanEndpoint}`;
}
getRequestOptions(options) {
return { headers: { "Content-Type": "application/json", ...this.config.headers, ...options?.headers }, ...options };
}
async get(endpoint, options) {
const url = this.getFullUrl(endpoint);
const requestOptions = this.getRequestOptions(options);
return await fetch(url, { method: "GET", ...requestOptions }).then((res) => OK(res.json())).catch((err) => this.errorHandler(err));
}
async post(endpoint, options) {
const url = this.getFullUrl(endpoint);
const requestOptions = this.getRequestOptions(options);
return await fetch(url, { method: "POST", ...requestOptions }).then((res) => OK(res.json())).catch((err) => this.errorHandler(err));
}
async delete(endpoint, options) {
const url = this.getFullUrl(endpoint);
const requestOptions = this.getRequestOptions(options);
return await fetch(url, { method: "DELETE", ...requestOptions }).then((res) => OK(res.json())).catch((err) => this.errorHandler(err));
}
async put(endpoint, options) {
const url = this.getFullUrl(endpoint);
const requestOptions = this.getRequestOptions(options);
return await fetch(url, { method: "PUT", ...requestOptions }).then((res) => OK(res.json())).catch((err) => this.errorHandler(err));
}
async patch(endpoint, options) {
const url = this.getFullUrl(endpoint);
const requestOptions = this.getRequestOptions(options);
return await fetch(url, { method: "PATCH", ...requestOptions }).then((res) => OK(res.json())).catch((err) => this.errorHandler(err));
}
};
// src/index.ts
var PayKit = class {
constructor(provider) {
this.provider = provider;
}
checkouts = {
create: (params) => this.provider.createCheckout(params),
retrieve: (id) => this.provider.retrieveCheckout(id)
};
customers = {
create: (params) => this.provider.createCustomer(params),
update: (id, params) => this.provider.updateCustomer(id, params),
retrieve: (id) => this.provider.retrieveCustomer(id)
};
subscriptions = {
update: (id, params) => this.provider.updateSubscription(id, params),
cancel: (id) => this.provider.cancelSubscription(id)
};
webhooks = {
setup: (config) => new Webhook().setup({ ...config, provider: this.provider })
};
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AbortedError,
ConnectionError,
ERR,
HTTPClient,
HTTPError,
Logger,
OK,
PayKit,
TimeoutError,
UnauthorizedError,
UnknownError,
ValidationError,
Webhook,
__IS_CLIENT__,
billingModeSchema,
createCheckoutSchema,
createCustomerSchema,
delay,
headersExtractor,
isAbortError,
isConnectionError,
isTimeoutError,
isUnauthorizedError,
logger,
metadataSchema,
retrieveCheckoutSchema,
retrieveCustomerSchema,
retrieveSubscriptionSchema,
safeDecode,
safeEncode,
safeParse,
stringifyObjectValues,
toPaykitEvent,
truncate,
tryCatchAsync,
tryCatchSync,
unwrapAsync,
updateCustomerSchema,
updateSubscriptionSchema,
validateEnvVars
});