@openzeppelin/ui-react 3.1.0 → 3.3.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/dist/index.cjs +304 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -10
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +69 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +299 -87
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -33,7 +33,7 @@ let _tanstack_react_query = require("@tanstack/react-query");
|
|
|
33
33
|
let _openzeppelin_ui_components = require("@openzeppelin/ui-components");
|
|
34
34
|
|
|
35
35
|
//#region src/version.ts
|
|
36
|
-
const VERSION = "3.
|
|
36
|
+
const VERSION = "3.3.0";
|
|
37
37
|
|
|
38
38
|
//#endregion
|
|
39
39
|
//#region src/hooks/AdapterContext.tsx
|
|
@@ -86,11 +86,31 @@ function RuntimeProvider({ children, resolveRuntime }) {
|
|
|
86
86
|
const [loadingNetworks, setLoadingNetworks] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
87
87
|
const runtimeRegistryRef = (0, react.useRef)(runtimeRegistry);
|
|
88
88
|
const failedNetworksRef = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
89
|
+
const resolverGenerationRef = (0, react.useRef)(0);
|
|
90
|
+
const resolverInitializedRef = (0, react.useRef)(false);
|
|
89
91
|
(0, react.useEffect)(() => {
|
|
90
92
|
runtimeRegistryRef.current = runtimeRegistry;
|
|
91
93
|
}, [runtimeRegistry]);
|
|
92
94
|
(0, react.useEffect)(() => {
|
|
95
|
+
if (resolverInitializedRef.current) resolverGenerationRef.current += 1;
|
|
96
|
+
else resolverInitializedRef.current = true;
|
|
97
|
+
const registry = runtimeRegistryRef.current;
|
|
98
|
+
const runtimes = Object.values(registry);
|
|
99
|
+
const hadCachedRuntimes = runtimes.length > 0;
|
|
93
100
|
failedNetworksRef.current = /* @__PURE__ */ new Set();
|
|
101
|
+
setLoadingNetworks(/* @__PURE__ */ new Set());
|
|
102
|
+
if (hadCachedRuntimes) {
|
|
103
|
+
setRuntimeRegistry({});
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
runtimes.forEach((runtime) => {
|
|
106
|
+
try {
|
|
107
|
+
runtime.dispose();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
_openzeppelin_ui_utils.logger.error("RuntimeProvider", "Error disposing runtime during registry flush:", error);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}, 0);
|
|
113
|
+
}
|
|
94
114
|
}, [resolveRuntime]);
|
|
95
115
|
(0, react.useEffect)(() => {
|
|
96
116
|
return () => {
|
|
@@ -178,7 +198,23 @@ function RuntimeProvider({ children, resolveRuntime }) {
|
|
|
178
198
|
return newSet;
|
|
179
199
|
});
|
|
180
200
|
_openzeppelin_ui_utils.logger.info("RuntimeProvider", `Starting runtime initialization for network ${networkId} (${networkConfig.name})`);
|
|
201
|
+
const generation = resolverGenerationRef.current;
|
|
181
202
|
resolveRuntime(networkConfig).then((runtime) => {
|
|
203
|
+
if (generation !== resolverGenerationRef.current) {
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
try {
|
|
206
|
+
runtime.dispose();
|
|
207
|
+
} catch (error) {
|
|
208
|
+
_openzeppelin_ui_utils.logger.error("RuntimeProvider", `Error disposing stale runtime for network ${networkId}:`, error);
|
|
209
|
+
}
|
|
210
|
+
}, 0);
|
|
211
|
+
setLoadingNetworks((prev) => {
|
|
212
|
+
const newSet = new Set(prev);
|
|
213
|
+
newSet.delete(networkId);
|
|
214
|
+
return newSet;
|
|
215
|
+
});
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
182
218
|
_openzeppelin_ui_utils.logger.info("RuntimeProvider", `Runtime for network ${networkId} loaded successfully`, {
|
|
183
219
|
type: runtime.constructor.name,
|
|
184
220
|
objectId: Object.prototype.toString.call(runtime)
|
|
@@ -193,6 +229,14 @@ function RuntimeProvider({ children, resolveRuntime }) {
|
|
|
193
229
|
return newSet;
|
|
194
230
|
});
|
|
195
231
|
}).catch((error) => {
|
|
232
|
+
if (generation !== resolverGenerationRef.current) {
|
|
233
|
+
setLoadingNetworks((prev) => {
|
|
234
|
+
const newSet = new Set(prev);
|
|
235
|
+
newSet.delete(networkId);
|
|
236
|
+
return newSet;
|
|
237
|
+
});
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
196
240
|
_openzeppelin_ui_utils.logger.error("RuntimeProvider", `Error loading runtime for network ${networkId}:`, error);
|
|
197
241
|
failedNetworksRef.current.add(networkId);
|
|
198
242
|
setLoadingNetworks((prev) => {
|
|
@@ -921,22 +965,42 @@ const DEFAULT_CONFIG = {
|
|
|
921
965
|
};
|
|
922
966
|
/** Stable prefix for every resolution cache key — namespaces this package's keys. */
|
|
923
967
|
const RESOLUTION_KEY_PREFIX = "oz-name-resolution";
|
|
968
|
+
const runtimeInstanceIds = /* @__PURE__ */ new WeakMap();
|
|
969
|
+
let nextRuntimeInstanceId = 1;
|
|
970
|
+
/**
|
|
971
|
+
* Assign a stable, serializable id to each {@link EcosystemRuntime} object identity.
|
|
972
|
+
* A disposed-and-recreated runtime (e.g. SF-4 opt-in toggle after INV-218 flush) gets
|
|
973
|
+
* a new id so resolution cache keys miss and results refresh (INV-230).
|
|
974
|
+
*/
|
|
975
|
+
function getRuntimeInstanceId(runtime) {
|
|
976
|
+
if (!runtime) return 0;
|
|
977
|
+
let id = runtimeInstanceIds.get(runtime);
|
|
978
|
+
if (id === void 0) {
|
|
979
|
+
id = nextRuntimeInstanceId;
|
|
980
|
+
nextRuntimeInstanceId += 1;
|
|
981
|
+
runtimeInstanceIds.set(runtime, id);
|
|
982
|
+
}
|
|
983
|
+
return id;
|
|
984
|
+
}
|
|
924
985
|
/**
|
|
925
986
|
* Build a network-scoped, namespace-separated cache key (INV-40). A name resolves
|
|
926
987
|
* differently per network and provenance can be chain-scoped, so `networkId` is
|
|
927
|
-
* part of the key; `namespace` keeps forward and reverse lookups disjoint
|
|
988
|
+
* part of the key; `namespace` keeps forward and reverse lookups disjoint;
|
|
989
|
+
* `runtimeInstanceId` scopes entries to the active capability instance (INV-230).
|
|
928
990
|
*
|
|
929
|
-
* @param namespace
|
|
930
|
-
* @param networkId
|
|
931
|
-
* @param normalizedInput
|
|
991
|
+
* @param namespace - `'name'` (forward) or `'addr'` (reverse).
|
|
992
|
+
* @param networkId - Active network id (`''` when no network is selected).
|
|
993
|
+
* @param normalizedInput - Trimmed + lowercased input (INV-26).
|
|
994
|
+
* @param runtimeInstanceId - Active runtime instance discriminator (`0` when absent).
|
|
932
995
|
* @returns A readonly tuple suitable for a TanStack Query `queryKey`.
|
|
933
996
|
*/
|
|
934
|
-
function buildResolutionKey(namespace, networkId, normalizedInput) {
|
|
997
|
+
function buildResolutionKey(namespace, networkId, normalizedInput, runtimeInstanceId = 0) {
|
|
935
998
|
return [
|
|
936
999
|
RESOLUTION_KEY_PREFIX,
|
|
937
1000
|
namespace,
|
|
938
1001
|
networkId,
|
|
939
|
-
normalizedInput
|
|
1002
|
+
normalizedInput,
|
|
1003
|
+
runtimeInstanceId
|
|
940
1004
|
];
|
|
941
1005
|
}
|
|
942
1006
|
/**
|
|
@@ -1109,11 +1173,11 @@ const NOOP_RETRY = () => {};
|
|
|
1109
1173
|
* {@link EngineResult}. Not exported from the package.
|
|
1110
1174
|
*/
|
|
1111
1175
|
function useResolutionEngine(params) {
|
|
1112
|
-
const { input, namespace, debounceMs, enabled, shouldAttempt, getMethod } = params;
|
|
1176
|
+
const { input, namespace, debounceMs, enabled, shouldAttempt, getMethod, runtimeSource } = params;
|
|
1113
1177
|
const walletState = (0, react.useContext)(WalletStateContext);
|
|
1114
|
-
const activeRuntime = walletState?.activeRuntime ?? null;
|
|
1115
|
-
const activeNetworkId = walletState?.activeNetworkId ?? null;
|
|
1116
|
-
const isRuntimeLoading = walletState?.isRuntimeLoading ?? false;
|
|
1178
|
+
const activeRuntime = runtimeSource ? runtimeSource.runtime : walletState?.activeRuntime ?? null;
|
|
1179
|
+
const activeNetworkId = runtimeSource ? runtimeSource.networkId : walletState?.activeNetworkId ?? null;
|
|
1180
|
+
const isRuntimeLoading = runtimeSource ? runtimeSource.isRuntimeLoading : walletState?.isRuntimeLoading ?? false;
|
|
1117
1181
|
const { queryClient, config } = useNameResolutionContext();
|
|
1118
1182
|
const trimmedLive = (input ?? "").trim();
|
|
1119
1183
|
const normalizedLive = trimmedLive.toLowerCase();
|
|
@@ -1135,12 +1199,13 @@ function useResolutionEngine(params) {
|
|
|
1135
1199
|
const normalizedKey = effectiveTrimmed.toLowerCase();
|
|
1136
1200
|
const capability = activeRuntime?.nameResolution;
|
|
1137
1201
|
const networkId = activeNetworkId ?? "";
|
|
1202
|
+
const runtimeInstanceId = getRuntimeInstanceId(activeRuntime);
|
|
1138
1203
|
const method = capability ? getMethod(capability) : void 0;
|
|
1139
1204
|
const liveAttemptable = capability ? shouldAttempt(capability, normalizedLive) : false;
|
|
1140
1205
|
const keyAttemptable = capability ? shouldAttempt(capability, normalizedKey) : false;
|
|
1141
1206
|
const queryEnabled = enabled && trimmedLive !== "" && capability != null && method != null && normalizedKey !== "" && keyAttemptable;
|
|
1142
1207
|
const query = (0, _tanstack_react_query.useQuery)({
|
|
1143
|
-
queryKey: buildResolutionKey(namespace, networkId, normalizedKey),
|
|
1208
|
+
queryKey: buildResolutionKey(namespace, networkId, normalizedKey, runtimeInstanceId),
|
|
1144
1209
|
queryFn: async () => {
|
|
1145
1210
|
if (!method) throw new ResolutionQueryError({
|
|
1146
1211
|
code: "ADAPTER_ERROR",
|
|
@@ -1267,40 +1332,13 @@ function toNameResult(engine) {
|
|
|
1267
1332
|
}
|
|
1268
1333
|
|
|
1269
1334
|
//#endregion
|
|
1270
|
-
//#region src/hooks/nameResolution/
|
|
1271
|
-
/**
|
|
1272
|
-
* Reverse-resolve an address to a name. Soft-reads the active runtime from
|
|
1273
|
-
* `WalletStateContext` (never throws when no provider is mounted — degrades to
|
|
1274
|
-
* idle / UNSUPPORTED_NETWORK) and calls `runtime.nameResolution?.resolveAddress`.
|
|
1275
|
-
* Caches per (network, address) via the owned QueryClient. Not debounced by
|
|
1276
|
-
* default — addresses are pasted, not typed char-by-char.
|
|
1277
|
-
*
|
|
1278
|
-
* Applies no client-side address-shape check (INV-32): resolution is attempted on
|
|
1279
|
-
* any non-empty input and malformed addresses are rejected via the adapter's typed
|
|
1280
|
-
* error union. Address-shape validation is SF-3's concern.
|
|
1281
|
-
*
|
|
1282
|
-
* @param address - The address to reverse-resolve. `null` / empty yields
|
|
1283
|
-
* `status: 'idle'`.
|
|
1284
|
-
* @param options - `debounceMs` / `enabled` overrides.
|
|
1285
|
-
* @returns The current {@link UseResolveAddressResult}.
|
|
1286
|
-
*/
|
|
1287
|
-
function useResolveAddress(address, options) {
|
|
1288
|
-
const { config } = useNameResolutionContext();
|
|
1289
|
-
return toAddressResult(useResolutionEngine({
|
|
1290
|
-
input: address,
|
|
1291
|
-
namespace: "addr",
|
|
1292
|
-
debounceMs: options?.debounceMs ?? config.reverseDebounceMs,
|
|
1293
|
-
enabled: options?.enabled ?? true,
|
|
1294
|
-
shouldAttempt: () => true,
|
|
1295
|
-
getMethod: (cap) => cap.resolveAddress
|
|
1296
|
-
}));
|
|
1297
|
-
}
|
|
1335
|
+
//#region src/hooks/nameResolution/mapAddressEngineResult.ts
|
|
1298
1336
|
/**
|
|
1299
1337
|
* Remap the engine's generic `input` to `address` (INV-24). A `debouncing` arm —
|
|
1300
1338
|
* only reachable when a caller passes a non-zero reverse `debounceMs` — collapses
|
|
1301
1339
|
* to `loading` so {@link UseResolveAddressResult} keeps no `debouncing` variant.
|
|
1302
1340
|
*/
|
|
1303
|
-
function
|
|
1341
|
+
function mapAddressEngineResult(engine) {
|
|
1304
1342
|
switch (engine.status) {
|
|
1305
1343
|
case "idle": return { status: "idle" };
|
|
1306
1344
|
case "debouncing":
|
|
@@ -1322,6 +1360,71 @@ function toAddressResult(engine) {
|
|
|
1322
1360
|
}
|
|
1323
1361
|
}
|
|
1324
1362
|
|
|
1363
|
+
//#endregion
|
|
1364
|
+
//#region src/hooks/nameResolution/useNetworkRuntimeSource.ts
|
|
1365
|
+
/**
|
|
1366
|
+
* Soft-reads {@link RuntimeContext} (never throws) and requests the registry
|
|
1367
|
+
* runtime for `network`. Call during render so loading state updates propagate.
|
|
1368
|
+
*
|
|
1369
|
+
* Does not mutate {@link WalletStateProvider}'s active network — wallet-global
|
|
1370
|
+
* runtime is never consulted when a scoped network is supplied (INV-154).
|
|
1371
|
+
*/
|
|
1372
|
+
function useNetworkRuntimeSource(network) {
|
|
1373
|
+
const runtimeContext = (0, react.useContext)(RuntimeContext);
|
|
1374
|
+
if (!network) return {
|
|
1375
|
+
runtime: null,
|
|
1376
|
+
networkId: "",
|
|
1377
|
+
isRuntimeLoading: false
|
|
1378
|
+
};
|
|
1379
|
+
if (!runtimeContext) return {
|
|
1380
|
+
runtime: null,
|
|
1381
|
+
networkId: network.id,
|
|
1382
|
+
isRuntimeLoading: false
|
|
1383
|
+
};
|
|
1384
|
+
const { runtime, isLoading } = runtimeContext.getRuntimeForNetwork(network);
|
|
1385
|
+
return {
|
|
1386
|
+
runtime,
|
|
1387
|
+
networkId: network.id,
|
|
1388
|
+
isRuntimeLoading: isLoading
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
//#endregion
|
|
1393
|
+
//#region src/hooks/nameResolution/useResolveAddress.ts
|
|
1394
|
+
/**
|
|
1395
|
+
* Reverse-resolve an address to a name. Soft-reads the active runtime from
|
|
1396
|
+
* `WalletStateContext` (never throws when no provider is mounted — degrades to
|
|
1397
|
+
* idle / UNSUPPORTED_NETWORK) and calls `runtime.nameResolution?.resolveAddress`.
|
|
1398
|
+
* Pass `options.network` to scope resolution to a specific network without
|
|
1399
|
+
* changing the wallet's active network. Caches per (network, address) via the
|
|
1400
|
+
* owned QueryClient. Not debounced by default — addresses are pasted, not
|
|
1401
|
+
* typed char-by-char.
|
|
1402
|
+
*
|
|
1403
|
+
* Applies no client-side address-shape check (INV-32): resolution is attempted on
|
|
1404
|
+
* any non-empty input and malformed addresses are rejected via the adapter's typed
|
|
1405
|
+
* error union. Address-shape validation is SF-3's concern.
|
|
1406
|
+
*
|
|
1407
|
+
* @param address - The address to reverse-resolve. `null` / empty yields
|
|
1408
|
+
* `status: 'idle'`.
|
|
1409
|
+
* @param options - `debounceMs` / `enabled` / `network` overrides.
|
|
1410
|
+
* @returns The current {@link UseResolveAddressResult}.
|
|
1411
|
+
*/
|
|
1412
|
+
function useResolveAddress(address, options) {
|
|
1413
|
+
const { config } = useNameResolutionContext();
|
|
1414
|
+
const debounceMs = options?.debounceMs ?? config.reverseDebounceMs;
|
|
1415
|
+
const enabled = options?.enabled ?? true;
|
|
1416
|
+
const networkSource = useNetworkRuntimeSource(options?.network ?? null);
|
|
1417
|
+
return mapAddressEngineResult(useResolutionEngine({
|
|
1418
|
+
input: address,
|
|
1419
|
+
namespace: "addr",
|
|
1420
|
+
debounceMs,
|
|
1421
|
+
enabled,
|
|
1422
|
+
shouldAttempt: () => true,
|
|
1423
|
+
getMethod: (cap) => cap.resolveAddress,
|
|
1424
|
+
runtimeSource: options?.network != null ? networkSource : void 0
|
|
1425
|
+
}));
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1325
1428
|
//#endregion
|
|
1326
1429
|
//#region src/hooks/nameResolution/NameResolutionProvider.tsx
|
|
1327
1430
|
/**
|
|
@@ -1347,6 +1450,54 @@ function NameResolutionProvider({ children, config, queryClient }) {
|
|
|
1347
1450
|
});
|
|
1348
1451
|
}
|
|
1349
1452
|
|
|
1453
|
+
//#endregion
|
|
1454
|
+
//#region src/hooks/nameResolution/createNameResolver.ts
|
|
1455
|
+
const EMPTY_RESOLVER$1 = {};
|
|
1456
|
+
/**
|
|
1457
|
+
* Projects a {@link NameResolutionCapability} into the SF-3 {@link NameResolver}
|
|
1458
|
+
* seam with SF-2 cache-key parity (INV-119).
|
|
1459
|
+
*/
|
|
1460
|
+
function createNameResolverFromCapability(capability, networkId, runtimeInstanceId, queryClient, config) {
|
|
1461
|
+
if (!capability) return EMPTY_RESOLVER$1;
|
|
1462
|
+
const resolveNameMethod = capability.resolveName;
|
|
1463
|
+
return {
|
|
1464
|
+
isValidName: (name) => capability.isValidName(name),
|
|
1465
|
+
resolveName: resolveNameMethod ? async (name) => {
|
|
1466
|
+
const normalized = name.trim().toLowerCase();
|
|
1467
|
+
try {
|
|
1468
|
+
return {
|
|
1469
|
+
ok: true,
|
|
1470
|
+
value: await queryClient.fetchQuery({
|
|
1471
|
+
queryKey: buildResolutionKey("name", networkId, normalized, runtimeInstanceId),
|
|
1472
|
+
queryFn: async () => {
|
|
1473
|
+
let result;
|
|
1474
|
+
try {
|
|
1475
|
+
result = await resolveNameMethod(normalized);
|
|
1476
|
+
} catch (cause) {
|
|
1477
|
+
throw new ResolutionQueryError({
|
|
1478
|
+
code: "ADAPTER_ERROR",
|
|
1479
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
1480
|
+
cause
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
if (!result.ok) throw new ResolutionQueryError(result.error);
|
|
1484
|
+
return result.value;
|
|
1485
|
+
},
|
|
1486
|
+
staleTime: config.staleTimeMs,
|
|
1487
|
+
gcTime: config.gcTimeMs,
|
|
1488
|
+
retry: (failureCount, error) => (error instanceof ResolutionQueryError ? isTransientError(error.resolutionError) : true) && failureCount < config.transientRetryCount
|
|
1489
|
+
})
|
|
1490
|
+
};
|
|
1491
|
+
} catch (error) {
|
|
1492
|
+
return {
|
|
1493
|
+
ok: false,
|
|
1494
|
+
error: toNameResolutionError(error)
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
} : void 0
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1350
1501
|
//#endregion
|
|
1351
1502
|
//#region src/hooks/nameResolution/useRuntimeNameResolver.ts
|
|
1352
1503
|
/**
|
|
@@ -1356,7 +1507,7 @@ function NameResolutionProvider({ children, config, queryClient }) {
|
|
|
1356
1507
|
*/
|
|
1357
1508
|
const EMPTY_RESOLVER = {};
|
|
1358
1509
|
/**
|
|
1359
|
-
* Project
|
|
1510
|
+
* Project a runtime's `NameResolutionCapability` into the injected
|
|
1360
1511
|
* {@link NameResolver} seam consumed by `@openzeppelin/ui-components` (SF-3, D3).
|
|
1361
1512
|
* Mounted ambiently by the renderer:
|
|
1362
1513
|
*
|
|
@@ -1364,6 +1515,10 @@ const EMPTY_RESOLVER = {};
|
|
|
1364
1515
|
* <NameResolverProvider {...useRuntimeNameResolver()}>{form}</NameResolverProvider>
|
|
1365
1516
|
* ```
|
|
1366
1517
|
*
|
|
1518
|
+
* Pass `scopedNetwork` to resolve against a specific network via
|
|
1519
|
+
* {@link RuntimeProvider}'s registry without changing {@link WalletStateProvider}'s
|
|
1520
|
+
* active network (e.g. address-book Add Alias dropdown).
|
|
1521
|
+
*
|
|
1367
1522
|
* Each imperative call is backed by SF-2's **owned** resolution `QueryClient`
|
|
1368
1523
|
* via `fetchQuery`, reusing SF-2's exact query-key convention
|
|
1369
1524
|
* (`buildResolutionKey('name', networkId, normalizedName)`) — so a name
|
|
@@ -1372,9 +1527,10 @@ const EMPTY_RESOLVER = {};
|
|
|
1372
1527
|
* out-of-order safety, never a parallel cache (INV-119).
|
|
1373
1528
|
*
|
|
1374
1529
|
* Degradation, in order (all method-omission, never a throw):
|
|
1375
|
-
* - No `WalletStateProvider` mounted
|
|
1376
|
-
*
|
|
1377
|
-
* renderer mount stays safe
|
|
1530
|
+
* - No `WalletStateProvider` mounted (wallet path) or no `RuntimeProvider`
|
|
1531
|
+
* (network path) → empty resolver. The context is read directly (not via
|
|
1532
|
+
* `useWalletState()`, which throws) so the ambient renderer mount stays safe
|
|
1533
|
+
* for wallet-less usage.
|
|
1378
1534
|
* - No active runtime, or runtime without the capability → empty resolver.
|
|
1379
1535
|
* - Capability without `resolveName` → `isValidName` only; forward unsupported.
|
|
1380
1536
|
*
|
|
@@ -1384,55 +1540,111 @@ const EMPTY_RESOLVER = {};
|
|
|
1384
1540
|
*
|
|
1385
1541
|
* @returns A referentially stable {@link NameResolver} for the active runtime.
|
|
1386
1542
|
*/
|
|
1387
|
-
function useRuntimeNameResolver() {
|
|
1543
|
+
function useRuntimeNameResolver(scopedNetwork) {
|
|
1388
1544
|
const walletState = (0, react.useContext)(WalletStateContext);
|
|
1389
1545
|
const { queryClient, config } = useNameResolutionContext();
|
|
1390
|
-
const
|
|
1391
|
-
const
|
|
1546
|
+
const networkSource = useNetworkRuntimeSource(scopedNetwork ?? null);
|
|
1547
|
+
const useNetworkScoped = scopedNetwork != null;
|
|
1548
|
+
const activeRuntime = useNetworkScoped ? networkSource.runtime : walletState?.activeRuntime ?? null;
|
|
1549
|
+
const capability = activeRuntime?.nameResolution;
|
|
1550
|
+
const networkId = useNetworkScoped ? networkSource.networkId : walletState?.activeNetworkId ?? "";
|
|
1551
|
+
const runtimeInstanceId = getRuntimeInstanceId(activeRuntime);
|
|
1392
1552
|
return (0, react.useMemo)(() => {
|
|
1393
1553
|
if (!capability) return EMPTY_RESOLVER;
|
|
1394
|
-
|
|
1395
|
-
return {
|
|
1396
|
-
isValidName: (name) => capability.isValidName(name),
|
|
1397
|
-
resolveName: resolveNameMethod ? async (name) => {
|
|
1398
|
-
const normalized = name.trim().toLowerCase();
|
|
1399
|
-
try {
|
|
1400
|
-
return {
|
|
1401
|
-
ok: true,
|
|
1402
|
-
value: await queryClient.fetchQuery({
|
|
1403
|
-
queryKey: buildResolutionKey("name", networkId, normalized),
|
|
1404
|
-
queryFn: async () => {
|
|
1405
|
-
let result;
|
|
1406
|
-
try {
|
|
1407
|
-
result = await resolveNameMethod(normalized);
|
|
1408
|
-
} catch (cause) {
|
|
1409
|
-
throw new ResolutionQueryError({
|
|
1410
|
-
code: "ADAPTER_ERROR",
|
|
1411
|
-
message: cause instanceof Error ? cause.message : String(cause),
|
|
1412
|
-
cause
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
if (!result.ok) throw new ResolutionQueryError(result.error);
|
|
1416
|
-
return result.value;
|
|
1417
|
-
},
|
|
1418
|
-
staleTime: config.staleTimeMs,
|
|
1419
|
-
gcTime: config.gcTimeMs,
|
|
1420
|
-
retry: (failureCount, error) => (error instanceof ResolutionQueryError ? isTransientError(error.resolutionError) : true) && failureCount < config.transientRetryCount
|
|
1421
|
-
})
|
|
1422
|
-
};
|
|
1423
|
-
} catch (error) {
|
|
1424
|
-
return {
|
|
1425
|
-
ok: false,
|
|
1426
|
-
error: toNameResolutionError(error)
|
|
1427
|
-
};
|
|
1428
|
-
}
|
|
1429
|
-
} : void 0
|
|
1430
|
-
};
|
|
1554
|
+
return createNameResolverFromCapability(capability, networkId, runtimeInstanceId, queryClient, config);
|
|
1431
1555
|
}, [
|
|
1432
1556
|
capability,
|
|
1557
|
+
networkId,
|
|
1558
|
+
runtimeInstanceId,
|
|
1433
1559
|
queryClient,
|
|
1434
1560
|
config,
|
|
1435
|
-
|
|
1561
|
+
useNetworkScoped ? networkSource.isRuntimeLoading : walletState?.isRuntimeLoading ?? false
|
|
1562
|
+
]);
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
//#endregion
|
|
1566
|
+
//#region src/hooks/nameResolution/useNetworkNameResolver.ts
|
|
1567
|
+
/**
|
|
1568
|
+
* @deprecated Pass the network to {@link useRuntimeNameResolver} instead.
|
|
1569
|
+
*/
|
|
1570
|
+
function useNetworkNameResolver(network) {
|
|
1571
|
+
return useRuntimeNameResolver(network ?? void 0);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
//#endregion
|
|
1575
|
+
//#region src/hooks/nameResolution/useNetworkResolveAddress.ts
|
|
1576
|
+
/**
|
|
1577
|
+
* @deprecated Pass `network` in {@link UseResolveAddressOptions} to {@link useResolveAddress}.
|
|
1578
|
+
*/
|
|
1579
|
+
function useNetworkResolveAddress(address, network, options) {
|
|
1580
|
+
return useResolveAddress(address, network != null ? {
|
|
1581
|
+
...options,
|
|
1582
|
+
network
|
|
1583
|
+
} : options);
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
//#endregion
|
|
1587
|
+
//#region src/hooks/runtime/runtimeCreationConfig.ts
|
|
1588
|
+
/** Safe default: miss-fallback OFF; no uiKit override. INV-204 */
|
|
1589
|
+
const DEFAULT_RUNTIME_CREATION_CONFIG = {};
|
|
1590
|
+
/**
|
|
1591
|
+
* Normalizes the opt-in flag to the adapter's strict-enable contract.
|
|
1592
|
+
* UIKit uses this at the threading boundary so `false` and `undefined` never
|
|
1593
|
+
* emit `enableMainnetL1MissFallback: false` into adapter options (absent = OFF).
|
|
1594
|
+
*/
|
|
1595
|
+
function isMainnetL1MissFallbackEnabled(options) {
|
|
1596
|
+
return options?.enableMainnetL1MissFallback === true;
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Builds the `createRuntime` options bag for adapter threading.
|
|
1600
|
+
* When OFF, `nameResolution` is omitted (INV-207). When ON, spreads only
|
|
1601
|
+
* `{ enableMainnetL1MissFallback: true }` (INV-208).
|
|
1602
|
+
*/
|
|
1603
|
+
function buildCreateRuntimeOptions(options) {
|
|
1604
|
+
return {
|
|
1605
|
+
...options?.uiKit !== void 0 ? { uiKit: options.uiKit } : {},
|
|
1606
|
+
...isMainnetL1MissFallbackEnabled(options?.nameResolution) ? { nameResolution: { enableMainnetL1MissFallback: true } } : {}
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
//#endregion
|
|
1611
|
+
//#region src/hooks/runtime/createResolveRuntime.ts
|
|
1612
|
+
/**
|
|
1613
|
+
* Build a `resolveRuntime` callback for {@link RuntimeProvider} that forwards
|
|
1614
|
+
* `CreateRuntimeOptions` to `ecosystemDefinition.createRuntime`.
|
|
1615
|
+
*
|
|
1616
|
+
* Does not cache — {@link RuntimeProvider} owns the per-network singleton registry.
|
|
1617
|
+
*/
|
|
1618
|
+
function createResolveRuntime(ecosystemDefinition, params) {
|
|
1619
|
+
const { profile, options } = params;
|
|
1620
|
+
const mergedOptions = buildCreateRuntimeOptions(options);
|
|
1621
|
+
return (networkConfig) => Promise.resolve(ecosystemDefinition.createRuntime(profile, networkConfig, mergedOptions));
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
//#endregion
|
|
1625
|
+
//#region src/hooks/runtime/useResolveRuntime.ts
|
|
1626
|
+
/**
|
|
1627
|
+
* Memoized {@link createResolveRuntime} for React apps. Recompute when
|
|
1628
|
+
* `ecosystemDefinition`, `profile`, or opt-in posture change (INV-217, INV-222).
|
|
1629
|
+
*
|
|
1630
|
+
* Changing the returned function identity MUST trigger runtime registry flush
|
|
1631
|
+
* in {@link RuntimeProvider} (INV-218).
|
|
1632
|
+
*/
|
|
1633
|
+
function useResolveRuntime(ecosystemDefinition, params) {
|
|
1634
|
+
const { profile, options } = params;
|
|
1635
|
+
const uiKit = options?.uiKit;
|
|
1636
|
+
const enableMainnetL1MissFallback = options?.nameResolution?.enableMainnetL1MissFallback;
|
|
1637
|
+
return (0, react.useMemo)(() => createResolveRuntime(ecosystemDefinition, {
|
|
1638
|
+
profile,
|
|
1639
|
+
options: {
|
|
1640
|
+
...uiKit !== void 0 ? { uiKit } : {},
|
|
1641
|
+
...enableMainnetL1MissFallback === true ? { nameResolution: { enableMainnetL1MissFallback: true } } : {}
|
|
1642
|
+
}
|
|
1643
|
+
}), [
|
|
1644
|
+
ecosystemDefinition,
|
|
1645
|
+
profile,
|
|
1646
|
+
uiKit,
|
|
1647
|
+
enableMainnetL1MissFallback
|
|
1436
1648
|
]);
|
|
1437
1649
|
}
|
|
1438
1650
|
|
|
@@ -1646,6 +1858,7 @@ const NetworkSwitchManager = ({ wallet, networkCatalog, targetNetworkId, onNetwo
|
|
|
1646
1858
|
exports.AnalyticsContext = AnalyticsContext;
|
|
1647
1859
|
exports.AnalyticsProvider = AnalyticsProvider;
|
|
1648
1860
|
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
1861
|
+
exports.DEFAULT_RUNTIME_CREATION_CONFIG = DEFAULT_RUNTIME_CREATION_CONFIG;
|
|
1649
1862
|
exports.NameResolutionContext = NameResolutionContext;
|
|
1650
1863
|
exports.NameResolutionProvider = NameResolutionProvider;
|
|
1651
1864
|
exports.NetworkSwitchManager = NetworkSwitchManager;
|
|
@@ -1656,6 +1869,8 @@ exports.WalletConnectionHeader = WalletConnectionHeader;
|
|
|
1656
1869
|
exports.WalletConnectionUI = WalletConnectionUI;
|
|
1657
1870
|
exports.WalletStateContext = WalletStateContext;
|
|
1658
1871
|
exports.WalletStateProvider = WalletStateProvider;
|
|
1872
|
+
exports.createResolveRuntime = createResolveRuntime;
|
|
1873
|
+
exports.isMainnetL1MissFallbackEnabled = isMainnetL1MissFallbackEnabled;
|
|
1659
1874
|
exports.useAnalytics = useAnalytics;
|
|
1660
1875
|
exports.useDerivedAccountStatus = useDerivedAccountStatus;
|
|
1661
1876
|
exports.useDerivedChainInfo = useDerivedChainInfo;
|
|
@@ -1663,8 +1878,11 @@ exports.useDerivedConnectStatus = useDerivedConnectStatus;
|
|
|
1663
1878
|
exports.useDerivedDisconnect = useDerivedDisconnect;
|
|
1664
1879
|
exports.useDerivedSwitchChainStatus = useDerivedSwitchChainStatus;
|
|
1665
1880
|
exports.useNameResolutionContext = useNameResolutionContext;
|
|
1881
|
+
exports.useNetworkNameResolver = useNetworkNameResolver;
|
|
1882
|
+
exports.useNetworkResolveAddress = useNetworkResolveAddress;
|
|
1666
1883
|
exports.useResolveAddress = useResolveAddress;
|
|
1667
1884
|
exports.useResolveName = useResolveName;
|
|
1885
|
+
exports.useResolveRuntime = useResolveRuntime;
|
|
1668
1886
|
exports.useRuntimeContext = useRuntimeContext;
|
|
1669
1887
|
exports.useRuntimeNameResolver = useRuntimeNameResolver;
|
|
1670
1888
|
exports.useWalletComponents = useWalletComponents;
|