@calimero-network/mero-react 5.1.0 → 6.0.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/index.d.cts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import React__default, { CSSProperties, ReactNode } from 'react';
4
4
  import * as _calimero_network_mero_js from '@calimero-network/mero-js';
5
- import { MeroJs, TokenStore, SetMetadataRequest, SseEventData, GroupMembershipEventData, GroupMigrationEventData, Codec, AddGroupMembersRequest, CreateContextRequest, CreateGroupInNamespaceRequest, CreateNamespaceRequest, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, DeleteGroupRequest, DeleteNamespaceRequest, DetachContextFromGroupRequest, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, RetryGroupUpgradeRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, SyncGroupRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, TokenData } from '@calimero-network/mero-js';
5
+ import { MeroJs, TokenStore, SetMetadataRequest, SseEventData, GroupMembershipEventData, GroupMigrationEventData, Codec, AddGroupMembersRequest, CreateContextRequest, CreateGroupInNamespaceRequest, CreateNamespaceRequest, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, DeleteGroupRequest, DeleteNamespaceRequest, DetachContextFromGroupRequest, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, NodeIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, RetryGroupUpgradeRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, SyncGroupRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, TokenData } from '@calimero-network/mero-js';
6
6
  export * from '@calimero-network/mero-js';
7
7
  export { CAPABILITIES, Codec, DEFAULT_LOCAL_NODE_PORTS, DiscoverLocalNodesOptions, EphemeralClient, EphemeralEntry, MetadataRecord, discoverLocalNodes, hasCap, localNodeUrl, nodeEndpoint, probeNodeHealth, withCap, withoutCap } from '@calimero-network/mero-js';
8
8
 
@@ -447,6 +447,11 @@ declare function useJoinGroup(): {
447
447
  loading: boolean;
448
448
  error: Error | null;
449
449
  };
450
+ /**
451
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
452
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
453
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
454
+ */
450
455
  declare function useGroupCapabilities(groupId?: string | null, memberId?: string | null): {
451
456
  capabilities: number | null;
452
457
  loading: boolean;
@@ -497,11 +502,22 @@ declare function useSyncGroup(): {
497
502
  loading: boolean;
498
503
  error: Error | null;
499
504
  };
505
+ /**
506
+ * Takes the invitee's signing KEY (bs58) - the one call on this resource that
507
+ * does, because someone being added may have no account here yet. Every other
508
+ * member call, including `useRemoveGroupMembers`, takes the ACCOUNT, so a value
509
+ * round-tripped from an add is the wrong one to remove with.
510
+ */
500
511
  declare function useAddGroupMembers(): {
501
512
  addGroupMembers: (groupId: string, request: AddGroupMembersRequest) => Promise<void | null>;
502
513
  loading: boolean;
503
514
  error: Error | null;
504
515
  };
516
+ /**
517
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
518
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
519
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
520
+ */
505
521
  declare function useRemoveGroupMembers(): {
506
522
  removeGroupMembers: (groupId: string, request: RemoveGroupMembersRequest) => Promise<void | null>;
507
523
  loading: boolean;
@@ -519,6 +535,24 @@ declare function useNamespace(namespaceId?: string | null): {
519
535
  error: Error | null;
520
536
  refetch: () => Promise<void>;
521
537
  };
538
+ /**
539
+ * Who this node is: `accountId` is what member-addressing takes and what
540
+ * `useGroupMembers` rows are keyed by — `publicKey` is the signing key and
541
+ * addresses nobody. Both are 32-byte strings, so a swap fails silently.
542
+ */
543
+ declare function useNodeIdentity(): {
544
+ identity: NodeIdentity | null;
545
+ loading: boolean;
546
+ error: Error | null;
547
+ refetch: () => Promise<void>;
548
+ };
549
+ /**
550
+ * @deprecated Use {@link useNodeIdentity}. Identity is per-node, not
551
+ * per-namespace, and this no longer gates on participation: it answers for a
552
+ * namespace this node never joined, so `identity != null` is not "am I a
553
+ * member?" — ask `useNamespaces` for that. Its `publicKey` is the signing key,
554
+ * NOT the account member-addressing wants.
555
+ */
522
556
  declare function useNamespaceIdentity(namespaceId?: string | null): {
523
557
  identity: NamespaceIdentity | null;
524
558
  loading: boolean;
@@ -562,6 +596,11 @@ declare function useNamespaceGroups(namespaceId?: string | null): {
562
596
  error: Error | null;
563
597
  refetch: () => Promise<void>;
564
598
  };
599
+ /**
600
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
601
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
602
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
603
+ */
565
604
  declare function useUpdateMemberRole(): {
566
605
  updateMemberRole: (groupId: string, identity: string, request: UpdateMemberRoleRequest) => Promise<void | null>;
567
606
  loading: boolean;
@@ -599,6 +638,11 @@ declare function useSetGroupMetadata(): {
599
638
  loading: boolean;
600
639
  error: Error | null;
601
640
  };
641
+ /**
642
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
643
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
644
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
645
+ */
602
646
  declare function useSetMemberMetadata(): {
603
647
  setMemberMetadata: (groupId: string, identity: string, request: SetMetadataInput) => Promise<void | null>;
604
648
  loading: boolean;
@@ -676,9 +720,31 @@ declare function useDetachContextFromGroup(): {
676
720
  error: Error | null;
677
721
  };
678
722
  /**
679
- * Migration-status rollup for a namespace (skew #3). Migration facts arrive via
680
- * heartbeat gossip (no SSE), so liveness is polling: pass `pollIntervalMs` to
681
- * re-fetch on an interval. Derived counters are null-safe before the first load.
723
+ * Subscribe to a namespace's `GroupMigration` events, invoking `onEvent` per
724
+ * frame and unsubscribing on unmount.
725
+ *
726
+ * A non-admin subscriber never sees `CascadeProgress`; core delivers that to
727
+ * namespace admins only, so a UI must not wait on it to decide progress.
728
+ */
729
+ /**
730
+ * Fallback poll cadence for `useMigrationStatus` when the SSE stream is
731
+ * unavailable (no token, a proxy that buffers, an older node) and the caller
732
+ * named no interval of its own. Chosen to match the heartbeat cadence that
733
+ * migration facts actually arrive on; an explicit `pollIntervalMs` overrides it.
734
+ */
735
+ declare const DEFAULT_MIGRATION_POLL_INTERVAL_MS = 5000;
736
+ declare function useMigrationEvents(namespaceId: string | null | undefined, onEvent: (event: GroupMigrationEventData) => void): boolean;
737
+ /**
738
+ * Migration-status rollup for a namespace (skew #3).
739
+ *
740
+ * Live: subscribes to the `GroupMigration` event family and re-reads on each
741
+ * frame. It re-READS rather than folding the event's counters in, because the
742
+ * rollup is recomputed from raw member rows and is the authoritative answer.
743
+ * `pollIntervalMs` stays as the fallback when SSE is unavailable, and when the
744
+ * caller names none it defaults to `DEFAULT_MIGRATION_POLL_INTERVAL_MS` for
745
+ * exactly as long as the stream is down - so the panel can never sit silently
746
+ * frozen with neither transport.
747
+ * Derived counters are null-safe before the first load.
682
748
  */
683
749
  declare function useMigrationStatus(namespaceId?: string | null, options?: {
684
750
  pollIntervalMs?: number;
@@ -687,6 +753,12 @@ declare function useMigrationStatus(namespaceId?: string | null, options?: {
687
753
  rollup: MigrationStatusRollup | null;
688
754
  members: MemberMigrationStatusEntry[];
689
755
  allMigrated: boolean;
756
+ /**
757
+ * When this node watched the fleet converge, or `null`. Durable, unlike
758
+ * `allMigrated`, which is recomputed from in-TTL heartbeats and lapses back
759
+ * to false when a member simply goes quiet.
760
+ */
761
+ fleetCompletedAt: number | null;
690
762
  membersPendingSignature: number;
691
763
  /** Members whose migrate aborted (migration-check failed or apply errored). */
692
764
  failed: number;
@@ -751,7 +823,6 @@ declare function useGroupAppVersion(groupId?: string): {
751
823
  applicationId: string | null;
752
824
  /** The installed blob differs from the one the group targets (see hook doc). */
753
825
  pendingApply: boolean;
754
- upgradePolicy: string | null;
755
826
  /** Only populated via the group-info path; `null` in the namespace path. */
756
827
  activeUpgrade: GroupUpgradeStatusResponseData;
757
828
  };
@@ -847,4 +918,4 @@ declare function clearContextIdentity(): void;
847
918
  */
848
919
  declare function clearAllStorage(): void;
849
920
 
850
- export { type AppContext, AppMode, type ApplicationContextRecord, CalimeroLogo, type CalimeroLogoProps, ConnectButton, type ConnectButtonProps, ConnectionType, type ContextDiscoveryOptions, type ContextDiscoveryState, type CustomConnectionConfig, type ExecutionResult, LoginModal, type LoginModalProps, MERO_CSS_VARS, MeroContext, type MeroContextValue, MeroProvider, type MeroProviderConfig, type MeroProviderProps, type MeroTheme, MigrationAdminPanel, type MigrationAdminPanelProps, MigrationPendingBanner, type MigrationPendingBannerProps, type ResolvedMeroTheme, type SetMetadataInput, type SubscriptionEventData, type SubscriptionInput, type UseEphemeralOptions, type UseEphemeralResult, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, clearTokenNodeUrl, cssVar, defaultMeroTheme, getApplicationId, getContextId, getContextIdentity, getNodeUrl, getTokenNodeUrl, localStorageTokenStorage, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, setTokenNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useEphemeral, useExecute, useGroupAppVersion, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useInstallFromRegistry, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateMemberRole, useUpgradeGroup };
921
+ export { type AppContext, AppMode, type ApplicationContextRecord, CalimeroLogo, type CalimeroLogoProps, ConnectButton, type ConnectButtonProps, ConnectionType, type ContextDiscoveryOptions, type ContextDiscoveryState, type CustomConnectionConfig, DEFAULT_MIGRATION_POLL_INTERVAL_MS, type ExecutionResult, LoginModal, type LoginModalProps, MERO_CSS_VARS, MeroContext, type MeroContextValue, MeroProvider, type MeroProviderConfig, type MeroProviderProps, type MeroTheme, MigrationAdminPanel, type MigrationAdminPanelProps, MigrationPendingBanner, type MigrationPendingBannerProps, type ResolvedMeroTheme, type SetMetadataInput, type SubscriptionEventData, type SubscriptionInput, type UseEphemeralOptions, type UseEphemeralResult, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, clearTokenNodeUrl, cssVar, defaultMeroTheme, getApplicationId, getContextId, getContextIdentity, getNodeUrl, getTokenNodeUrl, localStorageTokenStorage, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, setTokenNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useEphemeral, useExecute, useGroupAppVersion, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useInstallFromRegistry, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationEvents, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useNodeIdentity, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateMemberRole, useUpgradeGroup };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import React__default, { CSSProperties, ReactNode } from 'react';
4
4
  import * as _calimero_network_mero_js from '@calimero-network/mero-js';
5
- import { MeroJs, TokenStore, SetMetadataRequest, SseEventData, GroupMembershipEventData, GroupMigrationEventData, Codec, AddGroupMembersRequest, CreateContextRequest, CreateGroupInNamespaceRequest, CreateNamespaceRequest, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, DeleteGroupRequest, DeleteNamespaceRequest, DetachContextFromGroupRequest, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, RetryGroupUpgradeRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, SyncGroupRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, TokenData } from '@calimero-network/mero-js';
5
+ import { MeroJs, TokenStore, SetMetadataRequest, SseEventData, GroupMembershipEventData, GroupMigrationEventData, Codec, AddGroupMembersRequest, CreateContextRequest, CreateGroupInNamespaceRequest, CreateNamespaceRequest, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, DeleteGroupRequest, DeleteNamespaceRequest, DetachContextFromGroupRequest, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, NodeIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, RetryGroupUpgradeRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, SyncGroupRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, TokenData } from '@calimero-network/mero-js';
6
6
  export * from '@calimero-network/mero-js';
7
7
  export { CAPABILITIES, Codec, DEFAULT_LOCAL_NODE_PORTS, DiscoverLocalNodesOptions, EphemeralClient, EphemeralEntry, MetadataRecord, discoverLocalNodes, hasCap, localNodeUrl, nodeEndpoint, probeNodeHealth, withCap, withoutCap } from '@calimero-network/mero-js';
8
8
 
@@ -447,6 +447,11 @@ declare function useJoinGroup(): {
447
447
  loading: boolean;
448
448
  error: Error | null;
449
449
  };
450
+ /**
451
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
452
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
453
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
454
+ */
450
455
  declare function useGroupCapabilities(groupId?: string | null, memberId?: string | null): {
451
456
  capabilities: number | null;
452
457
  loading: boolean;
@@ -497,11 +502,22 @@ declare function useSyncGroup(): {
497
502
  loading: boolean;
498
503
  error: Error | null;
499
504
  };
505
+ /**
506
+ * Takes the invitee's signing KEY (bs58) - the one call on this resource that
507
+ * does, because someone being added may have no account here yet. Every other
508
+ * member call, including `useRemoveGroupMembers`, takes the ACCOUNT, so a value
509
+ * round-tripped from an add is the wrong one to remove with.
510
+ */
500
511
  declare function useAddGroupMembers(): {
501
512
  addGroupMembers: (groupId: string, request: AddGroupMembersRequest) => Promise<void | null>;
502
513
  loading: boolean;
503
514
  error: Error | null;
504
515
  };
516
+ /**
517
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
518
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
519
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
520
+ */
505
521
  declare function useRemoveGroupMembers(): {
506
522
  removeGroupMembers: (groupId: string, request: RemoveGroupMembersRequest) => Promise<void | null>;
507
523
  loading: boolean;
@@ -519,6 +535,24 @@ declare function useNamespace(namespaceId?: string | null): {
519
535
  error: Error | null;
520
536
  refetch: () => Promise<void>;
521
537
  };
538
+ /**
539
+ * Who this node is: `accountId` is what member-addressing takes and what
540
+ * `useGroupMembers` rows are keyed by — `publicKey` is the signing key and
541
+ * addresses nobody. Both are 32-byte strings, so a swap fails silently.
542
+ */
543
+ declare function useNodeIdentity(): {
544
+ identity: NodeIdentity | null;
545
+ loading: boolean;
546
+ error: Error | null;
547
+ refetch: () => Promise<void>;
548
+ };
549
+ /**
550
+ * @deprecated Use {@link useNodeIdentity}. Identity is per-node, not
551
+ * per-namespace, and this no longer gates on participation: it answers for a
552
+ * namespace this node never joined, so `identity != null` is not "am I a
553
+ * member?" — ask `useNamespaces` for that. Its `publicKey` is the signing key,
554
+ * NOT the account member-addressing wants.
555
+ */
522
556
  declare function useNamespaceIdentity(namespaceId?: string | null): {
523
557
  identity: NamespaceIdentity | null;
524
558
  loading: boolean;
@@ -562,6 +596,11 @@ declare function useNamespaceGroups(namespaceId?: string | null): {
562
596
  error: Error | null;
563
597
  refetch: () => Promise<void>;
564
598
  };
599
+ /**
600
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
601
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
602
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
603
+ */
565
604
  declare function useUpdateMemberRole(): {
566
605
  updateMemberRole: (groupId: string, identity: string, request: UpdateMemberRoleRequest) => Promise<void | null>;
567
606
  loading: boolean;
@@ -599,6 +638,11 @@ declare function useSetGroupMetadata(): {
599
638
  loading: boolean;
600
639
  error: Error | null;
601
640
  };
641
+ /**
642
+ * Takes the member's ACCOUNT (64 hex), as `useGroupMembers` rows are keyed by
643
+ * and `useNodeIdentity().identity?.accountId` returns - NOT a signing key.
644
+ * Both are 32-byte strings, so passing a key names nobody and raises nothing.
645
+ */
602
646
  declare function useSetMemberMetadata(): {
603
647
  setMemberMetadata: (groupId: string, identity: string, request: SetMetadataInput) => Promise<void | null>;
604
648
  loading: boolean;
@@ -676,9 +720,31 @@ declare function useDetachContextFromGroup(): {
676
720
  error: Error | null;
677
721
  };
678
722
  /**
679
- * Migration-status rollup for a namespace (skew #3). Migration facts arrive via
680
- * heartbeat gossip (no SSE), so liveness is polling: pass `pollIntervalMs` to
681
- * re-fetch on an interval. Derived counters are null-safe before the first load.
723
+ * Subscribe to a namespace's `GroupMigration` events, invoking `onEvent` per
724
+ * frame and unsubscribing on unmount.
725
+ *
726
+ * A non-admin subscriber never sees `CascadeProgress`; core delivers that to
727
+ * namespace admins only, so a UI must not wait on it to decide progress.
728
+ */
729
+ /**
730
+ * Fallback poll cadence for `useMigrationStatus` when the SSE stream is
731
+ * unavailable (no token, a proxy that buffers, an older node) and the caller
732
+ * named no interval of its own. Chosen to match the heartbeat cadence that
733
+ * migration facts actually arrive on; an explicit `pollIntervalMs` overrides it.
734
+ */
735
+ declare const DEFAULT_MIGRATION_POLL_INTERVAL_MS = 5000;
736
+ declare function useMigrationEvents(namespaceId: string | null | undefined, onEvent: (event: GroupMigrationEventData) => void): boolean;
737
+ /**
738
+ * Migration-status rollup for a namespace (skew #3).
739
+ *
740
+ * Live: subscribes to the `GroupMigration` event family and re-reads on each
741
+ * frame. It re-READS rather than folding the event's counters in, because the
742
+ * rollup is recomputed from raw member rows and is the authoritative answer.
743
+ * `pollIntervalMs` stays as the fallback when SSE is unavailable, and when the
744
+ * caller names none it defaults to `DEFAULT_MIGRATION_POLL_INTERVAL_MS` for
745
+ * exactly as long as the stream is down - so the panel can never sit silently
746
+ * frozen with neither transport.
747
+ * Derived counters are null-safe before the first load.
682
748
  */
683
749
  declare function useMigrationStatus(namespaceId?: string | null, options?: {
684
750
  pollIntervalMs?: number;
@@ -687,6 +753,12 @@ declare function useMigrationStatus(namespaceId?: string | null, options?: {
687
753
  rollup: MigrationStatusRollup | null;
688
754
  members: MemberMigrationStatusEntry[];
689
755
  allMigrated: boolean;
756
+ /**
757
+ * When this node watched the fleet converge, or `null`. Durable, unlike
758
+ * `allMigrated`, which is recomputed from in-TTL heartbeats and lapses back
759
+ * to false when a member simply goes quiet.
760
+ */
761
+ fleetCompletedAt: number | null;
690
762
  membersPendingSignature: number;
691
763
  /** Members whose migrate aborted (migration-check failed or apply errored). */
692
764
  failed: number;
@@ -751,7 +823,6 @@ declare function useGroupAppVersion(groupId?: string): {
751
823
  applicationId: string | null;
752
824
  /** The installed blob differs from the one the group targets (see hook doc). */
753
825
  pendingApply: boolean;
754
- upgradePolicy: string | null;
755
826
  /** Only populated via the group-info path; `null` in the namespace path. */
756
827
  activeUpgrade: GroupUpgradeStatusResponseData;
757
828
  };
@@ -847,4 +918,4 @@ declare function clearContextIdentity(): void;
847
918
  */
848
919
  declare function clearAllStorage(): void;
849
920
 
850
- export { type AppContext, AppMode, type ApplicationContextRecord, CalimeroLogo, type CalimeroLogoProps, ConnectButton, type ConnectButtonProps, ConnectionType, type ContextDiscoveryOptions, type ContextDiscoveryState, type CustomConnectionConfig, type ExecutionResult, LoginModal, type LoginModalProps, MERO_CSS_VARS, MeroContext, type MeroContextValue, MeroProvider, type MeroProviderConfig, type MeroProviderProps, type MeroTheme, MigrationAdminPanel, type MigrationAdminPanelProps, MigrationPendingBanner, type MigrationPendingBannerProps, type ResolvedMeroTheme, type SetMetadataInput, type SubscriptionEventData, type SubscriptionInput, type UseEphemeralOptions, type UseEphemeralResult, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, clearTokenNodeUrl, cssVar, defaultMeroTheme, getApplicationId, getContextId, getContextIdentity, getNodeUrl, getTokenNodeUrl, localStorageTokenStorage, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, setTokenNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useEphemeral, useExecute, useGroupAppVersion, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useInstallFromRegistry, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateMemberRole, useUpgradeGroup };
921
+ export { type AppContext, AppMode, type ApplicationContextRecord, CalimeroLogo, type CalimeroLogoProps, ConnectButton, type ConnectButtonProps, ConnectionType, type ContextDiscoveryOptions, type ContextDiscoveryState, type CustomConnectionConfig, DEFAULT_MIGRATION_POLL_INTERVAL_MS, type ExecutionResult, LoginModal, type LoginModalProps, MERO_CSS_VARS, MeroContext, type MeroContextValue, MeroProvider, type MeroProviderConfig, type MeroProviderProps, type MeroTheme, MigrationAdminPanel, type MigrationAdminPanelProps, MigrationPendingBanner, type MigrationPendingBannerProps, type ResolvedMeroTheme, type SetMetadataInput, type SubscriptionEventData, type SubscriptionInput, type UseEphemeralOptions, type UseEphemeralResult, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, clearTokenNodeUrl, cssVar, defaultMeroTheme, getApplicationId, getContextId, getContextIdentity, getNodeUrl, getTokenNodeUrl, localStorageTokenStorage, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, setTokenNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useEphemeral, useExecute, useGroupAppVersion, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useInstallFromRegistry, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationEvents, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useNodeIdentity, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateMemberRole, useUpgradeGroup };
package/dist/index.js CHANGED
@@ -328,6 +328,7 @@ function MeroProvider({
328
328
  const [contextId, setContextIdState] = useState(() => getContextId());
329
329
  const [contextIdentity, setContextIdentityState] = useState(() => getContextIdentity());
330
330
  const meroRef = useRef(null);
331
+ const recoveringRef = useRef(false);
331
332
  const callbackRef = useRef(void 0);
332
333
  if (callbackRef.current === void 0 && isBrowser) {
333
334
  callbackRef.current = parseAuthCallback(window.location.href);
@@ -351,12 +352,18 @@ function MeroProvider({
351
352
  async (instance) => {
352
353
  const accessToken = tokenStore.getTokens()?.access_token;
353
354
  if (!accessToken) return false;
354
- try {
355
- const { valid } = await instance.auth.validateToken(accessToken);
356
- return valid;
357
- } catch {
358
- return false;
359
- }
355
+ const validate = async (token) => {
356
+ try {
357
+ const { valid } = await instance.auth.validateToken(token);
358
+ return valid;
359
+ } catch {
360
+ return false;
361
+ }
362
+ };
363
+ if (await validate(accessToken)) return true;
364
+ const rotated = tokenStore.getTokens()?.access_token;
365
+ if (!rotated || rotated === accessToken) return false;
366
+ return validate(rotated);
360
367
  },
361
368
  [tokenStore]
362
369
  );
@@ -483,9 +490,23 @@ function MeroProvider({
483
490
  const onError = (err) => {
484
491
  if (!active) return;
485
492
  setIsOnline(false);
486
- if (err.message.includes("401")) {
487
- logout();
488
- }
493
+ if (!err.message.includes("401")) return;
494
+ if (recoveringRef.current) return;
495
+ recoveringRef.current = true;
496
+ void (async () => {
497
+ try {
498
+ const instance = meroRef.current;
499
+ if (!instance) return;
500
+ if (await checkAuth(instance)) {
501
+ if (active) await instance.events.connect().catch(() => {
502
+ });
503
+ return;
504
+ }
505
+ if (active) logout();
506
+ } finally {
507
+ recoveringRef.current = false;
508
+ }
509
+ })();
489
510
  };
490
511
  sse.on("connect", onConnect);
491
512
  sse.on("error", onError);
@@ -497,7 +518,7 @@ function MeroProvider({
497
518
  sse.off("connect", onConnect);
498
519
  sse.off("error", onError);
499
520
  };
500
- }, [isAuthenticated, mero]);
521
+ }, [isAuthenticated, mero, checkAuth, logout]);
501
522
  const contextValue = useMemo(
502
523
  () => ({
503
524
  mero,
@@ -1990,6 +2011,15 @@ function useNamespace(namespaceId) {
1990
2011
  );
1991
2012
  return { namespace: data, loading, error, refetch };
1992
2013
  }
2014
+ function useNodeIdentity() {
2015
+ const { mero } = useMero();
2016
+ const { data, loading, error, refetch } = useAsyncResource(
2017
+ mero ? () => mero.admin.getNodeIdentity() : null,
2018
+ null,
2019
+ [mero]
2020
+ );
2021
+ return { identity: data, loading, error, refetch };
2022
+ }
1993
2023
  function useNamespaceIdentity(namespaceId) {
1994
2024
  const { mero } = useMero();
1995
2025
  const { data, loading, error, refetch } = useAsyncResource(
@@ -2359,6 +2389,35 @@ function useDetachContextFromGroup() {
2359
2389
  );
2360
2390
  return { detachContextFromGroup, loading, error };
2361
2391
  }
2392
+ var DEFAULT_MIGRATION_POLL_INTERVAL_MS = 5e3;
2393
+ function useMigrationEvents(namespaceId, onEvent) {
2394
+ const { mero } = useMero();
2395
+ const mountedRef = useMountedRef();
2396
+ const [live, setLive] = useState(false);
2397
+ const handlerRef = useRef(onEvent);
2398
+ handlerRef.current = onEvent;
2399
+ useEffect(() => {
2400
+ if (!mero || !namespaceId) return;
2401
+ const sse = mero.events;
2402
+ const unsubscribe = sse.onMigrationEvent((event) => handlerRef.current(event));
2403
+ let cancelled = false;
2404
+ void (async () => {
2405
+ try {
2406
+ await sse.connect();
2407
+ await sse.subscribe({ groupIds: [namespaceId] });
2408
+ if (!cancelled && mountedRef.current) setLive(true);
2409
+ } catch {
2410
+ if (!cancelled && mountedRef.current) setLive(false);
2411
+ }
2412
+ })();
2413
+ return () => {
2414
+ cancelled = true;
2415
+ if (mountedRef.current) setLive(false);
2416
+ unsubscribe();
2417
+ };
2418
+ }, [mero, namespaceId, mountedRef]);
2419
+ return live;
2420
+ }
2362
2421
  function useMigrationStatus(namespaceId, options) {
2363
2422
  const { mero } = useMero();
2364
2423
  const [status, setStatus] = useState(null);
@@ -2403,7 +2462,8 @@ function useMigrationStatus(namespaceId, options) {
2403
2462
  useEffect(() => {
2404
2463
  void refetch();
2405
2464
  }, [refetch]);
2406
- const pollIntervalMs = options?.pollIntervalMs;
2465
+ const sseLive = useMigrationEvents(namespaceId, () => void refetch());
2466
+ const pollIntervalMs = options?.pollIntervalMs ?? (sseLive ? void 0 : DEFAULT_MIGRATION_POLL_INTERVAL_MS);
2407
2467
  useEffect(() => {
2408
2468
  if (!pollIntervalMs || !mero || !namespaceId) return;
2409
2469
  const handle = setInterval(() => void refetch(), pollIntervalMs);
@@ -2416,6 +2476,12 @@ function useMigrationStatus(namespaceId, options) {
2416
2476
  rollup,
2417
2477
  members,
2418
2478
  allMigrated: rollup?.allMigrated ?? false,
2479
+ /**
2480
+ * When this node watched the fleet converge, or `null`. Durable, unlike
2481
+ * `allMigrated`, which is recomputed from in-TTL heartbeats and lapses back
2482
+ * to false when a member simply goes quiet.
2483
+ */
2484
+ fleetCompletedAt: status?.fleetCompletedAt ?? null,
2419
2485
  membersPendingSignature: rollup?.membersPendingSignature ?? 0,
2420
2486
  /** Members whose migrate aborted (migration-check failed or apply errored). */
2421
2487
  failed: rollup?.failed ?? 0,
@@ -2535,7 +2601,6 @@ var EMPTY_GROUP_APP_VERSION = {
2535
2601
  version: null,
2536
2602
  applicationId: null,
2537
2603
  pendingApply: false,
2538
- upgradePolicy: null,
2539
2604
  activeUpgrade: null
2540
2605
  };
2541
2606
  function isZeroAppKey(appKey) {
@@ -2567,17 +2632,14 @@ function useGroupAppVersion(groupId) {
2567
2632
  const namespace = namespaces.find((entry) => entry.namespaceId === groupId);
2568
2633
  let appKey;
2569
2634
  let applicationId;
2570
- let upgradePolicy;
2571
2635
  let activeUpgrade = null;
2572
2636
  if (namespace) {
2573
2637
  appKey = namespace.appKey;
2574
2638
  applicationId = namespace.targetApplicationId;
2575
- upgradePolicy = namespace.upgradePolicy ?? null;
2576
2639
  } else {
2577
2640
  const info = await mero.admin.getGroupInfo(groupId);
2578
2641
  appKey = info.appKey;
2579
2642
  applicationId = info.targetApplicationId;
2580
- upgradePolicy = info.upgradePolicy ?? null;
2581
2643
  activeUpgrade = info.activeUpgrade ?? null;
2582
2644
  }
2583
2645
  let version = null;
@@ -2591,7 +2653,7 @@ function useGroupAppVersion(groupId) {
2591
2653
  }
2592
2654
  }
2593
2655
  if (mountedRef.current && seq === reqRef.current) {
2594
- setData({ version, applicationId, pendingApply, upgradePolicy, activeUpgrade });
2656
+ setData({ version, applicationId, pendingApply, activeUpgrade });
2595
2657
  }
2596
2658
  } catch (err) {
2597
2659
  const errorValue = toError(err);
@@ -2762,6 +2824,6 @@ function MigrationAdminPanel({ namespaceId, pollIntervalMs, className }) {
2762
2824
  ] });
2763
2825
  }
2764
2826
 
2765
- export { AppMode, CalimeroLogo, ConnectButton, ConnectionType, LoginModal, MERO_CSS_VARS, MeroContext, MeroProvider, MigrationAdminPanel, MigrationPendingBanner, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, clearTokenNodeUrl, cssVar, defaultMeroTheme, getApplicationId, getContextId, getContextIdentity, getNodeUrl, getTokenNodeUrl, localStorageTokenStorage, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, setTokenNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useEphemeral, useExecute, useGroupAppVersion, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useInstallFromRegistry, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateMemberRole, useUpgradeGroup };
2827
+ export { AppMode, CalimeroLogo, ConnectButton, ConnectionType, DEFAULT_MIGRATION_POLL_INTERVAL_MS, LoginModal, MERO_CSS_VARS, MeroContext, MeroProvider, MigrationAdminPanel, MigrationPendingBanner, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, clearTokenNodeUrl, cssVar, defaultMeroTheme, getApplicationId, getContextId, getContextIdentity, getNodeUrl, getTokenNodeUrl, localStorageTokenStorage, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, setTokenNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useEphemeral, useExecute, useGroupAppVersion, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useInstallFromRegistry, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationEvents, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useNodeIdentity, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateMemberRole, useUpgradeGroup };
2766
2828
  //# sourceMappingURL=index.js.map
2767
2829
  //# sourceMappingURL=index.js.map