From 84d3ec43b0dd582fee811f2330f2001095e90475 Mon Sep 17 00:00:00 2001 From: Annie Li Date: Fri, 23 Sep 2022 15:15:03 -0700 Subject: [PATCH] Migrate other Stripe infrastructure to TS --- .eslintrc.js | 1 + lib/Webhooks.js | 6 +++-- lib/crypto/SubtleCryptoProvider.js | 2 +- lib/multipart.js | 7 ++++-- lib/net/FetchHttpClient.js | 3 ++- lib/net/NodeHttpClient.js | 3 ++- lib/utils.js | 9 ++++--- src/Error.ts | 4 +-- ...ourceNamespace.js => ResourceNamespace.ts} | 0 src/{Webhooks.js => Webhooks.ts} | 10 +++++--- .../{CryptoProvider.js => CryptoProvider.ts} | 6 ++--- ...ryptoProvider.js => NodeCryptoProvider.ts} | 13 ++++++---- ...ptoProvider.js => SubtleCryptoProvider.ts} | 10 +++++--- src/{multipart.js => multipart.ts} | 9 ++++--- ...{FetchHttpClient.js => FetchHttpClient.ts} | 10 ++++++-- src/net/{HttpClient.js => HttpClient.ts} | 14 +++++++++-- .../{NodeHttpClient.js => NodeHttpClient.ts} | 9 +++++-- src/{utils.js => utils.ts} | 25 +++++++++++++++---- 18 files changed, 98 insertions(+), 43 deletions(-) rename src/{ResourceNamespace.js => ResourceNamespace.ts} (100%) rename src/{Webhooks.js => Webhooks.ts} (96%) rename src/crypto/{CryptoProvider.js => CryptoProvider.ts} (88%) rename src/crypto/{NodeCryptoProvider.js => NodeCryptoProvider.ts} (58%) rename src/crypto/{SubtleCryptoProvider.js => SubtleCryptoProvider.ts} (89%) rename src/{multipart.js => multipart.ts} (93%) rename src/net/{FetchHttpClient.js => FetchHttpClient.ts} (95%) rename src/net/{HttpClient.js => HttpClient.ts} (82%) rename src/net/{NodeHttpClient.js => NodeHttpClient.ts} (93%) rename src/{utils.js => utils.ts} (97%) diff --git a/.eslintrc.js b/.eslintrc.js index 7eecf96137..041cd2c19e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -271,6 +271,7 @@ module.exports = { '@typescript-eslint/no-explicit-any': 0, '@typescript-eslint/explicit-function-return-type': 0, '@typescript-eslint/no-var-requires': 0, + '@typescript-eslint/no-this-alias': 0, 'prefer-rest-params': 'off', }, }, diff --git a/lib/Webhooks.js b/lib/Webhooks.js index cfd9232527..9fb4850523 100644 --- a/lib/Webhooks.js +++ b/lib/Webhooks.js @@ -1,8 +1,10 @@ 'use strict'; const utils = require('./utils'); -const {StripeError, StripeSignatureVerificationError} = require('./Error'); +const _Error = require('./Error'); +const {StripeError, StripeSignatureVerificationError} = _Error; const Webhook = { DEFAULT_TOLERANCE: 300, + signature: null, constructEvent(payload, header, secret, tolerance, cryptoProvider) { this.signature.verifyHeader( payload, @@ -205,7 +207,7 @@ function parseHeader(header, scheme) { (accum, item) => { const kv = item.split('='); if (kv[0] === 't') { - accum.timestamp = kv[1]; + accum.timestamp = parseInt(kv[1], 10); } if (kv[0] === scheme) { accum.signatures.push(kv[1]); diff --git a/lib/crypto/SubtleCryptoProvider.js b/lib/crypto/SubtleCryptoProvider.js index 6ff0e2b3c2..cbf5d01373 100644 --- a/lib/crypto/SubtleCryptoProvider.js +++ b/lib/crypto/SubtleCryptoProvider.js @@ -21,7 +21,7 @@ class SubtleCryptoProvider extends CryptoProvider { } /** @override */ async computeHMACSignatureAsync(payload, secret) { - const encoder = new TextEncoder('utf-8'); + const encoder = new TextEncoder(); const key = await this.subtleCrypto.importKey( 'raw', encoder.encode(secret), diff --git a/lib/multipart.js b/lib/multipart.js index bb186e00db..1ba40140ce 100644 --- a/lib/multipart.js +++ b/lib/multipart.js @@ -1,6 +1,7 @@ 'use strict'; const utils = require('./utils'); -const {StripeError} = require('./Error'); +const _Error = require('./Error'); +const {StripeError} = _Error; class StreamProcessingError extends StripeError {} // Method for formatting HTTP body for the multipart/form-data specification // Mostly taken from Fermata.js @@ -79,4 +80,6 @@ const multipartRequestDataProcessor = (method, data, headers, callback) => { const buffer = multipartDataGenerator(method, data, headers); return callback(null, buffer); }; -module.exports.multipartRequestDataProcessor = multipartRequestDataProcessor; +module.exports = { + multipartRequestDataProcessor: multipartRequestDataProcessor, +}; diff --git a/lib/net/FetchHttpClient.js b/lib/net/FetchHttpClient.js index e57891b8cd..195b1bb0c6 100644 --- a/lib/net/FetchHttpClient.js +++ b/lib/net/FetchHttpClient.js @@ -1,5 +1,6 @@ 'use strict'; -const {HttpClient, HttpClientResponse} = require('./HttpClient'); +const _HttpClient = require('./HttpClient'); +const {HttpClient, HttpClientResponse} = _HttpClient; /** * HTTP client which uses a `fetch` function to issue requests. * diff --git a/lib/net/NodeHttpClient.js b/lib/net/NodeHttpClient.js index 1f9d12c4d8..c5712dfe2f 100644 --- a/lib/net/NodeHttpClient.js +++ b/lib/net/NodeHttpClient.js @@ -1,7 +1,8 @@ 'use strict'; const http = require('http'); const https = require('https'); -const {HttpClient, HttpClientResponse} = require('./HttpClient'); +const _HttpClient = require('./HttpClient'); +const {HttpClient, HttpClientResponse} = _HttpClient; const defaultHttpAgent = new http.Agent({keepAlive: true}); const defaultHttpsAgent = new https.Agent({keepAlive: true}); /** diff --git a/lib/utils.js b/lib/utils.js index 9efd90fd63..d88ffb9d2e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -31,7 +31,7 @@ const DEPRECATED_OPTIONS = { stripeVersion: 'apiVersion', }; const DEPRECATED_OPTIONS_KEYS = Object.keys(DEPRECATED_OPTIONS); -const utils = (module.exports = { +const utils = { isOptionsHash(o) { return ( o && @@ -342,7 +342,7 @@ const utils = (module.exports = { const value = obj[key]; const newKey = prevKey ? `${prevKey}[${key}]` : key; if (utils.isObject(value)) { - if (!Buffer.isBuffer(value) && !value.hasOwnProperty('data')) { + if (!Buffer.isBuffer(value) && !hasOwn(value, 'data')) { // Non-buffer non-file Objects are recursively flattened return step(value, newKey); } else { @@ -355,7 +355,7 @@ const utils = (module.exports = { } }); }; - step(data); + step(data, null); return result; }, /** @@ -386,7 +386,7 @@ const utils = (module.exports = { platform: process.platform, }; }, -}); +}; function emitWarning(warning) { if (typeof process.emitWarning !== 'function') { return console.warn( @@ -395,3 +395,4 @@ function emitWarning(warning) { } return process.emitWarning(warning, 'Stripe'); } +module.exports = utils; diff --git a/src/Error.ts b/src/Error.ts index c5de62ea0c..3a9cc390aa 100644 --- a/src/Error.ts +++ b/src/Error.ts @@ -18,7 +18,7 @@ type StripeRawError = { doc_url?: string; decline_code?: string; param?: string; - detail?: string; + detail?: any; charge?: string; payment_method_type?: string; @@ -44,7 +44,7 @@ class StripeError extends Error { readonly code?: string; readonly doc_url?: string; readonly param?: string; - readonly detail?: string; + readonly detail?: any; readonly statusCode?: number; readonly charge?: string; readonly decline_code?: string; diff --git a/src/ResourceNamespace.js b/src/ResourceNamespace.ts similarity index 100% rename from src/ResourceNamespace.js rename to src/ResourceNamespace.ts diff --git a/src/Webhooks.js b/src/Webhooks.ts similarity index 96% rename from src/Webhooks.js rename to src/Webhooks.ts index ffbe2004a9..0d3a7683e2 100644 --- a/src/Webhooks.js +++ b/src/Webhooks.ts @@ -1,10 +1,12 @@ 'use strict'; -const utils = require('./utils'); -const {StripeError, StripeSignatureVerificationError} = require('./Error'); +import utils = require('./utils'); +import _Error = require('./Error'); +const {StripeError, StripeSignatureVerificationError} = _Error; const Webhook = { DEFAULT_TOLERANCE: 300, // 5 minutes + signature: null, constructEvent(payload, header, secret, tolerance, cryptoProvider) { this.signature.verifyHeader( @@ -242,7 +244,7 @@ function parseHeader(header, scheme) { const kv = item.split('='); if (kv[0] === 't') { - accum.timestamp = kv[1]; + accum.timestamp = parseInt(kv[1], 10); } if (kv[0] === scheme) { @@ -274,4 +276,4 @@ function getNodeCryptoProvider() { Webhook.signature = signature; -module.exports = Webhook; +export = Webhook; diff --git a/src/crypto/CryptoProvider.js b/src/crypto/CryptoProvider.ts similarity index 88% rename from src/crypto/CryptoProvider.js rename to src/crypto/CryptoProvider.ts index 8f038d06ca..f7be333d61 100644 --- a/src/crypto/CryptoProvider.js +++ b/src/crypto/CryptoProvider.ts @@ -13,7 +13,7 @@ class CryptoProvider { * - computeHMACSignature('', 'test_secret') => 'f7f9bd47fb987337b5796fdc1fdb9ba221d0d5396814bfcaf9521f43fd8927fd' * - computeHMACSignature('\ud83d\ude00', 'test_secret') => '837da296d05c4fe31f61d5d7ead035099d9585a5bcde87de952012a78f0b0c43 */ - computeHMACSignature(payload, secret) { + computeHMACSignature(payload: string, secret: string): string { throw new Error('computeHMACSignature not implemented.'); } @@ -28,9 +28,9 @@ class CryptoProvider { * - computeHMACSignature('', 'test_secret') => 'f7f9bd47fb987337b5796fdc1fdb9ba221d0d5396814bfcaf9521f43fd8927fd' * - computeHMACSignature('\ud83d\ude00', 'test_secret') => '837da296d05c4fe31f61d5d7ead035099d9585a5bcde87de952012a78f0b0c43 */ - computeHMACSignatureAsync(payload, secret) { + computeHMACSignatureAsync(payload: string, secret: string): Promise { throw new Error('computeHMACSignatureAsync not implemented.'); } } -module.exports = CryptoProvider; +export = CryptoProvider; diff --git a/src/crypto/NodeCryptoProvider.js b/src/crypto/NodeCryptoProvider.ts similarity index 58% rename from src/crypto/NodeCryptoProvider.js rename to src/crypto/NodeCryptoProvider.ts index 83c2037ea2..9963825f47 100644 --- a/src/crypto/NodeCryptoProvider.js +++ b/src/crypto/NodeCryptoProvider.ts @@ -1,15 +1,15 @@ 'use strict'; -const crypto = require('crypto'); +import crypto = require('crypto'); -const CryptoProvider = require('./CryptoProvider'); +import CryptoProvider = require('./CryptoProvider'); /** * `CryptoProvider which uses the Node `crypto` package for its computations. */ class NodeCryptoProvider extends CryptoProvider { /** @override */ - computeHMACSignature(payload, secret) { + computeHMACSignature(payload: string, secret: string): string { return crypto .createHmac('sha256', secret) .update(payload, 'utf8') @@ -17,10 +17,13 @@ class NodeCryptoProvider extends CryptoProvider { } /** @override */ - async computeHMACSignatureAsync(payload, secret) { + async computeHMACSignatureAsync( + payload: string, + secret: string + ): Promise { const signature = await this.computeHMACSignature(payload, secret); return signature; } } -module.exports = NodeCryptoProvider; +export = NodeCryptoProvider; diff --git a/src/crypto/SubtleCryptoProvider.js b/src/crypto/SubtleCryptoProvider.ts similarity index 89% rename from src/crypto/SubtleCryptoProvider.js rename to src/crypto/SubtleCryptoProvider.ts index 45aa40dd46..762bbaaf9c 100644 --- a/src/crypto/SubtleCryptoProvider.js +++ b/src/crypto/SubtleCryptoProvider.ts @@ -1,6 +1,6 @@ 'use strict'; -const CryptoProvider = require('./CryptoProvider'); +import CryptoProvider = require('./CryptoProvider'); /** * `CryptoProvider which uses the SubtleCrypto interface of the Web Crypto API. @@ -8,6 +8,8 @@ const CryptoProvider = require('./CryptoProvider'); * This only supports asynchronous operations. */ class SubtleCryptoProvider extends CryptoProvider { + subtleCrypto: any; + constructor(subtleCrypto) { super(); @@ -18,7 +20,7 @@ class SubtleCryptoProvider extends CryptoProvider { } /** @override */ - computeHMACSignature(payload, secret) { + computeHMACSignature(payload: string, secret: string): string { throw new Error( 'SubtleCryptoProvider cannot be used in a synchronous context.' ); @@ -26,7 +28,7 @@ class SubtleCryptoProvider extends CryptoProvider { /** @override */ async computeHMACSignatureAsync(payload, secret) { - const encoder = new TextEncoder('utf-8'); + const encoder = new TextEncoder(); const key = await this.subtleCrypto.importKey( 'raw', @@ -66,4 +68,4 @@ for (let i = 0; i < byteHexMapping.length; i++) { byteHexMapping[i] = i.toString(16).padStart(2, '0'); } -module.exports = SubtleCryptoProvider; +export = SubtleCryptoProvider; diff --git a/src/multipart.js b/src/multipart.ts similarity index 93% rename from src/multipart.js rename to src/multipart.ts index 90682aedda..bc8d7ae9ff 100644 --- a/src/multipart.js +++ b/src/multipart.ts @@ -1,7 +1,8 @@ 'use strict'; -const utils = require('./utils'); -const {StripeError} = require('./Error'); +import utils = require('./utils'); +import _Error = require('./Error'); +const {StripeError} = _Error; class StreamProcessingError extends StripeError {} @@ -93,4 +94,6 @@ const multipartRequestDataProcessor = (method, data, headers, callback) => { return callback(null, buffer); }; -module.exports.multipartRequestDataProcessor = multipartRequestDataProcessor; +export = { + multipartRequestDataProcessor: multipartRequestDataProcessor, +}; diff --git a/src/net/FetchHttpClient.js b/src/net/FetchHttpClient.ts similarity index 95% rename from src/net/FetchHttpClient.js rename to src/net/FetchHttpClient.ts index 431282cd19..3a21ba10f1 100644 --- a/src/net/FetchHttpClient.js +++ b/src/net/FetchHttpClient.ts @@ -1,6 +1,7 @@ 'use strict'; -const {HttpClient, HttpClientResponse} = require('./HttpClient'); +import _HttpClient = require('./HttpClient'); +const {HttpClient, HttpClientResponse} = _HttpClient; /** * HTTP client which uses a `fetch` function to issue requests. @@ -11,6 +12,9 @@ const {HttpClient, HttpClientResponse} = require('./HttpClient'); * node-fetch package (https://github.com/node-fetch/node-fetch). */ class FetchHttpClient extends HttpClient { + _fetchFn: any; + _res: any; + constructor(fetchFn) { super(); this._fetchFn = fetchFn; @@ -88,6 +92,8 @@ class FetchHttpClient extends HttpClient { } class FetchHttpClientResponse extends HttpClientResponse { + _res: any; + constructor(res) { super( res.status, @@ -135,4 +141,4 @@ class FetchHttpClientResponse extends HttpClientResponse { } } -module.exports = {FetchHttpClient, FetchHttpClientResponse}; +export = {FetchHttpClient, FetchHttpClientResponse}; diff --git a/src/net/HttpClient.js b/src/net/HttpClient.ts similarity index 82% rename from src/net/HttpClient.js rename to src/net/HttpClient.ts index b309ce7d9d..3c5baefbc3 100644 --- a/src/net/HttpClient.js +++ b/src/net/HttpClient.ts @@ -1,5 +1,7 @@ 'use strict'; +type TimeoutError = TypeError & {code?: string}; + /** * Encapsulates the logic for issuing a request to the Stripe API. * @@ -10,6 +12,9 @@ * returning their own response class when making requests. */ class HttpClient { + static CONNECTION_CLOSED_ERROR_CODES: string[]; + static TIMEOUT_ERROR_CODE: string; + /** The client name used for diagnostics. */ getClientName() { throw new Error('getClientName not implemented.'); @@ -30,7 +35,9 @@ class HttpClient { /** Helper to make a consistent timeout error across implementations. */ static makeTimeoutError() { - const timeoutErr = new TypeError(HttpClient.TIMEOUT_ERROR_CODE); + const timeoutErr: TimeoutError = new TypeError( + HttpClient.TIMEOUT_ERROR_CODE + ); timeoutErr.code = HttpClient.TIMEOUT_ERROR_CODE; return timeoutErr; } @@ -40,6 +47,9 @@ HttpClient.CONNECTION_CLOSED_ERROR_CODES = ['ECONNRESET', 'EPIPE']; HttpClient.TIMEOUT_ERROR_CODE = 'ETIMEDOUT'; class HttpClientResponse { + _statusCode: number; + _headers: object; + constructor(statusCode, headers) { this._statusCode = statusCode; this._headers = headers; @@ -66,4 +76,4 @@ class HttpClientResponse { } } -module.exports = {HttpClient, HttpClientResponse}; +export = {HttpClient, HttpClientResponse}; diff --git a/src/net/NodeHttpClient.js b/src/net/NodeHttpClient.ts similarity index 93% rename from src/net/NodeHttpClient.js rename to src/net/NodeHttpClient.ts index 222a446ce7..f34358f748 100644 --- a/src/net/NodeHttpClient.js +++ b/src/net/NodeHttpClient.ts @@ -3,7 +3,8 @@ const http = require('http'); const https = require('https'); -const {HttpClient, HttpClientResponse} = require('./HttpClient'); +import _HttpClient = require('./HttpClient'); +const {HttpClient, HttpClientResponse} = _HttpClient; const defaultHttpAgent = new http.Agent({keepAlive: true}); const defaultHttpsAgent = new https.Agent({keepAlive: true}); @@ -13,6 +14,8 @@ const defaultHttpsAgent = new https.Agent({keepAlive: true}); * requests.` */ class NodeHttpClient extends HttpClient { + _agent: any; + constructor(agent) { super(); this._agent = agent; @@ -86,6 +89,8 @@ class NodeHttpClient extends HttpClient { } class NodeHttpClientResponse extends HttpClientResponse { + _res: any; + constructor(res) { super(res.statusCode, res.headers || {}); this._res = res; @@ -122,4 +127,4 @@ class NodeHttpClientResponse extends HttpClientResponse { } } -module.exports = {NodeHttpClient, NodeHttpClientResponse}; +export = {NodeHttpClient, NodeHttpClientResponse}; diff --git a/src/utils.js b/src/utils.ts similarity index 97% rename from src/utils.js rename to src/utils.ts index 7eed41defd..1a75f72732 100644 --- a/src/utils.js +++ b/src/utils.ts @@ -37,7 +37,20 @@ const DEPRECATED_OPTIONS = { }; const DEPRECATED_OPTIONS_KEYS = Object.keys(DEPRECATED_OPTIONS); -const utils = (module.exports = { +type Settings = { + timeout?: number; + maxNetworkRetries?: number; +}; + +type Options = { + auth?: any; + host?: any; + settings?: Settings; + streaming?: boolean; + headers?: {[header: string]: string}; +}; + +const utils = { isOptionsHash(o) { return ( o && @@ -140,7 +153,7 @@ const utils = (module.exports = { * Return the options hash from a list of arguments */ getOptionsFromArgs: (args) => { - const opts = { + const opts: Options = { auth: null, headers: {}, settings: {}, @@ -388,7 +401,7 @@ const utils = (module.exports = { const newKey = prevKey ? `${prevKey}[${key}]` : key; if (utils.isObject(value)) { - if (!Buffer.isBuffer(value) && !value.hasOwnProperty('data')) { + if (!Buffer.isBuffer(value) && !hasOwn(value, 'data')) { // Non-buffer non-file Objects are recursively flattened return step(value, newKey); } else { @@ -402,7 +415,7 @@ const utils = (module.exports = { }); }; - step(data); + step(data, null); return result; }, @@ -438,7 +451,7 @@ const utils = (module.exports = { platform: process.platform, }; }, -}); +}; function emitWarning(warning) { if (typeof process.emitWarning !== 'function') { @@ -449,3 +462,5 @@ function emitWarning(warning) { return process.emitWarning(warning, 'Stripe'); } + +export = utils;