@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 +246 -77
- package/dist/index.es.js +2017 -1416
- package/dist/index.umd.js +15 -16
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
397
|
+
* Form callbacks. Take note that these can be dynamically updated (but the object remains)
|
|
269
398
|
*/
|
|
270
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
|
483
|
+
private static assignAsSingleton;
|
|
337
484
|
/**
|
|
338
485
|
* Get the singleton instance of OpenPayForm
|
|
339
|
-
* @returns The OpenPayForm instance
|
|
340
486
|
*/
|
|
341
|
-
static getInstance()
|
|
342
|
-
|
|
343
|
-
setFormHeight(height: string)
|
|
344
|
-
tryInitOjsFlows: () => void;
|
|
487
|
+
static getInstance: () => OpenPayForm | null;
|
|
488
|
+
get checkoutSecureToken(): string;
|
|
489
|
+
setFormHeight: (height: string) => void;
|
|
345
490
|
onCdeLoaded: (payload: LoadedEventPayload) => void;
|
|
346
|
-
|
|
347
|
-
createElement(elementValue: ElementTypeEnumValue, options?: ElementProps)
|
|
348
|
-
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
|
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 { }
|