UNPKG

stripe

Version:
404 lines 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseHeadersForFetch = exports.parseHttpHeaderAsNumber = exports.parseHttpHeaderAsString = exports.getAPIMode = exports.jsonStringifyRequestData = exports.concat = exports.createApiKeyAuthenticator = exports.detectAIAgent = exports.AI_AGENTS = exports.determineProcessUserAgentProperties = exports.validateInteger = exports.flattenAndStringify = exports.isObject = exports.emitWarning = exports.pascalToCamelCase = exports.normalizeHeader = exports.normalizeHeaders = exports.removeNullish = exports.processOptions = exports.validateApiBase = exports.extractUrlParams = exports.makeURLInterpolator = exports.queryStringifyRequestData = exports.isOptionsHash = void 0; const Types_js_1 = require("./Types.js"); const OPTIONS_KEYS = [ 'apiKey', 'idempotencyKey', 'stripeAccount', 'apiVersion', 'maxNetworkRetries', 'timeout', 'apiBase', 'authenticator', 'stripeContext', 'headers', 'additionalHeaders', 'streaming', ]; function isOptionsHash(o) { return (o && typeof o === 'object' && OPTIONS_KEYS.some((prop) => Object.prototype.hasOwnProperty.call(o, prop))); } exports.isOptionsHash = isOptionsHash; /** * Stringifies an Object, accommodating nested objects * (forming the conventional key 'parent[child]=value') */ function queryStringifyRequestData(data) { return stringifyRequestData(data); } exports.queryStringifyRequestData = queryStringifyRequestData; /** * Encodes a value for use in a query string, keeping brackets unencoded * for readability (the server accepts both encoded and unencoded brackets). */ function encodeQueryValue(value) { return (encodeURIComponent(value) // Encode characters not encoded by encodeURIComponent but encoded by qs .replace(/!/g, '%21') .replace(/\*/g, '%2A') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/'/g, '%27') // Decode brackets for readability (server accepts both) .replace(/%5B/g, '[') .replace(/%5D/g, ']')); } /** * Converts a value to a string representation for query string encoding. * Dates are converted to Unix timestamps. */ function valueToString(value) { if (value instanceof Date) { return Math.floor(value.getTime() / 1000).toString(); } if (value === null) { return ''; } return String(value); } /** * Custom query string stringifier that handles nested objects and arrays. * Produces output compatible with the qs library's indexed array format. */ function stringifyRequestData(data) { const pairs = []; function encode(key, value) { if (value === undefined) { return; } if (value === null || typeof value !== 'object' || value instanceof Date) { // Primitive value (including null and Date) pairs.push(encodeQueryValue(key) + '=' + encodeQueryValue(valueToString(value))); return; } if (Array.isArray(value)) { // Array: use indexed format arr[0], arr[1], etc. for (let i = 0; i < value.length; i++) { if (value[i] !== undefined) { encode(key + '[' + i + ']', value[i]); } } return; } // Object: recurse with bracket notation for (const k of Object.keys(value)) { encode(key + '[' + k + ']', value[k]); } } // Handle top-level object if (typeof data === 'object' && data !== null) { for (const key of Object.keys(data)) { encode(key, data[key]); } } return pairs.join('&'); } /** * Outputs a new function with interpolated object property values. * Use like so: * const fn = makeURLInterpolator('some/url/{param1}/{param2}'); * fn({ param1: 123, param2: 456 }); // => 'some/url/123/456' */ exports.makeURLInterpolator = (() => { const rc = { '\n': '\\n', '"': '\\"', '\u2028': '\\u2028', '\u2029': '\\u2029', }; return (str) => { const cleanString = str.replace(/["\n\r\u2028\u2029]/g, ($0) => rc[$0]); return (outputs) => { return cleanString.replace(/\{([\s\S]+?)\}/g, ($0, $1) => { const output = outputs[$1]; if (isValidEncodeUriComponentType(output)) return encodeURIComponent(output); return ''; }); }; }; })(); function isValidEncodeUriComponentType(value) { return ['number', 'string', 'boolean'].includes(typeof value); } function extractUrlParams(path) { const params = path.match(/\{\w+\}/g); if (!params) { return []; } return params.map((param) => param.replace(/[{}]/g, '')); } exports.extractUrlParams = extractUrlParams; /** * enforces that only supplied API bases are allowed. */ const validateApiBase = (apiBase) => { if (typeof apiBase !== 'string') { throw new Error(`API base must be a string, got: ${typeof apiBase}`); } return apiBase in Types_js_1.DEFAULT_BASE_ADDRESSES; }; exports.validateApiBase = validateApiBase; function processOptions(options) { const result = { authenticator: null, headers: {}, settings: {}, streaming: false, apiBase: null, }; if (!options) { return result; } if (options.apiKey) { result.authenticator = createApiKeyAuthenticator(options.apiKey); } if (options.idempotencyKey) { result.headers['Idempotency-Key'] = options.idempotencyKey; } if (options.stripeAccount) { result.headers['Stripe-Account'] = options.stripeAccount; } if (options.stripeContext) { if (result.headers['Stripe-Account']) { throw new Error("Can't specify both stripeAccount and stripeContext."); } result.headers['Stripe-Context'] = options.stripeContext; } if (options.apiVersion) { result.headers['Stripe-Version'] = options.apiVersion; } if (Number.isInteger(options.maxNetworkRetries)) { result.settings.maxNetworkRetries = options.maxNetworkRetries; } if (Number.isInteger(options.timeout)) { result.settings.timeout = options.timeout; } if (options.authenticator) { if (options.apiKey) { throw new Error("Can't specify both apiKey and authenticator."); } if (typeof options.authenticator !== 'function') { throw new Error('The authenticator must be a function ' + 'receiving a request as the first parameter.'); } result.authenticator = options.authenticator; } if (options.headers) { Object.assign(result.headers, options.headers); } if (options.streaming) { result.streaming = true; } return result; } exports.processOptions = processOptions; /** * Remove empty values from an object */ function removeNullish(obj) { if (typeof obj !== 'object') { throw new Error('Argument must be an object'); } return Object.keys(obj).reduce((result, key) => { if (obj[key] != null) { result[key] = obj[key]; } return result; }, {}); } exports.removeNullish = removeNullish; /** * Normalize standard HTTP Headers: * {'foo-bar': 'hi'} * becomes * {'Foo-Bar': 'hi'} */ function normalizeHeaders(obj) { if (!(obj && typeof obj === 'object')) { return obj; } return Object.keys(obj).reduce((result, header) => { result[normalizeHeader(header)] = obj[header]; return result; }, {}); } exports.normalizeHeaders = normalizeHeaders; /** * Stolen from https://github.com/marten-de-vries/header-case-normalizer/blob/master/index.js#L36-L41 * without the exceptions which are irrelevant to us. */ function normalizeHeader(header) { return header .split('-') .map((text) => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase()) .join('-'); } exports.normalizeHeader = normalizeHeader; /** * Allow for special capitalization cases (such as OAuth) */ function pascalToCamelCase(name) { if (name === 'OAuth') { return 'oauth'; } else { return name[0].toLowerCase() + name.substring(1); } } exports.pascalToCamelCase = pascalToCamelCase; function emitWarning(warning) { if (typeof process.emitWarning !== 'function') { return console.warn(`Stripe: ${warning}`); /* eslint-disable-line no-console */ } return process.emitWarning(warning, 'Stripe'); } exports.emitWarning = emitWarning; function isObject(obj) { const type = typeof obj; return (type === 'function' || type === 'object') && !!obj; } exports.isObject = isObject; // For use in multipart requests function flattenAndStringify(data) { const result = {}; const step = (obj, prevKey) => { Object.entries(obj).forEach(([key, value]) => { const newKey = prevKey ? `${prevKey}[${key}]` : key; if (isObject(value)) { if (!(value instanceof Uint8Array) && !Object.prototype.hasOwnProperty.call(value, 'data')) { // Non-buffer non-file Objects are recursively flattened return step(value, newKey); } else { // Buffers and file objects are stored without modification result[newKey] = value; } } else { // Primitives are converted to strings result[newKey] = String(value); } }); }; step(data, null); return result; } exports.flattenAndStringify = flattenAndStringify; function validateInteger(name, n, defaultVal) { if (!Number.isInteger(n)) { if (defaultVal !== undefined) { return defaultVal; } else { throw new Error(`${name} must be an integer`); } } return n; } exports.validateInteger = validateInteger; function determineProcessUserAgentProperties() { return typeof process === 'undefined' ? {} : { lang_version: process.version, }; } exports.determineProcessUserAgentProperties = determineProcessUserAgentProperties; exports.AI_AGENTS = [ // The beginning of the section generated from our OpenAPI spec ['ANTIGRAVITY_CLI_ALIAS', 'antigravity'], ['CLAUDECODE', 'claude_code'], ['CLINE_ACTIVE', 'cline'], ['CODEX_SANDBOX', 'codex_cli'], ['CODEX_THREAD_ID', 'codex_cli'], ['CODEX_SANDBOX_NETWORK_DISABLED', 'codex_cli'], ['CODEX_CI', 'codex_cli'], ['CURSOR_AGENT', 'cursor'], ['GEMINI_CLI', 'gemini_cli'], ['OPENCLAW_SHELL', 'openclaw'], ['OPENCODE', 'open_code'], // The end of the section generated from our OpenAPI spec ]; function detectAIAgent(env) { for (const [envVar, agentName] of exports.AI_AGENTS) { if (env[envVar]) { return agentName; } } return ''; } exports.detectAIAgent = detectAIAgent; function createApiKeyAuthenticator(apiKey) { const authenticator = (request) => { request.headers.Authorization = 'Bearer ' + apiKey; return Promise.resolve(); }; // For testing authenticator._apiKey = apiKey; return authenticator; } exports.createApiKeyAuthenticator = createApiKeyAuthenticator; /** * Joins an array of Uint8Arrays into a single Uint8Array */ function concat(arrays) { const totalLength = arrays.reduce((len, array) => len + array.length, 0); const merged = new Uint8Array(totalLength); let offset = 0; arrays.forEach((array) => { merged.set(array, offset); offset += array.length; }); return merged; } exports.concat = concat; /** * Replaces Date objects with Unix timestamps */ function dateTimeReplacer(key, value) { if (this[key] instanceof Date) { return Math.floor(this[key].getTime() / 1000).toString(); } return value; } /** * JSON stringifies an Object, replacing Date objects with Unix timestamps */ function jsonStringifyRequestData(data) { return JSON.stringify(data, dateTimeReplacer); } exports.jsonStringifyRequestData = jsonStringifyRequestData; /** * Inspects the given path to determine if the endpoint is for v1 or v2 API */ function getAPIMode(path) { if (!path) { return 'v1'; } return path.startsWith('/v2') ? 'v2' : 'v1'; } exports.getAPIMode = getAPIMode; function parseHttpHeaderAsString(header) { if (Array.isArray(header)) { return header.join(', '); } return String(header); } exports.parseHttpHeaderAsString = parseHttpHeaderAsString; function parseHttpHeaderAsNumber(header) { const number = Array.isArray(header) ? header[0] : header; return Number(number); } exports.parseHttpHeaderAsNumber = parseHttpHeaderAsNumber; function parseHeadersForFetch(headers) { return Object.entries(headers).map(([key, value]) => { return [key, parseHttpHeaderAsString(value)]; }); } exports.parseHeadersForFetch = parseHeadersForFetch; //# sourceMappingURL=utils.js.map