@moonpay/platform-sdk-react-native 0.3.0-next.1 → 1.0.0

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