holosphere 1.3.0-alpha7 → 1.3.0-alpha8
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/hologram.js +7 -1
- package/holosphere-bundle.esm.js +46 -6
- package/holosphere-bundle.js +46 -6
- 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/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-alpha8
|
|
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-alpha8/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) {
|
|
@@ -25366,16 +25372,41 @@ function clearSchemaCache(holoInstance, lens = null) {
|
|
|
25366
25372
|
// content.js
|
|
25367
25373
|
var READ_TIMEOUT_MS = 8e3;
|
|
25368
25374
|
var WRITE_TIMEOUT_MS = 5e3;
|
|
25369
|
-
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS) {
|
|
25375
|
+
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS, { awaitNetwork = false } = {}) {
|
|
25376
|
+
if (!awaitNetwork) {
|
|
25377
|
+
return new Promise((resolve) => {
|
|
25378
|
+
let done = false;
|
|
25379
|
+
const finish = (v) => {
|
|
25380
|
+
if (!done) {
|
|
25381
|
+
done = true;
|
|
25382
|
+
resolve(v);
|
|
25383
|
+
}
|
|
25384
|
+
};
|
|
25385
|
+
node.once((data) => finish(data));
|
|
25386
|
+
if (timeoutMs > 0) {
|
|
25387
|
+
setTimeout(() => finish(null), timeoutMs);
|
|
25388
|
+
}
|
|
25389
|
+
});
|
|
25390
|
+
}
|
|
25370
25391
|
return new Promise((resolve) => {
|
|
25371
25392
|
let done = false;
|
|
25393
|
+
const detach = () => {
|
|
25394
|
+
try {
|
|
25395
|
+
if (node.off) node.off();
|
|
25396
|
+
} catch {
|
|
25397
|
+
}
|
|
25398
|
+
};
|
|
25372
25399
|
const finish = (v) => {
|
|
25373
25400
|
if (!done) {
|
|
25374
25401
|
done = true;
|
|
25402
|
+
detach();
|
|
25375
25403
|
resolve(v);
|
|
25376
25404
|
}
|
|
25377
25405
|
};
|
|
25378
|
-
node.
|
|
25406
|
+
node.on((data) => {
|
|
25407
|
+
if (data === void 0) return;
|
|
25408
|
+
finish(data);
|
|
25409
|
+
});
|
|
25379
25410
|
if (timeoutMs > 0) {
|
|
25380
25411
|
setTimeout(() => finish(null), timeoutMs);
|
|
25381
25412
|
}
|
|
@@ -25716,6 +25747,11 @@ async function get(holoInstance, holon, lens, key, password = null, options = {}
|
|
|
25716
25747
|
validationOptions = {},
|
|
25717
25748
|
visited,
|
|
25718
25749
|
timeout = READ_TIMEOUT_MS,
|
|
25750
|
+
// Network-aware read: skip Gun's cold synchronous `undefined` and wait
|
|
25751
|
+
// (up to `timeout`) for a peer to answer. Used by hologram soul
|
|
25752
|
+
// resolution so cross-holon reads aren't misreported as missing. See
|
|
25753
|
+
// `onceWithTimeout`. Off by default to keep same-holon reads fast.
|
|
25754
|
+
awaitNetwork = false,
|
|
25719
25755
|
// `_deleted: true` is the soft-tombstone convention used by the bot,
|
|
25720
25756
|
// the web dashboard, and the MCP council tools. Pre-this fix the
|
|
25721
25757
|
// library was unaware of it and every caller filtered defensively.
|
|
@@ -25801,7 +25837,7 @@ async function get(holoInstance, holon, lens, key, password = null, options = {}
|
|
|
25801
25837
|
}
|
|
25802
25838
|
};
|
|
25803
25839
|
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);
|
|
25840
|
+
onceWithTimeout(dataPath, timeout, { awaitNetwork }).then(handleData);
|
|
25805
25841
|
});
|
|
25806
25842
|
} catch (error) {
|
|
25807
25843
|
console.error("Error in get:", error);
|
|
@@ -27234,7 +27270,11 @@ function subscribe(holoInstance, holon, lens, callback) {
|
|
|
27234
27270
|
try {
|
|
27235
27271
|
let parsed = await holoInstance.parse(data);
|
|
27236
27272
|
if (parsed && holoInstance.isHologram(parsed)) {
|
|
27273
|
+
const hologramSoul = parsed.soul;
|
|
27237
27274
|
const resolved = await holoInstance.resolveHologram(parsed, { followHolograms: true });
|
|
27275
|
+
if (resolved === null) {
|
|
27276
|
+
console.warn(`Hologram at ${holon}/${lens}/${key} did not resolve (soul=${hologramSoul}); skipping.`);
|
|
27277
|
+
}
|
|
27238
27278
|
if (resolved !== parsed) {
|
|
27239
27279
|
parsed = resolved;
|
|
27240
27280
|
}
|
package/holosphere-bundle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HoloSphere Bundle v1.3.0-
|
|
2
|
+
* HoloSphere Bundle v1.3.0-alpha8
|
|
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-alpha8/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) {
|
|
@@ -25392,16 +25398,41 @@ var HoloSphere = (() => {
|
|
|
25392
25398
|
// content.js
|
|
25393
25399
|
var READ_TIMEOUT_MS = 8e3;
|
|
25394
25400
|
var WRITE_TIMEOUT_MS = 5e3;
|
|
25395
|
-
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS) {
|
|
25401
|
+
function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS, { awaitNetwork = false } = {}) {
|
|
25402
|
+
if (!awaitNetwork) {
|
|
25403
|
+
return new Promise((resolve) => {
|
|
25404
|
+
let done = false;
|
|
25405
|
+
const finish = (v) => {
|
|
25406
|
+
if (!done) {
|
|
25407
|
+
done = true;
|
|
25408
|
+
resolve(v);
|
|
25409
|
+
}
|
|
25410
|
+
};
|
|
25411
|
+
node.once((data) => finish(data));
|
|
25412
|
+
if (timeoutMs > 0) {
|
|
25413
|
+
setTimeout(() => finish(null), timeoutMs);
|
|
25414
|
+
}
|
|
25415
|
+
});
|
|
25416
|
+
}
|
|
25396
25417
|
return new Promise((resolve) => {
|
|
25397
25418
|
let done = false;
|
|
25419
|
+
const detach = () => {
|
|
25420
|
+
try {
|
|
25421
|
+
if (node.off) node.off();
|
|
25422
|
+
} catch {
|
|
25423
|
+
}
|
|
25424
|
+
};
|
|
25398
25425
|
const finish = (v) => {
|
|
25399
25426
|
if (!done) {
|
|
25400
25427
|
done = true;
|
|
25428
|
+
detach();
|
|
25401
25429
|
resolve(v);
|
|
25402
25430
|
}
|
|
25403
25431
|
};
|
|
25404
|
-
node.
|
|
25432
|
+
node.on((data) => {
|
|
25433
|
+
if (data === void 0) return;
|
|
25434
|
+
finish(data);
|
|
25435
|
+
});
|
|
25405
25436
|
if (timeoutMs > 0) {
|
|
25406
25437
|
setTimeout(() => finish(null), timeoutMs);
|
|
25407
25438
|
}
|
|
@@ -25742,6 +25773,11 @@ var HoloSphere = (() => {
|
|
|
25742
25773
|
validationOptions = {},
|
|
25743
25774
|
visited,
|
|
25744
25775
|
timeout = READ_TIMEOUT_MS,
|
|
25776
|
+
// Network-aware read: skip Gun's cold synchronous `undefined` and wait
|
|
25777
|
+
// (up to `timeout`) for a peer to answer. Used by hologram soul
|
|
25778
|
+
// resolution so cross-holon reads aren't misreported as missing. See
|
|
25779
|
+
// `onceWithTimeout`. Off by default to keep same-holon reads fast.
|
|
25780
|
+
awaitNetwork = false,
|
|
25745
25781
|
// `_deleted: true` is the soft-tombstone convention used by the bot,
|
|
25746
25782
|
// the web dashboard, and the MCP council tools. Pre-this fix the
|
|
25747
25783
|
// library was unaware of it and every caller filtered defensively.
|
|
@@ -25827,7 +25863,7 @@ var HoloSphere = (() => {
|
|
|
25827
25863
|
}
|
|
25828
25864
|
};
|
|
25829
25865
|
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);
|
|
25866
|
+
onceWithTimeout(dataPath, timeout, { awaitNetwork }).then(handleData);
|
|
25831
25867
|
});
|
|
25832
25868
|
} catch (error) {
|
|
25833
25869
|
console.error("Error in get:", error);
|
|
@@ -27260,7 +27296,11 @@ var HoloSphere = (() => {
|
|
|
27260
27296
|
try {
|
|
27261
27297
|
let parsed = await holoInstance.parse(data);
|
|
27262
27298
|
if (parsed && holoInstance.isHologram(parsed)) {
|
|
27299
|
+
const hologramSoul = parsed.soul;
|
|
27263
27300
|
const resolved = await holoInstance.resolveHologram(parsed, { followHolograms: true });
|
|
27301
|
+
if (resolved === null) {
|
|
27302
|
+
console.warn(`Hologram at ${holon}/${lens}/${key} did not resolve (soul=${hologramSoul}); skipping.`);
|
|
27303
|
+
}
|
|
27264
27304
|
if (resolved !== parsed) {
|
|
27265
27305
|
parsed = resolved;
|
|
27266
27306
|
}
|