@calimero-network/mero-react 4.6.1 → 5.1.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/README.md CHANGED
@@ -352,7 +352,6 @@ useGroupInfo, useGroupMembers, useGroupContexts, useGroupInvitations, useGroupCa
352
352
  useJoinGroup, useDeleteGroup, useAddGroupMembers, useRemoveGroupMembers
353
353
  useSyncGroup, useReparentGroup, useSubgroups
354
354
  useUpgradeGroup, useGroupUpgradeStatus, useRetryGroupUpgrade
355
- useRegisterGroupSigningKey, useUpdateGroupSettings
356
355
  useSetGroupMetadata, useSetMemberMetadata, useSetContextMetadata
357
356
  useGroupMetadata, useMemberMetadata, useUpdateMemberRole
358
357
  useSetDefaultCapabilities, useDefaultCapabilities
package/dist/index.cjs CHANGED
@@ -1266,6 +1266,185 @@ function base58ToHex(input) {
1266
1266
  }
1267
1267
 
1268
1268
  // src/hooks/index.ts
1269
+ var NO_EPHEMERAL_SURFACE_MESSAGE = "useEphemeral: this client has no `mero.ephemeral` surface. Ephemeral presence requires @calimero-network/mero-js >= 9.1.0; upgrade the installed @calimero-network/mero-js (and any lockfile pin) to use it.";
1270
+ var COULD_NOT_RESOLVE_IDENTITY_MESSAGE = "useEphemeral: could not resolve a local context identity, so your own presence cannot be filtered out. Pass includeSelf: true to accept this.";
1271
+ var REPLAY_RECONCILE_MS = 50;
1272
+ function useEphemeral(contextId, options = {}) {
1273
+ const { includeSelf = false } = options;
1274
+ const { mero } = useMero();
1275
+ const ephemeral = mero ? mero.ephemeral ?? null : null;
1276
+ const [peers, setPeers] = react.useState(/* @__PURE__ */ new Map());
1277
+ const [latchedError, setLatchedError] = react.useState(null);
1278
+ const contextKeyRef = react.useRef(contextId);
1279
+ contextKeyRef.current = contextId;
1280
+ const setSourceError = react.useCallback(
1281
+ (source, err, key) => {
1282
+ if (key !== contextKeyRef.current) return;
1283
+ setLatchedError({ contextKey: key, source, error: err });
1284
+ },
1285
+ []
1286
+ );
1287
+ const clearSourceError = react.useCallback((source, key) => {
1288
+ setLatchedError(
1289
+ (prev) => prev && prev.source === source && prev.contextKey === key ? null : prev
1290
+ );
1291
+ }, []);
1292
+ const surfaceError = react.useMemo(
1293
+ () => mero && !ephemeral ? new Error(NO_EPHEMERAL_SURFACE_MESSAGE) : null,
1294
+ [mero, ephemeral]
1295
+ );
1296
+ const error = surfaceError ?? (latchedError && latchedError.contextKey === contextId && !(latchedError.source === "identity" && includeSelf) ? latchedError.error : null);
1297
+ const receivedAtRef = react.useRef(/* @__PURE__ */ new Map());
1298
+ const codecRef = react.useRef(options.codec);
1299
+ codecRef.current = options.codec;
1300
+ const initialRef = react.useRef(options.initial);
1301
+ initialRef.current = options.initial;
1302
+ const selfRef = react.useRef(null);
1303
+ const lastLocalRef = react.useRef(options.initial);
1304
+ const pendingRef = react.useRef(void 0);
1305
+ const timerRef = react.useRef(null);
1306
+ const lastSentAtRef = react.useRef(Date.now());
1307
+ const replaySeenRef = react.useRef(null);
1308
+ const replayTimerRef = react.useRef(null);
1309
+ const ageOf = react.useCallback((author) => {
1310
+ const at = receivedAtRef.current.get(author);
1311
+ return at === void 0 ? void 0 : Date.now() - at;
1312
+ }, []);
1313
+ react.useEffect(() => {
1314
+ setPeers(/* @__PURE__ */ new Map());
1315
+ receivedAtRef.current = /* @__PURE__ */ new Map();
1316
+ if (timerRef.current) {
1317
+ clearTimeout(timerRef.current);
1318
+ timerRef.current = null;
1319
+ }
1320
+ if (replayTimerRef.current) {
1321
+ clearTimeout(replayTimerRef.current);
1322
+ replayTimerRef.current = null;
1323
+ }
1324
+ replaySeenRef.current = null;
1325
+ pendingRef.current = void 0;
1326
+ lastLocalRef.current = initialRef.current;
1327
+ selfRef.current = null;
1328
+ setLatchedError(null);
1329
+ }, [contextId]);
1330
+ react.useEffect(() => {
1331
+ if (!mero || !contextId) return;
1332
+ const key = contextId;
1333
+ let cancelled = false;
1334
+ mero.admin.getContextIdentitiesOwned(contextId).then((res) => {
1335
+ if (cancelled) return;
1336
+ const self = res.identities?.[0] ?? null;
1337
+ selfRef.current = self;
1338
+ if (!self) {
1339
+ setSourceError("identity", new Error(COULD_NOT_RESOLVE_IDENTITY_MESSAGE), key);
1340
+ return;
1341
+ }
1342
+ clearSourceError("identity", key);
1343
+ if (!includeSelf) {
1344
+ receivedAtRef.current.delete(self);
1345
+ setPeers((prev) => {
1346
+ if (!prev.has(self)) return prev;
1347
+ const next = new Map(prev);
1348
+ next.delete(self);
1349
+ return next;
1350
+ });
1351
+ }
1352
+ }).catch((err) => {
1353
+ if (!cancelled) {
1354
+ setSourceError("identity", toError(err), key);
1355
+ }
1356
+ });
1357
+ return () => {
1358
+ cancelled = true;
1359
+ };
1360
+ }, [mero, contextId, includeSelf, setSourceError, clearSourceError]);
1361
+ react.useEffect(() => {
1362
+ if (!ephemeral || !contextId) return;
1363
+ const closeReplayWindow = () => {
1364
+ replayTimerRef.current = null;
1365
+ const seen = replaySeenRef.current;
1366
+ replaySeenRef.current = null;
1367
+ if (!seen) return;
1368
+ setPeers((prev) => {
1369
+ let next = null;
1370
+ for (const author of prev.keys()) {
1371
+ if (seen.has(author)) continue;
1372
+ if (!next) next = new Map(prev);
1373
+ next.delete(author);
1374
+ receivedAtRef.current.delete(author);
1375
+ }
1376
+ return next ?? prev;
1377
+ });
1378
+ };
1379
+ const unsubscribe = ephemeral.subscribe(
1380
+ contextId,
1381
+ (entry) => {
1382
+ const { author, state } = entry;
1383
+ if (entry.ageMs !== void 0) {
1384
+ if (!replaySeenRef.current) replaySeenRef.current = /* @__PURE__ */ new Set();
1385
+ if (replayTimerRef.current) clearTimeout(replayTimerRef.current);
1386
+ replayTimerRef.current = setTimeout(closeReplayWindow, REPLAY_RECONCILE_MS);
1387
+ }
1388
+ if (entry.removed || state === void 0) {
1389
+ replaySeenRef.current?.delete(author);
1390
+ receivedAtRef.current.delete(author);
1391
+ setPeers((prev) => {
1392
+ if (!prev.has(author)) return prev;
1393
+ const next = new Map(prev);
1394
+ next.delete(author);
1395
+ return next;
1396
+ });
1397
+ return;
1398
+ }
1399
+ if (!includeSelf && author === selfRef.current) return;
1400
+ replaySeenRef.current?.add(author);
1401
+ receivedAtRef.current.set(author, Date.now() - (entry.ageMs ?? 0));
1402
+ setPeers((prev) => new Map(prev).set(author, state));
1403
+ },
1404
+ codecRef.current
1405
+ );
1406
+ return () => {
1407
+ if (replayTimerRef.current) {
1408
+ clearTimeout(replayTimerRef.current);
1409
+ replayTimerRef.current = null;
1410
+ }
1411
+ replaySeenRef.current = null;
1412
+ unsubscribe();
1413
+ };
1414
+ }, [ephemeral, contextId, includeSelf]);
1415
+ const publish = react.useCallback((value) => {
1416
+ if (!ephemeral || !contextId) return;
1417
+ const key = contextId;
1418
+ lastSentAtRef.current = Date.now();
1419
+ void ephemeral.set(key, value, codecRef.current).then(
1420
+ () => clearSourceError("publish", key),
1421
+ (err) => setSourceError("publish", toError(err), key)
1422
+ );
1423
+ }, [ephemeral, contextId, setSourceError, clearSourceError]);
1424
+ const setPresence = react.useCallback((partial) => {
1425
+ const next = { ...lastLocalRef.current ?? {}, ...partial };
1426
+ lastLocalRef.current = next;
1427
+ const throttleMs = options.throttleMs ?? 30;
1428
+ if (throttleMs <= 0) {
1429
+ publish(next);
1430
+ return;
1431
+ }
1432
+ pendingRef.current = next;
1433
+ if (timerRef.current) return;
1434
+ const elapsed = Date.now() - lastSentAtRef.current;
1435
+ const delay = Math.max(throttleMs - elapsed, 0);
1436
+ timerRef.current = setTimeout(() => {
1437
+ timerRef.current = null;
1438
+ const queued = pendingRef.current;
1439
+ pendingRef.current = void 0;
1440
+ if (queued !== void 0) publish(queued);
1441
+ }, delay);
1442
+ }, [publish, options.throttleMs]);
1443
+ react.useEffect(() => () => {
1444
+ if (timerRef.current) clearTimeout(timerRef.current);
1445
+ }, []);
1446
+ return { peers, setPresence, ageOf, error };
1447
+ }
1269
1448
  function toError(err) {
1270
1449
  return err instanceof Error ? err : new Error(String(err));
1271
1450
  }
@@ -1464,7 +1643,6 @@ function useGroupMembers(groupId) {
1464
1643
  );
1465
1644
  return {
1466
1645
  members: data?.members ?? [],
1467
- selfIdentity: data?.selfIdentity ?? null,
1468
1646
  loading,
1469
1647
  error,
1470
1648
  refetch
@@ -1965,18 +2143,6 @@ function useSetTeeAdmissionPolicy() {
1965
2143
  );
1966
2144
  return { setTeeAdmissionPolicy, loading, error };
1967
2145
  }
1968
- function useUpdateGroupSettings() {
1969
- const { mero } = useMero();
1970
- const { loading, error, run } = useAsyncMutation();
1971
- const updateGroupSettings = react.useCallback(
1972
- async (groupId, request) => {
1973
- if (!mero) return null;
1974
- return run(() => mero.admin.updateGroupSettings(groupId, request));
1975
- },
1976
- [mero, run]
1977
- );
1978
- return { updateGroupSettings, loading, error };
1979
- }
1980
2146
  function useSetGroupMetadata() {
1981
2147
  const { mero } = useMero();
1982
2148
  const { loading, error, run } = useAsyncMutation();
@@ -2065,18 +2231,6 @@ function useMemberMetadata(groupId, identity) {
2065
2231
  }, [run]);
2066
2232
  return { metadata, loading, error, refetch };
2067
2233
  }
2068
- function useRegisterGroupSigningKey() {
2069
- const { mero } = useMero();
2070
- const { loading, error, run } = useAsyncMutation();
2071
- const registerGroupSigningKey = react.useCallback(
2072
- async (groupId, request) => {
2073
- if (!mero) return null;
2074
- return run(() => mero.admin.registerGroupSigningKey(groupId, request));
2075
- },
2076
- [mero, run]
2077
- );
2078
- return { registerGroupSigningKey, loading, error };
2079
- }
2080
2234
  function useUpgradeGroup() {
2081
2235
  const { mero } = useMero();
2082
2236
  const { loading, error, run } = useAsyncMutation();
@@ -2418,12 +2572,12 @@ function useGroupAppVersion(groupId) {
2418
2572
  if (namespace) {
2419
2573
  appKey = namespace.appKey;
2420
2574
  applicationId = namespace.targetApplicationId;
2421
- upgradePolicy = namespace.upgradePolicy;
2575
+ upgradePolicy = namespace.upgradePolicy ?? null;
2422
2576
  } else {
2423
2577
  const info = await mero.admin.getGroupInfo(groupId);
2424
2578
  appKey = info.appKey;
2425
2579
  applicationId = info.targetApplicationId;
2426
- upgradePolicy = info.upgradePolicy;
2580
+ upgradePolicy = info.upgradePolicy ?? null;
2427
2581
  activeUpgrade = info.activeUpgrade ?? null;
2428
2582
  }
2429
2583
  let version = null;
@@ -2690,6 +2844,7 @@ exports.useDeleteContext = useDeleteContext;
2690
2844
  exports.useDeleteGroup = useDeleteGroup;
2691
2845
  exports.useDeleteNamespace = useDeleteNamespace;
2692
2846
  exports.useDetachContextFromGroup = useDetachContextFromGroup;
2847
+ exports.useEphemeral = useEphemeral;
2693
2848
  exports.useExecute = useExecute;
2694
2849
  exports.useGroupAppVersion = useGroupAppVersion;
2695
2850
  exports.useGroupCapabilities = useGroupCapabilities;
@@ -2714,7 +2869,6 @@ exports.useNamespaceGroups = useNamespaceGroups;
2714
2869
  exports.useNamespaceIdentity = useNamespaceIdentity;
2715
2870
  exports.useNamespaces = useNamespaces;
2716
2871
  exports.useNamespacesForApplication = useNamespacesForApplication;
2717
- exports.useRegisterGroupSigningKey = useRegisterGroupSigningKey;
2718
2872
  exports.useRemoveGroupMembers = useRemoveGroupMembers;
2719
2873
  exports.useReparentGroup = useReparentGroup;
2720
2874
  exports.useResyncContext = useResyncContext;
@@ -2729,7 +2883,6 @@ exports.useSubgroupVisibility = useSubgroupVisibility;
2729
2883
  exports.useSubgroups = useSubgroups;
2730
2884
  exports.useSubscription = useSubscription;
2731
2885
  exports.useSyncGroup = useSyncGroup;
2732
- exports.useUpdateGroupSettings = useUpdateGroupSettings;
2733
2886
  exports.useUpdateMemberRole = useUpdateMemberRole;
2734
2887
  exports.useUpgradeGroup = useUpgradeGroup;
2735
2888
  Object.keys(meroJs).forEach(function (k) {