@internetarchive/donation-form 0.5.9 → 0.5.10

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.
@@ -1,6 +1,7 @@
1
1
  import { __awaiter } from "tslib";
2
2
  import { PromisedSingleton } from '@internetarchive/promised-singleton';
3
3
  import { createNanoEvents } from 'nanoevents';
4
+ import { DonationFormError } from '../../../donation-form-error';
4
5
  export class CreditCardHandler {
5
6
  constructor(options) {
6
7
  var _a, _b;
@@ -38,18 +39,30 @@ export class CreditCardHandler {
38
39
  let timeout;
39
40
  const timeoutPromise = new Promise((resolve, reject) => {
40
41
  timeout = window.setTimeout(() => {
41
- reject(new Error('Timeout loading Hosted Fields'));
42
+ const error = new DonationFormError('Timeout loading Hosted Fields');
43
+ reject(error);
42
44
  }, this.loadTimeout);
43
45
  });
44
- const hostedFieldsPromise = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
45
- const fields = yield this.hostedFieldClient.create({
46
- client: braintreeClient,
47
- styles: this.hostedFieldConfig.hostedFieldStyle,
48
- fields: this.hostedFieldConfig.hostedFieldFieldOptions,
49
- });
50
- // clear the timeout when this finishes so we don't also get the timeout rejection
51
- window.clearTimeout(timeout);
52
- resolve(fields);
46
+ const hostedFieldsPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
47
+ try {
48
+ const fields = yield this.hostedFieldClient.create({
49
+ client: braintreeClient,
50
+ styles: this.hostedFieldConfig.hostedFieldStyle,
51
+ fields: this.hostedFieldConfig.hostedFieldFieldOptions,
52
+ });
53
+ // clear the timeout when this finishes so we don't also get the timeout rejection
54
+ window.clearTimeout(timeout);
55
+ resolve(fields);
56
+ }
57
+ catch (error) {
58
+ if (error instanceof Error && error.message.includes('Hosted Fields timed out')) {
59
+ // this is the timeout error, so we don't need to do anything
60
+ }
61
+ else {
62
+ // this is some other error. reject so it bubbles up to Sentry
63
+ reject(error);
64
+ }
65
+ }
53
66
  }));
54
67
  const result = yield Promise.race([timeoutPromise, hostedFieldsPromise]);
55
68
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"credit-card.js","sourceRoot":"","sources":["../../../../../src/braintree-manager/payment-providers/credit-card/credit-card.ts"],"names":[],"mappings":"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","sourcesContent":["import { PromisedSingleton } from '@internetarchive/promised-singleton';\nimport { BraintreeManagerInterface } from '../../braintree-interfaces';\nimport { HostedFieldConfiguration } from './hosted-field-configuration';\nimport { HostedFieldName } from './hosted-field-container';\nimport { CreditCardHandlerEvents, CreditCardHandlerInterface } from './credit-card-interface';\nimport { createNanoEvents, Unsubscribe } from 'nanoevents';\n\nexport class CreditCardHandler implements CreditCardHandlerInterface {\n on<E extends keyof CreditCardHandlerEvents>(\n event: E,\n callback: CreditCardHandlerEvents[E],\n ): Unsubscribe {\n return this.emitter.on(event, callback);\n }\n\n instance = new PromisedSingleton<braintree.HostedFields | undefined>({\n generator: async (): Promise<braintree.HostedFields | undefined> => {\n const braintreeClient = await this.braintreeManager.instance.get();\n const hostedFields = await this.createHostedFields(braintreeClient);\n return hostedFields;\n },\n });\n\n private emitter = createNanoEvents<CreditCardHandlerEvents>();\n\n private maxRetryCount: number;\n\n private loadTimeout: number;\n\n constructor(options: {\n braintreeManager: BraintreeManagerInterface;\n hostedFieldClient: braintree.HostedFields;\n hostedFieldConfig: HostedFieldConfiguration;\n maxRetryCount?: number;\n loadTimeout?: number;\n }) {\n this.braintreeManager = options.braintreeManager;\n this.hostedFieldClient = options.hostedFieldClient;\n this.hostedFieldConfig = options.hostedFieldConfig;\n this.maxRetryCount = options.maxRetryCount ?? 2;\n this.loadTimeout = (options.loadTimeout ?? 6) * 1000;\n }\n\n private braintreeManager: BraintreeManagerInterface;\n private hostedFieldClient: braintree.HostedFields;\n private hostedFieldConfig: HostedFieldConfiguration;\n\n private async createHostedFields(\n braintreeClient: braintree.Client,\n retryCount = 0,\n ): Promise<braintree.HostedFields | undefined> {\n // we mainly want to do this for retry events, but it doesn't\n // hurt to do it on the first try\n this.hostedFieldConfig.hostedFieldContainer.resetHostedFields();\n try {\n // The hosted fields have a 60 second timeout internally, but braintree\n // support recommended setting a shorter timeout because 99% of users\n // load the hosted fields in under 4 seconds and 99.9% with 18 seconds.\n // What we're doing here is creating a \"timeout\" promise\n // and a \"create hosted fields\" promise and doing a `Promise.race()` to\n // resolve when the first one finishes. If the timeout finishes first,\n // we throw an error to trigger the retry logic. If the hosted fields\n // finishes first, we cancel the timeout promise since we're done.\n let timeout: number;\n const timeoutPromise = new Promise<void>((resolve, reject) => {\n timeout = window.setTimeout(() => {\n reject(new Error('Timeout loading Hosted Fields'));\n }, this.loadTimeout);\n });\n\n const hostedFieldsPromise = new Promise<braintree.HostedFields | undefined>(async resolve => {\n const fields = await this.hostedFieldClient.create({\n client: braintreeClient,\n styles: this.hostedFieldConfig.hostedFieldStyle,\n fields: this.hostedFieldConfig.hostedFieldFieldOptions,\n });\n // clear the timeout when this finishes so we don't also get the timeout rejection\n window.clearTimeout(timeout);\n resolve(fields);\n });\n\n const result = await Promise.race([timeoutPromise, hostedFieldsPromise]);\n\n return result as braintree.HostedFields;\n } catch (error) {\n if (retryCount >= this.maxRetryCount) {\n this.emitter.emit('hostedFieldsFailed', error);\n throw error;\n }\n const newRetryCount = retryCount + 1;\n this.emitter.emit('hostedFieldsRetry', newRetryCount);\n return this.createHostedFields(braintreeClient, newRetryCount);\n }\n }\n\n async tokenizeHostedFields(): Promise<braintree.HostedFieldsTokenizePayload | undefined> {\n const hostedFields = await this.instance.get();\n return hostedFields?.tokenize();\n }\n\n markFieldErrors(fields: HostedFieldName[]): void {\n this.hostedFieldConfig.hostedFieldContainer.markFieldErrors(fields);\n }\n\n removeFieldErrors(fields: HostedFieldName[]): void {\n this.hostedFieldConfig.hostedFieldContainer.removeFieldErrors(fields);\n }\n\n showErrorMessage(message?: string): void {\n this.hostedFieldConfig.hostedFieldContainer.showErrorMessage(message);\n }\n\n hideErrorMessage(): void {\n this.hostedFieldConfig.hostedFieldContainer.hideErrorMessage();\n }\n}\n"]}
1
+ {"version":3,"file":"credit-card.js","sourceRoot":"","sources":["../../../../../src/braintree-manager/payment-providers/credit-card/credit-card.ts"],"names":[],"mappings":"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","sourcesContent":["import { PromisedSingleton } from '@internetarchive/promised-singleton';\nimport { BraintreeManagerInterface } from '../../braintree-interfaces';\nimport { HostedFieldConfiguration } from './hosted-field-configuration';\nimport { HostedFieldName } from './hosted-field-container';\nimport { CreditCardHandlerEvents, CreditCardHandlerInterface } from './credit-card-interface';\nimport { createNanoEvents, Unsubscribe } from 'nanoevents';\nimport { DonationFormError } from '../../../donation-form-error';\n\nexport class CreditCardHandler implements CreditCardHandlerInterface {\n on<E extends keyof CreditCardHandlerEvents>(\n event: E,\n callback: CreditCardHandlerEvents[E],\n ): Unsubscribe {\n return this.emitter.on(event, callback);\n }\n\n instance = new PromisedSingleton<braintree.HostedFields | undefined>({\n generator: async (): Promise<braintree.HostedFields | undefined> => {\n const braintreeClient = await this.braintreeManager.instance.get();\n const hostedFields = await this.createHostedFields(braintreeClient);\n return hostedFields;\n },\n });\n\n private emitter = createNanoEvents<CreditCardHandlerEvents>();\n\n private maxRetryCount: number;\n\n private loadTimeout: number;\n\n constructor(options: {\n braintreeManager: BraintreeManagerInterface;\n hostedFieldClient: braintree.HostedFields;\n hostedFieldConfig: HostedFieldConfiguration;\n maxRetryCount?: number;\n loadTimeout?: number;\n }) {\n this.braintreeManager = options.braintreeManager;\n this.hostedFieldClient = options.hostedFieldClient;\n this.hostedFieldConfig = options.hostedFieldConfig;\n this.maxRetryCount = options.maxRetryCount ?? 2;\n this.loadTimeout = (options.loadTimeout ?? 6) * 1000;\n }\n\n private braintreeManager: BraintreeManagerInterface;\n private hostedFieldClient: braintree.HostedFields;\n private hostedFieldConfig: HostedFieldConfiguration;\n\n private async createHostedFields(\n braintreeClient: braintree.Client,\n retryCount = 0,\n ): Promise<braintree.HostedFields | undefined> {\n // we mainly want to do this for retry events, but it doesn't\n // hurt to do it on the first try\n this.hostedFieldConfig.hostedFieldContainer.resetHostedFields();\n try {\n // The hosted fields have a 60 second timeout internally, but braintree\n // support recommended setting a shorter timeout because 99% of users\n // load the hosted fields in under 4 seconds and 99.9% with 18 seconds.\n // What we're doing here is creating a \"timeout\" promise\n // and a \"create hosted fields\" promise and doing a `Promise.race()` to\n // resolve when the first one finishes. If the timeout finishes first,\n // we throw an error to trigger the retry logic. If the hosted fields\n // finishes first, we cancel the timeout promise since we're done.\n let timeout: number;\n\n const timeoutPromise = new Promise<void>((resolve, reject) => {\n timeout = window.setTimeout(() => {\n const error = new DonationFormError('Timeout loading Hosted Fields');\n reject(error);\n }, this.loadTimeout);\n });\n\n const hostedFieldsPromise = new Promise<braintree.HostedFields | undefined>(\n async (resolve, reject) => {\n try {\n const fields = await this.hostedFieldClient.create({\n client: braintreeClient,\n styles: this.hostedFieldConfig.hostedFieldStyle,\n fields: this.hostedFieldConfig.hostedFieldFieldOptions,\n });\n // clear the timeout when this finishes so we don't also get the timeout rejection\n window.clearTimeout(timeout);\n resolve(fields);\n } catch (error) {\n if (error instanceof Error && error.message.includes('Hosted Fields timed out')) {\n // this is the timeout error, so we don't need to do anything\n } else {\n // this is some other error. reject so it bubbles up to Sentry\n reject(error);\n }\n }\n },\n );\n\n const result = await Promise.race([timeoutPromise, hostedFieldsPromise]);\n\n return result as braintree.HostedFields;\n } catch (error) {\n if (retryCount >= this.maxRetryCount) {\n this.emitter.emit('hostedFieldsFailed', error);\n throw error;\n }\n const newRetryCount = retryCount + 1;\n this.emitter.emit('hostedFieldsRetry', newRetryCount);\n return this.createHostedFields(braintreeClient, newRetryCount);\n }\n }\n\n async tokenizeHostedFields(): Promise<braintree.HostedFieldsTokenizePayload | undefined> {\n const hostedFields = await this.instance.get();\n return hostedFields?.tokenize();\n }\n\n markFieldErrors(fields: HostedFieldName[]): void {\n this.hostedFieldConfig.hostedFieldContainer.markFieldErrors(fields);\n }\n\n removeFieldErrors(fields: HostedFieldName[]): void {\n this.hostedFieldConfig.hostedFieldContainer.removeFieldErrors(fields);\n }\n\n showErrorMessage(message?: string): void {\n this.hostedFieldConfig.hostedFieldContainer.showErrorMessage(message);\n }\n\n hideErrorMessage(): void {\n this.hostedFieldConfig.hostedFieldContainer.hideErrorMessage();\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export declare class DonationFormError extends Error {
2
+ constructor(message: string);
3
+ }
@@ -0,0 +1,7 @@
1
+ export class DonationFormError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'DonationFormError';
5
+ }
6
+ }
7
+ //# sourceMappingURL=donation-form-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"donation-form-error.js","sourceRoot":"","sources":["../../src/donation-form-error.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF","sourcesContent":["export class DonationFormError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'DonationFormError';\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/donation-form",
3
- "version": "0.5.9",
3
+ "version": "0.5.10",
4
4
  "description": "The Internet Archive Donation Form",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "dist/index.js",
@@ -4,6 +4,7 @@ import { HostedFieldConfiguration } from './hosted-field-configuration';
4
4
  import { HostedFieldName } from './hosted-field-container';
5
5
  import { CreditCardHandlerEvents, CreditCardHandlerInterface } from './credit-card-interface';
6
6
  import { createNanoEvents, Unsubscribe } from 'nanoevents';
7
+ import { DonationFormError } from '../../../donation-form-error';
7
8
 
8
9
  export class CreditCardHandler implements CreditCardHandlerInterface {
9
10
  on<E extends keyof CreditCardHandlerEvents>(
@@ -62,22 +63,35 @@ export class CreditCardHandler implements CreditCardHandlerInterface {
62
63
  // we throw an error to trigger the retry logic. If the hosted fields
63
64
  // finishes first, we cancel the timeout promise since we're done.
64
65
  let timeout: number;
66
+
65
67
  const timeoutPromise = new Promise<void>((resolve, reject) => {
66
68
  timeout = window.setTimeout(() => {
67
- reject(new Error('Timeout loading Hosted Fields'));
69
+ const error = new DonationFormError('Timeout loading Hosted Fields');
70
+ reject(error);
68
71
  }, this.loadTimeout);
69
72
  });
70
73
 
71
- const hostedFieldsPromise = new Promise<braintree.HostedFields | undefined>(async resolve => {
72
- const fields = await this.hostedFieldClient.create({
73
- client: braintreeClient,
74
- styles: this.hostedFieldConfig.hostedFieldStyle,
75
- fields: this.hostedFieldConfig.hostedFieldFieldOptions,
76
- });
77
- // clear the timeout when this finishes so we don't also get the timeout rejection
78
- window.clearTimeout(timeout);
79
- resolve(fields);
80
- });
74
+ const hostedFieldsPromise = new Promise<braintree.HostedFields | undefined>(
75
+ async (resolve, reject) => {
76
+ try {
77
+ const fields = await this.hostedFieldClient.create({
78
+ client: braintreeClient,
79
+ styles: this.hostedFieldConfig.hostedFieldStyle,
80
+ fields: this.hostedFieldConfig.hostedFieldFieldOptions,
81
+ });
82
+ // clear the timeout when this finishes so we don't also get the timeout rejection
83
+ window.clearTimeout(timeout);
84
+ resolve(fields);
85
+ } catch (error) {
86
+ if (error instanceof Error && error.message.includes('Hosted Fields timed out')) {
87
+ // this is the timeout error, so we don't need to do anything
88
+ } else {
89
+ // this is some other error. reject so it bubbles up to Sentry
90
+ reject(error);
91
+ }
92
+ }
93
+ },
94
+ );
81
95
 
82
96
  const result = await Promise.race([timeoutPromise, hostedFieldsPromise]);
83
97
 
@@ -0,0 +1,6 @@
1
+ export class DonationFormError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = 'DonationFormError';
5
+ }
6
+ }