Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type information here and there #1612

Merged
merged 16 commits into from Nov 11, 2022
9 changes: 6 additions & 3 deletions lib/multipart.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions lib/stripe.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 52 additions & 29 deletions src/StripeResource.ts
Expand Up @@ -14,6 +14,7 @@ const {HttpClient} = require('./net/HttpClient');

type Settings = {
timeout?: number;
maxNetworkRetries?: number;
};

type Options = {
Expand All @@ -35,7 +36,7 @@ const MAX_RETRY_AFTER_WAIT = 60;
/**
* Encapsulates request logic for a Stripe Resource
*/
function StripeResource(stripe, deprecatedUrlData) {
function StripeResource(stripe, deprecatedUrlData?: never) {
this._stripe = stripe;
if (deprecatedUrlData) {
throw new Error(
Expand Down Expand Up @@ -78,7 +79,10 @@ StripeResource.prototype = {
// be thrown, and they will be passed to the callback/promise.
validateRequest: null,

createFullPath(commandPath, urlData) {
createFullPath(
commandPath: string | ((urlData: Record<string, unknown>) => string),
urlData: Record<string, unknown>
) {
const urlParts = [this.basePath(urlData), this.path(urlData)];

if (typeof commandPath === 'function') {
Expand All @@ -99,7 +103,7 @@ StripeResource.prototype = {
// Creates a relative resource path with symbols left in (unlike
// createFullPath which takes some data to replace them with). For example it
// might produce: /invoices/{id}
createResourcePathWithSymbols(pathWithSymbols) {
createResourcePathWithSymbols(pathWithSymbols: string) {
// If there is no path beyond the resource path, we want to produce just
// /<resource path> rather than /<resource path>/.
if (pathWithSymbols) {
Expand All @@ -109,7 +113,7 @@ StripeResource.prototype = {
}
},

_joinUrlParts(parts) {
_joinUrlParts(parts: Array<string>) {
// Replace any accidentally doubled up slashes. This previously used
// path.join, which would do this as well. Unfortunately we need to do this
// as the functions for creating paths are technically part of the public
Expand All @@ -129,7 +133,10 @@ StripeResource.prototype = {
};
},

_addHeadersDirectlyToObject(obj, headers) {
_addHeadersDirectlyToObject(
obj: Record<string, unknown>,
headers: Record<string, unknown>
) {
// For convenience, make some headers easily accessible on
// lastResponse.

Expand All @@ -140,7 +147,11 @@ StripeResource.prototype = {
obj.idempotencyKey = obj.idempotencyKey || headers['idempotency-key'];
},

_makeResponseEvent(requestEvent, statusCode, headers) {
_makeResponseEvent(
requestEvent,
statusCode: number,
headers: Record<string, unknown>
) {
const requestEndTime = Date.now();
const requestDurationMs = requestEndTime - requestEvent.request_start_time;

Expand All @@ -158,7 +169,7 @@ StripeResource.prototype = {
});
},

_getRequestId(headers) {
_getRequestId(headers: Record<string, unknown>) {
return headers['request-id'];
},

Expand Down Expand Up @@ -301,7 +312,7 @@ StripeResource.prototype = {
},

// For more on when and how to retry API requests, see https://stripe.com/docs/error-handling#safely-retrying-requests-with-idempotency
_shouldRetry(res, numRetries, maxRetries, error) {
_shouldRetry(res, numRetries: number, maxRetries: number, error?) {
if (
error &&
numRetries === 0 &&
Expand Down Expand Up @@ -346,7 +357,7 @@ StripeResource.prototype = {
return false;
},

_getSleepTimeInMS(numRetries, retryAfter = null) {
_getSleepTimeInMS(numRetries: number, retryAfter: number | null = null) {
const initialNetworkRetryDelay = this._stripe.getInitialNetworkRetryDelay();
const maxNetworkRetryDelay = this._stripe.getMaxNetworkRetryDelay();

Expand Down Expand Up @@ -374,14 +385,14 @@ StripeResource.prototype = {
},

// Max retries can be set on a per request basis. Favor those over the global setting
_getMaxNetworkRetries(settings: {maxNetworkRetries?: number} = {}) {
_getMaxNetworkRetries(settings: Settings = {}) {
return settings.maxNetworkRetries &&
Number.isInteger(settings.maxNetworkRetries)
? settings.maxNetworkRetries
: this._stripe.getMaxNetworkRetries();
},

_defaultIdempotencyKey(method, settings) {
_defaultIdempotencyKey(method: string, settings: Settings) {
// If this is a POST and we allow multiple retries, ensure an idempotency key.
const maxRetries = this._getMaxNetworkRetries(settings);

Expand All @@ -392,14 +403,14 @@ StripeResource.prototype = {
},

_makeHeaders(
auth,
contentLength,
apiVersion,
clientUserAgent,
method,
userSuppliedHeaders,
userSuppliedSettings
) {
auth: string,
contentLength: number,
apiVersion: string,
clientUserAgent: string,
method: string,
userSuppliedHeaders: Record<string, unknown>,
userSuppliedSettings: Settings
): Record<string, unknown> {
const defaultHeaders = {
// Use specified auth token or use default from this stripe instance:
Authorization: auth ? `Bearer ${auth}` : this._stripe.getApiField('auth'),
Expand Down Expand Up @@ -451,7 +462,7 @@ StripeResource.prototype = {
);
},

_getUserAgentString() {
_getUserAgentString(): string {
const packageVersion = this._stripe.getConstant('PACKAGE_VERSION');
const appInfo = this._stripe._appInfo
? this._stripe.getAppInfoAsString()
Expand All @@ -460,7 +471,7 @@ StripeResource.prototype = {
return `Stripe/v1 NodeBindings/${packageVersion} ${appInfo}`.trim();
},

_getTelemetryHeader() {
_getTelemetryHeader(): string {
if (
this._stripe.getTelemetryEnabled() &&
this._stripe._prevRequestMetrics.length > 0
Expand All @@ -472,7 +483,7 @@ StripeResource.prototype = {
}
},

_recordRequestMetrics(requestId, requestDurationMs) {
_recordRequestMetrics(requestId, requestDurationMs): void {
if (this._stripe.getTelemetryEnabled() && requestId) {
if (
this._stripe._prevRequestMetrics.length >
Expand All @@ -490,15 +501,23 @@ StripeResource.prototype = {
}
},

_request(method, host, path, data, auth, options: Options = {}, callback) {
_request(
method: string,
host: string,
path: string,
data: unknown,
auth: string,
options: Options = {},
callback
) {
let requestData;

const retryRequest = (
requestFn,
apiVersion,
headers,
requestRetries,
retryAfter
requestFn: typeof makeRequest,
apiVersion: string,
headers: Record<string, unknown>,
requestRetries: number,
retryAfter: number | null
) => {
return setTimeout(
requestFn,
Expand All @@ -509,7 +528,11 @@ StripeResource.prototype = {
);
};

const makeRequest = (apiVersion, headers, numRetries) => {
const makeRequest = (
apiVersion: string,
headers: Record<string, unknown>,
numRetries: number
) => {
// timeout can be set on a per-request basis. Favor that over the global setting
const timeout =
options.settings &&
Expand Down
42 changes: 30 additions & 12 deletions src/makeRequest.ts
@@ -1,6 +1,21 @@
const utils = require('./utils');

function getRequestOpts(self, requestArgs, spec, overrideData) {
type MethodSpec = {
method: string;
urlParams: Array<string>;
path?: string;
fullPath?: string;
encode: (data: Record<string, unknown>) => Record<string, unknown>;
validator: (
data: Record<string, unknown>,
headers: Record<string, string>
) => void;
headers: Record<string, string>;
streaming?: boolean;
host?: string;
};

function getRequestOpts(self, requestArgs, spec: MethodSpec, overrideData) {
// Extract spec values with defaults.
const requestMethod = (spec.method || 'GET').toUpperCase();
const urlParams = spec.urlParams || [];
Expand All @@ -20,17 +35,20 @@ function getRequestOpts(self, requestArgs, spec, overrideData) {
const args = [].slice.call(requestArgs);

// Generate and validate url params.
const urlData = urlParams.reduce((urlData, param) => {
const arg = args.shift();
if (typeof arg !== 'string') {
throw new Error(
`Stripe: Argument "${param}" must be a string, but got: ${arg} (on API request to \`${requestMethod} ${path}\`)`
);
}
const urlData = urlParams.reduce<Record<string, unknown>>(
(urlData, param) => {
const arg = args.shift();
if (typeof arg !== 'string') {
throw new Error(
`Stripe: Argument "${param}" must be a string, but got: ${arg} (on API request to \`${requestMethod} ${path}\`)`
);
}

urlData[param] = arg;
return urlData;
}, {});
urlData[param] = arg;
return urlData;
},
{}
);

// Pull request data and options (headers, auth) from args.
const dataFromArgs = utils.getDataFromArgs(args);
Expand Down Expand Up @@ -84,7 +102,7 @@ function makeRequest(self, requestArgs, spec, overrideData) {
return;
}

function requestCallback(err, response) {
function requestCallback(err: any, response) {
if (err) {
reject(err);
} else {
Expand Down
13 changes: 10 additions & 3 deletions src/multipart.ts
Expand Up @@ -33,14 +33,21 @@ const multipartDataGenerator = (method, data, headers) => {
const v = flattenedData[k];
push(`--${segno}`);
if (Object.prototype.hasOwnProperty.call(v, 'data')) {
// eslint-disable-next-line no-warning-comments
// TODO: I don't think we ever hit this branch
const typedEntry: {
name: string;
data: string;
type: string;
} = v as any;
push(
`Content-Disposition: form-data; name=${q(k)}; filename=${q(
v.name || 'blob'
typedEntry.name || 'blob'
)}`
);
push(`Content-Type: ${v.type || 'application/octet-stream'}`);
push(`Content-Type: ${typedEntry.type || 'application/octet-stream'}`);
push('');
push(v.data);
push(typedEntry.data);
} else {
push(`Content-Disposition: form-data; name=${q(k)}`);
push('');
Expand Down