@gluwa/connect-kit 0.2.0-next.7 → 0.2.0-next.8
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/CHANGELOG.md +11 -0
- package/dist/{chunk-EDNRW47A.js → chunk-VE5LB7BN.js} +4 -0
- package/dist/credit-connect.js +1 -1
- package/dist/index.js +159 -64
- package/dist/package.json +1 -1
- package/package.json +6 -6
- package/src/creditConnectConnector.ts +6 -0
- package/src/hooks/useConnectTimeout.ts +82 -0
- package/src/hooks/useWagmiConnect.ts +8 -1
- package/src/layout/connectDialog/index.tsx +56 -5
- package/src/layout/detailPanel/index.tsx +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @gluwa/wallet-kit
|
|
2
2
|
|
|
3
|
+
## 0.2.0-next.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e3789b4: emit OnSessionExpired when credit-connect QR session times out
|
|
8
|
+
- Updated dependencies [e3789b4]
|
|
9
|
+
- @gluwa/credit-connect-hub-node-ws@0.1.0-next.4
|
|
10
|
+
- @gluwa/credit-connect-sdk@0.2.0-next.4
|
|
11
|
+
- @gluwa/credit-connect-e2ee-tweetnacl@0.2.0-next.4
|
|
12
|
+
- @gluwa/credit-connect-storage-local@0.2.0-next.4
|
|
13
|
+
|
|
3
14
|
## 0.2.0-next.7
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
@@ -65,6 +65,10 @@ var creditConnectConnector = /* @__PURE__ */ __name((options) => {
|
|
|
65
65
|
emitWagmiDisconnect == null ? void 0 : emitWagmiDisconnect();
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
|
+
manager.on("sessionExpired", (payload) => {
|
|
69
|
+
console.log("[CC connector] session expired \u2192 emit session_expired", payload);
|
|
70
|
+
emitWagmiMessage == null ? void 0 : emitWagmiMessage("session_expired", payload);
|
|
71
|
+
});
|
|
68
72
|
return manager;
|
|
69
73
|
}, "createManagerIfNeeded");
|
|
70
74
|
const ensureManagerInitialized = /* @__PURE__ */ __name(async () => {
|
package/dist/credit-connect.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
__name,
|
|
4
4
|
creditConnectConnector
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VE5LB7BN.js";
|
|
6
6
|
|
|
7
7
|
// src/api/contract.ts
|
|
8
8
|
import { readContract as wagmiReadContract, writeContract as wagmiWriteContract } from "@wagmi/core";
|
|
@@ -194,13 +194,13 @@ var disconnectAll = /* @__PURE__ */ __name(async (onLog) => {
|
|
|
194
194
|
}, "disconnectAll");
|
|
195
195
|
|
|
196
196
|
// src/ConnectKitProvider.tsx
|
|
197
|
-
import { createContext, useCallback as
|
|
197
|
+
import { createContext, useCallback as useCallback4, useContext, useEffect as useEffect5, useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "react";
|
|
198
198
|
import { WagmiProvider, useAccount, useConfig as useConfig3, useDisconnect, useSwitchChain } from "wagmi";
|
|
199
199
|
import { getAccount as getAccount2 } from "@wagmi/core";
|
|
200
200
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
201
201
|
|
|
202
202
|
// src/layout/connectDialog/index.tsx
|
|
203
|
-
import { useEffect as
|
|
203
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
|
|
204
204
|
import { useConfig as useConfig2 } from "wagmi";
|
|
205
205
|
|
|
206
206
|
// src/layout/connectDialog/asset/closeIcon.tsx
|
|
@@ -919,7 +919,7 @@ var getTitle = /* @__PURE__ */ __name((content, connector) => {
|
|
|
919
919
|
return "";
|
|
920
920
|
}
|
|
921
921
|
}, "getTitle");
|
|
922
|
-
var DetailPanel = /* @__PURE__ */ __name(({ selectedConnector, selectedWallet = null, content = "idle", qrUri = null, wallets = [], walletListLoading = false, walletCount, onBack, onClose, onShowAllWallets, onSelectWallet, onCopyLink }) => {
|
|
922
|
+
var DetailPanel = /* @__PURE__ */ __name(({ selectedConnector, selectedWallet = null, content = "idle", qrUri = null, wallets = [], walletListLoading = false, walletCount, onBack, onClose, onShowAllWallets, onSelectWallet, onCopyLink, onRetry }) => {
|
|
923
923
|
const connectorMeta = selectedConnector ? CONNECTOR_META[selectedConnector] : null;
|
|
924
924
|
const connectorLogoUrl = connectorMeta == null ? void 0 : connectorMeta.logoUrl;
|
|
925
925
|
const connectorDownloadUrl = connectorMeta == null ? void 0 : connectorMeta.downloadUrl;
|
|
@@ -950,7 +950,9 @@ var DetailPanel = /* @__PURE__ */ __name(({ selectedConnector, selectedWallet =
|
|
|
950
950
|
uri: qrUri,
|
|
951
951
|
logoUrl: connectorLogoUrl,
|
|
952
952
|
downloadUrl: connectorDownloadUrl
|
|
953
|
-
}), content === "timeout" && /* @__PURE__ */ React.createElement(Timeout,
|
|
953
|
+
}), content === "timeout" && /* @__PURE__ */ React.createElement(Timeout, {
|
|
954
|
+
onRetry
|
|
955
|
+
}), (content === "metamask-ext" || content === "metamask-qr") && /* @__PURE__ */ React.createElement(MetaMask, {
|
|
954
956
|
variant: content === "metamask-ext" ? "extension" : "qr",
|
|
955
957
|
logoUrl: connectorLogoUrl,
|
|
956
958
|
uri: qrUri,
|
|
@@ -1060,29 +1062,36 @@ var resolveWagmiConnector = /* @__PURE__ */ __name((connectors, connectorId) =>
|
|
|
1060
1062
|
return void 0;
|
|
1061
1063
|
}
|
|
1062
1064
|
}, "resolveWagmiConnector");
|
|
1063
|
-
var useWagmiConnect = /* @__PURE__ */ __name(({ onConnect, onError, onQrUri }) => {
|
|
1065
|
+
var useWagmiConnect = /* @__PURE__ */ __name(({ onConnect, onError, onQrUri, onSessionExpired }) => {
|
|
1064
1066
|
const config = useConfig();
|
|
1065
1067
|
const pendingConnectorId = useRef(null);
|
|
1066
1068
|
const attemptCounter = useRef(0);
|
|
1067
1069
|
const onConnectRef = useRef(onConnect);
|
|
1068
1070
|
const onErrorRef = useRef(onError);
|
|
1069
1071
|
const onQrUriRef = useRef(onQrUri);
|
|
1072
|
+
const onSessionExpiredRef = useRef(onSessionExpired);
|
|
1070
1073
|
useEffect(() => {
|
|
1071
1074
|
onConnectRef.current = onConnect;
|
|
1072
1075
|
onErrorRef.current = onError;
|
|
1073
1076
|
onQrUriRef.current = onQrUri;
|
|
1077
|
+
onSessionExpiredRef.current = onSessionExpired;
|
|
1074
1078
|
}, [
|
|
1075
1079
|
onConnect,
|
|
1076
1080
|
onError,
|
|
1077
|
-
onQrUri
|
|
1081
|
+
onQrUri,
|
|
1082
|
+
onSessionExpired
|
|
1078
1083
|
]);
|
|
1079
1084
|
const { connectAsync, reset, isPending } = useConnect();
|
|
1080
1085
|
useEffect(() => {
|
|
1081
1086
|
const handler = /* @__PURE__ */ __name((data) => {
|
|
1087
|
+
var _a;
|
|
1082
1088
|
const msg = data;
|
|
1083
1089
|
if ((msg == null ? void 0 : msg.type) === "display_uri" && typeof msg.data === "string") {
|
|
1084
1090
|
onQrUriRef.current(msg.data);
|
|
1085
1091
|
}
|
|
1092
|
+
if ((msg == null ? void 0 : msg.type) === "session_expired") {
|
|
1093
|
+
(_a = onSessionExpiredRef.current) == null ? void 0 : _a.call(onSessionExpiredRef);
|
|
1094
|
+
}
|
|
1086
1095
|
}, "handler");
|
|
1087
1096
|
const unsubscribers = config.connectors.map((connector) => {
|
|
1088
1097
|
connector.emitter.on("message", handler);
|
|
@@ -1145,8 +1154,58 @@ var useWagmiConnect = /* @__PURE__ */ __name(({ onConnect, onError, onQrUri }) =
|
|
|
1145
1154
|
};
|
|
1146
1155
|
}, "useWagmiConnect");
|
|
1147
1156
|
|
|
1157
|
+
// src/hooks/useConnectTimeout.ts
|
|
1158
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
1159
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 6e5;
|
|
1160
|
+
var useConnectTimeout = /* @__PURE__ */ __name(({ connectorId, active, expiredSignal = 0, onRetry }) => {
|
|
1161
|
+
const [timedOut, setTimedOut] = useState2(false);
|
|
1162
|
+
const fire = useCallback2(() => {
|
|
1163
|
+
setTimedOut(true);
|
|
1164
|
+
}, []);
|
|
1165
|
+
useEffect2(() => {
|
|
1166
|
+
setTimedOut(false);
|
|
1167
|
+
}, [
|
|
1168
|
+
connectorId
|
|
1169
|
+
]);
|
|
1170
|
+
useEffect2(() => {
|
|
1171
|
+
if (!active || connectorId !== "METAMASK") return;
|
|
1172
|
+
const timer = setTimeout(fire, DEFAULT_CONNECT_TIMEOUT_MS);
|
|
1173
|
+
return () => clearTimeout(timer);
|
|
1174
|
+
}, [
|
|
1175
|
+
active,
|
|
1176
|
+
connectorId,
|
|
1177
|
+
fire
|
|
1178
|
+
]);
|
|
1179
|
+
const prevSignal = useRef2(expiredSignal);
|
|
1180
|
+
useEffect2(() => {
|
|
1181
|
+
if (!active || connectorId === "METAMASK" || !connectorId) {
|
|
1182
|
+
prevSignal.current = expiredSignal;
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
if (expiredSignal !== prevSignal.current) {
|
|
1186
|
+
prevSignal.current = expiredSignal;
|
|
1187
|
+
fire();
|
|
1188
|
+
}
|
|
1189
|
+
}, [
|
|
1190
|
+
expiredSignal,
|
|
1191
|
+
connectorId,
|
|
1192
|
+
active,
|
|
1193
|
+
fire
|
|
1194
|
+
]);
|
|
1195
|
+
const retry = useCallback2(() => {
|
|
1196
|
+
setTimedOut(false);
|
|
1197
|
+
onRetry == null ? void 0 : onRetry();
|
|
1198
|
+
}, [
|
|
1199
|
+
onRetry
|
|
1200
|
+
]);
|
|
1201
|
+
return {
|
|
1202
|
+
timedOut,
|
|
1203
|
+
retry
|
|
1204
|
+
};
|
|
1205
|
+
}, "useConnectTimeout");
|
|
1206
|
+
|
|
1148
1207
|
// src/hooks/useWCState.ts
|
|
1149
|
-
import { useState as
|
|
1208
|
+
import { useState as useState3, useRef as useRef3, useCallback as useCallback3, useEffect as useEffect3 } from "react";
|
|
1150
1209
|
var WC_EXPLORER_CREDIT_WALLET_NAME = "Credit Wallet";
|
|
1151
1210
|
var sortCreditWalletFirst = /* @__PURE__ */ __name((list) => [
|
|
1152
1211
|
...list
|
|
@@ -1193,16 +1252,16 @@ var fetchWCWalletList = /* @__PURE__ */ __name(async (projectId, signal) => {
|
|
|
1193
1252
|
return Array.from(byId.values());
|
|
1194
1253
|
}, "fetchWCWalletList");
|
|
1195
1254
|
var useWCState = /* @__PURE__ */ __name(() => {
|
|
1196
|
-
const [subView, setSubView] =
|
|
1197
|
-
const [walletList, setWalletList] =
|
|
1198
|
-
const [walletListLoading, setWalletListLoading] =
|
|
1199
|
-
const [walletListSearch, setWalletListSearch] =
|
|
1200
|
-
const [filterActive, setFilterActive] =
|
|
1201
|
-
const [selectedWallet, setSelectedWallet] =
|
|
1202
|
-
const loadedRef =
|
|
1203
|
-
const abortControllerRef =
|
|
1204
|
-
const isMountedRef =
|
|
1205
|
-
|
|
1255
|
+
const [subView, setSubView] = useState3("qr");
|
|
1256
|
+
const [walletList, setWalletList] = useState3([]);
|
|
1257
|
+
const [walletListLoading, setWalletListLoading] = useState3(false);
|
|
1258
|
+
const [walletListSearch, setWalletListSearch] = useState3("");
|
|
1259
|
+
const [filterActive, setFilterActive] = useState3(false);
|
|
1260
|
+
const [selectedWallet, setSelectedWallet] = useState3(null);
|
|
1261
|
+
const loadedRef = useRef3(false);
|
|
1262
|
+
const abortControllerRef = useRef3(null);
|
|
1263
|
+
const isMountedRef = useRef3(true);
|
|
1264
|
+
useEffect3(() => {
|
|
1206
1265
|
isMountedRef.current = true;
|
|
1207
1266
|
return () => {
|
|
1208
1267
|
var _a;
|
|
@@ -1211,7 +1270,7 @@ var useWCState = /* @__PURE__ */ __name(() => {
|
|
|
1211
1270
|
abortControllerRef.current = null;
|
|
1212
1271
|
};
|
|
1213
1272
|
}, []);
|
|
1214
|
-
const loadWalletList =
|
|
1273
|
+
const loadWalletList = useCallback3(async (projectId) => {
|
|
1215
1274
|
if (loadedRef.current) return;
|
|
1216
1275
|
loadedRef.current = true;
|
|
1217
1276
|
const controller = new AbortController();
|
|
@@ -1229,14 +1288,14 @@ var useWCState = /* @__PURE__ */ __name(() => {
|
|
|
1229
1288
|
if (abortControllerRef.current === controller) abortControllerRef.current = null;
|
|
1230
1289
|
}
|
|
1231
1290
|
}, []);
|
|
1232
|
-
const onShowList =
|
|
1233
|
-
const onSelectWallet =
|
|
1291
|
+
const onShowList = useCallback3(() => setSubView("list"), []);
|
|
1292
|
+
const onSelectWallet = useCallback3((wallet) => {
|
|
1234
1293
|
setSelectedWallet(wallet);
|
|
1235
1294
|
setSubView("wallet");
|
|
1236
1295
|
}, []);
|
|
1237
|
-
const onSearchChange =
|
|
1238
|
-
const onFilterToggle =
|
|
1239
|
-
const handleBack =
|
|
1296
|
+
const onSearchChange = useCallback3((q) => setWalletListSearch(q), []);
|
|
1297
|
+
const onFilterToggle = useCallback3(() => setFilterActive((prev) => !prev), []);
|
|
1298
|
+
const handleBack = useCallback3(() => {
|
|
1240
1299
|
if (subView === "wallet") {
|
|
1241
1300
|
setSelectedWallet(null);
|
|
1242
1301
|
setSubView("list");
|
|
@@ -1250,11 +1309,11 @@ var useWCState = /* @__PURE__ */ __name(() => {
|
|
|
1250
1309
|
}, [
|
|
1251
1310
|
subView
|
|
1252
1311
|
]);
|
|
1253
|
-
const resetView =
|
|
1312
|
+
const resetView = useCallback3(() => {
|
|
1254
1313
|
setSubView("qr");
|
|
1255
1314
|
setSelectedWallet(null);
|
|
1256
1315
|
}, []);
|
|
1257
|
-
const reset =
|
|
1316
|
+
const reset = useCallback3(() => {
|
|
1258
1317
|
setSubView("qr");
|
|
1259
1318
|
setWalletListSearch("");
|
|
1260
1319
|
setFilterActive(false);
|
|
@@ -1302,6 +1361,7 @@ var getContentForConnector = /* @__PURE__ */ __name((id) => {
|
|
|
1302
1361
|
if (id === "WALLET_CONNECT") return "walletconnect";
|
|
1303
1362
|
return "idle";
|
|
1304
1363
|
}, "getContentForConnector");
|
|
1364
|
+
var getInitialContentForConnector = /* @__PURE__ */ __name((id) => id === "METAMASK" && !detectMetaMaskExtension() ? "metamask-qr" : getContentForConnector(id), "getInitialContentForConnector");
|
|
1305
1365
|
var ConnectDialog = /* @__PURE__ */ __name(({
|
|
1306
1366
|
open,
|
|
1307
1367
|
theme = "dark",
|
|
@@ -1320,24 +1380,59 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1320
1380
|
onConnect,
|
|
1321
1381
|
onError
|
|
1322
1382
|
}) => {
|
|
1323
|
-
const dialogRef =
|
|
1324
|
-
const [selectedConnector, setSelectedConnector] =
|
|
1325
|
-
const [recentConnector, setRecentConnector] =
|
|
1326
|
-
const [selectedWallet, setSelectedWallet] =
|
|
1327
|
-
const [step, setStep] =
|
|
1328
|
-
const [content, setContent] =
|
|
1329
|
-
const [showCopySnackbar, setShowCopySnackbar] =
|
|
1330
|
-
const [qrUri, setQrUri] =
|
|
1383
|
+
const dialogRef = useRef4(null);
|
|
1384
|
+
const [selectedConnector, setSelectedConnector] = useState4(selectedConnectorProp);
|
|
1385
|
+
const [recentConnector, setRecentConnector] = useState4(null);
|
|
1386
|
+
const [selectedWallet, setSelectedWallet] = useState4(null);
|
|
1387
|
+
const [step, setStep] = useState4(stepProp);
|
|
1388
|
+
const [content, setContent] = useState4("idle");
|
|
1389
|
+
const [showCopySnackbar, setShowCopySnackbar] = useState4(false);
|
|
1390
|
+
const [qrUri, setQrUri] = useState4(null);
|
|
1391
|
+
const [expiredSignal, setExpiredSignal] = useState4(0);
|
|
1392
|
+
const contentRef = useRef4(content);
|
|
1393
|
+
contentRef.current = content;
|
|
1394
|
+
const preTimeoutContentRef = useRef4("idle");
|
|
1331
1395
|
const config = useConfig2();
|
|
1332
1396
|
const { triggerConnect, cancelConnect } = useWagmiConnect({
|
|
1333
1397
|
onConnect: /* @__PURE__ */ __name((result) => {
|
|
1334
1398
|
setRecentConnector(result.connectorId);
|
|
1335
1399
|
onConnect == null ? void 0 : onConnect(result);
|
|
1336
1400
|
}, "onConnect"),
|
|
1337
|
-
onError: /* @__PURE__ */ __name((err, connectorId) =>
|
|
1338
|
-
|
|
1401
|
+
onError: /* @__PURE__ */ __name((err, connectorId) => {
|
|
1402
|
+
if (connectorId === "WALLET_CONNECT") {
|
|
1403
|
+
setExpiredSignal((n) => n + 1);
|
|
1404
|
+
}
|
|
1405
|
+
onError == null ? void 0 : onError(err, connectorId);
|
|
1406
|
+
}, "onError"),
|
|
1407
|
+
onQrUri: /* @__PURE__ */ __name((uri) => setQrUri(uri), "onQrUri"),
|
|
1408
|
+
// CC connector 가 서버 OnSessionExpired 를 릴레이 → 만료 신호 증가.
|
|
1409
|
+
onSessionExpired: /* @__PURE__ */ __name(() => setExpiredSignal((n) => n + 1), "onSessionExpired")
|
|
1339
1410
|
});
|
|
1340
|
-
|
|
1411
|
+
const timeoutActive = step === "detail" && !!selectedConnector && content !== "timeout";
|
|
1412
|
+
const { timedOut, retry } = useConnectTimeout({
|
|
1413
|
+
connectorId: selectedConnector,
|
|
1414
|
+
active: timeoutActive,
|
|
1415
|
+
expiredSignal,
|
|
1416
|
+
onRetry: /* @__PURE__ */ __name(() => {
|
|
1417
|
+
if (!selectedConnector) return;
|
|
1418
|
+
cancelConnect();
|
|
1419
|
+
setQrUri(null);
|
|
1420
|
+
const restore = preTimeoutContentRef.current;
|
|
1421
|
+
const nextContent = restore !== "idle" && restore !== "timeout" ? restore : getInitialContentForConnector(selectedConnector);
|
|
1422
|
+
setContent(nextContent);
|
|
1423
|
+
triggerConnect(selectedConnector);
|
|
1424
|
+
}, "onRetry")
|
|
1425
|
+
});
|
|
1426
|
+
useEffect4(() => {
|
|
1427
|
+
if (!timedOut) return;
|
|
1428
|
+
preTimeoutContentRef.current = contentRef.current;
|
|
1429
|
+
cancelConnect();
|
|
1430
|
+
setContent("timeout");
|
|
1431
|
+
}, [
|
|
1432
|
+
timedOut,
|
|
1433
|
+
cancelConnect
|
|
1434
|
+
]);
|
|
1435
|
+
useEffect4(() => {
|
|
1341
1436
|
const restoreRecent = /* @__PURE__ */ __name(async () => {
|
|
1342
1437
|
var _a;
|
|
1343
1438
|
const wagmiId = await ((_a = config.storage) == null ? void 0 : _a.getItem("recentConnectorId"));
|
|
@@ -1351,8 +1446,7 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1351
1446
|
const wc = useWCState();
|
|
1352
1447
|
const handleSelect = /* @__PURE__ */ __name((id) => {
|
|
1353
1448
|
setSelectedConnector(id);
|
|
1354
|
-
|
|
1355
|
-
setContent(initialContent);
|
|
1449
|
+
setContent(getInitialContentForConnector(id));
|
|
1356
1450
|
setStep("detail");
|
|
1357
1451
|
triggerConnect(id);
|
|
1358
1452
|
onSelectConnector == null ? void 0 : onSelectConnector(id);
|
|
@@ -1384,7 +1478,7 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1384
1478
|
wc.loadWalletList(wcProjectId).catch(() => void 0);
|
|
1385
1479
|
}
|
|
1386
1480
|
}, "handleShowAllWallets");
|
|
1387
|
-
|
|
1481
|
+
useEffect4(() => {
|
|
1388
1482
|
const dialog = dialogRef.current;
|
|
1389
1483
|
if (!dialog) return;
|
|
1390
1484
|
if (open && !dialog.open) dialog.showModal();
|
|
@@ -1392,13 +1486,13 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1392
1486
|
}, [
|
|
1393
1487
|
open
|
|
1394
1488
|
]);
|
|
1395
|
-
const deeplinkTriedRef =
|
|
1396
|
-
|
|
1489
|
+
const deeplinkTriedRef = useRef4(false);
|
|
1490
|
+
useEffect4(() => {
|
|
1397
1491
|
deeplinkTriedRef.current = false;
|
|
1398
1492
|
}, [
|
|
1399
1493
|
selectedWallet
|
|
1400
1494
|
]);
|
|
1401
|
-
|
|
1495
|
+
useEffect4(() => {
|
|
1402
1496
|
if (deeplinkTriedRef.current) return;
|
|
1403
1497
|
if (!selectedWallet || !qrUri || content !== "wallet-qr") return;
|
|
1404
1498
|
if (!isMobileDevice()) return;
|
|
@@ -1411,13 +1505,13 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1411
1505
|
qrUri,
|
|
1412
1506
|
content
|
|
1413
1507
|
]);
|
|
1414
|
-
const creditConnectDeeplinkTriedRef =
|
|
1415
|
-
|
|
1508
|
+
const creditConnectDeeplinkTriedRef = useRef4(false);
|
|
1509
|
+
useEffect4(() => {
|
|
1416
1510
|
creditConnectDeeplinkTriedRef.current = false;
|
|
1417
1511
|
}, [
|
|
1418
1512
|
selectedConnector
|
|
1419
1513
|
]);
|
|
1420
|
-
|
|
1514
|
+
useEffect4(() => {
|
|
1421
1515
|
if (creditConnectDeeplinkTriedRef.current) return;
|
|
1422
1516
|
if (content !== "qr" || !qrUri) return;
|
|
1423
1517
|
if (selectedConnector !== "CREDIT_CONNECT") return;
|
|
@@ -1429,7 +1523,7 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1429
1523
|
qrUri,
|
|
1430
1524
|
selectedConnector
|
|
1431
1525
|
]);
|
|
1432
|
-
|
|
1526
|
+
useEffect4(() => {
|
|
1433
1527
|
const prev = document.body.style.overflow;
|
|
1434
1528
|
if (open) document.body.style.overflow = "hidden";
|
|
1435
1529
|
return () => {
|
|
@@ -1438,7 +1532,7 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1438
1532
|
}, [
|
|
1439
1533
|
open
|
|
1440
1534
|
]);
|
|
1441
|
-
|
|
1535
|
+
useEffect4(() => {
|
|
1442
1536
|
if (!open) {
|
|
1443
1537
|
cancelConnect();
|
|
1444
1538
|
setQrUri(null);
|
|
@@ -1451,7 +1545,7 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1451
1545
|
open,
|
|
1452
1546
|
cancelConnect
|
|
1453
1547
|
]);
|
|
1454
|
-
|
|
1548
|
+
useEffect4(() => {
|
|
1455
1549
|
const dialog = dialogRef.current;
|
|
1456
1550
|
if (!dialog) return void 0;
|
|
1457
1551
|
const handleCancel = /* @__PURE__ */ __name((e) => {
|
|
@@ -1492,6 +1586,7 @@ var ConnectDialog = /* @__PURE__ */ __name(({
|
|
|
1492
1586
|
walletCount: wc.walletList.length,
|
|
1493
1587
|
onBack: handleBack,
|
|
1494
1588
|
onClose,
|
|
1589
|
+
onRetry: retry,
|
|
1495
1590
|
onShowAllWallets: handleShowAllWallets,
|
|
1496
1591
|
onSelectWallet: handleSelectWallet,
|
|
1497
1592
|
onCopyLink: /* @__PURE__ */ __name(() => {
|
|
@@ -1538,32 +1633,32 @@ var ConnectKitProvider = /* @__PURE__ */ __name((props) => {
|
|
|
1538
1633
|
}, "ConnectKitProvider");
|
|
1539
1634
|
var ConnectKitProviderInner = /* @__PURE__ */ __name(({ children, connectors, kitConfig, requiredChainId, theme, onConnect, onLog }) => {
|
|
1540
1635
|
var _a;
|
|
1541
|
-
const [isOpen, setIsOpen] =
|
|
1542
|
-
const [pendingResult, setPendingResult] =
|
|
1636
|
+
const [isOpen, setIsOpen] = useState5(false);
|
|
1637
|
+
const [pendingResult, setPendingResult] = useState5(null);
|
|
1543
1638
|
const account = useAccount();
|
|
1544
1639
|
const wagmiConfig = useConfig3();
|
|
1545
1640
|
const { disconnectAsync } = useDisconnect();
|
|
1546
1641
|
const { switchChainAsync } = useSwitchChain();
|
|
1547
|
-
const onConnectRef =
|
|
1548
|
-
|
|
1642
|
+
const onConnectRef = useRef5(onConnect);
|
|
1643
|
+
useEffect5(() => {
|
|
1549
1644
|
onConnectRef.current = onConnect;
|
|
1550
1645
|
}, [
|
|
1551
1646
|
onConnect
|
|
1552
1647
|
]);
|
|
1553
|
-
const isMountedRef =
|
|
1554
|
-
|
|
1648
|
+
const isMountedRef = useRef5(true);
|
|
1649
|
+
useEffect5(() => {
|
|
1555
1650
|
isMountedRef.current = true;
|
|
1556
1651
|
return () => {
|
|
1557
1652
|
isMountedRef.current = false;
|
|
1558
1653
|
};
|
|
1559
1654
|
}, []);
|
|
1560
1655
|
const needsChainSwitch = requiredChainId != null && account.status === "connected" && account.chainId != null && account.chainId !== requiredChainId;
|
|
1561
|
-
const [isSwitchingChain, setIsSwitchingChain] =
|
|
1656
|
+
const [isSwitchingChain, setIsSwitchingChain] = useState5(false);
|
|
1562
1657
|
const effectiveOpen = isOpen;
|
|
1563
|
-
const open =
|
|
1658
|
+
const open = useCallback4(() => {
|
|
1564
1659
|
setIsOpen(true);
|
|
1565
1660
|
}, []);
|
|
1566
|
-
const close =
|
|
1661
|
+
const close = useCallback4(() => {
|
|
1567
1662
|
setIsOpen(false);
|
|
1568
1663
|
const status = getAccount2(wagmiConfig).status;
|
|
1569
1664
|
if (status === "connecting" || status === "reconnecting") {
|
|
@@ -1573,12 +1668,12 @@ var ConnectKitProviderInner = /* @__PURE__ */ __name(({ children, connectors, ki
|
|
|
1573
1668
|
wagmiConfig,
|
|
1574
1669
|
disconnectAsync
|
|
1575
1670
|
]);
|
|
1576
|
-
const disconnect =
|
|
1671
|
+
const disconnect = useCallback4(async () => {
|
|
1577
1672
|
await disconnectAsync();
|
|
1578
1673
|
}, [
|
|
1579
1674
|
disconnectAsync
|
|
1580
1675
|
]);
|
|
1581
|
-
const switchToRequiredChain =
|
|
1676
|
+
const switchToRequiredChain = useCallback4(async () => {
|
|
1582
1677
|
if (requiredChainId == null) return;
|
|
1583
1678
|
setIsSwitchingChain(true);
|
|
1584
1679
|
try {
|
|
@@ -1592,15 +1687,15 @@ var ConnectKitProviderInner = /* @__PURE__ */ __name(({ children, connectors, ki
|
|
|
1592
1687
|
requiredChainId,
|
|
1593
1688
|
switchChainAsync
|
|
1594
1689
|
]);
|
|
1595
|
-
const handleDialogConnect =
|
|
1690
|
+
const handleDialogConnect = useCallback4((result) => {
|
|
1596
1691
|
setPendingResult(result);
|
|
1597
1692
|
}, []);
|
|
1598
|
-
const handleDialogError =
|
|
1693
|
+
const handleDialogError = useCallback4((error, connectorId) => {
|
|
1599
1694
|
onLog == null ? void 0 : onLog(`[connect-kit] connect failed: ${connectorId} \u2014 ${error.message}`, error);
|
|
1600
1695
|
}, [
|
|
1601
1696
|
onLog
|
|
1602
1697
|
]);
|
|
1603
|
-
|
|
1698
|
+
useEffect5(() => {
|
|
1604
1699
|
if (!effectiveOpen) return;
|
|
1605
1700
|
if (account.status !== "connected") return;
|
|
1606
1701
|
setIsOpen(false);
|
|
@@ -1608,7 +1703,7 @@ var ConnectKitProviderInner = /* @__PURE__ */ __name(({ children, connectors, ki
|
|
|
1608
1703
|
effectiveOpen,
|
|
1609
1704
|
account.status
|
|
1610
1705
|
]);
|
|
1611
|
-
|
|
1706
|
+
useEffect5(() => {
|
|
1612
1707
|
var _a2;
|
|
1613
1708
|
if (!pendingResult) return;
|
|
1614
1709
|
if (account.status !== "connected") {
|
package/dist/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.2.0-next.
|
|
3
|
+
"version": "0.2.0-next.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"qrcode.react": "^4.2.0",
|
|
27
27
|
"wagmi": "^2.15.6",
|
|
28
28
|
"@wagmi/core": "^2.16.7",
|
|
29
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.
|
|
30
|
-
"@gluwa/credit-connect-storage-local": "0.2.0-next.
|
|
31
|
-
"@gluwa/credit-connect-e2ee-tweetnacl": "0.2.0-next.
|
|
32
|
-
"@gluwa/credit-connect-hub-node-ws": "0.1.0-next.
|
|
29
|
+
"@gluwa/credit-connect-sdk": "0.2.0-next.4",
|
|
30
|
+
"@gluwa/credit-connect-storage-local": "0.2.0-next.4",
|
|
31
|
+
"@gluwa/credit-connect-e2ee-tweetnacl": "0.2.0-next.4",
|
|
32
|
+
"@gluwa/credit-connect-hub-node-ws": "0.1.0-next.4"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@tanstack/react-query": "^5.62.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"typescript-eslint": "^8.18.2",
|
|
44
44
|
"viem": "^2.31.7",
|
|
45
45
|
"wagmi": "^2.15.6",
|
|
46
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.
|
|
46
|
+
"@gluwa/credit-connect-sdk": "0.2.0-next.4"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@tanstack/react-query": ">=5.0.0",
|
|
@@ -107,6 +107,12 @@ export const creditConnectConnector = (
|
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
manager.on('sessionExpired', (payload) => {
|
|
111
|
+
// eslint-disable-next-line no-console
|
|
112
|
+
console.log('[CC connector] session expired → emit session_expired', payload);
|
|
113
|
+
emitWagmiMessage?.('session_expired', payload);
|
|
114
|
+
});
|
|
115
|
+
|
|
110
116
|
return manager;
|
|
111
117
|
};
|
|
112
118
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { type ConnectorId } from '../types';
|
|
3
|
+
|
|
4
|
+
// MM / CC 폴백용 기본 타임아웃. (CC 는 원칙적으로 서버 push 로 만료가 오지만,
|
|
5
|
+
// 서버 값이 없거나 신호가 유실된 경우를 대비한 폴백 용도로도 쓸 수 있음.)
|
|
6
|
+
export const DEFAULT_CONNECT_TIMEOUT_MS = 600_000;
|
|
7
|
+
|
|
8
|
+
interface UseConnectTimeoutParams {
|
|
9
|
+
/** 현재 연결 시도 중인 커넥터. null = 유휴 상태. */
|
|
10
|
+
connectorId: ConnectorId | null;
|
|
11
|
+
/** 타임아웃 감시 활성화 여부 — pending/QR 표시 중일 때 true. */
|
|
12
|
+
active: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* 외부 이벤트 기반 만료 신호 (MM 제외). 값이 증가할 때마다 "만료 발생" 으로 간주.
|
|
15
|
+
* - CC: dialog 가 connector 의 `session_expired`(서버 push) 를 받아 올림.
|
|
16
|
+
* - WC: dialog 가 WC connect promise reject(프로토콜 ~5분 만료 등) 를 받아 올림.
|
|
17
|
+
*/
|
|
18
|
+
expiredSignal?: number;
|
|
19
|
+
/** "Try Again" 시 실행할 재연결 로직 (dialog 가 주입). */
|
|
20
|
+
onRetry?: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface UseConnectTimeoutResult {
|
|
24
|
+
/** 타임아웃 발생 여부 — true 면 dialog 가 <Timeout> 을 렌더. */
|
|
25
|
+
timedOut: boolean;
|
|
26
|
+
/** "Try Again" 버튼에 연결할 함수 — 상태 리셋 + onRetry 실행. */
|
|
27
|
+
retry: () => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 커넥터별로 타임아웃 신호원을 분기해 하나의 `timedOut` 으로 수렴시키는 훅.
|
|
32
|
+
* - CC: 서버 push (`OnSessionExpired` → connector → expiredSignal).
|
|
33
|
+
* - MM: 네이티브 타임아웃 없음 → client 타이머(DEFAULT_CONNECT_TIMEOUT_MS).
|
|
34
|
+
* - WC: 프로토콜 자체 ~5분 proposal reject → connect promise reject → expiredSignal.
|
|
35
|
+
*/
|
|
36
|
+
export const useConnectTimeout = ({
|
|
37
|
+
connectorId,
|
|
38
|
+
active,
|
|
39
|
+
expiredSignal = 0,
|
|
40
|
+
onRetry,
|
|
41
|
+
}: UseConnectTimeoutParams): UseConnectTimeoutResult => {
|
|
42
|
+
const [timedOut, setTimedOut] = useState(false);
|
|
43
|
+
|
|
44
|
+
const fire = useCallback(() => {
|
|
45
|
+
setTimedOut(true);
|
|
46
|
+
}, []);
|
|
47
|
+
|
|
48
|
+
// 커넥터가 바뀌면(=새 연결 시도) 타임아웃 상태 리셋.
|
|
49
|
+
// active 가 false 로 떨어질 때는 리셋하지 않는다 — timeout UI 표시 중 상태가 날아가지 않도록.
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
setTimedOut(false);
|
|
52
|
+
}, [connectorId]);
|
|
53
|
+
|
|
54
|
+
// MM 만 client 타이머로 강제 (승인 대기에 네이티브 상한이 없음).
|
|
55
|
+
// CC(서버 push) / WC(connect reject) 는 아래 expiredSignal effect 에서 처리.
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!active || connectorId !== 'METAMASK') return;
|
|
58
|
+
const timer = setTimeout(fire, DEFAULT_CONNECT_TIMEOUT_MS);
|
|
59
|
+
return () => clearTimeout(timer);
|
|
60
|
+
}, [active, connectorId, fire]);
|
|
61
|
+
|
|
62
|
+
// 외부 만료 신호 처리 (CC 서버 push / WC connect reject) — MM 은 client 타이머라 제외.
|
|
63
|
+
// signal 값이 올라가면(새 만료 이벤트) 발화.
|
|
64
|
+
const prevSignal = useRef(expiredSignal);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!active || connectorId === 'METAMASK' || !connectorId) {
|
|
67
|
+
prevSignal.current = expiredSignal;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (expiredSignal !== prevSignal.current) {
|
|
71
|
+
prevSignal.current = expiredSignal;
|
|
72
|
+
fire();
|
|
73
|
+
}
|
|
74
|
+
}, [expiredSignal, connectorId, active, fire]);
|
|
75
|
+
|
|
76
|
+
const retry = useCallback(() => {
|
|
77
|
+
setTimedOut(false);
|
|
78
|
+
onRetry?.();
|
|
79
|
+
}, [onRetry]);
|
|
80
|
+
|
|
81
|
+
return { timedOut, retry };
|
|
82
|
+
};
|
|
@@ -61,6 +61,7 @@ interface Options {
|
|
|
61
61
|
onConnect: (result: ConnectResult) => void;
|
|
62
62
|
onError: (error: Error, connectorId: ConnectorId) => void;
|
|
63
63
|
onQrUri: (uri: string | null) => void;
|
|
64
|
+
onSessionExpired?: () => void;
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
interface UseWagmiConnectResult {
|
|
@@ -73,6 +74,7 @@ export const useWagmiConnect = ({
|
|
|
73
74
|
onConnect,
|
|
74
75
|
onError,
|
|
75
76
|
onQrUri,
|
|
77
|
+
onSessionExpired,
|
|
76
78
|
}: Options): UseWagmiConnectResult => {
|
|
77
79
|
const config = useConfig();
|
|
78
80
|
const pendingConnectorId = useRef<ConnectorId | null>(null);
|
|
@@ -81,11 +83,13 @@ export const useWagmiConnect = ({
|
|
|
81
83
|
const onConnectRef = useRef(onConnect);
|
|
82
84
|
const onErrorRef = useRef(onError);
|
|
83
85
|
const onQrUriRef = useRef(onQrUri);
|
|
86
|
+
const onSessionExpiredRef = useRef(onSessionExpired);
|
|
84
87
|
useEffect(() => {
|
|
85
88
|
onConnectRef.current = onConnect;
|
|
86
89
|
onErrorRef.current = onError;
|
|
87
90
|
onQrUriRef.current = onQrUri;
|
|
88
|
-
|
|
91
|
+
onSessionExpiredRef.current = onSessionExpired;
|
|
92
|
+
}, [onConnect, onError, onQrUri, onSessionExpired]);
|
|
89
93
|
|
|
90
94
|
const { connectAsync, reset, isPending } = useConnect();
|
|
91
95
|
|
|
@@ -95,6 +99,9 @@ export const useWagmiConnect = ({
|
|
|
95
99
|
if (msg?.type === 'display_uri' && typeof msg.data === 'string') {
|
|
96
100
|
onQrUriRef.current(msg.data);
|
|
97
101
|
}
|
|
102
|
+
if (msg?.type === 'session_expired') {
|
|
103
|
+
onSessionExpiredRef.current?.();
|
|
104
|
+
}
|
|
98
105
|
};
|
|
99
106
|
|
|
100
107
|
const unsubscribers = config.connectors.map((connector) => {
|
|
@@ -13,6 +13,7 @@ import { DetailPanel } from '../detailPanel';
|
|
|
13
13
|
import { Snackbar } from '../../components/snackbar';
|
|
14
14
|
import { resolveConnectorId } from '../../connector-meta';
|
|
15
15
|
import { useWagmiConnect } from '../../hooks/useWagmiConnect';
|
|
16
|
+
import { useConnectTimeout } from '../../hooks/useConnectTimeout';
|
|
16
17
|
import { useWCState } from '../../hooks/useWCState';
|
|
17
18
|
import {
|
|
18
19
|
detectMetaMaskExtension,
|
|
@@ -47,6 +48,10 @@ const getContentForConnector = (id: ConnectorId): DetailContent => {
|
|
|
47
48
|
return 'idle';
|
|
48
49
|
};
|
|
49
50
|
|
|
51
|
+
// MM 은 확장 감지 시 즉시 extension 연결, 아니면 QR. (select / retry 공통)
|
|
52
|
+
const getInitialContentForConnector = (id: ConnectorId): DetailContent =>
|
|
53
|
+
id === 'METAMASK' && !detectMetaMaskExtension() ? 'metamask-qr' : getContentForConnector(id);
|
|
54
|
+
|
|
50
55
|
export const ConnectDialog: FC<ConnectDialogProps> = ({
|
|
51
56
|
open,
|
|
52
57
|
theme = 'dark',
|
|
@@ -83,6 +88,14 @@ export const ConnectDialog: FC<ConnectDialogProps> = ({
|
|
|
83
88
|
const [content, setContent] = useState<DetailContent>('idle');
|
|
84
89
|
const [showCopySnackbar, setShowCopySnackbar] = useState(false);
|
|
85
90
|
const [qrUri, setQrUri] = useState<string | null>(null);
|
|
91
|
+
// 외부 만료 신호 카운터 — CC(서버 push session_expired) / WC(connect reject) 수신 시 증가.
|
|
92
|
+
const [expiredSignal, setExpiredSignal] = useState(0);
|
|
93
|
+
|
|
94
|
+
// 현재 content 를 ref 로 추적 (effect deps 없이 최신값 참조용).
|
|
95
|
+
const contentRef = useRef<DetailContent>(content);
|
|
96
|
+
contentRef.current = content;
|
|
97
|
+
// 타임아웃 직전 화면 — retry 시 이 화면으로 복원 (예: WC 의 wallet-qr).
|
|
98
|
+
const preTimeoutContentRef = useRef<DetailContent>('idle');
|
|
86
99
|
|
|
87
100
|
const config = useConfig();
|
|
88
101
|
|
|
@@ -95,10 +108,50 @@ export const ConnectDialog: FC<ConnectDialogProps> = ({
|
|
|
95
108
|
setRecentConnector(result.connectorId);
|
|
96
109
|
onConnect?.(result);
|
|
97
110
|
},
|
|
98
|
-
onError: (err, connectorId) =>
|
|
111
|
+
onError: (err, connectorId) => {
|
|
112
|
+
// WC: connect reject(사용자 거절 / 프로토콜 ~5분 만료 / 네트워크 등)는
|
|
113
|
+
// 모두 timeout UI("Connection Failed")로 통일.
|
|
114
|
+
if (connectorId === 'WALLET_CONNECT') {
|
|
115
|
+
setExpiredSignal((n) => n + 1);
|
|
116
|
+
}
|
|
117
|
+
onError?.(err, connectorId);
|
|
118
|
+
},
|
|
99
119
|
onQrUri: (uri) => setQrUri(uri),
|
|
120
|
+
// CC connector 가 서버 OnSessionExpired 를 릴레이 → 만료 신호 증가.
|
|
121
|
+
onSessionExpired: () => setExpiredSignal((n) => n + 1),
|
|
100
122
|
});
|
|
101
123
|
|
|
124
|
+
// 연결 타임아웃 (CC=서버 push / MM=client 타이머 / WC=connect reject) → timedOut.
|
|
125
|
+
const timeoutActive = step === 'detail' && !!selectedConnector && content !== 'timeout';
|
|
126
|
+
const { timedOut, retry } = useConnectTimeout({
|
|
127
|
+
connectorId: selectedConnector,
|
|
128
|
+
active: timeoutActive,
|
|
129
|
+
expiredSignal,
|
|
130
|
+
onRetry: () => {
|
|
131
|
+
if (!selectedConnector) return;
|
|
132
|
+
cancelConnect();
|
|
133
|
+
setQrUri(null);
|
|
134
|
+
// 타임아웃 직전 화면으로 복원 (예: WC 의 wallet-qr → 선택 지갑 QR 유지).
|
|
135
|
+
// idle/timeout 처럼 복원 불가한 값이면 커넥터 초기 화면으로.
|
|
136
|
+
const restore = preTimeoutContentRef.current;
|
|
137
|
+
const nextContent: DetailContent =
|
|
138
|
+
restore !== 'idle' && restore !== 'timeout'
|
|
139
|
+
? restore
|
|
140
|
+
: getInitialContentForConnector(selectedConnector);
|
|
141
|
+
setContent(nextContent);
|
|
142
|
+
triggerConnect(selectedConnector);
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// 타임아웃 발생 → 진행 중 연결 취소 + timeout 화면 표시.
|
|
147
|
+
// 전환 전 화면을 저장해 retry 시 복원 (WC wallet-qr 등).
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
if (!timedOut) return;
|
|
150
|
+
preTimeoutContentRef.current = contentRef.current;
|
|
151
|
+
cancelConnect();
|
|
152
|
+
setContent('timeout');
|
|
153
|
+
}, [timedOut, cancelConnect]);
|
|
154
|
+
|
|
102
155
|
// 마운트 시 wagmi storage 의 recentConnectorId(연결 성공 시 wagmi 가 저장) 복원.
|
|
103
156
|
useEffect(() => {
|
|
104
157
|
const restoreRecent = async (): Promise<void> => {
|
|
@@ -115,10 +168,7 @@ export const ConnectDialog: FC<ConnectDialogProps> = ({
|
|
|
115
168
|
const handleSelect = (id: ConnectorId) => {
|
|
116
169
|
setSelectedConnector(id);
|
|
117
170
|
// recent 는 클릭이 아니라 연결 성공(onConnect) 시점에 기록 — 위 useWagmiConnect onConnect 참조.
|
|
118
|
-
|
|
119
|
-
const initialContent: DetailContent =
|
|
120
|
-
id === 'METAMASK' && !detectMetaMaskExtension() ? 'metamask-qr' : getContentForConnector(id);
|
|
121
|
-
setContent(initialContent);
|
|
171
|
+
setContent(getInitialContentForConnector(id));
|
|
122
172
|
setStep('detail');
|
|
123
173
|
// wagmi connect 시작 (display_uri 도착 시 setQrUri 자동 호출)
|
|
124
174
|
triggerConnect(id);
|
|
@@ -261,6 +311,7 @@ export const ConnectDialog: FC<ConnectDialogProps> = ({
|
|
|
261
311
|
walletCount={wc.walletList.length}
|
|
262
312
|
onBack={handleBack}
|
|
263
313
|
onClose={onClose}
|
|
314
|
+
onRetry={retry}
|
|
264
315
|
onShowAllWallets={handleShowAllWallets}
|
|
265
316
|
onSelectWallet={handleSelectWallet}
|
|
266
317
|
onCopyLink={() => {
|
|
@@ -40,6 +40,8 @@ interface DetailPanelProps {
|
|
|
40
40
|
onShowAllWallets?: () => void;
|
|
41
41
|
onSelectWallet?: (wallet: WCWallet) => void;
|
|
42
42
|
onCopyLink?: () => void;
|
|
43
|
+
/** timeout 화면의 "Try Again" 버튼 핸들러. */
|
|
44
|
+
onRetry?: () => void;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const getTitle = (content: DetailContent, connector: ConnectorId | null): string => {
|
|
@@ -78,6 +80,7 @@ export const DetailPanel: FC<DetailPanelProps> = ({
|
|
|
78
80
|
onShowAllWallets,
|
|
79
81
|
onSelectWallet,
|
|
80
82
|
onCopyLink,
|
|
83
|
+
onRetry,
|
|
81
84
|
}) => {
|
|
82
85
|
// CONNECTOR_META 에서 활성 connector 의 logo / downloadUrl 가져옴.
|
|
83
86
|
const connectorMeta = selectedConnector ? CONNECTOR_META[selectedConnector] : null;
|
|
@@ -112,7 +115,7 @@ export const DetailPanel: FC<DetailPanelProps> = ({
|
|
|
112
115
|
{content === 'qr' && (
|
|
113
116
|
<QR uri={qrUri} logoUrl={connectorLogoUrl} downloadUrl={connectorDownloadUrl} />
|
|
114
117
|
)}
|
|
115
|
-
{content === 'timeout' && <Timeout />}
|
|
118
|
+
{content === 'timeout' && <Timeout onRetry={onRetry} />}
|
|
116
119
|
{(content === 'metamask-ext' || content === 'metamask-qr') && (
|
|
117
120
|
<MetaMask
|
|
118
121
|
variant={content === 'metamask-ext' ? 'extension' : 'qr'}
|