@lumiapassport/ui-kit 1.16.0 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/iframe/index.html +1 -1
- package/dist/iframe/main.js +130 -102
- package/dist/iframe/main.js.map +1 -1
- package/dist/index.cjs +152 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -3
- package/dist/index.d.ts +22 -3
- package/dist/index.js +152 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -703,52 +703,72 @@ async function ensureDkgAndGetOwner(userId, _clientSeedHex) {
|
|
|
703
703
|
throw error;
|
|
704
704
|
}
|
|
705
705
|
}
|
|
706
|
+
function isChannelError(error) {
|
|
707
|
+
const message = error.message.toLowerCase();
|
|
708
|
+
return message.includes("invalid sdk channel") || message.includes("sdk channel not found") || message.includes("sdk channel expired") || // Backward compatibility
|
|
709
|
+
message === "invalid session";
|
|
710
|
+
}
|
|
706
711
|
async function signDigestWithMpc(userId, digest32, userOpDetails) {
|
|
712
|
+
const MAX_RETRIES = 1;
|
|
707
713
|
const startTime = performance.now();
|
|
708
714
|
currentSigningStats = {
|
|
709
715
|
startTime,
|
|
710
716
|
rounds: []
|
|
711
717
|
};
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
return signature;
|
|
733
|
-
} catch (error) {
|
|
734
|
-
(0, import_error_tracking.logSdkError)(
|
|
735
|
-
error instanceof Error ? error : new Error("MPC signing failed"),
|
|
736
|
-
{ userId, hasUserOpDetails: !!userOpDetails },
|
|
737
|
-
"iframe-mpc"
|
|
738
|
-
);
|
|
739
|
-
const endTime = performance.now();
|
|
740
|
-
if (currentSigningStats) {
|
|
718
|
+
let lastError;
|
|
719
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
720
|
+
try {
|
|
721
|
+
const iframeManager = getIframeManager();
|
|
722
|
+
const { jwtTokenManager: jwtTokenManager4 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
723
|
+
const accessToken = jwtTokenManager4.getAccessToken();
|
|
724
|
+
if (!accessToken) {
|
|
725
|
+
throw new Error("No access token available for signing");
|
|
726
|
+
}
|
|
727
|
+
const transaction = {
|
|
728
|
+
to: userOpDetails?.callTarget || "0x0000000000000000000000000000000000000000",
|
|
729
|
+
value: userOpDetails?.value || "0",
|
|
730
|
+
data: userOpDetails?.callData || "0x",
|
|
731
|
+
digest32,
|
|
732
|
+
// Pre-computed digest - DO NOT recompute!
|
|
733
|
+
// Additional UserOp fields for display in confirmation modal
|
|
734
|
+
userOpDetails
|
|
735
|
+
};
|
|
736
|
+
const signature = await iframeManager.signTransaction(userId, transaction, accessToken);
|
|
737
|
+
const endTime = performance.now();
|
|
741
738
|
currentSigningStats.endTime = endTime;
|
|
742
739
|
currentSigningStats.totalDurationMs = endTime - startTime;
|
|
740
|
+
return signature;
|
|
741
|
+
} catch (error) {
|
|
742
|
+
lastError = error instanceof Error ? error : new Error("MPC signing failed");
|
|
743
|
+
if (isChannelError(lastError) && attempt < MAX_RETRIES) {
|
|
744
|
+
console.warn(`[MPC] SDK channel error, reconnecting and retrying (attempt ${attempt + 1})...`);
|
|
745
|
+
try {
|
|
746
|
+
await getIframeManager().reconnect();
|
|
747
|
+
continue;
|
|
748
|
+
} catch (reconnectError) {
|
|
749
|
+
console.error("[MPC] Reconnect failed:", reconnectError);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
(0, import_error_tracking.logSdkError)(
|
|
753
|
+
lastError,
|
|
754
|
+
{ userId, hasUserOpDetails: !!userOpDetails, attempt },
|
|
755
|
+
"iframe-mpc"
|
|
756
|
+
);
|
|
757
|
+
const endTime = performance.now();
|
|
758
|
+
if (currentSigningStats) {
|
|
759
|
+
currentSigningStats.endTime = endTime;
|
|
760
|
+
currentSigningStats.totalDurationMs = endTime - startTime;
|
|
761
|
+
}
|
|
762
|
+
if (lastError instanceof LumiaPassportError) {
|
|
763
|
+
throw lastError;
|
|
764
|
+
}
|
|
765
|
+
throw new LumiaPassportError(
|
|
766
|
+
lastError.message,
|
|
767
|
+
ErrorCodes.MPC_SIGNING_ERROR
|
|
768
|
+
);
|
|
743
769
|
}
|
|
744
|
-
if (error instanceof LumiaPassportError) {
|
|
745
|
-
throw error;
|
|
746
|
-
}
|
|
747
|
-
throw new LumiaPassportError(
|
|
748
|
-
error instanceof Error ? error.message : "MPC signing failed",
|
|
749
|
-
ErrorCodes.MPC_SIGNING_ERROR
|
|
750
|
-
);
|
|
751
770
|
}
|
|
771
|
+
throw lastError || new Error("MPC signing failed after retries");
|
|
752
772
|
}
|
|
753
773
|
async function signTypedDataWithMpc(userId, digest32, typedData) {
|
|
754
774
|
const startTime = performance.now();
|
|
@@ -1379,7 +1399,7 @@ async function getShareVaultToken(scopes) {
|
|
|
1379
1399
|
}
|
|
1380
1400
|
return {
|
|
1381
1401
|
token: data.resourceToken,
|
|
1382
|
-
expiresAt: Date.now() + data.expiresIn * 1e3
|
|
1402
|
+
expiresAt: Date.now() + (data.expiresIn || 300) * 1e3
|
|
1383
1403
|
};
|
|
1384
1404
|
}
|
|
1385
1405
|
async function getShareRecoveryStats() {
|
|
@@ -2620,10 +2640,9 @@ var init_iframe_manager = __esm({
|
|
|
2620
2640
|
"src/internal/lib/iframe-manager.ts"() {
|
|
2621
2641
|
init_errors();
|
|
2622
2642
|
IframeManager = class {
|
|
2623
|
-
// 5 minutes
|
|
2624
2643
|
constructor(config) {
|
|
2625
2644
|
this.iframe = null;
|
|
2626
|
-
this.
|
|
2645
|
+
this.channelToken = null;
|
|
2627
2646
|
this.isReady = false;
|
|
2628
2647
|
// Message handling
|
|
2629
2648
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
@@ -2640,6 +2659,9 @@ var init_iframe_manager = __esm({
|
|
|
2640
2659
|
this.REQUEST_TIMEOUT = 3e5;
|
|
2641
2660
|
// 5 minutes (for user interactions like consent)
|
|
2642
2661
|
this.NONCE_EXPIRY = 3e5;
|
|
2662
|
+
// 5 minutes
|
|
2663
|
+
this.HEARTBEAT_INTERVAL = 5 * 60 * 1e3;
|
|
2664
|
+
this.isReconnecting = false;
|
|
2643
2665
|
this.iframeUrl = config.iframeUrl;
|
|
2644
2666
|
this.projectId = config.projectId;
|
|
2645
2667
|
this.debug = config.debug || false;
|
|
@@ -2680,6 +2702,8 @@ var init_iframe_manager = __esm({
|
|
|
2680
2702
|
await this.readyPromise;
|
|
2681
2703
|
await this.authenticateSDK();
|
|
2682
2704
|
await this.primeProviderSessions();
|
|
2705
|
+
this.startHeartbeat();
|
|
2706
|
+
this.setupVisibilityHandler();
|
|
2683
2707
|
this.log("[IframeManager] \u2705 Iframe ready and authenticated");
|
|
2684
2708
|
}
|
|
2685
2709
|
/**
|
|
@@ -2689,18 +2713,93 @@ var init_iframe_manager = __esm({
|
|
|
2689
2713
|
this.onWalletReadyCallback = callback;
|
|
2690
2714
|
}
|
|
2691
2715
|
/**
|
|
2692
|
-
* Authenticate SDK with iframe to establish
|
|
2716
|
+
* Authenticate SDK with iframe to establish secure channel
|
|
2693
2717
|
*/
|
|
2694
2718
|
async authenticateSDK() {
|
|
2695
2719
|
const response = await this.sendMessage("SDK_AUTH", {
|
|
2696
2720
|
projectId: this.projectId
|
|
2697
2721
|
});
|
|
2698
2722
|
if (response.type === "LUMIA_PASSPORT_SDK_AUTH_SUCCESS") {
|
|
2699
|
-
this.
|
|
2723
|
+
this.channelToken = response.sessionToken;
|
|
2700
2724
|
} else {
|
|
2701
|
-
throw new Error("SDK authentication failed");
|
|
2725
|
+
throw new Error("SDK channel authentication failed");
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
/**
|
|
2729
|
+
* Start periodic heartbeat to check SDK channel validity
|
|
2730
|
+
*/
|
|
2731
|
+
startHeartbeat() {
|
|
2732
|
+
if (this.heartbeatInterval) {
|
|
2733
|
+
clearInterval(this.heartbeatInterval);
|
|
2734
|
+
}
|
|
2735
|
+
this.heartbeatInterval = setInterval(async () => {
|
|
2736
|
+
if (!this.channelToken) return;
|
|
2737
|
+
try {
|
|
2738
|
+
const response = await this.sendMessage("SDK_CHANNEL_HEARTBEAT", {});
|
|
2739
|
+
if (!response.valid) {
|
|
2740
|
+
this.log("[IframeManager] SDK channel invalid, reconnecting...");
|
|
2741
|
+
await this.reconnect();
|
|
2742
|
+
}
|
|
2743
|
+
} catch (error) {
|
|
2744
|
+
this.log("[IframeManager] Heartbeat failed:", error);
|
|
2745
|
+
await this.reconnect();
|
|
2746
|
+
}
|
|
2747
|
+
}, this.HEARTBEAT_INTERVAL);
|
|
2748
|
+
this.log("[IframeManager] Heartbeat started (interval: 5 min)");
|
|
2749
|
+
}
|
|
2750
|
+
/**
|
|
2751
|
+
* Stop heartbeat
|
|
2752
|
+
*/
|
|
2753
|
+
stopHeartbeat() {
|
|
2754
|
+
if (this.heartbeatInterval) {
|
|
2755
|
+
clearInterval(this.heartbeatInterval);
|
|
2756
|
+
this.heartbeatInterval = void 0;
|
|
2757
|
+
this.log("[IframeManager] Heartbeat stopped");
|
|
2702
2758
|
}
|
|
2703
2759
|
}
|
|
2760
|
+
/**
|
|
2761
|
+
* Reconnect SDK channel after it becomes invalid
|
|
2762
|
+
*/
|
|
2763
|
+
async reconnect() {
|
|
2764
|
+
if (this.isReconnecting) {
|
|
2765
|
+
this.log("[IframeManager] Already reconnecting, skipping...");
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
this.isReconnecting = true;
|
|
2769
|
+
this.log("[IframeManager] Reconnecting SDK channel...");
|
|
2770
|
+
try {
|
|
2771
|
+
this.channelToken = null;
|
|
2772
|
+
await this.authenticateSDK();
|
|
2773
|
+
this.log("[IframeManager] \u2705 SDK channel reconnected");
|
|
2774
|
+
} catch (error) {
|
|
2775
|
+
this.log("[IframeManager] \u274C Reconnect failed:", error);
|
|
2776
|
+
throw error;
|
|
2777
|
+
} finally {
|
|
2778
|
+
this.isReconnecting = false;
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
/**
|
|
2782
|
+
* Setup visibility change handler to check channel when tab becomes visible
|
|
2783
|
+
*/
|
|
2784
|
+
setupVisibilityHandler() {
|
|
2785
|
+
if (typeof document === "undefined") return;
|
|
2786
|
+
document.addEventListener("visibilitychange", async () => {
|
|
2787
|
+
if (document.visibilityState === "visible" && this.channelToken) {
|
|
2788
|
+
this.log("[IframeManager] Tab visible, checking SDK channel...");
|
|
2789
|
+
try {
|
|
2790
|
+
const response = await this.sendMessage("SDK_CHANNEL_HEARTBEAT", {});
|
|
2791
|
+
if (!response.valid) {
|
|
2792
|
+
this.log("[IframeManager] SDK channel expired while tab was hidden");
|
|
2793
|
+
await this.reconnect();
|
|
2794
|
+
}
|
|
2795
|
+
} catch (error) {
|
|
2796
|
+
this.log("[IframeManager] Channel check failed, reconnecting...");
|
|
2797
|
+
await this.reconnect();
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
});
|
|
2801
|
+
this.log("[IframeManager] Visibility handler setup");
|
|
2802
|
+
}
|
|
2704
2803
|
/**
|
|
2705
2804
|
* Handle incoming postMessage events
|
|
2706
2805
|
*/
|
|
@@ -2724,6 +2823,7 @@ var init_iframe_manager = __esm({
|
|
|
2724
2823
|
"LUMIA_PASSPORT_TRUSTED_APP_REMOVED",
|
|
2725
2824
|
"LUMIA_PASSPORT_REQUEST_NEW_TOKEN",
|
|
2726
2825
|
"LUMIA_PASSPORT_TOKEN_REFRESHED",
|
|
2826
|
+
"LUMIA_PASSPORT_HEARTBEAT_RESPONSE",
|
|
2727
2827
|
"LUMIA_PASSPORT_RESPONSE",
|
|
2728
2828
|
"LUMIA_PASSPORT_ERROR"
|
|
2729
2829
|
];
|
|
@@ -2852,10 +2952,11 @@ var init_iframe_manager = __esm({
|
|
|
2852
2952
|
projectId: this.projectId,
|
|
2853
2953
|
data: {
|
|
2854
2954
|
...data,
|
|
2855
|
-
sessionToken: this.
|
|
2955
|
+
sessionToken: this.channelToken
|
|
2956
|
+
// named sessionToken for backward compatibility with iframe
|
|
2856
2957
|
}
|
|
2857
2958
|
};
|
|
2858
|
-
if (this.
|
|
2959
|
+
if (this.channelToken) {
|
|
2859
2960
|
message.hmac = await this.computeHMAC(message);
|
|
2860
2961
|
}
|
|
2861
2962
|
const responsePromise = new Promise((resolve, reject) => {
|
|
@@ -2877,7 +2978,7 @@ var init_iframe_manager = __esm({
|
|
|
2877
2978
|
return responsePromise;
|
|
2878
2979
|
}
|
|
2879
2980
|
/**
|
|
2880
|
-
* Compute HMAC for message authentication
|
|
2981
|
+
* Compute HMAC for message authentication using SDK channel token
|
|
2881
2982
|
*/
|
|
2882
2983
|
async computeHMAC(message) {
|
|
2883
2984
|
const encoder = new TextEncoder();
|
|
@@ -2889,7 +2990,7 @@ var init_iframe_manager = __esm({
|
|
|
2889
2990
|
data: JSON.stringify(message.data)
|
|
2890
2991
|
});
|
|
2891
2992
|
const data = encoder.encode(payload);
|
|
2892
|
-
const key = encoder.encode(this.
|
|
2993
|
+
const key = encoder.encode(this.channelToken);
|
|
2893
2994
|
const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
2894
2995
|
const signature = await crypto.subtle.sign("HMAC", cryptoKey, data);
|
|
2895
2996
|
return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
@@ -3634,6 +3735,7 @@ var init_iframe_manager = __esm({
|
|
|
3634
3735
|
*/
|
|
3635
3736
|
destroy() {
|
|
3636
3737
|
this.log("[IframeManager] Destroying iframe...");
|
|
3738
|
+
this.stopHeartbeat();
|
|
3637
3739
|
this.pendingRequests.forEach((pending) => {
|
|
3638
3740
|
pending.reject(new Error("Iframe manager destroyed"));
|
|
3639
3741
|
});
|
|
@@ -3647,7 +3749,7 @@ var init_iframe_manager = __esm({
|
|
|
3647
3749
|
}
|
|
3648
3750
|
this.iframe = null;
|
|
3649
3751
|
this.isReady = false;
|
|
3650
|
-
this.
|
|
3752
|
+
this.channelToken = null;
|
|
3651
3753
|
this.log("[IframeManager] \u2705 Destroyed");
|
|
3652
3754
|
}
|
|
3653
3755
|
/**
|
|
@@ -5570,7 +5672,7 @@ function Header() {
|
|
|
5570
5672
|
// package.json
|
|
5571
5673
|
var package_default = {
|
|
5572
5674
|
name: "@lumiapassport/ui-kit",
|
|
5573
|
-
version: "1.16.
|
|
5675
|
+
version: "1.16.1",
|
|
5574
5676
|
description: "React UI components and hooks for Lumia Passport authentication and Account Abstraction",
|
|
5575
5677
|
type: "module",
|
|
5576
5678
|
main: "./dist/index.cjs",
|
|
@@ -9991,6 +10093,7 @@ var useManageWalletStore = (0, import_zustand5.create)((set) => ({
|
|
|
9991
10093
|
emailCode: "",
|
|
9992
10094
|
emailCodeExpiresIn: 0,
|
|
9993
10095
|
linkIsLoading: false,
|
|
10096
|
+
linkError: null,
|
|
9994
10097
|
providerType: null,
|
|
9995
10098
|
confirmUnlink: null,
|
|
9996
10099
|
setAlert: (alert2) => set({ alert: alert2 }),
|
|
@@ -9999,6 +10102,7 @@ var useManageWalletStore = (0, import_zustand5.create)((set) => ({
|
|
|
9999
10102
|
setEmailCode: (emailCode) => set({ emailCode }),
|
|
10000
10103
|
setEmailCodeExpiresIn: (emailCodeExpiresIn) => set({ emailCodeExpiresIn }),
|
|
10001
10104
|
setLinkIsLoading: (linkIsLoading) => set({ linkIsLoading }),
|
|
10105
|
+
setLinkError: (linkError) => set({ linkError }),
|
|
10002
10106
|
setProviderType: (providerType) => set({ providerType }),
|
|
10003
10107
|
setConfirmUnlink: (confirmUnlink) => set({ confirmUnlink })
|
|
10004
10108
|
}));
|