holosphere 1.3.0-alpha0 → 1.3.0-alpha3

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,9 +1,9 @@
1
1
  /**
2
- * HoloSphere ESM Bundle v1.3.0-alpha0
2
+ * HoloSphere ESM Bundle v1.3.0-alpha3
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-alpha0/holosphere-bundle.esm.js';
6
+ * import HoloSphere from 'https://unpkg.com/holosphere@1.3.0-alpha3/holosphere-bundle.esm.js';
7
7
  * const hs = new HoloSphere('myapp');
8
8
  */
9
9
  var __create = Object.create;
@@ -7054,7 +7054,7 @@ var require_core = __commonJS({
7054
7054
  constructor(opts = {}) {
7055
7055
  this.schemas = {};
7056
7056
  this.refs = {};
7057
- this.formats = {};
7057
+ this.formats = /* @__PURE__ */ Object.create(null);
7058
7058
  this._compilations = /* @__PURE__ */ new Set();
7059
7059
  this._loading = {};
7060
7060
  this._cache = /* @__PURE__ */ new Map();
@@ -7835,6 +7835,7 @@ var require_pattern = __commonJS({
7835
7835
  "use strict";
7836
7836
  Object.defineProperty(exports, "__esModule", { value: true });
7837
7837
  var code_1 = require_code2();
7838
+ var util_1 = require_util();
7838
7839
  var codegen_1 = require_codegen();
7839
7840
  var error = {
7840
7841
  message: ({ schemaCode }) => (0, codegen_1.str)`must match pattern "${schemaCode}"`,
@@ -7847,10 +7848,18 @@ var require_pattern = __commonJS({
7847
7848
  $data: true,
7848
7849
  error,
7849
7850
  code(cxt) {
7850
- const { data, $data, schema, schemaCode, it } = cxt;
7851
+ const { gen, data, $data, schema, schemaCode, it } = cxt;
7851
7852
  const u = it.opts.unicodeRegExp ? "u" : "";
7852
- const regExp = $data ? (0, codegen_1._)`(new RegExp(${schemaCode}, ${u}))` : (0, code_1.usePattern)(cxt, schema);
7853
- cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
7853
+ if ($data) {
7854
+ const { regExp } = it.opts.code;
7855
+ const regExpCode = regExp.code === "new RegExp" ? (0, codegen_1._)`new RegExp` : (0, util_1.useFunc)(gen, regExp);
7856
+ const valid = gen.let("valid");
7857
+ gen.try(() => gen.assign(valid, (0, codegen_1._)`${regExpCode}(${schemaCode}, ${u}).test(${data})`), () => gen.assign(valid, false));
7858
+ cxt.fail$data((0, codegen_1._)`!${valid}`);
7859
+ } else {
7860
+ const regExp = (0, code_1.usePattern)(cxt, schema);
7861
+ cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
7862
+ }
7854
7863
  }
7855
7864
  };
7856
7865
  exports.default = def;
@@ -10061,7 +10070,7 @@ var require__ = __commonJS({
10061
10070
  var discriminator_1 = require_discriminator();
10062
10071
  var json_schema_2019_09_1 = require_json_schema_2019_09();
10063
10072
  var META_SCHEMA_ID = "https://json-schema.org/draft/2019-09/schema";
10064
- var Ajv20193 = class extends core_1.default {
10073
+ var Ajv20192 = class extends core_1.default {
10065
10074
  constructor(opts = {}) {
10066
10075
  super({
10067
10076
  ...opts,
@@ -10091,11 +10100,11 @@ var require__ = __commonJS({
10091
10100
  return this.opts.defaultMeta = super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : void 0);
10092
10101
  }
10093
10102
  };
10094
- exports.Ajv2019 = Ajv20193;
10095
- module.exports = exports = Ajv20193;
10096
- module.exports.Ajv2019 = Ajv20193;
10103
+ exports.Ajv2019 = Ajv20192;
10104
+ module.exports = exports = Ajv20192;
10105
+ module.exports.Ajv2019 = Ajv20192;
10097
10106
  Object.defineProperty(exports, "__esModule", { value: true });
10098
- exports.default = Ajv20193;
10107
+ exports.default = Ajv20192;
10099
10108
  var validate_1 = require_validate();
10100
10109
  Object.defineProperty(exports, "KeywordCxt", { enumerable: true, get: function() {
10101
10110
  return validate_1.KeywordCxt;
@@ -24197,7 +24206,120 @@ function degsToRads(deg) {
24197
24206
 
24198
24207
  // holosphere.js
24199
24208
  var import_gun = __toESM(require_browser(), 1);
24200
- var import__2 = __toESM(require__(), 1);
24209
+ var import__ = __toESM(require__(), 1);
24210
+
24211
+ // hologram.js
24212
+ function createHologram(holoInstance, holon, lens, data) {
24213
+ if (isHologram(data)) {
24214
+ return {
24215
+ id: data.id,
24216
+ soul: data.soul
24217
+ };
24218
+ }
24219
+ if (!holon || !lens || !data || !data.id) {
24220
+ throw new Error("createHologram: Missing required parameters for non-hologram data");
24221
+ }
24222
+ const soul = `${holoInstance.appname}/${holon}/${lens}/${data.id}`;
24223
+ return {
24224
+ id: data.id,
24225
+ soul
24226
+ };
24227
+ }
24228
+ function parseSoulPath(soul) {
24229
+ if (typeof soul !== "string") return null;
24230
+ const parts = soul.split("/");
24231
+ if (parts.length < 4) return null;
24232
+ const key = parts.slice(3).join("/");
24233
+ return {
24234
+ appname: parts[0],
24235
+ holon: parts[1],
24236
+ lens: parts[2],
24237
+ key
24238
+ };
24239
+ }
24240
+ function isHologram(data) {
24241
+ if (!data || typeof data !== "object") {
24242
+ return false;
24243
+ }
24244
+ if (data.id && typeof data.soul === "string" && data.soul.length > 0) {
24245
+ if (data.soul.includes("/")) {
24246
+ return true;
24247
+ }
24248
+ }
24249
+ return false;
24250
+ }
24251
+ function attachHologramMeta(originalData, hologramSoul) {
24252
+ const parts = parseSoulPath(hologramSoul);
24253
+ return {
24254
+ ...originalData,
24255
+ _hologram: {
24256
+ isHologram: true,
24257
+ soul: hologramSoul,
24258
+ sourceHolon: parts?.holon ?? null,
24259
+ sourceLens: parts?.lens ?? null,
24260
+ sourceKey: parts?.key ?? null,
24261
+ resolvedAt: Date.now()
24262
+ }
24263
+ };
24264
+ }
24265
+ async function resolveHologram(holoInstance, hologram, options = {}) {
24266
+ if (!isHologram(hologram)) {
24267
+ return hologram;
24268
+ }
24269
+ const {
24270
+ followHolograms = true,
24271
+ visited = /* @__PURE__ */ new Set(),
24272
+ maxDepth = 10,
24273
+ currentDepth = 0
24274
+ } = options;
24275
+ if (currentDepth >= maxDepth) {
24276
+ console.warn(`!!! Maximum resolution depth (${maxDepth}) reached for soul: ${hologram.soul}. Stopping resolution.`);
24277
+ return null;
24278
+ }
24279
+ if (hologram.soul && visited.has(hologram.soul)) {
24280
+ console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}. Breaking loop.`);
24281
+ return null;
24282
+ }
24283
+ try {
24284
+ if (hologram.soul) {
24285
+ const soulInfo = parseSoulPath(hologram.soul);
24286
+ if (!soulInfo) {
24287
+ console.warn(`Invalid soul format: ${hologram.soul}`);
24288
+ return null;
24289
+ }
24290
+ const nextVisited = new Set(visited);
24291
+ nextVisited.add(hologram.soul);
24292
+ const originalData = await holoInstance.get(
24293
+ soulInfo.holon,
24294
+ soulInfo.lens,
24295
+ soulInfo.key,
24296
+ null,
24297
+ {
24298
+ resolveHolograms: followHolograms,
24299
+ visited: nextVisited,
24300
+ maxDepth,
24301
+ currentDepth: currentDepth + 1
24302
+ }
24303
+ );
24304
+ if (originalData && !originalData._invalidHologram) {
24305
+ return attachHologramMeta(originalData, hologram.soul);
24306
+ } else {
24307
+ console.warn(`!!! Original data NOT FOUND for soul: ${hologram.soul}. Removing broken hologram.`);
24308
+ return null;
24309
+ }
24310
+ } else {
24311
+ console.warn("!!! resolveHologram called with object missing soul:", hologram);
24312
+ return null;
24313
+ }
24314
+ } catch (error) {
24315
+ if (error.message?.startsWith("CIRCULAR_REFERENCE")) {
24316
+ console.warn(`!!! Circular reference detected during hologram resolution: ${error.message}`);
24317
+ return null;
24318
+ }
24319
+ console.error(`!!! Error resolving hologram: ${error.message}`, error);
24320
+ return null;
24321
+ }
24322
+ }
24201
24323
 
24202
24324
  // federation.js
24203
24325
  async function federate(holosphere, spaceId1, spaceId2, password1 = null, password2 = null, bidirectional = true, lensConfig = {}) {
@@ -24207,109 +24329,84 @@ async function federate(holosphere, spaceId1, spaceId2, password1 = null, passwo
24207
24329
  if (spaceId1 === spaceId2) {
24208
24330
  throw new Error("Cannot federate a space with itself");
24209
24331
  }
24210
- const { federate: federate2 = [], notify = [] } = lensConfig;
24211
- if (!Array.isArray(federate2) || !Array.isArray(notify)) {
24212
- throw new Error("federate: lensConfig.federate and lensConfig.notify must be arrays");
24213
- }
24214
- const federateLenses = federate2;
24215
- const notifyLenses = notify;
24332
+ const { inbound = [], outbound = [] } = lensConfig;
24333
+ if (!Array.isArray(inbound) || !Array.isArray(outbound)) {
24334
+ throw new Error("federate: lensConfig.inbound and lensConfig.outbound must be arrays");
24335
+ }
24336
+ const applyDirection = (fedInfo, partnerId, partnerInbound, partnerOutbound) => {
24337
+ if (!fedInfo.federated) fedInfo.federated = [];
24338
+ if (!fedInfo.inbound) fedInfo.inbound = [];
24339
+ if (!fedInfo.outbound) fedInfo.outbound = [];
24340
+ if (!fedInfo.lensConfig) fedInfo.lensConfig = {};
24341
+ if (!fedInfo.federated.includes(partnerId)) {
24342
+ fedInfo.federated.push(partnerId);
24343
+ }
24344
+ const hasInbound = partnerInbound.length > 0;
24345
+ const hasOutbound = partnerOutbound.length > 0;
24346
+ if (hasInbound && !fedInfo.inbound.includes(partnerId)) {
24347
+ fedInfo.inbound.push(partnerId);
24348
+ } else if (!hasInbound) {
24349
+ fedInfo.inbound = fedInfo.inbound.filter((id) => id !== partnerId);
24350
+ }
24351
+ if (hasOutbound && !fedInfo.outbound.includes(partnerId)) {
24352
+ fedInfo.outbound.push(partnerId);
24353
+ } else if (!hasOutbound) {
24354
+ fedInfo.outbound = fedInfo.outbound.filter((id) => id !== partnerId);
24355
+ }
24356
+ fedInfo.lensConfig[partnerId] = {
24357
+ inbound: [...partnerInbound],
24358
+ outbound: [...partnerOutbound],
24359
+ timestamp: Date.now()
24360
+ };
24361
+ fedInfo.timestamp = Date.now();
24362
+ };
24216
24363
  try {
24217
24364
  let fedInfo1 = null;
24218
24365
  try {
24219
24366
  fedInfo1 = await holosphere.getGlobal("federation", spaceId1, password1);
24220
- } catch (error) {
24367
+ } catch {
24221
24368
  }
24222
24369
  if (fedInfo1 == null) {
24223
24370
  fedInfo1 = {
24224
24371
  id: spaceId1,
24225
24372
  name: spaceId1,
24226
- federation: [],
24227
- notify: [],
24373
+ federated: [],
24374
+ inbound: [],
24375
+ outbound: [],
24228
24376
  lensConfig: {},
24229
- // New field for lens-specific settings
24377
+ partnerNames: {},
24230
24378
  timestamp: Date.now()
24231
24379
  };
24232
24380
  }
24233
- if (!fedInfo1.federation) fedInfo1.federation = [];
24234
- if (!fedInfo1.notify) fedInfo1.notify = [];
24235
- if (!fedInfo1.lensConfig) fedInfo1.lensConfig = {};
24236
- if (!fedInfo1.federation.includes(spaceId2)) {
24237
- fedInfo1.federation.push(spaceId2);
24238
- }
24239
- if (!fedInfo1.notify.includes(spaceId2)) {
24240
- fedInfo1.notify.push(spaceId2);
24241
- }
24242
- const newLensConfigsForSpace1 = { ...fedInfo1.lensConfig || {} };
24243
- newLensConfigsForSpace1[spaceId2] = {
24244
- // Add/update config for the target spaceId2
24245
- federate: [...federateLenses],
24246
- // federateLenses & notifyLenses are from the main lensConfig parameter
24247
- notify: [...notifyLenses],
24248
- timestamp: Date.now()
24249
- };
24250
- fedInfo1.lensConfig = newLensConfigsForSpace1;
24251
- fedInfo1.timestamp = Date.now();
24381
+ applyDirection(fedInfo1, spaceId2, inbound, outbound);
24252
24382
  try {
24253
24383
  await holosphere.putGlobal("federation", fedInfo1, password1);
24254
24384
  } catch (error) {
24255
24385
  throw new Error(`Failed to create federation: ${error.message}`);
24256
24386
  }
24257
- {
24387
+ if (bidirectional) {
24258
24388
  let fedInfo2 = null;
24259
24389
  try {
24260
24390
  fedInfo2 = await holosphere.getGlobal("federation", spaceId2, password2);
24261
- } catch (error) {
24391
+ } catch {
24262
24392
  }
24263
24393
  if (fedInfo2 == null) {
24264
24394
  fedInfo2 = {
24265
24395
  id: spaceId2,
24266
24396
  name: spaceId2,
24267
- federation: [],
24268
- notify: [],
24397
+ federated: [],
24398
+ inbound: [],
24399
+ outbound: [],
24269
24400
  lensConfig: {},
24270
- // New field for lens-specific settings
24401
+ partnerNames: {},
24271
24402
  timestamp: Date.now()
24272
24403
  };
24273
24404
  }
24274
- if (!fedInfo2.federation) fedInfo2.federation = [];
24275
- if (!fedInfo2.notify) fedInfo2.notify = [];
24276
- if (!fedInfo2.lensConfig) fedInfo2.lensConfig = {};
24277
- if (bidirectional && !fedInfo2.federation.includes(spaceId1)) {
24278
- fedInfo2.federation.push(spaceId1);
24279
- }
24280
- if (!fedInfo2.notify.includes(spaceId1)) {
24281
- fedInfo2.notify.push(spaceId1);
24282
- }
24283
- fedInfo2.lensConfig[spaceId1] = {
24284
- federate: bidirectional ? [...federateLenses] : [],
24285
- // Create a copy of the array
24286
- notify: bidirectional ? [...notifyLenses] : [],
24287
- // Create a copy of the array
24288
- timestamp: Date.now()
24289
- };
24290
- fedInfo2.timestamp = Date.now();
24405
+ applyDirection(fedInfo2, spaceId1, outbound, inbound);
24291
24406
  try {
24292
24407
  await holosphere.putGlobal("federation", fedInfo2, password2);
24293
- } catch (error) {
24294
- }
24295
- }
24296
- const federationMeta = {
24297
- id: `${spaceId1}_${spaceId2}`,
24298
- space1: spaceId1,
24299
- space2: spaceId2,
24300
- created: Date.now(),
24301
- status: "active",
24302
- bidirectional,
24303
- lensConfig: {
24304
- federate: [...federateLenses],
24305
- // Create a copy of the array
24306
- notify: [...notifyLenses]
24307
- // Create a copy of the array
24408
+ } catch {
24308
24409
  }
24309
- };
24310
- try {
24311
- await holosphere.putGlobal("federationMeta", federationMeta);
24312
- } catch (error) {
24313
24410
  }
24314
24411
  return true;
24315
24412
  } catch (error) {
@@ -24327,8 +24424,8 @@ async function subscribeFederation(holosphere, spaceId, password = null, callbac
24327
24424
  }
24328
24425
  const subscriptions2 = [];
24329
24426
  let lastNotificationTime = {};
24330
- if (fedInfo.federation && fedInfo.federation.length > 0) {
24331
- for (const federatedSpace of fedInfo.federation) {
24427
+ if (fedInfo.inbound && fedInfo.inbound.length > 0) {
24428
+ for (const federatedSpace of fedInfo.inbound) {
24332
24429
  for (const lens of lenses) {
24333
24430
  try {
24334
24431
  const sub = await holosphere.subscribe(federatedSpace, lens, async (data) => {
@@ -24390,8 +24487,8 @@ async function getFederatedConfig(holosphere, spaceId, targetSpaceId, password =
24390
24487
  const fedInfo = await getFederation(holosphere, spaceId, password);
24391
24488
  if (fedInfo && fedInfo.lensConfig && fedInfo.lensConfig[targetSpaceId]) {
24392
24489
  return {
24393
- federate: fedInfo.lensConfig[targetSpaceId].federate || [],
24394
- notify: fedInfo.lensConfig[targetSpaceId].notify || []
24490
+ inbound: fedInfo.lensConfig[targetSpaceId].inbound || [],
24491
+ outbound: fedInfo.lensConfig[targetSpaceId].outbound || []
24395
24492
  };
24396
24493
  }
24397
24494
  return null;
@@ -24414,14 +24511,20 @@ async function unfederate(holosphere, spaceId1, spaceId2, password1 = null, pass
24414
24511
  if (!fedInfo1) {
24415
24512
  console.warn(`No federation info found for ${spaceId1}. Skipping its update.`);
24416
24513
  } else {
24417
- if (!fedInfo1.federation) fedInfo1.federation = [];
24418
- if (!fedInfo1.notify) fedInfo1.notify = [];
24419
- const originalFederationLength = fedInfo1.federation.length;
24420
- const originalNotifyLength = fedInfo1.notify.length;
24421
- fedInfo1.federation = fedInfo1.federation.filter((id) => id !== spaceId2);
24422
- fedInfo1.notify = fedInfo1.notify.filter((id) => id !== spaceId2);
24514
+ if (!fedInfo1.federated) fedInfo1.federated = [];
24515
+ if (!fedInfo1.inbound) fedInfo1.inbound = [];
24516
+ if (!fedInfo1.outbound) fedInfo1.outbound = [];
24517
+ if (!fedInfo1.lensConfig) fedInfo1.lensConfig = {};
24518
+ if (!fedInfo1.partnerNames) fedInfo1.partnerNames = {};
24519
+ const beforeIn = fedInfo1.inbound.length;
24520
+ const beforeOut = fedInfo1.outbound.length;
24521
+ fedInfo1.federated = fedInfo1.federated.filter((id) => id !== spaceId2);
24522
+ fedInfo1.inbound = fedInfo1.inbound.filter((id) => id !== spaceId2);
24523
+ fedInfo1.outbound = fedInfo1.outbound.filter((id) => id !== spaceId2);
24524
+ delete fedInfo1.lensConfig[spaceId2];
24525
+ delete fedInfo1.partnerNames[spaceId2];
24423
24526
  fedInfo1.timestamp = Date.now();
24424
- console.log(`Unfederate: Removed ${spaceId2} from ${spaceId1}: federation ${originalFederationLength} -> ${fedInfo1.federation.length}, notify ${originalNotifyLength} -> ${fedInfo1.notify.length}`);
24527
+ console.log(`Unfederate: removed ${spaceId2} from ${spaceId1}: inbound ${beforeIn} -> ${fedInfo1.inbound.length}, outbound ${beforeOut} -> ${fedInfo1.outbound.length}`);
24425
24528
  try {
24426
24529
  await holosphere.putGlobal("federation", fedInfo1, password1);
24427
24530
  } catch (error) {
@@ -24436,10 +24539,19 @@ async function unfederate(holosphere, spaceId1, spaceId2, password1 = null, pass
24436
24539
  } catch (error) {
24437
24540
  console.error(`Error getting fedInfo2 for ${spaceId2} during unfederate: ${error.message}`);
24438
24541
  }
24439
- if (!fedInfo2 || !fedInfo2.notify) {
24440
- console.warn(`No notify array found for ${spaceId2} or fedInfo2 is null. Skipping its update.`);
24542
+ if (!fedInfo2) {
24543
+ console.warn(`No federation info found for ${spaceId2}. Skipping its update.`);
24441
24544
  } else {
24442
- fedInfo2.notify = fedInfo2.notify.filter((id) => id !== spaceId1);
24545
+ if (!fedInfo2.federated) fedInfo2.federated = [];
24546
+ if (!fedInfo2.inbound) fedInfo2.inbound = [];
24547
+ if (!fedInfo2.outbound) fedInfo2.outbound = [];
24548
+ if (!fedInfo2.lensConfig) fedInfo2.lensConfig = {};
24549
+ if (!fedInfo2.partnerNames) fedInfo2.partnerNames = {};
24550
+ fedInfo2.federated = fedInfo2.federated.filter((id) => id !== spaceId1);
24551
+ fedInfo2.inbound = fedInfo2.inbound.filter((id) => id !== spaceId1);
24552
+ fedInfo2.outbound = fedInfo2.outbound.filter((id) => id !== spaceId1);
24553
+ delete fedInfo2.lensConfig[spaceId1];
24554
+ delete fedInfo2.partnerNames[spaceId1];
24443
24555
  fedInfo2.timestamp = Date.now();
24444
24556
  try {
24445
24557
  await holosphere.putGlobal("federation", fedInfo2, password2);
@@ -24472,19 +24584,19 @@ async function removeNotify(holosphere, spaceId1, spaceId2, password1 = null) {
24472
24584
  throw new Error("removeNotify: Missing required space IDs");
24473
24585
  }
24474
24586
  try {
24475
- let fedInfo = await holosphere.getGlobal("federation", spaceId1, password1);
24587
+ const fedInfo = await holosphere.getGlobal("federation", spaceId1, password1);
24476
24588
  if (!fedInfo) {
24477
24589
  throw new Error(`No federation info found for ${spaceId1}`);
24478
24590
  }
24479
- if (!fedInfo.notify) fedInfo.notify = [];
24480
- if (fedInfo.notify.includes(spaceId2)) {
24481
- fedInfo.notify = fedInfo.notify.filter((id) => id !== spaceId2);
24482
- fedInfo.timestamp = Date.now();
24483
- await holosphere.putGlobal("federation", fedInfo, password1);
24484
- return true;
24485
- } else {
24486
- return false;
24591
+ if (!fedInfo.outbound) fedInfo.outbound = [];
24592
+ if (!fedInfo.outbound.includes(spaceId2)) return false;
24593
+ fedInfo.outbound = fedInfo.outbound.filter((id) => id !== spaceId2);
24594
+ if (fedInfo.lensConfig?.[spaceId2]) {
24595
+ fedInfo.lensConfig[spaceId2].outbound = [];
24487
24596
  }
24597
+ fedInfo.timestamp = Date.now();
24598
+ await holosphere.putGlobal("federation", fedInfo, password1);
24599
+ return true;
24488
24600
  } catch (error) {
24489
24601
  throw error;
24490
24602
  }
@@ -24519,8 +24631,8 @@ async function getFederated(holosphere, holon, lens, options = {}) {
24519
24631
  if (includeLocal) {
24520
24632
  spacesToQuery.push(holon);
24521
24633
  }
24522
- if (includeFederated && fedInfo && fedInfo.federation && fedInfo.federation.length > 0) {
24523
- const federatedSpaces = maxFederatedSpaces === -1 ? fedInfo.federation : fedInfo.federation.slice(0, maxFederatedSpaces);
24634
+ if (includeFederated && fedInfo && fedInfo.inbound && fedInfo.inbound.length > 0) {
24635
+ const federatedSpaces = maxFederatedSpaces === -1 ? fedInfo.inbound : fedInfo.inbound.slice(0, maxFederatedSpaces);
24524
24636
  spacesToQuery = spacesToQuery.concat(federatedSpaces);
24525
24637
  }
24526
24638
  for (const currentSpace of spacesToQuery) {
@@ -24577,24 +24689,15 @@ async function getFederated(holosphere, holon, lens, options = {}) {
24577
24689
  );
24578
24690
  console.log(`Original data found via soul path:`, JSON.stringify(originalData));
24579
24691
  if (originalData) {
24580
- result[i] = {
24581
- ...originalData,
24582
- _federation: {
24583
- isReference: true,
24584
- resolved: true,
24585
- soul: item.soul,
24586
- timestamp: Date.now()
24587
- }
24588
- };
24692
+ result[i] = attachHologramMeta(originalData, item.soul);
24589
24693
  } else {
24590
24694
  result[i] = {
24591
24695
  id: item.id,
24592
- _federation: {
24593
- isReference: true,
24594
- resolved: false,
24696
+ _hologram: {
24697
+ isHologram: false,
24595
24698
  soul: item.soul,
24596
24699
  error: "Referenced data not found",
24597
- timestamp: Date.now()
24700
+ resolvedAt: Date.now()
24598
24701
  }
24599
24702
  };
24600
24703
  }
@@ -24602,55 +24705,25 @@ async function getFederated(holosphere, holon, lens, options = {}) {
24602
24705
  console.warn(`Soul doesn't match expected format: ${item.soul}`);
24603
24706
  result[i] = {
24604
24707
  id: item.id,
24605
- _federation: {
24606
- isReference: true,
24607
- resolved: false,
24708
+ _hologram: {
24709
+ isHologram: false,
24608
24710
  soul: item.soul,
24609
24711
  error: "Invalid soul format",
24610
- timestamp: Date.now()
24712
+ resolvedAt: Date.now()
24611
24713
  }
24612
24714
  };
24613
24715
  }
24614
24716
  } catch (refError) {
24615
24717
  result[i] = {
24616
24718
  id: item.id,
24617
- _federation: {
24618
- isReference: true,
24619
- resolved: false,
24719
+ _hologram: {
24720
+ isHologram: false,
24620
24721
  soul: item.soul,
24621
24722
  error: refError.message || "Error resolving reference",
24622
- timestamp: Date.now()
24723
+ resolvedAt: Date.now()
24623
24724
  }
24624
24725
  };
24625
24726
  }
24626
- } else if (item._federation && item._federation.isReference) {
24627
- console.log(`Found legacy reference: ${item._federation.origin}/${item._federation.lens}/${item[idField]}`);
24628
- try {
24629
- const reference = item._federation;
24630
- console.log(`Getting original data from ${reference.origin} / ${reference.lens} / ${item[idField]}`);
24631
- const originalData = await holosphere.get(
24632
- reference.origin,
24633
- reference.lens,
24634
- item[idField],
24635
- null,
24636
- { resolveReferences: false }
24637
- // Prevent infinite recursion
24638
- );
24639
- console.log(`Original data found:`, JSON.stringify(originalData));
24640
- if (originalData) {
24641
- result[i] = {
24642
- ...originalData,
24643
- _federation: {
24644
- ...reference,
24645
- resolved: true,
24646
- timestamp: Date.now()
24647
- }
24648
- };
24649
- } else {
24650
- console.warn(`Could not resolve legacy reference: original data not found`);
24651
- }
24652
- } catch (refError) {
24653
- }
24654
24727
  }
24655
24728
  }
24656
24729
  }
@@ -24717,8 +24790,8 @@ async function propagate(holosphere, holon, lens, data, options = {}) {
24717
24790
  };
24718
24791
  try {
24719
24792
  const fedInfo = await getFederation(holosphere, holon, password);
24720
- if (fedInfo && fedInfo.federation && fedInfo.federation.length > 0 && fedInfo.notify && fedInfo.notify.length > 0) {
24721
- let spaces = fedInfo.notify;
24793
+ if (fedInfo && fedInfo.outbound && fedInfo.outbound.length > 0) {
24794
+ let spaces = fedInfo.outbound;
24722
24795
  if (targetSpaces && Array.isArray(targetSpaces) && targetSpaces.length > 0) {
24723
24796
  spaces = spaces.filter((space) => targetSpaces.includes(space));
24724
24797
  }
@@ -24730,11 +24803,10 @@ async function propagate(holosphere, holon, lens, data, options = {}) {
24730
24803
  result.skipped++;
24731
24804
  return false;
24732
24805
  }
24733
- const federateLenses = Array.isArray(spaceConfig.federate) ? spaceConfig.federate : [];
24734
- const shouldFederate = federateLenses.includes("*") || federateLenses.includes(lens);
24735
- const shouldPropagate = shouldFederate;
24806
+ const outboundLenses = Array.isArray(spaceConfig.outbound) ? spaceConfig.outbound : [];
24807
+ const shouldPropagate = outboundLenses.includes("*") || outboundLenses.includes(lens);
24736
24808
  if (!shouldPropagate) {
24737
- result.messages.push(`Propagation of lens '${lens}' to target space ${targetSpace} skipped: lens not in 'federate' configuration.`);
24809
+ result.messages.push(`Propagation of lens '${lens}' to target space ${targetSpace} skipped: lens not in 'outbound' configuration.`);
24738
24810
  result.skipped++;
24739
24811
  }
24740
24812
  return shouldPropagate;
@@ -24963,60 +25035,64 @@ async function resetFederation(holosphere, spaceId, password = null, options = {
24963
25035
  message: "No federation configuration found for this space"
24964
25036
  };
24965
25037
  }
24966
- result.federatedCount = fedInfo.federation?.length || 0;
24967
- result.notifyCount = fedInfo.notify?.length || 0;
25038
+ const allPartners = fedInfo.federated || [];
25039
+ result.federatedCount = allPartners.length;
25040
+ result.inboundCount = fedInfo.inbound?.length || 0;
25041
+ result.outboundCount = fedInfo.outbound?.length || 0;
24968
25042
  const emptyFedInfo = {
24969
25043
  id: spaceId,
24970
25044
  name: spaceName || spaceId,
24971
- federation: [],
24972
- notify: [],
25045
+ federated: [],
25046
+ inbound: [],
25047
+ outbound: [],
25048
+ lensConfig: {},
25049
+ partnerNames: {},
24973
25050
  timestamp: Date.now()
24974
25051
  };
24975
25052
  await holosphere.putGlobal("federation", emptyFedInfo, password);
24976
- if (notifyPartners && fedInfo.federation && fedInfo.federation.length > 0) {
24977
- const updatePromises = fedInfo.federation.map(async (partnerSpace) => {
25053
+ if (notifyPartners && allPartners.length > 0) {
25054
+ const updatePromises = allPartners.map(async (partnerSpace) => {
24978
25055
  try {
24979
25056
  const partnerFedInfo = await getFederation(holosphere, partnerSpace);
24980
- if (partnerFedInfo) {
24981
- if (partnerFedInfo.federation) {
24982
- partnerFedInfo.federation = partnerFedInfo.federation.filter(
24983
- (id) => id !== spaceId.toString()
24984
- );
24985
- }
24986
- if (partnerFedInfo.notify) {
24987
- partnerFedInfo.notify = partnerFedInfo.notify.filter(
24988
- (id) => id !== spaceId.toString()
24989
- );
24990
- }
24991
- partnerFedInfo.timestamp = Date.now();
24992
- await holosphere.putGlobal("federation", partnerFedInfo);
24993
- result.partnersNotified++;
24994
- return true;
25057
+ if (!partnerFedInfo) return false;
25058
+ const sid = spaceId.toString();
25059
+ if (partnerFedInfo.federated) {
25060
+ partnerFedInfo.federated = partnerFedInfo.federated.filter((id) => id !== sid);
24995
25061
  }
24996
- return false;
25062
+ if (partnerFedInfo.inbound) {
25063
+ partnerFedInfo.inbound = partnerFedInfo.inbound.filter((id) => id !== sid);
25064
+ }
25065
+ if (partnerFedInfo.outbound) {
25066
+ partnerFedInfo.outbound = partnerFedInfo.outbound.filter((id) => id !== sid);
25067
+ }
25068
+ if (partnerFedInfo.lensConfig) {
25069
+ delete partnerFedInfo.lensConfig[sid];
25070
+ }
25071
+ if (partnerFedInfo.partnerNames) {
25072
+ delete partnerFedInfo.partnerNames[sid];
25073
+ }
25074
+ partnerFedInfo.timestamp = Date.now();
25075
+ await holosphere.putGlobal("federation", partnerFedInfo);
25076
+ result.partnersNotified++;
25077
+ return true;
24997
25078
  } catch (error) {
24998
- result.errors.push({
24999
- partner: partnerSpace,
25000
- error: error.message
25001
- });
25079
+ result.errors.push({ partner: partnerSpace, error: error.message });
25002
25080
  return false;
25003
25081
  }
25004
25082
  });
25005
25083
  await Promise.all(updatePromises);
25006
25084
  }
25007
- if (fedInfo.federation && fedInfo.federation.length > 0) {
25008
- for (const partnerSpace of fedInfo.federation) {
25009
- try {
25010
- const metaId = `${spaceId}_${partnerSpace}`;
25011
- const altMetaId = `${partnerSpace}_${spaceId}`;
25012
- const meta = await holosphere.getGlobal("federationMeta", metaId) || await holosphere.getGlobal("federationMeta", altMetaId);
25013
- if (meta) {
25014
- meta.status = "inactive";
25015
- meta.endedAt = Date.now();
25016
- await holosphere.putGlobal("federationMeta", meta);
25017
- }
25018
- } catch (error) {
25085
+ for (const partnerSpace of allPartners) {
25086
+ try {
25087
+ const metaId = `${spaceId}_${partnerSpace}`;
25088
+ const altMetaId = `${partnerSpace}_${spaceId}`;
25089
+ const meta = await holosphere.getGlobal("federationMeta", metaId) || await holosphere.getGlobal("federationMeta", altMetaId);
25090
+ if (meta) {
25091
+ meta.status = "inactive";
25092
+ meta.endedAt = Date.now();
25093
+ await holosphere.putGlobal("federationMeta", meta);
25019
25094
  }
25095
+ } catch {
25020
25096
  }
25021
25097
  }
25022
25098
  result.success = true;
@@ -25031,7 +25107,6 @@ async function resetFederation(holosphere, spaceId, password = null, options = {
25031
25107
  }
25032
25108
 
25033
25109
  // schema.js
25034
- var import__ = __toESM(require__(), 1);
25035
25110
  async function setSchema(holoInstance, lens, schema) {
25036
25111
  if (!lens || !schema) {
25037
25112
  throw new Error("setSchema: Missing required parameters");
@@ -25214,6 +25289,9 @@ async function put(holoInstance, holon, lens, data, password = null, options = {
25214
25289
  if (dataToStore._meta !== void 0) {
25215
25290
  delete dataToStore._meta;
25216
25291
  }
25292
+ if (dataToStore._hologram !== void 0) {
25293
+ delete dataToStore._hologram;
25294
+ }
25217
25295
  const payload = JSON.stringify(dataToStore);
25218
25296
  const putCallback = async (ack) => {
25219
25297
  if (ack.err) {
@@ -25503,7 +25581,8 @@ async function getAll(holoInstance, holon, lens, password = null) {
25503
25581
  const output = /* @__PURE__ */ new Map();
25504
25582
  const pendingProcessing = [];
25505
25583
  const dataPath = password ? user.get("private").get(lens) : holoInstance.gun.get(holoInstance.appname).get(holon).get(lens);
25506
- dataPath.once((data) => {
25584
+ const shallowOnce = () => new Promise((res) => dataPath.once((d) => res(d)));
25585
+ const processShallow = (data) => {
25507
25586
  if (!data) {
25508
25587
  resolve([]);
25509
25588
  return;
@@ -25520,72 +25599,75 @@ async function getAll(holoInstance, holon, lens, password = null) {
25520
25599
  resolve([]);
25521
25600
  return;
25522
25601
  }
25523
- let receivedCount = 0;
25524
- dataPath.map().once(async (itemData, key) => {
25525
- if (!itemData || key === "_") {
25526
- receivedCount++;
25527
- if (receivedCount >= expectedCount) {
25528
- await Promise.all(pendingProcessing);
25529
- resolve(Array.from(output.values()));
25530
- }
25531
- return;
25532
- }
25533
- const processingPromise = (async () => {
25534
- try {
25535
- const parsed = await holoInstance.parse(itemData);
25536
- if (!parsed || !parsed.id) return;
25537
- if (holoInstance.isHologram(parsed)) {
25538
- try {
25539
- const resolved = await holoInstance.resolveHologram(parsed, {
25540
- followHolograms: true,
25541
- maxDepth: 10,
25542
- currentDepth: 0
25543
- });
25544
- if (resolved === null) {
25545
- console.warn(`Broken hologram detected in getAll for key ${key}. Removing it...`);
25546
- try {
25547
- await holoInstance.delete(holon, lens, key, password);
25548
- } catch (cleanupError) {
25549
- console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
25550
- }
25551
- return;
25602
+ const processItem = async (itemData, key) => {
25603
+ if (!itemData) return;
25604
+ try {
25605
+ const parsed = await holoInstance.parse(itemData);
25606
+ if (!parsed || !parsed.id) return;
25607
+ if (holoInstance.isHologram(parsed)) {
25608
+ try {
25609
+ const resolved = await holoInstance.resolveHologram(parsed, {
25610
+ followHolograms: true,
25611
+ maxDepth: 10,
25612
+ currentDepth: 0
25613
+ });
25614
+ if (resolved === null) {
25615
+ console.warn(`Broken hologram detected in getAll for key ${key}. Removing it...`);
25616
+ try {
25617
+ await holoInstance.delete(holon, lens, key, password);
25618
+ } catch (cleanupError) {
25619
+ console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
25552
25620
  }
25553
- if (resolved && resolved !== parsed) {
25554
- if (schema) {
25555
- const valid = holoInstance.validator.validate(schema, resolved);
25556
- if (valid || !holoInstance.strict) {
25557
- output.set(resolved.id, resolved);
25558
- }
25559
- } else {
25621
+ return;
25622
+ }
25623
+ if (resolved && resolved !== parsed) {
25624
+ if (schema) {
25625
+ const valid = holoInstance.validator.validate(schema, resolved);
25626
+ if (valid || !holoInstance.strict) {
25560
25627
  output.set(resolved.id, resolved);
25561
25628
  }
25562
- return;
25629
+ } else {
25630
+ output.set(resolved.id, resolved);
25563
25631
  }
25564
- } catch (hologramError) {
25565
- console.error(`Error resolving hologram for key ${key}:`, hologramError);
25566
25632
  return;
25567
25633
  }
25634
+ } catch (hologramError) {
25635
+ console.error(`Error resolving hologram for key ${key}:`, hologramError);
25636
+ return;
25568
25637
  }
25569
- if (schema) {
25570
- const valid = holoInstance.validator.validate(schema, parsed);
25571
- if (valid || !holoInstance.strict) {
25572
- output.set(parsed.id, parsed);
25573
- }
25574
- } else {
25638
+ }
25639
+ if (schema) {
25640
+ const valid = holoInstance.validator.validate(schema, parsed);
25641
+ if (valid || !holoInstance.strict) {
25575
25642
  output.set(parsed.id, parsed);
25576
25643
  }
25577
- } catch (error) {
25578
- console.error("Error processing data:", error);
25644
+ } else {
25645
+ output.set(parsed.id, parsed);
25579
25646
  }
25580
- })();
25581
- pendingProcessing.push(processingPromise);
25582
- receivedCount++;
25583
- if (receivedCount >= expectedCount) {
25584
- await Promise.all(pendingProcessing);
25585
- resolve(Array.from(output.values()));
25647
+ } catch (error) {
25648
+ console.error("Error processing data:", error);
25586
25649
  }
25587
- });
25588
- });
25650
+ };
25651
+ Promise.all(keys.map((key) => {
25652
+ const inline = data[key];
25653
+ if (typeof inline !== "object" || inline === null) {
25654
+ return processItem(inline, key);
25655
+ }
25656
+ return new Promise((resolveItem) => {
25657
+ dataPath.get(key).once((itemData) => {
25658
+ processItem(itemData, key).then(resolveItem, resolveItem);
25659
+ });
25660
+ });
25661
+ })).then(() => resolve(Array.from(output.values())));
25662
+ };
25663
+ (async () => {
25664
+ let data = await shallowOnce();
25665
+ if (!data) {
25666
+ await new Promise((r) => setTimeout(r, 1500));
25667
+ data = await shallowOnce();
25668
+ }
25669
+ processShallow(data);
25670
+ })();
25589
25671
  });
25590
25672
  } catch (error) {
25591
25673
  console.error("Error in getAll:", error);
@@ -26064,6 +26146,9 @@ async function putGlobal(holoInstance, tableName, data, password = null) {
26064
26146
  if (dataToStore._meta !== void 0) {
26065
26147
  delete dataToStore._meta;
26066
26148
  }
26149
+ if (dataToStore._hologram !== void 0) {
26150
+ delete dataToStore._hologram;
26151
+ }
26067
26152
  const payload = JSON.stringify(dataToStore);
26068
26153
  const isHologram2 = holoInstance.isHologram(dataToStore);
26069
26154
  const dataPath = password ? user.get("private").get(tableName) : holoInstance.gun.get(holoInstance.appname).get(tableName);
@@ -26264,7 +26349,8 @@ async function getAllGlobal(holoInstance, tableName, password = null) {
26264
26349
  const output = [];
26265
26350
  const pendingProcessing = [];
26266
26351
  const dataPath = password ? user.get("private").get(tableName) : holoInstance.gun.get(holoInstance.appname).get(tableName);
26267
- dataPath.once((data) => {
26352
+ const shallowOnce = () => new Promise((res) => dataPath.once((d) => res(d)));
26353
+ const processShallow = (data) => {
26268
26354
  if (!data) {
26269
26355
  resolve([]);
26270
26356
  return;
@@ -26281,52 +26367,55 @@ async function getAllGlobal(holoInstance, tableName, password = null) {
26281
26367
  resolve([]);
26282
26368
  return;
26283
26369
  }
26284
- let receivedCount = 0;
26285
- dataPath.map().once(async (itemData, key) => {
26286
- if (!itemData || key === "_") {
26287
- receivedCount++;
26288
- if (receivedCount >= expectedCount) {
26289
- await Promise.all(pendingProcessing);
26290
- resolve(output);
26291
- }
26292
- return;
26293
- }
26294
- const processingPromise = (async () => {
26295
- try {
26296
- const parsed = await holoInstance.parse(itemData);
26297
- if (!parsed) return;
26298
- if (holoInstance.isHologram(parsed)) {
26299
- const resolved = await holoInstance.resolveHologram(parsed, {
26300
- followHolograms: true
26301
- });
26302
- if (resolved === null) {
26303
- try {
26304
- await holoInstance.deleteGlobal(tableName, key, password);
26305
- } catch (deleteError) {
26306
- console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
26307
- }
26308
- return;
26309
- }
26310
- if (resolved !== parsed) {
26311
- output.push(resolved);
26312
- } else {
26313
- output.push(parsed);
26370
+ const processItem = async (itemData, key) => {
26371
+ if (!itemData) return;
26372
+ try {
26373
+ const parsed = await holoInstance.parse(itemData);
26374
+ if (!parsed) return;
26375
+ if (holoInstance.isHologram(parsed)) {
26376
+ const resolved = await holoInstance.resolveHologram(parsed, {
26377
+ followHolograms: true
26378
+ });
26379
+ if (resolved === null) {
26380
+ try {
26381
+ await holoInstance.deleteGlobal(tableName, key, password);
26382
+ } catch (deleteError) {
26383
+ console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
26314
26384
  }
26385
+ return;
26386
+ }
26387
+ if (resolved !== parsed) {
26388
+ output.push(resolved);
26315
26389
  } else {
26316
26390
  output.push(parsed);
26317
26391
  }
26318
- } catch (error) {
26319
- console.error("Error parsing data:", error);
26392
+ } else {
26393
+ output.push(parsed);
26320
26394
  }
26321
- })();
26322
- pendingProcessing.push(processingPromise);
26323
- receivedCount++;
26324
- if (receivedCount >= expectedCount) {
26325
- await Promise.all(pendingProcessing);
26326
- resolve(output);
26395
+ } catch (error) {
26396
+ console.error("Error parsing data:", error);
26327
26397
  }
26328
- });
26329
- });
26398
+ };
26399
+ Promise.all(keys.map((key) => {
26400
+ const inline = data[key];
26401
+ if (typeof inline !== "object" || inline === null) {
26402
+ return processItem(inline, key);
26403
+ }
26404
+ return new Promise((resolveItem) => {
26405
+ dataPath.get(key).once((itemData) => {
26406
+ processItem(itemData, key).then(resolveItem, resolveItem);
26407
+ });
26408
+ });
26409
+ })).then(() => resolve(output));
26410
+ };
26411
+ (async () => {
26412
+ let data = await shallowOnce();
26413
+ if (!data) {
26414
+ await new Promise((r) => setTimeout(r, 1500));
26415
+ data = await shallowOnce();
26416
+ }
26417
+ processShallow(data);
26418
+ })();
26330
26419
  });
26331
26420
  } catch (error) {
26332
26421
  console.error("Error in getAllGlobal:", error);
@@ -26616,116 +26705,6 @@ async function subscribeGlobal(holoInstance, tableName, key, callback, options =
26616
26705
  };
26617
26706
  }
26618
26707
 
26619
- // hologram.js
26620
- function createHologram(holoInstance, holon, lens, data) {
26621
- if (isHologram(data)) {
26622
- return {
26623
- id: data.id,
26624
- soul: data.soul
26625
- };
26626
- }
26627
- if (!holon || !lens || !data || !data.id) {
26628
- throw new Error("createHologram: Missing required parameters for non-hologram data");
26629
- }
26630
- const soul = `${holoInstance.appname}/${holon}/${lens}/${data.id}`;
26631
- return {
26632
- id: data.id,
26633
- soul
26634
- };
26635
- }
26636
- function parseSoulPath(soul) {
26637
- if (typeof soul !== "string") return null;
26638
- const parts = soul.split("/");
26639
- if (parts.length < 4) return null;
26640
- const key = parts.slice(3).join("/");
26641
- return {
26642
- appname: parts[0],
26643
- holon: parts[1],
26644
- lens: parts[2],
26645
- key
26646
- };
26647
- }
26648
- function isHologram(data) {
26649
- if (!data || typeof data !== "object") {
26650
- return false;
26651
- }
26652
- if (data.id && typeof data.soul === "string" && data.soul.length > 0) {
26653
- if (data.soul.includes("/")) {
26654
- return true;
26655
- }
26656
- }
26657
- return false;
26658
- }
26659
- async function resolveHologram(holoInstance, hologram, options = {}) {
26660
- if (!isHologram(hologram)) {
26661
- return hologram;
26662
- }
26663
- const {
26664
- followHolograms = true,
26665
- visited = /* @__PURE__ */ new Set(),
26666
- maxDepth = 10,
26667
- currentDepth = 0
26668
- } = options;
26669
- if (currentDepth >= maxDepth) {
26670
- console.warn(`!!! Maximum resolution depth (${maxDepth}) reached for soul: ${hologram.soul}. Stopping resolution.`);
26671
- return null;
26672
- }
26673
- if (hologram.soul && visited.has(hologram.soul)) {
26674
- console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}. Breaking loop.`);
26675
- return null;
26676
- }
26677
- try {
26678
- if (hologram.soul) {
26679
- const soulInfo = parseSoulPath(hologram.soul);
26680
- if (!soulInfo) {
26681
- console.warn(`Invalid soul format: ${hologram.soul}`);
26682
- return null;
26683
- }
26684
- const nextVisited = new Set(visited);
26685
- nextVisited.add(hologram.soul);
26686
- const originalData = await holoInstance.get(
26687
- soulInfo.holon,
26688
- soulInfo.lens,
26689
- soulInfo.key,
26690
- null,
26691
- {
26692
- resolveHolograms: followHolograms,
26693
- visited: nextVisited,
26694
- maxDepth,
26695
- currentDepth: currentDepth + 1
26696
- }
26697
- );
26698
- if (originalData && !originalData._invalidHologram) {
26699
- return {
26700
- ...originalData,
26701
- _meta: {
26702
- ...originalData._meta || {},
26703
- // Preserve original _meta
26704
- resolvedFromHologram: true,
26705
- // This is now the primary indicator
26706
- hologramSoul: hologram.soul,
26707
- // Clarified meta field
26708
- resolutionDepth: currentDepth
26709
- }
26710
- };
26711
- } else {
26712
- console.warn(`!!! Original data NOT FOUND for soul: ${hologram.soul}. Removing broken hologram.`);
26713
- return null;
26714
- }
26715
- } else {
26716
- console.warn("!!! resolveHologram called with object missing soul:", hologram);
26717
- return null;
26718
- }
26719
- } catch (error) {
26720
- if (error.message?.startsWith("CIRCULAR_REFERENCE")) {
26721
- console.warn(`!!! Circular reference detected during hologram resolution: ${error.message}`);
26722
- return null;
26723
- }
26724
- console.error(`!!! Error resolving hologram: ${error.message}`, error);
26725
- return null;
26726
- }
26727
- }
26728
-
26729
26708
  // compute.js
26730
26709
  async function computeHierarchy(holoInstance, holon, lens, options, maxLevels = 15, password = null) {
26731
26710
  let currentHolon = holon;
@@ -30199,7 +30178,7 @@ var HoloSphere = class {
30199
30178
  this._privateKey = null;
30200
30179
  }
30201
30180
  console.log("HoloSphere v" + HOLOSPHERE_VERSION);
30202
- this.validator = new import__2.default({
30181
+ this.validator = new import__.default({
30203
30182
  allErrors: true,
30204
30183
  strict: false,
30205
30184
  validateSchema: true
@@ -30351,6 +30330,9 @@ var HoloSphere = class {
30351
30330
  async resolveHologram(hologram, options = {}) {
30352
30331
  return resolveHologram(this, hologram, options);
30353
30332
  }
30333
+ attachHologramMeta(originalData, hologramSoul) {
30334
+ return attachHologramMeta(originalData, hologramSoul);
30335
+ }
30354
30336
  // ================================ COMPUTE FUNCTIONS ================================
30355
30337
  async computeHierarchy(holon, lens, options, maxLevels = 15, password = null) {
30356
30338
  return computeHierarchy(this, holon, lens, options, maxLevels, password);
@@ -30393,41 +30375,37 @@ var HoloSphere = class {
30393
30375
  return federate(this, holonId1, holonId2, password1, password2, bidirectional, lensConfig);
30394
30376
  }
30395
30377
  /**
30396
- * v2-compatible federation creation.
30397
- * Maps v2 options to v1 federate() call.
30378
+ * Convenience wrapper around federate() for the common bidirectional case.
30398
30379
  * @param {string} sourceHolon - Source holon ID
30399
30380
  * @param {string} targetHolon - Target holon ID
30400
30381
  * @param {object} [options] - Federation options
30401
- * @param {object} [options.lensConfig] - Lens configuration
30402
- * @param {string} [options.partnerName] - Name of the partner holon
30403
- * @param {boolean} [options.skipPropagation] - Skip data propagation
30382
+ * @param {object} [options.lensConfig] - Lens config from sourceHolon's perspective
30383
+ * @param {string[]} [options.lensConfig.inbound] - Lenses sourceHolon receives from targetHolon
30384
+ * @param {string[]} [options.lensConfig.outbound] - Lenses sourceHolon sends to targetHolon
30385
+ * @param {string} [options.partnerName] - Display name for the partner
30404
30386
  * @returns {Promise<boolean>}
30405
30387
  */
30406
30388
  async federateHolon(sourceHolon, targetHolon, options = {}) {
30407
30389
  const lensConfig = options.lensConfig || {};
30408
- const lenses = lensConfig.lenses || lensConfig.outbound || lensConfig.federate || [];
30409
- if (options.partnerName) {
30390
+ const inbound = Array.isArray(lensConfig.inbound) ? lensConfig.inbound : [];
30391
+ const outbound = Array.isArray(lensConfig.outbound) ? lensConfig.outbound : [];
30392
+ const ok = await federate(this, sourceHolon, targetHolon, null, null, true, {
30393
+ inbound,
30394
+ outbound
30395
+ });
30396
+ if (ok && options.partnerName) {
30410
30397
  try {
30411
- const fedInfo = await this.getFederation(sourceHolon) || {
30412
- id: sourceHolon,
30413
- name: sourceHolon,
30414
- federation: [],
30415
- notify: [],
30416
- lensConfig: {},
30417
- partnerNames: {},
30418
- timestamp: Date.now()
30419
- };
30420
- if (!fedInfo.partnerNames) fedInfo.partnerNames = {};
30421
- fedInfo.partnerNames[targetHolon] = options.partnerName;
30422
- await this.putGlobal("federation", fedInfo);
30398
+ const fedInfo = await this.getFederation(sourceHolon);
30399
+ if (fedInfo) {
30400
+ if (!fedInfo.partnerNames) fedInfo.partnerNames = {};
30401
+ fedInfo.partnerNames[targetHolon] = options.partnerName;
30402
+ await this.putGlobal("federation", fedInfo);
30403
+ }
30423
30404
  } catch (e) {
30424
30405
  console.warn("Failed to store partner name:", e.message);
30425
30406
  }
30426
30407
  }
30427
- return federate(this, sourceHolon, targetHolon, null, null, true, {
30428
- federate: lenses,
30429
- notify: lenses
30430
- });
30408
+ return ok;
30431
30409
  }
30432
30410
  /**
30433
30411
  * v2-compatible federation removal.