stripe 11.7.0 → 11.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 11.8.0 - 2023-01-26
4
+ * [#1665](https://github.com/stripe/stripe-node/pull/1665) API Updates
5
+ * Add support for new value `BE` on enums `Checkout.Session.payment_method_options.customer_balance.bank_transfer.eu_bank_transfer.country`, `Invoice.payment_settings.payment_method_options.customer_balance.bank_transfer.eu_bank_transfer.country`, `PaymentIntent.payment_method_options.customer_balance.bank_transfer.eu_bank_transfer.country`, and `Subscription.payment_settings.payment_method_options.customer_balance.bank_transfer.eu_bank_transfer.country`
6
+ * Add support for new values `cs-CZ`, `el-GR`, `en-CZ`, and `en-GR` on enums `PaymentIntentConfirmParams.payment_method_options.klarna.preferred_locale`, `PaymentIntentCreateParams.payment_method_options.klarna.preferred_locale`, and `PaymentIntentUpdateParams.payment_method_options.klarna.preferred_locale`
7
+ * [#1660](https://github.com/stripe/stripe-node/pull/1660) Introduce separate entry point for worker environments
8
+
3
9
  ## 11.7.0 - 2023-01-19
4
10
  * [#1661](https://github.com/stripe/stripe-node/pull/1661) API Updates
5
11
  * Add support for `verification_session` on `EphemeralKeyCreateParams`
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.7.0
1
+ 11.8.0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
- const utils = require("./utils");
3
2
  const _Error = require("./Error");
3
+ const utils = require("./utils");
4
4
  const { StripeAPIError, StripeAuthenticationError, StripeConnectionError, StripeError, StripePermissionError, StripeRateLimitError, } = _Error;
5
5
  const { HttpClient } = require('./net/HttpClient');
6
6
  const MAX_RETRY_AFTER_WAIT = 60;
@@ -196,7 +196,7 @@ class RequestSender {
196
196
  // If this is a POST and we allow multiple retries, ensure an idempotency key.
197
197
  const maxRetries = this._getMaxNetworkRetries(settings);
198
198
  if (method === 'POST' && maxRetries > 0) {
199
- return `stripe-node-retry-${utils.uuid4()}`;
199
+ return `stripe-node-retry-${this._stripe._platformFunctions.uuid4()}`;
200
200
  }
201
201
  return null;
202
202
  }
package/lib/Webhooks.js CHANGED
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- const utils = require("./utils");
3
2
  const _Error = require("./Error");
4
3
  const { StripeError, StripeSignatureVerificationError } = _Error;
5
4
  const Webhook = {
@@ -40,7 +39,7 @@ const Webhook = {
40
39
  opts.timestamp =
41
40
  Math.floor(opts.timestamp) || Math.floor(Date.now() / 1000);
42
41
  opts.scheme = opts.scheme || signature.EXPECTED_SCHEME;
43
- opts.cryptoProvider = opts.cryptoProvider || getNodeCryptoProvider();
42
+ opts.cryptoProvider = opts.cryptoProvider || getCryptoProvider();
44
43
  opts.signature =
45
44
  opts.signature ||
46
45
  opts.cryptoProvider.computeHMACSignature(opts.timestamp + '.' + opts.payload, opts.secret);
@@ -50,19 +49,21 @@ const Webhook = {
50
49
  ].join(',');
51
50
  return generatedHeader;
52
51
  },
52
+ _createCryptoProvider: () => null,
53
+ _platformFunctions: null,
53
54
  };
54
55
  const signature = {
55
56
  EXPECTED_SCHEME: 'v1',
56
57
  verifyHeader(encodedPayload, encodedHeader, secret, tolerance, cryptoProvider) {
57
58
  const { decodedHeader: header, decodedPayload: payload, details, } = parseEventDetails(encodedPayload, encodedHeader, this.EXPECTED_SCHEME);
58
- cryptoProvider = cryptoProvider || getNodeCryptoProvider();
59
+ cryptoProvider = cryptoProvider || getCryptoProvider();
59
60
  const expectedSignature = cryptoProvider.computeHMACSignature(makeHMACContent(payload, details), secret);
60
61
  validateComputedSignature(payload, header, details, expectedSignature, tolerance);
61
62
  return true;
62
63
  },
63
64
  async verifyHeaderAsync(encodedPayload, encodedHeader, secret, tolerance, cryptoProvider) {
64
65
  const { decodedHeader: header, decodedPayload: payload, details, } = parseEventDetails(encodedPayload, encodedHeader, this.EXPECTED_SCHEME);
65
- cryptoProvider = cryptoProvider || getNodeCryptoProvider();
66
+ cryptoProvider = cryptoProvider || getCryptoProvider();
66
67
  const expectedSignature = await cryptoProvider.computeHMACSignatureAsync(makeHMACContent(payload, details), secret);
67
68
  return validateComputedSignature(payload, header, details, expectedSignature, tolerance);
68
69
  },
@@ -103,9 +104,7 @@ function parseEventDetails(encodedPayload, encodedHeader, expectedScheme) {
103
104
  };
104
105
  }
105
106
  function validateComputedSignature(payload, header, details, expectedSignature, tolerance) {
106
- const signatureFound = !!details.signatures.filter(
107
- // @ts-ignore
108
- utils.secureCompare.bind(utils, expectedSignature)).length;
107
+ const signatureFound = !!details.signatures.filter(Webhook._platformFunctions.secureCompare.bind(Webhook._platformFunctions, expectedSignature)).length;
109
108
  if (!signatureFound) {
110
109
  // @ts-ignore
111
110
  throw new StripeSignatureVerificationError(header, payload, {
@@ -141,17 +140,16 @@ function parseHeader(header, scheme) {
141
140
  signatures: [],
142
141
  });
143
142
  }
144
- let webhooksNodeCryptoProviderInstance = null;
143
+ let webhooksCryptoProviderInstance = null;
145
144
  /**
146
- * Lazily instantiate a NodeCryptoProvider instance. This is a stateless object
145
+ * Lazily instantiate a CryptoProvider instance. This is a stateless object
147
146
  * so a singleton can be used here.
148
147
  */
149
- function getNodeCryptoProvider() {
150
- if (!webhooksNodeCryptoProviderInstance) {
151
- const NodeCryptoProvider = require('./crypto/NodeCryptoProvider');
152
- webhooksNodeCryptoProviderInstance = new NodeCryptoProvider();
148
+ function getCryptoProvider() {
149
+ if (!webhooksCryptoProviderInstance) {
150
+ webhooksCryptoProviderInstance = Webhook._createCryptoProvider();
153
151
  }
154
- return webhooksNodeCryptoProviderInstance;
152
+ return webhooksCryptoProviderInstance;
155
153
  }
156
154
  Webhook.signature = signature;
157
155
  module.exports = Webhook;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * Interface encapsulating various utility functions whose
4
+ * implementations depend on the platform / JS runtime.
5
+ */
6
+ class DefaultPlatformFunctions {
7
+ /**
8
+ * Gets uname with Node's built-in `exec` function, if available.
9
+ */
10
+ getUname() {
11
+ return Promise.resolve(null);
12
+ }
13
+ /**
14
+ * Generates a v4 UUID. See https://stackoverflow.com/a/2117523
15
+ */
16
+ uuid4() {
17
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
18
+ const r = (Math.random() * 16) | 0;
19
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
20
+ return v.toString(16);
21
+ });
22
+ }
23
+ /**
24
+ * Compares strings in constant time.
25
+ */
26
+ secureCompare(a, b) {
27
+ // return early here if buffer lengths are not equal
28
+ if (a.length !== b.length) {
29
+ return false;
30
+ }
31
+ const len = a.length;
32
+ let result = 0;
33
+ for (let i = 0; i < len; ++i) {
34
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
35
+ }
36
+ return result === 0;
37
+ }
38
+ }
39
+ module.exports = DefaultPlatformFunctions;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ const crypto = require("crypto");
3
+ const DefaultPlatformFunctions = require("./DefaultPlatformFunctions");
4
+ /**
5
+ * Specializes DefaultPlatformFunctions using APIs available in Node.js.
6
+ */
7
+ class NodePlatformFunctions extends DefaultPlatformFunctions {
8
+ constructor() {
9
+ super();
10
+ this._exec = require('child_process').exec;
11
+ this._UNAME_CACHE = null;
12
+ }
13
+ /** @override */
14
+ uuid4() {
15
+ // available in: v14.17.x+
16
+ if (crypto.randomUUID) {
17
+ return crypto.randomUUID();
18
+ }
19
+ return super.uuid4();
20
+ }
21
+ /**
22
+ * @override
23
+ * Node's built in `exec` function sometimes throws outright,
24
+ * and sometimes has a callback with an error,
25
+ * depending on the type of error.
26
+ *
27
+ * This unifies that interface by resolving with a null uname
28
+ * if an error is encountered.
29
+ */
30
+ getUname() {
31
+ if (!this._UNAME_CACHE) {
32
+ this._UNAME_CACHE = new Promise((resolve, reject) => {
33
+ try {
34
+ this._exec('uname -a', (err, uname) => {
35
+ if (err) {
36
+ return resolve(null);
37
+ }
38
+ resolve(uname);
39
+ });
40
+ }
41
+ catch (e) {
42
+ resolve(null);
43
+ }
44
+ });
45
+ }
46
+ return this._UNAME_CACHE;
47
+ }
48
+ /**
49
+ * @override
50
+ * Secure compare, from https://github.com/freewil/scmp
51
+ */
52
+ secureCompare(a, b) {
53
+ if (!a || !b) {
54
+ throw new Error('secureCompare must receive two arguments');
55
+ }
56
+ // return early here if buffer lengths are not equal since timingSafeEqual
57
+ // will throw if buffer lengths are not equal
58
+ if (a.length !== b.length) {
59
+ return false;
60
+ }
61
+ // use crypto.timingSafeEqual if available (since Node.js v6.6.0),
62
+ // otherwise use our own scmp-internal function.
63
+ if (crypto.timingSafeEqual) {
64
+ const textEncoder = new TextEncoder();
65
+ const aEncoded = textEncoder.encode(a);
66
+ const bEncoded = textEncoder.encode(b);
67
+ return crypto.timingSafeEqual(aEncoded, bEncoded);
68
+ }
69
+ return super.secureCompare(a, b);
70
+ }
71
+ }
72
+ module.exports = NodePlatformFunctions;
@@ -0,0 +1,354 @@
1
+ "use strict";
2
+ const _Error = require("./Error");
3
+ const resources = require("./resources");
4
+ const DEFAULT_HOST = 'api.stripe.com';
5
+ const DEFAULT_PORT = '443';
6
+ const DEFAULT_BASE_PATH = '/v1/';
7
+ const DEFAULT_API_VERSION = null;
8
+ const DEFAULT_TIMEOUT = 80000;
9
+ Stripe.PACKAGE_VERSION = require('../package.json').version;
10
+ const utils = require("./utils");
11
+ const { determineProcessUserAgentProperties } = utils;
12
+ Stripe.USER_AGENT = Object.assign({ bindings_version: Stripe.PACKAGE_VERSION, lang: 'node', publisher: 'stripe', uname: null, typescript: false }, determineProcessUserAgentProperties());
13
+ const MAX_NETWORK_RETRY_DELAY_SEC = 2;
14
+ const INITIAL_NETWORK_RETRY_DELAY_SEC = 0.5;
15
+ const APP_INFO_PROPERTIES = ['name', 'version', 'url', 'partner_id'];
16
+ const ALLOWED_CONFIG_PROPERTIES = [
17
+ 'apiVersion',
18
+ 'typescript',
19
+ 'maxNetworkRetries',
20
+ 'httpAgent',
21
+ 'httpClient',
22
+ 'timeout',
23
+ 'host',
24
+ 'port',
25
+ 'protocol',
26
+ 'telemetry',
27
+ 'appInfo',
28
+ 'stripeAccount',
29
+ ];
30
+ const StripeResource = require("./StripeResource");
31
+ const RequestSender = require("./RequestSender");
32
+ Stripe.StripeResource = StripeResource;
33
+ Stripe.resources = resources;
34
+ const HttpClient = require("./net/HttpClient");
35
+ Stripe.HttpClient = HttpClient.HttpClient;
36
+ Stripe.HttpClientResponse = HttpClient.HttpClientResponse;
37
+ const CryptoProvider = require("./crypto/CryptoProvider");
38
+ const EventEmitter = require("events");
39
+ Stripe.CryptoProvider = CryptoProvider;
40
+ const DefaultPlatformFunctions = require("./platform/DefaultPlatformFunctions");
41
+ Stripe._platformFunctions = new DefaultPlatformFunctions();
42
+ function Stripe(key, config = {}) {
43
+ if (!(this instanceof Stripe)) {
44
+ return new Stripe(key, config);
45
+ }
46
+ const props = this._getPropsFromConfig(config);
47
+ Object.defineProperty(this, '_emitter', {
48
+ value: new EventEmitter(),
49
+ enumerable: false,
50
+ configurable: false,
51
+ writable: false,
52
+ });
53
+ this.VERSION = Stripe.PACKAGE_VERSION;
54
+ this.on = this._emitter.on.bind(this._emitter);
55
+ this.once = this._emitter.once.bind(this._emitter);
56
+ this.off = this._emitter.removeListener.bind(this._emitter);
57
+ if (props.protocol &&
58
+ props.protocol !== 'https' &&
59
+ (!props.host || /\.stripe\.com$/.test(props.host))) {
60
+ throw new Error('The `https` protocol must be used when sending requests to `*.stripe.com`');
61
+ }
62
+ const agent = props.httpAgent || null;
63
+ this._api = {
64
+ auth: null,
65
+ host: props.host || DEFAULT_HOST,
66
+ port: props.port || DEFAULT_PORT,
67
+ protocol: props.protocol || 'https',
68
+ basePath: DEFAULT_BASE_PATH,
69
+ version: props.apiVersion || DEFAULT_API_VERSION,
70
+ timeout: utils.validateInteger('timeout', props.timeout, DEFAULT_TIMEOUT),
71
+ maxNetworkRetries: utils.validateInteger('maxNetworkRetries', props.maxNetworkRetries, 0),
72
+ agent: agent,
73
+ httpClient: props.httpClient || Stripe.createHttpClient(agent),
74
+ dev: false,
75
+ stripeAccount: props.stripeAccount || null,
76
+ };
77
+ const typescript = props.typescript || false;
78
+ if (typescript !== Stripe.USER_AGENT.typescript) {
79
+ // The mutation here is uncomfortable, but likely fastest;
80
+ // serializing the user agent involves shelling out to the system,
81
+ // and given some users may instantiate the library many times without switching between TS and non-TS,
82
+ // we only want to incur the performance hit when that actually happens.
83
+ Stripe.USER_AGENT.typescript = typescript;
84
+ }
85
+ if (props.appInfo) {
86
+ this._setAppInfo(props.appInfo);
87
+ }
88
+ this._prepResources();
89
+ this._setApiKey(key);
90
+ this.errors = _Error;
91
+ this.webhooks = require('./Webhooks');
92
+ this.webhooks._platformFunctions = Stripe._platformFunctions;
93
+ this._prevRequestMetrics = [];
94
+ this._enableTelemetry = props.telemetry !== false;
95
+ this._requestSender = new RequestSender(this, Stripe.StripeResource.MAX_BUFFERED_REQUEST_METRICS);
96
+ // Expose StripeResource on the instance too
97
+ // @ts-ignore
98
+ this.StripeResource = Stripe.StripeResource;
99
+ this._platformFunctions = Stripe._platformFunctions;
100
+ }
101
+ Stripe.errors = _Error;
102
+ Stripe.webhooks = require('./Webhooks');
103
+ // @ts-ignore
104
+ Stripe.createHttpClient = null;
105
+ Stripe.createNodeHttpClient = (agent) => {
106
+ throw new Error('Stripe: createNodeHttpClient() is not available in non-Node environments. When instantiating the Stripe client, please set the `httpClient` configuration option to `Stripe.createFetchHttpClient()`, or to your own implementation of `HttpClient`.');
107
+ };
108
+ /**
109
+ * Creates an HTTP client for issuing Stripe API requests which uses the Web
110
+ * Fetch API.
111
+ *
112
+ * A fetch function can optionally be passed in as a parameter. If none is
113
+ * passed, will default to the default `fetch` function in the global scope.
114
+ */
115
+ Stripe.createFetchHttpClient = (fetchFn) => {
116
+ const { FetchHttpClient } = require('./net/FetchHttpClient');
117
+ return new FetchHttpClient(fetchFn);
118
+ };
119
+ /**
120
+ * Create a CryptoProvider which uses the built-in Node crypto libraries for
121
+ * its crypto operations.
122
+ */
123
+ Stripe.createNodeCryptoProvider = () => {
124
+ throw new Error('Stripe: `createNodeCryptoProvider()` is not available in non-Node environments. Please use `createSubtleCryptoProvider()` instead.');
125
+ };
126
+ /**
127
+ * Creates a CryptoProvider which uses the Subtle Crypto API from the Web
128
+ * Crypto API spec for its crypto operations.
129
+ *
130
+ * A SubtleCrypto interface can optionally be passed in as a parameter. If none
131
+ * is passed, will default to the default `crypto.subtle` object in the global
132
+ * scope.
133
+ */
134
+ Stripe.createSubtleCryptoProvider = (subtleCrypto) => {
135
+ const SubtleCryptoProvider = require('./crypto/SubtleCryptoProvider');
136
+ return new SubtleCryptoProvider(subtleCrypto);
137
+ };
138
+ Stripe.prototype = {
139
+ // Properties are set in the constructor above
140
+ _appInfo: undefined,
141
+ on: null,
142
+ off: null,
143
+ once: null,
144
+ VERSION: null,
145
+ StripeResource: null,
146
+ webhooks: null,
147
+ errors: null,
148
+ _api: null,
149
+ _prevRequestMetrics: null,
150
+ _emitter: null,
151
+ _enableTelemetry: null,
152
+ _requestSender: null,
153
+ _platformFunctions: null,
154
+ /**
155
+ * @private
156
+ */
157
+ _setApiKey(key) {
158
+ if (key) {
159
+ this._setApiField('auth', `Bearer ${key}`);
160
+ }
161
+ },
162
+ /**
163
+ * @private
164
+ * This may be removed in the future.
165
+ */
166
+ _setAppInfo(info) {
167
+ if (info && typeof info !== 'object') {
168
+ throw new Error('AppInfo must be an object.');
169
+ }
170
+ if (info && !info.name) {
171
+ throw new Error('AppInfo.name is required');
172
+ }
173
+ info = info || {};
174
+ this._appInfo = APP_INFO_PROPERTIES.reduce((accum, prop) => {
175
+ if (typeof info[prop] == 'string') {
176
+ accum = accum || {};
177
+ accum[prop] = info[prop];
178
+ }
179
+ return accum;
180
+ },
181
+ // @ts-ignore
182
+ undefined);
183
+ },
184
+ /**
185
+ * @private
186
+ * This may be removed in the future.
187
+ */
188
+ _setApiField(key, value) {
189
+ this._api[key] = value;
190
+ },
191
+ /**
192
+ * @private
193
+ * Please open or upvote an issue at github.com/stripe/stripe-node
194
+ * if you use this, detailing your use-case.
195
+ *
196
+ * It may be deprecated and removed in the future.
197
+ */
198
+ getApiField(key) {
199
+ return this._api[key];
200
+ },
201
+ setClientId(clientId) {
202
+ this._clientId = clientId;
203
+ },
204
+ getClientId() {
205
+ return this._clientId;
206
+ },
207
+ /**
208
+ * @private
209
+ * Please open or upvote an issue at github.com/stripe/stripe-node
210
+ * if you use this, detailing your use-case.
211
+ *
212
+ * It may be deprecated and removed in the future.
213
+ */
214
+ getConstant: (c) => {
215
+ switch (c) {
216
+ case 'DEFAULT_HOST':
217
+ return DEFAULT_HOST;
218
+ case 'DEFAULT_PORT':
219
+ return DEFAULT_PORT;
220
+ case 'DEFAULT_BASE_PATH':
221
+ return DEFAULT_BASE_PATH;
222
+ case 'DEFAULT_API_VERSION':
223
+ return DEFAULT_API_VERSION;
224
+ case 'DEFAULT_TIMEOUT':
225
+ return DEFAULT_TIMEOUT;
226
+ case 'MAX_NETWORK_RETRY_DELAY_SEC':
227
+ return MAX_NETWORK_RETRY_DELAY_SEC;
228
+ case 'INITIAL_NETWORK_RETRY_DELAY_SEC':
229
+ return INITIAL_NETWORK_RETRY_DELAY_SEC;
230
+ }
231
+ return Stripe[c];
232
+ },
233
+ getMaxNetworkRetries() {
234
+ return this.getApiField('maxNetworkRetries');
235
+ },
236
+ /**
237
+ * @private
238
+ * This may be removed in the future.
239
+ */
240
+ _setApiNumberField(prop, n, defaultVal) {
241
+ const val = utils.validateInteger(prop, n, defaultVal);
242
+ this._setApiField(prop, val);
243
+ },
244
+ getMaxNetworkRetryDelay() {
245
+ return MAX_NETWORK_RETRY_DELAY_SEC;
246
+ },
247
+ getInitialNetworkRetryDelay() {
248
+ return INITIAL_NETWORK_RETRY_DELAY_SEC;
249
+ },
250
+ /**
251
+ * @private
252
+ * Please open or upvote an issue at github.com/stripe/stripe-node
253
+ * if you use this, detailing your use-case.
254
+ *
255
+ * It may be deprecated and removed in the future.
256
+ *
257
+ * Gets a JSON version of a User-Agent and uses a cached version for a slight
258
+ * speed advantage.
259
+ */
260
+ getClientUserAgent(cb) {
261
+ return this.getClientUserAgentSeeded(Stripe.USER_AGENT, cb);
262
+ },
263
+ /**
264
+ * @private
265
+ * Please open or upvote an issue at github.com/stripe/stripe-node
266
+ * if you use this, detailing your use-case.
267
+ *
268
+ * It may be deprecated and removed in the future.
269
+ *
270
+ * Gets a JSON version of a User-Agent by encoding a seeded object and
271
+ * fetching a uname from the system.
272
+ */
273
+ getClientUserAgentSeeded(seed, cb) {
274
+ this._platformFunctions.getUname().then((uname) => {
275
+ var _a;
276
+ const userAgent = {};
277
+ for (const field in seed) {
278
+ userAgent[field] = encodeURIComponent((_a = seed[field]) !== null && _a !== void 0 ? _a : 'null');
279
+ }
280
+ // URI-encode in case there are unusual characters in the system's uname.
281
+ userAgent.uname = encodeURIComponent(uname || 'UNKNOWN');
282
+ const client = this.getApiField('httpClient');
283
+ if (client) {
284
+ userAgent.httplib = encodeURIComponent(client.getClientName());
285
+ }
286
+ if (this._appInfo) {
287
+ userAgent.application = this._appInfo;
288
+ }
289
+ cb(JSON.stringify(userAgent));
290
+ });
291
+ },
292
+ /**
293
+ * @private
294
+ * Please open or upvote an issue at github.com/stripe/stripe-node
295
+ * if you use this, detailing your use-case.
296
+ *
297
+ * It may be deprecated and removed in the future.
298
+ */
299
+ getAppInfoAsString() {
300
+ if (!this._appInfo) {
301
+ return '';
302
+ }
303
+ let formatted = this._appInfo.name;
304
+ if (this._appInfo.version) {
305
+ formatted += `/${this._appInfo.version}`;
306
+ }
307
+ if (this._appInfo.url) {
308
+ formatted += ` (${this._appInfo.url})`;
309
+ }
310
+ return formatted;
311
+ },
312
+ getTelemetryEnabled() {
313
+ return this._enableTelemetry;
314
+ },
315
+ /**
316
+ * @private
317
+ * This may be removed in the future.
318
+ */
319
+ _prepResources() {
320
+ for (const name in resources) {
321
+ // @ts-ignore
322
+ this[utils.pascalToCamelCase(name)] = new resources[name](this);
323
+ }
324
+ },
325
+ /**
326
+ * @private
327
+ * This may be removed in the future.
328
+ */
329
+ _getPropsFromConfig(config) {
330
+ // If config is null or undefined, just bail early with no props
331
+ if (!config) {
332
+ return {};
333
+ }
334
+ // config can be an object or a string
335
+ const isString = typeof config === 'string';
336
+ const isObject = config === Object(config) && !Array.isArray(config);
337
+ if (!isObject && !isString) {
338
+ throw new Error('Config must either be an object or a string');
339
+ }
340
+ // If config is a string, we assume the old behavior of passing in a string representation of the api version
341
+ if (isString) {
342
+ return {
343
+ apiVersion: config,
344
+ };
345
+ }
346
+ // If config is an object, we assume the new behavior and make sure it doesn't contain any unexpected values
347
+ const values = Object.keys(config).filter((value) => !ALLOWED_CONFIG_PROPERTIES.includes(value));
348
+ if (values.length > 0) {
349
+ throw new Error(`Config object may only contain the following: ${ALLOWED_CONFIG_PROPERTIES.join(', ')}`);
350
+ }
351
+ return config;
352
+ },
353
+ };
354
+ module.exports = Stripe;