@paykit-sdk/core
Version:
The Payment Toolkit for Typescript
1,224 lines (1,207 loc) • 37 kB
JavaScript
'use strict';
var zod = require('zod');
var promises = require('timers/promises');
// src/index.ts
// src/error.ts
var PayKitError = class extends Error {
code;
statusCode;
provider;
method;
context;
constructor(message, options) {
super(message);
this.name = this.constructor.name;
this.code = options?.code || "PAYKIT_ERROR";
this.statusCode = options?.statusCode || 500;
this.provider = options?.provider;
this.method = options?.method;
this.context = options?.context;
if (options?.cause) {
this.cause = options.cause;
}
Error.captureStackTrace(this, this.constructor);
}
};
var NotImplementedError = class extends PayKitError {
constructor(method, provider, options) {
const message = options?.futureSupport ? `${method} is not yet implemented${provider ? ` for ${provider}` : ""}. This feature is planned for a future release. If you need this urgently, please open an issue at https://github.com/usepaykit/paykit-sdk/issues` : `${method} is not implemented${provider ? ` for ${provider}` : ""}. If you believe this should be supported, please contact the maintainer at https://github.com/usepaykit/paykit-sdk/issues`;
super(message, {
code: "NOT_IMPLEMENTED",
statusCode: 501,
provider,
method
});
this.stack = void 0;
}
};
var ProviderNotSupportedError = class extends PayKitError {
constructor(method, provider, options) {
let message = `${provider} does not support ${method}.`;
if (options?.reason) {
message += ` ${options.reason}`;
}
if (options?.alternative) {
message += ` Alternative: ${options.alternative}`;
}
super(message, {
code: "PROVIDER_NOT_SUPPORTED",
statusCode: 501,
provider,
method,
context: {
reason: options?.reason,
alternative: options?.alternative
}
});
}
};
var ValidationError = class _ValidationError extends PayKitError {
constructor(message, options) {
super(message, {
code: "VALIDATION_ERROR",
statusCode: 400,
provider: options?.provider,
method: options?.method,
context: { field: options?.field, value: options?.value },
cause: options?.cause
});
}
/**
* Helper to create ValidationError from Zod error
*/
static fromZodError(zodError, provider, method) {
const message = zodError.message.split("\n").join(" ");
return new _ValidationError(message, {
provider,
method,
cause: zodError
});
}
};
var ResourceNotFoundError = class extends PayKitError {
constructor(resourceType, resourceId, provider) {
super(`${resourceType} with ID "${resourceId}" not found`, {
code: "RESOURCE_NOT_FOUND",
statusCode: 404,
provider,
context: { resourceType, resourceId }
});
}
};
var WebhookError = class extends PayKitError {
constructor(message, options) {
super(message, {
code: "WEBHOOK_ERROR",
statusCode: 400,
provider: options?.provider,
context: { provider: options?.provider }
});
this.stack = void 0;
}
};
var ConfigurationError = class extends PayKitError {
constructor(message, options) {
super(message, {
code: "CONFIGURATION_ERROR",
statusCode: 500,
provider: options?.provider,
context: { missingKeys: options?.missingKeys }
});
this.stack = void 0;
}
};
var OperationFailedError = class extends PayKitError {
constructor(operation, provider, options) {
const message = `Failed to ${operation}${provider ? ` with ${provider}` : ""}${options?.reason ? `: ${options.reason}` : ""}`;
super(message, {
code: "OPERATION_FAILED",
statusCode: 500,
provider,
method: operation,
cause: options?.cause
});
this.stack = void 0;
}
};
var AuthenticationError = class extends PayKitError {
constructor(provider, message) {
super(
message || `Authentication failed for ${provider}. Please check your API credentials.`,
{
code: "AUTHENTICATION_ERROR",
statusCode: 401,
provider
}
);
}
};
var RateLimitError = class extends PayKitError {
constructor(provider, options) {
super(
`Rate limit exceeded for ${provider}${options?.retryAfter ? `. Retry after ${options.retryAfter} seconds` : ""}`,
{
code: "RATE_LIMIT_ERROR",
statusCode: 429,
provider,
context: {
retryAfter: options?.retryAfter,
limit: options?.limit
}
}
);
}
};
var InvalidTypeError = class extends PayKitError {
constructor(field, expectedType, receivedType, options) {
super(
`Invalid type for "${field}": expected ${expectedType}, received ${receivedType}`,
{
code: "INVALID_TYPE",
statusCode: 400,
provider: options?.provider,
method: options?.method,
context: { field, expectedType, receivedType }
}
);
this.stack = void 0;
}
};
var ConstraintViolationError = class extends PayKitError {
constructor(constraint, options) {
super(
`Constraint violation: ${constraint}${options?.limit ? ` (limit: ${options.limit}, received: ${options.value})` : ""}`,
{
code: "CONSTRAINT_VIOLATION",
statusCode: 400,
provider: options?.provider,
context: {
constraint,
value: options?.value,
limit: options?.limit
}
}
);
}
};
var UnTraceableError = class extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
this.stack = void 0;
}
};
// src/paykit-provider.ts
var AbstractPayKitProvider = class {
providerVersion = process.env.PROVIDER_VERSION;
constructor(schema2, options, providerName) {
const { error } = schema2.safeParse(options);
if (error) {
throw new ConfigurationError(
`Invalid ${providerName} configuration`,
{
provider: providerName,
missingKeys: Object.keys(error.flatten().fieldErrors ?? {})
}
);
}
}
};
var PAYKIT_PROVIDER_METHODS = [
"createCheckout",
"retrieveCheckout",
"updateCheckout",
"deleteCheckout",
"createCustomer",
"updateCustomer",
"retrieveCustomer",
"deleteCustomer",
"createSubscription",
"updateSubscription",
"cancelSubscription",
"deleteSubscription",
"retrieveSubscription",
"createPayment",
"updatePayment",
"retrievePayment",
"deletePayment",
"capturePayment",
"cancelPayment",
"createRefund",
"handleWebhook"
];
var providerSchema = zod.z.custom(
(val) => {
if (!val || typeof val !== "object") return false;
const provider = val;
if (typeof provider.providerName !== "string") return false;
return PAYKIT_PROVIDER_METHODS.every(
(method) => typeof provider[method] === "function"
);
},
{
message: "Invalid PayKit provider: Missing implementation for required methods."
}
);
var payKitAdapterMetadataSchema = zod.z.object({
/**
* The name of the adapter
*/
name: zod.z.string(),
/**
* The version of the adapter
*/
version: zod.z.string()
});
var PAYKIT_METADATA_KEY = "__paykit";
var metadataSchema = zod.z.record(zod.z.string(), zod.z.string());
// 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/utils.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(buildError(errorMessage, 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"
);
};
async function executeWithRetryWithHandler(apiCall, errorHandler, maxRetries = 3, baseDelay = 1e3, currentAttempt = 1) {
try {
return await apiCall();
} catch (error) {
const handledError = errorHandler(error, currentAttempt);
if (!handledError.retry) {
if (handledError.data == null) throw error;
return handledError.data;
}
if (handledError.retry && currentAttempt <= maxRetries) {
const delay = baseDelay * Math.pow(2, currentAttempt - 1) * (0.5 + Math.random() * 0.5);
await promises.setTimeout(delay);
return executeWithRetryWithHandler(
apiCall,
errorHandler,
maxRetries,
baseDelay,
currentAttempt + 1
);
}
if (handledError.data == null) throw error;
return handledError.data;
}
}
function buildError(message, cause) {
const error = new Error(message);
if (cause) error.cause = cause;
return error;
}
var validateRequiredKeys = (requiredKeys, source, errorMessage, errorInstance) => {
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(", ");
const error = typeof errorMessage === "function" ? errorMessage(missingKeys) : errorMessage.replace("{keys}", missingKeysList);
throw errorInstance?.(error) ?? new UnTraceableError(error);
}
return result;
};
var parseJSON = (str, schema2) => {
try {
const parsed = JSON.parse(str);
return schema2.parse(parsed);
} catch (error) {
return null;
}
};
var schema = () => {
return (schema2) => schema2;
};
var omitInternalMetadata = (metadata, internalKeys = [PAYKIT_METADATA_KEY]) => {
return Object.entries(metadata).reduce((acc, [key, value]) => {
if (!internalKeys.includes(key)) {
acc[key] = String(value);
}
return acc;
}, {});
};
var stringifyMetadataValues = (metadata) => {
return Object.fromEntries(
Object.entries(metadata).map(([key, value]) => [
key,
typeof value === "string" ? value : JSON.stringify(value)
])
);
};
var getURLFromHeaders = (headers) => {
if (headers["origin"]) return headers["origin"];
if (headers["x-forwarded-host"]) {
const protocol = headers["x-forwarded-proto"] ?? "https";
const host = headers["x-forwarded-host"];
const path = headers["x-forwarded-path"] ?? "";
return `${protocol}://${host}${path}`;
}
if (headers["host"]) {
const protocol = headers["x-forwarded-proto"] ?? "https";
const host = headers["host"];
const path = headers["x-original-url"] ?? headers["x-forwarded-path"] ?? "";
return `${protocol}://${host}${path}`;
}
return "";
};
var refundReasonMatcher = (matcher) => {
if (/duplicate|duplicated|double.*charge|charged.*twice/i.test(
matcher.toLowerCase().trim()
)) {
return "duplicate";
}
if (/fraud|fraudulent|unauthorized|scam|stolen.*card|not.*authorized/i.test(
matcher.toLowerCase().trim()
)) {
return "fraudulent";
}
if (/customer.*request|requested.*customer|customer.*want|cancel|refund.*request|changed.*mind/i.test(
matcher.toLowerCase().trim()
)) {
return "requested_by_customer";
}
return "other";
};
// src/telemetry.ts
var Telemetry = class {
static log(event, sdkVersion, isLiveMode) {
tryCatchAsync(
fetch("https://telemetry.usepaykit.dev/v1/track", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
...event,
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
sdk_version: sdkVersion,
is_live_mode: isLiveMode
})
})
).catch(() => {
});
}
};
// 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 WebhookError(
"Webhook not configured. Call setup() first."
);
}
const typeStr = eventType;
if (!this.handlers.has(typeStr)) {
this.handlers.set(typeStr, []);
}
this.handlers.get(typeStr)?.push(handler);
return this;
}
async handle(dto) {
if (!this.config) {
throw new WebhookError(
"Webhook not configured. Call setup() first."
);
}
const { webhookSecret, provider } = this.config;
const events = await provider.handleWebhook(dto, webhookSecret);
const executionPromises = [];
for (const event of events) {
const matchedHandlers = this.handlers.get(event.type);
if (matchedHandlers) {
for (const handler of matchedHandlers) {
const payload = event.is_raw ? event.data : event;
executionPromises.push(handler(payload));
}
}
}
await Promise.all(executionPromises);
}
};
// src/tools/classify-error.ts
var STATUS_MAP = {
401: "unauthorized",
403: "forbidden",
404: "not_found",
429: "rate_limit",
500: "internal_server_error",
502: "bad_gateway",
503: "service_unavailable",
504: "gateway_timeout"
};
var CONNECTION_CODES = /ECONNREFUSED|ECONNRESET|ENOTFOUND|FETCH FAILED/;
var TIMEOUT_CODES = /ETIMEDOUT|ECONNABORTED|TIMEOUT/;
function classifyError(err, status) {
if (status && STATUS_MAP[status]) return STATUS_MAP[status];
if (err instanceof Error) {
const statusPrefix = /^(\d{3}):/.exec(err.message);
if (statusPrefix) {
const mapped = STATUS_MAP[Number(statusPrefix[1])];
if (mapped) return mapped;
}
const causeCode = String(
err.cause?.code ?? ""
);
const haystack = `${err.message} ${causeCode}`.toUpperCase();
if (CONNECTION_CODES.test(haystack)) return "connection";
if (TIMEOUT_CODES.test(haystack)) return "timeout";
}
return "unknown";
}
// src/http-client.ts
var HTTPClient = class {
constructor(config) {
this.config = config;
}
errorHandler = (err) => {
const errorType = classifyError(
err,
err?.status
);
return ERR(buildError(errorType, err));
};
getFullUrl(endpoint) {
const cleanEndpoint = endpoint.startsWith("/") ? endpoint.slice(1) : endpoint;
return `${this.config.baseUrl}/${cleanEndpoint}`;
}
getRequestOptions(options) {
return {
...options,
headers: {
"Content-Type": "application/json",
...this.config.headers,
...options?.headers
}
};
}
retryErrorHandler = (error, attempt) => {
const errorType = classifyError(
error,
error?.status
);
const retryableTypes = [
"rate_limit",
"connection",
"timeout",
"internal_server_error",
"bad_gateway",
"service_unavailable",
"gateway_timeout"
];
const shouldRetry = retryableTypes.includes(errorType);
if (this.config.retryOptions.debug) {
console.info(
`[HTTPClient] Attempt ${attempt} failed: ${errorType} - Retry: ${shouldRetry}`
);
}
return { retry: shouldRetry, data: null };
};
async withRetry(apiCall) {
return executeWithRetryWithHandler(
apiCall,
this.retryErrorHandler,
this.config.retryOptions.max,
this.config.retryOptions.baseDelay
);
}
request = async (method, endpoint, options) => {
return this.withRetry(async () => {
const url = this.getFullUrl(endpoint);
const requestOptions = this.getRequestOptions(options);
const res = await fetch(url, { method, ...requestOptions });
const text = await res.text();
let data = null;
if (text) {
try {
data = JSON.parse(text);
} catch (parseError) {
if (res.ok) {
return ERR(
buildError("Failed to parse response body", parseError)
);
}
data = text;
}
}
if (!res.ok) {
const error = buildError(`${res.status}: ${text}`, data);
error.status = res.status;
throw error;
}
return OK(data);
}).catch((err) => this.errorHandler(err));
};
get = async (endpoint, options) => {
return this.request("GET", endpoint, options);
};
post = async (endpoint, options) => {
return this.request("POST", endpoint, options);
};
delete = async (endpoint, options) => {
return this.request("DELETE", endpoint, options);
};
put = async (endpoint, options) => {
return this.request("PUT", endpoint, options);
};
patch = async (endpoint, options) => {
return this.request("PATCH", endpoint, options);
};
};
// src/oauth2-token-manager.ts
var OAuth2TokenManager = class {
_accessToken = null;
_expiresAt = 0;
// epoch ms
_refreshPromise = null;
config;
constructor(config) {
this.config = {
...config,
method: config.method ?? "POST",
expiryBuffer: config.expiryBuffer ?? 300
};
}
/**
* Get a valid access token, refreshing if necessary
*/
getToken = async () => {
if (this._accessToken && this._expiresAt > Date.now()) {
return this._accessToken;
}
if (this._refreshPromise) return this._refreshPromise;
this._refreshPromise = this._refreshToken().finally(() => {
this._refreshPromise = null;
});
return this._refreshPromise;
};
_refreshToken = async () => {
const credentials = Buffer.from(
`${this.config.credentials.username}:${this.config.credentials.password}`
).toString("base64");
const headers = {
Authorization: `Basic ${credentials}`,
...this.config.requestHeaders && {
...this.config.requestHeaders
}
};
const response = this.config.method === "GET" ? await this.config.client.get(this.config.tokenEndpoint, {
headers
}) : await this.config.client.post(this.config.tokenEndpoint, {
headers,
...this.config.requestBody && {
body: this.config.requestBody
}
});
if (!response.ok) {
throw new OperationFailedError(
"getAccessToken",
this.config.provider,
{
cause: new Error(
`Failed to obtain access token: ${JSON.stringify(response.value || response.error)}`
)
}
);
}
const tokenData = this.config.responseAdapter(
response.value
);
if (!tokenData.accessToken || !tokenData.expiresIn) {
throw new OperationFailedError(
"getAccessToken",
this.config.provider,
{
cause: new Error(
"Invalid token response: missing accessToken or expiresIn"
)
}
);
}
this._accessToken = tokenData.accessToken;
this._expiresAt = Date.now() + (tokenData.expiresIn - this.config.expiryBuffer) * 1e3;
return tokenData.accessToken;
};
/**
* Get authorization headers for API requests
*/
getAuthHeaders = async () => {
const token = await this.getToken();
return {
Authorization: `Bearer ${token}`,
...this.config.authHeaders && { ...this.config.authHeaders }
};
};
};
var billingAddressSchema = schema()(
zod.z.object({
name: zod.z.string().min(1, "Recipient name is required"),
line1: zod.z.string().min(1, "Address line 1 is required"),
line2: zod.z.string().default("").optional(),
city: zod.z.string().min(1, "City is required"),
state: zod.z.string().optional(),
// Optional because not all countries use states
postal_code: zod.z.string().min(1, "Postal code is required"),
country: zod.z.string().length(2, "Country must be a 2-letter ISO code").toUpperCase(),
phone: zod.z.string().optional()
})
);
var billingSchema = schema()(
zod.z.object({
address: billingAddressSchema,
carrier: zod.z.string().optional(),
currency: zod.z.string().min(1, "Currency is required")
})
);
var customerSchema = schema()(
zod.z.object({
id: zod.z.string(),
email: zod.z.string().email(),
name: zod.z.string(),
phone: zod.z.string().nullable(),
metadata: metadataSchema.optional(),
custom_fields: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
created_at: zod.z.date(),
updated_at: zod.z.date().nullable()
})
);
var payeeSchema = schema()(
zod.z.union([
zod.z.object({ email: zod.z.string().email() }),
zod.z.object({ id: zod.z.union([zod.z.string(), zod.z.number()]) })
])
);
var createCustomerSchema = schema()(
zod.z.object({
email: zod.z.string().email(),
name: zod.z.string().optional(),
phone: zod.z.string().nullable().optional(),
metadata: metadataSchema.optional(),
billing: billingSchema.nullable(),
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
})
);
var updateCustomerSchema = schema()(
zod.z.object({
email: zod.z.string().email().optional(),
name: zod.z.string().optional(),
metadata: metadataSchema.optional(),
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
})
);
var retrieveCustomerSchema = schema()(
zod.z.object({
id: zod.z.string()
})
);
var isEmailCustomer = (customer) => {
return typeof customer === "object" && customer !== null && "email" in customer;
};
var isIdCustomer = (customer) => {
return typeof customer === "object" && customer !== null && "id" in customer;
};
var parseCustomerName = (params) => {
const full = params.name?.trim() || params.email.split("@")[0];
const parts = full.split(/\s+/);
const first = parts[0] || "";
const last = parts.slice(1).join(" ") || "";
return {
fullName: full,
firstName: first,
lastName: last,
initials: `${first[0] || ""}${last[0] || ""}`.toUpperCase()
};
};
var subscriptionIntervalUnitSchema = zod.z.enum([
"day",
"week",
"month",
"year"
]);
var subscriptionBillingIntervalSchema = zod.z.union([
subscriptionIntervalUnitSchema,
zod.z.object({
type: zod.z.literal("custom"),
durationMs: zod.z.number().int().positive()
})
]);
var subscriptionStatusSchema = zod.z.enum([
"active",
"past_due",
"canceled",
"expired",
"trialing",
"pending"
]);
var subscriptionSchema = schema()(
zod.z.object({
id: zod.z.string(),
customer: payeeSchema.nullable(),
amount: zod.z.number(),
currency: zod.z.string(),
status: subscriptionStatusSchema,
current_period_start: zod.z.date(),
current_period_end: zod.z.date(),
item_id: zod.z.string(),
billing_interval: subscriptionBillingIntervalSchema,
metadata: metadataSchema.nullable(),
custom_fields: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
requires_action: zod.z.boolean(),
payment_url: zod.z.string().nullable()
})
);
var updateSubscriptionSchema = schema()(
zod.z.object({
metadata: metadataSchema,
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
})
);
var retrieveSubscriptionSchema = schema()(
zod.z.object({
id: zod.z.string()
})
);
var deleteSubscriptionSchema = schema()(
zod.z.object({
id: zod.z.string()
})
);
var createSubscriptionSchema = schema()(
subscriptionSchema.omit({
id: true,
status: true,
custom_fields: true,
current_period_start: true,
current_period_end: true,
requires_action: true,
payment_url: true
}).extend({
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
quantity: zod.z.number()
})
);
// src/resources/checkout.ts
var checkoutSubscriptionSchema = schema()(
zod.z.object({
billing_interval: subscriptionBillingIntervalSchema,
billing_interval_count: zod.z.number()
})
);
var billingModeSchema = zod.z.enum(["one_time", "recurring"]);
var checkoutSchema = schema()(
zod.z.object({
id: zod.z.string(),
customer: payeeSchema.nullable(),
payment_url: zod.z.string(),
metadata: metadataSchema.nullable(),
session_type: billingModeSchema,
products: zod.z.array(
zod.z.object({ id: zod.z.string(), quantity: zod.z.number() })
),
currency: zod.z.string(),
amount: zod.z.number(),
subscription: checkoutSubscriptionSchema.nullable().optional()
})
);
var createCheckoutBaseSchema = schema()(
zod.z.object({
customer: payeeSchema,
metadata: metadataSchema.nullable(),
item_id: zod.z.string(),
quantity: zod.z.number(),
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
billing: billingSchema.optional(),
success_url: zod.z.string(),
cancel_url: zod.z.string()
})
);
var createCheckoutSchema = schema()(
zod.z.object({
customer: payeeSchema,
metadata: metadataSchema.nullable(),
session_type: zod.z.literal(billingModeSchema.enum.one_time),
item_id: zod.z.string(),
quantity: zod.z.number(),
subscription: checkoutSubscriptionSchema.optional(),
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
billing: billingSchema.optional(),
success_url: zod.z.string(),
cancel_url: zod.z.string()
})
);
var updateCheckoutSchema = schema()(
createCheckoutSchema.partial()
);
var retrieveCheckoutSchema = schema()(
zod.z.object({
id: zod.z.string()
})
);
// src/resources/webhook.ts
var paykitEvent$InboundSchema = (event) => event;
var invoiceStatusSchema = zod.z.enum(["paid", "open"]);
var invoiceSchema = schema()(
zod.z.object({
id: zod.z.string(),
customer: payeeSchema.nullable(),
subscription_id: zod.z.string().nullable(),
billing_mode: billingModeSchema,
amount_paid: zod.z.number(),
currency: zod.z.string(),
status: invoiceStatusSchema,
paid_at: zod.z.string().nullable(),
line_items: zod.z.array(zod.z.object({ id: zod.z.string(), quantity: zod.z.number() })).nullable(),
metadata: metadataSchema.nullable(),
custom_fields: zod.z.record(zod.z.string(), zod.z.any()).nullable()
})
);
var paymentStatusSchema = zod.z.enum([
"pending",
"processing",
"requires_action",
"requires_capture",
"succeeded",
"canceled",
"failed"
]);
var paymentSchema = schema()(
zod.z.object({
id: zod.z.string(),
amount: zod.z.number().min(0),
currency: zod.z.string(),
customer: payeeSchema.nullable(),
status: paymentStatusSchema,
metadata: metadataSchema,
item_id: zod.z.string().nullable(),
requires_action: zod.z.boolean(),
payment_url: zod.z.string().nullable()
})
);
var createPaymentSchema = schema()(
paymentSchema.omit({
id: true,
status: true,
metadata: true,
requires_action: true,
payment_url: true
}).extend({
metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
billing: billingSchema.optional(),
capture_method: zod.z.enum(["automatic", "manual"])
})
);
var updatePaymentSchema = schema()(
paymentSchema.partial().extend({
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
})
);
var retrievePaymentSchema = schema()(
paymentSchema.pick({ id: true })
);
var deletePaymentSchema = schema()(
paymentSchema.pick({ id: true })
);
var capturePaymentSchema = schema()(
zod.z.object({
amount: zod.z.number()
})
);
var refundReasonSchema = schema()(
zod.z.string().nullable()
);
var refundSchema = schema()(
zod.z.object({
id: zod.z.string(),
amount: zod.z.number(),
currency: zod.z.string(),
reason: refundReasonSchema,
metadata: metadataSchema.nullable()
})
);
var createRefundSchema = schema()(
zod.z.object({
payment_id: zod.z.string(),
reason: refundReasonSchema,
amount: zod.z.number().min(0),
provider_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
metadata: metadataSchema.nullable()
})
);
// src/server/create-endpoint-handler.ts
function createEndpointHandlers(paykit) {
return {
"/customer/create": (params) => paykit.customers.create(params),
"/customer/retrieve": (id) => paykit.customers.retrieve(id),
"/customer/update": (id, params) => paykit.customers.update(id, params),
"/customer/delete": (id) => paykit.customers.delete(id),
"/checkout/create": (params) => paykit.checkouts.create(params),
"/checkout/retrieve": (id) => paykit.checkouts.retrieve(id),
"/checkout/update": (id, params) => paykit.checkouts.update(id, params),
"/checkout/delete": (id) => paykit.checkouts.delete(id),
"/subscription/create": (params) => paykit.subscriptions.create(params),
"/subscription/retrieve": (id) => paykit.subscriptions.retrieve(id),
"/subscription/update": (id, params) => paykit.subscriptions.update(id, params),
"/subscription/cancel": (id) => paykit.subscriptions.cancel(id),
"/subscription/delete": (id) => paykit.subscriptions.delete(id),
"/payment/create": (params) => paykit.payments.create(params),
"/payment/retrieve": (id) => paykit.payments.retrieve(id),
"/payment/update": (id, params) => paykit.payments.update(id, params),
"/payment/capture": (id, params) => paykit.payments.capture(id, params),
"/payment/cancel": (id) => paykit.payments.cancel(id),
"/payment/delete": (id) => paykit.payments.delete(id),
"/refund/create": (params) => paykit.refunds.create(params)
};
}
// src/index.ts
var PayKit = class {
constructor(provider, adapterMetadata) {
this.provider = provider;
this.adapterMetadata = adapterMetadata;
providerSchema.parse(provider);
if (this.adapterMetadata) {
payKitAdapterMetadataSchema.parse(this.adapterMetadata);
}
}
sdkVersion = "1.3.3";
/**
* Access the underlying native SDK (e.g., Stripe, Adyen) directly
* with full type safety.
*/
get _native() {
return this.provider._native;
}
_track(action, result, isLiveMode) {
if (!result) return;
Telemetry.log(
{
provider: this.provider.providerName,
action,
amount: result.amount,
currency: result.currency,
status: result.status,
provider_version: this.provider.providerVersion,
...this.adapterMetadata ? {
adapter: this.adapterMetadata.name,
adapter_version: this.adapterMetadata.version
} : {}
},
this.sdkVersion,
isLiveMode
);
}
/**
* Access the provider's name (e.g., 'stripe')
*/
get providerName() {
return this.provider.providerName;
}
get customers() {
return {
create: (params) => this.provider.createCustomer(params),
update: (id, params) => this.provider.updateCustomer(id, params),
retrieve: (id) => this.provider.retrieveCustomer(id),
delete: (id) => this.provider.deleteCustomer(id)
};
}
get checkouts() {
return {
create: async (params) => {
const res = await this.provider.createCheckout(params);
this._track("checkout.create", res, !this.provider.isSandbox);
return res;
},
retrieve: (id) => this.provider.retrieveCheckout(id),
update: (id, params) => this.provider.updateCheckout(id, params),
delete: (id) => this.provider.deleteCheckout(id)
};
}
get payments() {
return {
create: async (params) => {
const res = await this.provider.createPayment(params);
this._track("payment.create", res, !this.provider.isSandbox);
return res;
},
retrieve: (id) => this.provider.retrievePayment(id),
update: (id, params) => this.provider.updatePayment(id, params),
capture: async (id, params) => {
const res = await this.provider.capturePayment(id, params);
this._track("payment.capture", res, !this.provider.isSandbox);
return res;
},
delete: (id) => this.provider.deletePayment(id),
cancel: (id) => this.provider.cancelPayment(id)
};
}
get subscriptions() {
return {
create: async (params) => {
const res = await this.provider.createSubscription(params);
this._track(
"subscription.create",
res,
!this.provider.isSandbox
);
return res;
},
update: (id, params) => this.provider.updateSubscription(id, params),
cancel: (id) => this.provider.cancelSubscription(id),
retrieve: (id) => this.provider.retrieveSubscription(id),
delete: (id) => this.provider.deleteSubscription(id)
};
}
get refunds() {
return {
create: async (params) => {
const res = await this.provider.createRefund(params);
this._track("refund.create", res, !this.provider.isSandbox);
return res;
}
};
}
get webhooks() {
return {
setup: (config) => new Webhook().setup({
...config,
provider: this.provider
})
};
}
};
Object.defineProperty(exports, "Schema", {
enumerable: true,
get: function () { return zod.z; }
});
exports.AbstractPayKitProvider = AbstractPayKitProvider;
exports.AuthenticationError = AuthenticationError;
exports.ConfigurationError = ConfigurationError;
exports.ConstraintViolationError = ConstraintViolationError;
exports.ERR = ERR;
exports.HTTPClient = HTTPClient;
exports.InvalidTypeError = InvalidTypeError;
exports.NotImplementedError = NotImplementedError;
exports.OAuth2TokenManager = OAuth2TokenManager;
exports.OK = OK;
exports.OperationFailedError = OperationFailedError;
exports.PAYKIT_METADATA_KEY = PAYKIT_METADATA_KEY;
exports.PAYKIT_PROVIDER_METHODS = PAYKIT_PROVIDER_METHODS;
exports.PayKit = PayKit;
exports.PayKitError = PayKitError;
exports.ProviderNotSupportedError = ProviderNotSupportedError;
exports.RateLimitError = RateLimitError;
exports.ResourceNotFoundError = ResourceNotFoundError;
exports.UnTraceableError = UnTraceableError;
exports.ValidationError = ValidationError;
exports.Webhook = Webhook;
exports.WebhookError = WebhookError;
exports.billingAddressSchema = billingAddressSchema;
exports.billingModeSchema = billingModeSchema;
exports.billingSchema = billingSchema;
exports.buildError = buildError;
exports.capturePaymentSchema = capturePaymentSchema;
exports.checkoutSchema = checkoutSchema;
exports.checkoutSubscriptionSchema = checkoutSubscriptionSchema;
exports.createCheckoutBaseSchema = createCheckoutBaseSchema;
exports.createCheckoutSchema = createCheckoutSchema;
exports.createCustomerSchema = createCustomerSchema;
exports.createEndpointHandlers = createEndpointHandlers;
exports.createPaymentSchema = createPaymentSchema;
exports.createRefundSchema = createRefundSchema;
exports.createSubscriptionSchema = createSubscriptionSchema;
exports.customerSchema = customerSchema;
exports.deletePaymentSchema = deletePaymentSchema;
exports.deleteSubscriptionSchema = deleteSubscriptionSchema;
exports.executeWithRetryWithHandler = executeWithRetryWithHandler;
exports.getURLFromHeaders = getURLFromHeaders;
exports.invoiceSchema = invoiceSchema;
exports.invoiceStatusSchema = invoiceStatusSchema;
exports.isEmailCustomer = isEmailCustomer;
exports.isIdCustomer = isIdCustomer;
exports.metadataSchema = metadataSchema;
exports.omitInternalMetadata = omitInternalMetadata;
exports.parseCustomerName = parseCustomerName;
exports.parseJSON = parseJSON;
exports.payKitAdapterMetadataSchema = payKitAdapterMetadataSchema;
exports.payeeSchema = payeeSchema;
exports.paykitEvent$InboundSchema = paykitEvent$InboundSchema;
exports.paymentSchema = paymentSchema;
exports.paymentStatusSchema = paymentStatusSchema;
exports.providerSchema = providerSchema;
exports.refundReasonMatcher = refundReasonMatcher;
exports.refundSchema = refundSchema;
exports.retrieveCheckoutSchema = retrieveCheckoutSchema;
exports.retrieveCustomerSchema = retrieveCustomerSchema;
exports.retrievePaymentSchema = retrievePaymentSchema;
exports.retrieveSubscriptionSchema = retrieveSubscriptionSchema;
exports.safeDecode = safeDecode;
exports.safeEncode = safeEncode;
exports.safeParse = safeParse;
exports.schema = schema;
exports.stringifyMetadataValues = stringifyMetadataValues;
exports.subscriptionBillingIntervalSchema = subscriptionBillingIntervalSchema;
exports.subscriptionIntervalUnitSchema = subscriptionIntervalUnitSchema;
exports.subscriptionSchema = subscriptionSchema;
exports.subscriptionStatusSchema = subscriptionStatusSchema;
exports.tryCatchAsync = tryCatchAsync;
exports.tryCatchSync = tryCatchSync;
exports.unwrapAsync = unwrapAsync;
exports.updateCheckoutSchema = updateCheckoutSchema;
exports.updateCustomerSchema = updateCustomerSchema;
exports.updatePaymentSchema = updatePaymentSchema;
exports.updateSubscriptionSchema = updateSubscriptionSchema;
exports.validateRequiredKeys = validateRequiredKeys;