holosphere 1.1.8 → 1.1.10
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/federation.js +67 -21
- package/holosphere.js +601 -455
- package/package.json +1 -1
- package/test/auth.test.js +35 -19
- package/test/delete.test.js +1 -0
- package/test/holosphere.test.js +189 -5
- package/test/reference.test.js +211 -0
- package/test/subscription.test.js +329 -0
- package/babel.config.js +0 -5
- package/babel.config.json +0 -12
package/package.json
CHANGED
package/test/auth.test.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import Gun from 'gun';
|
|
2
1
|
import HoloSphere from '../holosphere.js';
|
|
3
|
-
import * as h3 from 'h3-js';
|
|
4
2
|
import { jest } from '@jest/globals';
|
|
5
3
|
|
|
6
4
|
// Increase timeout for all tests
|
|
7
|
-
jest.setTimeout(
|
|
5
|
+
jest.setTimeout(30000);
|
|
8
6
|
|
|
9
7
|
describe('HoloSphere Authentication and Authorization', () => {
|
|
10
8
|
let holoSphere;
|
|
@@ -16,6 +14,14 @@ describe('HoloSphere Authentication and Authorization', () => {
|
|
|
16
14
|
beforeAll(async () => {
|
|
17
15
|
holoSphere = new HoloSphere('test-app', false, null);
|
|
18
16
|
strictHoloSphere = new HoloSphere('test-app-strict', true, null);
|
|
17
|
+
// Wait for initialization
|
|
18
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
// Clean state before each test
|
|
23
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
24
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
19
25
|
});
|
|
20
26
|
|
|
21
27
|
afterEach(async () => {
|
|
@@ -37,12 +43,12 @@ describe('HoloSphere Authentication and Authorization', () => {
|
|
|
37
43
|
await holoSphere.deleteAll(testHolon, testLens);
|
|
38
44
|
await holoSphere.deleteAllGlobal('testTable');
|
|
39
45
|
|
|
40
|
-
// Close
|
|
41
|
-
if (holoSphere
|
|
42
|
-
holoSphere.
|
|
46
|
+
// Close HoloSphere instances
|
|
47
|
+
if (holoSphere) {
|
|
48
|
+
await holoSphere.close();
|
|
43
49
|
}
|
|
44
|
-
if (strictHoloSphere
|
|
45
|
-
strictHoloSphere.
|
|
50
|
+
if (strictHoloSphere) {
|
|
51
|
+
await strictHoloSphere.close();
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
// Wait for connections to close
|
|
@@ -50,16 +56,25 @@ describe('HoloSphere Authentication and Authorization', () => {
|
|
|
50
56
|
});
|
|
51
57
|
|
|
52
58
|
describe('Authentication System', () => {
|
|
53
|
-
it('should authenticate with password and
|
|
59
|
+
it('should authenticate with password and handle auth failures', async () => {
|
|
54
60
|
const testData = { id: 'test1', value: 'private-data' };
|
|
55
61
|
|
|
56
62
|
// Test storing with authentication
|
|
57
63
|
await holoSphere.put(testHolon, testLens, testData, testPassword);
|
|
64
|
+
// Wait for data to be properly stored
|
|
65
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
58
66
|
|
|
59
|
-
// Test retrieving with
|
|
60
|
-
const
|
|
61
|
-
expect(
|
|
62
|
-
|
|
67
|
+
// Test retrieving with wrong password
|
|
68
|
+
const wrongResult = await holoSphere.get(testHolon, testLens, testData.id, 'wrong_password');
|
|
69
|
+
expect(wrongResult).toBeNull();
|
|
70
|
+
|
|
71
|
+
// Test retrieving with no password
|
|
72
|
+
const noPassResult = await holoSphere.get(testHolon, testLens, testData.id);
|
|
73
|
+
expect(noPassResult).toBeNull();
|
|
74
|
+
|
|
75
|
+
// Test retrieving with correct password
|
|
76
|
+
const correctResult = await holoSphere.get(testHolon, testLens, testData.id, testPassword);
|
|
77
|
+
expect(correctResult).toEqual(testData); // Use full object comparison
|
|
63
78
|
});
|
|
64
79
|
|
|
65
80
|
it('should handle authentication errors gracefully', async () => {
|
|
@@ -103,15 +118,16 @@ describe('HoloSphere Authentication and Authorization', () => {
|
|
|
103
118
|
const testData = { id: 'test', value: 123 };
|
|
104
119
|
|
|
105
120
|
// Should work in non-strict mode without schema
|
|
106
|
-
await expect(holoSphere.put(testHolon,
|
|
121
|
+
await expect(holoSphere.put(testHolon, 'nonExistentLens', testData)).resolves.toBeTruthy();
|
|
107
122
|
|
|
108
|
-
// Delete any existing schema
|
|
109
|
-
await strictHoloSphere.putGlobal('schemas', { id:
|
|
123
|
+
// Delete any existing schema for the lens
|
|
124
|
+
await strictHoloSphere.putGlobal('schemas', { id: 'nonExistentLens', schema: null });
|
|
110
125
|
|
|
111
|
-
// Should fail in strict mode without schema
|
|
112
126
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
127
|
+
// This should throw an error in strict mode
|
|
128
|
+
await strictHoloSphere.put(testHolon, 'nonExistentLens', testData);
|
|
129
|
+
// If we get here, the test should fail
|
|
130
|
+
expect('Expected an error').toBe('but none was thrown');
|
|
115
131
|
} catch (error) {
|
|
116
132
|
expect(error.message).toBe('Schema required in strict mode');
|
|
117
133
|
}
|
package/test/delete.test.js
CHANGED
|
@@ -113,6 +113,7 @@ describe('HoloSphere Deletion Tests', () => {
|
|
|
113
113
|
// Verify global data exists
|
|
114
114
|
const storedGlobalData = await holoSphere.getGlobal(testGlobalTable, globalData.id);
|
|
115
115
|
expect(storedGlobalData).toBeDefined();
|
|
116
|
+
console.log(storedGlobalData);
|
|
116
117
|
expect(storedGlobalData.value).toBe(globalData.value);
|
|
117
118
|
|
|
118
119
|
// Delete global data
|
package/test/holosphere.test.js
CHANGED
|
@@ -36,12 +36,12 @@ describe('HoloSphere', () => {
|
|
|
36
36
|
await holoSphere.deleteAll(testHolon, testLens);
|
|
37
37
|
await holoSphere.deleteAllGlobal('testTable');
|
|
38
38
|
|
|
39
|
-
// Close
|
|
40
|
-
if (holoSphere
|
|
41
|
-
holoSphere.
|
|
39
|
+
// Close HoloSphere instances
|
|
40
|
+
if (holoSphere) {
|
|
41
|
+
await holoSphere.close();
|
|
42
42
|
}
|
|
43
|
-
if (strictHoloSphere
|
|
44
|
-
strictHoloSphere.
|
|
43
|
+
if (strictHoloSphere) {
|
|
44
|
+
await strictHoloSphere.close();
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// Wait for connections to close
|
|
@@ -167,4 +167,188 @@ describe('HoloSphere', () => {
|
|
|
167
167
|
expect(deletedResult).toBeNull();
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
|
+
|
|
171
|
+
describe('Schema Functions', () => {
|
|
172
|
+
test('should set and get a schema', async () => {
|
|
173
|
+
const schema = {
|
|
174
|
+
type: 'object',
|
|
175
|
+
properties: {
|
|
176
|
+
id: { type: 'string' },
|
|
177
|
+
value: { type: 'string' }
|
|
178
|
+
},
|
|
179
|
+
required: ['id', 'value']
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
await holoSphere.setSchema('testLens', schema);
|
|
183
|
+
const retrieved = await holoSphere.getSchema('testLens');
|
|
184
|
+
|
|
185
|
+
expect(retrieved).toEqual(schema);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('should cache schemas when fetched', async () => {
|
|
189
|
+
const schema = {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
id: { type: 'string' },
|
|
193
|
+
test: { type: 'string' }
|
|
194
|
+
},
|
|
195
|
+
required: ['id', 'test']
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Clear any existing cache and set up fresh schema
|
|
199
|
+
holoSphere.clearSchemaCache();
|
|
200
|
+
await holoSphere.setSchema('cacheTestLens', schema);
|
|
201
|
+
|
|
202
|
+
// Cache should be populated by setSchema
|
|
203
|
+
expect(holoSphere.schemaCache.has('cacheTestLens')).toBe(true);
|
|
204
|
+
|
|
205
|
+
// Save the getGlobal method to create a spy
|
|
206
|
+
const originalGetGlobal = holoSphere.getGlobal;
|
|
207
|
+
let globalCalled = false;
|
|
208
|
+
|
|
209
|
+
// Replace with a spy
|
|
210
|
+
holoSphere.getGlobal = async (...args) => {
|
|
211
|
+
globalCalled = true;
|
|
212
|
+
return originalGetGlobal.apply(holoSphere, args);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// This call should use the cache and not call getGlobal
|
|
216
|
+
const cachedFetch = await holoSphere.getSchema('cacheTestLens');
|
|
217
|
+
expect(cachedFetch).toEqual(schema);
|
|
218
|
+
|
|
219
|
+
// Verify getGlobal was not called because we used the cache
|
|
220
|
+
expect(globalCalled).toBe(false);
|
|
221
|
+
|
|
222
|
+
// Now force a non-cached fetch
|
|
223
|
+
globalCalled = false;
|
|
224
|
+
const forcedFetch = await holoSphere.getSchema('cacheTestLens', { useCache: false });
|
|
225
|
+
expect(forcedFetch).toEqual(schema);
|
|
226
|
+
|
|
227
|
+
// Verify getGlobal was called this time
|
|
228
|
+
expect(globalCalled).toBe(true);
|
|
229
|
+
|
|
230
|
+
// Restore original method
|
|
231
|
+
holoSphere.getGlobal = originalGetGlobal;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('should respect cache max age', async () => {
|
|
235
|
+
const schema = {
|
|
236
|
+
type: 'object',
|
|
237
|
+
properties: {
|
|
238
|
+
id: { type: 'string' },
|
|
239
|
+
age: { type: 'number' }
|
|
240
|
+
},
|
|
241
|
+
required: ['id', 'age']
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Clear any existing cache
|
|
245
|
+
holoSphere.clearSchemaCache();
|
|
246
|
+
await holoSphere.setSchema('ageTestLens', schema);
|
|
247
|
+
|
|
248
|
+
// First fetch to populate cache
|
|
249
|
+
await holoSphere.getSchema('ageTestLens');
|
|
250
|
+
|
|
251
|
+
// Verify cache has the entry now
|
|
252
|
+
expect(holoSphere.schemaCache.has('ageTestLens')).toBe(true);
|
|
253
|
+
|
|
254
|
+
// Manually set an old timestamp on the cache entry
|
|
255
|
+
const oldTimestamp = Date.now() - 3700000; // Older than the default maxCacheAge
|
|
256
|
+
holoSphere.schemaCache.set('ageTestLens', {
|
|
257
|
+
schema,
|
|
258
|
+
timestamp: oldTimestamp
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Save the getGlobal method to create a spy
|
|
262
|
+
const originalGetGlobal = holoSphere.getGlobal;
|
|
263
|
+
let globalCalled = false;
|
|
264
|
+
|
|
265
|
+
// Replace with a spy
|
|
266
|
+
holoSphere.getGlobal = async (...args) => {
|
|
267
|
+
globalCalled = true;
|
|
268
|
+
return originalGetGlobal.apply(holoSphere, args);
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// Call should bypass the cache due to age
|
|
272
|
+
const secondFetch = await holoSphere.getSchema('ageTestLens');
|
|
273
|
+
expect(secondFetch).toEqual(schema);
|
|
274
|
+
|
|
275
|
+
// getGlobal should have been called again
|
|
276
|
+
expect(globalCalled).toBe(true);
|
|
277
|
+
|
|
278
|
+
// Restore original method
|
|
279
|
+
holoSphere.getGlobal = originalGetGlobal;
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('should clear cache properly', async () => {
|
|
283
|
+
const schema1 = {
|
|
284
|
+
type: 'object',
|
|
285
|
+
properties: { id: { type: 'string' } },
|
|
286
|
+
required: ['id']
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const schema2 = {
|
|
290
|
+
type: 'object',
|
|
291
|
+
properties: { name: { type: 'string' } },
|
|
292
|
+
required: ['name']
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// Set two schemas
|
|
296
|
+
await holoSphere.setSchema('clearTest1', schema1);
|
|
297
|
+
await holoSphere.setSchema('clearTest2', schema2);
|
|
298
|
+
|
|
299
|
+
// Verify they're cached
|
|
300
|
+
expect(holoSphere.schemaCache.has('clearTest1')).toBe(true);
|
|
301
|
+
expect(holoSphere.schemaCache.has('clearTest2')).toBe(true);
|
|
302
|
+
|
|
303
|
+
// Clear one schema
|
|
304
|
+
holoSphere.clearSchemaCache('clearTest1');
|
|
305
|
+
expect(holoSphere.schemaCache.has('clearTest1')).toBe(false);
|
|
306
|
+
expect(holoSphere.schemaCache.has('clearTest2')).toBe(true);
|
|
307
|
+
|
|
308
|
+
// Clear all schemas
|
|
309
|
+
holoSphere.clearSchemaCache();
|
|
310
|
+
expect(holoSphere.schemaCache.has('clearTest1')).toBe(false);
|
|
311
|
+
expect(holoSphere.schemaCache.has('clearTest2')).toBe(false);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test('should provide significant performance improvement with caching', async () => {
|
|
315
|
+
const schema = {
|
|
316
|
+
type: 'object',
|
|
317
|
+
properties: {
|
|
318
|
+
id: { type: 'string' },
|
|
319
|
+
value: { type: 'number' },
|
|
320
|
+
name: { type: 'string' }
|
|
321
|
+
},
|
|
322
|
+
required: ['id', 'value']
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// Set up the schema
|
|
326
|
+
await holoSphere.setSchema('perfTestLens', schema);
|
|
327
|
+
|
|
328
|
+
// Measure time without caching (force bypass)
|
|
329
|
+
const start1 = Date.now();
|
|
330
|
+
for (let i = 0; i < 100; i++) {
|
|
331
|
+
await holoSphere.getSchema('perfTestLens', { useCache: false });
|
|
332
|
+
}
|
|
333
|
+
const end1 = Date.now();
|
|
334
|
+
const timeWithoutCache = end1 - start1;
|
|
335
|
+
|
|
336
|
+
// Measure time with caching
|
|
337
|
+
const start2 = Date.now();
|
|
338
|
+
for (let i = 0; i < 100; i++) {
|
|
339
|
+
await holoSphere.getSchema('perfTestLens');
|
|
340
|
+
}
|
|
341
|
+
const end2 = Date.now();
|
|
342
|
+
const timeWithCache = end2 - start2;
|
|
343
|
+
|
|
344
|
+
console.log(`Performance comparison:
|
|
345
|
+
Without cache: ${timeWithoutCache}ms
|
|
346
|
+
With cache: ${timeWithCache}ms
|
|
347
|
+
Improvement factor: ${timeWithoutCache / timeWithCache}x
|
|
348
|
+
`);
|
|
349
|
+
|
|
350
|
+
// The cached version should be at least 2x faster
|
|
351
|
+
expect(timeWithCache).toBeLessThan(timeWithoutCache / 2);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
170
354
|
});
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import HoloSphere from '../holosphere.js';
|
|
2
|
+
import { jest } from '@jest/globals';
|
|
3
|
+
|
|
4
|
+
// Configure timeout
|
|
5
|
+
jest.setTimeout(30000); // 30 second timeout
|
|
6
|
+
|
|
7
|
+
// Setup
|
|
8
|
+
describe('HoloSphere Reference System', () => {
|
|
9
|
+
let holoSphere;
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
// Create a new HoloSphere instance for each test
|
|
13
|
+
holoSphere = new HoloSphere('testApp');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
// Clean up after each test
|
|
18
|
+
if (holoSphere) {
|
|
19
|
+
await holoSphere.close();
|
|
20
|
+
// Wait for connections to close
|
|
21
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should create and parse a reference correctly', async () => {
|
|
26
|
+
// Test data
|
|
27
|
+
const holon = 'testHolon';
|
|
28
|
+
const lens = 'testLens';
|
|
29
|
+
const data = {
|
|
30
|
+
id: 'test-data-123',
|
|
31
|
+
title: 'Test Data',
|
|
32
|
+
content: 'This is test content'
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Create a reference
|
|
36
|
+
const reference = holoSphere.createReference(holon, lens, data);
|
|
37
|
+
|
|
38
|
+
// Validate reference structure
|
|
39
|
+
expect(reference).toBeTruthy();
|
|
40
|
+
expect(reference.id).toBe(data.id);
|
|
41
|
+
expect(reference.soul).toBe(`testApp/${holon}/${lens}/${data.id}`);
|
|
42
|
+
|
|
43
|
+
// Test soul path parsing
|
|
44
|
+
const soulInfo = holoSphere.parseSoulPath(reference.soul);
|
|
45
|
+
expect(soulInfo).toBeTruthy();
|
|
46
|
+
expect(soulInfo.appname).toBe('testApp');
|
|
47
|
+
expect(soulInfo.holon).toBe(holon);
|
|
48
|
+
expect(soulInfo.lens).toBe(lens);
|
|
49
|
+
expect(soulInfo.key).toBe(data.id);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('should detect different types of references correctly', async () => {
|
|
53
|
+
// Soul reference
|
|
54
|
+
const soulReference = {
|
|
55
|
+
id: 'test-data-123',
|
|
56
|
+
soul: 'testApp/testHolon/testLens/test-data-123'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Legacy federation reference
|
|
60
|
+
const legacyReference = {
|
|
61
|
+
id: 'test-data-456',
|
|
62
|
+
_federation: {
|
|
63
|
+
isReference: true,
|
|
64
|
+
origin: 'originHolon',
|
|
65
|
+
lens: 'originLens'
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Regular data (not a reference)
|
|
70
|
+
const regularData = {
|
|
71
|
+
id: 'test-data-789',
|
|
72
|
+
title: 'Regular Data',
|
|
73
|
+
content: 'This is not a reference'
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Test reference detection
|
|
77
|
+
expect(holoSphere.isReference(soulReference)).toBe(true);
|
|
78
|
+
expect(holoSphere.isReference(legacyReference)).toBe(true);
|
|
79
|
+
expect(holoSphere.isReference(regularData)).toBe(false);
|
|
80
|
+
expect(holoSphere.isReference(null)).toBe(false);
|
|
81
|
+
expect(holoSphere.isReference(undefined)).toBe(false);
|
|
82
|
+
expect(holoSphere.isReference("not an object")).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('should store and retrieve references properly', async () => {
|
|
86
|
+
// Original data
|
|
87
|
+
const originalData = {
|
|
88
|
+
id: 'original-123',
|
|
89
|
+
title: 'Original Data',
|
|
90
|
+
content: 'This is the original content'
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Store original data
|
|
94
|
+
await holoSphere.put('originHolon', 'testLens', originalData);
|
|
95
|
+
|
|
96
|
+
// Create a reference to the original data
|
|
97
|
+
const reference = holoSphere.createReference('originHolon', 'testLens', originalData);
|
|
98
|
+
|
|
99
|
+
// Store the reference in a different holon
|
|
100
|
+
await holoSphere.put('referenceHolon', 'testLens', reference);
|
|
101
|
+
|
|
102
|
+
// Retrieve the reference with resolution enabled (default)
|
|
103
|
+
const resolvedData = await holoSphere.get('referenceHolon', 'testLens', 'original-123');
|
|
104
|
+
|
|
105
|
+
// Verify the original data is present
|
|
106
|
+
expect(resolvedData).toBeTruthy();
|
|
107
|
+
expect(resolvedData.title).toBe(originalData.title);
|
|
108
|
+
expect(resolvedData.content).toBe(originalData.content);
|
|
109
|
+
|
|
110
|
+
// Verify the federation metadata is present
|
|
111
|
+
expect(resolvedData._federation).toBeTruthy();
|
|
112
|
+
expect(resolvedData._federation.isReference).toBe(true);
|
|
113
|
+
expect(resolvedData._federation.resolved).toBe(true);
|
|
114
|
+
expect(resolvedData._federation.soul).toBe(reference.soul);
|
|
115
|
+
expect(resolvedData._federation.timestamp).toBeGreaterThan(0);
|
|
116
|
+
|
|
117
|
+
// Retrieve the reference without resolution
|
|
118
|
+
const unresolvedData = await holoSphere.get('referenceHolon', 'testLens', 'original-123', null, {
|
|
119
|
+
resolveReferences: false
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Verify we got the actual reference
|
|
123
|
+
expect(unresolvedData).toBeTruthy();
|
|
124
|
+
expect(unresolvedData.id).toBe('original-123');
|
|
125
|
+
expect(unresolvedData.soul).toBe(reference.soul);
|
|
126
|
+
expect(unresolvedData.title).toBeUndefined();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should update original data and have references reflect the changes', async () => {
|
|
130
|
+
// Original data
|
|
131
|
+
const originalData = {
|
|
132
|
+
id: 'original-456',
|
|
133
|
+
title: 'Original Data',
|
|
134
|
+
content: 'This content will be updated'
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Store original data
|
|
138
|
+
await holoSphere.put('originHolon', 'testLens', originalData);
|
|
139
|
+
|
|
140
|
+
// Create a reference
|
|
141
|
+
const reference = holoSphere.createReference('originHolon', 'testLens', originalData);
|
|
142
|
+
|
|
143
|
+
// Store the reference in a different holon
|
|
144
|
+
await holoSphere.put('referenceHolon', 'testLens', reference);
|
|
145
|
+
|
|
146
|
+
// Update the original data
|
|
147
|
+
const updatedData = {
|
|
148
|
+
...originalData,
|
|
149
|
+
title: 'Updated Data',
|
|
150
|
+
content: 'This content has been updated'
|
|
151
|
+
};
|
|
152
|
+
await holoSphere.put('originHolon', 'testLens', updatedData);
|
|
153
|
+
|
|
154
|
+
// Retrieve the reference
|
|
155
|
+
const resolvedData = await holoSphere.get('referenceHolon', 'testLens', 'original-456');
|
|
156
|
+
|
|
157
|
+
// Verify the reference resolves to the updated data
|
|
158
|
+
expect(resolvedData).toBeTruthy();
|
|
159
|
+
expect(resolvedData.title).toBe('Updated Data');
|
|
160
|
+
expect(resolvedData.content).toBe('This content has been updated');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('should create and use manual references across holons', async () => {
|
|
164
|
+
// Original data to reference
|
|
165
|
+
const originalData = {
|
|
166
|
+
id: 'federated-123',
|
|
167
|
+
title: 'Federated Data',
|
|
168
|
+
content: 'This content should be referenced'
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Store original data
|
|
172
|
+
await holoSphere.put('sourceHolon', 'testLens', originalData);
|
|
173
|
+
|
|
174
|
+
// Create a reference to the original data
|
|
175
|
+
const reference = holoSphere.createReference('sourceHolon', 'testLens', originalData);
|
|
176
|
+
|
|
177
|
+
// Store reference in the target holon
|
|
178
|
+
await holoSphere.put('targetHolon', 'testLens', reference);
|
|
179
|
+
|
|
180
|
+
// Retrieve the reference with resolution
|
|
181
|
+
const resolvedData = await holoSphere.get('targetHolon', 'testLens', 'federated-123');
|
|
182
|
+
|
|
183
|
+
// Verify the reference was resolved to the original data
|
|
184
|
+
expect(resolvedData).toBeTruthy();
|
|
185
|
+
expect(resolvedData.title).toBe('Federated Data');
|
|
186
|
+
expect(resolvedData.content).toBe('This content should be referenced');
|
|
187
|
+
expect(resolvedData._federation).toBeTruthy();
|
|
188
|
+
expect(resolvedData._federation.isReference).toBe(true);
|
|
189
|
+
expect(resolvedData._federation.resolved).toBe(true);
|
|
190
|
+
expect(resolvedData._federation.soul).toBe(reference.soul);
|
|
191
|
+
|
|
192
|
+
// Update original data
|
|
193
|
+
const updatedData = {
|
|
194
|
+
...originalData,
|
|
195
|
+
title: 'Updated Data',
|
|
196
|
+
content: 'This content has been updated'
|
|
197
|
+
};
|
|
198
|
+
await holoSphere.put('sourceHolon', 'testLens', updatedData);
|
|
199
|
+
|
|
200
|
+
// Add a delay to ensure data is updated
|
|
201
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
202
|
+
|
|
203
|
+
// Retrieve the reference again
|
|
204
|
+
const updatedResolvedData = await holoSphere.get('targetHolon', 'testLens', 'federated-123');
|
|
205
|
+
|
|
206
|
+
// Verify the update was reflected via the reference
|
|
207
|
+
expect(updatedResolvedData).toBeTruthy();
|
|
208
|
+
expect(updatedResolvedData.title).toBe('Updated Data');
|
|
209
|
+
expect(updatedResolvedData.content).toBe('This content has been updated');
|
|
210
|
+
});
|
|
211
|
+
});
|