holosphere 1.1.11 → 1.1.12
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/content.js +175 -26
- package/examples/hologram-updates-example.js +106 -0
- package/federation.js +236 -118
- package/global.js +174 -9
- package/holosphere.d.ts +15 -0
- package/holosphere.js +2 -2
- package/node.js +92 -7
- package/package.json +1 -1
- package/test/hologram-deletion.test.js +197 -0
- package/test/hologram-updates-return.test.js +166 -0
- package/test/hologram-updates.test.js +143 -0
- package/test/hologram.test.js +3 -3
- package/test/meta-strip.test.js +159 -0
- package/test/parent-propagation.test.js +138 -0
package/holosphere.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ interface PropagationOptions {
|
|
|
8
8
|
targetSpaces?: string[];
|
|
9
9
|
/** Password for accessing the source holon (if needed) */
|
|
10
10
|
password?: string | null;
|
|
11
|
+
/** Whether to automatically propagate to parent hexagons (default: true) */
|
|
12
|
+
propagateToParents?: boolean;
|
|
13
|
+
/** Maximum number of parent levels to propagate to (default: 15) */
|
|
14
|
+
maxParentLevels?: number;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
/**
|
|
@@ -113,6 +117,17 @@ interface PropagationResult {
|
|
|
113
117
|
error?: string;
|
|
114
118
|
/** Information message if applicable */
|
|
115
119
|
message?: string;
|
|
120
|
+
/** Parent propagation results */
|
|
121
|
+
parentPropagation?: {
|
|
122
|
+
/** Number of successfully propagated items to parents */
|
|
123
|
+
success: number;
|
|
124
|
+
/** Number of errors encountered during parent propagation */
|
|
125
|
+
errors: number;
|
|
126
|
+
/** Number of parent propagations skipped */
|
|
127
|
+
skipped: number;
|
|
128
|
+
/** Messages from parent propagation */
|
|
129
|
+
messages: string[];
|
|
130
|
+
};
|
|
116
131
|
}
|
|
117
132
|
|
|
118
133
|
/**
|
package/holosphere.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module holosphere
|
|
3
|
-
* @version 1.1.
|
|
3
|
+
* @version 1.1.12
|
|
4
4
|
* @description Holonic Geospatial Communication Infrastructure
|
|
5
5
|
* @author Roberto Valenti
|
|
6
6
|
* @license GPL-3.0-or-later
|
|
@@ -20,7 +20,7 @@ import * as ComputeOps from './compute.js';
|
|
|
20
20
|
import * as Utils from './utils.js';
|
|
21
21
|
|
|
22
22
|
// Define the version constant
|
|
23
|
-
const HOLOSPHERE_VERSION = '1.1.
|
|
23
|
+
const HOLOSPHERE_VERSION = '1.1.12';
|
|
24
24
|
|
|
25
25
|
class HoloSphere {
|
|
26
26
|
/**
|
package/node.js
CHANGED
|
@@ -18,6 +18,10 @@ export async function putNode(holoInstance, holon, lens, data) {
|
|
|
18
18
|
// if (data && data.isHologram !== undefined) {
|
|
19
19
|
// delete data.isHologram;
|
|
20
20
|
// }
|
|
21
|
+
|
|
22
|
+
// Check if the data being stored is a hologram
|
|
23
|
+
const isHologram = data.value && holoInstance.isHologram(data.value);
|
|
24
|
+
|
|
21
25
|
holoInstance.gun.get(holoInstance.appname)
|
|
22
26
|
.get(holon)
|
|
23
27
|
.get(lens)
|
|
@@ -26,6 +30,27 @@ export async function putNode(holoInstance, holon, lens, data) {
|
|
|
26
30
|
if (ack.err) {
|
|
27
31
|
reject(new Error(ack.err));
|
|
28
32
|
} else {
|
|
33
|
+
// --- Start: Hologram Tracking Logic (for data *being put*, if it's a hologram) ---
|
|
34
|
+
if (isHologram) {
|
|
35
|
+
try {
|
|
36
|
+
const storedDataSoulInfo = holoInstance.parseSoulPath(data.value.soul);
|
|
37
|
+
if (storedDataSoulInfo) {
|
|
38
|
+
const targetNodeRef = holoInstance.getNodeRef(data.value.soul); // Target of the data *being put*
|
|
39
|
+
// Soul of the hologram that was *actually stored* at holon/lens/value
|
|
40
|
+
const storedHologramInstanceSoul = `${holoInstance.appname}/${holon}/${lens}/value`;
|
|
41
|
+
|
|
42
|
+
targetNodeRef.get('_holograms').get(storedHologramInstanceSoul).put(true);
|
|
43
|
+
|
|
44
|
+
console.log(`Data (ID: ${data.id}) being put is a hologram. Added its instance soul ${storedHologramInstanceSoul} to its target ${data.value.soul}'s _holograms set.`);
|
|
45
|
+
} else {
|
|
46
|
+
console.warn(`Data (ID: ${data.id}) being put is a hologram, but could not parse its soul ${data.value.soul} for tracking.`);
|
|
47
|
+
}
|
|
48
|
+
} catch (trackingError) {
|
|
49
|
+
console.warn(`Error updating _holograms set for the target of the data being put (data ID: ${data.id}, soul: ${data.value.soul}):`, trackingError);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// --- End: Hologram Tracking Logic ---
|
|
53
|
+
|
|
29
54
|
resolve(true);
|
|
30
55
|
}
|
|
31
56
|
});
|
|
@@ -139,17 +164,77 @@ export async function deleteNode(holoInstance, holon, lens, key) {
|
|
|
139
164
|
if (!holon || !lens || !key) {
|
|
140
165
|
throw new Error('deleteNode: Missing required parameters');
|
|
141
166
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const dataPath = holoInstance.gun.get(holoInstance.appname).get(holon).get(lens).get(key);
|
|
170
|
+
|
|
171
|
+
// --- Start: Hologram Tracking Removal ---
|
|
172
|
+
let trackingRemovalPromise = Promise.resolve(); // Default to resolved promise
|
|
173
|
+
|
|
174
|
+
// 1. Get the data first to check if it's a hologram
|
|
175
|
+
const rawDataToDelete = await new Promise((resolve) => dataPath.once(resolve));
|
|
176
|
+
let dataToDelete = null;
|
|
177
|
+
try {
|
|
178
|
+
if (typeof rawDataToDelete === 'string') {
|
|
179
|
+
dataToDelete = JSON.parse(rawDataToDelete);
|
|
180
|
+
} else {
|
|
181
|
+
// Handle cases where it might already be an object (though likely string)
|
|
182
|
+
dataToDelete = rawDataToDelete;
|
|
183
|
+
}
|
|
184
|
+
} catch(e) {
|
|
185
|
+
console.warn("[deleteNode] Could not JSON parse data for deletion check:", rawDataToDelete, e);
|
|
186
|
+
dataToDelete = null; // Ensure it's null if parsing fails
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 2. If it is a hologram, try to remove its reference from the target
|
|
190
|
+
const isDataHologram = dataToDelete && holoInstance.isHologram(dataToDelete);
|
|
191
|
+
|
|
192
|
+
if (isDataHologram) {
|
|
193
|
+
try {
|
|
194
|
+
const targetSoul = dataToDelete.soul;
|
|
195
|
+
const targetSoulInfo = holoInstance.parseSoulPath(targetSoul);
|
|
196
|
+
|
|
197
|
+
if (targetSoulInfo) {
|
|
198
|
+
const targetNodeRef = holoInstance.getNodeRef(targetSoul);
|
|
199
|
+
// putNode stores at the 'value' key, not at the data.id key
|
|
200
|
+
const deletedHologramSoul = `${holoInstance.appname}/${holon}/${lens}/value`;
|
|
201
|
+
|
|
202
|
+
// Create a promise that resolves when the hologram is removed from the list
|
|
203
|
+
trackingRemovalPromise = new Promise((resolveTrack) => { // No reject needed, just warn on error
|
|
204
|
+
targetNodeRef.get('_holograms').get(deletedHologramSoul).put(null, (ack) => { // Remove the hologram entry completely
|
|
205
|
+
if (ack.err) {
|
|
206
|
+
console.warn(`[deleteNode] Error removing hologram ${deletedHologramSoul} from target ${targetSoul}:`, ack.err);
|
|
207
|
+
}
|
|
208
|
+
console.log(`Removed hologram ${deletedHologramSoul} from target ${targetSoul}'s _holograms list`);
|
|
209
|
+
resolveTrack(); // Resolve regardless of ack error to not block main delete
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
} else {
|
|
213
|
+
console.warn(`Could not parse target soul ${targetSoul} for hologram tracking removal during deleteNode.`);
|
|
214
|
+
}
|
|
215
|
+
} catch (trackingError) {
|
|
216
|
+
console.warn(`Error initiating hologram reference removal from target ${dataToDelete.soul} during deleteNode:`, trackingError);
|
|
217
|
+
// Ensure trackingRemovalPromise remains resolved if setup fails
|
|
218
|
+
trackingRemovalPromise = Promise.resolve();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// --- End: Hologram Tracking Removal ---
|
|
222
|
+
|
|
223
|
+
// 3. Wait for the tracking removal attempt to be acknowledged
|
|
224
|
+
await trackingRemovalPromise;
|
|
225
|
+
|
|
226
|
+
// 4. Proceed with the actual deletion of the hologram node itself
|
|
227
|
+
return new Promise((resolve, reject) => {
|
|
228
|
+
dataPath.put(null, ack => {
|
|
148
229
|
if (ack.err) {
|
|
149
230
|
reject(new Error(ack.err));
|
|
150
231
|
} else {
|
|
151
232
|
resolve(true);
|
|
152
233
|
}
|
|
153
234
|
});
|
|
154
|
-
|
|
235
|
+
});
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.error('Error in deleteNode:', error);
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
155
240
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for hologram deletion functionality
|
|
3
|
+
* Verifies that when deleting holograms, only the hologram is deleted and the target's _holograms list is updated
|
|
4
|
+
* The original data should remain intact
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import HoloSphere from '../holosphere.js';
|
|
8
|
+
|
|
9
|
+
const appName = 'test-hologram-deletion-app';
|
|
10
|
+
const testHolon = 'hologramDeletionTestHolon';
|
|
11
|
+
const testLens = 'testLens';
|
|
12
|
+
const otherLens = 'otherLens';
|
|
13
|
+
|
|
14
|
+
const waitForGun = (delay = 250) => new Promise(resolve => setTimeout(resolve, delay));
|
|
15
|
+
|
|
16
|
+
describe('Hologram Deletion Tests', () => {
|
|
17
|
+
let holoSphere;
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
holoSphere = new HoloSphere(appName, false);
|
|
21
|
+
await waitForGun();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
if (holoSphere) {
|
|
26
|
+
await holoSphere.close();
|
|
27
|
+
}
|
|
28
|
+
await waitForGun();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('delete() should only delete hologram and update target _holograms list', async () => {
|
|
32
|
+
// 1. Store original data
|
|
33
|
+
const originalData = { id: 'original-data-1', value: 'Original content' };
|
|
34
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
35
|
+
await waitForGun();
|
|
36
|
+
const originalSoul = `${appName}/${testHolon}/${testLens}/original-data-1`;
|
|
37
|
+
|
|
38
|
+
// 2. Store a hologram pointing to the original data
|
|
39
|
+
const hologramData = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
40
|
+
const hologramStorage = { id: 'hologram-to-delete', soul: hologramData.soul };
|
|
41
|
+
await holoSphere.put(testHolon, otherLens, hologramStorage);
|
|
42
|
+
await waitForGun(500);
|
|
43
|
+
const hologramSoul = `${appName}/${testHolon}/${otherLens}/hologram-to-delete`;
|
|
44
|
+
|
|
45
|
+
// 3. Verify hologram was added to tracking initially
|
|
46
|
+
const targetNodeRef = holoSphere.getNodeRef(originalSoul);
|
|
47
|
+
let hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
48
|
+
expect(hologramsSet).toBeDefined();
|
|
49
|
+
expect(hologramsSet[hologramSoul]).toBeDefined();
|
|
50
|
+
|
|
51
|
+
// 4. Delete the hologram
|
|
52
|
+
await holoSphere.delete(testHolon, otherLens, 'hologram-to-delete');
|
|
53
|
+
await waitForGun(1000);
|
|
54
|
+
|
|
55
|
+
// 5. Verify the hologram is deleted
|
|
56
|
+
const deletedHologram = await holoSphere.get(testHolon, otherLens, 'hologram-to-delete');
|
|
57
|
+
expect(deletedHologram).toBeNull();
|
|
58
|
+
|
|
59
|
+
// 6. Verify the original data still exists
|
|
60
|
+
const originalStillExists = await holoSphere.get(testHolon, testLens, 'original-data-1');
|
|
61
|
+
expect(originalStillExists).toBeDefined();
|
|
62
|
+
expect(originalStillExists.value).toBe('Original content');
|
|
63
|
+
|
|
64
|
+
// 7. Verify the hologram was removed from target's _holograms list
|
|
65
|
+
hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
66
|
+
expect(hologramsSet[hologramSoul]).toBeNull();
|
|
67
|
+
}, 15000);
|
|
68
|
+
|
|
69
|
+
test('deleteAll() should handle holograms properly', async () => {
|
|
70
|
+
// 1. Store original data
|
|
71
|
+
const originalData = { id: 'original-data-2', value: 'Original content' };
|
|
72
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
73
|
+
await waitForGun();
|
|
74
|
+
const originalSoul = `${appName}/${testHolon}/${testLens}/original-data-2`;
|
|
75
|
+
|
|
76
|
+
// 2. Store just one hologram in otherLens (simplified test)
|
|
77
|
+
const hologramData = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
78
|
+
const hologramStorage = { id: 'hologram-in-deleteall', soul: hologramData.soul };
|
|
79
|
+
await holoSphere.put(testHolon, otherLens, hologramStorage);
|
|
80
|
+
await waitForGun(500);
|
|
81
|
+
const hologramSoul = `${appName}/${testHolon}/${otherLens}/hologram-in-deleteall`;
|
|
82
|
+
|
|
83
|
+
// 3. Verify hologram was added to tracking initially
|
|
84
|
+
const targetNodeRef = holoSphere.getNodeRef(originalSoul);
|
|
85
|
+
let hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
86
|
+
expect(hologramsSet).toBeDefined();
|
|
87
|
+
expect(hologramsSet[hologramSoul]).toBeDefined();
|
|
88
|
+
|
|
89
|
+
// 4. Delete all items from otherLens
|
|
90
|
+
await holoSphere.deleteAll(testHolon, otherLens);
|
|
91
|
+
await waitForGun(1000);
|
|
92
|
+
|
|
93
|
+
// 5. Verify all items in otherLens are deleted
|
|
94
|
+
const allItems = await holoSphere.getAll(testHolon, otherLens);
|
|
95
|
+
expect(allItems).toHaveLength(0);
|
|
96
|
+
|
|
97
|
+
// 6. Verify the original data still exists
|
|
98
|
+
const originalStillExists = await holoSphere.get(testHolon, testLens, 'original-data-2');
|
|
99
|
+
expect(originalStillExists).toBeDefined();
|
|
100
|
+
expect(originalStillExists.value).toBe('Original content');
|
|
101
|
+
|
|
102
|
+
// 7. Verify the hologram was removed from target's _holograms list
|
|
103
|
+
hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
104
|
+
expect(hologramsSet[hologramSoul]).toBeNull();
|
|
105
|
+
}, 15000);
|
|
106
|
+
|
|
107
|
+
test('deleteGlobal() should handle holograms properly', async () => {
|
|
108
|
+
// 1. Store original data
|
|
109
|
+
const originalData = { id: 'original-data-3', value: 'Original content' };
|
|
110
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
111
|
+
await waitForGun();
|
|
112
|
+
const originalSoul = `${appName}/${testHolon}/${testLens}/original-data-3`;
|
|
113
|
+
|
|
114
|
+
// 2. Store a hologram in global table
|
|
115
|
+
const hologramData = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
116
|
+
const hologramStorage = { id: 'hologram-in-global', soul: hologramData.soul };
|
|
117
|
+
await holoSphere.putGlobal('testTable', hologramStorage);
|
|
118
|
+
await waitForGun(500);
|
|
119
|
+
const hologramSoul = `${appName}/testTable/hologram-in-global`;
|
|
120
|
+
|
|
121
|
+
// 3. Verify hologram was added to tracking initially
|
|
122
|
+
const targetNodeRef = holoSphere.getNodeRef(originalSoul);
|
|
123
|
+
let hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
124
|
+
expect(hologramsSet).toBeDefined();
|
|
125
|
+
expect(hologramsSet[hologramSoul]).toBeDefined();
|
|
126
|
+
|
|
127
|
+
// 4. Delete the hologram from global table
|
|
128
|
+
await holoSphere.deleteGlobal('testTable', 'hologram-in-global');
|
|
129
|
+
await waitForGun(1000);
|
|
130
|
+
|
|
131
|
+
// 5. Verify the hologram is deleted
|
|
132
|
+
const deletedHologram = await holoSphere.getGlobal('testTable', 'hologram-in-global');
|
|
133
|
+
expect(deletedHologram).toBeNull();
|
|
134
|
+
|
|
135
|
+
// 6. Verify the original data still exists
|
|
136
|
+
const originalStillExists = await holoSphere.get(testHolon, testLens, 'original-data-3');
|
|
137
|
+
expect(originalStillExists).toBeDefined();
|
|
138
|
+
expect(originalStillExists.value).toBe('Original content');
|
|
139
|
+
|
|
140
|
+
// 7. Verify the hologram was removed from target's _holograms list
|
|
141
|
+
hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
142
|
+
expect(hologramsSet[hologramSoul]).toBeNull();
|
|
143
|
+
}, 15000);
|
|
144
|
+
|
|
145
|
+
test('deleteAllGlobal() should handle holograms properly', async () => {
|
|
146
|
+
// 1. Store original data
|
|
147
|
+
const originalData = { id: 'original-data-4', value: 'Original content' };
|
|
148
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
149
|
+
await waitForGun();
|
|
150
|
+
const originalSoul = `${appName}/${testHolon}/${testLens}/original-data-4`;
|
|
151
|
+
|
|
152
|
+
// 2. Store just one hologram in global table (simplified test)
|
|
153
|
+
const hologramData = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
154
|
+
const hologramStorage = { id: 'hologram-in-deleteallglobal', soul: hologramData.soul };
|
|
155
|
+
await holoSphere.putGlobal('testTable2', hologramStorage);
|
|
156
|
+
await waitForGun(500);
|
|
157
|
+
const hologramSoul = `${appName}/testTable2/hologram-in-deleteallglobal`;
|
|
158
|
+
|
|
159
|
+
// 3. Verify hologram was added to tracking initially
|
|
160
|
+
const targetNodeRef = holoSphere.getNodeRef(originalSoul);
|
|
161
|
+
let hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
162
|
+
expect(hologramsSet).toBeDefined();
|
|
163
|
+
expect(hologramsSet[hologramSoul]).toBeDefined();
|
|
164
|
+
|
|
165
|
+
// 4. Delete all items from global table
|
|
166
|
+
await holoSphere.deleteAllGlobal('testTable2');
|
|
167
|
+
await waitForGun(1000);
|
|
168
|
+
|
|
169
|
+
// 5. Verify all items in global table are deleted
|
|
170
|
+
const allItems = await holoSphere.getAllGlobal('testTable2');
|
|
171
|
+
expect(allItems).toHaveLength(0);
|
|
172
|
+
|
|
173
|
+
// 6. Verify the original data still exists
|
|
174
|
+
const originalStillExists = await holoSphere.get(testHolon, testLens, 'original-data-4');
|
|
175
|
+
expect(originalStillExists).toBeDefined();
|
|
176
|
+
expect(originalStillExists.value).toBe('Original content');
|
|
177
|
+
|
|
178
|
+
// 7. Verify the hologram was removed from target's _holograms list
|
|
179
|
+
hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
|
|
180
|
+
expect(hologramsSet[hologramSoul]).toBeNull();
|
|
181
|
+
}, 15000);
|
|
182
|
+
|
|
183
|
+
test('deleting non-hologram data should work normally', async () => {
|
|
184
|
+
// 1. Store regular data
|
|
185
|
+
const regularData = { id: 'regular-data-to-delete', value: 'Regular content' };
|
|
186
|
+
await holoSphere.put(testHolon, testLens, regularData);
|
|
187
|
+
await waitForGun();
|
|
188
|
+
|
|
189
|
+
// 2. Delete the regular data
|
|
190
|
+
await holoSphere.delete(testHolon, testLens, 'regular-data-to-delete');
|
|
191
|
+
await waitForGun();
|
|
192
|
+
|
|
193
|
+
// 3. Verify the data is deleted
|
|
194
|
+
const deletedData = await holoSphere.get(testHolon, testLens, 'regular-data-to-delete');
|
|
195
|
+
expect(deletedData).toBeNull();
|
|
196
|
+
}, 10000);
|
|
197
|
+
});
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// hologram-updates-return.test.js
|
|
2
|
+
|
|
3
|
+
import HoloSphere from '../holosphere.js';
|
|
4
|
+
|
|
5
|
+
describe('Hologram Updates Return Value Tests', () => {
|
|
6
|
+
let holoSphere;
|
|
7
|
+
const testHolon = 'updateReturnTestHolon';
|
|
8
|
+
const testLens = 'testLens';
|
|
9
|
+
const otherLens = 'otherLens';
|
|
10
|
+
const appName = 'test-hologram-return-app';
|
|
11
|
+
|
|
12
|
+
const waitForGun = (ms = 300) => new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
holoSphere = new HoloSphere(appName, false);
|
|
16
|
+
// Clean up before each test
|
|
17
|
+
try {
|
|
18
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
19
|
+
await holoSphere.deleteAll(testHolon, otherLens);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
// Ignore cleanup errors
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
await waitForGun(100);
|
|
25
|
+
}, 30000);
|
|
26
|
+
|
|
27
|
+
afterEach(async () => {
|
|
28
|
+
if (holoSphere) {
|
|
29
|
+
await holoSphere.close();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('put should return empty array when no holograms exist', async () => {
|
|
34
|
+
const originalData = { id: 'no-holograms-test', value: 'Original Value' };
|
|
35
|
+
|
|
36
|
+
// Put original data
|
|
37
|
+
const result = await holoSphere.put(testHolon, testLens, originalData);
|
|
38
|
+
|
|
39
|
+
expect(result).toBeDefined();
|
|
40
|
+
expect(result.success).toBe(true);
|
|
41
|
+
expect(result.updatedHolograms).toBeDefined();
|
|
42
|
+
expect(Array.isArray(result.updatedHolograms)).toBe(true);
|
|
43
|
+
expect(result.updatedHolograms).toHaveLength(0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('put should return list of updated holograms when they exist', async () => {
|
|
47
|
+
const originalData = { id: 'with-holograms-test', value: 'Original Value' };
|
|
48
|
+
|
|
49
|
+
// Step 1: Put original data
|
|
50
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
51
|
+
await waitForGun();
|
|
52
|
+
|
|
53
|
+
// Step 2: Create holograms pointing to the original data
|
|
54
|
+
const hologram1 = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
55
|
+
const hologram2 = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
56
|
+
|
|
57
|
+
await holoSphere.put(testHolon, otherLens, { id: 'hologram-1', soul: hologram1.soul });
|
|
58
|
+
await holoSphere.put(testHolon, otherLens, { id: 'hologram-2', soul: hologram2.soul });
|
|
59
|
+
await waitForGun(500);
|
|
60
|
+
|
|
61
|
+
// Step 3: Update the original data and check the return value
|
|
62
|
+
const updatedData = { ...originalData, value: 'Updated Value', count: 42 };
|
|
63
|
+
const result = await holoSphere.put(testHolon, testLens, updatedData);
|
|
64
|
+
|
|
65
|
+
expect(result).toBeDefined();
|
|
66
|
+
expect(result.success).toBe(true);
|
|
67
|
+
expect(result.updatedHolograms).toBeDefined();
|
|
68
|
+
expect(Array.isArray(result.updatedHolograms)).toBe(true);
|
|
69
|
+
expect(result.updatedHolograms.length).toBeGreaterThan(0);
|
|
70
|
+
|
|
71
|
+
// Check that the returned hologram info is complete
|
|
72
|
+
result.updatedHolograms.forEach(hologram => {
|
|
73
|
+
expect(hologram.soul).toBeDefined();
|
|
74
|
+
expect(hologram.holon).toBe(testHolon);
|
|
75
|
+
expect(hologram.lens).toBeDefined(); // Could be testLens or otherLens
|
|
76
|
+
expect(hologram.key).toBeDefined();
|
|
77
|
+
expect(hologram.id).toBeDefined();
|
|
78
|
+
expect(hologram.timestamp).toBeDefined();
|
|
79
|
+
expect(typeof hologram.timestamp).toBe('number');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Verify that the souls match what we expect
|
|
83
|
+
const expectedSouls = [
|
|
84
|
+
`${appName}/${testHolon}/${otherLens}/hologram-1`,
|
|
85
|
+
`${appName}/${testHolon}/${otherLens}/hologram-2`
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
const returnedSouls = result.updatedHolograms.map(h => h.soul);
|
|
89
|
+
expectedSouls.forEach(expectedSoul => {
|
|
90
|
+
expect(returnedSouls).toContain(expectedSoul);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('put should return updated holograms with correct structure', async () => {
|
|
95
|
+
const originalData = { id: 'structure-test', value: 'Test Value' };
|
|
96
|
+
|
|
97
|
+
// Put original data
|
|
98
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
99
|
+
await waitForGun();
|
|
100
|
+
|
|
101
|
+
// Create one hologram
|
|
102
|
+
const hologram = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
103
|
+
await holoSphere.put(testHolon, otherLens, { id: 'structure-hologram', soul: hologram.soul });
|
|
104
|
+
await waitForGun(500);
|
|
105
|
+
|
|
106
|
+
// Update original data
|
|
107
|
+
const updatedData = { ...originalData, value: 'Updated Test Value' };
|
|
108
|
+
const result = await holoSphere.put(testHolon, testLens, updatedData);
|
|
109
|
+
|
|
110
|
+
expect(result.updatedHolograms).toHaveLength(1);
|
|
111
|
+
|
|
112
|
+
const updatedHologram = result.updatedHolograms[0];
|
|
113
|
+
expect(updatedHologram).toEqual({
|
|
114
|
+
soul: `${appName}/${testHolon}/${otherLens}/structure-hologram`,
|
|
115
|
+
holon: testHolon,
|
|
116
|
+
lens: otherLens,
|
|
117
|
+
key: 'structure-hologram',
|
|
118
|
+
id: 'structure-hologram',
|
|
119
|
+
timestamp: expect.any(Number)
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Verify timestamp is recent (within last few seconds)
|
|
123
|
+
const now = Date.now();
|
|
124
|
+
expect(updatedHologram.timestamp).toBeGreaterThan(now - 5000);
|
|
125
|
+
expect(updatedHologram.timestamp).toBeLessThanOrEqual(now);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('put with isHologramUpdate option should not return updated holograms', async () => {
|
|
129
|
+
const originalData = { id: 'no-recursive-test', value: 'Original Value' };
|
|
130
|
+
|
|
131
|
+
// Put original data
|
|
132
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
133
|
+
await waitForGun();
|
|
134
|
+
|
|
135
|
+
// Create hologram
|
|
136
|
+
const hologram = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
137
|
+
await holoSphere.put(testHolon, otherLens, { id: 'recursive-test', soul: hologram.soul });
|
|
138
|
+
await waitForGun(500);
|
|
139
|
+
|
|
140
|
+
// Update with isHologramUpdate flag (should not trigger hologram updates)
|
|
141
|
+
const updatedData = { ...originalData, value: 'Updated Value' };
|
|
142
|
+
const result = await holoSphere.put(testHolon, testLens, updatedData, null, { isHologramUpdate: true });
|
|
143
|
+
|
|
144
|
+
expect(result).toBeDefined();
|
|
145
|
+
expect(result.success).toBe(true);
|
|
146
|
+
expect(result.updatedHolograms).toBeDefined();
|
|
147
|
+
expect(result.updatedHolograms).toHaveLength(0);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('put hologram should not return updated holograms', async () => {
|
|
151
|
+
const originalData = { id: 'hologram-put-test', value: 'Original Value' };
|
|
152
|
+
|
|
153
|
+
// Put original data
|
|
154
|
+
await holoSphere.put(testHolon, testLens, originalData);
|
|
155
|
+
await waitForGun();
|
|
156
|
+
|
|
157
|
+
// Put a hologram (not original data)
|
|
158
|
+
const hologram = holoSphere.createHologram(testHolon, testLens, originalData);
|
|
159
|
+
const result = await holoSphere.put(testHolon, otherLens, { id: 'test-hologram', soul: hologram.soul });
|
|
160
|
+
|
|
161
|
+
expect(result).toBeDefined();
|
|
162
|
+
expect(result.success).toBe(true);
|
|
163
|
+
expect(result.updatedHolograms).toBeDefined();
|
|
164
|
+
expect(result.updatedHolograms).toHaveLength(0);
|
|
165
|
+
});
|
|
166
|
+
});
|