@moonpay/platform-sdk-react-native 0.3.0 → 1.0.1

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
@@ -1,3 +1,378 @@
1
+ // src/index.ts
2
+ import { ConnectionStatus as ConnectionStatus2 } from "@moonpay/platform-protocol/models/connection";
3
+
4
+ // src/frame-specs.ts
5
+ import {
6
+ ConnectionErrorCode,
7
+ ConnectionStatus
8
+ } from "@moonpay/platform-protocol/models/connection";
9
+ import { decryptCredentials, FRAME_PATHS } from "@moonpay/platform-sdk-core";
10
+ function createQuoteCommands(send, channelId) {
11
+ return {
12
+ setQuote: (signature) => send({
13
+ version: 2,
14
+ meta: { channelId },
15
+ kind: "setQuote",
16
+ payload: { quote: { signature } }
17
+ })
18
+ };
19
+ }
20
+ var applePaySpec = {
21
+ channelPrefix: "applepay",
22
+ path: FRAME_PATHS.applePay,
23
+ hidden: false,
24
+ buildParams: (ctx, props) => ({
25
+ clientToken: ctx.core.context.clientToken,
26
+ signature: props.quote
27
+ }),
28
+ createCommands: createQuoteCommands,
29
+ reactiveProps: {
30
+ quote: (commands, quote) => commands.setQuote(quote)
31
+ },
32
+ mapMessage: (msg, commands) => {
33
+ switch (msg.kind) {
34
+ case "ready":
35
+ return { kind: "ready" };
36
+ case "complete":
37
+ return { kind: "complete", payload: msg.payload };
38
+ case "challenge":
39
+ return {
40
+ kind: "challenge",
41
+ payload: msg.payload
42
+ };
43
+ case "error": {
44
+ const payload = msg.payload;
45
+ if (payload.code === "quoteExpired") {
46
+ return { kind: "quoteExpired", payload: { setQuote: commands.setQuote } };
47
+ }
48
+ if (payload.code === "applePayUnavailable") {
49
+ return { kind: "unsupported" };
50
+ }
51
+ const kind = payload.code === "generic" ? "genericError" : payload.code;
52
+ return { kind: "error", payload: { kind, message: payload.message } };
53
+ }
54
+ default:
55
+ return null;
56
+ }
57
+ },
58
+ errorEvent: (message) => ({ kind: "error", payload: { kind: "genericError", message } })
59
+ };
60
+ var googlePaySpec = {
61
+ channelPrefix: "googlepay",
62
+ path: FRAME_PATHS.googlePay,
63
+ hidden: false,
64
+ buildParams: (ctx, props) => ({
65
+ clientToken: ctx.core.context.clientToken,
66
+ signature: props.quote,
67
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
68
+ }),
69
+ createCommands: createQuoteCommands,
70
+ reactiveProps: {
71
+ quote: (commands, quote) => commands.setQuote(quote)
72
+ },
73
+ mapMessage: (msg, commands) => {
74
+ switch (msg.kind) {
75
+ case "ready":
76
+ return { kind: "ready" };
77
+ case "complete":
78
+ return { kind: "complete", payload: msg.payload };
79
+ case "challenge":
80
+ return {
81
+ kind: "challenge",
82
+ payload: msg.payload
83
+ };
84
+ case "error": {
85
+ const payload = msg.payload;
86
+ if (payload.code === "quoteExpired") {
87
+ return { kind: "quoteExpired", payload: { setQuote: commands.setQuote } };
88
+ }
89
+ if (payload.code === "googlePayUnavailable") {
90
+ return { kind: "unsupported" };
91
+ }
92
+ const kind = payload.code === "generic" ? "genericError" : payload.code;
93
+ return { kind: "error", payload: { kind, message: payload.message } };
94
+ }
95
+ default:
96
+ return null;
97
+ }
98
+ },
99
+ errorEvent: (message) => ({ kind: "error", payload: { kind: "genericError", message } })
100
+ };
101
+ var buyButtonSpec = {
102
+ channelPrefix: "buy-button",
103
+ path: FRAME_PATHS.buyButton,
104
+ hidden: false,
105
+ buildParams: (ctx, props) => ({
106
+ clientToken: ctx.core.context.clientToken,
107
+ signature: props.quote
108
+ }),
109
+ createCommands: createQuoteCommands,
110
+ reactiveProps: {
111
+ quote: (commands, quote) => commands.setQuote(quote)
112
+ },
113
+ mapMessage: (msg) => {
114
+ switch (msg.kind) {
115
+ case "complete":
116
+ return { kind: "complete", payload: msg.payload };
117
+ case "challenge":
118
+ return {
119
+ kind: "challenge",
120
+ payload: msg.payload
121
+ };
122
+ case "error":
123
+ return { kind: "error", payload: msg.payload };
124
+ default:
125
+ return null;
126
+ }
127
+ },
128
+ errorEvent: (message) => ({
129
+ kind: "error",
130
+ payload: { code: "generic", message }
131
+ })
132
+ };
133
+ function applyCredentialsOnComplete(msg, ctx) {
134
+ if (msg.kind !== "complete" || !ctx.privateKey)
135
+ return;
136
+ const connection = msg.payload;
137
+ if (connection.status !== ConnectionStatus.active && connection.status !== ConnectionStatus.connectionRequired) {
138
+ return;
139
+ }
140
+ if (!connection.credentials)
141
+ return;
142
+ const creds = decryptCredentials(connection.credentials, ctx.privateKey);
143
+ ctx.core.context.setAccessToken(creds.accessToken);
144
+ ctx.core.context.setClientToken(creds.clientToken);
145
+ }
146
+ var connectionCheckSpec = {
147
+ channelPrefix: "check",
148
+ path: FRAME_PATHS.checkConnection,
149
+ hidden: true,
150
+ needsKeyPair: true,
151
+ handshakeTimeout: 1e4,
152
+ buildParams: (ctx, props, publicKey) => ({
153
+ sessionToken: ctx.sessionToken,
154
+ publicKey,
155
+ ...props.skipKyc && { skipKyc: true }
156
+ }),
157
+ onMessageEffect: applyCredentialsOnComplete,
158
+ mapMessage: (msg) => {
159
+ if (msg.kind === "complete") {
160
+ return { kind: "complete", payload: msg.payload };
161
+ }
162
+ if (msg.kind === "error") {
163
+ return { kind: "error", payload: msg.payload };
164
+ }
165
+ return null;
166
+ },
167
+ errorEvent: (message) => ({ kind: "error", payload: { message } })
168
+ };
169
+ var connectSpec = {
170
+ channelPrefix: "connect",
171
+ path: FRAME_PATHS.connect,
172
+ hidden: false,
173
+ needsKeyPair: true,
174
+ buildParams: (ctx, props, publicKey) => ({
175
+ sessionToken: ctx.sessionToken,
176
+ publicKey,
177
+ ...props.theme?.appearance && { appearance: props.theme.appearance }
178
+ }),
179
+ onMessageEffect: applyCredentialsOnComplete,
180
+ mapMessage: (msg) => {
181
+ switch (msg.kind) {
182
+ case "ready":
183
+ return { kind: "ready" };
184
+ case "error":
185
+ return { kind: "error", payload: msg.payload };
186
+ case "complete":
187
+ return { kind: "complete", payload: msg.payload };
188
+ default:
189
+ return null;
190
+ }
191
+ },
192
+ errorEvent: (message) => ({
193
+ kind: "error",
194
+ payload: { code: ConnectionErrorCode.connectionFailedGeneric, message }
195
+ })
196
+ };
197
+ var authSpec = {
198
+ channelPrefix: "auth",
199
+ path: FRAME_PATHS.auth,
200
+ hidden: false,
201
+ needsKeyPair: true,
202
+ buildParams: (ctx, _props, publicKey) => {
203
+ const clientToken = ctx.core.context.clientToken;
204
+ if (!clientToken) {
205
+ throw new Error(
206
+ 'No clientToken in context \u2014 call getConnection() first and ensure it resolved with status "connectionRequired".'
207
+ );
208
+ }
209
+ return { clientToken, publicKey };
210
+ },
211
+ onMessageEffect: applyCredentialsOnComplete,
212
+ mapMessage: (msg) => {
213
+ switch (msg.kind) {
214
+ case "ready":
215
+ return { kind: "ready" };
216
+ case "error":
217
+ return { kind: "error", payload: msg.payload };
218
+ case "complete": {
219
+ const connection = msg.payload;
220
+ if (connection.status === ConnectionStatus.active || connection.status === ConnectionStatus.termsAcceptanceRequired) {
221
+ return { kind: "complete", payload: msg.payload };
222
+ }
223
+ return null;
224
+ }
225
+ default:
226
+ return null;
227
+ }
228
+ },
229
+ errorEvent: (message) => ({
230
+ kind: "error",
231
+ payload: { code: ConnectionErrorCode.connectionFailedGeneric, message }
232
+ })
233
+ };
234
+ var widgetSpec = {
235
+ channelPrefix: "widget",
236
+ path: FRAME_PATHS.widget,
237
+ hidden: false,
238
+ buildParams: (ctx, props) => ({
239
+ flow: "buy",
240
+ clientToken: ctx.core.context.clientToken,
241
+ quoteSignature: props.quote
242
+ }),
243
+ mapMessage: (msg) => {
244
+ switch (msg.kind) {
245
+ case "ready":
246
+ return { kind: "ready" };
247
+ case "transactionCreated":
248
+ return {
249
+ kind: "transactionCreated",
250
+ payload: msg.payload
251
+ };
252
+ case "complete":
253
+ return { kind: "complete", payload: msg.payload };
254
+ case "error":
255
+ return { kind: "error", payload: msg.payload };
256
+ case "close":
257
+ return { kind: "close" };
258
+ default:
259
+ return null;
260
+ }
261
+ },
262
+ errorEvent: (message) => ({
263
+ kind: "error",
264
+ payload: { code: "generic", message }
265
+ })
266
+ };
267
+ var buySpec = {
268
+ channelPrefix: "buy",
269
+ path: FRAME_PATHS.buy,
270
+ hidden: true,
271
+ buildParams: (ctx, props) => ({
272
+ clientToken: ctx.core.context.clientToken,
273
+ signature: props.quote,
274
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
275
+ }),
276
+ createCommands: createQuoteCommands,
277
+ reactiveProps: {
278
+ quote: (commands, quote) => commands.setQuote(quote)
279
+ },
280
+ mapMessage: (msg) => {
281
+ switch (msg.kind) {
282
+ case "ready":
283
+ return { kind: "ready" };
284
+ case "complete":
285
+ return { kind: "complete", payload: msg.payload };
286
+ case "challenge":
287
+ return { kind: "challenge", payload: msg.payload };
288
+ case "error":
289
+ return { kind: "error", payload: msg.payload };
290
+ default:
291
+ return null;
292
+ }
293
+ },
294
+ errorEvent: (message) => ({
295
+ kind: "error",
296
+ payload: { code: "generic", message }
297
+ })
298
+ };
299
+ var addCardSpec = {
300
+ channelPrefix: "add-card",
301
+ path: FRAME_PATHS.addCard,
302
+ hidden: false,
303
+ buildParams: (ctx) => ({ clientToken: ctx.core.context.clientToken }),
304
+ mapMessage: (msg) => {
305
+ switch (msg.kind) {
306
+ case "ready":
307
+ return { kind: "ready" };
308
+ case "complete":
309
+ return {
310
+ kind: "complete",
311
+ payload: msg.payload
312
+ };
313
+ case "error":
314
+ return { kind: "error", payload: msg.payload };
315
+ default:
316
+ return null;
317
+ }
318
+ },
319
+ errorEvent: (message) => ({
320
+ kind: "error",
321
+ payload: { code: "generic", message }
322
+ })
323
+ };
324
+ var challengeSpec = {
325
+ channelPrefix: "challenge",
326
+ path: FRAME_PATHS.challenge,
327
+ // documentation only — buildUrl below wins
328
+ hidden: false,
329
+ resolveChannelId: (props, generated) => new URL(props.url).searchParams.get("channelId") || generated,
330
+ buildUrl: (_ctx, props, channelId) => {
331
+ const url = new URL(props.url);
332
+ url.searchParams.set("channelId", channelId);
333
+ return url.toString();
334
+ },
335
+ mapMessage: (msg) => {
336
+ switch (msg.kind) {
337
+ case "ready":
338
+ return { kind: "ready" };
339
+ case "complete":
340
+ return { kind: "complete", payload: msg.payload };
341
+ case "cancelled":
342
+ return { kind: "cancelled", payload: msg.payload };
343
+ case "error":
344
+ return { kind: "error", payload: msg.payload };
345
+ default:
346
+ return null;
347
+ }
348
+ },
349
+ errorEvent: (message) => ({
350
+ kind: "error",
351
+ payload: { code: "generic", message }
352
+ })
353
+ };
354
+ var connectionResetSpec = {
355
+ channelPrefix: "reset",
356
+ path: FRAME_PATHS.reset,
357
+ hidden: true,
358
+ handshakeTimeout: 5e3,
359
+ buildParams: (ctx) => ({ sessionToken: ctx.sessionToken }),
360
+ mapMessage: (msg) => {
361
+ if (msg.kind === "complete")
362
+ return { kind: "complete" };
363
+ if (msg.kind === "error") {
364
+ const payload = msg.payload;
365
+ return { kind: "error", payload: { message: payload?.message ?? "Reset failed" } };
366
+ }
367
+ return null;
368
+ },
369
+ errorEvent: (message) => ({ kind: "error", payload: { message } })
370
+ };
371
+
372
+ // src/frame-view.tsx
373
+ import { useEffect as useEffect2, useRef as useRef3, useState as useState2 } from "react";
374
+ import { View as View2 } from "react-native";
375
+
1
376
  // src/frame-component.tsx
2
377
  import { useEffect, useRef } from "react";
3
378
  import { View } from "react-native";
@@ -31,28 +406,12 @@ function MoonPayFrame({ transport, hidden, style }) {
31
406
  ) });
32
407
  }
33
408
 
34
- // src/provider.tsx
35
- import {
36
- ConnectionStatus,
37
- err,
38
- ok
39
- } from "@moonpay/platform-protocol";
409
+ // src/frame-engine.ts
40
410
  import {
41
411
  buildFrameUrl,
42
- createClientCore,
43
412
  createFrameOrchestrator,
44
- decryptCredentials,
45
- FRAME_PATHS,
46
413
  generateKeyPair
47
414
  } from "@moonpay/platform-sdk-core";
48
- import {
49
- createContext,
50
- useCallback,
51
- useContext,
52
- useMemo,
53
- useRef as useRef2,
54
- useState
55
- } from "react";
56
415
 
57
416
  // src/webview-transport.ts
58
417
  var WebViewTransport = class {
@@ -113,10 +472,413 @@ var WebViewTransport = class {
113
472
  }
114
473
  };
115
474
 
475
+ // src/frame-engine.ts
476
+ var FrameSessionDisposedError = class extends Error {
477
+ constructor() {
478
+ super("Frame session disposed");
479
+ this.name = "FrameSessionDisposedError";
480
+ }
481
+ };
482
+ function createFrameSession(spec, ctx, props, overrides = {}) {
483
+ const generated = `${spec.channelPrefix}-${Date.now()}`;
484
+ const channelId = spec.resolveChannelId ? spec.resolveChannelId(props, generated) : generated;
485
+ const keyPair = spec.needsKeyPair ? generateKeyPair() : void 0;
486
+ const url = spec.buildUrl ? spec.buildUrl(ctx, props, channelId, keyPair?.publicKey) : buildFrameUrl(
487
+ spec.path,
488
+ { ...spec.buildParams?.(ctx, props, keyPair?.publicKey), channelId },
489
+ { frameBaseUrl: ctx.frameBaseUrl }
490
+ );
491
+ const transport = (overrides.createTransport ?? (() => new WebViewTransport()))();
492
+ let resolvedHandle = null;
493
+ let rejectDisposed;
494
+ const disposedBeforeReady = new Promise((_, reject) => {
495
+ rejectDisposed = reject;
496
+ });
497
+ const handleReady = createFrameOrchestrator({
498
+ transport,
499
+ channelId,
500
+ url,
501
+ container: null,
502
+ hidden: spec.hidden,
503
+ handshakeTimeout: overrides.handshakeTimeout ?? spec.handshakeTimeout ?? 15e3
504
+ }).then((handle) => {
505
+ const send = (msg) => handle.sendMessage(msg);
506
+ const commands = spec.createCommands?.(send, channelId);
507
+ const eventHandlers = [];
508
+ const disposeHandlers = [];
509
+ let disposeNotified = false;
510
+ const notifyDisposed = () => {
511
+ if (disposeNotified)
512
+ return;
513
+ disposeNotified = true;
514
+ for (const handler of [...disposeHandlers]) {
515
+ handler();
516
+ }
517
+ };
518
+ handle.onMessage((msg) => {
519
+ let event;
520
+ try {
521
+ spec.onMessageEffect?.(msg, { ...ctx, privateKey: keyPair?.privateKey });
522
+ event = spec.mapMessage(msg, commands);
523
+ } catch (e) {
524
+ event = spec.errorEvent(e instanceof Error ? e.message : "Failed to process frame message");
525
+ }
526
+ if (event !== null) {
527
+ for (const handler of [...eventHandlers]) {
528
+ handler(event);
529
+ }
530
+ }
531
+ });
532
+ const sessionHandle = {
533
+ onEvent(handler) {
534
+ eventHandlers.push(handler);
535
+ return () => {
536
+ const idx = eventHandlers.indexOf(handler);
537
+ if (idx >= 0)
538
+ eventHandlers.splice(idx, 1);
539
+ };
540
+ },
541
+ onMessage: (handler) => handle.onMessage(handler),
542
+ onDispose(handler) {
543
+ disposeHandlers.push(handler);
544
+ return () => {
545
+ const idx = disposeHandlers.indexOf(handler);
546
+ if (idx >= 0)
547
+ disposeHandlers.splice(idx, 1);
548
+ };
549
+ },
550
+ sendMessage: send,
551
+ commands,
552
+ dispose: () => {
553
+ handle.dispose();
554
+ notifyDisposed();
555
+ }
556
+ };
557
+ resolvedHandle = sessionHandle;
558
+ return sessionHandle;
559
+ });
560
+ const ready = Promise.race([handleReady, disposedBeforeReady]);
561
+ ready.catch(() => {
562
+ });
563
+ return {
564
+ transport,
565
+ channelId,
566
+ url,
567
+ hidden: spec.hidden,
568
+ ready,
569
+ dispose: () => {
570
+ if (resolvedHandle) {
571
+ resolvedHandle.dispose();
572
+ } else {
573
+ transport.dispose();
574
+ rejectDisposed?.(new FrameSessionDisposedError());
575
+ }
576
+ }
577
+ };
578
+ }
579
+
580
+ // src/provider.tsx
581
+ import { createClientCore } from "@moonpay/platform-sdk-core";
582
+ import {
583
+ createContext,
584
+ useCallback,
585
+ useContext,
586
+ useMemo,
587
+ useRef as useRef2,
588
+ useState
589
+ } from "react";
590
+ import { Modal } from "react-native";
591
+
592
+ // src/methods/add-card.ts
593
+ import { err, ok } from "@moonpay/platform-protocol/result";
594
+ async function setupAddCard(deps, opts) {
595
+ try {
596
+ const { handle, dispose } = await deps.mountSession(addCardSpec, {});
597
+ handle.onEvent((event) => opts.onEvent?.(event));
598
+ return ok({ dispose });
599
+ } catch (e) {
600
+ return err({
601
+ kind: "genericError",
602
+ message: e instanceof Error ? e.message : "Add card setup failed"
603
+ });
604
+ }
605
+ }
606
+
607
+ // src/methods/apple-pay.ts
608
+ import { err as err2, ok as ok2 } from "@moonpay/platform-protocol/result";
609
+ async function setupApplePay(deps, opts) {
610
+ try {
611
+ const { handle, dispose } = await deps.mountSession(applePaySpec, { quote: opts.quote });
612
+ handle.onEvent((event) => opts.onEvent?.(event));
613
+ return ok2({ setQuote: handle.commands.setQuote, dispose });
614
+ } catch (e) {
615
+ return err2({
616
+ kind: "genericError",
617
+ message: e instanceof Error ? e.message : "Apple Pay setup failed"
618
+ });
619
+ }
620
+ }
621
+
622
+ // src/methods/auth.ts
623
+ import { err as err3, ok as ok3 } from "@moonpay/platform-protocol/result";
624
+ async function setupAuth(deps, opts) {
625
+ if (!deps.core.context.clientToken) {
626
+ return err3({
627
+ kind: "configurationError",
628
+ message: 'No clientToken in context \u2014 call getConnection() first and ensure it resolved with status "connectionRequired".'
629
+ });
630
+ }
631
+ try {
632
+ const { handle, dispose } = await deps.mountSession(authSpec, {});
633
+ return await new Promise((resolve) => {
634
+ handle.onEvent((event) => {
635
+ opts.onEvent?.(event);
636
+ if (event.kind === "error") {
637
+ resolve(err3({ kind: "genericError", message: "Auth frame error" }));
638
+ dispose();
639
+ }
640
+ });
641
+ handle.onMessage((msg) => {
642
+ if (msg.kind === "complete") {
643
+ resolve(ok3({ dispose }));
644
+ }
645
+ });
646
+ handle.onDispose(() => {
647
+ resolve(err3({ kind: "genericError", message: "Auth flow dismissed" }));
648
+ });
649
+ });
650
+ } catch (e) {
651
+ if (e instanceof FrameSessionDisposedError) {
652
+ return err3({ kind: "genericError", message: "Auth flow dismissed" });
653
+ }
654
+ return err3({
655
+ kind: "genericError",
656
+ message: e instanceof Error ? e.message : "Auth setup failed"
657
+ });
658
+ }
659
+ }
660
+
661
+ // src/methods/buy.ts
662
+ import { err as err4, ok as ok4 } from "@moonpay/platform-protocol/result";
663
+ async function setupBuy(deps, opts) {
664
+ try {
665
+ const { handle, dispose } = await deps.mountSession(buySpec, {
666
+ quote: opts.quote,
667
+ externalTransactionId: opts.externalTransactionId
668
+ });
669
+ handle.onEvent((event) => opts.onEvent?.(event));
670
+ return ok4({ setQuote: handle.commands.setQuote, dispose });
671
+ } catch (e) {
672
+ return err4({
673
+ kind: "genericError",
674
+ message: e instanceof Error ? e.message : "Buy setup failed"
675
+ });
676
+ }
677
+ }
678
+
679
+ // src/methods/buy-button.ts
680
+ import { err as err5, ok as ok5 } from "@moonpay/platform-protocol/result";
681
+ async function setupBuyButton(deps, opts) {
682
+ try {
683
+ const { handle, dispose } = await deps.mountSession(buyButtonSpec, { quote: opts.quote });
684
+ handle.onEvent((event) => opts.onEvent?.(event));
685
+ return ok5({ setQuote: handle.commands.setQuote, dispose });
686
+ } catch (e) {
687
+ return err5({
688
+ kind: "genericError",
689
+ message: e instanceof Error ? e.message : "Buy button setup failed"
690
+ });
691
+ }
692
+ }
693
+
694
+ // src/methods/challenge.ts
695
+ import { err as err6, ok as ok6 } from "@moonpay/platform-protocol/result";
696
+ async function setupChallenge(deps, opts) {
697
+ try {
698
+ const { handle, dispose } = await deps.mountSession(challengeSpec, { url: opts.url });
699
+ handle.onEvent((event) => opts.onEvent?.(event));
700
+ return ok6({ dispose });
701
+ } catch (e) {
702
+ if (e instanceof TypeError) {
703
+ return err6({ kind: "configurationError", message: "Invalid challenge URL" });
704
+ }
705
+ return err6({
706
+ kind: "genericError",
707
+ message: e instanceof Error ? e.message : "Challenge setup failed"
708
+ });
709
+ }
710
+ }
711
+
712
+ // src/methods/connect.ts
713
+ import { err as err7, ok as ok7 } from "@moonpay/platform-protocol/result";
714
+ async function connect(deps, opts) {
715
+ try {
716
+ const { handle, dispose } = await deps.mountSession(connectSpec, { theme: opts.theme });
717
+ return await new Promise((resolve) => {
718
+ handle.onEvent((event) => {
719
+ opts.onEvent?.(event);
720
+ if (event.kind === "error") {
721
+ resolve(err7({ message: "Connection error" }));
722
+ dispose();
723
+ } else if (event.kind === "complete") {
724
+ resolve(ok7({ dispose }));
725
+ }
726
+ });
727
+ handle.onDispose(() => {
728
+ resolve(err7({ message: "Connect flow dismissed" }));
729
+ });
730
+ });
731
+ } catch (e) {
732
+ if (e instanceof FrameSessionDisposedError) {
733
+ return err7({ message: "Connect flow dismissed" });
734
+ }
735
+ return err7({
736
+ message: e instanceof Error ? e.message : "Connect failed"
737
+ });
738
+ }
739
+ }
740
+
741
+ // src/methods/connection-check.ts
742
+ import { err as err8, ok as ok8 } from "@moonpay/platform-protocol/result";
743
+ async function getConnection(deps, options = {}) {
744
+ try {
745
+ const { handle, dispose } = await deps.mountSession(connectionCheckSpec, options);
746
+ return await new Promise((resolve) => {
747
+ const timeout = setTimeout(() => {
748
+ dispose();
749
+ resolve(err8({ message: "Get connection timed out" }));
750
+ }, 1e4);
751
+ handle.onEvent((event) => {
752
+ clearTimeout(timeout);
753
+ dispose();
754
+ if (event.kind === "error") {
755
+ resolve(err8({ message: event.payload.message }));
756
+ } else {
757
+ resolve(ok8(event.payload));
758
+ }
759
+ });
760
+ });
761
+ } catch (e) {
762
+ return err8({
763
+ message: e instanceof Error ? e.message : "Failed to check connection"
764
+ });
765
+ }
766
+ }
767
+
768
+ // src/methods/connection-reset.ts
769
+ import { ok as ok9 } from "@moonpay/platform-protocol/result";
770
+ async function resetConnection(deps) {
771
+ try {
772
+ const { handle, dispose } = await deps.mountSession(connectionResetSpec, {});
773
+ return await new Promise((resolve) => {
774
+ const timeout = setTimeout(() => {
775
+ dispose();
776
+ resolve(ok9(void 0));
777
+ }, 5e3);
778
+ handle.onEvent(() => {
779
+ clearTimeout(timeout);
780
+ dispose();
781
+ resolve(ok9(void 0));
782
+ });
783
+ });
784
+ } catch {
785
+ return ok9(void 0);
786
+ }
787
+ }
788
+
789
+ // src/methods/google-pay.ts
790
+ import { err as err9, ok as ok10 } from "@moonpay/platform-protocol/result";
791
+ async function setupGooglePay(deps, opts) {
792
+ try {
793
+ const { handle, dispose } = await deps.mountSession(googlePaySpec, {
794
+ quote: opts.quote,
795
+ externalTransactionId: opts.externalTransactionId
796
+ });
797
+ handle.onEvent((event) => opts.onEvent?.(event));
798
+ return ok10({ setQuote: handle.commands.setQuote, dispose });
799
+ } catch (e) {
800
+ return err9({
801
+ kind: "genericError",
802
+ message: e instanceof Error ? e.message : "Google Pay setup failed"
803
+ });
804
+ }
805
+ }
806
+
807
+ // src/methods/widget.ts
808
+ import { err as err10, ok as ok11 } from "@moonpay/platform-protocol/result";
809
+ async function setupWidget(deps, opts) {
810
+ try {
811
+ const { handle, dispose } = await deps.mountSession(widgetSpec, { quote: opts.quote });
812
+ handle.onEvent((event) => opts.onEvent?.(event));
813
+ return ok11({ dispose });
814
+ } catch (e) {
815
+ return err10({
816
+ kind: "genericError",
817
+ message: e instanceof Error ? e.message : "Widget setup failed"
818
+ });
819
+ }
820
+ }
821
+
822
+ // src/client.ts
823
+ function createRNClient(deps) {
824
+ const { core } = deps;
825
+ return {
826
+ getConnection: (options) => getConnection(deps, options ?? {}),
827
+ connect: (opts) => connect(deps, opts),
828
+ setupAuth: (opts) => setupAuth(deps, opts),
829
+ getPaymentMethods: () => core.getPaymentMethods(),
830
+ getQuote: (params) => core.getQuote(params),
831
+ listTransactions: (params) => core.listTransactions(params),
832
+ getTransaction: (id) => core.getTransaction(id),
833
+ setupWidget: (opts) => setupWidget(deps, opts),
834
+ setupApplePay: (opts) => setupApplePay(deps, opts),
835
+ setupBuy: (opts) => setupBuy(deps, opts),
836
+ setupBuyButton: (opts) => setupBuyButton(deps, opts),
837
+ setupGooglePay: (opts) => setupGooglePay(deps, opts),
838
+ deletePaymentMethod: (id) => core.deletePaymentMethod(id),
839
+ resetConnection: () => resetConnection(deps),
840
+ setupChallenge: (opts) => setupChallenge(deps, opts),
841
+ setupAddCard: (opts) => setupAddCard(deps, opts),
842
+ createIdentity: (body) => core.createIdentity(body),
843
+ getIdentity: (id) => core.getIdentity(id),
844
+ updateIdentity: (id, body) => core.updateIdentity(id, body),
845
+ verifyIdentity: (id) => core.verifyIdentity(id),
846
+ getIdentityUploadUrl: (id, body) => core.getIdentityUploadUrl(id, body),
847
+ submitIdentityFiles: (id, body) => core.submitIdentityFiles(id, body)
848
+ };
849
+ }
850
+
851
+ // src/methods/mount-session.ts
852
+ var slotCounter = 0;
853
+ function createMountSession(specCtx, host) {
854
+ return async function mountSession(spec, props) {
855
+ const session = createFrameSession(spec, specCtx, props);
856
+ const slotId = `slot-${++slotCounter}`;
857
+ host.addSlot({
858
+ id: slotId,
859
+ transport: session.transport,
860
+ hidden: session.hidden,
861
+ dispose: () => session.dispose()
862
+ });
863
+ try {
864
+ const handle = await session.ready;
865
+ return {
866
+ handle,
867
+ dispose: () => {
868
+ handle.dispose();
869
+ host.removeSlot(slotId);
870
+ }
871
+ };
872
+ } catch (e) {
873
+ host.removeSlot(slotId);
874
+ throw e;
875
+ }
876
+ };
877
+ }
878
+
116
879
  // src/provider.tsx
117
880
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
118
881
  var MoonPayContext = createContext(null);
119
- var slotCounter = 0;
120
882
  function MoonPayProvider({
121
883
  sessionToken,
122
884
  apiBaseUrl,
@@ -140,673 +902,312 @@ function MoonPayProvider({
140
902
  }
141
903
  const core = coreRef.current;
142
904
  const client = useMemo(() => {
143
- function createManagedFrame(opts) {
144
- const transport = new WebViewTransport();
145
- const slotId = `slot-${++slotCounter}`;
146
- const promise = new Promise((resolve, reject) => {
147
- transport.create(opts.url, { container: null, hidden: opts.hidden });
148
- addSlot({ id: slotId, transport, hidden: opts.hidden });
149
- createFrameOrchestrator({
150
- transport,
151
- channelId: opts.channelId,
152
- url: opts.url,
153
- container: null,
154
- hidden: opts.hidden,
155
- handshakeTimeout: opts.handshakeTimeout ?? 15e3
156
- }).then((handle) => resolve({ handle, slotId })).catch((e) => {
157
- removeSlot(slotId);
158
- reject(e);
159
- });
160
- });
161
- return { promise, transport };
162
- }
163
- async function getConnection(options = {}) {
164
- const { privateKey, publicKey } = generateKeyPair();
165
- const channelId = `check-${Date.now()}`;
166
- const url = buildFrameUrl(
167
- FRAME_PATHS.checkConnection,
168
- {
169
- sessionToken,
170
- channelId,
171
- publicKey,
172
- ...options.skipKyc && { skipKyc: true }
905
+ const specCtx = { sessionToken, core, frameBaseUrl };
906
+ return createRNClient({
907
+ mountSession: createMountSession(specCtx, { addSlot, removeSlot }),
908
+ core
909
+ });
910
+ }, [sessionToken, frameBaseUrl, core, addSlot, removeSlot]);
911
+ return /* @__PURE__ */ jsxs(MoonPayContext.Provider, { value: { client, sessionToken, core, frameBaseUrl }, children: [
912
+ children,
913
+ frameSlots.filter((slot) => slot.hidden).map((slot) => /* @__PURE__ */ jsx2(MoonPayFrame, { transport: slot.transport, hidden: true }, slot.id)),
914
+ frameSlots.filter((slot) => !slot.hidden).map((slot) => /* @__PURE__ */ jsx2(
915
+ Modal,
916
+ {
917
+ visible: true,
918
+ animationType: "slide",
919
+ onRequestClose: () => {
920
+ slot.dispose();
921
+ removeSlot(slot.id);
173
922
  },
174
- { frameBaseUrl }
175
- );
176
- try {
177
- const { promise } = createManagedFrame({
178
- url,
179
- channelId,
180
- hidden: true,
181
- handshakeTimeout: 1e4
182
- });
183
- const { handle, slotId } = await promise;
184
- return new Promise((resolve) => {
185
- const timeout = setTimeout(() => {
186
- handle.dispose();
187
- removeSlot(slotId);
188
- resolve(err({ message: "Get connection timed out" }));
189
- }, 1e4);
190
- handle.onMessage((msg) => {
191
- if (msg.kind === "error") {
192
- clearTimeout(timeout);
193
- handle.dispose();
194
- removeSlot(slotId);
195
- const payload = msg.payload;
196
- resolve(err({ message: payload.message }));
197
- return;
198
- }
199
- if (msg.kind === "complete") {
200
- clearTimeout(timeout);
201
- handle.dispose();
202
- removeSlot(slotId);
203
- const connection = msg.payload;
204
- if (connection.status === ConnectionStatus.active) {
205
- const creds = decryptCredentials(connection.credentials, privateKey);
206
- core.context.setAccessToken(creds.accessToken);
207
- core.context.setClientToken(creds.clientToken);
208
- }
209
- resolve(ok(connection));
210
- }
211
- });
212
- });
213
- } catch (e) {
214
- return err({
215
- message: e instanceof Error ? e.message : "Failed to check connection"
216
- });
217
- }
923
+ children: /* @__PURE__ */ jsx2(MoonPayFrame, { transport: slot.transport })
924
+ },
925
+ slot.id
926
+ ))
927
+ ] });
928
+ }
929
+ function useMoonPayContext() {
930
+ const ctx = useContext(MoonPayContext);
931
+ if (!ctx) {
932
+ throw new Error("useMoonPay must be used within a <MoonPayProvider>");
933
+ }
934
+ return ctx;
935
+ }
936
+ function useMoonPay() {
937
+ return useMoonPayContext();
938
+ }
939
+
940
+ // src/frame-view.tsx
941
+ import { jsx as jsx3 } from "react/jsx-runtime";
942
+ function applyReactiveProps(spec, keys, props, applied, handle) {
943
+ for (const key of keys) {
944
+ const next = props[key];
945
+ if (next !== void 0 && next !== applied[key]) {
946
+ spec.reactiveProps?.[key]?.(handle.commands, next);
947
+ applied[key] = next;
218
948
  }
219
- async function connect(opts) {
220
- const { privateKey, publicKey } = generateKeyPair();
221
- const channelId = `connect-${Date.now()}`;
222
- const url = buildFrameUrl(
223
- FRAME_PATHS.connect,
224
- {
225
- sessionToken,
226
- channelId,
227
- publicKey,
228
- ...opts.theme?.appearance && { appearance: opts.theme.appearance }
229
- },
230
- { frameBaseUrl }
949
+ }
950
+ }
951
+ function MoonPayFrameView({
952
+ spec,
953
+ props,
954
+ style,
955
+ defaultStyle,
956
+ onEvent
957
+ }) {
958
+ const { sessionToken, core, frameBaseUrl } = useMoonPayContext();
959
+ const [transport, setTransport] = useState2(null);
960
+ const handleRef = useRef3(null);
961
+ const onEventRef = useRef3(onEvent);
962
+ onEventRef.current = onEvent;
963
+ const propsRef = useRef3(props);
964
+ propsRef.current = props;
965
+ const reactiveKeys = Object.keys(spec.reactiveProps ?? {});
966
+ const mountProps = {};
967
+ const liveProps = {};
968
+ for (const [key, value] of Object.entries(props)) {
969
+ const k = key;
970
+ (reactiveKeys.includes(k) ? liveProps : mountProps)[k] = value;
971
+ }
972
+ const mountKey = JSON.stringify(mountProps);
973
+ const liveKey = JSON.stringify(liveProps);
974
+ const appliedRef = useRef3({});
975
+ useEffect2(() => {
976
+ let disposed = false;
977
+ let session;
978
+ const applied = {};
979
+ for (const key of reactiveKeys) {
980
+ applied[key] = propsRef.current[key];
981
+ }
982
+ appliedRef.current = applied;
983
+ try {
984
+ session = createFrameSession(spec, { sessionToken, core, frameBaseUrl }, propsRef.current);
985
+ } catch (e) {
986
+ onEventRef.current?.(
987
+ spec.errorEvent(e instanceof Error ? e.message : "Failed to create frame")
231
988
  );
232
- try {
233
- const { promise } = createManagedFrame({ url, channelId, hidden: false });
234
- const { handle, slotId } = await promise;
235
- return new Promise((resolve) => {
236
- handle.onMessage((msg) => {
237
- if (msg.kind === "ready") {
238
- opts.onEvent?.({ kind: "ready" });
239
- return;
240
- }
241
- if (msg.kind === "error") {
242
- const payload = msg.payload;
243
- opts.onEvent?.({ kind: "error", payload });
244
- handle.dispose();
245
- removeSlot(slotId);
246
- resolve(err({ message: "Connection error" }));
247
- return;
248
- }
249
- if (msg.kind === "complete") {
250
- const connection = msg.payload;
251
- if (connection.status === ConnectionStatus.active) {
252
- const creds = decryptCredentials(connection.credentials, privateKey);
253
- core.context.setAccessToken(creds.accessToken);
254
- core.context.setClientToken(creds.clientToken);
255
- }
256
- opts.onEvent?.({ kind: "complete", payload: connection });
257
- resolve(
258
- ok({
259
- dispose: () => {
260
- handle.dispose();
261
- removeSlot(slotId);
262
- }
263
- })
264
- );
265
- }
266
- });
267
- });
268
- } catch (e) {
269
- return err({
270
- message: e instanceof Error ? e.message : "Connect failed"
271
- });
272
- }
989
+ return;
273
990
  }
274
- async function setupAuth(opts) {
275
- const clientToken = core.context.clientToken;
276
- if (!clientToken) {
277
- return err({
278
- kind: "configurationError",
279
- message: 'No clientToken in context \u2014 call getConnection() first and ensure it resolved with status "connectionRequired".'
280
- });
991
+ setTransport(session.transport);
992
+ session.ready.then((handle) => {
993
+ if (disposed) {
994
+ handle.dispose();
995
+ return;
281
996
  }
282
- const { privateKey, publicKey } = generateKeyPair();
283
- const channelId = `auth-${Date.now()}`;
284
- const url = buildFrameUrl(
285
- FRAME_PATHS.auth,
286
- { clientToken, channelId, publicKey },
287
- { frameBaseUrl }
288
- );
289
- try {
290
- const { promise } = createManagedFrame({ url, channelId, hidden: false });
291
- const { handle, slotId } = await promise;
292
- return new Promise((resolve) => {
293
- handle.onMessage((msg) => {
294
- if (msg.kind === "ready") {
295
- opts.onEvent?.({ kind: "ready" });
296
- return;
297
- }
298
- if (msg.kind === "error") {
299
- const payload = msg.payload;
300
- opts.onEvent?.({ kind: "error", payload });
301
- handle.dispose();
302
- removeSlot(slotId);
303
- resolve(err({ kind: "genericError", message: "Auth frame error" }));
304
- return;
305
- }
306
- if (msg.kind === "complete") {
307
- const connection = msg.payload;
308
- if (connection.status === ConnectionStatus.active) {
309
- const creds = decryptCredentials(connection.credentials, privateKey);
310
- core.context.setAccessToken(creds.accessToken);
311
- core.context.setClientToken(creds.clientToken);
312
- }
313
- if (connection.status === ConnectionStatus.active || connection.status === ConnectionStatus.termsAcceptanceRequired) {
314
- opts.onEvent?.({ kind: "complete", payload: connection });
315
- }
316
- resolve(
317
- ok({
318
- dispose: () => {
319
- handle.dispose();
320
- removeSlot(slotId);
321
- }
322
- })
323
- );
324
- }
325
- });
326
- });
327
- } catch (e) {
328
- return err({
329
- kind: "genericError",
330
- message: e instanceof Error ? e.message : "Auth setup failed"
331
- });
997
+ handleRef.current = handle;
998
+ handle.onEvent((event) => onEventRef.current?.(event));
999
+ applyReactiveProps(spec, reactiveKeys, propsRef.current, appliedRef.current, handle);
1000
+ }).catch((e) => {
1001
+ if (!disposed) {
1002
+ onEventRef.current?.(
1003
+ spec.errorEvent(e instanceof Error ? e.message : "Frame handshake failed")
1004
+ );
332
1005
  }
1006
+ });
1007
+ return () => {
1008
+ disposed = true;
1009
+ handleRef.current = null;
1010
+ session.dispose();
1011
+ setTransport(null);
1012
+ };
1013
+ }, [mountKey, spec, sessionToken, core, frameBaseUrl]);
1014
+ useEffect2(() => {
1015
+ const handle = handleRef.current;
1016
+ if (!handle)
1017
+ return;
1018
+ applyReactiveProps(spec, reactiveKeys, propsRef.current, appliedRef.current, handle);
1019
+ }, [liveKey]);
1020
+ if (spec.hidden) {
1021
+ return transport ? /* @__PURE__ */ jsx3(MoonPayFrame, { transport, hidden: true }) : null;
1022
+ }
1023
+ const resolvedStyle = { ...defaultStyle, ...style };
1024
+ return /* @__PURE__ */ jsx3(View2, { style: resolvedStyle, children: transport ? /* @__PURE__ */ jsx3(MoonPayFrame, { transport }) : null });
1025
+ }
1026
+
1027
+ // src/components/add-card.tsx
1028
+ import { jsx as jsx4 } from "react/jsx-runtime";
1029
+ function MoonPayAddCard({ onEvent, style }) {
1030
+ return /* @__PURE__ */ jsx4(
1031
+ MoonPayFrameView,
1032
+ {
1033
+ spec: addCardSpec,
1034
+ props: {},
1035
+ style,
1036
+ defaultStyle: { flex: 1 },
1037
+ onEvent
333
1038
  }
334
- async function setupWidget(opts) {
335
- const channelId = `widget-${Date.now()}`;
336
- const url = buildFrameUrl(
337
- FRAME_PATHS.widget,
338
- {
339
- flow: "buy",
340
- clientToken: core.context.clientToken,
341
- quoteSignature: opts.quote,
342
- channelId
343
- },
344
- { frameBaseUrl }
345
- );
346
- try {
347
- const { promise } = createManagedFrame({ url, channelId, hidden: false });
348
- const { handle, slotId } = await promise;
349
- handle.onMessage((msg) => {
350
- switch (msg.kind) {
351
- case "ready":
352
- opts.onEvent?.({ kind: "ready" });
353
- break;
354
- case "transactionCreated":
355
- opts.onEvent?.({
356
- kind: "transactionCreated",
357
- payload: msg.payload
358
- });
359
- break;
360
- case "complete":
361
- opts.onEvent?.({
362
- kind: "complete",
363
- payload: msg.payload
364
- });
365
- break;
366
- case "error": {
367
- const payload = msg.payload;
368
- opts.onEvent?.({
369
- kind: "error",
370
- payload: { code: payload.code, message: payload.message }
371
- });
372
- break;
373
- }
374
- case "close":
375
- opts.onEvent?.({ kind: "close" });
376
- break;
377
- }
378
- });
379
- return ok({
380
- dispose: () => {
381
- handle.dispose();
382
- removeSlot(slotId);
383
- }
384
- });
385
- } catch (e) {
386
- return err({
387
- kind: "genericError",
388
- message: e instanceof Error ? e.message : "Widget setup failed"
389
- });
390
- }
1039
+ );
1040
+ }
1041
+
1042
+ // src/components/apple-pay-button.tsx
1043
+ import { jsx as jsx5 } from "react/jsx-runtime";
1044
+ function MoonPayApplePayButton({
1045
+ quote,
1046
+ onEvent,
1047
+ style
1048
+ }) {
1049
+ return /* @__PURE__ */ jsx5(
1050
+ MoonPayFrameView,
1051
+ {
1052
+ spec: applePaySpec,
1053
+ props: { quote },
1054
+ style,
1055
+ defaultStyle: { height: 48 },
1056
+ onEvent
391
1057
  }
392
- async function setupApplePay(opts) {
393
- const channelId = `applepay-${Date.now()}`;
394
- const url = buildFrameUrl(
395
- FRAME_PATHS.applePay,
396
- {
397
- clientToken: core.context.clientToken,
398
- signature: opts.quote,
399
- channelId
400
- },
401
- { frameBaseUrl }
402
- );
403
- try {
404
- const { promise } = createManagedFrame({ url, channelId, hidden: false });
405
- const { handle, slotId } = await promise;
406
- const setQuote = (signature) => {
407
- handle.sendMessage({
408
- version: 2,
409
- meta: { channelId },
410
- kind: "setQuote",
411
- payload: { quote: { signature } }
412
- });
413
- };
414
- handle.onMessage((msg) => {
415
- switch (msg.kind) {
416
- case "ready":
417
- opts.onEvent?.({ kind: "ready" });
418
- break;
419
- case "complete":
420
- opts.onEvent?.({
421
- kind: "complete",
422
- payload: msg.payload
423
- });
424
- break;
425
- case "error": {
426
- const payload = msg.payload;
427
- if (payload.code === "quoteExpired") {
428
- opts.onEvent?.({ kind: "quoteExpired", payload: { setQuote } });
429
- } else if (payload.code === "applePayUnavailable") {
430
- opts.onEvent?.({ kind: "unsupported" });
431
- } else {
432
- const kind = payload.code === "generic" ? "genericError" : payload.code;
433
- opts.onEvent?.({
434
- kind: "error",
435
- payload: { kind, message: payload.message }
436
- });
437
- }
438
- break;
439
- }
440
- }
441
- });
442
- return ok({
443
- setQuote,
444
- dispose: () => {
445
- handle.dispose();
446
- removeSlot(slotId);
447
- }
448
- });
449
- } catch (e) {
450
- return err({
451
- kind: "genericError",
452
- message: e instanceof Error ? e.message : "Apple Pay setup failed"
453
- });
454
- }
1058
+ );
1059
+ }
1060
+
1061
+ // src/components/auth.tsx
1062
+ import { jsx as jsx6 } from "react/jsx-runtime";
1063
+ function MoonPayAuth({ onEvent, style }) {
1064
+ return /* @__PURE__ */ jsx6(
1065
+ MoonPayFrameView,
1066
+ {
1067
+ spec: authSpec,
1068
+ props: {},
1069
+ style,
1070
+ defaultStyle: { flex: 1 },
1071
+ onEvent
455
1072
  }
456
- async function setupBuy(opts) {
457
- const channelId = `buy-${Date.now()}`;
458
- const url = buildFrameUrl(
459
- FRAME_PATHS.buy,
460
- {
461
- channelId,
462
- clientToken: core.context.clientToken,
463
- signature: opts.quote,
464
- ...opts.externalTransactionId && { externalTransactionId: opts.externalTransactionId }
465
- },
466
- { frameBaseUrl }
467
- );
468
- try {
469
- const { promise } = createManagedFrame({ url, channelId, hidden: true });
470
- const { handle, slotId } = await promise;
471
- const setQuote = (signature) => {
472
- handle.sendMessage({
473
- version: 2,
474
- meta: { channelId },
475
- kind: "setQuote",
476
- payload: { quote: { signature } }
477
- });
478
- };
479
- handle.onMessage((msg) => {
480
- switch (msg.kind) {
481
- case "ready":
482
- opts.onEvent?.({ kind: "ready" });
483
- break;
484
- case "complete":
485
- opts.onEvent?.({
486
- kind: "complete",
487
- payload: msg.payload
488
- });
489
- break;
490
- case "challenge":
491
- opts.onEvent?.({
492
- kind: "challenge",
493
- payload: msg.payload
494
- });
495
- break;
496
- case "error":
497
- opts.onEvent?.({
498
- kind: "error",
499
- payload: msg.payload
500
- });
501
- break;
502
- }
503
- });
504
- return ok({
505
- setQuote,
506
- dispose: () => {
507
- handle.dispose();
508
- removeSlot(slotId);
509
- }
510
- });
511
- } catch (e) {
512
- return err({
513
- kind: "genericError",
514
- message: e instanceof Error ? e.message : "Buy setup failed"
515
- });
516
- }
1073
+ );
1074
+ }
1075
+
1076
+ // src/components/buy-button.tsx
1077
+ import { jsx as jsx7 } from "react/jsx-runtime";
1078
+ function MoonPayBuyButton({ quote, onEvent, style }) {
1079
+ return /* @__PURE__ */ jsx7(
1080
+ MoonPayFrameView,
1081
+ {
1082
+ spec: buyButtonSpec,
1083
+ props: { quote },
1084
+ style,
1085
+ defaultStyle: { height: 48 },
1086
+ onEvent
517
1087
  }
518
- async function setupBuyButton(opts) {
519
- const channelId = `buy-button-${Date.now()}`;
520
- const url = buildFrameUrl(
521
- FRAME_PATHS.buyButton,
522
- {
523
- channelId,
524
- clientToken: core.context.clientToken,
525
- signature: opts.quote
526
- },
527
- { frameBaseUrl }
528
- );
529
- try {
530
- const { promise } = createManagedFrame({ url, channelId, hidden: false });
531
- const { handle, slotId } = await promise;
532
- const setQuote = (signature) => {
533
- handle.sendMessage({
534
- version: 2,
535
- meta: { channelId },
536
- kind: "setQuote",
537
- payload: { quote: { signature } }
538
- });
539
- };
540
- handle.onMessage((msg) => {
541
- switch (msg.kind) {
542
- case "complete":
543
- opts.onEvent?.({
544
- kind: "complete",
545
- payload: msg.payload
546
- });
547
- break;
548
- case "challenge":
549
- opts.onEvent?.({
550
- kind: "challenge",
551
- payload: msg.payload
552
- });
553
- break;
554
- case "error":
555
- opts.onEvent?.({
556
- kind: "error",
557
- payload: msg.payload
558
- });
559
- break;
560
- }
561
- });
562
- return ok({
563
- setQuote,
564
- dispose: () => {
565
- handle.dispose();
566
- removeSlot(slotId);
567
- }
568
- });
569
- } catch (e) {
570
- return err({
571
- kind: "genericError",
572
- message: e instanceof Error ? e.message : "Buy button setup failed"
573
- });
574
- }
1088
+ );
1089
+ }
1090
+
1091
+ // src/components/buy-frame.tsx
1092
+ import { jsx as jsx8 } from "react/jsx-runtime";
1093
+ function MoonPayBuyFrame({
1094
+ quote,
1095
+ externalTransactionId,
1096
+ onEvent
1097
+ }) {
1098
+ return /* @__PURE__ */ jsx8(
1099
+ MoonPayFrameView,
1100
+ {
1101
+ spec: buySpec,
1102
+ props: { quote, externalTransactionId },
1103
+ defaultStyle: {},
1104
+ onEvent
575
1105
  }
576
- async function setupGooglePay(opts) {
577
- const channelId = `googlepay-${Date.now()}`;
578
- const url = buildFrameUrl(
579
- FRAME_PATHS.googlePay,
580
- {
581
- clientToken: core.context.clientToken,
582
- signature: opts.quote,
583
- channelId,
584
- ...opts.externalTransactionId && { externalTransactionId: opts.externalTransactionId }
585
- },
586
- { frameBaseUrl }
587
- );
588
- try {
589
- const { promise } = createManagedFrame({ url, channelId, hidden: false });
590
- const { handle, slotId } = await promise;
591
- const setQuote = (signature) => {
592
- handle.sendMessage({
593
- version: 2,
594
- meta: { channelId },
595
- kind: "setQuote",
596
- payload: { quote: { signature } }
597
- });
598
- };
599
- handle.onMessage((msg) => {
600
- switch (msg.kind) {
601
- case "ready":
602
- opts.onEvent?.({ kind: "ready" });
603
- break;
604
- case "complete":
605
- opts.onEvent?.({
606
- kind: "complete",
607
- payload: msg.payload
608
- });
609
- break;
610
- case "challenge":
611
- opts.onEvent?.({
612
- kind: "challenge",
613
- payload: msg.payload
614
- });
615
- break;
616
- case "error": {
617
- const payload = msg.payload;
618
- if (payload.code === "quoteExpired") {
619
- opts.onEvent?.({ kind: "quoteExpired", payload: { setQuote } });
620
- } else if (payload.code === "googlePayUnavailable") {
621
- opts.onEvent?.({ kind: "unsupported" });
622
- } else {
623
- const kind = payload.code === "generic" ? "genericError" : payload.code;
624
- opts.onEvent?.({
625
- kind: "error",
626
- payload: { kind, message: payload.message }
627
- });
628
- }
629
- break;
630
- }
631
- }
632
- });
633
- return ok({
634
- setQuote,
635
- dispose: () => {
636
- handle.dispose();
637
- removeSlot(slotId);
638
- }
639
- });
640
- } catch (e) {
641
- return err({
642
- kind: "genericError",
643
- message: e instanceof Error ? e.message : "Google Pay setup failed"
644
- });
645
- }
1106
+ );
1107
+ }
1108
+
1109
+ // src/components/challenge.tsx
1110
+ import { jsx as jsx9 } from "react/jsx-runtime";
1111
+ function MoonPayChallenge({ url, onEvent, style }) {
1112
+ return /* @__PURE__ */ jsx9(
1113
+ MoonPayFrameView,
1114
+ {
1115
+ spec: challengeSpec,
1116
+ props: { url },
1117
+ style,
1118
+ defaultStyle: { flex: 1 },
1119
+ onEvent
646
1120
  }
647
- async function resetConnection() {
648
- const channelId = `reset-${Date.now()}`;
649
- const url = buildFrameUrl(FRAME_PATHS.reset, { sessionToken, channelId }, { frameBaseUrl });
650
- try {
651
- const { promise } = createManagedFrame({
652
- url,
653
- channelId,
654
- hidden: true,
655
- handshakeTimeout: 5e3
656
- });
657
- const { handle, slotId } = await promise;
658
- return new Promise((resolve) => {
659
- const timeout = setTimeout(() => {
660
- handle.dispose();
661
- removeSlot(slotId);
662
- resolve(ok(void 0));
663
- }, 5e3);
664
- handle.onMessage((msg) => {
665
- if (msg.kind === "complete" || msg.kind === "error") {
666
- clearTimeout(timeout);
667
- handle.dispose();
668
- removeSlot(slotId);
669
- resolve(ok(void 0));
670
- }
671
- });
672
- });
673
- } catch {
674
- return ok(void 0);
675
- }
1121
+ );
1122
+ }
1123
+
1124
+ // src/components/connect.tsx
1125
+ import { jsx as jsx10 } from "react/jsx-runtime";
1126
+ function MoonPayConnect({ theme, onEvent, style }) {
1127
+ return /* @__PURE__ */ jsx10(
1128
+ MoonPayFrameView,
1129
+ {
1130
+ spec: connectSpec,
1131
+ props: { theme },
1132
+ style,
1133
+ defaultStyle: { flex: 1 },
1134
+ onEvent
676
1135
  }
677
- async function setupChallenge(opts) {
678
- let url;
679
- try {
680
- url = new URL(opts.url);
681
- } catch {
682
- return err({ kind: "configurationError", message: "Invalid challenge URL" });
683
- }
684
- let channelId = url.searchParams.get("channelId") ?? "";
685
- if (!channelId) {
686
- channelId = `challenge-${Date.now()}`;
687
- url.searchParams.set("channelId", channelId);
688
- }
689
- try {
690
- const { promise } = createManagedFrame({
691
- url: url.toString(),
692
- channelId,
693
- hidden: false
694
- });
695
- const { handle, slotId } = await promise;
696
- handle.onMessage((msg) => {
697
- switch (msg.kind) {
698
- case "ready":
699
- opts.onEvent?.({ kind: "ready" });
700
- break;
701
- case "complete":
702
- opts.onEvent?.({
703
- kind: "complete",
704
- payload: msg.payload
705
- });
706
- break;
707
- case "cancelled":
708
- opts.onEvent?.({
709
- kind: "cancelled",
710
- payload: msg.payload
711
- });
712
- break;
713
- case "error":
714
- opts.onEvent?.({
715
- kind: "error",
716
- payload: msg.payload
717
- });
718
- break;
719
- }
720
- });
721
- return ok({
722
- dispose: () => {
723
- handle.dispose();
724
- removeSlot(slotId);
725
- }
726
- });
727
- } catch (e) {
728
- return err({
729
- kind: "genericError",
730
- message: e instanceof Error ? e.message : "Challenge setup failed"
731
- });
732
- }
1136
+ );
1137
+ }
1138
+
1139
+ // src/components/connection-check.tsx
1140
+ import { jsx as jsx11 } from "react/jsx-runtime";
1141
+ function MoonPayConnectionCheck({
1142
+ skipKyc,
1143
+ onEvent
1144
+ }) {
1145
+ return /* @__PURE__ */ jsx11(
1146
+ MoonPayFrameView,
1147
+ {
1148
+ spec: connectionCheckSpec,
1149
+ props: { skipKyc },
1150
+ defaultStyle: {},
1151
+ onEvent
733
1152
  }
734
- async function setupAddCard(opts) {
735
- const channelId = `add-card-${Date.now()}`;
736
- const url = buildFrameUrl(
737
- FRAME_PATHS.addCard,
738
- { channelId, clientToken: core.context.clientToken },
739
- { frameBaseUrl }
740
- );
741
- try {
742
- const { promise } = createManagedFrame({ url, channelId, hidden: false });
743
- const { handle, slotId } = await promise;
744
- handle.onMessage((msg) => {
745
- switch (msg.kind) {
746
- case "complete":
747
- opts.onEvent?.({ kind: "complete", payload: msg.payload });
748
- break;
749
- case "error":
750
- opts.onEvent?.({
751
- kind: "error",
752
- payload: msg.payload
753
- });
754
- break;
755
- }
756
- });
757
- return ok({
758
- dispose: () => {
759
- handle.dispose();
760
- removeSlot(slotId);
761
- }
762
- });
763
- } catch (e) {
764
- return err({
765
- kind: "genericError",
766
- message: e instanceof Error ? e.message : "Add card setup failed"
767
- });
768
- }
1153
+ );
1154
+ }
1155
+
1156
+ // src/components/connection-reset.tsx
1157
+ import { jsx as jsx12 } from "react/jsx-runtime";
1158
+ function MoonPayConnectionReset({ onEvent }) {
1159
+ return /* @__PURE__ */ jsx12(MoonPayFrameView, { spec: connectionResetSpec, props: {}, defaultStyle: {}, onEvent });
1160
+ }
1161
+
1162
+ // src/components/google-pay-button.tsx
1163
+ import { jsx as jsx13 } from "react/jsx-runtime";
1164
+ function MoonPayGooglePayButton({
1165
+ quote,
1166
+ externalTransactionId,
1167
+ onEvent,
1168
+ style
1169
+ }) {
1170
+ return /* @__PURE__ */ jsx13(
1171
+ MoonPayFrameView,
1172
+ {
1173
+ spec: googlePaySpec,
1174
+ props: { quote, externalTransactionId },
1175
+ style,
1176
+ defaultStyle: { height: 48 },
1177
+ onEvent
769
1178
  }
770
- return {
771
- getConnection,
772
- connect,
773
- setupAuth,
774
- getPaymentMethods: () => core.getPaymentMethods(),
775
- getQuote: (params) => core.getQuote(params),
776
- listTransactions: (params) => core.listTransactions(params),
777
- getTransaction: (id) => core.getTransaction(id),
778
- setupWidget,
779
- setupApplePay,
780
- setupBuy,
781
- setupBuyButton,
782
- setupGooglePay,
783
- deletePaymentMethod: (id) => core.deletePaymentMethod(id),
784
- resetConnection,
785
- setupChallenge,
786
- setupAddCard,
787
- createIdentity: (body) => core.createIdentity(body),
788
- getIdentity: (id) => core.getIdentity(id),
789
- updateIdentity: (id, body) => core.updateIdentity(id, body),
790
- verifyIdentity: (id) => core.verifyIdentity(id),
791
- getIdentityUploadUrl: (id, body) => core.getIdentityUploadUrl(id, body),
792
- submitIdentityFiles: (id, body) => core.submitIdentityFiles(id, body)
793
- };
794
- }, [sessionToken, frameBaseUrl, core, addSlot, removeSlot]);
795
- return /* @__PURE__ */ jsxs(MoonPayContext.Provider, { value: { client }, children: [
796
- children,
797
- frameSlots.map((slot) => /* @__PURE__ */ jsx2(MoonPayFrame, { transport: slot.transport, hidden: slot.hidden }, slot.id))
798
- ] });
1179
+ );
799
1180
  }
800
- function useMoonPay() {
801
- const ctx = useContext(MoonPayContext);
802
- if (!ctx) {
803
- throw new Error("useMoonPay must be used within a <MoonPayProvider>");
804
- }
805
- return ctx;
1181
+
1182
+ // src/components/widget.tsx
1183
+ import { jsx as jsx14 } from "react/jsx-runtime";
1184
+ function MoonPayWidget({ quote, onEvent, style }) {
1185
+ return /* @__PURE__ */ jsx14(
1186
+ MoonPayFrameView,
1187
+ {
1188
+ spec: widgetSpec,
1189
+ props: { quote },
1190
+ style,
1191
+ defaultStyle: { flex: 1 },
1192
+ onEvent
1193
+ }
1194
+ );
806
1195
  }
807
1196
  export {
1197
+ ConnectionStatus2 as ConnectionStatus,
1198
+ MoonPayAddCard,
1199
+ MoonPayApplePayButton,
1200
+ MoonPayAuth,
1201
+ MoonPayBuyButton,
1202
+ MoonPayBuyFrame,
1203
+ MoonPayChallenge,
1204
+ MoonPayConnect,
1205
+ MoonPayConnectionCheck,
1206
+ MoonPayConnectionReset,
808
1207
  MoonPayFrame,
1208
+ MoonPayGooglePayButton,
809
1209
  MoonPayProvider,
1210
+ MoonPayWidget,
810
1211
  WebViewTransport,
811
1212
  useMoonPay
812
1213
  };