UNPKG

@paykit-sdk/core

Version:

The Payment Toolkit for Typescript

178 lines (172 loc) 5.03 kB
import { setTimeout } from 'timers/promises'; import { z } from 'zod'; // src/tools/utils.ts // src/error.ts var UnTraceableError = class extends Error { constructor(message) { super(message); this.name = this.constructor.name; this.stack = void 0; } }; var PAYKIT_METADATA_KEY = "__paykit"; 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"; }; export { ERR, OK, buildError, executeWithRetryWithHandler, getURLFromHeaders, omitInternalMetadata, parseJSON, refundReasonMatcher, safeDecode, safeEncode, safeParse, schema, stringifyMetadataValues, tryCatchAsync, tryCatchSync, unwrapAsync, validateRequiredKeys };