holosphere 1.1.10 → 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/.cursor/rules/futura.mdc +55 -0
- package/FEDERATION.md +17 -17
- package/compute.js +289 -0
- package/content.js +946 -0
- package/examples/federation.js +98 -90
- package/examples/hologram-updates-example.js +106 -0
- package/examples/{references.js → holograms.js} +49 -51
- package/federation.js +427 -245
- package/global.js +725 -0
- package/hologram.js +156 -0
- package/holosphere.d.ts +109 -7
- package/holosphere.js +172 -1565
- package/node.js +240 -0
- package/package.json +2 -5
- package/schema.js +132 -0
- package/test/auth.test.js +55 -37
- package/test/delete.test.js +15 -12
- package/test/federation.test.js +179 -0
- 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 +316 -0
- package/test/meta-strip.test.js +159 -0
- package/test/parent-propagation.test.js +138 -0
- package/test/subscription.test.js +105 -70
- package/utils.js +290 -0
- package/test/reference.test.js +0 -211
package/test/federation.test.js
CHANGED
|
@@ -88,6 +88,135 @@ describe('Federation Tests', () => {
|
|
|
88
88
|
await expect(holosphere.federate(space, space, null))
|
|
89
89
|
.rejects.toThrow('Cannot federate a space with itself');
|
|
90
90
|
});
|
|
91
|
+
|
|
92
|
+
test('should create a federation with lens-specific settings', async () => {
|
|
93
|
+
const space1 = `${testPrefix}lens_space1`;
|
|
94
|
+
const space2 = `${testPrefix}lens_space2`;
|
|
95
|
+
|
|
96
|
+
// Create federation with specific lens configuration
|
|
97
|
+
const lensConfig = {
|
|
98
|
+
federate: ['quests', 'announcements'],
|
|
99
|
+
notify: ['quests']
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const result = await holosphere.federate(space1, space2, null, null, true, lensConfig);
|
|
103
|
+
expect(result).toBe(true);
|
|
104
|
+
|
|
105
|
+
// Verify federation info contains lens configuration
|
|
106
|
+
const fedInfo = await holosphere.getFederation(space1);
|
|
107
|
+
expect(fedInfo).toBeTruthy();
|
|
108
|
+
expect(fedInfo.lensConfig).toBeTruthy();
|
|
109
|
+
expect(fedInfo.lensConfig[space2]).toBeTruthy();
|
|
110
|
+
expect(fedInfo.lensConfig[space2].federate).toEqual(['quests', 'announcements']);
|
|
111
|
+
expect(fedInfo.lensConfig[space2].notify).toEqual(['quests']);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('should respect lens configuration during propagation', async () => {
|
|
115
|
+
const space1 = `${testPrefix}prop_space1`;
|
|
116
|
+
const space2 = `${testPrefix}prop_space2`;
|
|
117
|
+
|
|
118
|
+
// Create federation with specific lens configuration
|
|
119
|
+
const lensConfig = {
|
|
120
|
+
federate: ['quests', 'announcements'],
|
|
121
|
+
notify: ['quests']
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
await holosphere.federate(space1, space2, null, null, true, lensConfig);
|
|
125
|
+
|
|
126
|
+
// Test propagation for allowed lens
|
|
127
|
+
const questData = { id: 'test-quest', title: 'Test Quest' };
|
|
128
|
+
const questResult = await holosphere.propagate(space1, 'quests', questData);
|
|
129
|
+
expect(questResult.success).toBe(1); // Should propagate
|
|
130
|
+
|
|
131
|
+
// Test propagation for non-allowed lens
|
|
132
|
+
const shoppingData = { id: 'test-shopping', item: 'Test Item' };
|
|
133
|
+
const shoppingResult = await holosphere.propagate(space1, 'shopping', shoppingData);
|
|
134
|
+
expect(shoppingResult.success).toBe(0); // Should not propagate
|
|
135
|
+
expect(shoppingResult.message).toContain("Propagation of lens 'shopping' to target space " + space2 + " skipped: lens not in 'federate' configuration.");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('should handle wildcard lens configuration', async () => {
|
|
139
|
+
const space1 = `${testPrefix}wild_space1`;
|
|
140
|
+
const space2 = `${testPrefix}wild_space2`;
|
|
141
|
+
|
|
142
|
+
// Create federation with wildcard lens configuration
|
|
143
|
+
const lensConfig = {
|
|
144
|
+
federate: ['*'],
|
|
145
|
+
notify: ['quests', 'announcements']
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
await holosphere.federate(space1, space2, null, null, true, lensConfig);
|
|
149
|
+
|
|
150
|
+
// Test propagation for various lenses
|
|
151
|
+
const testData = { id: 'test-item', value: 'test' };
|
|
152
|
+
|
|
153
|
+
// Should propagate for quests (in notify list)
|
|
154
|
+
const questResult = await holosphere.propagate(space1, 'quests', testData);
|
|
155
|
+
expect(questResult.success).toBe(1);
|
|
156
|
+
|
|
157
|
+
// Should propagate for announcements (in notify list)
|
|
158
|
+
const announcementResult = await holosphere.propagate(space1, 'announcements', testData);
|
|
159
|
+
expect(announcementResult.success).toBe(1);
|
|
160
|
+
|
|
161
|
+
// Should now propagate for other lenses because federate is ['*'] and space2 is in space1's notify list.
|
|
162
|
+
const otherResult = await holosphere.propagate(space1, 'shopping', testData);
|
|
163
|
+
expect(otherResult.success).toBe(1);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('should handle bidirectional lens configuration correctly', async () => {
|
|
167
|
+
const space1 = `${testPrefix}bi_space1`;
|
|
168
|
+
const space2 = `${testPrefix}bi_space2`;
|
|
169
|
+
|
|
170
|
+
// Create federation with different lens configs for each direction
|
|
171
|
+
const lensConfig = {
|
|
172
|
+
federate: ['quests', 'announcements'],
|
|
173
|
+
notify: ['quests']
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
await holosphere.federate(space1, space2, null, null, true, lensConfig);
|
|
177
|
+
|
|
178
|
+
// Verify both spaces have correct lens configuration
|
|
179
|
+
const fedInfo1 = await holosphere.getFederation(space1);
|
|
180
|
+
const fedInfo2 = await holosphere.getFederation(space2);
|
|
181
|
+
|
|
182
|
+
expect(fedInfo1.lensConfig[space2].federate).toEqual(['quests', 'announcements']);
|
|
183
|
+
expect(fedInfo1.lensConfig[space2].notify).toEqual(['quests']);
|
|
184
|
+
expect(fedInfo2.lensConfig[space1].federate).toEqual(['quests', 'announcements']);
|
|
185
|
+
expect(fedInfo2.lensConfig[space1].notify).toEqual(['quests']);
|
|
186
|
+
|
|
187
|
+
// Test propagation in both directions
|
|
188
|
+
const testData = { id: 'test-item', value: 'test' };
|
|
189
|
+
|
|
190
|
+
// Space1 to Space2
|
|
191
|
+
const result1 = await holosphere.propagate(space1, 'quests', testData);
|
|
192
|
+
expect(result1.success).toBe(1);
|
|
193
|
+
|
|
194
|
+
// Space2 to Space1
|
|
195
|
+
const result2 = await holosphere.propagate(space2, 'quests', testData);
|
|
196
|
+
expect(result2.success).toBe(1);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('should handle unidirectional lens configuration', async () => {
|
|
200
|
+
const space1 = `${testPrefix}uni_space1`;
|
|
201
|
+
const space2 = `${testPrefix}uni_space2`;
|
|
202
|
+
|
|
203
|
+
// Create federation with unidirectional lens config
|
|
204
|
+
const lensConfig = {
|
|
205
|
+
federate: ['quests', 'announcements'],
|
|
206
|
+
notify: ['quests']
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
await holosphere.federate(space1, space2, null, null, false, lensConfig);
|
|
210
|
+
|
|
211
|
+
// Verify lens configuration is only set for one direction
|
|
212
|
+
const fedInfo1 = await holosphere.getFederation(space1);
|
|
213
|
+
const fedInfo2 = await holosphere.getFederation(space2);
|
|
214
|
+
|
|
215
|
+
expect(fedInfo1.lensConfig[space2].federate).toEqual(['quests', 'announcements']);
|
|
216
|
+
expect(fedInfo1.lensConfig[space2].notify).toEqual(['quests']);
|
|
217
|
+
expect(fedInfo2.lensConfig[space1].federate).toEqual([]);
|
|
218
|
+
expect(fedInfo2.lensConfig[space1].notify).toEqual([]);
|
|
219
|
+
});
|
|
91
220
|
});
|
|
92
221
|
|
|
93
222
|
describe('unfederate', () => {
|
|
@@ -167,4 +296,54 @@ describe('Federation Tests', () => {
|
|
|
167
296
|
expect(result.message).toBeDefined();
|
|
168
297
|
});
|
|
169
298
|
});
|
|
299
|
+
|
|
300
|
+
describe('getFederatedConfig', () => {
|
|
301
|
+
test('should retrieve the correct lens configuration for a specific federation link', async () => {
|
|
302
|
+
const space1 = `${testPrefix}lens_config_space1`;
|
|
303
|
+
const space2 = `${testPrefix}lens_config_space2`;
|
|
304
|
+
const space3 = `${testPrefix}lens_config_space3`; // Another space for testing
|
|
305
|
+
|
|
306
|
+
const specificLensConfig = {
|
|
307
|
+
federate: ['books', 'movies'],
|
|
308
|
+
notify: ['books']
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// Federate space1 with space2 with specific lens config
|
|
312
|
+
await holosphere.federate(space1, space2, null, null, true, specificLensConfig);
|
|
313
|
+
// Federate space1 with space3 with default (empty or wildcard) lens config
|
|
314
|
+
await holosphere.federate(space1, space3, null, null, true, {});
|
|
315
|
+
|
|
316
|
+
// Test 1: Get specific lens config for space1 -> space2
|
|
317
|
+
const retrievedConfig1to2 = await holosphere.getFederatedConfig(space1, space2);
|
|
318
|
+
expect(retrievedConfig1to2).toEqual(specificLensConfig);
|
|
319
|
+
|
|
320
|
+
// Test 2: Get lens config for space1 -> space3 (should be default/empty or null)
|
|
321
|
+
// Depending on implementation, it might return null or { federate: [], notify: [] }
|
|
322
|
+
// For now, let's check if it's not the specific one and is an object (or null)
|
|
323
|
+
const retrievedConfig1to3 = await holosphere.getFederatedConfig(space1, space3);
|
|
324
|
+
expect(retrievedConfig1to3).not.toEqual(specificLensConfig);
|
|
325
|
+
if (retrievedConfig1to3 !== null) {
|
|
326
|
+
expect(typeof retrievedConfig1to3).toBe('object');
|
|
327
|
+
expect(Array.isArray(retrievedConfig1to3.federate)).toBe(true);
|
|
328
|
+
expect(Array.isArray(retrievedConfig1to3.notify)).toBe(true);
|
|
329
|
+
// Check if it defaulted to empty arrays as per current federate logic for empty lensConfig input
|
|
330
|
+
expect(retrievedConfig1to3.federate).toEqual([]);
|
|
331
|
+
expect(retrievedConfig1to3.notify).toEqual([]);
|
|
332
|
+
} else {
|
|
333
|
+
expect(retrievedConfig1to3).toBeNull();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Test 3: Try to get config for a non-federated link
|
|
337
|
+
const space4 = `${testPrefix}lens_config_space4`;
|
|
338
|
+
const retrievedConfig1to4 = await holosphere.getFederatedConfig(space1, space4);
|
|
339
|
+
expect(retrievedConfig1to4).toBeNull();
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test('should return null if no federation info exists for the source space', async () => {
|
|
343
|
+
const nonExistentSpace = `${testPrefix}non_existent_space`;
|
|
344
|
+
const targetSpace = `${testPrefix}any_target_space`;
|
|
345
|
+
const config = await holosphere.getFederatedConfig(nonExistentSpace, targetSpace);
|
|
346
|
+
expect(config).toBeNull();
|
|
347
|
+
});
|
|
348
|
+
});
|
|
170
349
|
});
|
|
@@ -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
|
+
});
|