holosphere 1.1.16 → 1.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/compute.js CHANGED
@@ -286,7 +286,7 @@ export async function updateParent(holoInstance, id, report) {
286
286
  // Re-throw or handle error appropriately
287
287
  throw error;
288
288
  }
289
- }
289
+ }
290
290
 
291
291
  // Export all compute operations as default
292
292
  export default {
package/content.js CHANGED
@@ -50,7 +50,6 @@ export async function put(holoInstance, holon, lens, data, password = null, opti
50
50
  if (soulInfo.appname !== holoInstance.appname) {
51
51
  console.warn(`Existing hologram at ${targetHolon}/${targetLens}/${targetKey} has appname (${soulInfo.appname}) in its soul ${existingItemAtPath.soul} which does not match current HoloSphere instance appname (${holoInstance.appname}). Redirecting put to soul's holon/lens within this instance.`);
52
52
  }
53
- console.log(`Redirecting put for data (ID: ${data.id}). Original target ${targetHolon}/${targetLens}/${targetKey} contained hologram (ID: ${existingItemAtPath.id}, Soul: ${existingItemAtPath.soul}). New target is ${soulInfo.holon}/${soulInfo.lens}/${soulInfo.key}.`);
54
53
  targetHolon = soulInfo.holon; // Redirect holon
55
54
  targetLens = soulInfo.lens; // Redirect lens
56
55
  targetKey = soulInfo.key; // Redirect key (important!)
@@ -61,7 +60,6 @@ export async function put(holoInstance, holon, lens, data, password = null, opti
61
60
  // It's crucial that the actual GunDB path uses targetKey.
62
61
  // The 'data' object itself retains its original 'data.id' unless explicitly changed.
63
62
  }
64
-
65
63
  } else {
66
64
  console.warn(`Existing item at ${targetHolon}/${targetLens}/${targetKey} (ID: ${existingItemAtPath.id}) is a hologram, but its soul ('${existingItemAtPath.soul}') is invalid. Proceeding with original target.`);
67
65
  }
@@ -165,8 +163,6 @@ export async function put(holoInstance, holon, lens, data, password = null, opti
165
163
  const storedHologramInstanceSoul = `${holoInstance.appname}/${targetHolon}/${targetLens}/${targetKey}`;
166
164
 
167
165
  targetNodeRef.get('_holograms').get(storedHologramInstanceSoul).put(true);
168
-
169
- console.log(`Data (ID: ${data.id}) being put is a hologram. Added its instance soul ${storedHologramInstanceSoul} to its target ${data.soul}'s _holograms set.`);
170
166
  } else {
171
167
  console.warn(`Data (ID: ${data.id}) being put is a hologram, but could not parse its soul ${data.soul} for tracking.`);
172
168
  }
@@ -191,10 +187,8 @@ export async function put(holoInstance, holon, lens, data, password = null, opti
191
187
  k !== '_' && hologramsSet[k] === true // Only active holograms (deleted ones are null/removed)
192
188
  );
193
189
 
194
- if (hologramSouls.length > 0) {
195
- console.log(`Updating ${hologramSouls.length} active holograms for data ${data.id}`);
196
-
197
- // Update each active hologram with an 'updated' timestamp
190
+ if (hologramSouls.length > 0) {
191
+ // Update each active hologram with an 'updated' timestamp
198
192
  const updatePromises = hologramSouls.map(async (hologramSoul) => {
199
193
  try {
200
194
  const hologramSoulInfo = holoInstance.parseSoulPath(hologramSoul);
@@ -227,9 +221,7 @@ export async function put(holoInstance, holon, lens, data, password = null, opti
227
221
  }
228
222
  );
229
223
 
230
- console.log(`Updated hologram at ${hologramSoul} with timestamp`);
231
-
232
- // Add to the list of updated holograms
224
+ // Add to the list of updated holograms
233
225
  updatedHolograms.push({
234
226
  soul: hologramSoul,
235
227
  holon: hologramSoulInfo.holon,
@@ -387,23 +379,31 @@ export async function get(holoInstance, holon, lens, key, password = null, optio
387
379
  if (resolveHolograms && holoInstance.isHologram(parsed)) {
388
380
  const resolvedValue = await holoInstance.resolveHologram(parsed, {
389
381
  followHolograms: resolveHolograms,
390
- visited: visited
382
+ visited: visited,
383
+ maxDepth: options.maxDepth || 10,
384
+ currentDepth: options.currentDepth || 0
391
385
  });
392
386
 
393
- console.log(`### get/handleData received resolved value:`, resolvedValue);
394
-
395
387
  if (resolvedValue === null) {
396
- // This means resolveHologram determined the target doesn't exist or a sub-resolution failed to null.
397
- console.warn(`Hologram at ${holon}/${lens}/${key} could not be fully resolved (target not found or sub-problem). Resolving null.`);
388
+ // This means resolveHologram determined the target doesn't exist or encountered an error
389
+ console.warn(`Broken hologram detected at ${holon}/${lens}/${key}. Removing it...`);
390
+
391
+ try {
392
+ // Delete the broken hologram
393
+ await holoInstance.delete(holon, lens, key, password);
394
+ console.log(`Successfully removed broken hologram from ${holon}/${lens}/${key}`);
395
+ } catch (cleanupError) {
396
+ console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
397
+ }
398
+
398
399
  resolve(null);
399
- return; // Important to return after resolving
400
+ return;
400
401
  }
401
402
  // If resolveHologram encountered a circular ref, it would throw, not return.
402
403
  // If it returned the hologram itself (if we ever revert to that), this logic would need adjustment.
403
404
  // For now, assume resolvedValue is either the resolved data or we've returned null above.
404
405
 
405
406
  if (resolvedValue !== parsed) {
406
- console.log(`### get/handleData using resolved data:`, resolvedValue);
407
407
  parsed = resolvedValue;
408
408
  }
409
409
  }
@@ -518,21 +518,41 @@ export async function getAll(holoInstance, holon, lens, password = null) {
518
518
 
519
519
  // Check if this is a hologram that needs to be resolved
520
520
  if (holoInstance.isHologram(parsed)) {
521
- const resolved = await holoInstance.resolveHologram(parsed, {
522
- followHolograms: true
523
- });
521
+ try {
522
+ const resolved = await holoInstance.resolveHologram(parsed, {
523
+ followHolograms: true,
524
+ maxDepth: 10,
525
+ currentDepth: 0
526
+ });
527
+
528
+ if (resolved === null) {
529
+ console.warn(`Broken hologram detected in getAll for key ${key}. Removing it...`);
530
+
531
+ try {
532
+ // Delete the broken hologram
533
+ await holoInstance.delete(holon, lens, key, password);
534
+ console.log(`Successfully removed broken hologram from ${holon}/${lens}/${key}`);
535
+ } catch (cleanupError) {
536
+ console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
537
+ }
538
+ return; // Skip adding this item to output
539
+ }
524
540
 
525
- if (resolved !== parsed) {
526
- // Hologram was resolved successfully
527
- if (schema) {
528
- const valid = holoInstance.validator.validate(schema, resolved);
529
- if (valid || !holoInstance.strict) {
541
+ if (resolved && resolved !== parsed) {
542
+ // Hologram was resolved successfully
543
+ if (schema) {
544
+ const valid = holoInstance.validator.validate(schema, resolved);
545
+ if (valid || !holoInstance.strict) {
546
+ output.set(resolved.id, resolved);
547
+ }
548
+ } else {
530
549
  output.set(resolved.id, resolved);
531
550
  }
532
- } else {
533
- output.set(resolved.id, resolved);
551
+ return;
534
552
  }
535
- return;
553
+ } catch (hologramError) {
554
+ console.error(`Error resolving hologram for key ${key}:`, hologramError);
555
+ return; // Skip this item
536
556
  }
537
557
  }
538
558
 
@@ -619,18 +639,57 @@ export async function parse(holoInstance, rawData) {
619
639
  } else if (rawData._) {
620
640
  // Handle potential GunDB metadata remnants (attempt cleanup)
621
641
  console.warn('Parsing raw Gun object with metadata (_) - attempting cleanup:', rawData);
642
+
643
+ // Enhanced cleanup for complex GunDB structures
622
644
  const potentialData = Object.keys(rawData).reduce((acc, k) => {
623
645
  if (k !== '_') {
624
- acc[k] = rawData[k];
646
+ // Handle nested raw GunDB nodes
647
+ if (rawData[k] && typeof rawData[k] === 'object' && rawData[k]._) {
648
+ // Recursively parse nested raw nodes
649
+ const parsedNested = parse(holoInstance, rawData[k]);
650
+ if (parsedNested !== null) {
651
+ acc[k] = parsedNested;
652
+ }
653
+ } else if (rawData[k] !== null) {
654
+ // Only include non-null values
655
+ acc[k] = rawData[k];
656
+ }
625
657
  }
626
658
  return acc;
627
659
  }, {});
660
+
628
661
  if (Object.keys(potentialData).length === 0) {
629
- console.warn('Raw Gun object had only metadata (_), returning null.');
662
+ console.warn('Raw Gun object had only metadata (_) or null values, returning null.');
630
663
  return null;
631
664
  }
665
+
666
+ // Additional validation: check if the cleaned object has meaningful data
667
+ const hasValidData = Object.values(potentialData).some(value =>
668
+ value !== null && value !== undefined &&
669
+ (typeof value !== 'object' || Object.keys(value).length > 0)
670
+ );
671
+
672
+ if (!hasValidData) {
673
+ console.warn('Cleaned Gun object has no valid data, returning null.');
674
+ return null;
675
+ }
676
+
632
677
  return potentialData; // Return cleaned-up object
633
678
  } else {
679
+ // Check for objects that might be arrays of raw GunDB nodes
680
+ if (Array.isArray(rawData)) {
681
+ const cleanedArray = rawData
682
+ .map(item => parse(holoInstance, item))
683
+ .filter(item => item !== null);
684
+
685
+ if (cleanedArray.length === 0) {
686
+ console.warn('Array contained only invalid/raw GunDB nodes, returning null.');
687
+ return null;
688
+ }
689
+
690
+ return cleanedArray;
691
+ }
692
+
634
693
  // Assume it's a regular plain object
635
694
  return rawData;
636
695
  }
@@ -739,7 +798,6 @@ export async function deleteFunc(holoInstance, holon, lens, key, password = null
739
798
  if (ack.err) {
740
799
  console.warn(`[deleteFunc] Error removing hologram ${deletedHologramSoul} from target ${targetSoul}:`, ack.err);
741
800
  }
742
- console.log(`Removed hologram ${deletedHologramSoul} from target ${targetSoul}'s _holograms list`);
743
801
  resolveTrack(); // Resolve regardless of ack error to not block main delete
744
802
  });
745
803
  });
@@ -891,9 +949,8 @@ export async function deleteAll(holoInstance, holon, lens, password = null) {
891
949
  targetNodeRef.get('_holograms').get(deletedHologramSoul).put(null, (ack) => {
892
950
  if (ack.err) {
893
951
  console.warn(`[deleteAll] Error removing hologram ${deletedHologramSoul} from target ${targetSoul}:`, ack.err);
894
- }
895
- console.log(`Removed hologram ${deletedHologramSoul} from target ${targetSoul}'s _holograms list`);
896
- resolveTrack();
952
+ }
953
+ resolveTrack();
897
954
  });
898
955
  });
899
956
  } else {
package/federation.js CHANGED
@@ -890,7 +890,7 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
890
890
 
891
891
  // Check if we should propagate to parent hexagons
892
892
  if (propagateToParents) {
893
- console.log(`[Federation] Starting parent propagation for holon: ${holon}`);
893
+
894
894
  try {
895
895
  // Validate if the holon is a proper H3 hexagon
896
896
  // H3 hexagons should start with '8' and have a valid format
@@ -898,13 +898,12 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
898
898
  let isValidH3 = false;
899
899
 
900
900
  // First check: H3 hexagons should start with '8' and be at least 15 characters long
901
- if (typeof holon === 'string' && holon.startsWith('8') && holon.length >= 15) {
901
+ if (typeof holon === 'string' && /^[8][0-9A-Fa-f]+$/.test(holon) && holon.length >= 15) {
902
902
  try {
903
903
  holonResolution = h3.getResolution(holon);
904
904
  // Additional validation: resolution should be >= 0 and <= 15
905
905
  if (holonResolution >= 0 && holonResolution <= 15) {
906
906
  isValidH3 = true;
907
- console.log(`[Federation] Holon ${holon} is valid H3 hexagon with resolution: ${holonResolution}`);
908
907
  } else {
909
908
  console.log(`[Federation] Holon ${holon} has invalid resolution: ${holonResolution}`);
910
909
  }
@@ -912,11 +911,9 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
912
911
  console.log(`[Federation] Holon ${holon} failed H3 validation: ${error.message}`);
913
912
  }
914
913
  } else {
915
- console.log(`[Federation] Holon ${holon} is not a valid H3 hexagon: does not start with '8' or too short`);
916
914
  }
917
915
 
918
916
  if (!isValidH3) {
919
- console.log(`[Federation] Skipping parent propagation for non-H3 holon: ${holon}`);
920
917
  result.parentPropagation.messages.push(`Holon ${holon} is not a valid H3 hexagon. Skipping parent propagation.`);
921
918
  result.parentPropagation.skipped++;
922
919
  }
@@ -928,13 +925,10 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
928
925
  let currentRes = holonResolution;
929
926
  let levelsProcessed = 0;
930
927
 
931
- console.log(`[Federation] Getting parent hexagons for ${holon} (resolution ${holonResolution}) up to ${maxParentLevels} levels`);
932
-
933
928
  while (currentRes > 0 && levelsProcessed < maxParentLevels) {
934
929
  try {
935
930
  const parent = h3.cellToParent(currentHolon, currentRes - 1);
936
931
  parentHexagons.push(parent);
937
- console.log(`[Federation] Found parent hexagon: ${parent} (resolution ${currentRes - 1})`);
938
932
  currentHolon = parent;
939
933
  currentRes--;
940
934
  levelsProcessed++;
@@ -947,17 +941,14 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
947
941
  }
948
942
 
949
943
  if (parentHexagons.length > 0) {
950
- console.log(`[Federation] Found ${parentHexagons.length} parent hexagons to propagate to: ${parentHexagons.join(', ')}`);
951
944
  result.parentPropagation.messages.push(`Found ${parentHexagons.length} parent hexagons to propagate to: ${parentHexagons.join(', ')}`);
952
945
 
953
946
  // Check if data is already a hologram (reuse from federation section)
954
947
  const isAlreadyHologram = holosphere.isHologram(data);
955
- console.log(`[Federation] Data is already hologram: ${isAlreadyHologram}`);
956
948
 
957
949
  // Propagate to each parent hexagon
958
950
  const parentPropagatePromises = parentHexagons.map(async (parentHexagon) => {
959
951
  try {
960
- console.log(`[Federation] Propagating to parent hexagon: ${parentHexagon}`);
961
952
  let payloadToPut;
962
953
  const parentFederationMeta = {
963
954
  origin: holon, // The original holon from which this data is being propagated
@@ -971,7 +962,6 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
971
962
  if (useHolograms && !isAlreadyHologram) {
972
963
  // Create a new hologram referencing the original data
973
964
  const newHologram = holosphere.createHologram(holon, lens, data);
974
- console.log(`[Federation] Created hologram for parent propagation:`, newHologram);
975
965
  payloadToPut = {
976
966
  ...newHologram, // This will be { id: data.id, soul: 'path/to/original' }
977
967
  _federation: parentFederationMeta
@@ -988,8 +978,6 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
988
978
  };
989
979
  }
990
980
 
991
- console.log(`[Federation] Storing in parent hexagon ${parentHexagon} with payload:`, payloadToPut);
992
-
993
981
  // Store in the parent hexagon with redirection disabled and no further auto-propagation
994
982
  await holosphere.put(parentHexagon, lens, payloadToPut, null, {
995
983
  disableHologramRedirection: true,
@@ -1009,7 +997,6 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
1009
997
 
1010
998
  await Promise.all(parentPropagatePromises);
1011
999
  } else {
1012
- console.log(`[Federation] No parent hexagons found for ${holon} (already at resolution 0 or max levels reached)`);
1013
1000
  result.parentPropagation.messages.push(`No parent hexagons found for ${holon} (already at resolution 0 or max levels reached)`);
1014
1001
  result.parentPropagation.skipped++;
1015
1002
  }
@@ -1019,8 +1006,6 @@ export async function propagate(holosphere, holon, lens, data, options = {}) {
1019
1006
  result.parentPropagation.errors++;
1020
1007
  result.parentPropagation.messages.push(`Error during parent propagation: ${error.message}`);
1021
1008
  }
1022
- } else {
1023
- console.log(`[Federation] Parent propagation disabled for holon: ${holon}`);
1024
1009
  }
1025
1010
 
1026
1011
  // ================================ END PARENT PROPAGATION ================================
@@ -1230,7 +1215,7 @@ export async function resetFederation(holosphere, spaceId, password = null, opti
1230
1215
  error: error.message
1231
1216
  };
1232
1217
  }
1233
- }
1218
+ }
1234
1219
 
1235
1220
  // Export all federation operations as default
1236
1221
  export default {
package/global.js CHANGED
@@ -94,10 +94,8 @@ export async function putGlobal(holoInstance, tableName, data, password = null)
94
94
  // Soul of the hologram that was *actually stored* at tableName/data.id
95
95
  const storedHologramInstanceSoul = `${holoInstance.appname}/${tableName}/${data.id}`;
96
96
 
97
- targetNodeRef.get('_holograms').get(storedHologramInstanceSoul).put(true);
98
-
99
- console.log(`Data (ID: ${data.id}) being put is a hologram. Added its instance soul ${storedHologramInstanceSoul} to its target ${dataToStore.soul}'s _holograms set.`);
100
- } else {
97
+ targetNodeRef.get('_holograms').get(storedHologramInstanceSoul).put(true);
98
+ } else {
101
99
  console.warn(`Data (ID: ${data.id}) being put is a hologram, but could not parse its soul ${dataToStore.soul} for tracking.`);
102
100
  }
103
101
  } catch (trackingError) {
@@ -123,10 +121,8 @@ export async function putGlobal(holoInstance, tableName, data, password = null)
123
121
  // Soul of the hologram that was *actually stored* at tableName (without specific key)
124
122
  const storedHologramInstanceSoul = `${holoInstance.appname}/${tableName}`;
125
123
 
126
- targetNodeRef.get('_holograms').get(storedHologramInstanceSoul).put(true);
127
-
128
- console.log(`Data being put is a hologram. Added its instance soul ${storedHologramInstanceSoul} to its target ${dataToStore.soul}'s _holograms set.`);
129
- } else {
124
+ targetNodeRef.get('_holograms').get(storedHologramInstanceSoul).put(true);
125
+ } else {
130
126
  console.warn(`Data being put is a hologram, but could not parse its soul ${dataToStore.soul} for tracking.`);
131
127
  }
132
128
  } catch (trackingError) {
@@ -228,7 +224,6 @@ export async function getGlobal(holoInstance, tableName, key, password = null) {
228
224
  });
229
225
 
230
226
  if (resolved === null) {
231
- console.log(`Hologram at ${tableName}/${key} points to non-existent data. Deleting hologram.`);
232
227
  try {
233
228
  await holoInstance.deleteGlobal(tableName, key, password); // Use instance's deleteGlobal
234
229
  } catch (deleteError) {
@@ -364,7 +359,6 @@ export async function getAllGlobal(holoInstance, tableName, password = null) {
364
359
  });
365
360
 
366
361
  if (resolved === null) {
367
- console.log(`Hologram at ${tableName}/${key} points to non-existent data. Deleting hologram.`);
368
362
  try {
369
363
  await holoInstance.deleteGlobal(tableName, key, password); // Use instance's deleteGlobal
370
364
  } catch (deleteError) {
@@ -515,7 +509,6 @@ export async function deleteGlobal(holoInstance, tableName, key, password = null
515
509
  if (ack.err) {
516
510
  console.warn(`[deleteGlobal] Error removing hologram ${deletedHologramSoul} from target ${targetSoul}:`, ack.err);
517
511
  }
518
- console.log(`Removed hologram ${deletedHologramSoul} from target ${targetSoul}'s _holograms list`);
519
512
  resolveTrack(); // Resolve regardless of ack error to not block main delete
520
513
  });
521
514
  });
@@ -674,9 +667,8 @@ export async function deleteAllGlobal(holoInstance, tableName, password = null)
674
667
  targetNodeRef.get('_holograms').get(deletedHologramSoul).put(null, (ack) => {
675
668
  if (ack.err) {
676
669
  console.warn(`[deleteAllGlobal] Error removing hologram ${deletedHologramSoul} from target ${targetSoul}:`, ack.err);
677
- }
678
- console.log(`Removed hologram ${deletedHologramSoul} from target ${targetSoul}'s _holograms list`);
679
- resolveTrack();
670
+ }
671
+ resolveTrack();
680
672
  });
681
673
  });
682
674
  } else {
@@ -732,7 +724,7 @@ export async function deleteAllGlobal(holoInstance, tableName, password = null)
732
724
  console.error('Error in deleteAllGlobal:', error);
733
725
  throw error;
734
726
  }
735
- }
727
+ }
736
728
 
737
729
  // Export all global operations as default
738
730
  export default {
package/hologram.js CHANGED
@@ -12,7 +12,6 @@ export function createHologram(holoInstance, holon, lens, data) {
12
12
  // Check if the input data is already a hologram
13
13
  if (isHologram(data)) {
14
14
  // If it is, just return its existing ID and Soul, ignoring the provided holon/lens
15
- console.warn('createHologram called with data that is already a hologram. Reusing existing soul:', data.soul);
16
15
  return {
17
16
  id: data.id,
18
17
  soul: data.soul
@@ -85,6 +84,8 @@ export function isHologram(data) {
85
84
  * @param {object} [options] - Optional parameters
86
85
  * @param {boolean} [options.followHolograms=true] - Whether to follow nested holograms
87
86
  * @param {Set<string>} [options.visited] - Internal use: Tracks visited souls to prevent loops
87
+ * @param {number} [options.maxDepth=10] - Maximum resolution depth to prevent infinite loops
88
+ * @param {number} [options.currentDepth=0] - Current resolution depth
88
89
  * @returns {Promise<object|null>} - The resolved data, null if resolution failed due to target not found, or the original hologram for circular/invalid cases.
89
90
  */
90
91
  export async function resolveHologram(holoInstance, hologram, options = {}) {
@@ -92,29 +93,42 @@ export async function resolveHologram(holoInstance, hologram, options = {}) {
92
93
  return hologram; // Not a hologram, return as is
93
94
  }
94
95
 
95
- const { followHolograms = true, visited = new Set() } = options;
96
+ const {
97
+ followHolograms = true,
98
+ visited = new Set(),
99
+ maxDepth = 10,
100
+ currentDepth = 0
101
+ } = options;
102
+
103
+ // Check depth limit first
104
+ if (currentDepth >= maxDepth) {
105
+ console.warn(`!!! Maximum resolution depth (${maxDepth}) reached for soul: ${hologram.soul}. Stopping resolution.`);
106
+ return null;
107
+ }
96
108
 
97
- // Check for circular hologram FIRST
109
+ // Check for circular hologram
98
110
  if (hologram.soul && visited.has(hologram.soul)) {
99
- console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}. Returning original hologram.`);
100
- throw new Error(`CIRCULAR_REFERENCE:${hologram.soul}`);
101
- } else {
111
+ console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}. Breaking loop.`);
112
+ return null;
113
+ }
114
+
102
115
  try {
103
116
  // Handle direct soul hologram
104
117
  if (hologram.soul) {
105
118
  const soulInfo = parseSoulPath(hologram.soul);
106
119
  if (!soulInfo) {
107
120
  console.warn(`Invalid soul format: ${hologram.soul}`);
108
- return hologram;
121
+ return null;
109
122
  }
110
123
 
111
124
  // Add current soul to visited set for THIS resolution path
112
125
  const nextVisited = new Set(visited);
113
126
  nextVisited.add(hologram.soul);
114
127
 
115
- console.log(`Resolving hologram with soul: ${hologram.soul}`);
128
+ // Only log when actually resolving a hologram for debugging if needed
129
+ // console.log(`Resolving hologram: ${hologram.soul}`);
116
130
 
117
- // Get original data
131
+ // Get original data with increased depth
118
132
  const originalData = await holoInstance.get(
119
133
  soulInfo.holon,
120
134
  soulInfo.lens,
@@ -122,36 +136,41 @@ export async function resolveHologram(holoInstance, hologram, options = {}) {
122
136
  null,
123
137
  {
124
138
  resolveHolograms: followHolograms,
125
- visited: nextVisited
139
+ visited: nextVisited,
140
+ maxDepth: maxDepth,
141
+ currentDepth: currentDepth + 1
126
142
  }
127
143
  );
128
144
 
129
- console.log('### resolveHologram received originalData:', originalData);
130
-
131
- if (originalData) {
132
- console.log(`### Returning RESOLVED data for soul: ${hologram.soul}`);
145
+ if (originalData && !originalData._invalidHologram) {
133
146
  // Structure for the returned object - isHologram (top-level) is removed
134
147
  return {
135
148
  ...originalData,
136
149
  _meta: {
137
150
  ...(originalData._meta || {}), // Preserve original _meta
138
151
  resolvedFromHologram: true, // This is now the primary indicator
139
- hologramSoul: hologram.soul // Clarified meta field
152
+ hologramSoul: hologram.soul, // Clarified meta field
153
+ resolutionDepth: currentDepth
140
154
  }
141
155
  };
142
156
  } else {
143
- console.warn(`!!! Original data NOT FOUND for soul: ${hologram.soul}. Returning null.`);
144
- return null;
157
+ console.warn(`!!! Original data NOT FOUND for soul: ${hologram.soul}. Removing broken hologram.`);
158
+
159
+ // Return null to indicate the hologram should be removed
160
+ return null;
145
161
  }
146
162
  } else {
147
163
  // Should not happen if isHologram() passed
148
164
  console.warn('!!! resolveHologram called with object missing soul:', hologram);
149
- return hologram;
165
+ return null;
150
166
  }
151
167
  } catch (error) {
152
- console.error(`!!! Error resolving hologram: ${error.message}`, error);
153
- return hologram; // Return original hologram on error
168
+ if (error.message?.startsWith('CIRCULAR_REFERENCE')) {
169
+ console.warn(`!!! Circular reference detected during hologram resolution: ${error.message}`);
170
+ return null;
154
171
  }
172
+ console.error(`!!! Error resolving hologram: ${error.message}`, error);
173
+ return null; // Return null on error to prevent loops
155
174
  }
156
175
  }
157
176