@lumiapassport/ui-kit 1.13.9 → 1.13.11

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
@@ -267,15 +267,14 @@ That's it! The `ConnectWalletButton` provides a complete authentication UI with
267
267
 
268
268
  ## Using Hooks
269
269
 
270
- > **Note:** The `useLumiaPassportSession` hook is based on pure Zustand store so if you already using hook consider 2 options: 1) refactor state extarction so it uses zustand state extraction feature. 2) consider using new session hooks: `useLumiaPassportAccountSession`, `useLumiaPassportAddress` etc. Otherwise you might experience excessive re-rendering issues
271
-
272
- ### useLumiaPassportAccountSession, useLumiaPassportLoadingStatus, useLumiaPassportBalance, useLumiaPassportIFrameReady, useLumiaPassportAddress, useLumiaPassportError, useLumiaPassportLoadingStatus, useLumiaPassportRecoveryUserId, useLumiaPassportHasServerVault
270
+ > **Note:** The `useLumiaPassportSession` hook is based on pure Zustand store so if you're already using useLumiaPassportSession hook please consider 2 options: 1) refactor state extarction so it uses zustand state extraction feature. 2) consider using dedicated LumiaPassport shared store values hooks: `useLumiaPassportAccountSession`, `useLumiaPassportAddress` etc. Otherwise you might experience excessive re-rendering issues as LumiaPassport shares its internal store and might update some state values which should not affect app render.
273
271
 
274
272
  ```tsx
275
273
  import { useLumiaPassportAccountSession, useLumiaPassportLoadingStatus } from '@lumiapassport/ui-kit'
276
274
 
277
275
  function MyComponent() {
278
- const session = useLumiaPassportAccountSession() // const session = useLumiaPassportSession(s => s.session) - with prev hook & Zustand state extraction feature
276
+ // const session = useLumiaPassportSession(s => s.session) - with prev hook & Zustand state extraction feature, please prefer this instead:
277
+ const session = useLumiaPassportAccountSession()
279
278
  const { isSessionLoading } = useLumiaPassportLoadingStatus()
280
279
 
281
280
  if (isSessionLoading) return <div>Loading...</div>
@@ -295,6 +294,18 @@ function MyComponent() {
295
294
  }
296
295
  ```
297
296
 
297
+ ### Lumia Passport shared store values hooks
298
+
299
+ - **useLumiaPassportIsMobileView** - Returns boolean indicating if UI is in mobile view mode
300
+ - **useLumiaPassportAccountSession** - Returns current user session object with userId, addresses, and auth info
301
+ - **useLumiaPassportLoadingStatus** - Returns `{ isSessionLoading, sessionStatus }` for tracking authentication state
302
+ - **useLumiaPassportBalance** - Returns wallet balance data: `{ walletBalance, fiatBalance, cryptoRate, fiatSymbol, cryptoSymbol }`
303
+ - **useLumiaPassportIFrameReady** - Returns boolean indicating if the MPC iframe is ready for operations
304
+ - **useLumiaPassportAddress** - Returns the current user's wallet address
305
+ - **useLumiaPassportError** - Returns any error that occurred during authentication or operations
306
+ - **useLumiaPassportRecoveryUserId** - Returns userId for account recovery flow
307
+ - **useLumiaPassportHasServerVault** - Returns boolean indicating if user has server-side keyshare backup
308
+
298
309
  ### useSendTransaction - Send Transactions
299
310
 
300
311
  ```tsx
@@ -15,7 +15,7 @@
15
15
  <meta http-equiv="X-Content-Type-Options" content="nosniff" />
16
16
  <meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin" />
17
17
 
18
- <title>Lumia Passport Secure Wallet - iframe version 1.13.8</title>
18
+ <title>Lumia Passport Secure Wallet - iframe version 1.13.11</title>
19
19
 
20
20
  <!-- Styles will be injected by build process -->
21
21
  <style>
@@ -2786,6 +2786,259 @@ var DKGManager = class extends TokenRefreshApiClient {
2786
2786
  }
2787
2787
  };
2788
2788
 
2789
+ // src/iframe/lib/onramp/utils.ts
2790
+ var LP_JWT_TOKENS_LS_KEY = "lumia-passport-jwt-tokens";
2791
+ function getBearer() {
2792
+ try {
2793
+ const sessionString = localStorage.getItem(LP_JWT_TOKENS_LS_KEY);
2794
+ if (!sessionString) return null;
2795
+ const session = JSON.parse(sessionString);
2796
+ if (session && typeof session.accessToken === "string" && typeof session.userId === "string") {
2797
+ return `Bearer ${session.accessToken}`;
2798
+ }
2799
+ return null;
2800
+ } catch (error) {
2801
+ console.error("Failed to parse Lumia Passport session:", error);
2802
+ return null;
2803
+ }
2804
+ }
2805
+
2806
+ // src/iframe/lib/onramp/binance.ts
2807
+ var API_DOMAIN = "https://api.lumiapassport.com/on-ramp";
2808
+ var BinanceOnrampAPI = class {
2809
+ async checkIsLumaiAvailableQuery() {
2810
+ const auth = getBearer();
2811
+ const response = await fetch(`${API_DOMAIN}/api/binance/pairs`, {
2812
+ method: "POST",
2813
+ headers: {
2814
+ "Content-Type": "application/json",
2815
+ ...auth && { Authorization: auth }
2816
+ }
2817
+ });
2818
+ const data = await response.json();
2819
+ if (!data.success) {
2820
+ throw new Error(`${data.code}: ${data.message}`);
2821
+ }
2822
+ if (!data.data?.cryptoCurrencies?.includes("LUMIA")) {
2823
+ console.error("Lumia is not available in Binance pairs API");
2824
+ throw new Error("Lumia is not available in API");
2825
+ }
2826
+ return !!data.data.cryptoCurrencies.includes("LUMIA");
2827
+ }
2828
+ async getLumiaNetworkQuery() {
2829
+ const auth = getBearer();
2830
+ const response = await fetch(`${API_DOMAIN}/api/binance/networks`, {
2831
+ method: "POST",
2832
+ headers: {
2833
+ "Content-Type": "application/json",
2834
+ ...auth && { Authorization: auth }
2835
+ }
2836
+ });
2837
+ const data = await response.json();
2838
+ if (!data?.success) {
2839
+ throw new Error(`${data.code}: ${data.message}`);
2840
+ }
2841
+ const lumiaNetwork = data.data?.find((el) => el.cryptoCurrency === "LUMIA") || null;
2842
+ if (!lumiaNetwork) {
2843
+ console.error("Lumia is not available in Binance pairs API");
2844
+ throw new Error("Lumia is not available in API");
2845
+ }
2846
+ return lumiaNetwork;
2847
+ }
2848
+ async getPaymentMethodsQuery(payload) {
2849
+ const auth = getBearer();
2850
+ const response = await fetch(`${API_DOMAIN}/api/binance/modes`, {
2851
+ method: "POST",
2852
+ headers: {
2853
+ "Content-Type": "application/json",
2854
+ ...auth && { Authorization: auth }
2855
+ },
2856
+ body: JSON.stringify(payload)
2857
+ });
2858
+ const data = await response.json();
2859
+ if (!data.success) {
2860
+ throw new Error(`${data.code}: ${data.message}`);
2861
+ }
2862
+ if (!data.data.paymentMethods.length) {
2863
+ throw new Error("No payment methods available yet");
2864
+ }
2865
+ return data.data.paymentMethods;
2866
+ }
2867
+ async getQuoteQuery(payload) {
2868
+ const auth = getBearer();
2869
+ const response = await fetch(`${API_DOMAIN}/api/binance/quote`, {
2870
+ method: "POST",
2871
+ headers: {
2872
+ "Content-Type": "application/json",
2873
+ ...auth && { Authorization: auth }
2874
+ },
2875
+ body: JSON.stringify(payload)
2876
+ });
2877
+ const data = await response.json();
2878
+ if (!data.success) {
2879
+ throw new Error(`${data.code}: ${data.message}`);
2880
+ }
2881
+ return data.data;
2882
+ }
2883
+ async createPreorderMutation(payload) {
2884
+ const auth = getBearer();
2885
+ const response = await fetch(`${API_DOMAIN}/api/binance/pre-order`, {
2886
+ method: "POST",
2887
+ headers: {
2888
+ "Content-Type": "application/json",
2889
+ ...auth && { Authorization: auth }
2890
+ },
2891
+ body: JSON.stringify(payload)
2892
+ });
2893
+ const data = await response.json();
2894
+ if (!data.success) {
2895
+ throw new Error(`${data.code}: ${data.message}`);
2896
+ }
2897
+ return data.data;
2898
+ }
2899
+ async handleMessage(message, origin, sendResponseFn) {
2900
+ const { type, messageId, data } = message;
2901
+ console.log("[ BINANCE Received message ]", type, message);
2902
+ switch (type) {
2903
+ case "BINANCE_CHECK_IS_LUMIA_AVAILABLE_QUERY":
2904
+ const isLumiaAvalableRes = await this.checkIsLumaiAvailableQuery();
2905
+ sendResponseFn(messageId, isLumiaAvalableRes, origin);
2906
+ break;
2907
+ case "BINANCE_GET_LUMIA_NETWORK_QUERY":
2908
+ const lumiaNetworkResponse = await this.getLumiaNetworkQuery();
2909
+ sendResponseFn(messageId, lumiaNetworkResponse, origin);
2910
+ break;
2911
+ case "BINANCE_GET_PAYMENT_METHODS_QUERY":
2912
+ const paymentMethodsResponse = await this.getPaymentMethodsQuery(this.ensurePayload(data, "methods"));
2913
+ sendResponseFn(messageId, paymentMethodsResponse, origin);
2914
+ break;
2915
+ case "BINANCE_GET_QUOTE_QUERY":
2916
+ const quoteResponse = await this.getQuoteQuery(this.ensurePayload(data, "quote"));
2917
+ sendResponseFn(messageId, quoteResponse, origin);
2918
+ break;
2919
+ case "BINANCE_CREATE_PREORDER_MUTATION":
2920
+ const preorderResponse = await this.createPreorderMutation(this.ensurePayload(data, "preorder"));
2921
+ sendResponseFn(messageId, preorderResponse, origin);
2922
+ break;
2923
+ default:
2924
+ throw new Error(`[ BINANCE ]: Unknown message type: ${type}`);
2925
+ }
2926
+ }
2927
+ ensurePayload(data, type) {
2928
+ if (!data || typeof data !== "object") {
2929
+ throw new Error(`Invalid payload: expected object, got ${typeof data}`);
2930
+ }
2931
+ const payload = data;
2932
+ switch (type) {
2933
+ case "methods":
2934
+ if (typeof payload.totalAmount !== "string") {
2935
+ throw new Error("Invalid payload: totalAmount must be a string");
2936
+ }
2937
+ return { totalAmount: payload.totalAmount };
2938
+ case "quote":
2939
+ if (typeof payload.network !== "string") {
2940
+ throw new Error("Invalid payload: network must be a string");
2941
+ }
2942
+ if (typeof payload.walletAddress !== "string") {
2943
+ throw new Error("Invalid payload: walletAddress must be a string");
2944
+ }
2945
+ if (typeof payload.requestedAmount !== "string") {
2946
+ throw new Error("Invalid payload: requestedAmount must be a string");
2947
+ }
2948
+ return {
2949
+ network: payload.network,
2950
+ walletAddress: payload.walletAddress,
2951
+ requestedAmount: payload.requestedAmount,
2952
+ ...payload.payMethodCode && typeof payload.payMethodCode === "string" ? { payMethodCode: payload.payMethodCode } : {},
2953
+ ...payload.payMethodSubCode && typeof payload.payMethodSubCode === "string" ? { payMethodSubCode: payload.payMethodSubCode } : {}
2954
+ };
2955
+ case "preorder":
2956
+ if (typeof payload.requestedAmount !== "string") {
2957
+ throw new Error("Invalid payload: requestedAmount must be a string");
2958
+ }
2959
+ if (typeof payload.address !== "string") {
2960
+ throw new Error("Invalid payload: address must be a string");
2961
+ }
2962
+ if (typeof payload.network !== "string") {
2963
+ throw new Error("Invalid payload: network must be a string");
2964
+ }
2965
+ return {
2966
+ requestedAmount: payload.requestedAmount,
2967
+ address: payload.address,
2968
+ network: payload.network,
2969
+ ...payload.payMethodCode && typeof payload.payMethodCode === "string" ? { payMethodCode: payload.payMethodCode } : {},
2970
+ ...payload.payMethodSubCode && typeof payload.payMethodSubCode === "string" ? { payMethodSubCode: payload.payMethodSubCode } : {},
2971
+ ...payload.redirectUrl && typeof payload.redirectUrl === "string" ? { redirectUrl: payload.redirectUrl } : {},
2972
+ ...payload.failRedirectUrl && typeof payload.failRedirectUrl === "string" ? { failRedirectUrl: payload.failRedirectUrl } : {}
2973
+ };
2974
+ default:
2975
+ throw new Error(`Unknown payload type: ${type}`);
2976
+ }
2977
+ }
2978
+ };
2979
+
2980
+ // src/iframe/lib/onramp/rampnow.ts
2981
+ var API_DOMAIN2 = "https://api.lumiapassport.com/on-ramp";
2982
+ var RampnowOnrampAPI = class {
2983
+ async getRampnowConfigQuery() {
2984
+ const auth = getBearer();
2985
+ const response = await fetch(`${API_DOMAIN2}/api/rampnow/cfg`, {
2986
+ method: "GET",
2987
+ headers: { ...auth && { Authorization: auth } }
2988
+ });
2989
+ const data = await response.json();
2990
+ return data;
2991
+ }
2992
+ async getRampOrderQuoteQuery(payload) {
2993
+ const auth = getBearer();
2994
+ const response = await fetch(`${API_DOMAIN2}/api/rampnow/quote`, {
2995
+ method: "POST",
2996
+ headers: {
2997
+ "Content-Type": "application/json",
2998
+ ...auth && { Authorization: auth }
2999
+ },
3000
+ body: JSON.stringify(payload)
3001
+ });
3002
+ const data = await response.json();
3003
+ if (!data.data) {
3004
+ throw new Error(`${data.code}: ${data.message}`);
3005
+ }
3006
+ return data;
3007
+ }
3008
+ ensureOrderQuotePayload(payload) {
3009
+ if (typeof payload !== "object" || payload === null || typeof payload?.paymentMode !== "string" || typeof payload?.srcAmount !== "number" || typeof payload?.walletAddress !== "string") {
3010
+ throw new Error("Invalid Ramp order quote payload");
3011
+ }
3012
+ return payload;
3013
+ }
3014
+ // UNUSED due to Rampnow APP redirect order flow
3015
+ // async ctreateChekoutOrderMutation(payload: CreateCheckoutOrderMutationPayload) {
3016
+ // const checkoutedOrderData = await axios
3017
+ // .post('/api/rampnow/order', payload)
3018
+ // .then((r) => r.data.data as CreateCheckoutOrderMutationResponse)
3019
+ // .catch((err) => {
3020
+ // throw new Error(err?.message || 'Ramp quote query failed')
3021
+ // })
3022
+ // return checkoutedOrderData
3023
+ // }
3024
+ async handleMessage(message, origin, sendResponseFn) {
3025
+ const { type, data, messageId } = message;
3026
+ console.log("[ BINANCE Received message ]", type, message);
3027
+ switch (type) {
3028
+ case "RAMPNOW_GET_CONFIG":
3029
+ const ramnowCfg = await this.getRampnowConfigQuery();
3030
+ sendResponseFn(messageId, ramnowCfg, origin);
3031
+ break;
3032
+ case "RAMPNOW_GET_ORDER_QUOTE":
3033
+ const orderQuote = await this.getRampOrderQuoteQuery(this.ensureOrderQuotePayload(data));
3034
+ sendResponseFn(messageId, orderQuote, origin);
3035
+ break;
3036
+ default:
3037
+ throw new Error(`[ RAMPNOW ]: Unknown message type: ${type}`);
3038
+ }
3039
+ }
3040
+ };
3041
+
2789
3042
  // src/iframe/lib/secure-messenger.ts
2790
3043
  var SecureMessenger = class {
2791
3044
  constructor() {
@@ -2799,7 +3052,7 @@ var SecureMessenger = class {
2799
3052
  this.NONCE_CLEANUP_INTERVAL = 5 * 60 * 1e3;
2800
3053
  // 5 minutes
2801
3054
  // Debug flag: set to true to log all filtered messages (for debugging only)
2802
- this.DEBUG_FILTERED_MESSAGES = false;
3055
+ this.DEBUG_FILTERED_MESSAGES = true;
2803
3056
  setInterval(() => this.cleanupOldNonces(), this.NONCE_CLEANUP_INTERVAL);
2804
3057
  }
2805
3058
  /**
@@ -2964,9 +3217,10 @@ var SecureMessenger = class {
2964
3217
  "TRUSTED_APP_REMOVED",
2965
3218
  "TOKEN_REFRESHED"
2966
3219
  ];
2967
- if (!message.type || !validTypes.includes(message.type)) {
2968
- return false;
2969
- }
3220
+ const validTypeGroups = ["BINANCE_", "RAMPNOW_"];
3221
+ const isTypeValid = validTypes.includes(message.type);
3222
+ const isGroupTypeValid = validTypeGroups.some((prefix) => message.type.startsWith(prefix));
3223
+ if (!message.type || !isTypeValid && !isGroupTypeValid) return false;
2970
3224
  return !!(message.messageId && message.timestamp);
2971
3225
  }
2972
3226
  /**
@@ -3006,13 +3260,7 @@ var SecureMessenger = class {
3006
3260
  });
3007
3261
  const data = encoder3.encode(payload);
3008
3262
  const key = encoder3.encode(this.sessionToken);
3009
- const cryptoKey = await crypto.subtle.importKey(
3010
- "raw",
3011
- key,
3012
- { name: "HMAC", hash: "SHA-256" },
3013
- false,
3014
- ["sign"]
3015
- );
3263
+ const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
3016
3264
  const signature = await crypto.subtle.sign("HMAC", cryptoKey, data);
3017
3265
  return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
3018
3266
  }
@@ -4010,7 +4258,7 @@ var SigningManager = class extends TokenRefreshApiClient {
4010
4258
  };
4011
4259
 
4012
4260
  // src/iframe/main.ts
4013
- var IFRAME_VERSION = "1.13.8";
4261
+ var IFRAME_VERSION = "1.13.11";
4014
4262
  var IframeWallet = class {
4015
4263
  constructor() {
4016
4264
  console.log("=".repeat(60));
@@ -4025,6 +4273,8 @@ var IframeWallet = class {
4025
4273
  this.storage = new StorageManager();
4026
4274
  this.trustedApps = new TrustedAppsManager();
4027
4275
  this.backupManager = new BackupManager();
4276
+ this.binance = new BinanceOnrampAPI();
4277
+ this.rampnow = new RampnowOnrampAPI();
4028
4278
  }
4029
4279
  applyThemeColors() {
4030
4280
  try {
@@ -4076,54 +4326,61 @@ var IframeWallet = class {
4076
4326
  }
4077
4327
  async handleMessage(message, origin) {
4078
4328
  const { type, messageId, projectId } = message;
4329
+ console.log("[IFRAME INTERNAL] message", type, message);
4079
4330
  try {
4080
- switch (type) {
4081
- case "SDK_AUTH":
4331
+ switch (true) {
4332
+ case type.startsWith("BINANCE_"):
4333
+ await this.binance.handleMessage(message, origin, this.messenger.sendResponse.bind(this.messenger));
4334
+ break;
4335
+ case type.startsWith("RAMPNOW_"):
4336
+ await this.rampnow.handleMessage(message, origin, this.messenger.sendResponse.bind(this.messenger));
4337
+ break;
4338
+ case type === "SDK_AUTH":
4082
4339
  await this.handleSDKAuth(message, origin);
4083
4340
  break;
4084
- case "AUTHENTICATE":
4341
+ case type === "AUTHENTICATE":
4085
4342
  await this.handleAuthenticate(message, origin);
4086
4343
  break;
4087
- case "START_DKG":
4344
+ case type === "START_DKG":
4088
4345
  await this.handleStartDKG(message, origin);
4089
4346
  break;
4090
- case "SIGN_TRANSACTION":
4347
+ case type === "SIGN_TRANSACTION":
4091
4348
  await this.handleSignTransaction(message, origin);
4092
4349
  break;
4093
- case "SIGN_TYPED_DATA":
4350
+ case type === "SIGN_TYPED_DATA":
4094
4351
  await this.handleSignTypedData(message, origin);
4095
4352
  break;
4096
- case "GET_ADDRESS":
4353
+ case type === "GET_ADDRESS":
4097
4354
  await this.handleGetAddress(message, origin);
4098
4355
  break;
4099
- case "CHECK_KEYSHARE":
4356
+ case type === "CHECK_KEYSHARE":
4100
4357
  await this.handleCheckKeyshare(message, origin);
4101
4358
  break;
4102
- case "GET_TRUSTED_APPS":
4359
+ case type === "GET_TRUSTED_APPS":
4103
4360
  await this.handleGetTrustedApps(message, origin);
4104
4361
  break;
4105
- case "REMOVE_TRUSTED_APP":
4362
+ case type === "REMOVE_TRUSTED_APP":
4106
4363
  await this.handleRemoveTrustedApp(message, origin);
4107
4364
  break;
4108
- case "CLEAR_AUTHORIZATIONS":
4365
+ case type === "CLEAR_AUTHORIZATIONS":
4109
4366
  await this.handleClearAuthorizations(message, origin);
4110
4367
  break;
4111
- case "CREATE_BACKUP":
4368
+ case type === "CREATE_BACKUP":
4112
4369
  await this.handleCreateBackup(message, origin);
4113
4370
  break;
4114
- case "GET_BACKUP_STATUS":
4371
+ case type === "GET_BACKUP_STATUS":
4115
4372
  await this.handleGetBackupStatus(message, origin);
4116
4373
  break;
4117
- case "GET_CLOUD_PROVIDERS":
4374
+ case type === "GET_CLOUD_PROVIDERS":
4118
4375
  await this.handleGetCloudProviders(message, origin);
4119
4376
  break;
4120
- case "RESTORE_BACKUP":
4377
+ case type === "RESTORE_BACKUP":
4121
4378
  await this.handleRestoreBackup(message, origin);
4122
4379
  break;
4123
- case "RESTORE_FROM_FILE":
4380
+ case type === "RESTORE_FROM_FILE":
4124
4381
  await this.handleRestoreFromFile(message, origin);
4125
4382
  break;
4126
- case "ENCRYPT_BACKUP_DATA":
4383
+ case type === "ENCRYPT_BACKUP_DATA":
4127
4384
  await this.handleEncryptBackupData(message, origin);
4128
4385
  break;
4129
4386
  default: