@calimero-network/mero-react 2.3.0 → 2.5.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 CHANGED
@@ -1493,6 +1493,18 @@ function useJoinContext() {
1493
1493
  );
1494
1494
  return { joinContext, loading, error };
1495
1495
  }
1496
+ function useJoinSubgroupInheritance() {
1497
+ const { mero } = useMero();
1498
+ const { loading, error, run } = useAsyncMutation();
1499
+ const joinSubgroupInheritance = react.useCallback(
1500
+ async (groupId) => {
1501
+ if (!mero) return null;
1502
+ return run(() => mero.admin.joinSubgroupInheritance(groupId));
1503
+ },
1504
+ [mero, run]
1505
+ );
1506
+ return { joinSubgroupInheritance, loading, error };
1507
+ }
1496
1508
  function useContextGroup(contextId) {
1497
1509
  const { mero } = useMero();
1498
1510
  const [groupId, setGroupId] = react.useState(null);
@@ -2282,6 +2294,256 @@ function useDetachContextFromGroup() {
2282
2294
  );
2283
2295
  return { detachContextFromGroup, loading, error };
2284
2296
  }
2297
+ function useMigrationStatus(namespaceId, options) {
2298
+ const { mero } = useMero();
2299
+ const [status, setStatus] = react.useState(null);
2300
+ const [loading, setLoading] = react.useState(false);
2301
+ const [error, setError] = react.useState(null);
2302
+ const mountedRef = useMountedRef();
2303
+ const reqRef = react.useRef(0);
2304
+ const refetch = react.useCallback(async () => {
2305
+ if (!mero || !namespaceId) {
2306
+ if (mountedRef.current) {
2307
+ setStatus(null);
2308
+ setError(null);
2309
+ setLoading(false);
2310
+ }
2311
+ return;
2312
+ }
2313
+ const seq = ++reqRef.current;
2314
+ if (mountedRef.current) {
2315
+ setLoading(true);
2316
+ setError(null);
2317
+ }
2318
+ try {
2319
+ const result = await mero.admin.getMigrationStatus(namespaceId);
2320
+ if (mountedRef.current && seq === reqRef.current) {
2321
+ setStatus(result);
2322
+ }
2323
+ } catch (err) {
2324
+ const errorValue = toError(err);
2325
+ if (mountedRef.current && seq === reqRef.current) {
2326
+ setError(errorValue);
2327
+ }
2328
+ } finally {
2329
+ if (mountedRef.current && seq === reqRef.current) {
2330
+ setLoading(false);
2331
+ }
2332
+ }
2333
+ }, [namespaceId, mero, mountedRef]);
2334
+ react.useEffect(() => {
2335
+ setStatus(null);
2336
+ setError(null);
2337
+ }, [namespaceId]);
2338
+ react.useEffect(() => {
2339
+ void refetch();
2340
+ }, [refetch]);
2341
+ const pollIntervalMs = options?.pollIntervalMs;
2342
+ react.useEffect(() => {
2343
+ if (!pollIntervalMs || !mero || !namespaceId) return;
2344
+ const handle = setInterval(() => void refetch(), pollIntervalMs);
2345
+ return () => clearInterval(handle);
2346
+ }, [pollIntervalMs, mero, namespaceId, refetch]);
2347
+ const rollup = status?.rollup ?? null;
2348
+ const members = status?.members ?? [];
2349
+ return {
2350
+ status,
2351
+ rollup,
2352
+ members,
2353
+ allMigrated: rollup?.allMigrated ?? false,
2354
+ membersPendingSignature: rollup?.membersPendingSignature ?? 0,
2355
+ loading,
2356
+ error,
2357
+ refetch
2358
+ };
2359
+ }
2360
+ function useAppVersion(contextId, expected) {
2361
+ const { mero } = useMero();
2362
+ const [appVersion, setAppVersion] = react.useState(void 0);
2363
+ const [loading, setLoading] = react.useState(false);
2364
+ const [error, setError] = react.useState(null);
2365
+ const mountedRef = useMountedRef();
2366
+ const reqRef = react.useRef(0);
2367
+ const refetch = react.useCallback(async () => {
2368
+ if (!mero || !contextId) {
2369
+ if (mountedRef.current) {
2370
+ setAppVersion(void 0);
2371
+ setError(null);
2372
+ setLoading(false);
2373
+ }
2374
+ return;
2375
+ }
2376
+ const seq = ++reqRef.current;
2377
+ if (mountedRef.current) {
2378
+ setLoading(true);
2379
+ setError(null);
2380
+ }
2381
+ try {
2382
+ const context = await mero.admin.getContext(contextId);
2383
+ if (mountedRef.current && seq === reqRef.current) {
2384
+ setAppVersion(context.applicationVersion);
2385
+ }
2386
+ } catch (err) {
2387
+ const errorValue = toError(err);
2388
+ if (mountedRef.current && seq === reqRef.current) {
2389
+ setError(errorValue);
2390
+ }
2391
+ } finally {
2392
+ if (mountedRef.current && seq === reqRef.current) {
2393
+ setLoading(false);
2394
+ }
2395
+ }
2396
+ }, [contextId, mero, mountedRef]);
2397
+ react.useEffect(() => {
2398
+ setAppVersion(void 0);
2399
+ setError(null);
2400
+ }, [contextId]);
2401
+ react.useEffect(() => {
2402
+ void refetch();
2403
+ }, [refetch]);
2404
+ react.useEffect(() => {
2405
+ if (!mero?.events || !contextId) return;
2406
+ const off = mero.events.onAppVersionChanged((event) => {
2407
+ if (event.contextId !== contextId) return;
2408
+ if (mountedRef.current && event.toVersion) {
2409
+ reqRef.current += 1;
2410
+ setAppVersion(event.toVersion);
2411
+ }
2412
+ });
2413
+ return off;
2414
+ }, [mero, contextId, mountedRef]);
2415
+ const isStale = appVersion != null && expected != null && appVersion !== expected;
2416
+ return { appVersion, expected, isStale, loading, error, refetch };
2417
+ }
2418
+ function useMyAuthoredMigration(contextId) {
2419
+ const { mero } = useMero();
2420
+ const [summary, setSummary] = react.useState(null);
2421
+ const [pendingCount, setPendingCount] = react.useState(0);
2422
+ const mountedRef = useMountedRef();
2423
+ const { loading, error, run } = useAsyncMutation();
2424
+ const reqRef = react.useRef(0);
2425
+ const refresh = react.useCallback(async () => {
2426
+ if (!mero || !contextId) {
2427
+ if (mountedRef.current) setPendingCount(0);
2428
+ return;
2429
+ }
2430
+ const seq = ++reqRef.current;
2431
+ try {
2432
+ const count = await mero.rpc.countMyPending(contextId);
2433
+ if (mountedRef.current && seq === reqRef.current) setPendingCount(count);
2434
+ } catch {
2435
+ }
2436
+ }, [mero, contextId, mountedRef]);
2437
+ react.useEffect(() => {
2438
+ void refresh();
2439
+ }, [refresh]);
2440
+ const authorize = react.useCallback(async () => {
2441
+ if (!mero || !contextId) return null;
2442
+ const result = await run(() => mero.rpc.migrateMyEntries(contextId));
2443
+ if (result && mountedRef.current) {
2444
+ reqRef.current += 1;
2445
+ setSummary(result);
2446
+ setPendingCount(result.remaining);
2447
+ }
2448
+ return result;
2449
+ }, [mero, contextId, run, mountedRef]);
2450
+ return {
2451
+ summary,
2452
+ pendingCount,
2453
+ pending: pendingCount > 0,
2454
+ authorize,
2455
+ loading,
2456
+ error,
2457
+ refresh
2458
+ };
2459
+ }
2460
+ function MigrationPendingBanner({
2461
+ contextId,
2462
+ className,
2463
+ children,
2464
+ onMigrated
2465
+ }) {
2466
+ const { pending, pendingCount, authorize, loading } = useMyAuthoredMigration(contextId);
2467
+ if (!pending) return null;
2468
+ const handleClick = async () => {
2469
+ const result = await authorize();
2470
+ if (result && result.remaining === 0) {
2471
+ onMigrated?.();
2472
+ }
2473
+ };
2474
+ const message = children ?? `You have ${pendingCount} ${pendingCount === 1 ? "entry" : "entries"} to re-sign after a recent upgrade.`;
2475
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-testid": "migration-pending-banner", role: "status", children: [
2476
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: message }),
2477
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: handleClick, disabled: loading, children: loading ? "Migrating\u2026" : "Migrate my data" })
2478
+ ] });
2479
+ }
2480
+ function MigrationAdminPanel({ namespaceId, pollIntervalMs, className }) {
2481
+ const { status, rollup, members, membersPendingSignature, error } = useMigrationStatus(
2482
+ namespaceId,
2483
+ { pollIntervalMs }
2484
+ );
2485
+ if (error && !status) {
2486
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-testid": "migration-admin-panel", children: [
2487
+ "Failed to load migration status: ",
2488
+ error.message
2489
+ ] });
2490
+ }
2491
+ if (!status || !rollup) {
2492
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-testid": "migration-admin-panel", children: "Loading migration status\u2026" });
2493
+ }
2494
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-testid": "migration-admin-panel", children: [
2495
+ error && // A poll failed after data was already loaded — keep showing the last
2496
+ // good rollup but flag that it may be stale.
2497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": "migration-status-error", role: "alert", children: [
2498
+ "Could not refresh migration status: ",
2499
+ error.message
2500
+ ] }),
2501
+ /* @__PURE__ */ jsxRuntime.jsxs("dl", { children: [
2502
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2503
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Target version" }),
2504
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: status.targetVersion })
2505
+ ] }),
2506
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2507
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Migrated" }),
2508
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.migrated })
2509
+ ] }),
2510
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2511
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "In progress" }),
2512
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.inProgress })
2513
+ ] }),
2514
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2515
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Unknown" }),
2516
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.unknown })
2517
+ ] }),
2518
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2519
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Total" }),
2520
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.total })
2521
+ ] }),
2522
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2523
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "All migrated" }),
2524
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: rollup.allMigrated ? "yes" : "no" })
2525
+ ] }),
2526
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2527
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Members pending signature" }),
2528
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { "data-testid": "members-pending-signature", children: membersPendingSignature })
2529
+ ] })
2530
+ ] }),
2531
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
2532
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2533
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "Peer" }),
2534
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "State" }),
2535
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "Schema" }),
2536
+ /* @__PURE__ */ jsxRuntime.jsx("th", { children: "Pending" })
2537
+ ] }) }),
2538
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: members.map((m) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { "data-testid": "migration-member-row", children: [
2539
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: m.peer }),
2540
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: m.state }),
2541
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: m.report?.schemaVersion ?? "\u2014" }),
2542
+ /* @__PURE__ */ jsxRuntime.jsx("td", { children: m.report?.authoredRemaining ?? "\u2014" })
2543
+ ] }, m.peer)) })
2544
+ ] })
2545
+ ] });
2546
+ }
2285
2547
 
2286
2548
  Object.defineProperty(exports, "CAPABILITIES", {
2287
2549
  enumerable: true,
@@ -2307,6 +2569,8 @@ exports.LoginModal = LoginModal;
2307
2569
  exports.MERO_CSS_VARS = MERO_CSS_VARS;
2308
2570
  exports.MeroContext = MeroContext;
2309
2571
  exports.MeroProvider = MeroProvider;
2572
+ exports.MigrationAdminPanel = MigrationAdminPanel;
2573
+ exports.MigrationPendingBanner = MigrationPendingBanner;
2310
2574
  exports.clearAllStorage = clearAllStorage;
2311
2575
  exports.clearApplicationId = clearApplicationId;
2312
2576
  exports.clearContextId = clearContextId;
@@ -2326,6 +2590,7 @@ exports.setContextIdentity = setContextIdentity;
2326
2590
  exports.setNodeUrl = setNodeUrl;
2327
2591
  exports.themeToCssVars = themeToCssVars;
2328
2592
  exports.useAddGroupMembers = useAddGroupMembers;
2593
+ exports.useAppVersion = useAppVersion;
2329
2594
  exports.useApplicationContexts = useApplicationContexts;
2330
2595
  exports.useContextDiscovery = useContextDiscovery;
2331
2596
  exports.useContextGroup = useContextGroup;
@@ -2350,8 +2615,11 @@ exports.useGroupUpgradeStatus = useGroupUpgradeStatus;
2350
2615
  exports.useJoinContext = useJoinContext;
2351
2616
  exports.useJoinGroup = useJoinGroup;
2352
2617
  exports.useJoinNamespace = useJoinNamespace;
2618
+ exports.useJoinSubgroupInheritance = useJoinSubgroupInheritance;
2353
2619
  exports.useMemberMetadata = useMemberMetadata;
2354
2620
  exports.useMero = useMero;
2621
+ exports.useMigrationStatus = useMigrationStatus;
2622
+ exports.useMyAuthoredMigration = useMyAuthoredMigration;
2355
2623
  exports.useNamespace = useNamespace;
2356
2624
  exports.useNamespaceGroups = useNamespaceGroups;
2357
2625
  exports.useNamespaceIdentity = useNamespaceIdentity;