UNPKG

@paykit-sdk/core

Version:

The Payment Toolkit for Typescript

1,142 lines (1,126 loc) 34.1 kB
import { z } from 'zod'; export { z as Schema } from 'zod'; import { setTimeout } from '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 = 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 = z.object({ /** * The name of the adapter */ name: z.string(), /** * The version of the adapter */ version: z.string() }); var PAYKIT_METADATA_KEY = "__paykit"; var metadataSchema = z.record(z.string(), 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 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()( z.object({ name: z.string().min(1, "Recipient name is required"), line1: z.string().min(1, "Address line 1 is required"), line2: z.string().default("").optional(), city: z.string().min(1, "City is required"), state: z.string().optional(), // Optional because not all countries use states postal_code: z.string().min(1, "Postal code is required"), country: z.string().length(2, "Country must be a 2-letter ISO code").toUpperCase(), phone: z.string().optional() }) ); var billingSchema = schema()( z.object({ address: billingAddressSchema, carrier: z.string().optional(), currency: z.string().min(1, "Currency is required") }) ); var customerSchema = schema()( z.object({ id: z.string(), email: z.string().email(), name: z.string(), phone: z.string().nullable(), metadata: metadataSchema.optional(), custom_fields: z.record(z.string(), z.unknown()).optional(), created_at: z.date(), updated_at: z.date().nullable() }) ); var payeeSchema = schema()( z.union([ z.object({ email: z.string().email() }), z.object({ id: z.union([z.string(), z.number()]) }) ]) ); var createCustomerSchema = schema()( z.object({ email: z.string().email(), name: z.string().optional(), phone: z.string().nullable().optional(), metadata: metadataSchema.optional(), billing: billingSchema.nullable(), provider_metadata: z.record(z.string(), z.unknown()).optional() }) ); var updateCustomerSchema = schema()( z.object({ email: z.string().email().optional(), name: z.string().optional(), metadata: metadataSchema.optional(), provider_metadata: z.record(z.string(), z.unknown()).optional() }) ); var retrieveCustomerSchema = schema()( z.object({ id: 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 = z.enum([ "day", "week", "month", "year" ]); var subscriptionBillingIntervalSchema = z.union([ subscriptionIntervalUnitSchema, z.object({ type: z.literal("custom"), durationMs: z.number().int().positive() }) ]); var subscriptionStatusSchema = z.enum([ "active", "past_due", "canceled", "expired", "trialing", "pending" ]); var subscriptionSchema = schema()( z.object({ id: z.string(), customer: payeeSchema.nullable(), amount: z.number(), currency: z.string(), status: subscriptionStatusSchema, current_period_start: z.date(), current_period_end: z.date(), item_id: z.string(), billing_interval: subscriptionBillingIntervalSchema, metadata: metadataSchema.nullable(), custom_fields: z.record(z.string(), z.unknown()).nullable(), requires_action: z.boolean(), payment_url: z.string().nullable() }) ); var updateSubscriptionSchema = schema()( z.object({ metadata: metadataSchema, provider_metadata: z.record(z.string(), z.unknown()).optional() }) ); var retrieveSubscriptionSchema = schema()( z.object({ id: z.string() }) ); var deleteSubscriptionSchema = schema()( z.object({ id: 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: z.record(z.string(), z.unknown()).optional(), quantity: z.number() }) ); // src/resources/checkout.ts var checkoutSubscriptionSchema = schema()( z.object({ billing_interval: subscriptionBillingIntervalSchema, billing_interval_count: z.number() }) ); var billingModeSchema = z.enum(["one_time", "recurring"]); var checkoutSchema = schema()( z.object({ id: z.string(), customer: payeeSchema.nullable(), payment_url: z.string(), metadata: metadataSchema.nullable(), session_type: billingModeSchema, products: z.array( z.object({ id: z.string(), quantity: z.number() }) ), currency: z.string(), amount: z.number(), subscription: checkoutSubscriptionSchema.nullable().optional() }) ); var createCheckoutBaseSchema = schema()( z.object({ customer: payeeSchema, metadata: metadataSchema.nullable(), item_id: z.string(), quantity: z.number(), provider_metadata: z.record(z.string(), z.unknown()).optional(), billing: billingSchema.optional(), success_url: z.string(), cancel_url: z.string() }) ); var createCheckoutSchema = schema()( z.object({ customer: payeeSchema, metadata: metadataSchema.nullable(), session_type: z.literal(billingModeSchema.enum.one_time), item_id: z.string(), quantity: z.number(), subscription: checkoutSubscriptionSchema.optional(), provider_metadata: z.record(z.string(), z.unknown()).optional(), billing: billingSchema.optional(), success_url: z.string(), cancel_url: z.string() }) ); var updateCheckoutSchema = schema()( createCheckoutSchema.partial() ); var retrieveCheckoutSchema = schema()( z.object({ id: z.string() }) ); // src/resources/webhook.ts var paykitEvent$InboundSchema = (event) => event; var invoiceStatusSchema = z.enum(["paid", "open"]); var invoiceSchema = schema()( z.object({ id: z.string(), customer: payeeSchema.nullable(), subscription_id: z.string().nullable(), billing_mode: billingModeSchema, amount_paid: z.number(), currency: z.string(), status: invoiceStatusSchema, paid_at: z.string().nullable(), line_items: z.array(z.object({ id: z.string(), quantity: z.number() })).nullable(), metadata: metadataSchema.nullable(), custom_fields: z.record(z.string(), z.any()).nullable() }) ); var paymentStatusSchema = z.enum([ "pending", "processing", "requires_action", "requires_capture", "succeeded", "canceled", "failed" ]); var paymentSchema = schema()( z.object({ id: z.string(), amount: z.number().min(0), currency: z.string(), customer: payeeSchema.nullable(), status: paymentStatusSchema, metadata: metadataSchema, item_id: z.string().nullable(), requires_action: z.boolean(), payment_url: z.string().nullable() }) ); var createPaymentSchema = schema()( paymentSchema.omit({ id: true, status: true, metadata: true, requires_action: true, payment_url: true }).extend({ metadata: z.record(z.string(), z.unknown()).optional(), provider_metadata: z.record(z.string(), z.unknown()).optional(), billing: billingSchema.optional(), capture_method: z.enum(["automatic", "manual"]) }) ); var updatePaymentSchema = schema()( paymentSchema.partial().extend({ provider_metadata: z.record(z.string(), z.unknown()).optional() }) ); var retrievePaymentSchema = schema()( paymentSchema.pick({ id: true }) ); var deletePaymentSchema = schema()( paymentSchema.pick({ id: true }) ); var capturePaymentSchema = schema()( z.object({ amount: z.number() }) ); var refundReasonSchema = schema()( z.string().nullable() ); var refundSchema = schema()( z.object({ id: z.string(), amount: z.number(), currency: z.string(), reason: refundReasonSchema, metadata: metadataSchema.nullable() }) ); var createRefundSchema = schema()( z.object({ payment_id: z.string(), reason: refundReasonSchema, amount: z.number().min(0), provider_metadata: z.record(z.string(), 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 }) }; } }; export { AbstractPayKitProvider, AuthenticationError, ConfigurationError, ConstraintViolationError, ERR, HTTPClient, InvalidTypeError, NotImplementedError, OAuth2TokenManager, OK, OperationFailedError, PAYKIT_METADATA_KEY, PAYKIT_PROVIDER_METHODS, PayKit, PayKitError, ProviderNotSupportedError, RateLimitError, ResourceNotFoundError, UnTraceableError, ValidationError, Webhook, WebhookError, billingAddressSchema, billingModeSchema, billingSchema, buildError, capturePaymentSchema, checkoutSchema, checkoutSubscriptionSchema, createCheckoutBaseSchema, createCheckoutSchema, createCustomerSchema, createEndpointHandlers, createPaymentSchema, createRefundSchema, createSubscriptionSchema, customerSchema, deletePaymentSchema, deleteSubscriptionSchema, executeWithRetryWithHandler, getURLFromHeaders, invoiceSchema, invoiceStatusSchema, isEmailCustomer, isIdCustomer, metadataSchema, omitInternalMetadata, parseCustomerName, parseJSON, payKitAdapterMetadataSchema, payeeSchema, paykitEvent$InboundSchema, paymentSchema, paymentStatusSchema, providerSchema, refundReasonMatcher, refundSchema, retrieveCheckoutSchema, retrieveCustomerSchema, retrievePaymentSchema, retrieveSubscriptionSchema, safeDecode, safeEncode, safeParse, schema, stringifyMetadataValues, subscriptionBillingIntervalSchema, subscriptionIntervalUnitSchema, subscriptionSchema, subscriptionStatusSchema, tryCatchAsync, tryCatchSync, unwrapAsync, updateCheckoutSchema, updateCustomerSchema, updatePaymentSchema, updateSubscriptionSchema, validateRequiredKeys };