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 +1 -1
- package/content.js +92 -35
- package/federation.js +3 -18
- package/global.js +7 -15
- package/hologram.js +39 -20
- package/holosphere-bundle.esm.js +143 -96
- package/holosphere-bundle.js +143 -96
- package/holosphere-bundle.min.js +18 -18
- package/holosphere.js +25 -3
- package/node.js +5 -8
- package/package.json +9 -9
- package/schema.js +1 -1
- package/utils.js +1 -1
package/compute.js
CHANGED
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
|
-
|
|
195
|
-
|
|
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
|
-
|
|
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
|
|
397
|
-
console.warn(`
|
|
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;
|
|
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
|
-
|
|
522
|
-
|
|
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
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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
|
-
|
|
533
|
-
output.set(resolved.id, resolved);
|
|
551
|
+
return;
|
|
534
552
|
}
|
|
535
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
109
|
+
// Check for circular hologram
|
|
98
110
|
if (hologram.soul && visited.has(hologram.soul)) {
|
|
99
|
-
console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}.
|
|
100
|
-
|
|
101
|
-
}
|
|
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
|
-
|
|
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
|
-
|
|
128
|
+
// Only log when actually resolving a hologram for debugging if needed
|
|
129
|
+
// console.log(`Resolving hologram: ${hologram.soul}`);
|
|
116
130
|
|
|
117
|
-
|
|
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
|
-
|
|
139
|
+
visited: nextVisited,
|
|
140
|
+
maxDepth: maxDepth,
|
|
141
|
+
currentDepth: currentDepth + 1
|
|
126
142
|
}
|
|
127
143
|
);
|
|
128
144
|
|
|
129
|
-
|
|
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
|
-
|
|
152
|
+
hologramSoul: hologram.soul, // Clarified meta field
|
|
153
|
+
resolutionDepth: currentDepth
|
|
140
154
|
}
|
|
141
155
|
};
|
|
142
156
|
} else {
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
165
|
+
return null;
|
|
150
166
|
}
|
|
151
167
|
} catch (error) {
|
|
152
|
-
|
|
153
|
-
|
|
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
|
|