@dodopayments/express 0.2.2 → 0.2.3

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/dist/index.js CHANGED
@@ -3959,7 +3959,7 @@ const unknownType = ZodUnknown.create;
3959
3959
  ZodNever.create;
3960
3960
  const arrayType = ZodArray.create;
3961
3961
  const objectType = ZodObject.create;
3962
- ZodUnion.create;
3962
+ const unionType = ZodUnion.create;
3963
3963
  const discriminatedUnionType = ZodDiscriminatedUnion.create;
3964
3964
  ZodIntersection.create;
3965
3965
  ZodTuple.create;
@@ -4178,7 +4178,7 @@ const safeJSON = (text) => {
4178
4178
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
4179
4179
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4180
4180
 
4181
- const VERSION = '2.2.0'; // x-release-please-version
4181
+ const VERSION = '2.4.6'; // x-release-please-version
4182
4182
 
4183
4183
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
4184
4184
  /**
@@ -4928,6 +4928,9 @@ class CheckoutSessions extends APIResource {
4928
4928
  create(body, options) {
4929
4929
  return this._client.post('/checkouts', { body, ...options });
4930
4930
  }
4931
+ retrieve(id, options) {
4932
+ return this._client.get(path `/checkouts/${id}`, options);
4933
+ }
4931
4934
  }
4932
4935
 
4933
4936
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
@@ -5606,1421 +5609,325 @@ let Headers$1 = class Headers extends APIResource {
5606
5609
  }
5607
5610
  };
5608
5611
 
5609
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
5610
- let Webhooks$1 = class Webhooks extends APIResource {
5611
- constructor() {
5612
- super(...arguments);
5613
- this.headers = new Headers$1(this._client);
5614
- }
5615
- /**
5616
- * Create a new webhook
5617
- */
5618
- create(body, options) {
5619
- return this._client.post('/webhooks', { body, ...options });
5620
- }
5621
- /**
5622
- * Get a webhook by id
5623
- */
5624
- retrieve(webhookID, options) {
5625
- return this._client.get(path `/webhooks/${webhookID}`, options);
5612
+ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
5613
+
5614
+ var dist = {};
5615
+
5616
+ var timing_safe_equal = {};
5617
+
5618
+ Object.defineProperty(timing_safe_equal, "__esModule", { value: true });
5619
+ timing_safe_equal.timingSafeEqual = void 0;
5620
+ function assert(expr, msg = "") {
5621
+ if (!expr) {
5622
+ throw new Error(msg);
5626
5623
  }
5627
- /**
5628
- * Patch a webhook by id
5629
- */
5630
- update(webhookID, body, options) {
5631
- return this._client.patch(path `/webhooks/${webhookID}`, { body, ...options });
5624
+ }
5625
+ function timingSafeEqual(a, b) {
5626
+ if (a.byteLength !== b.byteLength) {
5627
+ return false;
5632
5628
  }
5633
- /**
5634
- * List all webhooks
5635
- */
5636
- list(query = {}, options) {
5637
- return this._client.getAPIList('/webhooks', (CursorPagePagination), { query, ...options });
5629
+ if (!(a instanceof DataView)) {
5630
+ a = new DataView(ArrayBuffer.isView(a) ? a.buffer : a);
5638
5631
  }
5639
- /**
5640
- * Delete a webhook by id
5641
- */
5642
- delete(webhookID, options) {
5643
- return this._client.delete(path `/webhooks/${webhookID}`, {
5644
- ...options,
5645
- headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
5646
- });
5632
+ if (!(b instanceof DataView)) {
5633
+ b = new DataView(ArrayBuffer.isView(b) ? b.buffer : b);
5647
5634
  }
5648
- /**
5649
- * Get webhook secret by id
5650
- */
5651
- retrieveSecret(webhookID, options) {
5652
- return this._client.get(path `/webhooks/${webhookID}/secret`, options);
5635
+ assert(a instanceof DataView);
5636
+ assert(b instanceof DataView);
5637
+ const length = a.byteLength;
5638
+ let out = 0;
5639
+ let i = -1;
5640
+ while (++i < length) {
5641
+ out |= a.getUint8(i) ^ b.getUint8(i);
5653
5642
  }
5654
- };
5655
- Webhooks$1.Headers = Headers$1;
5643
+ return out === 0;
5644
+ }
5645
+ timing_safe_equal.timingSafeEqual = timingSafeEqual;
5656
5646
 
5657
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
5647
+ var base64$1 = {};
5648
+
5649
+ // Copyright (C) 2016 Dmitry Chestnykh
5650
+ // MIT License. See LICENSE file for details.
5651
+ var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () {
5652
+ var extendStatics = function (d, b) {
5653
+ extendStatics = Object.setPrototypeOf ||
5654
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5655
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
5656
+ return extendStatics(d, b);
5657
+ };
5658
+ return function (d, b) {
5659
+ extendStatics(d, b);
5660
+ function __() { this.constructor = d; }
5661
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
5662
+ };
5663
+ })();
5664
+ Object.defineProperty(base64$1, "__esModule", { value: true });
5658
5665
  /**
5659
- * Read an environment variable.
5660
- *
5661
- * Trims beginning and trailing whitespace.
5662
- *
5663
- * Will return undefined if the environment variable doesn't exist or cannot be accessed.
5666
+ * Package base64 implements Base64 encoding and decoding.
5664
5667
  */
5665
- const readEnv = (env) => {
5666
- if (typeof globalThis.process !== 'undefined') {
5667
- return globalThis.process.env?.[env]?.trim() ?? undefined;
5668
- }
5669
- if (typeof globalThis.Deno !== 'undefined') {
5670
- return globalThis.Deno.env?.get?.(env)?.trim();
5671
- }
5672
- return undefined;
5673
- };
5674
-
5675
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
5676
- var _DodoPayments_instances, _a, _DodoPayments_encoder, _DodoPayments_baseURLOverridden;
5677
- const environments = {
5678
- live_mode: 'https://live.dodopayments.com',
5679
- test_mode: 'https://test.dodopayments.com',
5680
- };
5668
+ // Invalid character used in decoding to indicate
5669
+ // that the character to decode is out of range of
5670
+ // alphabet and cannot be decoded.
5671
+ var INVALID_BYTE = 256;
5681
5672
  /**
5682
- * API Client for interfacing with the Dodo Payments API.
5673
+ * Implements standard Base64 encoding.
5674
+ *
5675
+ * Operates in constant time.
5683
5676
  */
5684
- class DodoPayments {
5685
- /**
5686
- * API Client for interfacing with the Dodo Payments API.
5687
- *
5688
- * @param {string | undefined} [opts.bearerToken=process.env['DODO_PAYMENTS_API_KEY'] ?? undefined]
5689
- * @param {Environment} [opts.environment=live_mode] - Specifies the environment URL to use for the API.
5690
- * @param {string} [opts.baseURL=process.env['DODO_PAYMENTS_BASE_URL'] ?? https://live.dodopayments.com] - Override the default base URL for the API.
5691
- * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
5692
- * @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls.
5693
- * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
5694
- * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
5695
- * @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API.
5696
- * @param {Record<string, string | undefined>} opts.defaultQuery - Default query parameters to include with every request to the API.
5697
- */
5698
- constructor({ baseURL = readEnv('DODO_PAYMENTS_BASE_URL'), bearerToken = readEnv('DODO_PAYMENTS_API_KEY'), ...opts } = {}) {
5699
- _DodoPayments_instances.add(this);
5700
- _DodoPayments_encoder.set(this, void 0);
5701
- this.checkoutSessions = new CheckoutSessions(this);
5702
- this.payments = new Payments(this);
5703
- this.subscriptions = new Subscriptions(this);
5704
- this.invoices = new Invoices(this);
5705
- this.licenses = new Licenses(this);
5706
- this.licenseKeys = new LicenseKeys(this);
5707
- this.licenseKeyInstances = new LicenseKeyInstances(this);
5708
- this.customers = new Customers(this);
5709
- this.refunds = new Refunds(this);
5710
- this.disputes = new Disputes(this);
5711
- this.payouts = new Payouts(this);
5712
- this.webhookEvents = new WebhookEvents(this);
5713
- this.products = new Products(this);
5714
- this.misc = new Misc(this);
5715
- this.discounts = new Discounts(this);
5716
- this.addons = new Addons(this);
5717
- this.brands = new Brands(this);
5718
- this.webhooks = new Webhooks$1(this);
5719
- this.usageEvents = new UsageEvents(this);
5720
- this.meters = new Meters(this);
5721
- if (bearerToken === undefined) {
5722
- throw new DodoPaymentsError("The DODO_PAYMENTS_API_KEY environment variable is missing or empty; either provide it, or instantiate the DodoPayments client with an bearerToken option, like new DodoPayments({ bearerToken: 'My Bearer Token' }).");
5677
+ var Coder = /** @class */ (function () {
5678
+ // TODO(dchest): methods to encode chunk-by-chunk.
5679
+ function Coder(_paddingCharacter) {
5680
+ if (_paddingCharacter === void 0) { _paddingCharacter = "="; }
5681
+ this._paddingCharacter = _paddingCharacter;
5682
+ }
5683
+ Coder.prototype.encodedLength = function (length) {
5684
+ if (!this._paddingCharacter) {
5685
+ return (length * 8 + 5) / 6 | 0;
5723
5686
  }
5724
- const options = {
5725
- bearerToken,
5726
- ...opts,
5727
- baseURL,
5728
- environment: opts.environment ?? 'live_mode',
5729
- };
5730
- if (baseURL && opts.environment) {
5731
- throw new DodoPaymentsError('Ambiguous URL; The `baseURL` option (or DODO_PAYMENTS_BASE_URL env var) and the `environment` option are given. If you want to use the environment you must pass baseURL: null');
5687
+ return (length + 2) / 3 * 4 | 0;
5688
+ };
5689
+ Coder.prototype.encode = function (data) {
5690
+ var out = "";
5691
+ var i = 0;
5692
+ for (; i < data.length - 2; i += 3) {
5693
+ var c = (data[i] << 16) | (data[i + 1] << 8) | (data[i + 2]);
5694
+ out += this._encodeByte((c >>> 3 * 6) & 63);
5695
+ out += this._encodeByte((c >>> 2 * 6) & 63);
5696
+ out += this._encodeByte((c >>> 1 * 6) & 63);
5697
+ out += this._encodeByte((c >>> 0 * 6) & 63);
5732
5698
  }
5733
- this.baseURL = options.baseURL || environments[options.environment || 'live_mode'];
5734
- this.timeout = options.timeout ?? _a.DEFAULT_TIMEOUT /* 1 minute */;
5735
- this.logger = options.logger ?? console;
5736
- const defaultLogLevel = 'warn';
5737
- // Set default logLevel early so that we can log a warning in parseLogLevel.
5738
- this.logLevel = defaultLogLevel;
5739
- this.logLevel =
5740
- parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ??
5741
- parseLogLevel(readEnv('DODO_PAYMENTS_LOG'), "process.env['DODO_PAYMENTS_LOG']", this) ??
5742
- defaultLogLevel;
5743
- this.fetchOptions = options.fetchOptions;
5744
- this.maxRetries = options.maxRetries ?? 2;
5745
- this.fetch = options.fetch ?? getDefaultFetch();
5746
- __classPrivateFieldSet(this, _DodoPayments_encoder, FallbackEncoder);
5747
- this._options = options;
5748
- this.bearerToken = bearerToken;
5749
- }
5750
- /**
5751
- * Create a new client instance re-using the same options given to the current client with optional overriding.
5752
- */
5753
- withOptions(options) {
5754
- const client = new this.constructor({
5755
- ...this._options,
5756
- environment: options.environment ? options.environment : undefined,
5757
- baseURL: options.environment ? undefined : this.baseURL,
5758
- maxRetries: this.maxRetries,
5759
- timeout: this.timeout,
5760
- logger: this.logger,
5761
- logLevel: this.logLevel,
5762
- fetch: this.fetch,
5763
- fetchOptions: this.fetchOptions,
5764
- bearerToken: this.bearerToken,
5765
- ...options,
5766
- });
5767
- return client;
5768
- }
5769
- defaultQuery() {
5770
- return this._options.defaultQuery;
5771
- }
5772
- validateHeaders({ values, nulls }) {
5773
- return;
5774
- }
5775
- async authHeaders(opts) {
5776
- return buildHeaders([{ Authorization: `Bearer ${this.bearerToken}` }]);
5777
- }
5778
- /**
5779
- * Basic re-implementation of `qs.stringify` for primitive types.
5780
- */
5781
- stringifyQuery(query) {
5782
- return Object.entries(query)
5783
- .filter(([_, value]) => typeof value !== 'undefined')
5784
- .map(([key, value]) => {
5785
- if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
5786
- return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
5699
+ var left = data.length - i;
5700
+ if (left > 0) {
5701
+ var c = (data[i] << 16) | (left === 2 ? data[i + 1] << 8 : 0);
5702
+ out += this._encodeByte((c >>> 3 * 6) & 63);
5703
+ out += this._encodeByte((c >>> 2 * 6) & 63);
5704
+ if (left === 2) {
5705
+ out += this._encodeByte((c >>> 1 * 6) & 63);
5787
5706
  }
5788
- if (value === null) {
5789
- return `${encodeURIComponent(key)}=`;
5707
+ else {
5708
+ out += this._paddingCharacter || "";
5790
5709
  }
5791
- throw new DodoPaymentsError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);
5792
- })
5793
- .join('&');
5794
- }
5795
- getUserAgent() {
5796
- return `${this.constructor.name}/JS ${VERSION}`;
5797
- }
5798
- defaultIdempotencyKey() {
5799
- return `stainless-node-retry-${uuid4()}`;
5800
- }
5801
- makeStatusError(status, error, message, headers) {
5802
- return APIError.generate(status, error, message, headers);
5803
- }
5804
- buildURL(path, query, defaultBaseURL) {
5805
- const baseURL = (!__classPrivateFieldGet(this, _DodoPayments_instances, "m", _DodoPayments_baseURLOverridden).call(this) && defaultBaseURL) || this.baseURL;
5806
- const url = isAbsoluteURL(path) ?
5807
- new URL(path)
5808
- : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
5809
- const defaultQuery = this.defaultQuery();
5810
- if (!isEmptyObj(defaultQuery)) {
5811
- query = { ...defaultQuery, ...query };
5812
- }
5813
- if (typeof query === 'object' && query && !Array.isArray(query)) {
5814
- url.search = this.stringifyQuery(query);
5710
+ out += this._paddingCharacter || "";
5815
5711
  }
5816
- return url.toString();
5817
- }
5818
- /**
5819
- * Used as a callback for mutating the given `FinalRequestOptions` object.
5820
- */
5821
- async prepareOptions(options) { }
5822
- /**
5823
- * Used as a callback for mutating the given `RequestInit` object.
5824
- *
5825
- * This is useful for cases where you want to add certain headers based off of
5826
- * the request properties, e.g. `method` or `url`.
5827
- */
5828
- async prepareRequest(request, { url, options }) { }
5829
- get(path, opts) {
5830
- return this.methodRequest('get', path, opts);
5831
- }
5832
- post(path, opts) {
5833
- return this.methodRequest('post', path, opts);
5834
- }
5835
- patch(path, opts) {
5836
- return this.methodRequest('patch', path, opts);
5837
- }
5838
- put(path, opts) {
5839
- return this.methodRequest('put', path, opts);
5840
- }
5841
- delete(path, opts) {
5842
- return this.methodRequest('delete', path, opts);
5843
- }
5844
- methodRequest(method, path, opts) {
5845
- return this.request(Promise.resolve(opts).then((opts) => {
5846
- return { method, path, ...opts };
5847
- }));
5848
- }
5849
- request(options, remainingRetries = null) {
5850
- return new APIPromise(this, this.makeRequest(options, remainingRetries, undefined));
5851
- }
5852
- async makeRequest(optionsInput, retriesRemaining, retryOfRequestLogID) {
5853
- const options = await optionsInput;
5854
- const maxRetries = options.maxRetries ?? this.maxRetries;
5855
- if (retriesRemaining == null) {
5856
- retriesRemaining = maxRetries;
5712
+ return out;
5713
+ };
5714
+ Coder.prototype.maxDecodedLength = function (length) {
5715
+ if (!this._paddingCharacter) {
5716
+ return (length * 6 + 7) / 8 | 0;
5857
5717
  }
5858
- await this.prepareOptions(options);
5859
- const { req, url, timeout } = await this.buildRequest(options, {
5860
- retryCount: maxRetries - retriesRemaining,
5861
- });
5862
- await this.prepareRequest(req, { url, options });
5863
- /** Not an API request ID, just for correlating local log entries. */
5864
- const requestLogID = 'log_' + ((Math.random() * (1 << 24)) | 0).toString(16).padStart(6, '0');
5865
- const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`;
5866
- const startTime = Date.now();
5867
- loggerFor(this).debug(`[${requestLogID}] sending request`, formatRequestDetails({
5868
- retryOfRequestLogID,
5869
- method: options.method,
5870
- url,
5871
- options,
5872
- headers: req.headers,
5873
- }));
5874
- if (options.signal?.aborted) {
5875
- throw new APIUserAbortError();
5718
+ return length / 4 * 3 | 0;
5719
+ };
5720
+ Coder.prototype.decodedLength = function (s) {
5721
+ return this.maxDecodedLength(s.length - this._getPaddingLength(s));
5722
+ };
5723
+ Coder.prototype.decode = function (s) {
5724
+ if (s.length === 0) {
5725
+ return new Uint8Array(0);
5876
5726
  }
5877
- const controller = new AbortController();
5878
- const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);
5879
- const headersTime = Date.now();
5880
- if (response instanceof globalThis.Error) {
5881
- const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
5882
- if (options.signal?.aborted) {
5883
- throw new APIUserAbortError();
5884
- }
5885
- // detect native connection timeout errors
5886
- // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)"
5887
- // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)"
5888
- // others do not provide enough information to distinguish timeouts from other connection errors
5889
- const isTimeout = isAbortError(response) ||
5890
- /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : ''));
5891
- if (retriesRemaining) {
5892
- loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`);
5893
- loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, formatRequestDetails({
5894
- retryOfRequestLogID,
5895
- url,
5896
- durationMs: headersTime - startTime,
5897
- message: response.message,
5898
- }));
5899
- return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID);
5900
- }
5901
- loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`);
5902
- loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, formatRequestDetails({
5903
- retryOfRequestLogID,
5904
- url,
5905
- durationMs: headersTime - startTime,
5906
- message: response.message,
5907
- }));
5908
- if (isTimeout) {
5909
- throw new APIConnectionTimeoutError();
5910
- }
5911
- throw new APIConnectionError({ cause: response });
5727
+ var paddingLength = this._getPaddingLength(s);
5728
+ var length = s.length - paddingLength;
5729
+ var out = new Uint8Array(this.maxDecodedLength(length));
5730
+ var op = 0;
5731
+ var i = 0;
5732
+ var haveBad = 0;
5733
+ var v0 = 0, v1 = 0, v2 = 0, v3 = 0;
5734
+ for (; i < length - 4; i += 4) {
5735
+ v0 = this._decodeChar(s.charCodeAt(i + 0));
5736
+ v1 = this._decodeChar(s.charCodeAt(i + 1));
5737
+ v2 = this._decodeChar(s.charCodeAt(i + 2));
5738
+ v3 = this._decodeChar(s.charCodeAt(i + 3));
5739
+ out[op++] = (v0 << 2) | (v1 >>> 4);
5740
+ out[op++] = (v1 << 4) | (v2 >>> 2);
5741
+ out[op++] = (v2 << 6) | v3;
5742
+ haveBad |= v0 & INVALID_BYTE;
5743
+ haveBad |= v1 & INVALID_BYTE;
5744
+ haveBad |= v2 & INVALID_BYTE;
5745
+ haveBad |= v3 & INVALID_BYTE;
5912
5746
  }
5913
- const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${response.ok ? 'succeeded' : 'failed'} with status ${response.status} in ${headersTime - startTime}ms`;
5914
- if (!response.ok) {
5915
- const shouldRetry = await this.shouldRetry(response);
5916
- if (retriesRemaining && shouldRetry) {
5917
- const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
5918
- // We don't need the body of this response.
5919
- await CancelReadableStream(response.body);
5920
- loggerFor(this).info(`${responseInfo} - ${retryMessage}`);
5921
- loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({
5922
- retryOfRequestLogID,
5923
- url: response.url,
5924
- status: response.status,
5925
- headers: response.headers,
5926
- durationMs: headersTime - startTime,
5927
- }));
5928
- return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID, response.headers);
5929
- }
5930
- const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`;
5931
- loggerFor(this).info(`${responseInfo} - ${retryMessage}`);
5932
- const errText = await response.text().catch((err) => castToError(err).message);
5933
- const errJSON = safeJSON(errText);
5934
- const errMessage = errJSON ? undefined : errText;
5935
- loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({
5936
- retryOfRequestLogID,
5937
- url: response.url,
5938
- status: response.status,
5939
- headers: response.headers,
5940
- message: errMessage,
5941
- durationMs: Date.now() - startTime,
5942
- }));
5943
- const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers);
5944
- throw err;
5747
+ if (i < length - 1) {
5748
+ v0 = this._decodeChar(s.charCodeAt(i));
5749
+ v1 = this._decodeChar(s.charCodeAt(i + 1));
5750
+ out[op++] = (v0 << 2) | (v1 >>> 4);
5751
+ haveBad |= v0 & INVALID_BYTE;
5752
+ haveBad |= v1 & INVALID_BYTE;
5945
5753
  }
5946
- loggerFor(this).info(responseInfo);
5947
- loggerFor(this).debug(`[${requestLogID}] response start`, formatRequestDetails({
5948
- retryOfRequestLogID,
5949
- url: response.url,
5950
- status: response.status,
5951
- headers: response.headers,
5952
- durationMs: headersTime - startTime,
5953
- }));
5954
- return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
5955
- }
5956
- getAPIList(path, Page, opts) {
5957
- return this.requestAPIList(Page, { method: 'get', path, ...opts });
5958
- }
5959
- requestAPIList(Page, options) {
5960
- const request = this.makeRequest(options, null, undefined);
5961
- return new PagePromise(this, request, Page);
5962
- }
5963
- async fetchWithTimeout(url, init, ms, controller) {
5964
- const { signal, method, ...options } = init || {};
5965
- if (signal)
5966
- signal.addEventListener('abort', () => controller.abort());
5967
- const timeout = setTimeout(() => controller.abort(), ms);
5968
- const isReadableBody = (globalThis.ReadableStream && options.body instanceof globalThis.ReadableStream) ||
5969
- (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body);
5970
- const fetchOptions = {
5971
- signal: controller.signal,
5972
- ...(isReadableBody ? { duplex: 'half' } : {}),
5973
- method: 'GET',
5974
- ...options,
5975
- };
5976
- if (method) {
5977
- // Custom methods like 'patch' need to be uppercased
5978
- // See https://github.com/nodejs/undici/issues/2294
5979
- fetchOptions.method = method.toUpperCase();
5754
+ if (i < length - 2) {
5755
+ v2 = this._decodeChar(s.charCodeAt(i + 2));
5756
+ out[op++] = (v1 << 4) | (v2 >>> 2);
5757
+ haveBad |= v2 & INVALID_BYTE;
5980
5758
  }
5981
- try {
5982
- // use undefined this binding; fetch errors if bound to something else in browser/cloudflare
5983
- return await this.fetch.call(undefined, url, fetchOptions);
5759
+ if (i < length - 3) {
5760
+ v3 = this._decodeChar(s.charCodeAt(i + 3));
5761
+ out[op++] = (v2 << 6) | v3;
5762
+ haveBad |= v3 & INVALID_BYTE;
5984
5763
  }
5985
- finally {
5986
- clearTimeout(timeout);
5764
+ if (haveBad !== 0) {
5765
+ throw new Error("Base64Coder: incorrect characters for decoding");
5987
5766
  }
5988
- }
5989
- async shouldRetry(response) {
5990
- // Note this is not a standard header.
5991
- const shouldRetryHeader = response.headers.get('x-should-retry');
5992
- // If the server explicitly says whether or not to retry, obey.
5993
- if (shouldRetryHeader === 'true')
5994
- return true;
5995
- if (shouldRetryHeader === 'false')
5996
- return false;
5997
- // Retry on request timeouts.
5998
- if (response.status === 408)
5999
- return true;
6000
- // Retry on lock timeouts.
6001
- if (response.status === 409)
6002
- return true;
6003
- // Retry on rate limits.
6004
- if (response.status === 429)
6005
- return true;
6006
- // Retry internal errors.
6007
- if (response.status >= 500)
6008
- return true;
6009
- return false;
6010
- }
6011
- async retryRequest(options, retriesRemaining, requestLogID, responseHeaders) {
6012
- let timeoutMillis;
6013
- // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
6014
- const retryAfterMillisHeader = responseHeaders?.get('retry-after-ms');
6015
- if (retryAfterMillisHeader) {
6016
- const timeoutMs = parseFloat(retryAfterMillisHeader);
6017
- if (!Number.isNaN(timeoutMs)) {
6018
- timeoutMillis = timeoutMs;
6019
- }
6020
- }
6021
- // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
6022
- const retryAfterHeader = responseHeaders?.get('retry-after');
6023
- if (retryAfterHeader && !timeoutMillis) {
6024
- const timeoutSeconds = parseFloat(retryAfterHeader);
6025
- if (!Number.isNaN(timeoutSeconds)) {
6026
- timeoutMillis = timeoutSeconds * 1000;
5767
+ return out;
5768
+ };
5769
+ // Standard encoding have the following encoded/decoded ranges,
5770
+ // which we need to convert between.
5771
+ //
5772
+ // ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 + /
5773
+ // Index: 0 - 25 26 - 51 52 - 61 62 63
5774
+ // ASCII: 65 - 90 97 - 122 48 - 57 43 47
5775
+ //
5776
+ // Encode 6 bits in b into a new character.
5777
+ Coder.prototype._encodeByte = function (b) {
5778
+ // Encoding uses constant time operations as follows:
5779
+ //
5780
+ // 1. Define comparison of A with B using (A - B) >>> 8:
5781
+ // if A > B, then result is positive integer
5782
+ // if A <= B, then result is 0
5783
+ //
5784
+ // 2. Define selection of C or 0 using bitwise AND: X & C:
5785
+ // if X == 0, then result is 0
5786
+ // if X != 0, then result is C
5787
+ //
5788
+ // 3. Start with the smallest comparison (b >= 0), which is always
5789
+ // true, so set the result to the starting ASCII value (65).
5790
+ //
5791
+ // 4. Continue comparing b to higher ASCII values, and selecting
5792
+ // zero if comparison isn't true, otherwise selecting a value
5793
+ // to add to result, which:
5794
+ //
5795
+ // a) undoes the previous addition
5796
+ // b) provides new value to add
5797
+ //
5798
+ var result = b;
5799
+ // b >= 0
5800
+ result += 65;
5801
+ // b > 25
5802
+ result += ((25 - b) >>> 8) & ((0 - 65) - 26 + 97);
5803
+ // b > 51
5804
+ result += ((51 - b) >>> 8) & ((26 - 97) - 52 + 48);
5805
+ // b > 61
5806
+ result += ((61 - b) >>> 8) & ((52 - 48) - 62 + 43);
5807
+ // b > 62
5808
+ result += ((62 - b) >>> 8) & ((62 - 43) - 63 + 47);
5809
+ return String.fromCharCode(result);
5810
+ };
5811
+ // Decode a character code into a byte.
5812
+ // Must return 256 if character is out of alphabet range.
5813
+ Coder.prototype._decodeChar = function (c) {
5814
+ // Decoding works similar to encoding: using the same comparison
5815
+ // function, but now it works on ranges: result is always incremented
5816
+ // by value, but this value becomes zero if the range is not
5817
+ // satisfied.
5818
+ //
5819
+ // Decoding starts with invalid value, 256, which is then
5820
+ // subtracted when the range is satisfied. If none of the ranges
5821
+ // apply, the function returns 256, which is then checked by
5822
+ // the caller to throw error.
5823
+ var result = INVALID_BYTE; // start with invalid character
5824
+ // c == 43 (c > 42 and c < 44)
5825
+ result += (((42 - c) & (c - 44)) >>> 8) & (-INVALID_BYTE + c - 43 + 62);
5826
+ // c == 47 (c > 46 and c < 48)
5827
+ result += (((46 - c) & (c - 48)) >>> 8) & (-INVALID_BYTE + c - 47 + 63);
5828
+ // c > 47 and c < 58
5829
+ result += (((47 - c) & (c - 58)) >>> 8) & (-INVALID_BYTE + c - 48 + 52);
5830
+ // c > 64 and c < 91
5831
+ result += (((64 - c) & (c - 91)) >>> 8) & (-INVALID_BYTE + c - 65 + 0);
5832
+ // c > 96 and c < 123
5833
+ result += (((96 - c) & (c - 123)) >>> 8) & (-INVALID_BYTE + c - 97 + 26);
5834
+ return result;
5835
+ };
5836
+ Coder.prototype._getPaddingLength = function (s) {
5837
+ var paddingLength = 0;
5838
+ if (this._paddingCharacter) {
5839
+ for (var i = s.length - 1; i >= 0; i--) {
5840
+ if (s[i] !== this._paddingCharacter) {
5841
+ break;
5842
+ }
5843
+ paddingLength++;
6027
5844
  }
6028
- else {
6029
- timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
5845
+ if (s.length < 4 || paddingLength > 2) {
5846
+ throw new Error("Base64Coder: incorrect padding");
6030
5847
  }
6031
5848
  }
6032
- // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
6033
- // just do what it says, but otherwise calculate a default
6034
- if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
6035
- const maxRetries = options.maxRetries ?? this.maxRetries;
6036
- timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
6037
- }
6038
- await sleep(timeoutMillis);
6039
- return this.makeRequest(options, retriesRemaining - 1, requestLogID);
6040
- }
6041
- calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
6042
- const initialRetryDelay = 0.5;
6043
- const maxRetryDelay = 8.0;
6044
- const numRetries = maxRetries - retriesRemaining;
6045
- // Apply exponential backoff, but not more than the max.
6046
- const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
6047
- // Apply some jitter, take up to at most 25 percent of the retry time.
6048
- const jitter = 1 - Math.random() * 0.25;
6049
- return sleepSeconds * jitter * 1000;
6050
- }
6051
- async buildRequest(inputOptions, { retryCount = 0 } = {}) {
6052
- const options = { ...inputOptions };
6053
- const { method, path, query, defaultBaseURL } = options;
6054
- const url = this.buildURL(path, query, defaultBaseURL);
6055
- if ('timeout' in options)
6056
- validatePositiveInteger('timeout', options.timeout);
6057
- options.timeout = options.timeout ?? this.timeout;
6058
- const { bodyHeaders, body } = this.buildBody({ options });
6059
- const reqHeaders = await this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount });
6060
- const req = {
6061
- method,
6062
- headers: reqHeaders,
6063
- ...(options.signal && { signal: options.signal }),
6064
- ...(globalThis.ReadableStream &&
6065
- body instanceof globalThis.ReadableStream && { duplex: 'half' }),
6066
- ...(body && { body }),
6067
- ...(this.fetchOptions ?? {}),
6068
- ...(options.fetchOptions ?? {}),
6069
- };
6070
- return { req, url, timeout: options.timeout };
6071
- }
6072
- async buildHeaders({ options, method, bodyHeaders, retryCount, }) {
6073
- let idempotencyHeaders = {};
6074
- if (this.idempotencyHeader && method !== 'get') {
6075
- if (!options.idempotencyKey)
6076
- options.idempotencyKey = this.defaultIdempotencyKey();
6077
- idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey;
6078
- }
6079
- const headers = buildHeaders([
6080
- idempotencyHeaders,
6081
- {
6082
- Accept: 'application/json',
6083
- 'User-Agent': this.getUserAgent(),
6084
- 'X-Stainless-Retry-Count': String(retryCount),
6085
- ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}),
6086
- ...getPlatformHeaders(),
6087
- },
6088
- await this.authHeaders(options),
6089
- this._options.defaultHeaders,
6090
- bodyHeaders,
6091
- options.headers,
6092
- ]);
6093
- this.validateHeaders(headers);
6094
- return headers.values;
6095
- }
6096
- buildBody({ options: { body, headers: rawHeaders } }) {
6097
- if (!body) {
6098
- return { bodyHeaders: undefined, body: undefined };
6099
- }
6100
- const headers = buildHeaders([rawHeaders]);
6101
- if (
6102
- // Pass raw type verbatim
6103
- ArrayBuffer.isView(body) ||
6104
- body instanceof ArrayBuffer ||
6105
- body instanceof DataView ||
6106
- (typeof body === 'string' &&
6107
- // Preserve legacy string encoding behavior for now
6108
- headers.values.has('content-type')) ||
6109
- // `Blob` is superset of `File`
6110
- (globalThis.Blob && body instanceof globalThis.Blob) ||
6111
- // `FormData` -> `multipart/form-data`
6112
- body instanceof FormData ||
6113
- // `URLSearchParams` -> `application/x-www-form-urlencoded`
6114
- body instanceof URLSearchParams ||
6115
- // Send chunked stream (each chunk has own `length`)
6116
- (globalThis.ReadableStream && body instanceof globalThis.ReadableStream)) {
6117
- return { bodyHeaders: undefined, body: body };
6118
- }
6119
- else if (typeof body === 'object' &&
6120
- (Symbol.asyncIterator in body ||
6121
- (Symbol.iterator in body && 'next' in body && typeof body.next === 'function'))) {
6122
- return { bodyHeaders: undefined, body: ReadableStreamFrom(body) };
6123
- }
6124
- else {
6125
- return __classPrivateFieldGet(this, _DodoPayments_encoder, "f").call(this, { body, headers });
6126
- }
6127
- }
5849
+ return paddingLength;
5850
+ };
5851
+ return Coder;
5852
+ }());
5853
+ base64$1.Coder = Coder;
5854
+ var stdCoder = new Coder();
5855
+ function encode(data) {
5856
+ return stdCoder.encode(data);
6128
5857
  }
6129
- _a = DodoPayments, _DodoPayments_encoder = new WeakMap(), _DodoPayments_instances = new WeakSet(), _DodoPayments_baseURLOverridden = function _DodoPayments_baseURLOverridden() {
6130
- return this.baseURL !== environments[this._options.environment || 'live_mode'];
6131
- };
6132
- DodoPayments.DodoPayments = _a;
6133
- DodoPayments.DEFAULT_TIMEOUT = 60000; // 1 minute
6134
- DodoPayments.DodoPaymentsError = DodoPaymentsError;
6135
- DodoPayments.APIError = APIError;
6136
- DodoPayments.APIConnectionError = APIConnectionError;
6137
- DodoPayments.APIConnectionTimeoutError = APIConnectionTimeoutError;
6138
- DodoPayments.APIUserAbortError = APIUserAbortError;
6139
- DodoPayments.NotFoundError = NotFoundError;
6140
- DodoPayments.ConflictError = ConflictError;
6141
- DodoPayments.RateLimitError = RateLimitError;
6142
- DodoPayments.BadRequestError = BadRequestError;
6143
- DodoPayments.AuthenticationError = AuthenticationError;
6144
- DodoPayments.InternalServerError = InternalServerError;
6145
- DodoPayments.PermissionDeniedError = PermissionDeniedError;
6146
- DodoPayments.UnprocessableEntityError = UnprocessableEntityError;
6147
- DodoPayments.toFile = toFile;
6148
- DodoPayments.CheckoutSessions = CheckoutSessions;
6149
- DodoPayments.Payments = Payments;
6150
- DodoPayments.Subscriptions = Subscriptions;
6151
- DodoPayments.Invoices = Invoices;
6152
- DodoPayments.Licenses = Licenses;
6153
- DodoPayments.LicenseKeys = LicenseKeys;
6154
- DodoPayments.LicenseKeyInstances = LicenseKeyInstances;
6155
- DodoPayments.Customers = Customers;
6156
- DodoPayments.Refunds = Refunds;
6157
- DodoPayments.Disputes = Disputes;
6158
- DodoPayments.Payouts = Payouts;
6159
- DodoPayments.WebhookEvents = WebhookEvents;
6160
- DodoPayments.Products = Products;
6161
- DodoPayments.Misc = Misc;
6162
- DodoPayments.Discounts = Discounts;
6163
- DodoPayments.Addons = Addons;
6164
- DodoPayments.Brands = Brands;
6165
- DodoPayments.Webhooks = Webhooks$1;
6166
- DodoPayments.UsageEvents = UsageEvents;
6167
- DodoPayments.Meters = Meters;
6168
-
6169
- // src/checkout/checkout.ts
6170
- var checkoutQuerySchema = objectType({
6171
- productId: stringType(),
6172
- quantity: stringType().optional(),
6173
- // Customer fields
6174
- fullName: stringType().optional(),
6175
- firstName: stringType().optional(),
6176
- lastName: stringType().optional(),
6177
- email: stringType().optional(),
6178
- country: stringType().optional(),
6179
- addressLine: stringType().optional(),
6180
- city: stringType().optional(),
6181
- state: stringType().optional(),
6182
- zipCode: stringType().optional(),
6183
- // Disable flags
6184
- disableFullName: stringType().optional(),
6185
- disableFirstName: stringType().optional(),
6186
- disableLastName: stringType().optional(),
6187
- disableEmail: stringType().optional(),
6188
- disableCountry: stringType().optional(),
6189
- disableAddressLine: stringType().optional(),
6190
- disableCity: stringType().optional(),
6191
- disableState: stringType().optional(),
6192
- disableZipCode: stringType().optional(),
6193
- // Advanced controls
6194
- paymentCurrency: stringType().optional(),
6195
- showCurrencySelector: stringType().optional(),
6196
- paymentAmount: stringType().optional(),
6197
- showDiscounts: stringType().optional()
6198
- // Metadata (allow any key starting with metadata_)
6199
- // We'll handle metadata separately in the handler
6200
- }).catchall(unknownType());
6201
- var dynamicCheckoutBodySchema = objectType({
6202
- // For subscription
6203
- product_id: stringType().optional(),
6204
- quantity: numberType().optional(),
6205
- // For one-time payment
6206
- product_cart: arrayType(
6207
- objectType({
6208
- product_id: stringType(),
6209
- quantity: numberType()
6210
- })
6211
- ).optional(),
6212
- // Common fields
6213
- billing: objectType({
6214
- city: stringType(),
6215
- country: stringType(),
6216
- state: stringType(),
6217
- street: stringType(),
6218
- zipcode: stringType()
6219
- }),
6220
- customer: objectType({
6221
- customer_id: stringType().optional(),
6222
- email: stringType().optional(),
6223
- name: stringType().optional()
6224
- }),
6225
- discount_id: stringType().optional(),
6226
- addons: arrayType(
6227
- objectType({
6228
- addon_id: stringType(),
6229
- quantity: numberType()
6230
- })
6231
- ).optional(),
6232
- metadata: recordType(stringType(), stringType()).optional(),
6233
- currency: stringType().optional()
6234
- // Allow any additional fields (for future compatibility)
6235
- }).catchall(unknownType());
6236
- var checkoutSessionProductCartItemSchema = objectType({
6237
- product_id: stringType().min(1, "Product ID is required"),
6238
- quantity: numberType().int().positive("Quantity must be a positive integer")
6239
- });
6240
- var checkoutSessionCustomerSchema = objectType({
6241
- email: stringType().email().optional(),
6242
- name: stringType().min(1).optional(),
6243
- phone_number: stringType().optional()
6244
- }).optional();
6245
- var checkoutSessionBillingAddressSchema = objectType({
6246
- street: stringType().optional(),
6247
- city: stringType().optional(),
6248
- state: stringType().optional(),
6249
- country: stringType().length(2, "Country must be a 2-letter ISO code"),
6250
- zipcode: stringType().optional()
6251
- }).optional();
6252
- var paymentMethodTypeSchema = enumType([
6253
- "credit",
6254
- "debit",
6255
- "upi_collect",
6256
- "upi_intent",
6257
- "apple_pay",
6258
- "google_pay",
6259
- "amazon_pay",
6260
- "klarna",
6261
- "affirm",
6262
- "afterpay_clearpay",
6263
- "sepa",
6264
- "ach"
6265
- ]);
6266
- var checkoutSessionCustomizationSchema = objectType({
6267
- theme: enumType(["light", "dark", "system"]).optional(),
6268
- show_order_details: booleanType().optional(),
6269
- show_on_demand_tag: booleanType().optional()
6270
- }).optional();
6271
- var checkoutSessionFeatureFlagsSchema = objectType({
6272
- allow_currency_selection: booleanType().optional(),
6273
- allow_discount_code: booleanType().optional(),
6274
- allow_phone_number_collection: booleanType().optional(),
6275
- allow_tax_id: booleanType().optional(),
6276
- always_create_new_customer: booleanType().optional()
6277
- }).optional();
6278
- var checkoutSessionSubscriptionDataSchema = objectType({
6279
- trial_period_days: numberType().int().nonnegative().optional()
6280
- }).optional();
6281
- var checkoutSessionPayloadSchema = objectType({
6282
- // Required fields
6283
- product_cart: arrayType(checkoutSessionProductCartItemSchema).min(1, "At least one product is required"),
6284
- // Optional fields
6285
- customer: checkoutSessionCustomerSchema,
6286
- billing_address: checkoutSessionBillingAddressSchema,
6287
- return_url: stringType().url().optional(),
6288
- allowed_payment_method_types: arrayType(paymentMethodTypeSchema).optional(),
6289
- billing_currency: stringType().length(3, "Currency must be a 3-letter ISO code").optional(),
6290
- show_saved_payment_methods: booleanType().optional(),
6291
- confirm: booleanType().optional(),
6292
- discount_code: stringType().optional(),
6293
- metadata: recordType(stringType(), stringType()).optional(),
6294
- customization: checkoutSessionCustomizationSchema,
6295
- feature_flags: checkoutSessionFeatureFlagsSchema,
6296
- subscription_data: checkoutSessionSubscriptionDataSchema
6297
- });
6298
- var checkoutSessionResponseSchema = objectType({
6299
- session_id: stringType().min(1, "Session ID is required"),
6300
- checkout_url: stringType().url("Invalid checkout URL")
6301
- });
6302
- var createCheckoutSession = async (payload, config) => {
6303
- const validation = checkoutSessionPayloadSchema.safeParse(payload);
6304
- if (!validation.success) {
6305
- throw new Error(
6306
- `Invalid checkout session payload: ${validation.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ")}`
6307
- );
6308
- }
6309
- const dodopayments = new DodoPayments({
6310
- bearerToken: config.bearerToken,
6311
- environment: config.environment
6312
- });
6313
- try {
6314
- const sdkPayload = {
6315
- ...validation.data,
6316
- ...validation.data.billing_address && {
6317
- billing_address: {
6318
- ...validation.data.billing_address,
6319
- country: validation.data.billing_address.country
6320
- }
6321
- }
6322
- };
6323
- const session = await dodopayments.checkoutSessions.create(
6324
- sdkPayload
6325
- );
6326
- const responseValidation = checkoutSessionResponseSchema.safeParse(session);
6327
- if (!responseValidation.success) {
6328
- throw new Error(
6329
- `Invalid checkout session response from API: ${responseValidation.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ")}`
6330
- );
6331
- }
6332
- return responseValidation.data;
6333
- } catch (error) {
6334
- if (error instanceof Error) {
6335
- console.error("Dodo Payments Checkout Session API Error:", {
6336
- message: error.message,
6337
- payload: validation.data,
6338
- config: {
6339
- environment: config.environment,
6340
- hasBearerToken: !!config.bearerToken
6341
- }
6342
- });
6343
- throw new Error(`Failed to create checkout session: ${error.message}`);
5858
+ base64$1.encode = encode;
5859
+ function decode(s) {
5860
+ return stdCoder.decode(s);
5861
+ }
5862
+ base64$1.decode = decode;
5863
+ /**
5864
+ * Implements URL-safe Base64 encoding.
5865
+ * (Same as Base64, but '+' is replaced with '-', and '/' with '_').
5866
+ *
5867
+ * Operates in constant time.
5868
+ */
5869
+ var URLSafeCoder = /** @class */ (function (_super) {
5870
+ __extends(URLSafeCoder, _super);
5871
+ function URLSafeCoder() {
5872
+ return _super !== null && _super.apply(this, arguments) || this;
6344
5873
  }
6345
- console.error("Unknown error creating checkout session:", error);
6346
- throw new Error(
6347
- "Failed to create checkout session due to an unknown error"
6348
- );
6349
- }
5874
+ // URL-safe encoding have the following encoded/decoded ranges:
5875
+ //
5876
+ // ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 - _
5877
+ // Index: 0 - 25 26 - 51 52 - 61 62 63
5878
+ // ASCII: 65 - 90 97 - 122 48 - 57 45 95
5879
+ //
5880
+ URLSafeCoder.prototype._encodeByte = function (b) {
5881
+ var result = b;
5882
+ // b >= 0
5883
+ result += 65;
5884
+ // b > 25
5885
+ result += ((25 - b) >>> 8) & ((0 - 65) - 26 + 97);
5886
+ // b > 51
5887
+ result += ((51 - b) >>> 8) & ((26 - 97) - 52 + 48);
5888
+ // b > 61
5889
+ result += ((61 - b) >>> 8) & ((52 - 48) - 62 + 45);
5890
+ // b > 62
5891
+ result += ((62 - b) >>> 8) & ((62 - 45) - 63 + 95);
5892
+ return String.fromCharCode(result);
5893
+ };
5894
+ URLSafeCoder.prototype._decodeChar = function (c) {
5895
+ var result = INVALID_BYTE;
5896
+ // c == 45 (c > 44 and c < 46)
5897
+ result += (((44 - c) & (c - 46)) >>> 8) & (-INVALID_BYTE + c - 45 + 62);
5898
+ // c == 95 (c > 94 and c < 96)
5899
+ result += (((94 - c) & (c - 96)) >>> 8) & (-INVALID_BYTE + c - 95 + 63);
5900
+ // c > 47 and c < 58
5901
+ result += (((47 - c) & (c - 58)) >>> 8) & (-INVALID_BYTE + c - 48 + 52);
5902
+ // c > 64 and c < 91
5903
+ result += (((64 - c) & (c - 91)) >>> 8) & (-INVALID_BYTE + c - 65 + 0);
5904
+ // c > 96 and c < 123
5905
+ result += (((96 - c) & (c - 123)) >>> 8) & (-INVALID_BYTE + c - 97 + 26);
5906
+ return result;
5907
+ };
5908
+ return URLSafeCoder;
5909
+ }(Coder));
5910
+ base64$1.URLSafeCoder = URLSafeCoder;
5911
+ var urlSafeCoder = new URLSafeCoder();
5912
+ function encodeURLSafe(data) {
5913
+ return urlSafeCoder.encode(data);
5914
+ }
5915
+ base64$1.encodeURLSafe = encodeURLSafe;
5916
+ function decodeURLSafe(s) {
5917
+ return urlSafeCoder.decode(s);
5918
+ }
5919
+ base64$1.decodeURLSafe = decodeURLSafe;
5920
+ base64$1.encodedLength = function (length) {
5921
+ return stdCoder.encodedLength(length);
6350
5922
  };
6351
- var buildCheckoutUrl = async ({
6352
- queryParams,
6353
- body,
6354
- sessionPayload,
6355
- returnUrl,
6356
- bearerToken,
6357
- environment,
6358
- type = "static"
6359
- }) => {
6360
- if (type === "session") {
6361
- if (!sessionPayload) {
6362
- throw new Error("sessionPayload is required when type is 'session'");
6363
- }
6364
- const session = await createCheckoutSession(sessionPayload, {
6365
- bearerToken,
6366
- environment
6367
- });
6368
- return session.checkout_url;
6369
- }
6370
- const inputData = type === "dynamic" ? body : queryParams;
6371
- let parseResult;
6372
- if (type === "dynamic") {
6373
- parseResult = dynamicCheckoutBodySchema.safeParse(inputData);
6374
- } else {
6375
- parseResult = checkoutQuerySchema.safeParse(inputData);
6376
- }
6377
- const { success, data, error } = parseResult;
6378
- if (!success) {
6379
- throw new Error(
6380
- `Invalid ${type === "dynamic" ? "body" : "query parameters"}.
6381
- ${error.message}`
6382
- );
6383
- }
6384
- if (type !== "dynamic") {
6385
- const {
6386
- productId,
6387
- quantity: quantity2,
6388
- fullName,
6389
- firstName,
6390
- lastName,
6391
- email,
6392
- country,
6393
- addressLine,
6394
- city,
6395
- state,
6396
- zipCode,
6397
- disableFullName,
6398
- disableFirstName,
6399
- disableLastName,
6400
- disableEmail,
6401
- disableCountry,
6402
- disableAddressLine,
6403
- disableCity,
6404
- disableState,
6405
- disableZipCode,
6406
- paymentCurrency,
6407
- showCurrencySelector,
6408
- paymentAmount,
6409
- showDiscounts
6410
- // metadata handled below
6411
- } = data;
6412
- const dodopayments2 = new DodoPayments({
6413
- bearerToken,
6414
- environment
6415
- });
6416
- if (!productId) throw new Error("Missing required field: productId");
6417
- try {
6418
- await dodopayments2.products.retrieve(productId);
6419
- } catch (err) {
6420
- console.error(err);
6421
- throw new Error("Product not found");
6422
- }
6423
- const url = new URL(
6424
- `${environment === "test_mode" ? "https://test.checkout.dodopayments.com" : "https://checkout.dodopayments.com"}/buy/${productId}`
6425
- );
6426
- url.searchParams.set("quantity", quantity2 ? String(quantity2) : "1");
6427
- if (returnUrl) url.searchParams.set("redirect_url", returnUrl);
6428
- if (fullName) url.searchParams.set("fullName", String(fullName));
6429
- if (firstName) url.searchParams.set("firstName", String(firstName));
6430
- if (lastName) url.searchParams.set("lastName", String(lastName));
6431
- if (email) url.searchParams.set("email", String(email));
6432
- if (country) url.searchParams.set("country", String(country));
6433
- if (addressLine) url.searchParams.set("addressLine", String(addressLine));
6434
- if (city) url.searchParams.set("city", String(city));
6435
- if (state) url.searchParams.set("state", String(state));
6436
- if (zipCode) url.searchParams.set("zipCode", String(zipCode));
6437
- if (disableFullName === "true")
6438
- url.searchParams.set("disableFullName", "true");
6439
- if (disableFirstName === "true")
6440
- url.searchParams.set("disableFirstName", "true");
6441
- if (disableLastName === "true")
6442
- url.searchParams.set("disableLastName", "true");
6443
- if (disableEmail === "true") url.searchParams.set("disableEmail", "true");
6444
- if (disableCountry === "true")
6445
- url.searchParams.set("disableCountry", "true");
6446
- if (disableAddressLine === "true")
6447
- url.searchParams.set("disableAddressLine", "true");
6448
- if (disableCity === "true") url.searchParams.set("disableCity", "true");
6449
- if (disableState === "true") url.searchParams.set("disableState", "true");
6450
- if (disableZipCode === "true")
6451
- url.searchParams.set("disableZipCode", "true");
6452
- if (paymentCurrency)
6453
- url.searchParams.set("paymentCurrency", String(paymentCurrency));
6454
- if (showCurrencySelector)
6455
- url.searchParams.set(
6456
- "showCurrencySelector",
6457
- String(showCurrencySelector)
6458
- );
6459
- if (paymentAmount)
6460
- url.searchParams.set("paymentAmount", String(paymentAmount));
6461
- if (showDiscounts)
6462
- url.searchParams.set("showDiscounts", String(showDiscounts));
6463
- for (const [key, value] of Object.entries(queryParams || {})) {
6464
- if (key.startsWith("metadata_") && value && typeof value !== "object") {
6465
- url.searchParams.set(key, String(value));
6466
- }
6467
- }
6468
- return url.toString();
6469
- }
6470
- const dyn = data;
6471
- const {
6472
- product_id,
6473
- product_cart,
6474
- quantity,
6475
- billing,
6476
- customer,
6477
- addons,
6478
- metadata,
6479
- allowed_payment_method_types,
6480
- billing_currency,
6481
- discount_code,
6482
- on_demand,
6483
- return_url: bodyReturnUrl,
6484
- show_saved_payment_methods,
6485
- tax_id,
6486
- trial_period_days
6487
- } = dyn;
6488
- const dodopayments = new DodoPayments({
6489
- bearerToken,
6490
- environment
6491
- });
6492
- let isSubscription = false;
6493
- let productIdToFetch = product_id;
6494
- if (!product_id && product_cart && product_cart.length > 0) {
6495
- productIdToFetch = product_cart[0].product_id;
6496
- }
6497
- if (!productIdToFetch)
6498
- throw new Error(
6499
- "Missing required field: product_id or product_cart[0].product_id"
6500
- );
6501
- let product;
6502
- try {
6503
- product = await dodopayments.products.retrieve(productIdToFetch);
6504
- } catch (err) {
6505
- console.error(err);
6506
- throw new Error("Product not found");
6507
- }
6508
- isSubscription = Boolean(product.is_recurring);
6509
- if (isSubscription && !product_id)
6510
- throw new Error("Missing required field: product_id for subscription");
6511
- if (!billing) throw new Error("Missing required field: billing");
6512
- if (!customer) throw new Error("Missing required field: customer");
6513
- if (isSubscription) {
6514
- const subscriptionPayload = {
6515
- billing,
6516
- customer,
6517
- product_id,
6518
- quantity: quantity ? Number(quantity) : 1
6519
- };
6520
- if (metadata) subscriptionPayload.metadata = metadata;
6521
- if (discount_code) subscriptionPayload.discount_code = discount_code;
6522
- if (addons) subscriptionPayload.addons = addons;
6523
- if (allowed_payment_method_types)
6524
- subscriptionPayload.allowed_payment_method_types = allowed_payment_method_types;
6525
- if (billing_currency)
6526
- subscriptionPayload.billing_currency = billing_currency;
6527
- if (on_demand) subscriptionPayload.on_demand = on_demand;
6528
- subscriptionPayload.payment_link = true;
6529
- if (bodyReturnUrl) {
6530
- subscriptionPayload.return_url = bodyReturnUrl;
6531
- } else if (returnUrl) {
6532
- subscriptionPayload.return_url = returnUrl;
6533
- }
6534
- if (show_saved_payment_methods)
6535
- subscriptionPayload.show_saved_payment_methods = show_saved_payment_methods;
6536
- if (tax_id) subscriptionPayload.tax_id = tax_id;
6537
- if (trial_period_days)
6538
- subscriptionPayload.trial_period_days = trial_period_days;
6539
- let subscription;
6540
- try {
6541
- subscription = await dodopayments.subscriptions.create(subscriptionPayload);
6542
- } catch (err) {
6543
- console.error("Error when creating subscription", err);
6544
- throw new Error(err instanceof Error ? err.message : String(err));
6545
- }
6546
- if (!subscription || !subscription.payment_link) {
6547
- throw new Error(
6548
- "No payment link returned from Dodo Payments API (subscription). Make sure to set payment_link as true in payload"
6549
- );
6550
- }
6551
- return subscription.payment_link;
6552
- } else {
6553
- let cart = product_cart;
6554
- if (!cart && product_id) {
6555
- cart = [
6556
- { product_id, quantity: quantity ? Number(quantity) : 1 }
6557
- ];
6558
- }
6559
- if (!cart || cart.length === 0)
6560
- throw new Error("Missing required field: product_cart or product_id");
6561
- const paymentPayload = {
6562
- billing,
6563
- customer,
6564
- product_cart: cart
6565
- };
6566
- if (metadata) paymentPayload.metadata = metadata;
6567
- paymentPayload.payment_link = true;
6568
- if (allowed_payment_method_types)
6569
- paymentPayload.allowed_payment_method_types = allowed_payment_method_types;
6570
- if (billing_currency) paymentPayload.billing_currency = billing_currency;
6571
- if (discount_code) paymentPayload.discount_code = discount_code;
6572
- if (bodyReturnUrl) {
6573
- paymentPayload.return_url = bodyReturnUrl;
6574
- } else if (returnUrl) {
6575
- paymentPayload.return_url = returnUrl;
6576
- }
6577
- if (show_saved_payment_methods)
6578
- paymentPayload.show_saved_payment_methods = show_saved_payment_methods;
6579
- if (tax_id) paymentPayload.tax_id = tax_id;
6580
- let payment;
6581
- try {
6582
- payment = await dodopayments.payments.create(paymentPayload);
6583
- } catch (err) {
6584
- console.error("Error when creating payment link", err);
6585
- throw new Error(err instanceof Error ? err.message : String(err));
6586
- }
6587
- if (!payment || !payment.payment_link) {
6588
- throw new Error(
6589
- "No payment link returned from Dodo Payments API. Make sure to set payment_link as true in payload."
6590
- );
6591
- }
6592
- return payment.payment_link;
6593
- }
5923
+ base64$1.maxDecodedLength = function (length) {
5924
+ return stdCoder.maxDecodedLength(length);
5925
+ };
5926
+ base64$1.decodedLength = function (s) {
5927
+ return stdCoder.decodedLength(s);
6594
5928
  };
6595
5929
 
6596
- function checkoutHandler(config) {
6597
- const getHandler = async (req, res) => {
6598
- const queryParams = req.query;
6599
- if (!queryParams.productId) {
6600
- return res.status(400).send("Please provide productId query parameter");
6601
- }
6602
- const { success, data, error } = checkoutQuerySchema.safeParse(queryParams);
6603
- if (!success) {
6604
- if (error.errors.some((e) => e.path.toString() === "productId")) {
6605
- return res.status(400).send("Please provide productId query parameter");
6606
- }
6607
- return res
6608
- .status(400)
6609
- .send(`Invalid query parameters.\n ${error.message}`);
6610
- }
6611
- let url = "";
6612
- try {
6613
- url = await buildCheckoutUrl({ queryParams: data, ...config });
6614
- }
6615
- catch (error) {
6616
- return res.status(400).send(error.message);
6617
- }
6618
- return res.json({ checkout_url: url });
6619
- };
6620
- const postHandler = async (req, res) => {
6621
- if (config.type === "dynamic") {
6622
- // Handle dynamic checkout
6623
- const { success, data, error } = dynamicCheckoutBodySchema.safeParse(req.body);
6624
- if (!success) {
6625
- return res.status(400).send(`Invalid request body.\n ${error.message}`);
6626
- }
6627
- let url = "";
6628
- try {
6629
- url = await buildCheckoutUrl({
6630
- body: data,
6631
- ...config,
6632
- type: "dynamic",
6633
- });
6634
- }
6635
- catch (error) {
6636
- return res.status(400).send(error.message);
6637
- }
6638
- return res.json({ checkout_url: url });
6639
- }
6640
- else {
6641
- // Handle checkout session
6642
- const { success, data, error } = checkoutSessionPayloadSchema.safeParse(req.body);
6643
- if (!success) {
6644
- return res
6645
- .status(400)
6646
- .send(`Invalid checkout session payload.\n ${error.message}`);
6647
- }
6648
- let url = "";
6649
- try {
6650
- url = await buildCheckoutUrl({
6651
- sessionPayload: data,
6652
- ...config,
6653
- type: "session",
6654
- });
6655
- }
6656
- catch (error) {
6657
- return res.status(400).send(error.message);
6658
- }
6659
- return res.json({ checkout_url: url });
6660
- }
6661
- };
6662
- return (req, res) => {
6663
- if (req.method === "POST") {
6664
- return postHandler(req, res);
6665
- }
6666
- if (req.method === "GET") {
6667
- return getHandler(req, res);
6668
- }
6669
- return res.status(405).send("Method Not Allowed");
6670
- };
6671
- }
6672
-
6673
- const CustomerPortal = ({ bearerToken, environment, }) => {
6674
- const getHandler = async (req, res) => {
6675
- // Extract customerId from query parameters
6676
- const { customer_id: customerId, send_email } = req.query;
6677
- const params = {
6678
- send_email: false,
6679
- };
6680
- const sendEmail = Boolean(send_email);
6681
- if (sendEmail) {
6682
- params.send_email = sendEmail;
6683
- }
6684
- if (!customerId) {
6685
- return res.status(400).send("Missing customerId in query parameters");
6686
- }
6687
- const dodopayments = new DodoPayments({
6688
- bearerToken,
6689
- environment,
6690
- });
6691
- try {
6692
- const session = await dodopayments.customers.customerPortal.create(customerId, params);
6693
- return res.redirect(session.link);
6694
- }
6695
- catch (error) {
6696
- console.error("Error creating customer portal session:", error);
6697
- return res
6698
- .status(500)
6699
- .send(`Failed to create customer portal session: ${error.message}`);
6700
- }
6701
- };
6702
- return getHandler;
6703
- };
6704
-
6705
- var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
6706
-
6707
- var dist = {};
6708
-
6709
- var timing_safe_equal = {};
6710
-
6711
- Object.defineProperty(timing_safe_equal, "__esModule", { value: true });
6712
- timing_safe_equal.timingSafeEqual = void 0;
6713
- function assert(expr, msg = "") {
6714
- if (!expr) {
6715
- throw new Error(msg);
6716
- }
6717
- }
6718
- function timingSafeEqual(a, b) {
6719
- if (a.byteLength !== b.byteLength) {
6720
- return false;
6721
- }
6722
- if (!(a instanceof DataView)) {
6723
- a = new DataView(ArrayBuffer.isView(a) ? a.buffer : a);
6724
- }
6725
- if (!(b instanceof DataView)) {
6726
- b = new DataView(ArrayBuffer.isView(b) ? b.buffer : b);
6727
- }
6728
- assert(a instanceof DataView);
6729
- assert(b instanceof DataView);
6730
- const length = a.byteLength;
6731
- let out = 0;
6732
- let i = -1;
6733
- while (++i < length) {
6734
- out |= a.getUint8(i) ^ b.getUint8(i);
6735
- }
6736
- return out === 0;
6737
- }
6738
- timing_safe_equal.timingSafeEqual = timingSafeEqual;
6739
-
6740
- var base64$1 = {};
6741
-
6742
- // Copyright (C) 2016 Dmitry Chestnykh
6743
- // MIT License. See LICENSE file for details.
6744
- var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () {
6745
- var extendStatics = function (d, b) {
6746
- extendStatics = Object.setPrototypeOf ||
6747
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6748
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6749
- return extendStatics(d, b);
6750
- };
6751
- return function (d, b) {
6752
- extendStatics(d, b);
6753
- function __() { this.constructor = d; }
6754
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
6755
- };
6756
- })();
6757
- Object.defineProperty(base64$1, "__esModule", { value: true });
6758
- /**
6759
- * Package base64 implements Base64 encoding and decoding.
6760
- */
6761
- // Invalid character used in decoding to indicate
6762
- // that the character to decode is out of range of
6763
- // alphabet and cannot be decoded.
6764
- var INVALID_BYTE = 256;
6765
- /**
6766
- * Implements standard Base64 encoding.
6767
- *
6768
- * Operates in constant time.
6769
- */
6770
- var Coder = /** @class */ (function () {
6771
- // TODO(dchest): methods to encode chunk-by-chunk.
6772
- function Coder(_paddingCharacter) {
6773
- if (_paddingCharacter === void 0) { _paddingCharacter = "="; }
6774
- this._paddingCharacter = _paddingCharacter;
6775
- }
6776
- Coder.prototype.encodedLength = function (length) {
6777
- if (!this._paddingCharacter) {
6778
- return (length * 8 + 5) / 6 | 0;
6779
- }
6780
- return (length + 2) / 3 * 4 | 0;
6781
- };
6782
- Coder.prototype.encode = function (data) {
6783
- var out = "";
6784
- var i = 0;
6785
- for (; i < data.length - 2; i += 3) {
6786
- var c = (data[i] << 16) | (data[i + 1] << 8) | (data[i + 2]);
6787
- out += this._encodeByte((c >>> 3 * 6) & 63);
6788
- out += this._encodeByte((c >>> 2 * 6) & 63);
6789
- out += this._encodeByte((c >>> 1 * 6) & 63);
6790
- out += this._encodeByte((c >>> 0 * 6) & 63);
6791
- }
6792
- var left = data.length - i;
6793
- if (left > 0) {
6794
- var c = (data[i] << 16) | (left === 2 ? data[i + 1] << 8 : 0);
6795
- out += this._encodeByte((c >>> 3 * 6) & 63);
6796
- out += this._encodeByte((c >>> 2 * 6) & 63);
6797
- if (left === 2) {
6798
- out += this._encodeByte((c >>> 1 * 6) & 63);
6799
- }
6800
- else {
6801
- out += this._paddingCharacter || "";
6802
- }
6803
- out += this._paddingCharacter || "";
6804
- }
6805
- return out;
6806
- };
6807
- Coder.prototype.maxDecodedLength = function (length) {
6808
- if (!this._paddingCharacter) {
6809
- return (length * 6 + 7) / 8 | 0;
6810
- }
6811
- return length / 4 * 3 | 0;
6812
- };
6813
- Coder.prototype.decodedLength = function (s) {
6814
- return this.maxDecodedLength(s.length - this._getPaddingLength(s));
6815
- };
6816
- Coder.prototype.decode = function (s) {
6817
- if (s.length === 0) {
6818
- return new Uint8Array(0);
6819
- }
6820
- var paddingLength = this._getPaddingLength(s);
6821
- var length = s.length - paddingLength;
6822
- var out = new Uint8Array(this.maxDecodedLength(length));
6823
- var op = 0;
6824
- var i = 0;
6825
- var haveBad = 0;
6826
- var v0 = 0, v1 = 0, v2 = 0, v3 = 0;
6827
- for (; i < length - 4; i += 4) {
6828
- v0 = this._decodeChar(s.charCodeAt(i + 0));
6829
- v1 = this._decodeChar(s.charCodeAt(i + 1));
6830
- v2 = this._decodeChar(s.charCodeAt(i + 2));
6831
- v3 = this._decodeChar(s.charCodeAt(i + 3));
6832
- out[op++] = (v0 << 2) | (v1 >>> 4);
6833
- out[op++] = (v1 << 4) | (v2 >>> 2);
6834
- out[op++] = (v2 << 6) | v3;
6835
- haveBad |= v0 & INVALID_BYTE;
6836
- haveBad |= v1 & INVALID_BYTE;
6837
- haveBad |= v2 & INVALID_BYTE;
6838
- haveBad |= v3 & INVALID_BYTE;
6839
- }
6840
- if (i < length - 1) {
6841
- v0 = this._decodeChar(s.charCodeAt(i));
6842
- v1 = this._decodeChar(s.charCodeAt(i + 1));
6843
- out[op++] = (v0 << 2) | (v1 >>> 4);
6844
- haveBad |= v0 & INVALID_BYTE;
6845
- haveBad |= v1 & INVALID_BYTE;
6846
- }
6847
- if (i < length - 2) {
6848
- v2 = this._decodeChar(s.charCodeAt(i + 2));
6849
- out[op++] = (v1 << 4) | (v2 >>> 2);
6850
- haveBad |= v2 & INVALID_BYTE;
6851
- }
6852
- if (i < length - 3) {
6853
- v3 = this._decodeChar(s.charCodeAt(i + 3));
6854
- out[op++] = (v2 << 6) | v3;
6855
- haveBad |= v3 & INVALID_BYTE;
6856
- }
6857
- if (haveBad !== 0) {
6858
- throw new Error("Base64Coder: incorrect characters for decoding");
6859
- }
6860
- return out;
6861
- };
6862
- // Standard encoding have the following encoded/decoded ranges,
6863
- // which we need to convert between.
6864
- //
6865
- // ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 + /
6866
- // Index: 0 - 25 26 - 51 52 - 61 62 63
6867
- // ASCII: 65 - 90 97 - 122 48 - 57 43 47
6868
- //
6869
- // Encode 6 bits in b into a new character.
6870
- Coder.prototype._encodeByte = function (b) {
6871
- // Encoding uses constant time operations as follows:
6872
- //
6873
- // 1. Define comparison of A with B using (A - B) >>> 8:
6874
- // if A > B, then result is positive integer
6875
- // if A <= B, then result is 0
6876
- //
6877
- // 2. Define selection of C or 0 using bitwise AND: X & C:
6878
- // if X == 0, then result is 0
6879
- // if X != 0, then result is C
6880
- //
6881
- // 3. Start with the smallest comparison (b >= 0), which is always
6882
- // true, so set the result to the starting ASCII value (65).
6883
- //
6884
- // 4. Continue comparing b to higher ASCII values, and selecting
6885
- // zero if comparison isn't true, otherwise selecting a value
6886
- // to add to result, which:
6887
- //
6888
- // a) undoes the previous addition
6889
- // b) provides new value to add
6890
- //
6891
- var result = b;
6892
- // b >= 0
6893
- result += 65;
6894
- // b > 25
6895
- result += ((25 - b) >>> 8) & ((0 - 65) - 26 + 97);
6896
- // b > 51
6897
- result += ((51 - b) >>> 8) & ((26 - 97) - 52 + 48);
6898
- // b > 61
6899
- result += ((61 - b) >>> 8) & ((52 - 48) - 62 + 43);
6900
- // b > 62
6901
- result += ((62 - b) >>> 8) & ((62 - 43) - 63 + 47);
6902
- return String.fromCharCode(result);
6903
- };
6904
- // Decode a character code into a byte.
6905
- // Must return 256 if character is out of alphabet range.
6906
- Coder.prototype._decodeChar = function (c) {
6907
- // Decoding works similar to encoding: using the same comparison
6908
- // function, but now it works on ranges: result is always incremented
6909
- // by value, but this value becomes zero if the range is not
6910
- // satisfied.
6911
- //
6912
- // Decoding starts with invalid value, 256, which is then
6913
- // subtracted when the range is satisfied. If none of the ranges
6914
- // apply, the function returns 256, which is then checked by
6915
- // the caller to throw error.
6916
- var result = INVALID_BYTE; // start with invalid character
6917
- // c == 43 (c > 42 and c < 44)
6918
- result += (((42 - c) & (c - 44)) >>> 8) & (-INVALID_BYTE + c - 43 + 62);
6919
- // c == 47 (c > 46 and c < 48)
6920
- result += (((46 - c) & (c - 48)) >>> 8) & (-INVALID_BYTE + c - 47 + 63);
6921
- // c > 47 and c < 58
6922
- result += (((47 - c) & (c - 58)) >>> 8) & (-INVALID_BYTE + c - 48 + 52);
6923
- // c > 64 and c < 91
6924
- result += (((64 - c) & (c - 91)) >>> 8) & (-INVALID_BYTE + c - 65 + 0);
6925
- // c > 96 and c < 123
6926
- result += (((96 - c) & (c - 123)) >>> 8) & (-INVALID_BYTE + c - 97 + 26);
6927
- return result;
6928
- };
6929
- Coder.prototype._getPaddingLength = function (s) {
6930
- var paddingLength = 0;
6931
- if (this._paddingCharacter) {
6932
- for (var i = s.length - 1; i >= 0; i--) {
6933
- if (s[i] !== this._paddingCharacter) {
6934
- break;
6935
- }
6936
- paddingLength++;
6937
- }
6938
- if (s.length < 4 || paddingLength > 2) {
6939
- throw new Error("Base64Coder: incorrect padding");
6940
- }
6941
- }
6942
- return paddingLength;
6943
- };
6944
- return Coder;
6945
- }());
6946
- base64$1.Coder = Coder;
6947
- var stdCoder = new Coder();
6948
- function encode(data) {
6949
- return stdCoder.encode(data);
6950
- }
6951
- base64$1.encode = encode;
6952
- function decode(s) {
6953
- return stdCoder.decode(s);
6954
- }
6955
- base64$1.decode = decode;
6956
- /**
6957
- * Implements URL-safe Base64 encoding.
6958
- * (Same as Base64, but '+' is replaced with '-', and '/' with '_').
6959
- *
6960
- * Operates in constant time.
6961
- */
6962
- var URLSafeCoder = /** @class */ (function (_super) {
6963
- __extends(URLSafeCoder, _super);
6964
- function URLSafeCoder() {
6965
- return _super !== null && _super.apply(this, arguments) || this;
6966
- }
6967
- // URL-safe encoding have the following encoded/decoded ranges:
6968
- //
6969
- // ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 - _
6970
- // Index: 0 - 25 26 - 51 52 - 61 62 63
6971
- // ASCII: 65 - 90 97 - 122 48 - 57 45 95
6972
- //
6973
- URLSafeCoder.prototype._encodeByte = function (b) {
6974
- var result = b;
6975
- // b >= 0
6976
- result += 65;
6977
- // b > 25
6978
- result += ((25 - b) >>> 8) & ((0 - 65) - 26 + 97);
6979
- // b > 51
6980
- result += ((51 - b) >>> 8) & ((26 - 97) - 52 + 48);
6981
- // b > 61
6982
- result += ((61 - b) >>> 8) & ((52 - 48) - 62 + 45);
6983
- // b > 62
6984
- result += ((62 - b) >>> 8) & ((62 - 45) - 63 + 95);
6985
- return String.fromCharCode(result);
6986
- };
6987
- URLSafeCoder.prototype._decodeChar = function (c) {
6988
- var result = INVALID_BYTE;
6989
- // c == 45 (c > 44 and c < 46)
6990
- result += (((44 - c) & (c - 46)) >>> 8) & (-INVALID_BYTE + c - 45 + 62);
6991
- // c == 95 (c > 94 and c < 96)
6992
- result += (((94 - c) & (c - 96)) >>> 8) & (-INVALID_BYTE + c - 95 + 63);
6993
- // c > 47 and c < 58
6994
- result += (((47 - c) & (c - 58)) >>> 8) & (-INVALID_BYTE + c - 48 + 52);
6995
- // c > 64 and c < 91
6996
- result += (((64 - c) & (c - 91)) >>> 8) & (-INVALID_BYTE + c - 65 + 0);
6997
- // c > 96 and c < 123
6998
- result += (((96 - c) & (c - 123)) >>> 8) & (-INVALID_BYTE + c - 97 + 26);
6999
- return result;
7000
- };
7001
- return URLSafeCoder;
7002
- }(Coder));
7003
- base64$1.URLSafeCoder = URLSafeCoder;
7004
- var urlSafeCoder = new URLSafeCoder();
7005
- function encodeURLSafe(data) {
7006
- return urlSafeCoder.encode(data);
7007
- }
7008
- base64$1.encodeURLSafe = encodeURLSafe;
7009
- function decodeURLSafe(s) {
7010
- return urlSafeCoder.decode(s);
7011
- }
7012
- base64$1.decodeURLSafe = decodeURLSafe;
7013
- base64$1.encodedLength = function (length) {
7014
- return stdCoder.encodedLength(length);
7015
- };
7016
- base64$1.maxDecodedLength = function (length) {
7017
- return stdCoder.maxDecodedLength(length);
7018
- };
7019
- base64$1.decodedLength = function (s) {
7020
- return stdCoder.decodedLength(s);
7021
- };
7022
-
7023
- var sha256$1 = {exports: {}};
5930
+ var sha256$1 = {exports: {}};
7024
5931
 
7025
5932
  (function (module) {
7026
5933
  (function (root, factory) {
@@ -7462,96 +6369,1240 @@ class ExtendableError extends Error {
7462
6369
  this.name = "ExtendableError";
7463
6370
  this.stack = new Error(message).stack;
7464
6371
  }
7465
- }
7466
- class WebhookVerificationError extends ExtendableError {
7467
- constructor(message) {
7468
- super(message);
7469
- Object.setPrototypeOf(this, WebhookVerificationError.prototype);
7470
- this.name = "WebhookVerificationError";
6372
+ }
6373
+ class WebhookVerificationError extends ExtendableError {
6374
+ constructor(message) {
6375
+ super(message);
6376
+ Object.setPrototypeOf(this, WebhookVerificationError.prototype);
6377
+ this.name = "WebhookVerificationError";
6378
+ }
6379
+ }
6380
+ var WebhookVerificationError_1 = dist.WebhookVerificationError = WebhookVerificationError;
6381
+ class Webhook {
6382
+ constructor(secret, options) {
6383
+ if (!secret) {
6384
+ throw new Error("Secret can't be empty.");
6385
+ }
6386
+ if ((options === null || options === void 0 ? void 0 : options.format) === "raw") {
6387
+ if (secret instanceof Uint8Array) {
6388
+ this.key = secret;
6389
+ }
6390
+ else {
6391
+ this.key = Uint8Array.from(secret, (c) => c.charCodeAt(0));
6392
+ }
6393
+ }
6394
+ else {
6395
+ if (typeof secret !== "string") {
6396
+ throw new Error("Expected secret to be of type string");
6397
+ }
6398
+ if (secret.startsWith(Webhook.prefix)) {
6399
+ secret = secret.substring(Webhook.prefix.length);
6400
+ }
6401
+ this.key = base64.decode(secret);
6402
+ }
6403
+ }
6404
+ verify(payload, headers_) {
6405
+ const headers = {};
6406
+ for (const key of Object.keys(headers_)) {
6407
+ headers[key.toLowerCase()] = headers_[key];
6408
+ }
6409
+ const msgId = headers["webhook-id"];
6410
+ const msgSignature = headers["webhook-signature"];
6411
+ const msgTimestamp = headers["webhook-timestamp"];
6412
+ if (!msgSignature || !msgId || !msgTimestamp) {
6413
+ throw new WebhookVerificationError("Missing required headers");
6414
+ }
6415
+ const timestamp = this.verifyTimestamp(msgTimestamp);
6416
+ const computedSignature = this.sign(msgId, timestamp, payload);
6417
+ const expectedSignature = computedSignature.split(",")[1];
6418
+ const passedSignatures = msgSignature.split(" ");
6419
+ const encoder = new globalThis.TextEncoder();
6420
+ for (const versionedSignature of passedSignatures) {
6421
+ const [version, signature] = versionedSignature.split(",");
6422
+ if (version !== "v1") {
6423
+ continue;
6424
+ }
6425
+ if ((0, timing_safe_equal_1.timingSafeEqual)(encoder.encode(signature), encoder.encode(expectedSignature))) {
6426
+ return JSON.parse(payload.toString());
6427
+ }
6428
+ }
6429
+ throw new WebhookVerificationError("No matching signature found");
6430
+ }
6431
+ sign(msgId, timestamp, payload) {
6432
+ if (typeof payload === "string") ;
6433
+ else if (payload.constructor.name === "Buffer") {
6434
+ payload = payload.toString();
6435
+ }
6436
+ else {
6437
+ throw new Error("Expected payload to be of type string or Buffer.");
6438
+ }
6439
+ const encoder = new TextEncoder();
6440
+ const timestampNumber = Math.floor(timestamp.getTime() / 1000);
6441
+ const toSign = encoder.encode(`${msgId}.${timestampNumber}.${payload}`);
6442
+ const expectedSignature = base64.encode(sha256.hmac(this.key, toSign));
6443
+ return `v1,${expectedSignature}`;
6444
+ }
6445
+ verifyTimestamp(timestampHeader) {
6446
+ const now = Math.floor(Date.now() / 1000);
6447
+ const timestamp = parseInt(timestampHeader, 10);
6448
+ if (isNaN(timestamp)) {
6449
+ throw new WebhookVerificationError("Invalid Signature Headers");
6450
+ }
6451
+ if (now - timestamp > WEBHOOK_TOLERANCE_IN_SECONDS) {
6452
+ throw new WebhookVerificationError("Message timestamp too old");
6453
+ }
6454
+ if (timestamp > now + WEBHOOK_TOLERANCE_IN_SECONDS) {
6455
+ throw new WebhookVerificationError("Message timestamp too new");
6456
+ }
6457
+ return new Date(timestamp * 1000);
6458
+ }
6459
+ }
6460
+ Webhook_1 = dist.Webhook = Webhook;
6461
+ Webhook.prefix = "whsec_";
6462
+
6463
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
6464
+ let Webhooks$1 = class Webhooks extends APIResource {
6465
+ constructor() {
6466
+ super(...arguments);
6467
+ this.headers = new Headers$1(this._client);
6468
+ }
6469
+ /**
6470
+ * Create a new webhook
6471
+ */
6472
+ create(body, options) {
6473
+ return this._client.post('/webhooks', { body, ...options });
6474
+ }
6475
+ /**
6476
+ * Get a webhook by id
6477
+ */
6478
+ retrieve(webhookID, options) {
6479
+ return this._client.get(path `/webhooks/${webhookID}`, options);
6480
+ }
6481
+ /**
6482
+ * Patch a webhook by id
6483
+ */
6484
+ update(webhookID, body, options) {
6485
+ return this._client.patch(path `/webhooks/${webhookID}`, { body, ...options });
6486
+ }
6487
+ /**
6488
+ * List all webhooks
6489
+ */
6490
+ list(query = {}, options) {
6491
+ return this._client.getAPIList('/webhooks', (CursorPagePagination), { query, ...options });
6492
+ }
6493
+ /**
6494
+ * Delete a webhook by id
6495
+ */
6496
+ delete(webhookID, options) {
6497
+ return this._client.delete(path `/webhooks/${webhookID}`, {
6498
+ ...options,
6499
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
6500
+ });
6501
+ }
6502
+ /**
6503
+ * Get webhook secret by id
6504
+ */
6505
+ retrieveSecret(webhookID, options) {
6506
+ return this._client.get(path `/webhooks/${webhookID}/secret`, options);
6507
+ }
6508
+ unsafeUnwrap(body) {
6509
+ return JSON.parse(body);
6510
+ }
6511
+ unwrap(body, { headers, key }) {
6512
+ if (headers !== undefined) {
6513
+ const keyStr = key === undefined ? this._client.webhookKey : key;
6514
+ if (keyStr === null)
6515
+ throw new Error('Webhook key must not be null in order to unwrap');
6516
+ const wh = new Webhook_1(keyStr);
6517
+ wh.verify(body, headers);
6518
+ }
6519
+ return JSON.parse(body);
6520
+ }
6521
+ };
6522
+ Webhooks$1.Headers = Headers$1;
6523
+
6524
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
6525
+ /**
6526
+ * Read an environment variable.
6527
+ *
6528
+ * Trims beginning and trailing whitespace.
6529
+ *
6530
+ * Will return undefined if the environment variable doesn't exist or cannot be accessed.
6531
+ */
6532
+ const readEnv = (env) => {
6533
+ if (typeof globalThis.process !== 'undefined') {
6534
+ return globalThis.process.env?.[env]?.trim() ?? undefined;
6535
+ }
6536
+ if (typeof globalThis.Deno !== 'undefined') {
6537
+ return globalThis.Deno.env?.get?.(env)?.trim();
6538
+ }
6539
+ return undefined;
6540
+ };
6541
+
6542
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
6543
+ var _DodoPayments_instances, _a, _DodoPayments_encoder, _DodoPayments_baseURLOverridden;
6544
+ const environments = {
6545
+ live_mode: 'https://live.dodopayments.com',
6546
+ test_mode: 'https://test.dodopayments.com',
6547
+ };
6548
+ /**
6549
+ * API Client for interfacing with the Dodo Payments API.
6550
+ */
6551
+ class DodoPayments {
6552
+ /**
6553
+ * API Client for interfacing with the Dodo Payments API.
6554
+ *
6555
+ * @param {string | undefined} [opts.bearerToken=process.env['DODO_PAYMENTS_API_KEY'] ?? undefined]
6556
+ * @param {string | null | undefined} [opts.webhookKey=process.env['DODO_PAYMENTS_WEBHOOK_KEY'] ?? null]
6557
+ * @param {Environment} [opts.environment=live_mode] - Specifies the environment URL to use for the API.
6558
+ * @param {string} [opts.baseURL=process.env['DODO_PAYMENTS_BASE_URL'] ?? https://live.dodopayments.com] - Override the default base URL for the API.
6559
+ * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
6560
+ * @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls.
6561
+ * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
6562
+ * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
6563
+ * @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API.
6564
+ * @param {Record<string, string | undefined>} opts.defaultQuery - Default query parameters to include with every request to the API.
6565
+ */
6566
+ constructor({ baseURL = readEnv('DODO_PAYMENTS_BASE_URL'), bearerToken = readEnv('DODO_PAYMENTS_API_KEY'), webhookKey = readEnv('DODO_PAYMENTS_WEBHOOK_KEY') ?? null, ...opts } = {}) {
6567
+ _DodoPayments_instances.add(this);
6568
+ _DodoPayments_encoder.set(this, void 0);
6569
+ this.checkoutSessions = new CheckoutSessions(this);
6570
+ this.payments = new Payments(this);
6571
+ this.subscriptions = new Subscriptions(this);
6572
+ this.invoices = new Invoices(this);
6573
+ this.licenses = new Licenses(this);
6574
+ this.licenseKeys = new LicenseKeys(this);
6575
+ this.licenseKeyInstances = new LicenseKeyInstances(this);
6576
+ this.customers = new Customers(this);
6577
+ this.refunds = new Refunds(this);
6578
+ this.disputes = new Disputes(this);
6579
+ this.payouts = new Payouts(this);
6580
+ this.products = new Products(this);
6581
+ this.misc = new Misc(this);
6582
+ this.discounts = new Discounts(this);
6583
+ this.addons = new Addons(this);
6584
+ this.brands = new Brands(this);
6585
+ this.webhooks = new Webhooks$1(this);
6586
+ this.webhookEvents = new WebhookEvents(this);
6587
+ this.usageEvents = new UsageEvents(this);
6588
+ this.meters = new Meters(this);
6589
+ if (bearerToken === undefined) {
6590
+ throw new DodoPaymentsError("The DODO_PAYMENTS_API_KEY environment variable is missing or empty; either provide it, or instantiate the DodoPayments client with an bearerToken option, like new DodoPayments({ bearerToken: 'My Bearer Token' }).");
6591
+ }
6592
+ const options = {
6593
+ bearerToken,
6594
+ webhookKey,
6595
+ ...opts,
6596
+ baseURL,
6597
+ environment: opts.environment ?? 'live_mode',
6598
+ };
6599
+ if (baseURL && opts.environment) {
6600
+ throw new DodoPaymentsError('Ambiguous URL; The `baseURL` option (or DODO_PAYMENTS_BASE_URL env var) and the `environment` option are given. If you want to use the environment you must pass baseURL: null');
6601
+ }
6602
+ this.baseURL = options.baseURL || environments[options.environment || 'live_mode'];
6603
+ this.timeout = options.timeout ?? _a.DEFAULT_TIMEOUT /* 1 minute */;
6604
+ this.logger = options.logger ?? console;
6605
+ const defaultLogLevel = 'warn';
6606
+ // Set default logLevel early so that we can log a warning in parseLogLevel.
6607
+ this.logLevel = defaultLogLevel;
6608
+ this.logLevel =
6609
+ parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ??
6610
+ parseLogLevel(readEnv('DODO_PAYMENTS_LOG'), "process.env['DODO_PAYMENTS_LOG']", this) ??
6611
+ defaultLogLevel;
6612
+ this.fetchOptions = options.fetchOptions;
6613
+ this.maxRetries = options.maxRetries ?? 2;
6614
+ this.fetch = options.fetch ?? getDefaultFetch();
6615
+ __classPrivateFieldSet(this, _DodoPayments_encoder, FallbackEncoder);
6616
+ this._options = options;
6617
+ this.bearerToken = bearerToken;
6618
+ this.webhookKey = webhookKey;
6619
+ }
6620
+ /**
6621
+ * Create a new client instance re-using the same options given to the current client with optional overriding.
6622
+ */
6623
+ withOptions(options) {
6624
+ const client = new this.constructor({
6625
+ ...this._options,
6626
+ environment: options.environment ? options.environment : undefined,
6627
+ baseURL: options.environment ? undefined : this.baseURL,
6628
+ maxRetries: this.maxRetries,
6629
+ timeout: this.timeout,
6630
+ logger: this.logger,
6631
+ logLevel: this.logLevel,
6632
+ fetch: this.fetch,
6633
+ fetchOptions: this.fetchOptions,
6634
+ bearerToken: this.bearerToken,
6635
+ webhookKey: this.webhookKey,
6636
+ ...options,
6637
+ });
6638
+ return client;
6639
+ }
6640
+ defaultQuery() {
6641
+ return this._options.defaultQuery;
6642
+ }
6643
+ validateHeaders({ values, nulls }) {
6644
+ return;
6645
+ }
6646
+ async authHeaders(opts) {
6647
+ return buildHeaders([{ Authorization: `Bearer ${this.bearerToken}` }]);
6648
+ }
6649
+ /**
6650
+ * Basic re-implementation of `qs.stringify` for primitive types.
6651
+ */
6652
+ stringifyQuery(query) {
6653
+ return Object.entries(query)
6654
+ .filter(([_, value]) => typeof value !== 'undefined')
6655
+ .map(([key, value]) => {
6656
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
6657
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
6658
+ }
6659
+ if (value === null) {
6660
+ return `${encodeURIComponent(key)}=`;
6661
+ }
6662
+ throw new DodoPaymentsError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);
6663
+ })
6664
+ .join('&');
6665
+ }
6666
+ getUserAgent() {
6667
+ return `${this.constructor.name}/JS ${VERSION}`;
6668
+ }
6669
+ defaultIdempotencyKey() {
6670
+ return `stainless-node-retry-${uuid4()}`;
6671
+ }
6672
+ makeStatusError(status, error, message, headers) {
6673
+ return APIError.generate(status, error, message, headers);
6674
+ }
6675
+ buildURL(path, query, defaultBaseURL) {
6676
+ const baseURL = (!__classPrivateFieldGet(this, _DodoPayments_instances, "m", _DodoPayments_baseURLOverridden).call(this) && defaultBaseURL) || this.baseURL;
6677
+ const url = isAbsoluteURL(path) ?
6678
+ new URL(path)
6679
+ : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
6680
+ const defaultQuery = this.defaultQuery();
6681
+ if (!isEmptyObj(defaultQuery)) {
6682
+ query = { ...defaultQuery, ...query };
6683
+ }
6684
+ if (typeof query === 'object' && query && !Array.isArray(query)) {
6685
+ url.search = this.stringifyQuery(query);
6686
+ }
6687
+ return url.toString();
6688
+ }
6689
+ /**
6690
+ * Used as a callback for mutating the given `FinalRequestOptions` object.
6691
+ */
6692
+ async prepareOptions(options) { }
6693
+ /**
6694
+ * Used as a callback for mutating the given `RequestInit` object.
6695
+ *
6696
+ * This is useful for cases where you want to add certain headers based off of
6697
+ * the request properties, e.g. `method` or `url`.
6698
+ */
6699
+ async prepareRequest(request, { url, options }) { }
6700
+ get(path, opts) {
6701
+ return this.methodRequest('get', path, opts);
6702
+ }
6703
+ post(path, opts) {
6704
+ return this.methodRequest('post', path, opts);
6705
+ }
6706
+ patch(path, opts) {
6707
+ return this.methodRequest('patch', path, opts);
6708
+ }
6709
+ put(path, opts) {
6710
+ return this.methodRequest('put', path, opts);
6711
+ }
6712
+ delete(path, opts) {
6713
+ return this.methodRequest('delete', path, opts);
6714
+ }
6715
+ methodRequest(method, path, opts) {
6716
+ return this.request(Promise.resolve(opts).then((opts) => {
6717
+ return { method, path, ...opts };
6718
+ }));
6719
+ }
6720
+ request(options, remainingRetries = null) {
6721
+ return new APIPromise(this, this.makeRequest(options, remainingRetries, undefined));
6722
+ }
6723
+ async makeRequest(optionsInput, retriesRemaining, retryOfRequestLogID) {
6724
+ const options = await optionsInput;
6725
+ const maxRetries = options.maxRetries ?? this.maxRetries;
6726
+ if (retriesRemaining == null) {
6727
+ retriesRemaining = maxRetries;
6728
+ }
6729
+ await this.prepareOptions(options);
6730
+ const { req, url, timeout } = await this.buildRequest(options, {
6731
+ retryCount: maxRetries - retriesRemaining,
6732
+ });
6733
+ await this.prepareRequest(req, { url, options });
6734
+ /** Not an API request ID, just for correlating local log entries. */
6735
+ const requestLogID = 'log_' + ((Math.random() * (1 << 24)) | 0).toString(16).padStart(6, '0');
6736
+ const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`;
6737
+ const startTime = Date.now();
6738
+ loggerFor(this).debug(`[${requestLogID}] sending request`, formatRequestDetails({
6739
+ retryOfRequestLogID,
6740
+ method: options.method,
6741
+ url,
6742
+ options,
6743
+ headers: req.headers,
6744
+ }));
6745
+ if (options.signal?.aborted) {
6746
+ throw new APIUserAbortError();
6747
+ }
6748
+ const controller = new AbortController();
6749
+ const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);
6750
+ const headersTime = Date.now();
6751
+ if (response instanceof globalThis.Error) {
6752
+ const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
6753
+ if (options.signal?.aborted) {
6754
+ throw new APIUserAbortError();
6755
+ }
6756
+ // detect native connection timeout errors
6757
+ // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)"
6758
+ // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)"
6759
+ // others do not provide enough information to distinguish timeouts from other connection errors
6760
+ const isTimeout = isAbortError(response) ||
6761
+ /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : ''));
6762
+ if (retriesRemaining) {
6763
+ loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`);
6764
+ loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, formatRequestDetails({
6765
+ retryOfRequestLogID,
6766
+ url,
6767
+ durationMs: headersTime - startTime,
6768
+ message: response.message,
6769
+ }));
6770
+ return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID);
6771
+ }
6772
+ loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`);
6773
+ loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, formatRequestDetails({
6774
+ retryOfRequestLogID,
6775
+ url,
6776
+ durationMs: headersTime - startTime,
6777
+ message: response.message,
6778
+ }));
6779
+ if (isTimeout) {
6780
+ throw new APIConnectionTimeoutError();
6781
+ }
6782
+ throw new APIConnectionError({ cause: response });
6783
+ }
6784
+ const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${response.ok ? 'succeeded' : 'failed'} with status ${response.status} in ${headersTime - startTime}ms`;
6785
+ if (!response.ok) {
6786
+ const shouldRetry = await this.shouldRetry(response);
6787
+ if (retriesRemaining && shouldRetry) {
6788
+ const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
6789
+ // We don't need the body of this response.
6790
+ await CancelReadableStream(response.body);
6791
+ loggerFor(this).info(`${responseInfo} - ${retryMessage}`);
6792
+ loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({
6793
+ retryOfRequestLogID,
6794
+ url: response.url,
6795
+ status: response.status,
6796
+ headers: response.headers,
6797
+ durationMs: headersTime - startTime,
6798
+ }));
6799
+ return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID, response.headers);
6800
+ }
6801
+ const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`;
6802
+ loggerFor(this).info(`${responseInfo} - ${retryMessage}`);
6803
+ const errText = await response.text().catch((err) => castToError(err).message);
6804
+ const errJSON = safeJSON(errText);
6805
+ const errMessage = errJSON ? undefined : errText;
6806
+ loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({
6807
+ retryOfRequestLogID,
6808
+ url: response.url,
6809
+ status: response.status,
6810
+ headers: response.headers,
6811
+ message: errMessage,
6812
+ durationMs: Date.now() - startTime,
6813
+ }));
6814
+ const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers);
6815
+ throw err;
6816
+ }
6817
+ loggerFor(this).info(responseInfo);
6818
+ loggerFor(this).debug(`[${requestLogID}] response start`, formatRequestDetails({
6819
+ retryOfRequestLogID,
6820
+ url: response.url,
6821
+ status: response.status,
6822
+ headers: response.headers,
6823
+ durationMs: headersTime - startTime,
6824
+ }));
6825
+ return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
6826
+ }
6827
+ getAPIList(path, Page, opts) {
6828
+ return this.requestAPIList(Page, { method: 'get', path, ...opts });
6829
+ }
6830
+ requestAPIList(Page, options) {
6831
+ const request = this.makeRequest(options, null, undefined);
6832
+ return new PagePromise(this, request, Page);
6833
+ }
6834
+ async fetchWithTimeout(url, init, ms, controller) {
6835
+ const { signal, method, ...options } = init || {};
6836
+ if (signal)
6837
+ signal.addEventListener('abort', () => controller.abort());
6838
+ const timeout = setTimeout(() => controller.abort(), ms);
6839
+ const isReadableBody = (globalThis.ReadableStream && options.body instanceof globalThis.ReadableStream) ||
6840
+ (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body);
6841
+ const fetchOptions = {
6842
+ signal: controller.signal,
6843
+ ...(isReadableBody ? { duplex: 'half' } : {}),
6844
+ method: 'GET',
6845
+ ...options,
6846
+ };
6847
+ if (method) {
6848
+ // Custom methods like 'patch' need to be uppercased
6849
+ // See https://github.com/nodejs/undici/issues/2294
6850
+ fetchOptions.method = method.toUpperCase();
6851
+ }
6852
+ try {
6853
+ // use undefined this binding; fetch errors if bound to something else in browser/cloudflare
6854
+ return await this.fetch.call(undefined, url, fetchOptions);
6855
+ }
6856
+ finally {
6857
+ clearTimeout(timeout);
6858
+ }
6859
+ }
6860
+ async shouldRetry(response) {
6861
+ // Note this is not a standard header.
6862
+ const shouldRetryHeader = response.headers.get('x-should-retry');
6863
+ // If the server explicitly says whether or not to retry, obey.
6864
+ if (shouldRetryHeader === 'true')
6865
+ return true;
6866
+ if (shouldRetryHeader === 'false')
6867
+ return false;
6868
+ // Retry on request timeouts.
6869
+ if (response.status === 408)
6870
+ return true;
6871
+ // Retry on lock timeouts.
6872
+ if (response.status === 409)
6873
+ return true;
6874
+ // Retry on rate limits.
6875
+ if (response.status === 429)
6876
+ return true;
6877
+ // Retry internal errors.
6878
+ if (response.status >= 500)
6879
+ return true;
6880
+ return false;
6881
+ }
6882
+ async retryRequest(options, retriesRemaining, requestLogID, responseHeaders) {
6883
+ let timeoutMillis;
6884
+ // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
6885
+ const retryAfterMillisHeader = responseHeaders?.get('retry-after-ms');
6886
+ if (retryAfterMillisHeader) {
6887
+ const timeoutMs = parseFloat(retryAfterMillisHeader);
6888
+ if (!Number.isNaN(timeoutMs)) {
6889
+ timeoutMillis = timeoutMs;
6890
+ }
6891
+ }
6892
+ // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
6893
+ const retryAfterHeader = responseHeaders?.get('retry-after');
6894
+ if (retryAfterHeader && !timeoutMillis) {
6895
+ const timeoutSeconds = parseFloat(retryAfterHeader);
6896
+ if (!Number.isNaN(timeoutSeconds)) {
6897
+ timeoutMillis = timeoutSeconds * 1000;
6898
+ }
6899
+ else {
6900
+ timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
6901
+ }
6902
+ }
6903
+ // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
6904
+ // just do what it says, but otherwise calculate a default
6905
+ if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
6906
+ const maxRetries = options.maxRetries ?? this.maxRetries;
6907
+ timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
6908
+ }
6909
+ await sleep(timeoutMillis);
6910
+ return this.makeRequest(options, retriesRemaining - 1, requestLogID);
6911
+ }
6912
+ calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
6913
+ const initialRetryDelay = 0.5;
6914
+ const maxRetryDelay = 8.0;
6915
+ const numRetries = maxRetries - retriesRemaining;
6916
+ // Apply exponential backoff, but not more than the max.
6917
+ const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
6918
+ // Apply some jitter, take up to at most 25 percent of the retry time.
6919
+ const jitter = 1 - Math.random() * 0.25;
6920
+ return sleepSeconds * jitter * 1000;
6921
+ }
6922
+ async buildRequest(inputOptions, { retryCount = 0 } = {}) {
6923
+ const options = { ...inputOptions };
6924
+ const { method, path, query, defaultBaseURL } = options;
6925
+ const url = this.buildURL(path, query, defaultBaseURL);
6926
+ if ('timeout' in options)
6927
+ validatePositiveInteger('timeout', options.timeout);
6928
+ options.timeout = options.timeout ?? this.timeout;
6929
+ const { bodyHeaders, body } = this.buildBody({ options });
6930
+ const reqHeaders = await this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount });
6931
+ const req = {
6932
+ method,
6933
+ headers: reqHeaders,
6934
+ ...(options.signal && { signal: options.signal }),
6935
+ ...(globalThis.ReadableStream &&
6936
+ body instanceof globalThis.ReadableStream && { duplex: 'half' }),
6937
+ ...(body && { body }),
6938
+ ...(this.fetchOptions ?? {}),
6939
+ ...(options.fetchOptions ?? {}),
6940
+ };
6941
+ return { req, url, timeout: options.timeout };
6942
+ }
6943
+ async buildHeaders({ options, method, bodyHeaders, retryCount, }) {
6944
+ let idempotencyHeaders = {};
6945
+ if (this.idempotencyHeader && method !== 'get') {
6946
+ if (!options.idempotencyKey)
6947
+ options.idempotencyKey = this.defaultIdempotencyKey();
6948
+ idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey;
6949
+ }
6950
+ const headers = buildHeaders([
6951
+ idempotencyHeaders,
6952
+ {
6953
+ Accept: 'application/json',
6954
+ 'User-Agent': this.getUserAgent(),
6955
+ 'X-Stainless-Retry-Count': String(retryCount),
6956
+ ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}),
6957
+ ...getPlatformHeaders(),
6958
+ },
6959
+ await this.authHeaders(options),
6960
+ this._options.defaultHeaders,
6961
+ bodyHeaders,
6962
+ options.headers,
6963
+ ]);
6964
+ this.validateHeaders(headers);
6965
+ return headers.values;
6966
+ }
6967
+ buildBody({ options: { body, headers: rawHeaders } }) {
6968
+ if (!body) {
6969
+ return { bodyHeaders: undefined, body: undefined };
6970
+ }
6971
+ const headers = buildHeaders([rawHeaders]);
6972
+ if (
6973
+ // Pass raw type verbatim
6974
+ ArrayBuffer.isView(body) ||
6975
+ body instanceof ArrayBuffer ||
6976
+ body instanceof DataView ||
6977
+ (typeof body === 'string' &&
6978
+ // Preserve legacy string encoding behavior for now
6979
+ headers.values.has('content-type')) ||
6980
+ // `Blob` is superset of `File`
6981
+ (globalThis.Blob && body instanceof globalThis.Blob) ||
6982
+ // `FormData` -> `multipart/form-data`
6983
+ body instanceof FormData ||
6984
+ // `URLSearchParams` -> `application/x-www-form-urlencoded`
6985
+ body instanceof URLSearchParams ||
6986
+ // Send chunked stream (each chunk has own `length`)
6987
+ (globalThis.ReadableStream && body instanceof globalThis.ReadableStream)) {
6988
+ return { bodyHeaders: undefined, body: body };
6989
+ }
6990
+ else if (typeof body === 'object' &&
6991
+ (Symbol.asyncIterator in body ||
6992
+ (Symbol.iterator in body && 'next' in body && typeof body.next === 'function'))) {
6993
+ return { bodyHeaders: undefined, body: ReadableStreamFrom(body) };
6994
+ }
6995
+ else {
6996
+ return __classPrivateFieldGet(this, _DodoPayments_encoder, "f").call(this, { body, headers });
6997
+ }
6998
+ }
6999
+ }
7000
+ _a = DodoPayments, _DodoPayments_encoder = new WeakMap(), _DodoPayments_instances = new WeakSet(), _DodoPayments_baseURLOverridden = function _DodoPayments_baseURLOverridden() {
7001
+ return this.baseURL !== environments[this._options.environment || 'live_mode'];
7002
+ };
7003
+ DodoPayments.DodoPayments = _a;
7004
+ DodoPayments.DEFAULT_TIMEOUT = 60000; // 1 minute
7005
+ DodoPayments.DodoPaymentsError = DodoPaymentsError;
7006
+ DodoPayments.APIError = APIError;
7007
+ DodoPayments.APIConnectionError = APIConnectionError;
7008
+ DodoPayments.APIConnectionTimeoutError = APIConnectionTimeoutError;
7009
+ DodoPayments.APIUserAbortError = APIUserAbortError;
7010
+ DodoPayments.NotFoundError = NotFoundError;
7011
+ DodoPayments.ConflictError = ConflictError;
7012
+ DodoPayments.RateLimitError = RateLimitError;
7013
+ DodoPayments.BadRequestError = BadRequestError;
7014
+ DodoPayments.AuthenticationError = AuthenticationError;
7015
+ DodoPayments.InternalServerError = InternalServerError;
7016
+ DodoPayments.PermissionDeniedError = PermissionDeniedError;
7017
+ DodoPayments.UnprocessableEntityError = UnprocessableEntityError;
7018
+ DodoPayments.toFile = toFile;
7019
+ DodoPayments.CheckoutSessions = CheckoutSessions;
7020
+ DodoPayments.Payments = Payments;
7021
+ DodoPayments.Subscriptions = Subscriptions;
7022
+ DodoPayments.Invoices = Invoices;
7023
+ DodoPayments.Licenses = Licenses;
7024
+ DodoPayments.LicenseKeys = LicenseKeys;
7025
+ DodoPayments.LicenseKeyInstances = LicenseKeyInstances;
7026
+ DodoPayments.Customers = Customers;
7027
+ DodoPayments.Refunds = Refunds;
7028
+ DodoPayments.Disputes = Disputes;
7029
+ DodoPayments.Payouts = Payouts;
7030
+ DodoPayments.Products = Products;
7031
+ DodoPayments.Misc = Misc;
7032
+ DodoPayments.Discounts = Discounts;
7033
+ DodoPayments.Addons = Addons;
7034
+ DodoPayments.Brands = Brands;
7035
+ DodoPayments.Webhooks = Webhooks$1;
7036
+ DodoPayments.WebhookEvents = WebhookEvents;
7037
+ DodoPayments.UsageEvents = UsageEvents;
7038
+ DodoPayments.Meters = Meters;
7039
+
7040
+ // src/checkout/checkout.ts
7041
+ var checkoutQuerySchema = objectType({
7042
+ productId: stringType(),
7043
+ quantity: stringType().optional(),
7044
+ // Customer fields
7045
+ fullName: stringType().optional(),
7046
+ firstName: stringType().optional(),
7047
+ lastName: stringType().optional(),
7048
+ email: stringType().optional(),
7049
+ country: stringType().optional(),
7050
+ addressLine: stringType().optional(),
7051
+ city: stringType().optional(),
7052
+ state: stringType().optional(),
7053
+ zipCode: stringType().optional(),
7054
+ // Disable flags
7055
+ disableFullName: stringType().optional(),
7056
+ disableFirstName: stringType().optional(),
7057
+ disableLastName: stringType().optional(),
7058
+ disableEmail: stringType().optional(),
7059
+ disableCountry: stringType().optional(),
7060
+ disableAddressLine: stringType().optional(),
7061
+ disableCity: stringType().optional(),
7062
+ disableState: stringType().optional(),
7063
+ disableZipCode: stringType().optional(),
7064
+ // Advanced controls
7065
+ paymentCurrency: stringType().optional(),
7066
+ showCurrencySelector: stringType().optional(),
7067
+ paymentAmount: stringType().optional(),
7068
+ showDiscounts: stringType().optional()
7069
+ // Metadata (allow any key starting with metadata_)
7070
+ // We'll handle metadata separately in the handler
7071
+ }).catchall(unknownType());
7072
+ var dynamicCheckoutBodySchema = objectType({
7073
+ // For subscription
7074
+ product_id: stringType().optional(),
7075
+ quantity: numberType().optional(),
7076
+ // For one-time payment
7077
+ product_cart: arrayType(
7078
+ objectType({
7079
+ product_id: stringType(),
7080
+ quantity: numberType()
7081
+ })
7082
+ ).optional(),
7083
+ // Common fields
7084
+ billing: objectType({
7085
+ city: stringType(),
7086
+ country: stringType(),
7087
+ state: stringType(),
7088
+ street: stringType(),
7089
+ zipcode: stringType()
7090
+ }),
7091
+ customer: objectType({
7092
+ customer_id: stringType().optional(),
7093
+ email: stringType().optional(),
7094
+ name: stringType().optional()
7095
+ }),
7096
+ discount_id: stringType().optional(),
7097
+ addons: arrayType(
7098
+ objectType({
7099
+ addon_id: stringType(),
7100
+ quantity: numberType()
7101
+ })
7102
+ ).optional(),
7103
+ metadata: recordType(stringType(), stringType()).optional(),
7104
+ currency: stringType().optional()
7105
+ // Allow any additional fields (for future compatibility)
7106
+ }).catchall(unknownType());
7107
+ var checkoutSessionProductCartItemSchema = objectType({
7108
+ product_id: stringType().min(1, "Product ID is required"),
7109
+ quantity: numberType().int().positive("Quantity must be a positive integer"),
7110
+ addons: arrayType(
7111
+ objectType({
7112
+ addon_id: stringType(),
7113
+ quantity: numberType().int().nonnegative()
7114
+ })
7115
+ ).optional(),
7116
+ amount: numberType().int().nonnegative(
7117
+ "Amount must be a non-negative integer (for pay-what-you-want products)"
7118
+ ).optional()
7119
+ });
7120
+ var checkoutSessionCustomerSchema = unionType([
7121
+ objectType({
7122
+ email: stringType().email(),
7123
+ name: stringType().min(1).optional(),
7124
+ phone_number: stringType().optional()
7125
+ }),
7126
+ objectType({
7127
+ customer_id: stringType()
7128
+ })
7129
+ ]).optional();
7130
+ var checkoutSessionBillingAddressSchema = objectType({
7131
+ street: stringType().optional(),
7132
+ city: stringType().optional(),
7133
+ state: stringType().optional(),
7134
+ country: stringType().length(2, "Country must be a 2-letter ISO code"),
7135
+ zipcode: stringType().optional()
7136
+ }).optional();
7137
+ var paymentMethodTypeSchema = enumType([
7138
+ "credit",
7139
+ "debit",
7140
+ "upi_collect",
7141
+ "upi_intent",
7142
+ "apple_pay",
7143
+ "cashapp",
7144
+ "google_pay",
7145
+ "multibanco",
7146
+ "bancontact_card",
7147
+ "eps",
7148
+ "ideal",
7149
+ "przelewy24",
7150
+ "paypal",
7151
+ "affirm",
7152
+ "klarna",
7153
+ "sepa",
7154
+ "ach",
7155
+ "amazon_pay",
7156
+ "afterpay_clearpay"
7157
+ ]);
7158
+ var checkoutSessionCustomizationSchema = objectType({
7159
+ theme: enumType(["light", "dark", "system"]).optional(),
7160
+ show_order_details: booleanType().optional(),
7161
+ show_on_demand_tag: booleanType().optional(),
7162
+ force_language: stringType().optional()
7163
+ }).optional();
7164
+ var checkoutSessionFeatureFlagsSchema = objectType({
7165
+ allow_currency_selection: booleanType().optional(),
7166
+ allow_discount_code: booleanType().optional(),
7167
+ allow_phone_number_collection: booleanType().optional(),
7168
+ allow_tax_id: booleanType().optional(),
7169
+ always_create_new_customer: booleanType().optional()
7170
+ }).optional();
7171
+ var checkoutSessionOnDemandSchema = objectType({
7172
+ mandate_only: booleanType(),
7173
+ product_price: numberType().int().optional(),
7174
+ product_currency: stringType().length(3).optional(),
7175
+ product_description: stringType().optional(),
7176
+ adaptive_currency_fees_inclusive: booleanType().optional()
7177
+ }).optional();
7178
+ var checkoutSessionSubscriptionDataSchema = objectType({
7179
+ trial_period_days: numberType().int().nonnegative().optional(),
7180
+ on_demand: checkoutSessionOnDemandSchema
7181
+ }).optional();
7182
+ var checkoutSessionPayloadSchema = objectType({
7183
+ // Required fields
7184
+ product_cart: arrayType(checkoutSessionProductCartItemSchema).min(1, "At least one product is required"),
7185
+ // Optional fields
7186
+ customer: checkoutSessionCustomerSchema,
7187
+ billing_address: checkoutSessionBillingAddressSchema,
7188
+ return_url: stringType().url().optional(),
7189
+ allowed_payment_method_types: arrayType(paymentMethodTypeSchema).optional(),
7190
+ billing_currency: stringType().length(3, "Currency must be a 3-letter ISO code").optional(),
7191
+ show_saved_payment_methods: booleanType().optional(),
7192
+ confirm: booleanType().optional(),
7193
+ discount_code: stringType().optional(),
7194
+ metadata: recordType(stringType(), stringType()).optional(),
7195
+ customization: checkoutSessionCustomizationSchema,
7196
+ feature_flags: checkoutSessionFeatureFlagsSchema,
7197
+ subscription_data: checkoutSessionSubscriptionDataSchema,
7198
+ force_3ds: booleanType().optional()
7199
+ });
7200
+ var checkoutSessionResponseSchema = objectType({
7201
+ session_id: stringType().min(1, "Session ID is required"),
7202
+ checkout_url: stringType().url("Invalid checkout URL")
7203
+ });
7204
+ var createCheckoutSession = async (payload, config) => {
7205
+ const validation = checkoutSessionPayloadSchema.safeParse(payload);
7206
+ if (!validation.success) {
7207
+ throw new Error(
7208
+ `Invalid checkout session payload: ${validation.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ")}`
7209
+ );
7210
+ }
7211
+ const dodopayments = new DodoPayments({
7212
+ bearerToken: config.bearerToken,
7213
+ environment: config.environment
7214
+ });
7215
+ try {
7216
+ const sdkPayload = {
7217
+ ...validation.data,
7218
+ ...validation.data.billing_address && {
7219
+ billing_address: {
7220
+ ...validation.data.billing_address,
7221
+ country: validation.data.billing_address.country
7222
+ }
7223
+ }
7224
+ };
7225
+ const session = await dodopayments.checkoutSessions.create(
7226
+ sdkPayload
7227
+ );
7228
+ const responseValidation = checkoutSessionResponseSchema.safeParse(session);
7229
+ if (!responseValidation.success) {
7230
+ throw new Error(
7231
+ `Invalid checkout session response from API: ${responseValidation.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ")}`
7232
+ );
7233
+ }
7234
+ return responseValidation.data;
7235
+ } catch (error) {
7236
+ if (error instanceof Error) {
7237
+ console.error("Dodo Payments Checkout Session API Error:", {
7238
+ message: error.message,
7239
+ payload: validation.data,
7240
+ config: {
7241
+ environment: config.environment,
7242
+ hasBearerToken: !!config.bearerToken
7243
+ }
7244
+ });
7245
+ throw new Error(`Failed to create checkout session: ${error.message}`);
7246
+ }
7247
+ console.error("Unknown error creating checkout session:", error);
7248
+ throw new Error(
7249
+ "Failed to create checkout session due to an unknown error"
7250
+ );
7251
+ }
7252
+ };
7253
+ var buildCheckoutUrl = async ({
7254
+ queryParams,
7255
+ body,
7256
+ sessionPayload,
7257
+ returnUrl,
7258
+ bearerToken,
7259
+ environment,
7260
+ type = "static"
7261
+ }) => {
7262
+ if (type === "session") {
7263
+ if (!sessionPayload) {
7264
+ throw new Error("sessionPayload is required when type is 'session'");
7265
+ }
7266
+ const session = await createCheckoutSession(sessionPayload, {
7267
+ bearerToken,
7268
+ environment
7269
+ });
7270
+ return session.checkout_url;
7271
+ }
7272
+ const inputData = type === "dynamic" ? body : queryParams;
7273
+ let parseResult;
7274
+ if (type === "dynamic") {
7275
+ parseResult = dynamicCheckoutBodySchema.safeParse(inputData);
7276
+ } else {
7277
+ parseResult = checkoutQuerySchema.safeParse(inputData);
7278
+ }
7279
+ const { success, data, error } = parseResult;
7280
+ if (!success) {
7281
+ throw new Error(
7282
+ `Invalid ${type === "dynamic" ? "body" : "query parameters"}.
7283
+ ${error.message}`
7284
+ );
7285
+ }
7286
+ if (type !== "dynamic") {
7287
+ const {
7288
+ productId,
7289
+ quantity: quantity2,
7290
+ fullName,
7291
+ firstName,
7292
+ lastName,
7293
+ email,
7294
+ country,
7295
+ addressLine,
7296
+ city,
7297
+ state,
7298
+ zipCode,
7299
+ disableFullName,
7300
+ disableFirstName,
7301
+ disableLastName,
7302
+ disableEmail,
7303
+ disableCountry,
7304
+ disableAddressLine,
7305
+ disableCity,
7306
+ disableState,
7307
+ disableZipCode,
7308
+ paymentCurrency,
7309
+ showCurrencySelector,
7310
+ paymentAmount,
7311
+ showDiscounts
7312
+ // metadata handled below
7313
+ } = data;
7314
+ const dodopayments2 = new DodoPayments({
7315
+ bearerToken,
7316
+ environment
7317
+ });
7318
+ if (!productId) throw new Error("Missing required field: productId");
7319
+ try {
7320
+ await dodopayments2.products.retrieve(productId);
7321
+ } catch (err) {
7322
+ console.error(err);
7323
+ throw new Error("Product not found");
7324
+ }
7325
+ const url = new URL(
7326
+ `${environment === "test_mode" ? "https://test.checkout.dodopayments.com" : "https://checkout.dodopayments.com"}/buy/${productId}`
7327
+ );
7328
+ url.searchParams.set("quantity", quantity2 ? String(quantity2) : "1");
7329
+ if (returnUrl) url.searchParams.set("redirect_url", returnUrl);
7330
+ if (fullName) url.searchParams.set("fullName", String(fullName));
7331
+ if (firstName) url.searchParams.set("firstName", String(firstName));
7332
+ if (lastName) url.searchParams.set("lastName", String(lastName));
7333
+ if (email) url.searchParams.set("email", String(email));
7334
+ if (country) url.searchParams.set("country", String(country));
7335
+ if (addressLine) url.searchParams.set("addressLine", String(addressLine));
7336
+ if (city) url.searchParams.set("city", String(city));
7337
+ if (state) url.searchParams.set("state", String(state));
7338
+ if (zipCode) url.searchParams.set("zipCode", String(zipCode));
7339
+ if (disableFullName === "true")
7340
+ url.searchParams.set("disableFullName", "true");
7341
+ if (disableFirstName === "true")
7342
+ url.searchParams.set("disableFirstName", "true");
7343
+ if (disableLastName === "true")
7344
+ url.searchParams.set("disableLastName", "true");
7345
+ if (disableEmail === "true") url.searchParams.set("disableEmail", "true");
7346
+ if (disableCountry === "true")
7347
+ url.searchParams.set("disableCountry", "true");
7348
+ if (disableAddressLine === "true")
7349
+ url.searchParams.set("disableAddressLine", "true");
7350
+ if (disableCity === "true") url.searchParams.set("disableCity", "true");
7351
+ if (disableState === "true") url.searchParams.set("disableState", "true");
7352
+ if (disableZipCode === "true")
7353
+ url.searchParams.set("disableZipCode", "true");
7354
+ if (paymentCurrency)
7355
+ url.searchParams.set("paymentCurrency", String(paymentCurrency));
7356
+ if (showCurrencySelector)
7357
+ url.searchParams.set(
7358
+ "showCurrencySelector",
7359
+ String(showCurrencySelector)
7360
+ );
7361
+ if (paymentAmount)
7362
+ url.searchParams.set("paymentAmount", String(paymentAmount));
7363
+ if (showDiscounts)
7364
+ url.searchParams.set("showDiscounts", String(showDiscounts));
7365
+ for (const [key, value] of Object.entries(queryParams || {})) {
7366
+ if (key.startsWith("metadata_") && value && typeof value !== "object") {
7367
+ url.searchParams.set(key, String(value));
7368
+ }
7369
+ }
7370
+ return url.toString();
7371
+ }
7372
+ const dyn = data;
7373
+ const {
7374
+ product_id,
7375
+ product_cart,
7376
+ quantity,
7377
+ billing,
7378
+ customer,
7379
+ addons,
7380
+ metadata,
7381
+ allowed_payment_method_types,
7382
+ billing_currency,
7383
+ discount_code,
7384
+ on_demand,
7385
+ return_url: bodyReturnUrl,
7386
+ show_saved_payment_methods,
7387
+ tax_id,
7388
+ trial_period_days
7389
+ } = dyn;
7390
+ const dodopayments = new DodoPayments({
7391
+ bearerToken,
7392
+ environment
7393
+ });
7394
+ let isSubscription = false;
7395
+ let productIdToFetch = product_id;
7396
+ if (!product_id && product_cart && product_cart.length > 0) {
7397
+ productIdToFetch = product_cart[0].product_id;
7398
+ }
7399
+ if (!productIdToFetch)
7400
+ throw new Error(
7401
+ "Missing required field: product_id or product_cart[0].product_id"
7402
+ );
7403
+ let product;
7404
+ try {
7405
+ product = await dodopayments.products.retrieve(productIdToFetch);
7406
+ } catch (err) {
7407
+ console.error(err);
7408
+ throw new Error("Product not found");
7409
+ }
7410
+ isSubscription = Boolean(product.is_recurring);
7411
+ if (isSubscription && !product_id)
7412
+ throw new Error("Missing required field: product_id for subscription");
7413
+ if (!billing) throw new Error("Missing required field: billing");
7414
+ if (!customer) throw new Error("Missing required field: customer");
7415
+ if (isSubscription) {
7416
+ const subscriptionPayload = {
7417
+ billing,
7418
+ customer,
7419
+ product_id,
7420
+ quantity: quantity ? Number(quantity) : 1
7421
+ };
7422
+ if (metadata) subscriptionPayload.metadata = metadata;
7423
+ if (discount_code) subscriptionPayload.discount_code = discount_code;
7424
+ if (addons) subscriptionPayload.addons = addons;
7425
+ if (allowed_payment_method_types)
7426
+ subscriptionPayload.allowed_payment_method_types = allowed_payment_method_types;
7427
+ if (billing_currency)
7428
+ subscriptionPayload.billing_currency = billing_currency;
7429
+ if (on_demand) subscriptionPayload.on_demand = on_demand;
7430
+ subscriptionPayload.payment_link = true;
7431
+ if (bodyReturnUrl) {
7432
+ subscriptionPayload.return_url = bodyReturnUrl;
7433
+ } else if (returnUrl) {
7434
+ subscriptionPayload.return_url = returnUrl;
7435
+ }
7436
+ if (show_saved_payment_methods)
7437
+ subscriptionPayload.show_saved_payment_methods = show_saved_payment_methods;
7438
+ if (tax_id) subscriptionPayload.tax_id = tax_id;
7439
+ if (trial_period_days)
7440
+ subscriptionPayload.trial_period_days = trial_period_days;
7441
+ let subscription;
7442
+ try {
7443
+ subscription = await dodopayments.subscriptions.create(subscriptionPayload);
7444
+ } catch (err) {
7445
+ console.error("Error when creating subscription", err);
7446
+ throw new Error(err instanceof Error ? err.message : String(err));
7471
7447
  }
7472
- }
7473
- var WebhookVerificationError_1 = dist.WebhookVerificationError = WebhookVerificationError;
7474
- class Webhook {
7475
- constructor(secret, options) {
7476
- if (!secret) {
7477
- throw new Error("Secret can't be empty.");
7448
+ if (!subscription || !subscription.payment_link) {
7449
+ throw new Error(
7450
+ "No payment link returned from Dodo Payments API (subscription). Make sure to set payment_link as true in payload"
7451
+ );
7452
+ }
7453
+ return subscription.payment_link;
7454
+ } else {
7455
+ let cart = product_cart;
7456
+ if (!cart && product_id) {
7457
+ cart = [
7458
+ { product_id, quantity: quantity ? Number(quantity) : 1 }
7459
+ ];
7460
+ }
7461
+ if (!cart || cart.length === 0)
7462
+ throw new Error("Missing required field: product_cart or product_id");
7463
+ const paymentPayload = {
7464
+ billing,
7465
+ customer,
7466
+ product_cart: cart
7467
+ };
7468
+ if (metadata) paymentPayload.metadata = metadata;
7469
+ paymentPayload.payment_link = true;
7470
+ if (allowed_payment_method_types)
7471
+ paymentPayload.allowed_payment_method_types = allowed_payment_method_types;
7472
+ if (billing_currency) paymentPayload.billing_currency = billing_currency;
7473
+ if (discount_code) paymentPayload.discount_code = discount_code;
7474
+ if (bodyReturnUrl) {
7475
+ paymentPayload.return_url = bodyReturnUrl;
7476
+ } else if (returnUrl) {
7477
+ paymentPayload.return_url = returnUrl;
7478
+ }
7479
+ if (show_saved_payment_methods)
7480
+ paymentPayload.show_saved_payment_methods = show_saved_payment_methods;
7481
+ if (tax_id) paymentPayload.tax_id = tax_id;
7482
+ let payment;
7483
+ try {
7484
+ payment = await dodopayments.payments.create(paymentPayload);
7485
+ } catch (err) {
7486
+ console.error("Error when creating payment link", err);
7487
+ throw new Error(err instanceof Error ? err.message : String(err));
7488
+ }
7489
+ if (!payment || !payment.payment_link) {
7490
+ throw new Error(
7491
+ "No payment link returned from Dodo Payments API. Make sure to set payment_link as true in payload."
7492
+ );
7493
+ }
7494
+ return payment.payment_link;
7495
+ }
7496
+ };
7497
+
7498
+ function checkoutHandler(config) {
7499
+ const getHandler = async (req, res) => {
7500
+ const queryParams = req.query;
7501
+ if (!queryParams.productId) {
7502
+ return res.status(400).send("Please provide productId query parameter");
7478
7503
  }
7479
- if ((options === null || options === void 0 ? void 0 : options.format) === "raw") {
7480
- if (secret instanceof Uint8Array) {
7481
- this.key = secret;
7482
- }
7483
- else {
7484
- this.key = Uint8Array.from(secret, (c) => c.charCodeAt(0));
7504
+ const { success, data, error } = checkoutQuerySchema.safeParse(queryParams);
7505
+ if (!success) {
7506
+ if (error.errors.some((e) => e.path.toString() === "productId")) {
7507
+ return res.status(400).send("Please provide productId query parameter");
7485
7508
  }
7509
+ return res
7510
+ .status(400)
7511
+ .send(`Invalid query parameters.\n ${error.message}`);
7486
7512
  }
7487
- else {
7488
- if (typeof secret !== "string") {
7489
- throw new Error("Expected secret to be of type string");
7490
- }
7491
- if (secret.startsWith(Webhook.prefix)) {
7492
- secret = secret.substring(Webhook.prefix.length);
7493
- }
7494
- this.key = base64.decode(secret);
7513
+ let url = "";
7514
+ try {
7515
+ url = await buildCheckoutUrl({ queryParams: data, ...config });
7495
7516
  }
7496
- }
7497
- verify(payload, headers_) {
7498
- const headers = {};
7499
- for (const key of Object.keys(headers_)) {
7500
- headers[key.toLowerCase()] = headers_[key];
7517
+ catch (error) {
7518
+ return res.status(400).send(error.message);
7501
7519
  }
7502
- const msgId = headers["webhook-id"];
7503
- const msgSignature = headers["webhook-signature"];
7504
- const msgTimestamp = headers["webhook-timestamp"];
7505
- if (!msgSignature || !msgId || !msgTimestamp) {
7506
- throw new WebhookVerificationError("Missing required headers");
7520
+ return res.json({ checkout_url: url });
7521
+ };
7522
+ const postHandler = async (req, res) => {
7523
+ if (config.type === "dynamic") {
7524
+ // Handle dynamic checkout
7525
+ const { success, data, error } = dynamicCheckoutBodySchema.safeParse(req.body);
7526
+ if (!success) {
7527
+ return res.status(400).send(`Invalid request body.\n ${error.message}`);
7528
+ }
7529
+ let url = "";
7530
+ try {
7531
+ url = await buildCheckoutUrl({
7532
+ body: data,
7533
+ ...config,
7534
+ type: "dynamic",
7535
+ });
7536
+ }
7537
+ catch (error) {
7538
+ return res.status(400).send(error.message);
7539
+ }
7540
+ return res.json({ checkout_url: url });
7507
7541
  }
7508
- const timestamp = this.verifyTimestamp(msgTimestamp);
7509
- const computedSignature = this.sign(msgId, timestamp, payload);
7510
- const expectedSignature = computedSignature.split(",")[1];
7511
- const passedSignatures = msgSignature.split(" ");
7512
- const encoder = new globalThis.TextEncoder();
7513
- for (const versionedSignature of passedSignatures) {
7514
- const [version, signature] = versionedSignature.split(",");
7515
- if (version !== "v1") {
7516
- continue;
7542
+ else {
7543
+ // Handle checkout session
7544
+ const { success, data, error } = checkoutSessionPayloadSchema.safeParse(req.body);
7545
+ if (!success) {
7546
+ return res
7547
+ .status(400)
7548
+ .send(`Invalid checkout session payload.\n ${error.message}`);
7517
7549
  }
7518
- if ((0, timing_safe_equal_1.timingSafeEqual)(encoder.encode(signature), encoder.encode(expectedSignature))) {
7519
- return JSON.parse(payload.toString());
7550
+ let url = "";
7551
+ try {
7552
+ url = await buildCheckoutUrl({
7553
+ sessionPayload: data,
7554
+ ...config,
7555
+ type: "session",
7556
+ });
7557
+ }
7558
+ catch (error) {
7559
+ return res.status(400).send(error.message);
7520
7560
  }
7561
+ return res.json({ checkout_url: url });
7521
7562
  }
7522
- throw new WebhookVerificationError("No matching signature found");
7523
- }
7524
- sign(msgId, timestamp, payload) {
7525
- if (typeof payload === "string") ;
7526
- else if (payload.constructor.name === "Buffer") {
7527
- payload = payload.toString();
7563
+ };
7564
+ return (req, res) => {
7565
+ if (req.method === "POST") {
7566
+ return postHandler(req, res);
7528
7567
  }
7529
- else {
7530
- throw new Error("Expected payload to be of type string or Buffer.");
7568
+ if (req.method === "GET") {
7569
+ return getHandler(req, res);
7531
7570
  }
7532
- const encoder = new TextEncoder();
7533
- const timestampNumber = Math.floor(timestamp.getTime() / 1000);
7534
- const toSign = encoder.encode(`${msgId}.${timestampNumber}.${payload}`);
7535
- const expectedSignature = base64.encode(sha256.hmac(this.key, toSign));
7536
- return `v1,${expectedSignature}`;
7537
- }
7538
- verifyTimestamp(timestampHeader) {
7539
- const now = Math.floor(Date.now() / 1000);
7540
- const timestamp = parseInt(timestampHeader, 10);
7541
- if (isNaN(timestamp)) {
7542
- throw new WebhookVerificationError("Invalid Signature Headers");
7571
+ return res.status(405).send("Method Not Allowed");
7572
+ };
7573
+ }
7574
+
7575
+ const CustomerPortal = ({ bearerToken, environment, }) => {
7576
+ const getHandler = async (req, res) => {
7577
+ // Extract customerId from query parameters
7578
+ const { customer_id: customerId, send_email } = req.query;
7579
+ const params = {
7580
+ send_email: false,
7581
+ };
7582
+ const sendEmail = Boolean(send_email);
7583
+ if (sendEmail) {
7584
+ params.send_email = sendEmail;
7543
7585
  }
7544
- if (now - timestamp > WEBHOOK_TOLERANCE_IN_SECONDS) {
7545
- throw new WebhookVerificationError("Message timestamp too old");
7586
+ if (!customerId) {
7587
+ return res.status(400).send("Missing customerId in query parameters");
7546
7588
  }
7547
- if (timestamp > now + WEBHOOK_TOLERANCE_IN_SECONDS) {
7548
- throw new WebhookVerificationError("Message timestamp too new");
7589
+ const dodopayments = new DodoPayments({
7590
+ bearerToken,
7591
+ environment,
7592
+ });
7593
+ try {
7594
+ const session = await dodopayments.customers.customerPortal.create(customerId, params);
7595
+ return res.redirect(session.link);
7549
7596
  }
7550
- return new Date(timestamp * 1000);
7551
- }
7552
- }
7553
- Webhook_1 = dist.Webhook = Webhook;
7554
- Webhook.prefix = "whsec_";
7597
+ catch (error) {
7598
+ console.error("Error creating customer portal session:", error);
7599
+ return res
7600
+ .status(500)
7601
+ .send(`Failed to create customer portal session: ${error.message}`);
7602
+ }
7603
+ };
7604
+ return getHandler;
7605
+ };
7555
7606
 
7556
7607
  // src/schemas/webhook.ts
7557
7608
  var PaymentSchema = objectType({