holosphere 1.3.0-alpha5 → 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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * HoloSphere Bundle v1.3.0-alpha5
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-alpha5/holosphere-bundle.js"></script>
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) {
@@ -25391,21 +25397,64 @@ var HoloSphere = (() => {
25391
25397
 
25392
25398
  // content.js
25393
25399
  var READ_TIMEOUT_MS = 8e3;
25394
- function onceWithTimeout(node, timeoutMs = READ_TIMEOUT_MS) {
25400
+ var WRITE_TIMEOUT_MS = 5e3;
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
+ }
25395
25417
  return new Promise((resolve) => {
25396
25418
  let done = false;
25419
+ const detach = () => {
25420
+ try {
25421
+ if (node.off) node.off();
25422
+ } catch {
25423
+ }
25424
+ };
25397
25425
  const finish = (v) => {
25398
25426
  if (!done) {
25399
25427
  done = true;
25428
+ detach();
25400
25429
  resolve(v);
25401
25430
  }
25402
25431
  };
25403
- node.once((data) => finish(data));
25432
+ node.on((data) => {
25433
+ if (data === void 0) return;
25434
+ finish(data);
25435
+ });
25404
25436
  if (timeoutMs > 0) {
25405
25437
  setTimeout(() => finish(null), timeoutMs);
25406
25438
  }
25407
25439
  });
25408
25440
  }
25441
+ function withWriteTimeout(promise, timeoutMs, queuedResult) {
25442
+ if (!timeoutMs || timeoutMs <= 0) return promise;
25443
+ return new Promise((resolve, reject) => {
25444
+ let done = false;
25445
+ const finish = (fn, val) => {
25446
+ if (!done) {
25447
+ done = true;
25448
+ fn(val);
25449
+ }
25450
+ };
25451
+ promise.then(
25452
+ (v) => finish(resolve, v),
25453
+ (e) => finish(reject, e)
25454
+ );
25455
+ setTimeout(() => finish(resolve, queuedResult), timeoutMs);
25456
+ });
25457
+ }
25409
25458
  function sanitizeForStorage(value, path = "", seen = /* @__PURE__ */ new WeakSet(), warnings = []) {
25410
25459
  if (value === null) return null;
25411
25460
  const t = typeof value;
@@ -25452,7 +25501,11 @@ var HoloSphere = (() => {
25452
25501
  if (!holon || !lens) {
25453
25502
  throw new Error("put: Missing required holon or lens parameters:", holon, lens);
25454
25503
  }
25455
- const { disableHologramRedirection = false } = options;
25504
+ const {
25505
+ disableHologramRedirection = false,
25506
+ timeout: writeTimeoutOverride
25507
+ } = options;
25508
+ const writeTimeoutMs = writeTimeoutOverride !== void 0 ? writeTimeoutOverride : WRITE_TIMEOUT_MS;
25456
25509
  let targetHolon = holon;
25457
25510
  let targetLens = lens;
25458
25511
  let targetKey = data.id;
@@ -25540,7 +25593,7 @@ var HoloSphere = (() => {
25540
25593
  });
25541
25594
  });
25542
25595
  }
25543
- return new Promise((resolve, reject) => {
25596
+ const ackPromise = new Promise((resolve, reject) => {
25544
25597
  try {
25545
25598
  const sanitizeWarnings = [];
25546
25599
  let dataToStore = sanitizeForStorage(data, "", /* @__PURE__ */ new WeakSet(), sanitizeWarnings) || {};
@@ -25573,16 +25626,17 @@ var HoloSphere = (() => {
25573
25626
  }
25574
25627
  }
25575
25628
  let updatedHolograms = [];
25576
- if (!isHologram2 && !options.isHologramUpdate) {
25629
+ const currentDataSoul = `${holoInstance.appname}/${targetHolon}/${targetLens}/${targetKey}`;
25630
+ const cascadeVisited = new Set(options._cascadeVisited || []);
25631
+ if (!cascadeVisited.has(currentDataSoul)) {
25632
+ cascadeVisited.add(currentDataSoul);
25577
25633
  try {
25578
- const currentDataSoul = `${holoInstance.appname}/${targetHolon}/${targetLens}/${targetKey}`;
25579
25634
  const currentNodeRef = holoInstance.getNodeRef(currentDataSoul);
25580
25635
  await new Promise((resolveHologramUpdate) => {
25581
25636
  currentNodeRef.get("_holograms").once(async (hologramsSet) => {
25582
25637
  if (hologramsSet) {
25583
25638
  const hologramSouls = Object.keys(hologramsSet).filter(
25584
- (k) => k !== "_" && hologramsSet[k] === true
25585
- // Only active holograms (deleted ones are null/removed)
25639
+ (k) => k !== "_" && hologramsSet[k] === true && !cascadeVisited.has(k)
25586
25640
  );
25587
25641
  if (hologramSouls.length > 0) {
25588
25642
  const updatePromises = hologramSouls.map(async (hologramSoul) => {
@@ -25611,8 +25665,12 @@ var HoloSphere = (() => {
25611
25665
  // Don't auto-propagate hologram updates
25612
25666
  disableHologramRedirection: true,
25613
25667
  // Prevent redirection when updating holograms
25614
- isHologramUpdate: true
25615
- // Prevent recursive hologram updates
25668
+ isHologramUpdate: true,
25669
+ // Carry the visited set forward so the
25670
+ // recursive put keeps cascading through
25671
+ // this hop's `_holograms` set without
25672
+ // looping back through us.
25673
+ _cascadeVisited: cascadeVisited
25616
25674
  }
25617
25675
  );
25618
25676
  updatedHolograms.push({
@@ -25690,6 +25748,16 @@ var HoloSphere = (() => {
25690
25748
  reject(error);
25691
25749
  }
25692
25750
  });
25751
+ return withWriteTimeout(ackPromise, writeTimeoutMs, {
25752
+ success: true,
25753
+ queued: true,
25754
+ isHologramAtPath: isHologram2,
25755
+ pathHolon: targetHolon,
25756
+ pathLens: targetLens,
25757
+ pathKey: targetKey,
25758
+ propagationResult: null,
25759
+ updatedHolograms: []
25760
+ });
25693
25761
  } catch (error) {
25694
25762
  console.error("Error in put:", error);
25695
25763
  throw error;
@@ -25705,6 +25773,11 @@ var HoloSphere = (() => {
25705
25773
  validationOptions = {},
25706
25774
  visited,
25707
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,
25708
25781
  // `_deleted: true` is the soft-tombstone convention used by the bot,
25709
25782
  // the web dashboard, and the MCP council tools. Pre-this fix the
25710
25783
  // library was unaware of it and every caller filtered defensively.
@@ -25790,7 +25863,7 @@ var HoloSphere = (() => {
25790
25863
  }
25791
25864
  };
25792
25865
  const dataPath = password ? user.get("private").get(lens).get(key) : holoInstance.gun.get(holoInstance.appname).get(holon).get(lens).get(key);
25793
- onceWithTimeout(dataPath, timeout).then(handleData);
25866
+ onceWithTimeout(dataPath, timeout, { awaitNetwork }).then(handleData);
25794
25867
  });
25795
25868
  } catch (error) {
25796
25869
  console.error("Error in get:", error);
@@ -26362,7 +26435,25 @@ var HoloSphere = (() => {
26362
26435
  }
26363
26436
 
26364
26437
  // global.js
26365
- async function putGlobal(holoInstance, tableName, data, password = null) {
26438
+ var WRITE_TIMEOUT_MS2 = 5e3;
26439
+ function withWriteTimeout2(promise, timeoutMs, queuedResult) {
26440
+ if (!timeoutMs || timeoutMs <= 0) return promise;
26441
+ return new Promise((resolve, reject) => {
26442
+ let done = false;
26443
+ const finish = (fn, val) => {
26444
+ if (!done) {
26445
+ done = true;
26446
+ fn(val);
26447
+ }
26448
+ };
26449
+ promise.then(
26450
+ (v) => finish(resolve, v),
26451
+ (e) => finish(reject, e)
26452
+ );
26453
+ setTimeout(() => finish(resolve, queuedResult), timeoutMs);
26454
+ });
26455
+ }
26456
+ async function putGlobal(holoInstance, tableName, data, password = null, options = {}) {
26366
26457
  try {
26367
26458
  if (!tableName || !data) {
26368
26459
  throw new Error("Table name and data are required");
@@ -26409,7 +26500,8 @@ var HoloSphere = (() => {
26409
26500
  });
26410
26501
  });
26411
26502
  }
26412
- return new Promise((resolve, reject) => {
26503
+ const writeTimeoutMs = options.timeout !== void 0 ? options.timeout : WRITE_TIMEOUT_MS2;
26504
+ const ackPromise = new Promise((resolve, reject) => {
26413
26505
  try {
26414
26506
  let dataToStore = { ...data };
26415
26507
  if (dataToStore._meta !== void 0) {
@@ -26471,6 +26563,17 @@ var HoloSphere = (() => {
26471
26563
  reject(error);
26472
26564
  }
26473
26565
  });
26566
+ const ACK_OK = Symbol("ackOk");
26567
+ return withWriteTimeout2(
26568
+ ackPromise.then(() => ACK_OK),
26569
+ writeTimeoutMs,
26570
+ void 0
26571
+ ).then((result) => {
26572
+ if (result !== ACK_OK) {
26573
+ console.warn(`putGlobal: no ack within ${writeTimeoutMs}ms for table=${tableName} \u2014 write queued locally, will replay on reconnect`);
26574
+ }
26575
+ return void 0;
26576
+ });
26474
26577
  } catch (error) {
26475
26578
  console.error("Error in putGlobal:", error);
26476
26579
  throw error;
@@ -27193,7 +27296,11 @@ var HoloSphere = (() => {
27193
27296
  try {
27194
27297
  let parsed = await holoInstance.parse(data);
27195
27298
  if (parsed && holoInstance.isHologram(parsed)) {
27299
+ const hologramSoul = parsed.soul;
27196
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
+ }
27197
27304
  if (resolved !== parsed) {
27198
27305
  parsed = resolved;
27199
27306
  }
@@ -30554,14 +30661,14 @@ var HoloSphere = (() => {
30554
30661
  return deleteNode(this, holon, lens, key);
30555
30662
  }
30556
30663
  // ================================ GLOBAL FUNCTIONS ================================
30557
- async putGlobal(tableName, data, password = null) {
30558
- return putGlobal(this, tableName, data, password);
30664
+ async putGlobal(tableName, data, password = null, options = {}) {
30665
+ return putGlobal(this, tableName, data, password, options);
30559
30666
  }
30560
30667
  /**
30561
30668
  * v2-compatible alias for putGlobal (no password param)
30562
30669
  */
30563
- async writeGlobal(tableName, data) {
30564
- return putGlobal(this, tableName, data, null);
30670
+ async writeGlobal(tableName, data, options = {}) {
30671
+ return putGlobal(this, tableName, data, null, options);
30565
30672
  }
30566
30673
  async getGlobal(tableName, key, password = null) {
30567
30674
  return getGlobal(this, tableName, key, password);