holosphere 1.3.0-alpha0 → 1.3.0-alpha4

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-alpha0
2
+ * HoloSphere Bundle v1.3.0-alpha4
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-alpha0/holosphere-bundle.js"></script>
12
+ * <script src="https://unpkg.com/holosphere@1.3.0-alpha4/holosphere-bundle.js"></script>
13
13
  * <script>
14
14
  * const hs = new HoloSphere('myapp');
15
15
  * </script>
@@ -7067,7 +7067,7 @@ var HoloSphere = (() => {
7067
7067
  constructor(opts = {}) {
7068
7068
  this.schemas = {};
7069
7069
  this.refs = {};
7070
- this.formats = {};
7070
+ this.formats = /* @__PURE__ */ Object.create(null);
7071
7071
  this._compilations = /* @__PURE__ */ new Set();
7072
7072
  this._loading = {};
7073
7073
  this._cache = /* @__PURE__ */ new Map();
@@ -7848,6 +7848,7 @@ var HoloSphere = (() => {
7848
7848
  "use strict";
7849
7849
  Object.defineProperty(exports, "__esModule", { value: true });
7850
7850
  var code_1 = require_code2();
7851
+ var util_1 = require_util();
7851
7852
  var codegen_1 = require_codegen();
7852
7853
  var error = {
7853
7854
  message: ({ schemaCode }) => (0, codegen_1.str)`must match pattern "${schemaCode}"`,
@@ -7860,10 +7861,18 @@ var HoloSphere = (() => {
7860
7861
  $data: true,
7861
7862
  error,
7862
7863
  code(cxt) {
7863
- const { data, $data, schema, schemaCode, it } = cxt;
7864
+ const { gen, data, $data, schema, schemaCode, it } = cxt;
7864
7865
  const u = it.opts.unicodeRegExp ? "u" : "";
7865
- const regExp = $data ? (0, codegen_1._)`(new RegExp(${schemaCode}, ${u}))` : (0, code_1.usePattern)(cxt, schema);
7866
- cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
7866
+ if ($data) {
7867
+ const { regExp } = it.opts.code;
7868
+ const regExpCode = regExp.code === "new RegExp" ? (0, codegen_1._)`new RegExp` : (0, util_1.useFunc)(gen, regExp);
7869
+ const valid = gen.let("valid");
7870
+ gen.try(() => gen.assign(valid, (0, codegen_1._)`${regExpCode}(${schemaCode}, ${u}).test(${data})`), () => gen.assign(valid, false));
7871
+ cxt.fail$data((0, codegen_1._)`!${valid}`);
7872
+ } else {
7873
+ const regExp = (0, code_1.usePattern)(cxt, schema);
7874
+ cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
7875
+ }
7867
7876
  }
7868
7877
  };
7869
7878
  exports.default = def;
@@ -10074,7 +10083,7 @@ var HoloSphere = (() => {
10074
10083
  var discriminator_1 = require_discriminator();
10075
10084
  var json_schema_2019_09_1 = require_json_schema_2019_09();
10076
10085
  var META_SCHEMA_ID = "https://json-schema.org/draft/2019-09/schema";
10077
- var Ajv20193 = class extends core_1.default {
10086
+ var Ajv20192 = class extends core_1.default {
10078
10087
  constructor(opts = {}) {
10079
10088
  super({
10080
10089
  ...opts,
@@ -10104,11 +10113,11 @@ var HoloSphere = (() => {
10104
10113
  return this.opts.defaultMeta = super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : void 0);
10105
10114
  }
10106
10115
  };
10107
- exports.Ajv2019 = Ajv20193;
10108
- module.exports = exports = Ajv20193;
10109
- module.exports.Ajv2019 = Ajv20193;
10116
+ exports.Ajv2019 = Ajv20192;
10117
+ module.exports = exports = Ajv20192;
10118
+ module.exports.Ajv2019 = Ajv20192;
10110
10119
  Object.defineProperty(exports, "__esModule", { value: true });
10111
- exports.default = Ajv20193;
10120
+ exports.default = Ajv20192;
10112
10121
  var validate_1 = require_validate();
10113
10122
  Object.defineProperty(exports, "KeywordCxt", { enumerable: true, get: function() {
10114
10123
  return validate_1.KeywordCxt;
@@ -24223,9 +24232,139 @@ var HoloSphere = (() => {
24223
24232
 
24224
24233
  // holosphere.js
24225
24234
  var import_gun = __toESM(require_browser(), 1);
24226
- var import__2 = __toESM(require__(), 1);
24235
+ var import__ = __toESM(require__(), 1);
24236
+
24237
+ // hologram.js
24238
+ function createHologram(holoInstance, holon, lens, data) {
24239
+ if (isHologram(data)) {
24240
+ return {
24241
+ id: data.id,
24242
+ soul: data.soul
24243
+ };
24244
+ }
24245
+ if (!holon || !lens || !data || !data.id) {
24246
+ throw new Error("createHologram: Missing required parameters for non-hologram data");
24247
+ }
24248
+ const soul = `${holoInstance.appname}/${holon}/${lens}/${data.id}`;
24249
+ return {
24250
+ id: data.id,
24251
+ soul
24252
+ };
24253
+ }
24254
+ function parseSoulPath(soul) {
24255
+ if (typeof soul !== "string") return null;
24256
+ const parts = soul.split("/");
24257
+ if (parts.length < 4) return null;
24258
+ const key = parts.slice(3).join("/");
24259
+ return {
24260
+ appname: parts[0],
24261
+ holon: parts[1],
24262
+ lens: parts[2],
24263
+ key
24264
+ };
24265
+ }
24266
+ function isHologram(data) {
24267
+ if (!data || typeof data !== "object") {
24268
+ return false;
24269
+ }
24270
+ if (data.id && typeof data.soul === "string" && data.soul.length > 0) {
24271
+ if (data.soul.includes("/")) {
24272
+ return true;
24273
+ }
24274
+ }
24275
+ return false;
24276
+ }
24277
+ function attachHologramMeta(originalData, hologramSoul) {
24278
+ const parts = parseSoulPath(hologramSoul);
24279
+ return {
24280
+ ...originalData,
24281
+ _hologram: {
24282
+ isHologram: true,
24283
+ soul: hologramSoul,
24284
+ sourceHolon: parts?.holon ?? null,
24285
+ sourceLens: parts?.lens ?? null,
24286
+ sourceKey: parts?.key ?? null,
24287
+ resolvedAt: Date.now()
24288
+ }
24289
+ };
24290
+ }
24291
+ async function resolveHologram(holoInstance, hologram, options = {}) {
24292
+ if (!isHologram(hologram)) {
24293
+ return hologram;
24294
+ }
24295
+ const {
24296
+ followHolograms = true,
24297
+ visited = /* @__PURE__ */ new Set(),
24298
+ maxDepth = 10,
24299
+ currentDepth = 0
24300
+ } = options;
24301
+ if (currentDepth >= maxDepth) {
24302
+ console.warn(`!!! Maximum resolution depth (${maxDepth}) reached for soul: ${hologram.soul}. Stopping resolution.`);
24303
+ return null;
24304
+ }
24305
+ if (hologram.soul && visited.has(hologram.soul)) {
24306
+ console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}. Breaking loop.`);
24307
+ return null;
24308
+ }
24309
+ try {
24310
+ if (hologram.soul) {
24311
+ const soulInfo = parseSoulPath(hologram.soul);
24312
+ if (!soulInfo) {
24313
+ console.warn(`Invalid soul format: ${hologram.soul}`);
24314
+ return null;
24315
+ }
24316
+ const nextVisited = new Set(visited);
24317
+ nextVisited.add(hologram.soul);
24318
+ const originalData = await holoInstance.get(
24319
+ soulInfo.holon,
24320
+ soulInfo.lens,
24321
+ soulInfo.key,
24322
+ null,
24323
+ {
24324
+ resolveHolograms: followHolograms,
24325
+ visited: nextVisited,
24326
+ maxDepth,
24327
+ currentDepth: currentDepth + 1
24328
+ }
24329
+ );
24330
+ if (originalData && !originalData._invalidHologram) {
24331
+ return attachHologramMeta(originalData, hologram.soul);
24332
+ } else {
24333
+ console.warn(`!!! Original data NOT FOUND for soul: ${hologram.soul}. Removing broken hologram.`);
24334
+ return null;
24335
+ }
24336
+ } else {
24337
+ console.warn("!!! resolveHologram called with object missing soul:", hologram);
24338
+ return null;
24339
+ }
24340
+ } catch (error) {
24341
+ if (error.message?.startsWith("CIRCULAR_REFERENCE")) {
24342
+ console.warn(`!!! Circular reference detected during hologram resolution: ${error.message}`);
24343
+ return null;
24344
+ }
24345
+ console.error(`!!! Error resolving hologram: ${error.message}`, error);
24346
+ return null;
24347
+ }
24348
+ }
24227
24349
 
24228
24350
  // federation.js
24351
+ async function getHolonName(holosphere, space) {
24352
+ if (!holosphere || !space) return null;
24353
+ try {
24354
+ const settings = await holosphere.get(space, "settings", space);
24355
+ if (!settings) return null;
24356
+ if (Array.isArray(settings)) {
24357
+ const found = settings.find((s) => s && typeof s.name === "string" && s.name.trim() !== "");
24358
+ return found ? found.name : null;
24359
+ }
24360
+ if (typeof settings.name === "string" && settings.name.trim() !== "") {
24361
+ return settings.name;
24362
+ }
24363
+ return null;
24364
+ } catch {
24365
+ return null;
24366
+ }
24367
+ }
24229
24368
  async function federate(holosphere, spaceId1, spaceId2, password1 = null, password2 = null, bidirectional = true, lensConfig = {}) {
24230
24369
  if (!spaceId1 || !spaceId2) {
24231
24370
  throw new Error("federate: Missing required space IDs");
@@ -24233,110 +24372,85 @@ var HoloSphere = (() => {
24233
24372
  if (spaceId1 === spaceId2) {
24234
24373
  throw new Error("Cannot federate a space with itself");
24235
24374
  }
24236
- const { federate: federate2 = [], notify = [] } = lensConfig;
24237
- if (!Array.isArray(federate2) || !Array.isArray(notify)) {
24238
- throw new Error("federate: lensConfig.federate and lensConfig.notify must be arrays");
24239
- }
24240
- const federateLenses = federate2;
24241
- const notifyLenses = notify;
24375
+ const { inbound = [], outbound = [] } = lensConfig;
24376
+ if (!Array.isArray(inbound) || !Array.isArray(outbound)) {
24377
+ throw new Error("federate: lensConfig.inbound and lensConfig.outbound must be arrays");
24378
+ }
24379
+ const applyDirection = (fedInfo, partnerId, partnerInbound, partnerOutbound) => {
24380
+ if (!fedInfo.federated) fedInfo.federated = [];
24381
+ if (!fedInfo.inbound) fedInfo.inbound = [];
24382
+ if (!fedInfo.outbound) fedInfo.outbound = [];
24383
+ if (!fedInfo.lensConfig) fedInfo.lensConfig = {};
24384
+ if (!fedInfo.federated.includes(partnerId)) {
24385
+ fedInfo.federated.push(partnerId);
24386
+ }
24387
+ const hasInbound = partnerInbound.length > 0;
24388
+ const hasOutbound = partnerOutbound.length > 0;
24389
+ if (hasInbound && !fedInfo.inbound.includes(partnerId)) {
24390
+ fedInfo.inbound.push(partnerId);
24391
+ } else if (!hasInbound) {
24392
+ fedInfo.inbound = fedInfo.inbound.filter((id) => id !== partnerId);
24393
+ }
24394
+ if (hasOutbound && !fedInfo.outbound.includes(partnerId)) {
24395
+ fedInfo.outbound.push(partnerId);
24396
+ } else if (!hasOutbound) {
24397
+ fedInfo.outbound = fedInfo.outbound.filter((id) => id !== partnerId);
24398
+ }
24399
+ fedInfo.lensConfig[partnerId] = {
24400
+ inbound: [...partnerInbound],
24401
+ outbound: [...partnerOutbound],
24402
+ timestamp: Date.now()
24403
+ };
24404
+ fedInfo.timestamp = Date.now();
24405
+ };
24242
24406
  try {
24243
24407
  let fedInfo1 = null;
24244
24408
  try {
24245
24409
  fedInfo1 = await holosphere.getGlobal("federation", spaceId1, password1);
24246
- } catch (error) {
24410
+ } catch {
24247
24411
  }
24248
24412
  if (fedInfo1 == null) {
24249
24413
  fedInfo1 = {
24250
24414
  id: spaceId1,
24251
24415
  name: spaceId1,
24252
- federation: [],
24253
- notify: [],
24416
+ federated: [],
24417
+ inbound: [],
24418
+ outbound: [],
24254
24419
  lensConfig: {},
24255
- // New field for lens-specific settings
24420
+ partnerNames: {},
24256
24421
  timestamp: Date.now()
24257
24422
  };
24258
24423
  }
24259
- if (!fedInfo1.federation) fedInfo1.federation = [];
24260
- if (!fedInfo1.notify) fedInfo1.notify = [];
24261
- if (!fedInfo1.lensConfig) fedInfo1.lensConfig = {};
24262
- if (!fedInfo1.federation.includes(spaceId2)) {
24263
- fedInfo1.federation.push(spaceId2);
24264
- }
24265
- if (!fedInfo1.notify.includes(spaceId2)) {
24266
- fedInfo1.notify.push(spaceId2);
24267
- }
24268
- const newLensConfigsForSpace1 = { ...fedInfo1.lensConfig || {} };
24269
- newLensConfigsForSpace1[spaceId2] = {
24270
- // Add/update config for the target spaceId2
24271
- federate: [...federateLenses],
24272
- // federateLenses & notifyLenses are from the main lensConfig parameter
24273
- notify: [...notifyLenses],
24274
- timestamp: Date.now()
24275
- };
24276
- fedInfo1.lensConfig = newLensConfigsForSpace1;
24277
- fedInfo1.timestamp = Date.now();
24424
+ applyDirection(fedInfo1, spaceId2, inbound, outbound);
24278
24425
  try {
24279
24426
  await holosphere.putGlobal("federation", fedInfo1, password1);
24280
24427
  } catch (error) {
24281
24428
  throw new Error(`Failed to create federation: ${error.message}`);
24282
24429
  }
24283
- {
24430
+ if (bidirectional) {
24284
24431
  let fedInfo2 = null;
24285
24432
  try {
24286
24433
  fedInfo2 = await holosphere.getGlobal("federation", spaceId2, password2);
24287
- } catch (error) {
24434
+ } catch {
24288
24435
  }
24289
24436
  if (fedInfo2 == null) {
24290
24437
  fedInfo2 = {
24291
24438
  id: spaceId2,
24292
24439
  name: spaceId2,
24293
- federation: [],
24294
- notify: [],
24440
+ federated: [],
24441
+ inbound: [],
24442
+ outbound: [],
24295
24443
  lensConfig: {},
24296
- // New field for lens-specific settings
24444
+ partnerNames: {},
24297
24445
  timestamp: Date.now()
24298
24446
  };
24299
24447
  }
24300
- if (!fedInfo2.federation) fedInfo2.federation = [];
24301
- if (!fedInfo2.notify) fedInfo2.notify = [];
24302
- if (!fedInfo2.lensConfig) fedInfo2.lensConfig = {};
24303
- if (bidirectional && !fedInfo2.federation.includes(spaceId1)) {
24304
- fedInfo2.federation.push(spaceId1);
24305
- }
24306
- if (!fedInfo2.notify.includes(spaceId1)) {
24307
- fedInfo2.notify.push(spaceId1);
24308
- }
24309
- fedInfo2.lensConfig[spaceId1] = {
24310
- federate: bidirectional ? [...federateLenses] : [],
24311
- // Create a copy of the array
24312
- notify: bidirectional ? [...notifyLenses] : [],
24313
- // Create a copy of the array
24314
- timestamp: Date.now()
24315
- };
24316
- fedInfo2.timestamp = Date.now();
24448
+ applyDirection(fedInfo2, spaceId1, outbound, inbound);
24317
24449
  try {
24318
24450
  await holosphere.putGlobal("federation", fedInfo2, password2);
24319
- } catch (error) {
24451
+ } catch {
24320
24452
  }
24321
24453
  }
24322
- const federationMeta = {
24323
- id: `${spaceId1}_${spaceId2}`,
24324
- space1: spaceId1,
24325
- space2: spaceId2,
24326
- created: Date.now(),
24327
- status: "active",
24328
- bidirectional,
24329
- lensConfig: {
24330
- federate: [...federateLenses],
24331
- // Create a copy of the array
24332
- notify: [...notifyLenses]
24333
- // Create a copy of the array
24334
- }
24335
- };
24336
- try {
24337
- await holosphere.putGlobal("federationMeta", federationMeta);
24338
- } catch (error) {
24339
- }
24340
24454
  return true;
24341
24455
  } catch (error) {
24342
24456
  throw error;
@@ -24353,8 +24467,15 @@ var HoloSphere = (() => {
24353
24467
  }
24354
24468
  const subscriptions2 = [];
24355
24469
  let lastNotificationTime = {};
24356
- if (fedInfo.federation && fedInfo.federation.length > 0) {
24357
- for (const federatedSpace of fedInfo.federation) {
24470
+ const partnerNames = /* @__PURE__ */ new Map();
24471
+ if (fedInfo.inbound && fedInfo.inbound.length > 0) {
24472
+ await Promise.all(
24473
+ fedInfo.inbound.map(async (space) => {
24474
+ const name = await getHolonName(holosphere, space);
24475
+ partnerNames.set(space, name);
24476
+ })
24477
+ );
24478
+ for (const federatedSpace of fedInfo.inbound) {
24358
24479
  for (const lens of lenses) {
24359
24480
  try {
24360
24481
  const sub = await holosphere.subscribe(federatedSpace, lens, async (data) => {
@@ -24368,10 +24489,13 @@ var HoloSphere = (() => {
24368
24489
  }
24369
24490
  lastNotificationTime[key] = now;
24370
24491
  }
24371
- if (!data.federation) {
24372
- data.federation = {
24492
+ if (!data._federation) {
24493
+ const partnerName = partnerNames.get(federatedSpace);
24494
+ data._federation = {
24373
24495
  origin: federatedSpace,
24374
- timestamp: now
24496
+ sourceLens: lens,
24497
+ timestamp: now,
24498
+ ...partnerName ? { originName: partnerName } : {}
24375
24499
  };
24376
24500
  }
24377
24501
  await callback(data, federatedSpace, lens);
@@ -24416,8 +24540,8 @@ var HoloSphere = (() => {
24416
24540
  const fedInfo = await getFederation(holosphere, spaceId, password);
24417
24541
  if (fedInfo && fedInfo.lensConfig && fedInfo.lensConfig[targetSpaceId]) {
24418
24542
  return {
24419
- federate: fedInfo.lensConfig[targetSpaceId].federate || [],
24420
- notify: fedInfo.lensConfig[targetSpaceId].notify || []
24543
+ inbound: fedInfo.lensConfig[targetSpaceId].inbound || [],
24544
+ outbound: fedInfo.lensConfig[targetSpaceId].outbound || []
24421
24545
  };
24422
24546
  }
24423
24547
  return null;
@@ -24440,14 +24564,20 @@ var HoloSphere = (() => {
24440
24564
  if (!fedInfo1) {
24441
24565
  console.warn(`No federation info found for ${spaceId1}. Skipping its update.`);
24442
24566
  } else {
24443
- if (!fedInfo1.federation) fedInfo1.federation = [];
24444
- if (!fedInfo1.notify) fedInfo1.notify = [];
24445
- const originalFederationLength = fedInfo1.federation.length;
24446
- const originalNotifyLength = fedInfo1.notify.length;
24447
- fedInfo1.federation = fedInfo1.federation.filter((id) => id !== spaceId2);
24448
- fedInfo1.notify = fedInfo1.notify.filter((id) => id !== spaceId2);
24567
+ if (!fedInfo1.federated) fedInfo1.federated = [];
24568
+ if (!fedInfo1.inbound) fedInfo1.inbound = [];
24569
+ if (!fedInfo1.outbound) fedInfo1.outbound = [];
24570
+ if (!fedInfo1.lensConfig) fedInfo1.lensConfig = {};
24571
+ if (!fedInfo1.partnerNames) fedInfo1.partnerNames = {};
24572
+ const beforeIn = fedInfo1.inbound.length;
24573
+ const beforeOut = fedInfo1.outbound.length;
24574
+ fedInfo1.federated = fedInfo1.federated.filter((id) => id !== spaceId2);
24575
+ fedInfo1.inbound = fedInfo1.inbound.filter((id) => id !== spaceId2);
24576
+ fedInfo1.outbound = fedInfo1.outbound.filter((id) => id !== spaceId2);
24577
+ delete fedInfo1.lensConfig[spaceId2];
24578
+ delete fedInfo1.partnerNames[spaceId2];
24449
24579
  fedInfo1.timestamp = Date.now();
24450
- console.log(`Unfederate: Removed ${spaceId2} from ${spaceId1}: federation ${originalFederationLength} -> ${fedInfo1.federation.length}, notify ${originalNotifyLength} -> ${fedInfo1.notify.length}`);
24580
+ console.log(`Unfederate: removed ${spaceId2} from ${spaceId1}: inbound ${beforeIn} -> ${fedInfo1.inbound.length}, outbound ${beforeOut} -> ${fedInfo1.outbound.length}`);
24451
24581
  try {
24452
24582
  await holosphere.putGlobal("federation", fedInfo1, password1);
24453
24583
  } catch (error) {
@@ -24462,10 +24592,19 @@ var HoloSphere = (() => {
24462
24592
  } catch (error) {
24463
24593
  console.error(`Error getting fedInfo2 for ${spaceId2} during unfederate: ${error.message}`);
24464
24594
  }
24465
- if (!fedInfo2 || !fedInfo2.notify) {
24466
- console.warn(`No notify array found for ${spaceId2} or fedInfo2 is null. Skipping its update.`);
24595
+ if (!fedInfo2) {
24596
+ console.warn(`No federation info found for ${spaceId2}. Skipping its update.`);
24467
24597
  } else {
24468
- fedInfo2.notify = fedInfo2.notify.filter((id) => id !== spaceId1);
24598
+ if (!fedInfo2.federated) fedInfo2.federated = [];
24599
+ if (!fedInfo2.inbound) fedInfo2.inbound = [];
24600
+ if (!fedInfo2.outbound) fedInfo2.outbound = [];
24601
+ if (!fedInfo2.lensConfig) fedInfo2.lensConfig = {};
24602
+ if (!fedInfo2.partnerNames) fedInfo2.partnerNames = {};
24603
+ fedInfo2.federated = fedInfo2.federated.filter((id) => id !== spaceId1);
24604
+ fedInfo2.inbound = fedInfo2.inbound.filter((id) => id !== spaceId1);
24605
+ fedInfo2.outbound = fedInfo2.outbound.filter((id) => id !== spaceId1);
24606
+ delete fedInfo2.lensConfig[spaceId1];
24607
+ delete fedInfo2.partnerNames[spaceId1];
24469
24608
  fedInfo2.timestamp = Date.now();
24470
24609
  try {
24471
24610
  await holosphere.putGlobal("federation", fedInfo2, password2);
@@ -24498,19 +24637,19 @@ var HoloSphere = (() => {
24498
24637
  throw new Error("removeNotify: Missing required space IDs");
24499
24638
  }
24500
24639
  try {
24501
- let fedInfo = await holosphere.getGlobal("federation", spaceId1, password1);
24640
+ const fedInfo = await holosphere.getGlobal("federation", spaceId1, password1);
24502
24641
  if (!fedInfo) {
24503
24642
  throw new Error(`No federation info found for ${spaceId1}`);
24504
24643
  }
24505
- if (!fedInfo.notify) fedInfo.notify = [];
24506
- if (fedInfo.notify.includes(spaceId2)) {
24507
- fedInfo.notify = fedInfo.notify.filter((id) => id !== spaceId2);
24508
- fedInfo.timestamp = Date.now();
24509
- await holosphere.putGlobal("federation", fedInfo, password1);
24510
- return true;
24511
- } else {
24512
- return false;
24644
+ if (!fedInfo.outbound) fedInfo.outbound = [];
24645
+ if (!fedInfo.outbound.includes(spaceId2)) return false;
24646
+ fedInfo.outbound = fedInfo.outbound.filter((id) => id !== spaceId2);
24647
+ if (fedInfo.lensConfig?.[spaceId2]) {
24648
+ fedInfo.lensConfig[spaceId2].outbound = [];
24513
24649
  }
24650
+ fedInfo.timestamp = Date.now();
24651
+ await holosphere.putGlobal("federation", fedInfo, password1);
24652
+ return true;
24514
24653
  } catch (error) {
24515
24654
  throw error;
24516
24655
  }
@@ -24545,10 +24684,29 @@ var HoloSphere = (() => {
24545
24684
  if (includeLocal) {
24546
24685
  spacesToQuery.push(holon);
24547
24686
  }
24548
- if (includeFederated && fedInfo && fedInfo.federation && fedInfo.federation.length > 0) {
24549
- const federatedSpaces = maxFederatedSpaces === -1 ? fedInfo.federation : fedInfo.federation.slice(0, maxFederatedSpaces);
24687
+ if (includeFederated && fedInfo && fedInfo.inbound && fedInfo.inbound.length > 0) {
24688
+ const federatedSpaces = maxFederatedSpaces === -1 ? fedInfo.inbound : fedInfo.inbound.slice(0, maxFederatedSpaces);
24550
24689
  spacesToQuery = spacesToQuery.concat(federatedSpaces);
24551
24690
  }
24691
+ const remoteSpaces = spacesToQuery.filter((s) => s !== holon);
24692
+ const spaceNames = /* @__PURE__ */ new Map();
24693
+ await Promise.all(
24694
+ remoteSpaces.map(async (space) => {
24695
+ const name = await getHolonName(holosphere, space);
24696
+ spaceNames.set(space, name);
24697
+ })
24698
+ );
24699
+ const tagWithSource = (item, space) => {
24700
+ if (!item || space === holon) return item;
24701
+ const originName = spaceNames.get(space);
24702
+ const fed = {
24703
+ ...item._federation || {},
24704
+ origin: space,
24705
+ sourceLens: lens
24706
+ };
24707
+ if (originName) fed.originName = originName;
24708
+ return { ...item, _federation: fed };
24709
+ };
24552
24710
  for (const currentSpace of spacesToQuery) {
24553
24711
  if (queryIds && Array.isArray(queryIds)) {
24554
24712
  console.log(`Fetching specific IDs from ${currentSpace}: ${queryIds.join(", ")}`);
@@ -24557,7 +24715,7 @@ var HoloSphere = (() => {
24557
24715
  fetchPromises.push(
24558
24716
  holosphere.get(currentSpace, lens, itemId).then((item) => {
24559
24717
  if (item) {
24560
- fetchedItems.set(itemId, item);
24718
+ fetchedItems.set(itemId, tagWithSource(item, currentSpace));
24561
24719
  }
24562
24720
  }).catch((err) => console.warn(`Error fetching item ${itemId} from ${currentSpace}: ${err.message}`))
24563
24721
  );
@@ -24571,7 +24729,7 @@ var HoloSphere = (() => {
24571
24729
  holosphere.getAll(currentSpace, lens).then((items) => {
24572
24730
  for (const item of items) {
24573
24731
  if (item && item[idField] && !fetchedItems.has(item[idField])) {
24574
- fetchedItems.set(item[idField], item);
24732
+ fetchedItems.set(item[idField], tagWithSource(item, currentSpace));
24575
24733
  }
24576
24734
  }
24577
24735
  }).catch((err) => console.warn(`Error fetching all items from ${currentSpace}: ${err.message}`))
@@ -24603,24 +24761,29 @@ var HoloSphere = (() => {
24603
24761
  );
24604
24762
  console.log(`Original data found via soul path:`, JSON.stringify(originalData));
24605
24763
  if (originalData) {
24606
- result[i] = {
24607
- ...originalData,
24608
- _federation: {
24609
- isReference: true,
24610
- resolved: true,
24611
- soul: item.soul,
24612
- timestamp: Date.now()
24764
+ const withMeta = attachHologramMeta(originalData, item.soul);
24765
+ if (withMeta._hologram?.sourceHolon) {
24766
+ let sourceHolonName = spaceNames.get(withMeta._hologram.sourceHolon);
24767
+ if (sourceHolonName === void 0) {
24768
+ sourceHolonName = await getHolonName(holosphere, withMeta._hologram.sourceHolon);
24769
+ spaceNames.set(withMeta._hologram.sourceHolon, sourceHolonName);
24613
24770
  }
24614
- };
24771
+ if (sourceHolonName) {
24772
+ withMeta._hologram = {
24773
+ ...withMeta._hologram,
24774
+ sourceHolonName
24775
+ };
24776
+ }
24777
+ }
24778
+ result[i] = withMeta;
24615
24779
  } else {
24616
24780
  result[i] = {
24617
24781
  id: item.id,
24618
- _federation: {
24619
- isReference: true,
24620
- resolved: false,
24782
+ _hologram: {
24783
+ isHologram: false,
24621
24784
  soul: item.soul,
24622
24785
  error: "Referenced data not found",
24623
- timestamp: Date.now()
24786
+ resolvedAt: Date.now()
24624
24787
  }
24625
24788
  };
24626
24789
  }
@@ -24628,55 +24791,25 @@ var HoloSphere = (() => {
24628
24791
  console.warn(`Soul doesn't match expected format: ${item.soul}`);
24629
24792
  result[i] = {
24630
24793
  id: item.id,
24631
- _federation: {
24632
- isReference: true,
24633
- resolved: false,
24794
+ _hologram: {
24795
+ isHologram: false,
24634
24796
  soul: item.soul,
24635
24797
  error: "Invalid soul format",
24636
- timestamp: Date.now()
24798
+ resolvedAt: Date.now()
24637
24799
  }
24638
24800
  };
24639
24801
  }
24640
24802
  } catch (refError) {
24641
24803
  result[i] = {
24642
24804
  id: item.id,
24643
- _federation: {
24644
- isReference: true,
24645
- resolved: false,
24805
+ _hologram: {
24806
+ isHologram: false,
24646
24807
  soul: item.soul,
24647
24808
  error: refError.message || "Error resolving reference",
24648
- timestamp: Date.now()
24809
+ resolvedAt: Date.now()
24649
24810
  }
24650
24811
  };
24651
24812
  }
24652
- } else if (item._federation && item._federation.isReference) {
24653
- console.log(`Found legacy reference: ${item._federation.origin}/${item._federation.lens}/${item[idField]}`);
24654
- try {
24655
- const reference = item._federation;
24656
- console.log(`Getting original data from ${reference.origin} / ${reference.lens} / ${item[idField]}`);
24657
- const originalData = await holosphere.get(
24658
- reference.origin,
24659
- reference.lens,
24660
- item[idField],
24661
- null,
24662
- { resolveReferences: false }
24663
- // Prevent infinite recursion
24664
- );
24665
- console.log(`Original data found:`, JSON.stringify(originalData));
24666
- if (originalData) {
24667
- result[i] = {
24668
- ...originalData,
24669
- _federation: {
24670
- ...reference,
24671
- resolved: true,
24672
- timestamp: Date.now()
24673
- }
24674
- };
24675
- } else {
24676
- console.warn(`Could not resolve legacy reference: original data not found`);
24677
- }
24678
- } catch (refError) {
24679
- }
24680
24813
  }
24681
24814
  }
24682
24815
  }
@@ -24743,8 +24876,8 @@ var HoloSphere = (() => {
24743
24876
  };
24744
24877
  try {
24745
24878
  const fedInfo = await getFederation(holosphere, holon, password);
24746
- if (fedInfo && fedInfo.federation && fedInfo.federation.length > 0 && fedInfo.notify && fedInfo.notify.length > 0) {
24747
- let spaces = fedInfo.notify;
24879
+ if (fedInfo && fedInfo.outbound && fedInfo.outbound.length > 0) {
24880
+ let spaces = fedInfo.outbound;
24748
24881
  if (targetSpaces && Array.isArray(targetSpaces) && targetSpaces.length > 0) {
24749
24882
  spaces = spaces.filter((space) => targetSpaces.includes(space));
24750
24883
  }
@@ -24756,17 +24889,17 @@ var HoloSphere = (() => {
24756
24889
  result.skipped++;
24757
24890
  return false;
24758
24891
  }
24759
- const federateLenses = Array.isArray(spaceConfig.federate) ? spaceConfig.federate : [];
24760
- const shouldFederate = federateLenses.includes("*") || federateLenses.includes(lens);
24761
- const shouldPropagate = shouldFederate;
24892
+ const outboundLenses = Array.isArray(spaceConfig.outbound) ? spaceConfig.outbound : [];
24893
+ const shouldPropagate = outboundLenses.includes("*") || outboundLenses.includes(lens);
24762
24894
  if (!shouldPropagate) {
24763
- result.messages.push(`Propagation of lens '${lens}' to target space ${targetSpace} skipped: lens not in 'federate' configuration.`);
24895
+ result.messages.push(`Propagation of lens '${lens}' to target space ${targetSpace} skipped: lens not in 'outbound' configuration.`);
24764
24896
  result.skipped++;
24765
24897
  }
24766
24898
  return shouldPropagate;
24767
24899
  });
24768
24900
  if (spaces.length > 0) {
24769
24901
  const isAlreadyHologram = holosphere.isHologram(data);
24902
+ const ownName = await getHolonName(holosphere, holon);
24770
24903
  const propagatePromises = spaces.map(async (targetSpace) => {
24771
24904
  try {
24772
24905
  let payloadToPut;
@@ -24776,7 +24909,8 @@ var HoloSphere = (() => {
24776
24909
  sourceLens: lens,
24777
24910
  // The lens from which this data is being propagated
24778
24911
  propagatedAt: Date.now(),
24779
- originalId: data.id
24912
+ originalId: data.id,
24913
+ ...ownName ? { originName: ownName } : {}
24780
24914
  };
24781
24915
  if (useHolograms && !isAlreadyHologram) {
24782
24916
  const newHologram = holosphere.createHologram(holon, lens, data);
@@ -24861,6 +24995,7 @@ var HoloSphere = (() => {
24861
24995
  if (parentHexagons.length > 0) {
24862
24996
  result.parentPropagation.messages.push(`Found ${parentHexagons.length} parent hexagons to propagate to: ${parentHexagons.join(", ")}`);
24863
24997
  const isAlreadyHologram = holosphere.isHologram(data);
24998
+ const ownNameParent = await getHolonName(holosphere, holon);
24864
24999
  const parentPropagatePromises = parentHexagons.map(async (parentHexagon) => {
24865
25000
  try {
24866
25001
  let payloadToPut;
@@ -24873,8 +25008,9 @@ var HoloSphere = (() => {
24873
25008
  originalId: data.id,
24874
25009
  propagationType: "parent",
24875
25010
  // Indicate this is parent propagation
24876
- parentLevel: holonResolution - getResolution(parentHexagon)
25011
+ parentLevel: holonResolution - getResolution(parentHexagon),
24877
25012
  // How many levels up
25013
+ ...ownNameParent ? { originName: ownNameParent } : {}
24878
25014
  };
24879
25015
  if (useHolograms && !isAlreadyHologram) {
24880
25016
  const newHologram = holosphere.createHologram(holon, lens, data);
@@ -24989,60 +25125,64 @@ var HoloSphere = (() => {
24989
25125
  message: "No federation configuration found for this space"
24990
25126
  };
24991
25127
  }
24992
- result.federatedCount = fedInfo.federation?.length || 0;
24993
- result.notifyCount = fedInfo.notify?.length || 0;
25128
+ const allPartners = fedInfo.federated || [];
25129
+ result.federatedCount = allPartners.length;
25130
+ result.inboundCount = fedInfo.inbound?.length || 0;
25131
+ result.outboundCount = fedInfo.outbound?.length || 0;
24994
25132
  const emptyFedInfo = {
24995
25133
  id: spaceId,
24996
25134
  name: spaceName || spaceId,
24997
- federation: [],
24998
- notify: [],
25135
+ federated: [],
25136
+ inbound: [],
25137
+ outbound: [],
25138
+ lensConfig: {},
25139
+ partnerNames: {},
24999
25140
  timestamp: Date.now()
25000
25141
  };
25001
25142
  await holosphere.putGlobal("federation", emptyFedInfo, password);
25002
- if (notifyPartners && fedInfo.federation && fedInfo.federation.length > 0) {
25003
- const updatePromises = fedInfo.federation.map(async (partnerSpace) => {
25143
+ if (notifyPartners && allPartners.length > 0) {
25144
+ const updatePromises = allPartners.map(async (partnerSpace) => {
25004
25145
  try {
25005
25146
  const partnerFedInfo = await getFederation(holosphere, partnerSpace);
25006
- if (partnerFedInfo) {
25007
- if (partnerFedInfo.federation) {
25008
- partnerFedInfo.federation = partnerFedInfo.federation.filter(
25009
- (id) => id !== spaceId.toString()
25010
- );
25011
- }
25012
- if (partnerFedInfo.notify) {
25013
- partnerFedInfo.notify = partnerFedInfo.notify.filter(
25014
- (id) => id !== spaceId.toString()
25015
- );
25016
- }
25017
- partnerFedInfo.timestamp = Date.now();
25018
- await holosphere.putGlobal("federation", partnerFedInfo);
25019
- result.partnersNotified++;
25020
- return true;
25147
+ if (!partnerFedInfo) return false;
25148
+ const sid = spaceId.toString();
25149
+ if (partnerFedInfo.federated) {
25150
+ partnerFedInfo.federated = partnerFedInfo.federated.filter((id) => id !== sid);
25021
25151
  }
25022
- return false;
25152
+ if (partnerFedInfo.inbound) {
25153
+ partnerFedInfo.inbound = partnerFedInfo.inbound.filter((id) => id !== sid);
25154
+ }
25155
+ if (partnerFedInfo.outbound) {
25156
+ partnerFedInfo.outbound = partnerFedInfo.outbound.filter((id) => id !== sid);
25157
+ }
25158
+ if (partnerFedInfo.lensConfig) {
25159
+ delete partnerFedInfo.lensConfig[sid];
25160
+ }
25161
+ if (partnerFedInfo.partnerNames) {
25162
+ delete partnerFedInfo.partnerNames[sid];
25163
+ }
25164
+ partnerFedInfo.timestamp = Date.now();
25165
+ await holosphere.putGlobal("federation", partnerFedInfo);
25166
+ result.partnersNotified++;
25167
+ return true;
25023
25168
  } catch (error) {
25024
- result.errors.push({
25025
- partner: partnerSpace,
25026
- error: error.message
25027
- });
25169
+ result.errors.push({ partner: partnerSpace, error: error.message });
25028
25170
  return false;
25029
25171
  }
25030
25172
  });
25031
25173
  await Promise.all(updatePromises);
25032
25174
  }
25033
- if (fedInfo.federation && fedInfo.federation.length > 0) {
25034
- for (const partnerSpace of fedInfo.federation) {
25035
- try {
25036
- const metaId = `${spaceId}_${partnerSpace}`;
25037
- const altMetaId = `${partnerSpace}_${spaceId}`;
25038
- const meta = await holosphere.getGlobal("federationMeta", metaId) || await holosphere.getGlobal("federationMeta", altMetaId);
25039
- if (meta) {
25040
- meta.status = "inactive";
25041
- meta.endedAt = Date.now();
25042
- await holosphere.putGlobal("federationMeta", meta);
25043
- }
25044
- } catch (error) {
25175
+ for (const partnerSpace of allPartners) {
25176
+ try {
25177
+ const metaId = `${spaceId}_${partnerSpace}`;
25178
+ const altMetaId = `${partnerSpace}_${spaceId}`;
25179
+ const meta = await holosphere.getGlobal("federationMeta", metaId) || await holosphere.getGlobal("federationMeta", altMetaId);
25180
+ if (meta) {
25181
+ meta.status = "inactive";
25182
+ meta.endedAt = Date.now();
25183
+ await holosphere.putGlobal("federationMeta", meta);
25045
25184
  }
25185
+ } catch {
25046
25186
  }
25047
25187
  }
25048
25188
  result.success = true;
@@ -25057,7 +25197,6 @@ var HoloSphere = (() => {
25057
25197
  }
25058
25198
 
25059
25199
  // schema.js
25060
- var import__ = __toESM(require__(), 1);
25061
25200
  async function setSchema(holoInstance, lens, schema) {
25062
25201
  if (!lens || !schema) {
25063
25202
  throw new Error("setSchema: Missing required parameters");
@@ -25139,6 +25278,45 @@ var HoloSphere = (() => {
25139
25278
  }
25140
25279
 
25141
25280
  // content.js
25281
+ function sanitizeForStorage(value, path = "", seen = /* @__PURE__ */ new WeakSet(), warnings = []) {
25282
+ if (value === null) return null;
25283
+ const t = typeof value;
25284
+ if (t === "number") {
25285
+ if (!Number.isFinite(value)) {
25286
+ warnings.push(`${path || "<root>"}: ${value} (non-finite number)`);
25287
+ return void 0;
25288
+ }
25289
+ return value;
25290
+ }
25291
+ if (t === "string" || t === "boolean") return value;
25292
+ if (t === "undefined" || t === "function" || t === "symbol" || t === "bigint") {
25293
+ warnings.push(`${path || "<root>"}: ${t}`);
25294
+ return void 0;
25295
+ }
25296
+ if (t === "object") {
25297
+ if (seen.has(value)) {
25298
+ warnings.push(`${path || "<root>"}: circular reference`);
25299
+ return void 0;
25300
+ }
25301
+ seen.add(value);
25302
+ if (Array.isArray(value)) {
25303
+ const out2 = [];
25304
+ for (let i = 0; i < value.length; i++) {
25305
+ const cleaned = sanitizeForStorage(value[i], `${path}[${i}]`, seen, warnings);
25306
+ out2.push(cleaned === void 0 ? null : cleaned);
25307
+ }
25308
+ return out2;
25309
+ }
25310
+ const out = {};
25311
+ for (const k of Object.keys(value)) {
25312
+ const cleaned = sanitizeForStorage(value[k], path ? `${path}.${k}` : k, seen, warnings);
25313
+ if (cleaned !== void 0) out[k] = cleaned;
25314
+ }
25315
+ return out;
25316
+ }
25317
+ warnings.push(`${path || "<root>"}: unsupported type ${t}`);
25318
+ return void 0;
25319
+ }
25142
25320
  async function put(holoInstance, holon, lens, data, password = null, options = {}) {
25143
25321
  if (!data) {
25144
25322
  throw new Error("put: Missing required data parameter");
@@ -25236,10 +25414,16 @@ var HoloSphere = (() => {
25236
25414
  }
25237
25415
  return new Promise((resolve, reject) => {
25238
25416
  try {
25239
- let dataToStore = { ...data };
25240
- if (dataToStore._meta !== void 0) {
25241
- delete dataToStore._meta;
25417
+ const sanitizeWarnings = [];
25418
+ let dataToStore = sanitizeForStorage(data, "", /* @__PURE__ */ new WeakSet(), sanitizeWarnings) || {};
25419
+ if (sanitizeWarnings.length > 0) {
25420
+ console.warn(
25421
+ `holosphere.put: sanitized ${sanitizeWarnings.length} field(s) at ${targetHolon}/${targetLens}/${targetKey} (id=${data.id}):`,
25422
+ sanitizeWarnings
25423
+ );
25242
25424
  }
25425
+ if (dataToStore._meta !== void 0) delete dataToStore._meta;
25426
+ if (dataToStore._hologram !== void 0) delete dataToStore._hologram;
25243
25427
  const payload = JSON.stringify(dataToStore);
25244
25428
  const putCallback = async (ack) => {
25245
25429
  if (ack.err) {
@@ -25529,7 +25713,8 @@ var HoloSphere = (() => {
25529
25713
  const output = /* @__PURE__ */ new Map();
25530
25714
  const pendingProcessing = [];
25531
25715
  const dataPath = password ? user.get("private").get(lens) : holoInstance.gun.get(holoInstance.appname).get(holon).get(lens);
25532
- dataPath.once((data) => {
25716
+ const shallowOnce = () => new Promise((res) => dataPath.once((d) => res(d)));
25717
+ const processShallow = (data) => {
25533
25718
  if (!data) {
25534
25719
  resolve([]);
25535
25720
  return;
@@ -25546,72 +25731,75 @@ var HoloSphere = (() => {
25546
25731
  resolve([]);
25547
25732
  return;
25548
25733
  }
25549
- let receivedCount = 0;
25550
- dataPath.map().once(async (itemData, key) => {
25551
- if (!itemData || key === "_") {
25552
- receivedCount++;
25553
- if (receivedCount >= expectedCount) {
25554
- await Promise.all(pendingProcessing);
25555
- resolve(Array.from(output.values()));
25556
- }
25557
- return;
25558
- }
25559
- const processingPromise = (async () => {
25560
- try {
25561
- const parsed = await holoInstance.parse(itemData);
25562
- if (!parsed || !parsed.id) return;
25563
- if (holoInstance.isHologram(parsed)) {
25564
- try {
25565
- const resolved = await holoInstance.resolveHologram(parsed, {
25566
- followHolograms: true,
25567
- maxDepth: 10,
25568
- currentDepth: 0
25569
- });
25570
- if (resolved === null) {
25571
- console.warn(`Broken hologram detected in getAll for key ${key}. Removing it...`);
25572
- try {
25573
- await holoInstance.delete(holon, lens, key, password);
25574
- } catch (cleanupError) {
25575
- console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
25576
- }
25577
- return;
25734
+ const processItem = async (itemData, key) => {
25735
+ if (!itemData) return;
25736
+ try {
25737
+ const parsed = await holoInstance.parse(itemData);
25738
+ if (!parsed || !parsed.id) return;
25739
+ if (holoInstance.isHologram(parsed)) {
25740
+ try {
25741
+ const resolved = await holoInstance.resolveHologram(parsed, {
25742
+ followHolograms: true,
25743
+ maxDepth: 10,
25744
+ currentDepth: 0
25745
+ });
25746
+ if (resolved === null) {
25747
+ console.warn(`Broken hologram detected in getAll for key ${key}. Removing it...`);
25748
+ try {
25749
+ await holoInstance.delete(holon, lens, key, password);
25750
+ } catch (cleanupError) {
25751
+ console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
25578
25752
  }
25579
- if (resolved && resolved !== parsed) {
25580
- if (schema) {
25581
- const valid = holoInstance.validator.validate(schema, resolved);
25582
- if (valid || !holoInstance.strict) {
25583
- output.set(resolved.id, resolved);
25584
- }
25585
- } else {
25753
+ return;
25754
+ }
25755
+ if (resolved && resolved !== parsed) {
25756
+ if (schema) {
25757
+ const valid = holoInstance.validator.validate(schema, resolved);
25758
+ if (valid || !holoInstance.strict) {
25586
25759
  output.set(resolved.id, resolved);
25587
25760
  }
25588
- return;
25761
+ } else {
25762
+ output.set(resolved.id, resolved);
25589
25763
  }
25590
- } catch (hologramError) {
25591
- console.error(`Error resolving hologram for key ${key}:`, hologramError);
25592
25764
  return;
25593
25765
  }
25766
+ } catch (hologramError) {
25767
+ console.error(`Error resolving hologram for key ${key}:`, hologramError);
25768
+ return;
25594
25769
  }
25595
- if (schema) {
25596
- const valid = holoInstance.validator.validate(schema, parsed);
25597
- if (valid || !holoInstance.strict) {
25598
- output.set(parsed.id, parsed);
25599
- }
25600
- } else {
25770
+ }
25771
+ if (schema) {
25772
+ const valid = holoInstance.validator.validate(schema, parsed);
25773
+ if (valid || !holoInstance.strict) {
25601
25774
  output.set(parsed.id, parsed);
25602
25775
  }
25603
- } catch (error) {
25604
- console.error("Error processing data:", error);
25776
+ } else {
25777
+ output.set(parsed.id, parsed);
25605
25778
  }
25606
- })();
25607
- pendingProcessing.push(processingPromise);
25608
- receivedCount++;
25609
- if (receivedCount >= expectedCount) {
25610
- await Promise.all(pendingProcessing);
25611
- resolve(Array.from(output.values()));
25779
+ } catch (error) {
25780
+ console.error("Error processing data:", error);
25612
25781
  }
25613
- });
25614
- });
25782
+ };
25783
+ Promise.all(keys.map((key) => {
25784
+ const inline = data[key];
25785
+ if (typeof inline !== "object" || inline === null) {
25786
+ return processItem(inline, key);
25787
+ }
25788
+ return new Promise((resolveItem) => {
25789
+ dataPath.get(key).once((itemData) => {
25790
+ processItem(itemData, key).then(resolveItem, resolveItem);
25791
+ });
25792
+ });
25793
+ })).then(() => resolve(Array.from(output.values())));
25794
+ };
25795
+ (async () => {
25796
+ let data = await shallowOnce();
25797
+ if (!data) {
25798
+ await new Promise((r) => setTimeout(r, 1500));
25799
+ data = await shallowOnce();
25800
+ }
25801
+ processShallow(data);
25802
+ })();
25615
25803
  });
25616
25804
  } catch (error) {
25617
25805
  console.error("Error in getAll:", error);
@@ -26090,6 +26278,9 @@ var HoloSphere = (() => {
26090
26278
  if (dataToStore._meta !== void 0) {
26091
26279
  delete dataToStore._meta;
26092
26280
  }
26281
+ if (dataToStore._hologram !== void 0) {
26282
+ delete dataToStore._hologram;
26283
+ }
26093
26284
  const payload = JSON.stringify(dataToStore);
26094
26285
  const isHologram2 = holoInstance.isHologram(dataToStore);
26095
26286
  const dataPath = password ? user.get("private").get(tableName) : holoInstance.gun.get(holoInstance.appname).get(tableName);
@@ -26290,7 +26481,8 @@ var HoloSphere = (() => {
26290
26481
  const output = [];
26291
26482
  const pendingProcessing = [];
26292
26483
  const dataPath = password ? user.get("private").get(tableName) : holoInstance.gun.get(holoInstance.appname).get(tableName);
26293
- dataPath.once((data) => {
26484
+ const shallowOnce = () => new Promise((res) => dataPath.once((d) => res(d)));
26485
+ const processShallow = (data) => {
26294
26486
  if (!data) {
26295
26487
  resolve([]);
26296
26488
  return;
@@ -26307,52 +26499,55 @@ var HoloSphere = (() => {
26307
26499
  resolve([]);
26308
26500
  return;
26309
26501
  }
26310
- let receivedCount = 0;
26311
- dataPath.map().once(async (itemData, key) => {
26312
- if (!itemData || key === "_") {
26313
- receivedCount++;
26314
- if (receivedCount >= expectedCount) {
26315
- await Promise.all(pendingProcessing);
26316
- resolve(output);
26317
- }
26318
- return;
26319
- }
26320
- const processingPromise = (async () => {
26321
- try {
26322
- const parsed = await holoInstance.parse(itemData);
26323
- if (!parsed) return;
26324
- if (holoInstance.isHologram(parsed)) {
26325
- const resolved = await holoInstance.resolveHologram(parsed, {
26326
- followHolograms: true
26327
- });
26328
- if (resolved === null) {
26329
- try {
26330
- await holoInstance.deleteGlobal(tableName, key, password);
26331
- } catch (deleteError) {
26332
- console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
26333
- }
26334
- return;
26335
- }
26336
- if (resolved !== parsed) {
26337
- output.push(resolved);
26338
- } else {
26339
- output.push(parsed);
26502
+ const processItem = async (itemData, key) => {
26503
+ if (!itemData) return;
26504
+ try {
26505
+ const parsed = await holoInstance.parse(itemData);
26506
+ if (!parsed) return;
26507
+ if (holoInstance.isHologram(parsed)) {
26508
+ const resolved = await holoInstance.resolveHologram(parsed, {
26509
+ followHolograms: true
26510
+ });
26511
+ if (resolved === null) {
26512
+ try {
26513
+ await holoInstance.deleteGlobal(tableName, key, password);
26514
+ } catch (deleteError) {
26515
+ console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
26340
26516
  }
26517
+ return;
26518
+ }
26519
+ if (resolved !== parsed) {
26520
+ output.push(resolved);
26341
26521
  } else {
26342
26522
  output.push(parsed);
26343
26523
  }
26344
- } catch (error) {
26345
- console.error("Error parsing data:", error);
26524
+ } else {
26525
+ output.push(parsed);
26346
26526
  }
26347
- })();
26348
- pendingProcessing.push(processingPromise);
26349
- receivedCount++;
26350
- if (receivedCount >= expectedCount) {
26351
- await Promise.all(pendingProcessing);
26352
- resolve(output);
26527
+ } catch (error) {
26528
+ console.error("Error parsing data:", error);
26353
26529
  }
26354
- });
26355
- });
26530
+ };
26531
+ Promise.all(keys.map((key) => {
26532
+ const inline = data[key];
26533
+ if (typeof inline !== "object" || inline === null) {
26534
+ return processItem(inline, key);
26535
+ }
26536
+ return new Promise((resolveItem) => {
26537
+ dataPath.get(key).once((itemData) => {
26538
+ processItem(itemData, key).then(resolveItem, resolveItem);
26539
+ });
26540
+ });
26541
+ })).then(() => resolve(output));
26542
+ };
26543
+ (async () => {
26544
+ let data = await shallowOnce();
26545
+ if (!data) {
26546
+ await new Promise((r) => setTimeout(r, 1500));
26547
+ data = await shallowOnce();
26548
+ }
26549
+ processShallow(data);
26550
+ })();
26356
26551
  });
26357
26552
  } catch (error) {
26358
26553
  console.error("Error in getAllGlobal:", error);
@@ -26642,116 +26837,6 @@ var HoloSphere = (() => {
26642
26837
  };
26643
26838
  }
26644
26839
 
26645
- // hologram.js
26646
- function createHologram(holoInstance, holon, lens, data) {
26647
- if (isHologram(data)) {
26648
- return {
26649
- id: data.id,
26650
- soul: data.soul
26651
- };
26652
- }
26653
- if (!holon || !lens || !data || !data.id) {
26654
- throw new Error("createHologram: Missing required parameters for non-hologram data");
26655
- }
26656
- const soul = `${holoInstance.appname}/${holon}/${lens}/${data.id}`;
26657
- return {
26658
- id: data.id,
26659
- soul
26660
- };
26661
- }
26662
- function parseSoulPath(soul) {
26663
- if (typeof soul !== "string") return null;
26664
- const parts = soul.split("/");
26665
- if (parts.length < 4) return null;
26666
- const key = parts.slice(3).join("/");
26667
- return {
26668
- appname: parts[0],
26669
- holon: parts[1],
26670
- lens: parts[2],
26671
- key
26672
- };
26673
- }
26674
- function isHologram(data) {
26675
- if (!data || typeof data !== "object") {
26676
- return false;
26677
- }
26678
- if (data.id && typeof data.soul === "string" && data.soul.length > 0) {
26679
- if (data.soul.includes("/")) {
26680
- return true;
26681
- }
26682
- }
26683
- return false;
26684
- }
26685
- async function resolveHologram(holoInstance, hologram, options = {}) {
26686
- if (!isHologram(hologram)) {
26687
- return hologram;
26688
- }
26689
- const {
26690
- followHolograms = true,
26691
- visited = /* @__PURE__ */ new Set(),
26692
- maxDepth = 10,
26693
- currentDepth = 0
26694
- } = options;
26695
- if (currentDepth >= maxDepth) {
26696
- console.warn(`!!! Maximum resolution depth (${maxDepth}) reached for soul: ${hologram.soul}. Stopping resolution.`);
26697
- return null;
26698
- }
26699
- if (hologram.soul && visited.has(hologram.soul)) {
26700
- console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}. Breaking loop.`);
26701
- return null;
26702
- }
26703
- try {
26704
- if (hologram.soul) {
26705
- const soulInfo = parseSoulPath(hologram.soul);
26706
- if (!soulInfo) {
26707
- console.warn(`Invalid soul format: ${hologram.soul}`);
26708
- return null;
26709
- }
26710
- const nextVisited = new Set(visited);
26711
- nextVisited.add(hologram.soul);
26712
- const originalData = await holoInstance.get(
26713
- soulInfo.holon,
26714
- soulInfo.lens,
26715
- soulInfo.key,
26716
- null,
26717
- {
26718
- resolveHolograms: followHolograms,
26719
- visited: nextVisited,
26720
- maxDepth,
26721
- currentDepth: currentDepth + 1
26722
- }
26723
- );
26724
- if (originalData && !originalData._invalidHologram) {
26725
- return {
26726
- ...originalData,
26727
- _meta: {
26728
- ...originalData._meta || {},
26729
- // Preserve original _meta
26730
- resolvedFromHologram: true,
26731
- // This is now the primary indicator
26732
- hologramSoul: hologram.soul,
26733
- // Clarified meta field
26734
- resolutionDepth: currentDepth
26735
- }
26736
- };
26737
- } else {
26738
- console.warn(`!!! Original data NOT FOUND for soul: ${hologram.soul}. Removing broken hologram.`);
26739
- return null;
26740
- }
26741
- } else {
26742
- console.warn("!!! resolveHologram called with object missing soul:", hologram);
26743
- return null;
26744
- }
26745
- } catch (error) {
26746
- if (error.message?.startsWith("CIRCULAR_REFERENCE")) {
26747
- console.warn(`!!! Circular reference detected during hologram resolution: ${error.message}`);
26748
- return null;
26749
- }
26750
- console.error(`!!! Error resolving hologram: ${error.message}`, error);
26751
- return null;
26752
- }
26753
- }
26754
-
26755
26840
  // compute.js
26756
26841
  async function computeHierarchy(holoInstance, holon, lens, options, maxLevels = 15, password = null) {
26757
26842
  let currentHolon = holon;
@@ -30225,7 +30310,7 @@ var HoloSphere = (() => {
30225
30310
  this._privateKey = null;
30226
30311
  }
30227
30312
  console.log("HoloSphere v" + HOLOSPHERE_VERSION);
30228
- this.validator = new import__2.default({
30313
+ this.validator = new import__.default({
30229
30314
  allErrors: true,
30230
30315
  strict: false,
30231
30316
  validateSchema: true
@@ -30377,6 +30462,9 @@ var HoloSphere = (() => {
30377
30462
  async resolveHologram(hologram, options = {}) {
30378
30463
  return resolveHologram(this, hologram, options);
30379
30464
  }
30465
+ attachHologramMeta(originalData, hologramSoul) {
30466
+ return attachHologramMeta(originalData, hologramSoul);
30467
+ }
30380
30468
  // ================================ COMPUTE FUNCTIONS ================================
30381
30469
  async computeHierarchy(holon, lens, options, maxLevels = 15, password = null) {
30382
30470
  return computeHierarchy(this, holon, lens, options, maxLevels, password);
@@ -30419,41 +30507,37 @@ var HoloSphere = (() => {
30419
30507
  return federate(this, holonId1, holonId2, password1, password2, bidirectional, lensConfig);
30420
30508
  }
30421
30509
  /**
30422
- * v2-compatible federation creation.
30423
- * Maps v2 options to v1 federate() call.
30510
+ * Convenience wrapper around federate() for the common bidirectional case.
30424
30511
  * @param {string} sourceHolon - Source holon ID
30425
30512
  * @param {string} targetHolon - Target holon ID
30426
30513
  * @param {object} [options] - Federation options
30427
- * @param {object} [options.lensConfig] - Lens configuration
30428
- * @param {string} [options.partnerName] - Name of the partner holon
30429
- * @param {boolean} [options.skipPropagation] - Skip data propagation
30514
+ * @param {object} [options.lensConfig] - Lens config from sourceHolon's perspective
30515
+ * @param {string[]} [options.lensConfig.inbound] - Lenses sourceHolon receives from targetHolon
30516
+ * @param {string[]} [options.lensConfig.outbound] - Lenses sourceHolon sends to targetHolon
30517
+ * @param {string} [options.partnerName] - Display name for the partner
30430
30518
  * @returns {Promise<boolean>}
30431
30519
  */
30432
30520
  async federateHolon(sourceHolon, targetHolon, options = {}) {
30433
30521
  const lensConfig = options.lensConfig || {};
30434
- const lenses = lensConfig.lenses || lensConfig.outbound || lensConfig.federate || [];
30435
- if (options.partnerName) {
30522
+ const inbound = Array.isArray(lensConfig.inbound) ? lensConfig.inbound : [];
30523
+ const outbound = Array.isArray(lensConfig.outbound) ? lensConfig.outbound : [];
30524
+ const ok = await federate(this, sourceHolon, targetHolon, null, null, true, {
30525
+ inbound,
30526
+ outbound
30527
+ });
30528
+ if (ok && options.partnerName) {
30436
30529
  try {
30437
- const fedInfo = await this.getFederation(sourceHolon) || {
30438
- id: sourceHolon,
30439
- name: sourceHolon,
30440
- federation: [],
30441
- notify: [],
30442
- lensConfig: {},
30443
- partnerNames: {},
30444
- timestamp: Date.now()
30445
- };
30446
- if (!fedInfo.partnerNames) fedInfo.partnerNames = {};
30447
- fedInfo.partnerNames[targetHolon] = options.partnerName;
30448
- await this.putGlobal("federation", fedInfo);
30530
+ const fedInfo = await this.getFederation(sourceHolon);
30531
+ if (fedInfo) {
30532
+ if (!fedInfo.partnerNames) fedInfo.partnerNames = {};
30533
+ fedInfo.partnerNames[targetHolon] = options.partnerName;
30534
+ await this.putGlobal("federation", fedInfo);
30535
+ }
30449
30536
  } catch (e) {
30450
30537
  console.warn("Failed to store partner name:", e.message);
30451
30538
  }
30452
30539
  }
30453
- return federate(this, sourceHolon, targetHolon, null, null, true, {
30454
- federate: lenses,
30455
- notify: lenses
30456
- });
30540
+ return ok;
30457
30541
  }
30458
30542
  /**
30459
30543
  * v2-compatible federation removal.