@moonpay/platform-sdk-react-native 1.9.0 → 1.11.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
@@ -71,7 +71,8 @@ var applePaySpec = {
71
71
  buildParams: (ctx, props) => ({
72
72
  clientToken: ctx.core.context.clientToken,
73
73
  signature: props.quote,
74
- ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
74
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId },
75
+ ...(0, import_platform_sdk_core.presentationParams)(props.presentation)
75
76
  }),
76
77
  createCommands: createQuoteCommands,
77
78
  reactiveProps: {
@@ -114,7 +115,8 @@ var googlePaySpec = {
114
115
  buildParams: (ctx, props) => ({
115
116
  clientToken: ctx.core.context.clientToken,
116
117
  signature: props.quote,
117
- ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
118
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId },
119
+ ...(0, import_platform_sdk_core.presentationParams)(props.presentation)
118
120
  }),
119
121
  createCommands: createQuoteCommands,
120
122
  reactiveProps: {
@@ -157,7 +159,8 @@ var buyButtonSpec = {
157
159
  buildParams: (ctx, props) => ({
158
160
  clientToken: ctx.core.context.clientToken,
159
161
  signature: props.quote,
160
- ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
162
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId },
163
+ ...(0, import_platform_sdk_core.presentationParams)(props.presentation)
161
164
  }),
162
165
  createCommands: createQuoteCommands,
163
166
  reactiveProps: {
@@ -198,6 +201,14 @@ function applyCredentialsOnComplete(msg, ctx) {
198
201
  ctx.core.context.setAccessToken(creds.accessToken);
199
202
  ctx.core.context.setClientToken(creds.clientToken);
200
203
  }
204
+ function requireSessionToken(ctx) {
205
+ if (!ctx.sessionToken) {
206
+ throw new Error(
207
+ "No session token \u2014 pass sessionToken to <MoonPayProvider> or call initialize() from useMoonPay() before starting a connection."
208
+ );
209
+ }
210
+ return ctx.sessionToken;
211
+ }
201
212
  var connectionCheckSpec = {
202
213
  channelPrefix: "check",
203
214
  path: import_platform_sdk_core.FRAME_PATHS.checkConnection,
@@ -205,7 +216,7 @@ var connectionCheckSpec = {
205
216
  needsKeyPair: true,
206
217
  handshakeTimeout: 1e4,
207
218
  buildParams: (ctx, props, publicKey) => ({
208
- sessionToken: ctx.sessionToken,
219
+ sessionToken: requireSessionToken(ctx),
209
220
  publicKey,
210
221
  ...props.skipKyc && { skipKyc: true }
211
222
  }),
@@ -226,13 +237,22 @@ var connectSpec = {
226
237
  path: import_platform_sdk_core.FRAME_PATHS.connect,
227
238
  hidden: false,
228
239
  needsKeyPair: true,
229
- buildParams: (ctx, props, publicKey) => ({
230
- sessionToken: ctx.sessionToken,
231
- publicKey,
232
- // Per-call override; `applyThemeParam` in the engine fills the client
233
- // default for connect (and every other visible frame) when this is absent.
234
- ...(0, import_platform_sdk_core.themeParams)(props.theme)
235
- }),
240
+ buildParams: (ctx, props, publicKey) => {
241
+ const clientToken = ctx.core.context.clientToken;
242
+ if (!clientToken) {
243
+ throw new Error(
244
+ 'No clientToken in context \u2014 call getConnection() first and ensure it resolved with status "connectionRequired".'
245
+ );
246
+ }
247
+ return {
248
+ clientToken,
249
+ publicKey,
250
+ // Per-call override; `applyThemeParam` in the engine fills the client
251
+ // default for connect (and every other visible frame) when this is absent.
252
+ ...(0, import_platform_sdk_core.themeParams)(props.theme),
253
+ ...(0, import_platform_sdk_core.presentationParams)(props.presentation)
254
+ };
255
+ },
236
256
  onMessageEffect: applyCredentialsOnComplete,
237
257
  mapMessage: (msg) => {
238
258
  switch (msg.kind) {
@@ -256,14 +276,14 @@ var authSpec = {
256
276
  path: import_platform_sdk_core.FRAME_PATHS.auth,
257
277
  hidden: false,
258
278
  needsKeyPair: true,
259
- buildParams: (ctx, _props, publicKey) => {
279
+ buildParams: (ctx, props, publicKey) => {
260
280
  const clientToken = ctx.core.context.clientToken;
261
281
  if (!clientToken) {
262
282
  throw new Error(
263
283
  'No clientToken in context \u2014 call getConnection() first and ensure it resolved with status "connectionRequired".'
264
284
  );
265
285
  }
266
- return { clientToken, publicKey };
286
+ return { clientToken, publicKey, ...(0, import_platform_sdk_core.presentationParams)(props.presentation) };
267
287
  },
268
288
  onMessageEffect: applyCredentialsOnComplete,
269
289
  mapMessage: (msg) => {
@@ -296,7 +316,8 @@ var widgetSpec = {
296
316
  flow: "buy",
297
317
  clientToken: ctx.core.context.clientToken,
298
318
  quoteSignature: props.quote,
299
- ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId }
319
+ ...props.externalTransactionId && { externalTransactionId: props.externalTransactionId },
320
+ ...(0, import_platform_sdk_core.presentationParams)(props.presentation)
300
321
  }),
301
322
  mapMessage: (msg) => {
302
323
  switch (msg.kind) {
@@ -358,7 +379,10 @@ var addCardSpec = {
358
379
  channelPrefix: "add-card",
359
380
  path: import_platform_sdk_core.FRAME_PATHS.addCard,
360
381
  hidden: false,
361
- buildParams: (ctx) => ({ clientToken: ctx.core.context.clientToken }),
382
+ buildParams: (ctx, props) => ({
383
+ clientToken: ctx.core.context.clientToken,
384
+ ...(0, import_platform_sdk_core.presentationParams)(props.presentation)
385
+ }),
362
386
  mapMessage: (msg) => {
363
387
  switch (msg.kind) {
364
388
  case "ready":
@@ -383,7 +407,10 @@ var customerExportSpec = {
383
407
  channelPrefix: "customer-export",
384
408
  path: import_platform_sdk_core.FRAME_PATHS.customerExport,
385
409
  hidden: false,
386
- buildParams: (ctx) => ({ clientToken: ctx.core.context.clientToken }),
410
+ buildParams: (ctx, props) => ({
411
+ clientToken: ctx.core.context.clientToken,
412
+ ...(0, import_platform_sdk_core.presentationParams)(props.presentation)
413
+ }),
387
414
  mapMessage: (msg) => {
388
415
  switch (msg.kind) {
389
416
  case "ready":
@@ -415,7 +442,7 @@ var challengeSpec = {
415
442
  buildUrl: (_ctx, props, channelId) => {
416
443
  const url = new URL(props.url);
417
444
  url.searchParams.set("channelId", channelId);
418
- return url.toString();
445
+ return (0, import_platform_sdk_core.applyPresentationParam)(url.toString(), props.presentation);
419
446
  },
420
447
  mapMessage: (msg) => {
421
448
  switch (msg.kind) {
@@ -441,7 +468,7 @@ var connectionResetSpec = {
441
468
  path: import_platform_sdk_core.FRAME_PATHS.reset,
442
469
  hidden: true,
443
470
  handshakeTimeout: 5e3,
444
- buildParams: (ctx) => ({ sessionToken: ctx.sessionToken }),
471
+ buildParams: (ctx) => ({ sessionToken: requireSessionToken(ctx) }),
445
472
  mapMessage: (msg) => {
446
473
  if (msg.kind === "complete") return { kind: "complete" };
447
474
  if (msg.kind === "error") {
@@ -660,7 +687,9 @@ var import_react3 = require("react");
660
687
  var import_result = require("@moonpay/platform-protocol/result");
661
688
  async function setupAddCard(deps, opts) {
662
689
  try {
663
- const { handle, dispose } = await deps.mountSession(addCardSpec, {});
690
+ const { handle, dispose } = await deps.mountSession(addCardSpec, {
691
+ presentation: opts.presentation
692
+ });
664
693
  handle.onEvent((event) => opts.onEvent?.(event));
665
694
  return (0, import_result.ok)({ dispose });
666
695
  } catch (e) {
@@ -677,7 +706,8 @@ async function setupApplePay(deps, opts) {
677
706
  try {
678
707
  const { handle, dispose } = await deps.mountSession(applePaySpec, {
679
708
  quote: opts.quote,
680
- externalTransactionId: opts.externalTransactionId
709
+ externalTransactionId: opts.externalTransactionId,
710
+ presentation: opts.presentation
681
711
  });
682
712
  handle.onEvent((event) => opts.onEvent?.(event));
683
713
  return (0, import_result2.ok)({ setQuote: handle.commands.setQuote, dispose });
@@ -699,7 +729,9 @@ async function setupAuth(deps, opts) {
699
729
  });
700
730
  }
701
731
  try {
702
- const { handle, dispose } = await deps.mountSession(authSpec, {});
732
+ const { handle, dispose } = await deps.mountSession(authSpec, {
733
+ presentation: opts.presentation
734
+ });
703
735
  return await new Promise((resolve) => {
704
736
  handle.onEvent((event) => {
705
737
  opts.onEvent?.(event);
@@ -752,7 +784,8 @@ async function setupBuyButton(deps, opts) {
752
784
  try {
753
785
  const { handle, dispose } = await deps.mountSession(buyButtonSpec, {
754
786
  quote: opts.quote,
755
- externalTransactionId: opts.externalTransactionId
787
+ externalTransactionId: opts.externalTransactionId,
788
+ presentation: opts.presentation
756
789
  });
757
790
  handle.onEvent((event) => opts.onEvent?.(event));
758
791
  return (0, import_result5.ok)({ setQuote: handle.commands.setQuote, dispose });
@@ -775,7 +808,10 @@ async function setupChallenge(deps, opts) {
775
808
  });
776
809
  }
777
810
  try {
778
- const { handle, dispose } = await deps.mountSession(challengeSpec, { url: opts.url });
811
+ const { handle, dispose } = await deps.mountSession(challengeSpec, {
812
+ url: opts.url,
813
+ presentation: opts.presentation
814
+ });
779
815
  handle.onEvent((event) => opts.onEvent?.(event));
780
816
  return (0, import_result6.ok)({ dispose });
781
817
  } catch (e) {
@@ -790,7 +826,10 @@ async function setupChallenge(deps, opts) {
790
826
  var import_result7 = require("@moonpay/platform-protocol/result");
791
827
  async function connect(deps, opts) {
792
828
  try {
793
- const { handle, dispose } = await deps.mountSession(connectSpec, { theme: opts.theme });
829
+ const { handle, dispose } = await deps.mountSession(connectSpec, {
830
+ theme: opts.theme,
831
+ presentation: opts.presentation
832
+ });
794
833
  return await new Promise((resolve) => {
795
834
  handle.onEvent((event) => {
796
835
  opts.onEvent?.(event);
@@ -867,7 +906,9 @@ async function resetConnection(deps) {
867
906
  var import_result10 = require("@moonpay/platform-protocol/result");
868
907
  async function setupCustomerExport(deps, opts) {
869
908
  try {
870
- const { handle, dispose } = await deps.mountSession(customerExportSpec, {});
909
+ const { handle, dispose } = await deps.mountSession(customerExportSpec, {
910
+ presentation: opts.presentation
911
+ });
871
912
  handle.onEvent((event) => opts.onEvent?.(event));
872
913
  return (0, import_result10.ok)({ dispose });
873
914
  } catch (e) {
@@ -884,7 +925,8 @@ async function setupGooglePay(deps, opts) {
884
925
  try {
885
926
  const { handle, dispose } = await deps.mountSession(googlePaySpec, {
886
927
  quote: opts.quote,
887
- externalTransactionId: opts.externalTransactionId
928
+ externalTransactionId: opts.externalTransactionId,
929
+ presentation: opts.presentation
888
930
  });
889
931
  handle.onEvent((event) => opts.onEvent?.(event));
890
932
  return (0, import_result11.ok)({ setQuote: handle.commands.setQuote, dispose });
@@ -902,7 +944,8 @@ async function setupWidget(deps, opts) {
902
944
  try {
903
945
  const { handle, dispose } = await deps.mountSession(widgetSpec, {
904
946
  quote: opts.quote,
905
- externalTransactionId: opts.externalTransactionId
947
+ externalTransactionId: opts.externalTransactionId,
948
+ presentation: opts.presentation
906
949
  });
907
950
  handle.onEvent((event) => opts.onEvent?.(event));
908
951
  return (0, import_result12.ok)({ dispose });
@@ -1184,13 +1227,15 @@ var styles = import_react_native2.StyleSheet.create({
1184
1227
  var import_jsx_runtime3 = require("react/jsx-runtime");
1185
1228
  var MoonPayContext = (0, import_react3.createContext)(null);
1186
1229
  function MoonPayProvider({
1187
- sessionToken,
1230
+ sessionToken: sessionTokenProp,
1188
1231
  apiBaseUrl,
1189
1232
  frameBaseUrl,
1190
1233
  theme,
1191
1234
  children
1192
1235
  }) {
1193
1236
  const [frameSlots, setFrameSlots] = (0, import_react3.useState)([]);
1237
+ const [internalToken, setInternalToken] = (0, import_react3.useState)(void 0);
1238
+ const sessionToken = sessionTokenProp ?? internalToken;
1194
1239
  const addSlot = (0, import_react3.useCallback)((slot) => {
1195
1240
  setFrameSlots((prev) => [...prev, slot]);
1196
1241
  }, []);
@@ -1206,6 +1251,14 @@ function MoonPayProvider({
1206
1251
  });
1207
1252
  }
1208
1253
  const core = coreRef.current;
1254
+ const initialize = (0, import_react3.useCallback)(
1255
+ (token) => {
1256
+ core.context.setAccessToken("");
1257
+ core.context.setClientToken("");
1258
+ setInternalToken(token);
1259
+ },
1260
+ [core]
1261
+ );
1209
1262
  const client = (0, import_react3.useMemo)(() => {
1210
1263
  const specCtx = { sessionToken, core, frameBaseUrl, theme };
1211
1264
  return createRNClient({
@@ -1213,21 +1266,28 @@ function MoonPayProvider({
1213
1266
  core
1214
1267
  });
1215
1268
  }, [sessionToken, frameBaseUrl, core, addSlot, removeSlot, theme?.appearance]);
1216
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MoonPayContext.Provider, { value: { client, sessionToken, core, frameBaseUrl, theme }, children: [
1217
- children,
1218
- frameSlots.filter((slot) => slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonPayFrame, { transport: slot.transport, hidden: true }, slot.id)),
1219
- frameSlots.filter((slot) => !slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1220
- VisibleFrameSlotSheet,
1221
- {
1222
- slot,
1223
- onClose: () => {
1224
- slot.dispose();
1225
- removeSlot(slot.id);
1226
- }
1227
- },
1228
- slot.id
1229
- ))
1230
- ] });
1269
+ const isInitialized = sessionToken !== void 0;
1270
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1271
+ MoonPayContext.Provider,
1272
+ {
1273
+ value: { client, sessionToken, core, frameBaseUrl, theme, initialize, isInitialized },
1274
+ children: [
1275
+ children,
1276
+ frameSlots.filter((slot) => slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonPayFrame, { transport: slot.transport, hidden: true }, slot.id)),
1277
+ frameSlots.filter((slot) => !slot.hidden).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1278
+ VisibleFrameSlotSheet,
1279
+ {
1280
+ slot,
1281
+ onClose: () => {
1282
+ slot.dispose();
1283
+ removeSlot(slot.id);
1284
+ }
1285
+ },
1286
+ slot.id
1287
+ ))
1288
+ ]
1289
+ }
1290
+ );
1231
1291
  }
1232
1292
  function useMoonPayContext() {
1233
1293
  const ctx = (0, import_react3.useContext)(MoonPayContext);
@@ -1237,7 +1297,8 @@ function useMoonPayContext() {
1237
1297
  return ctx;
1238
1298
  }
1239
1299
  function useMoonPay() {
1240
- return useMoonPayContext();
1300
+ const { client, initialize, isInitialized } = useMoonPayContext();
1301
+ return { client, initialize, isInitialized };
1241
1302
  }
1242
1303
 
1243
1304
  // src/frame-view.tsx