holosphere 1.3.0-alpha7 → 1.3.0-alpha9
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/content.js +38 -4
- package/federation.js +50 -8
- package/hologram.js +7 -1
- package/holosphere-bundle.esm.js +59 -7
- package/holosphere-bundle.js +59 -7
- package/holosphere-bundle.min.js +8 -8
- package/package.json +1 -1
- package/utils.js +16 -0
package/content.js
CHANGED
|
@@ -38,12 +38,41 @@ const WRITE_TIMEOUT_MS = 5000;
|
|
|
38
38
|
*
|
|
39
39
|
* The first responder wins — both branches are idempotent so a late
|
|
40
40
|
* `.once()` callback after timeout is harmlessly ignored.
|
|
41
|
+
*
|
|
42
|
+
* Pass `{ awaitNetwork: true }` for cold reads that MUST reach the network —
|
|
43
|
+
* notably cross-holon hologram soul resolution. Gun's `.once()` fires
|
|
44
|
+
* synchronously with whatever is in the local graph and never re-fires; for a
|
|
45
|
+
* node we never subscribed to (another holon's lens), that first value is
|
|
46
|
+
* `undefined` even though a peer is about to deliver the real data a few ms
|
|
47
|
+
* later. Accepting that `undefined` as "not found" is exactly what produced
|
|
48
|
+
* the `Could not resolve hologram soul: … (target not present locally)` false
|
|
49
|
+
* negatives on freshly-loaded federated data. In `awaitNetwork` mode we use
|
|
50
|
+
* `.on()` instead, skip the cold `undefined`, and settle once the value
|
|
51
|
+
* syncs — while still honouring an explicit `null` (a real tombstone) and the
|
|
52
|
+
* deadline (for nodes no peer ever answers). The common, same-holon read path
|
|
53
|
+
* keeps the fast `.once()` behaviour so empty/missing local reads resolve
|
|
54
|
+
* immediately instead of blocking for the full deadline.
|
|
41
55
|
*/
|
|
42
|
-
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS) {
|
|
56
|
+
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS, { awaitNetwork = false } = {}) {
|
|
57
|
+
if (!awaitNetwork) {
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
let done = false;
|
|
60
|
+
const finish = (v) => { if (!done) { done = true; resolve(v); } };
|
|
61
|
+
node.once((data) => finish(data));
|
|
62
|
+
if (timeoutMs > 0) {
|
|
63
|
+
setTimeout(() => finish(null), timeoutMs);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
return new Promise((resolve) => {
|
|
44
69
|
let done = false;
|
|
45
|
-
const
|
|
46
|
-
|
|
70
|
+
const detach = () => { try { if (node.off) node.off(); } catch { /* ignore */ } };
|
|
71
|
+
const finish = (v) => { if (!done) { done = true; detach(); resolve(v); } };
|
|
72
|
+
node.on((data) => {
|
|
73
|
+
if (data === undefined) return; // cold/not-known yet — wait for a peer
|
|
74
|
+
finish(data); // defined value OR explicit null tombstone — definitive
|
|
75
|
+
});
|
|
47
76
|
if (timeoutMs > 0) {
|
|
48
77
|
setTimeout(() => finish(null), timeoutMs);
|
|
49
78
|
}
|
|
@@ -535,6 +564,11 @@ export async function get(holoInstance, holon, lens, key, password = null, optio
|
|
|
535
564
|
validationOptions = {},
|
|
536
565
|
visited,
|
|
537
566
|
timeout = READ_TIMEOUT_MS,
|
|
567
|
+
// Network-aware read: skip Gun's cold synchronous `undefined` and wait
|
|
568
|
+
// (up to `timeout`) for a peer to answer. Used by hologram soul
|
|
569
|
+
// resolution so cross-holon reads aren't misreported as missing. See
|
|
570
|
+
// `onceWithTimeout`. Off by default to keep same-holon reads fast.
|
|
571
|
+
awaitNetwork = false,
|
|
538
572
|
// `_deleted: true` is the soft-tombstone convention used by the bot,
|
|
539
573
|
// the web dashboard, and the MCP council tools. Pre-this fix the
|
|
540
574
|
// library was unaware of it and every caller filtered defensively.
|
|
@@ -661,7 +695,7 @@ export async function get(holoInstance, holon, lens, key, password = null, optio
|
|
|
661
695
|
// `.once()` wrapped in a deadline — cold-path reads (peer offline,
|
|
662
696
|
// never-written key) used to hang forever otherwise. After
|
|
663
697
|
// `timeout` ms with no Gun response we treat it as "not found".
|
|
664
|
-
onceWithTimeout(dataPath, timeout).then(handleData);
|
|
698
|
+
onceWithTimeout(dataPath, timeout, { awaitNetwork }).then(handleData);
|
|
665
699
|
});
|
|
666
700
|
} catch (error) {
|
|
667
701
|
console.error('Error in get:', error);
|
package/federation.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as h3 from 'h3-js';
|
|
7
|
-
import { attachHologramMeta } from './hologram.js';
|
|
7
|
+
import { attachHologramMeta, parseSoulPath } from './hologram.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Look up a holon's display name from its `settings` lens.
|
|
@@ -887,11 +887,32 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
|
|
|
887
887
|
};
|
|
888
888
|
}
|
|
889
889
|
|
|
890
|
-
//
|
|
891
|
-
//
|
|
892
|
-
//
|
|
893
|
-
|
|
890
|
+
// Never write a hologram to the holon its soul
|
|
891
|
+
// already points at — that overwrites the original
|
|
892
|
+
// record with a pointer to itself (a circular
|
|
893
|
+
// hologram that can never resolve, so get() logs
|
|
894
|
+
// "CIRCULAR … Breaking loop" forever). Two cases:
|
|
895
|
+
// • target === source: the source already holds
|
|
896
|
+
// the original; don't self-hologram it.
|
|
897
|
+
// • forwarding a RECEIVED hologram back toward its
|
|
898
|
+
// birthplace via a third hop (A→B propagates,
|
|
899
|
+
// then B→A federation echoes the hologram — whose
|
|
900
|
+
// soul still points at A — home). The plain
|
|
901
|
+
// `target === holon` check misses this because
|
|
902
|
+
// here `holon` is B, not A.
|
|
903
|
+
const soulTargetHolon =
|
|
904
|
+
payloadToPut && typeof payloadToPut.soul === 'string'
|
|
905
|
+
? parseSoulPath(payloadToPut.soul)?.holon
|
|
906
|
+
: null;
|
|
907
|
+
if (
|
|
908
|
+
String(targetSpace) === String(holon) ||
|
|
909
|
+
(soulTargetHolon != null &&
|
|
910
|
+
String(soulTargetHolon) === String(targetSpace))
|
|
911
|
+
) {
|
|
894
912
|
result.skipped++;
|
|
913
|
+
result.messages.push(
|
|
914
|
+
`Skipped self-referential propagation of ${data.id} to ${targetSpace} (hologram soul already points there).`
|
|
915
|
+
);
|
|
895
916
|
return true;
|
|
896
917
|
}
|
|
897
918
|
|
|
@@ -1018,10 +1039,31 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
|
|
|
1018
1039
|
};
|
|
1019
1040
|
}
|
|
1020
1041
|
|
|
1042
|
+
// Same self-reference guard as partner
|
|
1043
|
+
// propagation: never write a hologram to the
|
|
1044
|
+
// holon its soul points at (would create a
|
|
1045
|
+
// circular self-pointer that can never resolve).
|
|
1046
|
+
const soulTargetHolonParent =
|
|
1047
|
+
payloadToPut && typeof payloadToPut.soul === 'string'
|
|
1048
|
+
? parseSoulPath(payloadToPut.soul)?.holon
|
|
1049
|
+
: null;
|
|
1050
|
+
if (
|
|
1051
|
+
String(parentHexagon) === String(holon) ||
|
|
1052
|
+
(soulTargetHolonParent != null &&
|
|
1053
|
+
String(soulTargetHolonParent) === String(parentHexagon))
|
|
1054
|
+
) {
|
|
1055
|
+
result.parentPropagation.skipped =
|
|
1056
|
+
(result.parentPropagation.skipped || 0) + 1;
|
|
1057
|
+
result.parentPropagation.messages.push(
|
|
1058
|
+
`Skipped self-referential parent propagation of ${data.id} to ${parentHexagon} (hologram soul already points there).`
|
|
1059
|
+
);
|
|
1060
|
+
return true;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1021
1063
|
// Store in the parent hexagon with redirection disabled and no further auto-propagation
|
|
1022
|
-
await holosphere.put(parentHexagon, lens, payloadToPut, null, {
|
|
1023
|
-
disableHologramRedirection: true,
|
|
1024
|
-
autoPropagate: false
|
|
1064
|
+
await holosphere.put(parentHexagon, lens, payloadToPut, null, {
|
|
1065
|
+
disableHologramRedirection: true,
|
|
1066
|
+
autoPropagate: false
|
|
1025
1067
|
});
|
|
1026
1068
|
|
|
1027
1069
|
console.log(`[Federation] Successfully propagated to parent hexagon: ${parentHexagon}`);
|
package/hologram.js
CHANGED
|
@@ -168,7 +168,13 @@ export async function resolveHologram(holoInstance, hologram, options = {}) {
|
|
|
168
168
|
resolveHolograms: followHolograms,
|
|
169
169
|
visited: nextVisited,
|
|
170
170
|
maxDepth: maxDepth,
|
|
171
|
-
currentDepth: currentDepth + 1
|
|
171
|
+
currentDepth: currentDepth + 1,
|
|
172
|
+
// The soul almost always points at a DIFFERENT holon's lens
|
|
173
|
+
// this peer never subscribed to, so the node is cold: Gun's
|
|
174
|
+
// `.once()` would fire `undefined` synchronously and we'd
|
|
175
|
+
// wrongly report "target not present locally". Wait for the
|
|
176
|
+
// network round-trip instead.
|
|
177
|
+
awaitNetwork: true
|
|
172
178
|
}
|
|
173
179
|
);
|
|
174
180
|
|
package/holosphere-bundle.esm.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HoloSphere ESM Bundle v1.3.0-
|
|
2
|
+
* HoloSphere ESM Bundle v1.3.0-alpha9
|
|
3
3
|
* ES6 Module version with all dependencies bundled
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
|
-
* import HoloSphere from 'https://unpkg.com/holosphere@1.3.0-
|
|
6
|
+
* import HoloSphere from 'https://unpkg.com/holosphere@1.3.0-alpha9/holosphere-bundle.esm.js';
|
|
7
7
|
* const hs = new HoloSphere('myapp');
|
|
8
8
|
*/
|
|
9
9
|
var __create = Object.create;
|
|
@@ -24385,7 +24385,13 @@ async function resolveHologram(holoInstance, hologram, options = {}) {
|
|
|
24385
24385
|
resolveHolograms: followHolograms,
|
|
24386
24386
|
visited: nextVisited,
|
|
24387
24387
|
maxDepth,
|
|
24388
|
-
currentDepth: currentDepth + 1
|
|
24388
|
+
currentDepth: currentDepth + 1,
|
|
24389
|
+
// The soul almost always points at a DIFFERENT holon's lens
|
|
24390
|
+
// this peer never subscribed to, so the node is cold: Gun's
|
|
24391
|
+
// `.once()` would fire `undefined` synchronously and we'd
|
|
24392
|
+
// wrongly report "target not present locally". Wait for the
|
|
24393
|
+
// network round-trip instead.
|
|
24394
|
+
awaitNetwork: true
|
|
24389
24395
|
}
|
|
24390
24396
|
);
|
|
24391
24397
|
if (originalData && !originalData._invalidHologram) {
|
|
@@ -25012,8 +25018,12 @@ async function propagate(holosphere, holon, lens, data, options = {}) {
|
|
|
25012
25018
|
}
|
|
25013
25019
|
};
|
|
25014
25020
|
}
|
|
25015
|
-
|
|
25021
|
+
const soulTargetHolon = payloadToPut && typeof payloadToPut.soul === "string" ? parseSoulPath(payloadToPut.soul)?.holon : null;
|
|
25022
|
+
if (String(targetSpace) === String(holon) || soulTargetHolon != null && String(soulTargetHolon) === String(targetSpace)) {
|
|
25016
25023
|
result.skipped++;
|
|
25024
|
+
result.messages.push(
|
|
25025
|
+
`Skipped self-referential propagation of ${data.id} to ${targetSpace} (hologram soul already points there).`
|
|
25026
|
+
);
|
|
25017
25027
|
return true;
|
|
25018
25028
|
}
|
|
25019
25029
|
await holosphere.put(targetSpace, lens, payloadToPut, null, {
|
|
@@ -25116,6 +25126,14 @@ async function propagate(holosphere, holon, lens, data, options = {}) {
|
|
|
25116
25126
|
}
|
|
25117
25127
|
};
|
|
25118
25128
|
}
|
|
25129
|
+
const soulTargetHolonParent = payloadToPut && typeof payloadToPut.soul === "string" ? parseSoulPath(payloadToPut.soul)?.holon : null;
|
|
25130
|
+
if (String(parentHexagon) === String(holon) || soulTargetHolonParent != null && String(soulTargetHolonParent) === String(parentHexagon)) {
|
|
25131
|
+
result.parentPropagation.skipped = (result.parentPropagation.skipped || 0) + 1;
|
|
25132
|
+
result.parentPropagation.messages.push(
|
|
25133
|
+
`Skipped self-referential parent propagation of ${data.id} to ${parentHexagon} (hologram soul already points there).`
|
|
25134
|
+
);
|
|
25135
|
+
return true;
|
|
25136
|
+
}
|
|
25119
25137
|
await holosphere.put(parentHexagon, lens, payloadToPut, null, {
|
|
25120
25138
|
disableHologramRedirection: true,
|
|
25121
25139
|
autoPropagate: false
|
|
@@ -25366,16 +25384,41 @@ function clearSchemaCache(holoInstance, lens = null) {
|
|
|
25366
25384
|
// content.js
|
|
25367
25385
|
var READ_TIMEOUT_MS = 8e3;
|
|
25368
25386
|
var WRITE_TIMEOUT_MS = 5e3;
|
|
25369
|
-
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS) {
|
|
25387
|
+
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS, { awaitNetwork = false } = {}) {
|
|
25388
|
+
if (!awaitNetwork) {
|
|
25389
|
+
return new Promise((resolve) => {
|
|
25390
|
+
let done = false;
|
|
25391
|
+
const finish = (v) => {
|
|
25392
|
+
if (!done) {
|
|
25393
|
+
done = true;
|
|
25394
|
+
resolve(v);
|
|
25395
|
+
}
|
|
25396
|
+
};
|
|
25397
|
+
node.once((data) => finish(data));
|
|
25398
|
+
if (timeoutMs > 0) {
|
|
25399
|
+
setTimeout(() => finish(null), timeoutMs);
|
|
25400
|
+
}
|
|
25401
|
+
});
|
|
25402
|
+
}
|
|
25370
25403
|
return new Promise((resolve) => {
|
|
25371
25404
|
let done = false;
|
|
25405
|
+
const detach = () => {
|
|
25406
|
+
try {
|
|
25407
|
+
if (node.off) node.off();
|
|
25408
|
+
} catch {
|
|
25409
|
+
}
|
|
25410
|
+
};
|
|
25372
25411
|
const finish = (v) => {
|
|
25373
25412
|
if (!done) {
|
|
25374
25413
|
done = true;
|
|
25414
|
+
detach();
|
|
25375
25415
|
resolve(v);
|
|
25376
25416
|
}
|
|
25377
25417
|
};
|
|
25378
|
-
node.
|
|
25418
|
+
node.on((data) => {
|
|
25419
|
+
if (data === void 0) return;
|
|
25420
|
+
finish(data);
|
|
25421
|
+
});
|
|
25379
25422
|
if (timeoutMs > 0) {
|
|
25380
25423
|
setTimeout(() => finish(null), timeoutMs);
|
|
25381
25424
|
}
|
|
@@ -25716,6 +25759,11 @@ async function get(holoInstance, holon, lens, key, password = null, options = {}
|
|
|
25716
25759
|
validationOptions = {},
|
|
25717
25760
|
visited,
|
|
25718
25761
|
timeout = READ_TIMEOUT_MS,
|
|
25762
|
+
// Network-aware read: skip Gun's cold synchronous `undefined` and wait
|
|
25763
|
+
// (up to `timeout`) for a peer to answer. Used by hologram soul
|
|
25764
|
+
// resolution so cross-holon reads aren't misreported as missing. See
|
|
25765
|
+
// `onceWithTimeout`. Off by default to keep same-holon reads fast.
|
|
25766
|
+
awaitNetwork = false,
|
|
25719
25767
|
// `_deleted: true` is the soft-tombstone convention used by the bot,
|
|
25720
25768
|
// the web dashboard, and the MCP council tools. Pre-this fix the
|
|
25721
25769
|
// library was unaware of it and every caller filtered defensively.
|
|
@@ -25801,7 +25849,7 @@ async function get(holoInstance, holon, lens, key, password = null, options = {}
|
|
|
25801
25849
|
}
|
|
25802
25850
|
};
|
|
25803
25851
|
const dataPath = password ? user.get("private").get(lens).get(key) : holoInstance.gun.get(holoInstance.appname).get(holon).get(lens).get(key);
|
|
25804
|
-
onceWithTimeout(dataPath, timeout).then(handleData);
|
|
25852
|
+
onceWithTimeout(dataPath, timeout, { awaitNetwork }).then(handleData);
|
|
25805
25853
|
});
|
|
25806
25854
|
} catch (error) {
|
|
25807
25855
|
console.error("Error in get:", error);
|
|
@@ -27234,7 +27282,11 @@ function subscribe(holoInstance, holon, lens, callback) {
|
|
|
27234
27282
|
try {
|
|
27235
27283
|
let parsed = await holoInstance.parse(data);
|
|
27236
27284
|
if (parsed && holoInstance.isHologram(parsed)) {
|
|
27285
|
+
const hologramSoul = parsed.soul;
|
|
27237
27286
|
const resolved = await holoInstance.resolveHologram(parsed, { followHolograms: true });
|
|
27287
|
+
if (resolved === null) {
|
|
27288
|
+
console.warn(`Hologram at ${holon}/${lens}/${key} did not resolve (soul=${hologramSoul}); skipping.`);
|
|
27289
|
+
}
|
|
27238
27290
|
if (resolved !== parsed) {
|
|
27239
27291
|
parsed = resolved;
|
|
27240
27292
|
}
|
package/holosphere-bundle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HoloSphere Bundle v1.3.0-
|
|
2
|
+
* HoloSphere Bundle v1.3.0-alpha9
|
|
3
3
|
* Holonic Geospatial Communication Infrastructure
|
|
4
4
|
*
|
|
5
5
|
* Includes:
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Ajv (JSON schema validation)
|
|
10
10
|
*
|
|
11
11
|
* Usage:
|
|
12
|
-
* <script src="https://unpkg.com/holosphere@1.3.0-
|
|
12
|
+
* <script src="https://unpkg.com/holosphere@1.3.0-alpha9/holosphere-bundle.js"></script>
|
|
13
13
|
* <script>
|
|
14
14
|
* const hs = new HoloSphere('myapp');
|
|
15
15
|
* </script>
|
|
@@ -24411,7 +24411,13 @@ var HoloSphere = (() => {
|
|
|
24411
24411
|
resolveHolograms: followHolograms,
|
|
24412
24412
|
visited: nextVisited,
|
|
24413
24413
|
maxDepth,
|
|
24414
|
-
currentDepth: currentDepth + 1
|
|
24414
|
+
currentDepth: currentDepth + 1,
|
|
24415
|
+
// The soul almost always points at a DIFFERENT holon's lens
|
|
24416
|
+
// this peer never subscribed to, so the node is cold: Gun's
|
|
24417
|
+
// `.once()` would fire `undefined` synchronously and we'd
|
|
24418
|
+
// wrongly report "target not present locally". Wait for the
|
|
24419
|
+
// network round-trip instead.
|
|
24420
|
+
awaitNetwork: true
|
|
24415
24421
|
}
|
|
24416
24422
|
);
|
|
24417
24423
|
if (originalData && !originalData._invalidHologram) {
|
|
@@ -25038,8 +25044,12 @@ var HoloSphere = (() => {
|
|
|
25038
25044
|
}
|
|
25039
25045
|
};
|
|
25040
25046
|
}
|
|
25041
|
-
|
|
25047
|
+
const soulTargetHolon = payloadToPut && typeof payloadToPut.soul === "string" ? parseSoulPath(payloadToPut.soul)?.holon : null;
|
|
25048
|
+
if (String(targetSpace) === String(holon) || soulTargetHolon != null && String(soulTargetHolon) === String(targetSpace)) {
|
|
25042
25049
|
result.skipped++;
|
|
25050
|
+
result.messages.push(
|
|
25051
|
+
`Skipped self-referential propagation of ${data.id} to ${targetSpace} (hologram soul already points there).`
|
|
25052
|
+
);
|
|
25043
25053
|
return true;
|
|
25044
25054
|
}
|
|
25045
25055
|
await holosphere.put(targetSpace, lens, payloadToPut, null, {
|
|
@@ -25142,6 +25152,14 @@ var HoloSphere = (() => {
|
|
|
25142
25152
|
}
|
|
25143
25153
|
};
|
|
25144
25154
|
}
|
|
25155
|
+
const soulTargetHolonParent = payloadToPut && typeof payloadToPut.soul === "string" ? parseSoulPath(payloadToPut.soul)?.holon : null;
|
|
25156
|
+
if (String(parentHexagon) === String(holon) || soulTargetHolonParent != null && String(soulTargetHolonParent) === String(parentHexagon)) {
|
|
25157
|
+
result.parentPropagation.skipped = (result.parentPropagation.skipped || 0) + 1;
|
|
25158
|
+
result.parentPropagation.messages.push(
|
|
25159
|
+
`Skipped self-referential parent propagation of ${data.id} to ${parentHexagon} (hologram soul already points there).`
|
|
25160
|
+
);
|
|
25161
|
+
return true;
|
|
25162
|
+
}
|
|
25145
25163
|
await holosphere.put(parentHexagon, lens, payloadToPut, null, {
|
|
25146
25164
|
disableHologramRedirection: true,
|
|
25147
25165
|
autoPropagate: false
|
|
@@ -25392,16 +25410,41 @@ var HoloSphere = (() => {
|
|
|
25392
25410
|
// content.js
|
|
25393
25411
|
var READ_TIMEOUT_MS = 8e3;
|
|
25394
25412
|
var WRITE_TIMEOUT_MS = 5e3;
|
|
25395
|
-
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS) {
|
|
25413
|
+
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS, { awaitNetwork = false } = {}) {
|
|
25414
|
+
if (!awaitNetwork) {
|
|
25415
|
+
return new Promise((resolve) => {
|
|
25416
|
+
let done = false;
|
|
25417
|
+
const finish = (v) => {
|
|
25418
|
+
if (!done) {
|
|
25419
|
+
done = true;
|
|
25420
|
+
resolve(v);
|
|
25421
|
+
}
|
|
25422
|
+
};
|
|
25423
|
+
node.once((data) => finish(data));
|
|
25424
|
+
if (timeoutMs > 0) {
|
|
25425
|
+
setTimeout(() => finish(null), timeoutMs);
|
|
25426
|
+
}
|
|
25427
|
+
});
|
|
25428
|
+
}
|
|
25396
25429
|
return new Promise((resolve) => {
|
|
25397
25430
|
let done = false;
|
|
25431
|
+
const detach = () => {
|
|
25432
|
+
try {
|
|
25433
|
+
if (node.off) node.off();
|
|
25434
|
+
} catch {
|
|
25435
|
+
}
|
|
25436
|
+
};
|
|
25398
25437
|
const finish = (v) => {
|
|
25399
25438
|
if (!done) {
|
|
25400
25439
|
done = true;
|
|
25440
|
+
detach();
|
|
25401
25441
|
resolve(v);
|
|
25402
25442
|
}
|
|
25403
25443
|
};
|
|
25404
|
-
node.
|
|
25444
|
+
node.on((data) => {
|
|
25445
|
+
if (data === void 0) return;
|
|
25446
|
+
finish(data);
|
|
25447
|
+
});
|
|
25405
25448
|
if (timeoutMs > 0) {
|
|
25406
25449
|
setTimeout(() => finish(null), timeoutMs);
|
|
25407
25450
|
}
|
|
@@ -25742,6 +25785,11 @@ var HoloSphere = (() => {
|
|
|
25742
25785
|
validationOptions = {},
|
|
25743
25786
|
visited,
|
|
25744
25787
|
timeout = READ_TIMEOUT_MS,
|
|
25788
|
+
// Network-aware read: skip Gun's cold synchronous `undefined` and wait
|
|
25789
|
+
// (up to `timeout`) for a peer to answer. Used by hologram soul
|
|
25790
|
+
// resolution so cross-holon reads aren't misreported as missing. See
|
|
25791
|
+
// `onceWithTimeout`. Off by default to keep same-holon reads fast.
|
|
25792
|
+
awaitNetwork = false,
|
|
25745
25793
|
// `_deleted: true` is the soft-tombstone convention used by the bot,
|
|
25746
25794
|
// the web dashboard, and the MCP council tools. Pre-this fix the
|
|
25747
25795
|
// library was unaware of it and every caller filtered defensively.
|
|
@@ -25827,7 +25875,7 @@ var HoloSphere = (() => {
|
|
|
25827
25875
|
}
|
|
25828
25876
|
};
|
|
25829
25877
|
const dataPath = password ? user.get("private").get(lens).get(key) : holoInstance.gun.get(holoInstance.appname).get(holon).get(lens).get(key);
|
|
25830
|
-
onceWithTimeout(dataPath, timeout).then(handleData);
|
|
25878
|
+
onceWithTimeout(dataPath, timeout, { awaitNetwork }).then(handleData);
|
|
25831
25879
|
});
|
|
25832
25880
|
} catch (error) {
|
|
25833
25881
|
console.error("Error in get:", error);
|
|
@@ -27260,7 +27308,11 @@ var HoloSphere = (() => {
|
|
|
27260
27308
|
try {
|
|
27261
27309
|
let parsed = await holoInstance.parse(data);
|
|
27262
27310
|
if (parsed && holoInstance.isHologram(parsed)) {
|
|
27311
|
+
const hologramSoul = parsed.soul;
|
|
27263
27312
|
const resolved = await holoInstance.resolveHologram(parsed, { followHolograms: true });
|
|
27313
|
+
if (resolved === null) {
|
|
27314
|
+
console.warn(`Hologram at ${holon}/${lens}/${key} did not resolve (soul=${hologramSoul}); skipping.`);
|
|
27315
|
+
}
|
|
27264
27316
|
if (resolved !== parsed) {
|
|
27265
27317
|
parsed = resolved;
|
|
27266
27318
|
}
|