@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 +0 -1
- package/dist/index.cjs +182 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -15
- package/dist/index.d.ts +48 -15
- package/dist/index.js +182 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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) {
|