@calimero-network/mero-react 9.0.0 → 9.1.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, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, NodeIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, TokenData } from '@calimero-network/mero-js';
5
+ import { MeroJs, TokenStore, SetMetadataRequest, SseEventData, GroupMembershipEventData, GroupMigrationEventData, Codec, AddGroupMembersRequest, GetBlobInfoResponseData, CreateContextRequest, CreateGroupInNamespaceRequest, CreateNamespaceRequest, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, NodeIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, UploadBlobRequest, 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
 
@@ -841,6 +841,106 @@ declare function useMyAuthoredMigration(contextId?: string | null): {
841
841
  error: Error | null;
842
842
  refresh: () => Promise<void>;
843
843
  };
844
+ /**
845
+ * Options for the blob READ hooks.
846
+ *
847
+ * `contextId` is what picks the mode, and the two modes have wildly different
848
+ * costs:
849
+ *
850
+ * - **omitted** — local-only read. The node answers from its own blob store
851
+ * and returns immediately, or 404s.
852
+ * - **supplied** — network discovery. The node probes that context's peers
853
+ * (availability nodes first) for a holder. Core bounds the search by a ~30s
854
+ * deadline, and for {@link useBlobUrl} the byte transfer is on top of that.
855
+ *
856
+ * So `loading` is load-bearing UI state on these hooks, not decoration: a
857
+ * discovery read can plausibly spin for half a minute before it resolves
858
+ * either way. Render a spinner (or a cancel affordance) accordingly.
859
+ */
860
+ interface BlobHookOptions {
861
+ /** Context whose peers to probe. Omit for a local-only read. */
862
+ contextId?: string;
863
+ }
864
+ /** Options for {@link useBlobUrl}. */
865
+ interface UseBlobUrlOptions extends BlobHookOptions {
866
+ /**
867
+ * MIME type stamped on the `Blob` the object URL points at. The blob read
868
+ * itself carries no type, and a peer-sourced answer has no `mimeType` at
869
+ * all, so pass it when the consumer needs one (`<img>` sniffs; a download
870
+ * `<a>` and an `<iframe>` do not).
871
+ */
872
+ type?: string;
873
+ }
874
+ /**
875
+ * A blob's presence and size, WITHOUT downloading it — the cheap half of the
876
+ * blob surface, and the one to ask before pulling something large.
877
+ *
878
+ * `blobId` follows the same `string | null` convention as the other read
879
+ * hooks: null/undefined means "no read", not "read nothing" — nothing is
880
+ * fetched and `info` stays null.
881
+ *
882
+ * `hash` and `mimeType` on the result are genuinely optional: a peer probe
883
+ * answers with presence and size only, so a discovery-sourced hit carries
884
+ * neither. `info.source` (`'local' | 'peer'`, undefined on nodes that predate
885
+ * the header) tells the two apart — do not treat a missing `mimeType` as a
886
+ * malformed response.
887
+ *
888
+ * `notFound` distinguishes the legitimate "no holder" outcome (the node
889
+ * answered 404) from a transport failure. `error` is set in BOTH cases — this
890
+ * hook does not swallow the 404, it only labels it.
891
+ *
892
+ * Latency: immediate without `contextId`, up to core's ~30s discovery deadline
893
+ * with one. See {@link BlobHookOptions}.
894
+ */
895
+ declare function useBlobInfo(blobId?: string | null, options?: BlobHookOptions): {
896
+ info: GetBlobInfoResponseData | null;
897
+ notFound: boolean;
898
+ loading: boolean;
899
+ error: Error | null;
900
+ refetch: () => Promise<void>;
901
+ };
902
+ /**
903
+ * A blob's bytes as an object URL, ready for `<img src>`, an `<a href>`
904
+ * download, or an `<iframe>`.
905
+ *
906
+ * Lifecycle is handled here so the consumer never has to revoke: the URL is
907
+ * revoked on unmount, and whenever `blobId`/`contextId`/`type` change. `url`
908
+ * goes back to null synchronously on such a change, so a revoked URL is never
909
+ * handed out as the current one — render off `url` and it is always live.
910
+ *
911
+ * A response for a superseded `blobId` is dropped before an object URL is even
912
+ * created, so an out-of-order arrival can neither overwrite the newer result
913
+ * nor leak.
914
+ *
915
+ * Latency: this is the expensive hook. Without `contextId` it is a local read;
916
+ * with one it is discovery (core's ~30s deadline) PLUS the transfer of the
917
+ * bytes. Prefer {@link useBlobInfo} to decide whether the download is worth
918
+ * starting, and always render `loading`.
919
+ *
920
+ * `notFound` marks the node's 404 ("no peer holds this") apart from a
921
+ * transport failure; `error` is set for both.
922
+ */
923
+ declare function useBlobUrl(blobId?: string | null, options?: UseBlobUrlOptions): {
924
+ url: string | null;
925
+ notFound: boolean;
926
+ loading: boolean;
927
+ error: Error | null;
928
+ refetch: () => Promise<void>;
929
+ };
930
+ /**
931
+ * Upload bytes to the node's blob store. Mutation-shaped, like the other
932
+ * write hooks: `uploadBlob` resolves to `{ blobId, size }`, or null when the
933
+ * client is absent or the call failed (read `error` for which).
934
+ *
935
+ * Pass `contextId` to announce the blob to that context, which is what lets
936
+ * the context's other members later discover it with {@link useBlobUrl} /
937
+ * {@link useBlobInfo}. Without it the blob is only readable on this node.
938
+ */
939
+ declare function useUploadBlob(): {
940
+ uploadBlob: (request: UploadBlobRequest) => Promise<_calimero_network_mero_js.BlobInfo | null>;
941
+ loading: boolean;
942
+ error: Error | null;
943
+ };
844
944
 
845
945
  /**
846
946
  * Storage utilities for mero-react
@@ -918,4 +1018,4 @@ declare function clearContextIdentity(): void;
918
1018
  */
919
1019
  declare function clearAllStorage(): void;
920
1020
 
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 };
1021
+ export { type AppContext, AppMode, type ApplicationContextRecord, type BlobHookOptions, 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 UseBlobUrlOptions, 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, useBlobInfo, useBlobUrl, 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, useUploadBlob };
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, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, NodeIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, TokenData } from '@calimero-network/mero-js';
5
+ import { MeroJs, TokenStore, SetMetadataRequest, SseEventData, GroupMembershipEventData, GroupMigrationEventData, Codec, AddGroupMembersRequest, GetBlobInfoResponseData, CreateContextRequest, CreateGroupInNamespaceRequest, CreateNamespaceRequest, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, GroupUpgradeStatusResponseData, GroupContextEntry, GroupInfo, CreateGroupInvitationRequest, MetadataRecord, JoinGroupRequest, JoinNamespaceRequest, MigrationStatus, MigrationStatusRollup, MemberMigrationStatusEntry, MigrateMyEntriesSummary, Namespace, SubgroupEntry, NamespaceIdentity, NodeIdentity, RemoveGroupMembersRequest, ReparentGroupRequest, ResyncContextRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, UpdateMemberRoleRequest, UpgradeGroupRequest, UploadBlobRequest, 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
 
@@ -841,6 +841,106 @@ declare function useMyAuthoredMigration(contextId?: string | null): {
841
841
  error: Error | null;
842
842
  refresh: () => Promise<void>;
843
843
  };
844
+ /**
845
+ * Options for the blob READ hooks.
846
+ *
847
+ * `contextId` is what picks the mode, and the two modes have wildly different
848
+ * costs:
849
+ *
850
+ * - **omitted** — local-only read. The node answers from its own blob store
851
+ * and returns immediately, or 404s.
852
+ * - **supplied** — network discovery. The node probes that context's peers
853
+ * (availability nodes first) for a holder. Core bounds the search by a ~30s
854
+ * deadline, and for {@link useBlobUrl} the byte transfer is on top of that.
855
+ *
856
+ * So `loading` is load-bearing UI state on these hooks, not decoration: a
857
+ * discovery read can plausibly spin for half a minute before it resolves
858
+ * either way. Render a spinner (or a cancel affordance) accordingly.
859
+ */
860
+ interface BlobHookOptions {
861
+ /** Context whose peers to probe. Omit for a local-only read. */
862
+ contextId?: string;
863
+ }
864
+ /** Options for {@link useBlobUrl}. */
865
+ interface UseBlobUrlOptions extends BlobHookOptions {
866
+ /**
867
+ * MIME type stamped on the `Blob` the object URL points at. The blob read
868
+ * itself carries no type, and a peer-sourced answer has no `mimeType` at
869
+ * all, so pass it when the consumer needs one (`<img>` sniffs; a download
870
+ * `<a>` and an `<iframe>` do not).
871
+ */
872
+ type?: string;
873
+ }
874
+ /**
875
+ * A blob's presence and size, WITHOUT downloading it — the cheap half of the
876
+ * blob surface, and the one to ask before pulling something large.
877
+ *
878
+ * `blobId` follows the same `string | null` convention as the other read
879
+ * hooks: null/undefined means "no read", not "read nothing" — nothing is
880
+ * fetched and `info` stays null.
881
+ *
882
+ * `hash` and `mimeType` on the result are genuinely optional: a peer probe
883
+ * answers with presence and size only, so a discovery-sourced hit carries
884
+ * neither. `info.source` (`'local' | 'peer'`, undefined on nodes that predate
885
+ * the header) tells the two apart — do not treat a missing `mimeType` as a
886
+ * malformed response.
887
+ *
888
+ * `notFound` distinguishes the legitimate "no holder" outcome (the node
889
+ * answered 404) from a transport failure. `error` is set in BOTH cases — this
890
+ * hook does not swallow the 404, it only labels it.
891
+ *
892
+ * Latency: immediate without `contextId`, up to core's ~30s discovery deadline
893
+ * with one. See {@link BlobHookOptions}.
894
+ */
895
+ declare function useBlobInfo(blobId?: string | null, options?: BlobHookOptions): {
896
+ info: GetBlobInfoResponseData | null;
897
+ notFound: boolean;
898
+ loading: boolean;
899
+ error: Error | null;
900
+ refetch: () => Promise<void>;
901
+ };
902
+ /**
903
+ * A blob's bytes as an object URL, ready for `<img src>`, an `<a href>`
904
+ * download, or an `<iframe>`.
905
+ *
906
+ * Lifecycle is handled here so the consumer never has to revoke: the URL is
907
+ * revoked on unmount, and whenever `blobId`/`contextId`/`type` change. `url`
908
+ * goes back to null synchronously on such a change, so a revoked URL is never
909
+ * handed out as the current one — render off `url` and it is always live.
910
+ *
911
+ * A response for a superseded `blobId` is dropped before an object URL is even
912
+ * created, so an out-of-order arrival can neither overwrite the newer result
913
+ * nor leak.
914
+ *
915
+ * Latency: this is the expensive hook. Without `contextId` it is a local read;
916
+ * with one it is discovery (core's ~30s deadline) PLUS the transfer of the
917
+ * bytes. Prefer {@link useBlobInfo} to decide whether the download is worth
918
+ * starting, and always render `loading`.
919
+ *
920
+ * `notFound` marks the node's 404 ("no peer holds this") apart from a
921
+ * transport failure; `error` is set for both.
922
+ */
923
+ declare function useBlobUrl(blobId?: string | null, options?: UseBlobUrlOptions): {
924
+ url: string | null;
925
+ notFound: boolean;
926
+ loading: boolean;
927
+ error: Error | null;
928
+ refetch: () => Promise<void>;
929
+ };
930
+ /**
931
+ * Upload bytes to the node's blob store. Mutation-shaped, like the other
932
+ * write hooks: `uploadBlob` resolves to `{ blobId, size }`, or null when the
933
+ * client is absent or the call failed (read `error` for which).
934
+ *
935
+ * Pass `contextId` to announce the blob to that context, which is what lets
936
+ * the context's other members later discover it with {@link useBlobUrl} /
937
+ * {@link useBlobInfo}. Without it the blob is only readable on this node.
938
+ */
939
+ declare function useUploadBlob(): {
940
+ uploadBlob: (request: UploadBlobRequest) => Promise<_calimero_network_mero_js.BlobInfo | null>;
941
+ loading: boolean;
942
+ error: Error | null;
943
+ };
844
944
 
845
945
  /**
846
946
  * Storage utilities for mero-react
@@ -918,4 +1018,4 @@ declare function clearContextIdentity(): void;
918
1018
  */
919
1019
  declare function clearAllStorage(): void;
920
1020
 
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 };
1021
+ export { type AppContext, AppMode, type ApplicationContextRecord, type BlobHookOptions, 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 UseBlobUrlOptions, 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, useBlobInfo, useBlobUrl, 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, useUploadBlob };
package/dist/index.js CHANGED
@@ -1546,11 +1546,13 @@ function useAsyncResource(fetcher, initialValue, deps) {
1546
1546
  if (mountedRef.current && seq === reqRef.current) setLoading(false);
1547
1547
  }
1548
1548
  }, deps);
1549
- useEffect(() => {
1549
+ const prevDeps = useRef(deps);
1550
+ if (deps.length !== prevDeps.current.length || deps.some((d, i) => !Object.is(d, prevDeps.current[i]))) {
1551
+ prevDeps.current = deps;
1550
1552
  reqRef.current += 1;
1551
1553
  setData(initialRef.current);
1552
1554
  setError(null);
1553
- }, deps);
1555
+ }
1554
1556
  useEffect(() => {
1555
1557
  void refetch();
1556
1558
  }, [refetch]);
@@ -2223,6 +2225,13 @@ function useMemberMetadata(groupId, identity) {
2223
2225
  const [metadata, setMetadata] = useState(null);
2224
2226
  const [loading, setLoading] = useState(false);
2225
2227
  const [error, setError] = useState(null);
2228
+ const prevKey = useRef(null);
2229
+ const key = `${groupId ?? ""}:${identity ?? ""}`;
2230
+ if (prevKey.current !== null && prevKey.current !== key) {
2231
+ setMetadata(null);
2232
+ setError(null);
2233
+ }
2234
+ prevKey.current = key;
2226
2235
  const run = useCallback(
2227
2236
  async (signal) => {
2228
2237
  if (!mero || !groupId || !identity) {
@@ -2730,6 +2739,80 @@ function useMyAuthoredMigration(contextId) {
2730
2739
  refresh
2731
2740
  };
2732
2741
  }
2742
+ function isBlobNotFound(error) {
2743
+ return !!error && error.status === 404;
2744
+ }
2745
+ function useBlobInfo(blobId, options) {
2746
+ const { mero } = useMero();
2747
+ const contextId = options?.contextId;
2748
+ const { data, loading, error, refetch } = useAsyncResource(
2749
+ mero && blobId ? () => mero.admin.getBlobInfo(blobId, contextId ? { contextId } : void 0) : null,
2750
+ null,
2751
+ [mero, blobId, contextId]
2752
+ );
2753
+ return { info: data, notFound: isBlobNotFound(error), loading, error, refetch };
2754
+ }
2755
+ function useBlobUrl(blobId, options) {
2756
+ const { mero } = useMero();
2757
+ const contextId = options?.contextId;
2758
+ const type = options?.type;
2759
+ const mountedRef = useMountedRef();
2760
+ const [url, setUrl] = useState(null);
2761
+ const [loading, setLoading] = useState(false);
2762
+ const [error, setError] = useState(null);
2763
+ const reqRef = useRef(0);
2764
+ const urlRef = useRef(null);
2765
+ const revoke = useCallback(() => {
2766
+ if (urlRef.current) {
2767
+ URL.revokeObjectURL(urlRef.current);
2768
+ urlRef.current = null;
2769
+ }
2770
+ }, []);
2771
+ const refetch = useCallback(async () => {
2772
+ const seq = ++reqRef.current;
2773
+ if (!mero || !blobId) return;
2774
+ if (mountedRef.current) {
2775
+ setLoading(true);
2776
+ setError(null);
2777
+ }
2778
+ try {
2779
+ const bytes = await mero.admin.getBlob(blobId, contextId ? { contextId } : void 0);
2780
+ if (!mountedRef.current || seq !== reqRef.current) return;
2781
+ revoke();
2782
+ const objectUrl = URL.createObjectURL(new Blob([bytes], type ? { type } : void 0));
2783
+ urlRef.current = objectUrl;
2784
+ setUrl(objectUrl);
2785
+ } catch (err) {
2786
+ if (mountedRef.current && seq === reqRef.current) setError(toError(err));
2787
+ } finally {
2788
+ if (mountedRef.current && seq === reqRef.current) setLoading(false);
2789
+ }
2790
+ }, [mero, blobId, contextId, type, revoke, mountedRef]);
2791
+ useEffect(() => {
2792
+ reqRef.current += 1;
2793
+ revoke();
2794
+ setUrl(null);
2795
+ setError(null);
2796
+ setLoading(false);
2797
+ }, [mero, blobId, contextId, type, revoke]);
2798
+ useEffect(() => {
2799
+ void refetch();
2800
+ }, [refetch]);
2801
+ useEffect(() => revoke, [revoke]);
2802
+ return { url, notFound: isBlobNotFound(error), loading, error, refetch };
2803
+ }
2804
+ function useUploadBlob() {
2805
+ const { mero } = useMero();
2806
+ const { loading, error, run } = useAsyncMutation();
2807
+ const uploadBlob = useCallback(
2808
+ async (request) => {
2809
+ if (!mero) return null;
2810
+ return run(() => mero.admin.uploadBlob(request));
2811
+ },
2812
+ [mero, run]
2813
+ );
2814
+ return { uploadBlob, loading, error };
2815
+ }
2733
2816
  function MigrationPendingBanner({
2734
2817
  contextId,
2735
2818
  className,
@@ -2824,6 +2907,6 @@ function MigrationAdminPanel({ namespaceId, pollIntervalMs, className }) {
2824
2907
  ] });
2825
2908
  }
2826
2909
 
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 };
2910
+ 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, useBlobInfo, useBlobUrl, 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, useUploadBlob };
2828
2911
  //# sourceMappingURL=index.js.map
2829
2912
  //# sourceMappingURL=index.js.map