@getopenpay/openpay-js 0.1.14 → 0.1.16-alpha.d3a4efb

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.d.ts CHANGED
@@ -1,6 +1,21 @@
1
1
  import { PaymentRequest as PaymentRequest_2 } from '@stripe/stripe-js';
2
+ import { Subject } from 'rxjs';
2
3
  import { z } from 'zod';
3
4
 
5
+ declare type AllCallbacks = {
6
+ onFocus?: (elementId: string, field: AllFieldNames) => void;
7
+ onBlur?: (elementId: string, field: AllFieldNames) => void;
8
+ onChange?: (elementId: string, field: AllFieldNames, errors?: string[]) => void;
9
+ onLoad?: (totalAmountAtoms?: number, currency?: string) => void;
10
+ onLoadError?: (message: string) => void;
11
+ onValidationError?: OnValidationError;
12
+ onCheckoutStarted?: OnCheckoutStarted;
13
+ onCheckoutSuccess?: OnCheckoutSuccess;
14
+ onSetupPaymentMethodSuccess?: OnSetupPaymentMethodSuccess;
15
+ onCheckoutError?: OnCheckoutError;
16
+ onPaymentRequestLoad?: (paymentRequests: PRStatuses) => void;
17
+ };
18
+
4
19
  declare const AllFieldNames = z.union([FieldNameEnum, PrivateFieldNameEnum]);
5
20
 
6
21
  declare type AllFieldNames = z.infer<typeof AllFieldNames>;
@@ -34,17 +49,9 @@ declare const CheckoutPaymentMethod = z.object({
34
49
 
35
50
  declare type CheckoutPaymentMethod = z.infer<typeof CheckoutPaymentMethod>;
36
51
 
37
- export declare type Config = ElementsFormProps & {
38
- _frameUrl?: URL;
39
- };
52
+ export declare type Config = ElementsFormProps & AllCallbacks;
40
53
 
41
- declare class ConnectionManager {
42
- private connections;
43
- constructor();
44
- addConnection(id: ElementType, connection: CdeConnection): void;
45
- getConnection(): CdeConnection;
46
- getAllConnections(): Map<ElementType, CdeConnection>;
47
- }
54
+ declare type CurrentStatus<T> = InitialStatus | SuccessStatus<T> | ErrorStatus;
48
55
 
49
56
  declare type CustomInitParams = {
50
57
  stripeLink?: {
@@ -78,19 +85,8 @@ declare type ElementProps<PlaceholderType extends z.ZodTypeAny = z.ZodString> =
78
85
  export declare type ElementsFormProps = {
79
86
  className?: string;
80
87
  checkoutSecureToken: string;
81
- onFocus?: (elementId: string, field: AllFieldNames) => void;
82
- onBlur?: (elementId: string, field: AllFieldNames) => void;
83
- onChange?: (elementId: string, field: AllFieldNames, errors?: string[]) => void;
84
- onLoad?: (totalAmountAtoms?: number, currency?: string) => void;
85
- onLoadError?: (message: string) => void;
86
- onValidationError?: (field: AllFieldNames, errors: string[], elementId?: string) => void;
87
- onCheckoutStarted?: () => void;
88
- onCheckoutSuccess?: (invoiceUrls: string[], subscriptionIds: string[], customerId: string) => void;
89
- onSetupPaymentMethodSuccess?: (paymentMethodId: string) => void;
90
- onCheckoutError?: (message: string) => void;
91
88
  baseUrl?: string;
92
89
  formTarget?: string;
93
- onPaymentRequestLoad?: (paymentRequests: Record<PaymentRequestProvider, PaymentRequestStatus>) => void;
94
90
  customInitParams?: CustomInitParams;
95
91
  };
96
92
 
@@ -124,6 +120,13 @@ declare enum ElementTypeEnum {
124
120
 
125
121
  declare type ElementTypeEnumValue = ElementTypeEnum[keyof ElementTypeEnum];
126
122
 
123
+ declare type ErrorStatus = {
124
+ status: 'error';
125
+ isSuccess: false;
126
+ error: unknown; // Anything can be thrown, so we don't want to be strict here
127
+ errMsg: string;
128
+ };
129
+
127
130
  /**
128
131
  * Expected input fields
129
132
  */
@@ -142,6 +145,55 @@ export declare enum FieldName {
142
145
  PROMOTION_CODE = 'promotionCode',
143
146
  }
144
147
 
148
+ declare class FormCallbacks {
149
+ private static readonly NOOP = () => {};
150
+ private _callbacks: Required<AllCallbacks>;
151
+
152
+ constructor() {
153
+ this._callbacks = FormCallbacks.createEmptyCallbacks();
154
+ }
155
+
156
+ private static createEmptyCallbacks = (): Required<AllCallbacks> => {
157
+ const x: AllCallbacks = {};
158
+ Object.keys(ZodFormCallbacks.keyof().enum).forEach((key) => {
159
+ // @ts-expect-error - trust the process
160
+ x[key] = FormCallbacks.NOOP;
161
+ });
162
+ return x as Required<AllCallbacks>;
163
+ };
164
+
165
+ static fromObject = (obj: unknown) => {
166
+ const instance = new FormCallbacks();
167
+ instance.setCallbacks(ZodFormCallbacks.parse(obj));
168
+ return instance;
169
+ };
170
+
171
+ /**
172
+ * Sets ALL form callbacks. Note that all old callbacks are removed.
173
+ */
174
+ setCallbacks = (rawCallbacks: AllCallbacks) => {
175
+ // Making sure to reinitialize
176
+ this._callbacks = FormCallbacks.createEmptyCallbacks();
177
+ Object.entries(rawCallbacks).forEach(([key, rawCallback]) => {
178
+ const safeCallback = makeCallbackSafe(key, rawCallback ?? FormCallbacks.NOOP, err__);
179
+ // @ts-expect-error - trust the process
180
+ this._callbacks[key] = safeCallback;
181
+ });
182
+ };
183
+
184
+ /**
185
+ * Returns a read-only version of the callbacks object.
186
+ */
187
+ get get() {
188
+ return { ...this._callbacks };
189
+ }
190
+ }
191
+
192
+ declare type InitialStatus = {
193
+ status: 'initial';
194
+ isSuccess: false;
195
+ };
196
+
145
197
  declare type InitOjsFlow<T extends InitOjsFlowResult> = (params: InitOjsFlowParams) => Promise<T>;
146
198
 
147
199
  declare type InitOjsFlowParams = {
@@ -154,13 +206,22 @@ declare type InitOjsFlowParams = {
154
206
  /**
155
207
  * Lifecycle callbacks for OJS flows.
156
208
  */
157
- flowCallbacks: OjsFlowCallbacks;
209
+ formCallbacks: FormCallbacks;
158
210
  };
159
211
 
160
212
  declare type InitOjsFlowResult = {
161
213
  isAvailable: boolean;
162
214
  };
163
215
 
216
+ declare type InitStripeLinkFlowResult =
217
+ | {
218
+ isAvailable: true;
219
+ controller: StripeLinkController;
220
+ }
221
+ | {
222
+ isAvailable: false;
223
+ };
224
+
164
225
  declare type InitStripePrFlowResult =
165
226
  | InitStripePrFlowSuccess
166
227
  | {
@@ -179,19 +240,6 @@ declare type InitStripePrFlowSuccess = {
179
240
  };
180
241
  };
181
242
 
182
- declare type Loadable<T> =
183
- | {
184
- status: 'loading';
185
- }
186
- | {
187
- status: 'loaded';
188
- result: T;
189
- }
190
- | {
191
- status: 'error';
192
- message: string;
193
- };
194
-
195
243
  declare const LoadedEventPayload = z.object({
196
244
  type: z.literal(EventType.enum.LOADED),
197
245
  sessionId: RequiredString,
@@ -202,6 +250,95 @@ declare const LoadedEventPayload = z.object({
202
250
 
203
251
  declare type LoadedEventPayload = z.infer<typeof LoadedEventPayload>;
204
252
 
253
+ declare class LoadedOncePublisher<T> {
254
+ private _current: CurrentStatus<T>;
255
+ private _subject: Subject<T>;
256
+
257
+ constructor() {
258
+ this._current = { status: 'initial', isSuccess: false };
259
+ this._subject = new Subject<T>();
260
+ }
261
+
262
+ set = (value: T) => {
263
+ if (this._current.status === 'success') {
264
+ throw new Error('LoadedOnce is already in success state');
265
+ }
266
+ this._current = { status: 'success', isSuccess: true, loadedValue: value };
267
+ this._subject.next(value);
268
+ this._subject.complete();
269
+ };
270
+
271
+ throw = (error: unknown, errMsg: string) => {
272
+ if (this._current.status === 'success') {
273
+ throw new Error('LoadedOnce is already in success state');
274
+ }
275
+ this._current = { status: 'error', isSuccess: false, error, errMsg };
276
+ this._subject.error(error);
277
+ // Do not complete the subject since a set() call might be made after this
278
+ };
279
+
280
+ get current() {
281
+ return this._current;
282
+ }
283
+
284
+ getValueIfLoadedElse = <T_ELSE>(valueIfNotLoaded: T_ELSE): T | T_ELSE => {
285
+ if (this._current.status === 'success') return this._current.loadedValue;
286
+ return valueIfNotLoaded;
287
+ };
288
+
289
+ subscribe = (fn: (value: Exclude<CurrentStatus<T>, InitialStatus>) => void) => {
290
+ if (this._current.status === 'success') {
291
+ fn(this._current);
292
+ return;
293
+ }
294
+
295
+ if (this._current.status === 'error') {
296
+ fn(this._current);
297
+ // Do not return, as we will still have the fn subscribed to the subject
298
+ }
299
+
300
+ const subscription = this._subject.subscribe({
301
+ next: () => {
302
+ if (this._current.status !== 'success') {
303
+ throw new Error('Invalid state (next): please make sure to update _current before the subject');
304
+ }
305
+ fn(this._current);
306
+ subscription.unsubscribe();
307
+ },
308
+ error: () => {
309
+ if (this._current.status !== 'error') {
310
+ throw new Error('Invalid state (error): please make sure to update _current before the subject');
311
+ }
312
+ fn(this._current);
313
+ // Do not unsubscribe
314
+ },
315
+ });
316
+ };
317
+
318
+ waitForLoad = (timeoutConfig: { timeoutSec: number; timeoutErrMsg: string }): Promise<T> => {
319
+ if (this._current.status === 'success') return Promise.resolve(this._current.loadedValue);
320
+ if (this._current.status === 'error') return Promise.reject(this._current.error);
321
+ if (this._current.status !== 'initial') assertNever(this._current);
322
+
323
+ const timeoutParams = {
324
+ first: timeoutConfig.timeoutSec * 1000,
325
+ with: () => throwError(() => new Error(timeoutConfig.timeoutErrMsg)),
326
+ };
327
+
328
+ /*
329
+ * Note: lastValueFrom converts the observable to a promise (https://rxjs.dev/api/index/function/lastValueFrom)
330
+ *
331
+ * We use lastValueFrom to wait for the observable to close successfully before resolving the Promise.
332
+ * To avoid hanging threads forever, we use timeoutParams to throw an error if it takes too long.
333
+ * firstValueFrom is theoretically also usable, but it might result in bugs
334
+ * if we do decide to emit more values in this Observable/Subject in the future.
335
+ *
336
+ * For more details, see: https://rxjs.dev/deprecations/to-promise
337
+ */
338
+ return lastValueFrom(this._subject.pipe(timeout(timeoutParams)));
339
+ };
340
+ }
341
+
205
342
  declare type OjsContext = {
206
343
  /**
207
344
  * The form element for the OJS form (non-CDE form).
@@ -221,7 +358,7 @@ declare type OjsContext = {
221
358
  /**
222
359
  * All the CDE connection objects (one for each CDE iframe).
223
360
  */
224
- cdeConnections: Map<ElementType, CdeConnection>;
361
+ anyCdeConnection: CdeConnection;
225
362
 
226
363
  /**
227
364
  * Custom init params for init flows.
@@ -239,14 +376,6 @@ declare type OjsFlow<T_PARAMS = unknown, T_INIT_RESULT extends InitOjsFlowResult
239
376
  run: RunOjsFlow<T_PARAMS, T_INIT_RESULT>;
240
377
  };
241
378
 
242
- declare type OjsFlowCallbacks = {
243
- onCheckoutError: OnCheckoutError;
244
- onCheckoutStarted: OnCheckoutStarted;
245
- onCheckoutSuccess: OnCheckoutSuccess;
246
- onSetupPaymentMethodSuccess: OnSetupPaymentMethodSuccess;
247
- onValidationError: OnValidationError;
248
- };
249
-
250
379
  declare type OjsFlowParams<T_PARAMS = void, T_INIT_RESULT = void> = {
251
380
  /**
252
381
  * Contains the context where OJS is run.
@@ -265,9 +394,9 @@ declare type OjsFlowParams<T_PARAMS = void, T_INIT_RESULT = void> = {
265
394
  nonCdeFormInputs: Record<string, unknown>;
266
395
 
267
396
  /**
268
- * Lifecycle callbacks for OJS flows.
397
+ * Form callbacks. Take note that these can be dynamically updated (but the object remains)
269
398
  */
270
- flowCallbacks: OjsFlowCallbacks;
399
+ formCallbacks: FormCallbacks;
271
400
 
272
401
  /**
273
402
  * Custom parameters for the flow.
@@ -285,6 +414,7 @@ declare const OjsFlows = {
285
414
 
286
415
  // Common
287
416
  commonCC: {
417
+ init: async () => {},
288
418
  run: runCommonCcFlow,
289
419
  },
290
420
 
@@ -314,53 +444,72 @@ declare type OnSetupPaymentMethodSuccess = (paymentMethodId: string) => void;
314
444
  declare type OnValidationError = (field: AllFieldNames, errors: string[], elementId?: string) => void;
315
445
 
316
446
  export declare class OpenPayForm {
317
- config: Config;
318
- formId: string;
319
- formTarget: string;
320
- checkoutFired: boolean;
321
- ojsVersion: string;
322
- ojsReleaseVersion: string;
323
- private referer;
447
+ readonly config: Config;
448
+ readonly formId: string;
449
+ readonly formTarget: string;
450
+ readonly ojsVersion: string;
451
+ readonly ojsReleaseVersion: string;
452
+ readonly formProperties: {
453
+ height: string;
454
+ };
455
+ readonly referrer: string;
456
+ readonly baseUrl: string;
457
+ readonly formCallbacks: FormCallbacks;
458
+ private registeredElements;
324
459
  private eventHandler;
325
- private formProperties;
326
460
  private connectionManager;
327
- private ojsFlowsInitialization;
328
- private cdeLoadedPayload;
329
- private elements;
330
461
  static ojsFlows: typeof OjsFlows;
462
+ private readonly cdeLoadEvent;
463
+ private readonly anyCdeConn;
464
+ private readonly context;
465
+ readonly initFlows: {
466
+ readonly stripePR: {
467
+ publisher: LoadedOncePublisher<InitStripePrFlowResult>;
468
+ initialize: (initParams: InitOjsFlowParams) => Promise<void>;
469
+ };
470
+ readonly stripeLink: {
471
+ publisher: LoadedOncePublisher<InitStripeLinkFlowResult>;
472
+ initialize: (initParams: InitOjsFlowParams) => Promise<void>;
473
+ };
474
+ };
331
475
  constructor(config: Config);
476
+ /**
477
+ * Starts the form initialization process
478
+ */
479
+ private startFormInit;
332
480
  /**
333
481
  * Assign the instance to the window as a singleton
334
- * @param form - The OpenPayForm instance
335
482
  */
336
- static assignAsSingleton(form: OpenPayForm): void;
483
+ private static assignAsSingleton;
337
484
  /**
338
485
  * Get the singleton instance of OpenPayForm
339
- * @returns The OpenPayForm instance
340
486
  */
341
- static getInstance(): OpenPayForm | null;
342
- getConnectionManager(): ConnectionManager;
343
- setFormHeight(height: string): void;
344
- tryInitOjsFlows: () => void;
487
+ static getInstance: () => OpenPayForm | null;
488
+ get checkoutSecureToken(): string;
489
+ setFormHeight: (height: string) => void;
345
490
  onCdeLoaded: (payload: LoadedEventPayload) => void;
346
- onStripePRStatusChange: (initStatus: Loadable<InitStripePrFlowResult>) => void;
347
- createElement(elementValue: ElementTypeEnumValue, options?: ElementProps): {
348
- type: ElementTypeEnum;
349
- node: HTMLIFrameElement;
350
- mount: (selector: string) => HTMLIFrameElement | undefined;
351
- };
491
+ onCdeLoadError: (errMsg: string) => void;
492
+ createElement: (elementValue: ElementTypeEnumValue, options?: ElementProps) => RegisteredElement;
493
+ registerIframe: (type: ElementTypeEnum, frame: HTMLIFrameElement) => RegisteredElement;
352
494
  private buildQueryString;
353
495
  private connectToElement;
354
496
  private getFormDiv;
355
- private createOjsFlowContext;
356
- private createOjsFlowCallbacks;
357
- submit(): void;
358
- submitPaymentRequest: (provider: PaymentRequestProvider, initResult: InitStripePrFlowSuccess, params?: PaymentRequestStartParams) => Promise<void>;
359
- onPaymentRequestError(errMsg: string): void;
360
- destroy(): void;
497
+ /**
498
+ * Builds the OJS context object. Take note that this is a pure function.
499
+ */
500
+ private static buildOjsFlowContext;
501
+ /**
502
+ * Runs the common credit card flow
503
+ */
504
+ submitCard: () => void;
505
+ /**
506
+ * Alias for submitCard
507
+ */
508
+ submit: () => void;
509
+ destroy: () => void;
361
510
  }
362
511
 
363
- declare const PaymentRequestProvider: z.ZodEnum<["apple_pay", "google_pay"]>;
512
+ declare const PaymentRequestProvider = z.enum(['apple_pay', 'google_pay']);
364
513
 
365
514
  declare type PaymentRequestProvider = z.infer<typeof PaymentRequestProvider>;
366
515
 
@@ -377,8 +526,28 @@ declare type PaymentRequestStatus = {
377
526
  startFlow: (params?: PaymentRequestStartParams) => Promise<void>;
378
527
  };
379
528
 
529
+ declare type PRStatuses = Record<PaymentRequestProvider, PaymentRequestStatus>;
530
+
531
+ declare type RegisteredElement = {
532
+ type: ElementType;
533
+ node: HTMLIFrameElement;
534
+ mount: (selector: string) => void;
535
+ };
536
+
380
537
  declare type RunOjsFlow<T_PARAMS = undefined, T_INIT_RESULT = undefined> = (
381
538
  params: OjsFlowParams<T_PARAMS, T_INIT_RESULT>
382
539
  ) => Promise<void>;
383
540
 
541
+ declare type StripeLinkController = {
542
+ mountButton: () => void;
543
+ dismountButton: () => void;
544
+ waitForButtonToMount: () => Promise<HTMLElement>;
545
+ };
546
+
547
+ declare type SuccessStatus<T> = {
548
+ status: 'success';
549
+ isSuccess: true;
550
+ loadedValue: T;
551
+ };
552
+
384
553
  export { }