@moonpay/platform-sdk-react-native 1.8.0 → 1.10.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/README.md CHANGED
@@ -63,6 +63,53 @@ export function App() {
63
63
 
64
64
  Pass an optional `theme={{ appearance: 'light' | 'dark' }}` to render every MoonPay frame in light or dark mode. Omit it to follow the customer's system preference. The connect flow can override it per call (`client.connect({ theme })` or `<MoonPayConnect theme={...} />`).
65
65
 
66
+ #### Providing the session token later
67
+
68
+ The `sessionToken` prop is optional. If you don't have it when the provider mounts (for example, you fetch it from your server after the customer signs in), mount `MoonPayProvider` without it and call `initialize()` from `useMoonPay()` once the token is available:
69
+
70
+ ```tsx
71
+ import { MoonPayProvider, useMoonPay } from '@moonpay/platform-sdk-react-native';
72
+
73
+ export function App() {
74
+ return (
75
+ <MoonPayProvider>
76
+ <YourApp />
77
+ </MoonPayProvider>
78
+ );
79
+ }
80
+
81
+ function SignInScreen() {
82
+ const { initialize, isInitialized } = useMoonPay();
83
+
84
+ const onSignedIn = async () => {
85
+ const sessionToken = await fetchSessionTokenFromYourServer();
86
+ initialize(sessionToken); // the SDK is now ready
87
+ };
88
+
89
+ // ...
90
+ }
91
+ ```
92
+
93
+ `isInitialized` is `true` once a token is available (via the prop or `initialize()`). Calling a connection method before then resolves to an `err()` Result. You can also call `initialize()` again later to replace the token (for example, after a refresh). Choose one style — the controlled `sessionToken` prop or `initialize()`; if both are used, the prop wins.
94
+
95
+ Because `initialize()` updates React state, the `client` that carries the new token is available on the **next render** — not synchronously within the same call. Gate your connection flow on `isInitialized` (or read `client` from `useMoonPay()` after the re-render) rather than reusing a `client` captured before `initialize()`:
96
+
97
+ ```tsx
98
+ function BuyScreen() {
99
+ const { client, isInitialized } = useMoonPay();
100
+
101
+ useEffect(() => {
102
+ if (!isInitialized) return;
103
+ // `client` here reflects the initialized session token
104
+ client.getConnection().then((result) => {
105
+ // ...
106
+ });
107
+ }, [isInitialized, client]);
108
+ }
109
+ ```
110
+
111
+ Reusing a `client` reference captured before `initialize()` runs against the pre-initialization client and resolves to an `err()` (no session token).
112
+
66
113
  **3. Check the connection and connect the customer:**
67
114
 
68
115
  ```tsx
package/dist/index.cjs CHANGED
@@ -70,7 +70,8 @@ var applePaySpec = {
70
70
  hidden: false,
71
71
  buildParams: (ctx, props) => ({
72
72
  clientToken: ctx.core.context.clientToken,
73
- signature: props.quote
73
+ signature: props.quote,
74
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
74
75
  }),
75
76
  createCommands: createQuoteCommands,
76
77
  reactiveProps: {
@@ -80,6 +81,8 @@ var applePaySpec = {
80
81
  switch (msg.kind) {
81
82
  case "ready":
82
83
  return { kind: "ready" };
84
+ case "buttonPressed":
85
+ return { kind: "buttonPressed" };
83
86
  case "complete":
84
87
  return { kind: "complete", payload: msg.payload };
85
88
  case "challenge":
@@ -121,6 +124,8 @@ var googlePaySpec = {
121
124
  switch (msg.kind) {
122
125
  case "ready":
123
126
  return { kind: "ready" };
127
+ case "buttonPressed":
128
+ return { kind: "buttonPressed" };
124
129
  case "complete":
125
130
  return { kind: "complete", payload: msg.payload };
126
131
  case "challenge":
@@ -151,7 +156,8 @@ var buyButtonSpec = {
151
156
  hidden: false,
152
157
  buildParams: (ctx, props) => ({
153
158
  clientToken: ctx.core.context.clientToken,
154
- signature: props.quote
159
+ signature: props.quote,
160
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
155
161
  }),
156
162
  createCommands: createQuoteCommands,
157
163
  reactiveProps: {
@@ -161,6 +167,8 @@ var buyButtonSpec = {
161
167
  switch (msg.kind) {
162
168
  case "ready":
163
169
  return { kind: "ready" };
170
+ case "buttonPressed":
171
+ return { kind: "buttonPressed" };
164
172
  case "complete":
165
173
  return { kind: "complete", payload: msg.payload };
166
174
  case "challenge":
@@ -190,6 +198,14 @@ function applyCredentialsOnComplete(msg, ctx) {
190
198
  ctx.core.context.setAccessToken(creds.accessToken);
191
199
  ctx.core.context.setClientToken(creds.clientToken);
192
200
  }
201
+ function requireSessionToken(ctx) {
202
+ if (!ctx.sessionToken) {
203
+ throw new Error(
204
+ "No session token \u2014 pass sessionToken to <MoonPayProvider> or call initialize() from useMoonPay() before starting a connection."
205
+ );
206
+ }
207
+ return ctx.sessionToken;
208
+ }
193
209
  var connectionCheckSpec = {
194
210
  channelPrefix: "check",
195
211
  path: import_platform_sdk_core.FRAME_PATHS.checkConnection,
@@ -197,7 +213,7 @@ var connectionCheckSpec = {
197
213
  needsKeyPair: true,
198
214
  handshakeTimeout: 1e4,
199
215
  buildParams: (ctx, props, publicKey) => ({
200
- sessionToken: ctx.sessionToken,
216
+ sessionToken: requireSessionToken(ctx),
201
217
  publicKey,
202
218
  ...props.skipKyc && { skipKyc: true }
203
219
  }),
@@ -219,7 +235,7 @@ var connectSpec = {
219
235
  hidden: false,
220
236
  needsKeyPair: true,
221
237
  buildParams: (ctx, props, publicKey) => ({
222
- sessionToken: ctx.sessionToken,
238
+ sessionToken: requireSessionToken(ctx),
223
239
  publicKey,
224
240
  // Per-call override; `applyThemeParam` in the engine fills the client
225
241
  // default for connect (and every other visible frame) when this is absent.
@@ -287,7 +303,8 @@ var widgetSpec = {
287
303
  buildParams: (ctx, props) => ({
288
304
  flow: "buy",
289
305
  clientToken: ctx.core.context.clientToken,
290
- quoteSignature: props.quote
306
+ quoteSignature: props.quote,
307
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
291
308
  }),
292
309
  mapMessage: (msg) => {
293
310
  switch (msg.kind) {
@@ -432,7 +449,7 @@ var connectionResetSpec = {
432
449
  path: import_platform_sdk_core.FRAME_PATHS.reset,
433
450
  hidden: true,
434
451
  handshakeTimeout: 5e3,
435
- buildParams: (ctx) => ({ sessionToken: ctx.sessionToken }),
452
+ buildParams: (ctx) => ({ sessionToken: requireSessionToken(ctx) }),
436
453
  mapMessage: (msg) => {
437
454
  if (msg.kind === "complete") return { kind: "complete" };
438
455
  if (msg.kind === "error") {
@@ -666,7 +683,10 @@ async function setupAddCard(deps, opts) {
666
683
  var import_result2 = require("@moonpay/platform-protocol/result");
667
684
  async function setupApplePay(deps, opts) {
668
685
  try {
669
- const { handle, dispose } = await deps.mountSession(applePaySpec, { quote: opts.quote });
686
+ const { handle, dispose } = await deps.mountSession(applePaySpec, {
687
+ quote: opts.quote,
688
+ externalTransactionId: opts.externalTransactionId
689
+ });
670
690
  handle.onEvent((event) => opts.onEvent?.(event));
671
691
  return (0, import_result2.ok)({ setQuote: handle.commands.setQuote, dispose });
672
692
  } catch (e) {
@@ -738,7 +758,10 @@ async function setupBuy(deps, opts) {
738
758
  var import_result5 = require("@moonpay/platform-protocol/result");
739
759
  async function setupBuyButton(deps, opts) {
740
760
  try {
741
- const { handle, dispose } = await deps.mountSession(buyButtonSpec, { quote: opts.quote });
761
+ const { handle, dispose } = await deps.mountSession(buyButtonSpec, {
762
+ quote: opts.quote,
763
+ externalTransactionId: opts.externalTransactionId
764
+ });
742
765
  handle.onEvent((event) => opts.onEvent?.(event));
743
766
  return (0, import_result5.ok)({ setQuote: handle.commands.setQuote, dispose });
744
767
  } catch (e) {
@@ -885,7 +908,10 @@ async function setupGooglePay(deps, opts) {
885
908
  var import_result12 = require("@moonpay/platform-protocol/result");
886
909
  async function setupWidget(deps, opts) {
887
910
  try {
888
- const { handle, dispose } = await deps.mountSession(widgetSpec, { quote: opts.quote });
911
+ const { handle, dispose } = await deps.mountSession(widgetSpec, {
912
+ quote: opts.quote,
913
+ externalTransactionId: opts.externalTransactionId
914
+ });
889
915
  handle.onEvent((event) => opts.onEvent?.(event));
890
916
  return (0, import_result12.ok)({ dispose });
891
917
  } catch (e) {
@@ -1166,13 +1192,15 @@ var styles = import_react_native2.StyleSheet.create({
1166
1192
  var import_jsx_runtime3 = require("react/jsx-runtime");
1167
1193
  var MoonPayContext = (0, import_react3.createContext)(null);
1168
1194
  function MoonPayProvider({
1169
- sessionToken,
1195
+ sessionToken: sessionTokenProp,
1170
1196
  apiBaseUrl,
1171
1197
  frameBaseUrl,
1172
1198
  theme,
1173
1199
  children
1174
1200
  }) {
1175
1201
  const [frameSlots, setFrameSlots] = (0, import_react3.useState)([]);
1202
+ const [internalToken, setInternalToken] = (0, import_react3.useState)(void 0);
1203
+ const sessionToken = sessionTokenProp ?? internalToken;
1176
1204
  const addSlot = (0, import_react3.useCallback)((slot) => {
1177
1205
  setFrameSlots((prev) => [...prev, slot]);
1178
1206
  }, []);
@@ -1188,6 +1216,14 @@ function MoonPayProvider({
1188
1216
  });
1189
1217
  }
1190
1218
  const core = coreRef.current;
1219
+ const initialize = (0, import_react3.useCallback)(
1220
+ (token) => {
1221
+ core.context.setAccessToken("");
1222
+ core.context.setClientToken("");
1223
+ setInternalToken(token);
1224
+ },
1225
+ [core]
1226
+ );
1191
1227
  const client = (0, import_react3.useMemo)(() => {
1192
1228
  const specCtx = { sessionToken, core, frameBaseUrl, theme };
1193
1229
  return createRNClient({
@@ -1195,21 +1231,28 @@ function MoonPayProvider({
1195
1231
  core
1196
1232
  });
1197
1233
  }, [sessionToken, frameBaseUrl, core, addSlot, removeSlot, theme?.appearance]);
1198
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MoonPayContext.Provider, { value: { client, sessionToken, core, frameBaseUrl, theme }, children: [
1199
- children,
1200
- frameSlots.filter((slot) => slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonPayFrame, { transport: slot.transport, hidden: true }, slot.id)),
1201
- frameSlots.filter((slot) => !slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1202
- VisibleFrameSlotSheet,
1203
- {
1204
- slot,
1205
- onClose: () => {
1206
- slot.dispose();
1207
- removeSlot(slot.id);
1208
- }
1209
- },
1210
- slot.id
1211
- ))
1212
- ] });
1234
+ const isInitialized = sessionToken !== void 0;
1235
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1236
+ MoonPayContext.Provider,
1237
+ {
1238
+ value: { client, sessionToken, core, frameBaseUrl, theme, initialize, isInitialized },
1239
+ children: [
1240
+ children,
1241
+ frameSlots.filter((slot) => slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonPayFrame, { transport: slot.transport, hidden: true }, slot.id)),
1242
+ frameSlots.filter((slot) => !slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1243
+ VisibleFrameSlotSheet,
1244
+ {
1245
+ slot,
1246
+ onClose: () => {
1247
+ slot.dispose();
1248
+ removeSlot(slot.id);
1249
+ }
1250
+ },
1251
+ slot.id
1252
+ ))
1253
+ ]
1254
+ }
1255
+ );
1213
1256
  }
1214
1257
  function useMoonPayContext() {
1215
1258
  const ctx = (0, import_react3.useContext)(MoonPayContext);
@@ -1219,7 +1262,8 @@ function useMoonPayContext() {
1219
1262
  return ctx;
1220
1263
  }
1221
1264
  function useMoonPay() {
1222
- return useMoonPayContext();
1265
+ const { client, initialize, isInitialized } = useMoonPayContext();
1266
+ return { client, initialize, isInitialized };
1223
1267
  }
1224
1268
 
1225
1269
  // src/frame-view.tsx
@@ -1331,6 +1375,7 @@ function MoonPayAddCard({ onEvent, style }) {
1331
1375
  var import_jsx_runtime6 = require("react/jsx-runtime");
1332
1376
  function MoonPayApplePayButton({
1333
1377
  quote,
1378
+ externalTransactionId,
1334
1379
  onEvent,
1335
1380
  style
1336
1381
  }) {
@@ -1338,7 +1383,7 @@ function MoonPayApplePayButton({
1338
1383
  MoonPayFrameView,
1339
1384
  {
1340
1385
  spec: applePaySpec,
1341
- props: { quote },
1386
+ props: { quote, externalTransactionId },
1342
1387
  style,
1343
1388
  defaultStyle: { height: 48 },
1344
1389
  onEvent
@@ -1363,12 +1408,17 @@ function MoonPayAuth({ onEvent, style }) {
1363
1408
 
1364
1409
  // src/components/buy-button.tsx
1365
1410
  var import_jsx_runtime8 = require("react/jsx-runtime");
1366
- function MoonPayBuyButton({ quote, onEvent, style }) {
1411
+ function MoonPayBuyButton({
1412
+ quote,
1413
+ externalTransactionId,
1414
+ onEvent,
1415
+ style
1416
+ }) {
1367
1417
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1368
1418
  MoonPayFrameView,
1369
1419
  {
1370
1420
  spec: buyButtonSpec,
1371
- props: { quote },
1421
+ props: { quote, externalTransactionId },
1372
1422
  style,
1373
1423
  defaultStyle: { height: 48 },
1374
1424
  onEvent
@@ -1484,12 +1534,17 @@ function MoonPayGooglePayButton({
1484
1534
 
1485
1535
  // src/components/widget.tsx
1486
1536
  var import_jsx_runtime16 = require("react/jsx-runtime");
1487
- function MoonPayWidget({ quote, onEvent, style }) {
1537
+ function MoonPayWidget({
1538
+ quote,
1539
+ externalTransactionId,
1540
+ onEvent,
1541
+ style
1542
+ }) {
1488
1543
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1489
1544
  MoonPayFrameView,
1490
1545
  {
1491
1546
  spec: widgetSpec,
1492
- props: { quote },
1547
+ props: { quote, externalTransactionId },
1493
1548
  style,
1494
1549
  defaultStyle: { flex: 1 },
1495
1550
  onEvent