diff --git a/src/Error.ts b/src/Error.ts index aa094c0952..8ffb55232b 100644 --- a/src/Error.ts +++ b/src/Error.ts @@ -1,5 +1,6 @@ /* eslint-disable camelcase */ +import {HttpClientResponseError} from './RequestSender.js'; import {RawErrorType, StripeRawError} from './Types.js'; export const generate = (rawStripeError: StripeRawError): StripeError => { @@ -38,7 +39,7 @@ export class StripeError extends Error { readonly code?: string; readonly doc_url?: string; readonly param?: string; - readonly detail?: string | Error; + readonly detail?: string | Error | HttpClientResponseError; readonly statusCode?: number; readonly charge?: string; readonly decline_code?: string; @@ -62,8 +63,7 @@ export class StripeError extends Error { this.headers = raw.headers; this.requestId = raw.requestId; this.statusCode = raw.statusCode; - // @ts-ignore - this.message = raw.message; + this.message = raw.message ?? ''; this.charge = raw.charge; this.decline_code = raw.decline_code; diff --git a/src/RequestSender.ts b/src/RequestSender.ts index d69c3c0b87..d92dac1f24 100644 --- a/src/RequestSender.ts +++ b/src/RequestSender.ts @@ -9,6 +9,8 @@ import { import { emitWarning, normalizeHeaders, + parseHttpHeaderAsNumber, + parseHttpHeaderAsString, removeNullish, stringifyRequestData, } from './utils.js'; @@ -480,11 +482,10 @@ export class RequestSender { const requestStartTime = Date.now(); - // @ts-ignore const requestEvent: RequestEvent = removeNullish({ api_version: apiVersion, - account: headers['Stripe-Account'], - idempotency_key: headers['Idempotency-Key'], + account: parseHttpHeaderAsString(headers['Stripe-Account']), + idempotency_key: parseHttpHeaderAsString(headers['Idempotency-Key']), method, path, request_start_time: requestStartTime, @@ -503,8 +504,7 @@ export class RequestSender { apiVersion, headers, requestRetries, - // @ts-ignore - res.getHeaders()['retry-after'] + parseHttpHeaderAsNumber(res.getHeaders()['retry-after']) ); } else if (options.streaming && res.getStatusCode() < 400) { return this._streamingResponseHandler( @@ -542,7 +542,6 @@ export class RequestSender { : RequestSender._generateConnectionErrorMessage( requestRetries ), - // @ts-ignore detail: error, }) ); diff --git a/src/Types.d.ts b/src/Types.d.ts index f6ab743848..6eec55a377 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -5,6 +5,7 @@ import { HttpClientResponseInterface, } from './net/HttpClient.js'; import {PlatformFunctions} from './platform/PlatformFunctions.js'; +import {HttpClientResponseError} from './RequestSender.js'; export type AppInfo = {name?: string} & Record; export type BufferedFile = { @@ -50,7 +51,7 @@ export type RequestEvent = { method?: string; path?: string; request_start_time: number; - usage: Array; + usage?: Array; }; export type RequestHeaders = Record; export type RequestOptions = { @@ -173,7 +174,7 @@ export type StripeRawError = { doc_url?: string; decline_code?: string; param?: string; - detail?: string | Error; + detail?: string | Error | HttpClientResponseError; charge?: string; payment_method_type?: string; payment_intent?: any; diff --git a/src/Webhooks.ts b/src/Webhooks.ts index fc3dec8907..633ca71834 100644 --- a/src/Webhooks.ts +++ b/src/Webhooks.ts @@ -47,7 +47,7 @@ type WebhookSignatureObject = { }; export type WebhookObject = { DEFAULT_TOLERANCE: number; - signature: WebhookSignatureObject; + signature: WebhookSignatureObject | null; constructEvent: ( payload: WebhookPayload, header: WebhookHeader, @@ -75,7 +75,6 @@ export function createWebhooks( ): WebhookObject { const Webhook: WebhookObject = { DEFAULT_TOLERANCE: 300, // 5 minutes - // @ts-ignore signature: null, constructEvent( payload: WebhookPayload, @@ -86,7 +85,7 @@ export function createWebhooks( receivedAt: number ): WebhookEvent { try { - this.signature.verifyHeader( + this.signature?.verifyHeader( payload, header, secret, @@ -117,7 +116,7 @@ export function createWebhooks( cryptoProvider: CryptoProvider, receivedAt: number ): Promise { - await this.signature.verifyHeaderAsync( + await this.signature?.verifyHeaderAsync( payload, header, secret, @@ -394,7 +393,6 @@ export function createWebhooks( ) - details.timestamp; if (tolerance > 0 && timestampAge > tolerance) { - // @ts-ignore throw new StripeSignatureVerificationError(header, payload, { message: 'Timestamp outside the tolerance zone', }); diff --git a/src/net/FetchHttpClient.ts b/src/net/FetchHttpClient.ts index bea479b463..251d727fcd 100644 --- a/src/net/FetchHttpClient.ts +++ b/src/net/FetchHttpClient.ts @@ -1,4 +1,5 @@ import {RequestHeaders, RequestData, ResponseHeaders} from '../Types.js'; +import {parseHeadersForFetch} from '../utils.js'; import { HttpClient, HttpClientInterface, @@ -139,10 +140,8 @@ export class FetchHttpClient extends HttpClient implements HttpClientInterface { url.toString(), { method, - // @ts-ignore - headers, - // @ts-ignore - body, + headers: parseHeadersForFetch(headers), + body: typeof body === 'object' ? JSON.stringify(body) : body, }, timeout ); diff --git a/src/stripe.core.ts b/src/stripe.core.ts index 9263b7cf8a..3e90f2497b 100644 --- a/src/stripe.core.ts +++ b/src/stripe.core.ts @@ -242,8 +242,7 @@ export function createStripe( return accum; }, - // @ts-ignore - undefined + {} ); }, diff --git a/src/utils.ts b/src/utils.ts index 005256d56e..ea6f7bdf93 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -73,14 +73,22 @@ export const makeURLInterpolator = ((): ((s: string) => UrlInterpolator) => { return (str: string): UrlInterpolator => { const cleanString = str.replace(/["\n\r\u2028\u2029]/g, ($0) => rc[$0]); return (outputs: Record): string => { - return cleanString.replace(/\{([\s\S]+?)\}/g, ($0, $1) => - // @ts-ignore - encodeURIComponent(outputs[$1] || '') - ); + return cleanString.replace(/\{([\s\S]+?)\}/g, ($0, $1) => { + const output = outputs[$1]; + if (isValidEncodeUriComponentType(output)) + return encodeURIComponent(output); + return ''; + }); }; }; })(); +function isValidEncodeUriComponentType( + value: unknown +): value is number | string | boolean { + return ['number', 'string', 'boolean'].includes(typeof value); +} + export function extractUrlParams(path: string): Array { const params = path.match(/\{\w+\}/g); if (!params) { @@ -376,3 +384,27 @@ export function concat(arrays: Array): Uint8Array { return merged; } + +export function parseHttpHeaderAsString( + header: RequestHeaders[K] +): string { + if (Array.isArray(header)) { + return header.join(', '); + } + return String(header); +} + +export function parseHttpHeaderAsNumber( + header: RequestHeaders[K] +): number { + const number = Array.isArray(header) ? header[0] : header; + return Number(number); +} + +export function parseHeadersForFetch( + headers: RequestHeaders +): [string, string][] { + return Object.entries(headers).map(([key, value]) => { + return [key, parseHttpHeaderAsString(value)]; + }); +} diff --git a/test/utils.spec.ts b/test/utils.spec.ts index 248d8ee92b..5f210dcefa 100644 --- a/test/utils.spec.ts +++ b/test/utils.spec.ts @@ -11,6 +11,8 @@ describe('utils', () => { expect(template({foo: '', baz: ''})).to.equal('/some/url//?ok=1'); + expect(template({foo: 0, baz: 't'})).to.equal('/some/url/0/t?ok=1'); + expect( // Test encoding: template({foo: 'FOO', baz: '__::baz::__'})