holosphere 1.1.12 → 1.1.13
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 +25 -8
- package/holosphere-bundle.esm.js +33184 -0
- package/holosphere-bundle.js +33206 -0
- package/holosphere-bundle.min.js +38 -0
- package/package.json +78 -3
- package/.cursor/rules/futura.mdc +0 -55
- package/examples/federation.js +0 -162
- package/examples/hologram-updates-example.js +0 -106
- package/examples/holograms.js +0 -175
- package/test/auth.test.js +0 -275
- package/test/delete.test.js +0 -229
- package/test/federation.test.js +0 -349
- package/test/hologram-deletion.test.js +0 -197
- package/test/hologram-updates-return.test.js +0 -166
- package/test/hologram-updates.test.js +0 -143
- package/test/hologram.test.js +0 -316
- package/test/holosphere.test.js +0 -354
- package/test/meta-strip.test.js +0 -159
- package/test/parent-propagation.test.js +0 -138
- package/test/subscription.test.js +0 -364
package/test/holosphere.test.js
DELETED
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
import HoloSphere from '../holosphere.js';
|
|
2
|
-
import * as h3 from 'h3-js';
|
|
3
|
-
import { jest } from '@jest/globals';
|
|
4
|
-
|
|
5
|
-
// Configure Jest
|
|
6
|
-
jest.setTimeout(30000); // 30 second timeout
|
|
7
|
-
|
|
8
|
-
describe('HoloSphere', () => {
|
|
9
|
-
const testAppName = 'test-app3';
|
|
10
|
-
const testHolon = 'testHolon3';
|
|
11
|
-
const testLens = 'testLens3';
|
|
12
|
-
const testPassword = 'testPassword1234';
|
|
13
|
-
let holoSphere;
|
|
14
|
-
let strictHoloSphere;
|
|
15
|
-
beforeAll(async () => {
|
|
16
|
-
holoSphere = new HoloSphere('test-app', false, null);
|
|
17
|
-
strictHoloSphere = new HoloSphere('test-app-strict', true, null);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
afterEach(async () => {
|
|
21
|
-
// Clean up test data
|
|
22
|
-
try {
|
|
23
|
-
if (holoSphere) {
|
|
24
|
-
await holoSphere.deleteAll(testHolon, testLens);
|
|
25
|
-
}
|
|
26
|
-
if (strictHoloSphere) {
|
|
27
|
-
await strictHoloSphere.deleteAll(testHolon, testLens);
|
|
28
|
-
}
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.error('Error in afterEach cleanup:', error);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
afterAll(async () => {
|
|
35
|
-
// Clean up all test data
|
|
36
|
-
await holoSphere.deleteAll(testHolon, testLens);
|
|
37
|
-
await holoSphere.deleteAllGlobal('testTable');
|
|
38
|
-
|
|
39
|
-
// Close HoloSphere instances
|
|
40
|
-
if (holoSphere) {
|
|
41
|
-
await holoSphere.close();
|
|
42
|
-
}
|
|
43
|
-
if (strictHoloSphere) {
|
|
44
|
-
await strictHoloSphere.close();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Wait for connections to close
|
|
48
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
describe('Constructor', () => {
|
|
53
|
-
test('should have initialized with correct properties', () => {
|
|
54
|
-
expect(holoSphere).toBeInstanceOf(HoloSphere);
|
|
55
|
-
expect(holoSphere.gun).toBeDefined();
|
|
56
|
-
expect(holoSphere.validator).toBeDefined();
|
|
57
|
-
expect(holoSphere.openai).toBeUndefined();
|
|
58
|
-
expect(holoSphere.subscriptions).toBeDefined();
|
|
59
|
-
expect(holoSphere.subscriptions).toEqual({});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test('should initialize with OpenAI', () => {
|
|
63
|
-
expect(new HoloSphere(testAppName, false, 'fake-key').openai).toBeDefined();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe('Space Management', () => {
|
|
68
|
-
test('should handle private space authentication', async () => {
|
|
69
|
-
const testData = { id: 'test1', value: 'data' + Date.now() };
|
|
70
|
-
|
|
71
|
-
await holoSphere.put(testHolon, testLens, testData, testPassword);
|
|
72
|
-
const result = await holoSphere.get(testHolon, testLens, testData.id, testPassword);
|
|
73
|
-
expect(result).toBeDefined();
|
|
74
|
-
expect(result.value).toBe(testData.value);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('should handle public space access', async () => {
|
|
78
|
-
const testData = { id: 'public1', value: 'public data' + Date.now() };
|
|
79
|
-
|
|
80
|
-
await holoSphere.put(testHolon, testLens, testData);
|
|
81
|
-
const result = await holoSphere.get(testHolon, testLens, testData.id);
|
|
82
|
-
expect(result).toBeDefined();
|
|
83
|
-
expect(result.value).toBe(testData.value);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('should handle missing parameters gracefully', async () => {
|
|
87
|
-
const result1 = await holoSphere.get(null, testLens, 'key');
|
|
88
|
-
expect(result1).toBeNull();
|
|
89
|
-
|
|
90
|
-
const result2 = await holoSphere.get(testHolon, null, 'key');
|
|
91
|
-
expect(result2).toBeNull();
|
|
92
|
-
|
|
93
|
-
const result3 = await holoSphere.get(testHolon, testLens, null);
|
|
94
|
-
expect(result3).toBeNull();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('should handle authentication errors gracefully', async () => {
|
|
98
|
-
const testData = { id: 'test2', value: 'private data' };
|
|
99
|
-
|
|
100
|
-
await holoSphere.put(testHolon, testLens, testData, testPassword);
|
|
101
|
-
const result = await holoSphere.get(testHolon, testLens, testData.id, 'wrong_password');
|
|
102
|
-
expect(result).toBeNull();
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
describe('Data Operations', () => {
|
|
107
|
-
const validSchema = {
|
|
108
|
-
type: 'object',
|
|
109
|
-
properties: {
|
|
110
|
-
id: { type: 'string' },
|
|
111
|
-
value: { type: 'string' }
|
|
112
|
-
},
|
|
113
|
-
required: ['id', 'value']
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
beforeEach(async () => {
|
|
117
|
-
await holoSphere.setSchema(testLens, validSchema);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test('should handle data operations gracefully', async () => {
|
|
121
|
-
const testData = { id: 'test3', value: 'test data' };
|
|
122
|
-
|
|
123
|
-
// Test non-existent data
|
|
124
|
-
const nonExistent = await holoSphere.get(testHolon, testLens, 'non-existent');
|
|
125
|
-
expect(nonExistent).toBeNull();
|
|
126
|
-
|
|
127
|
-
// Test storing and retrieving data
|
|
128
|
-
await holoSphere.put(testHolon, testLens, testData);
|
|
129
|
-
const result = await holoSphere.get(testHolon, testLens, testData.id);
|
|
130
|
-
expect(result).toEqual(testData);
|
|
131
|
-
|
|
132
|
-
// Test deleting data
|
|
133
|
-
await holoSphere.delete(testHolon, testLens, testData.id);
|
|
134
|
-
const deletedResult = await holoSphere.get(testHolon, testLens, testData.id);
|
|
135
|
-
expect(deletedResult).toBeNull();
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test('should handle invalid data gracefully', async () => {
|
|
139
|
-
const invalidData = { wrongField: 'no id field' };
|
|
140
|
-
|
|
141
|
-
// Should not throw when storing invalid data in non-strict mode
|
|
142
|
-
await expect(holoSphere.put(testHolon, testLens, invalidData))
|
|
143
|
-
.resolves.toBeTruthy();
|
|
144
|
-
|
|
145
|
-
// Should return null when retrieving invalid data
|
|
146
|
-
const result = await holoSphere.get(testHolon, testLens, 'undefined');
|
|
147
|
-
expect(result).toBeNull();
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe('Global Operations', () => {
|
|
152
|
-
test('should handle global operations gracefully', async () => {
|
|
153
|
-
const globalData = { id: 'global1', value: 'global test data' };
|
|
154
|
-
|
|
155
|
-
// Test non-existent data
|
|
156
|
-
const nonExistent = await holoSphere.getGlobal(testHolon, testLens, 'non-existent');
|
|
157
|
-
expect(nonExistent).toBeNull();
|
|
158
|
-
|
|
159
|
-
// Test storing and retrieving data
|
|
160
|
-
await holoSphere.putGlobal(testLens, globalData);
|
|
161
|
-
const result = await holoSphere.getGlobal(testLens, globalData.id);
|
|
162
|
-
expect(result).toEqual(globalData);
|
|
163
|
-
|
|
164
|
-
// Test deleting data
|
|
165
|
-
await holoSphere.deleteGlobal( testLens, globalData.id);
|
|
166
|
-
const deletedResult = await holoSphere.getGlobal( testLens, globalData.id);
|
|
167
|
-
expect(deletedResult).toBeNull();
|
|
168
|
-
});
|
|
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
|
-
});
|
|
354
|
-
});
|
package/test/meta-strip.test.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
// meta-strip.test.js
|
|
2
|
-
|
|
3
|
-
import HoloSphere from '../holosphere.js';
|
|
4
|
-
|
|
5
|
-
describe('Meta Field Stripping Tests', () => {
|
|
6
|
-
let holoSphere;
|
|
7
|
-
const testHolon = 'testHolon';
|
|
8
|
-
const testLens = 'testLens';
|
|
9
|
-
const testGlobalTable = 'testGlobalTable';
|
|
10
|
-
|
|
11
|
-
beforeEach(async () => {
|
|
12
|
-
holoSphere = new HoloSphere('test_app', false);
|
|
13
|
-
// Clean up before each test
|
|
14
|
-
try {
|
|
15
|
-
await holoSphere.deleteAll(testHolon, testLens);
|
|
16
|
-
await holoSphere.deleteAllGlobal(testGlobalTable);
|
|
17
|
-
} catch (error) {
|
|
18
|
-
// Ignore cleanup errors
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Small wait for Gun to settle
|
|
22
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
23
|
-
}, 30000);
|
|
24
|
-
|
|
25
|
-
afterEach(async () => {
|
|
26
|
-
if (holoSphere) {
|
|
27
|
-
await holoSphere.close();
|
|
28
|
-
}
|
|
29
|
-
}, 30000);
|
|
30
|
-
|
|
31
|
-
describe('put() should strip _meta field', () => {
|
|
32
|
-
test('should not store _meta field when putting data', async () => {
|
|
33
|
-
const testData = {
|
|
34
|
-
id: 'test1',
|
|
35
|
-
name: 'Test Item',
|
|
36
|
-
value: 42,
|
|
37
|
-
_meta: {
|
|
38
|
-
resolvedFromHologram: true,
|
|
39
|
-
hologramSoul: 'app/holon/lens/key',
|
|
40
|
-
someOtherMeta: 'should not be stored'
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// Store the data (should strip _meta)
|
|
45
|
-
await holoSphere.put(testHolon, testLens, testData);
|
|
46
|
-
|
|
47
|
-
// Wait for Gun to settle
|
|
48
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
49
|
-
|
|
50
|
-
// Retrieve the data
|
|
51
|
-
const retrieved = await holoSphere.get(testHolon, testLens, testData.id);
|
|
52
|
-
|
|
53
|
-
// Verify data exists and _meta is not stored
|
|
54
|
-
expect(retrieved).not.toBeNull();
|
|
55
|
-
expect(retrieved.id).toBe(testData.id);
|
|
56
|
-
expect(retrieved.name).toBe(testData.name);
|
|
57
|
-
expect(retrieved.value).toBe(testData.value);
|
|
58
|
-
expect(retrieved._meta).toBeUndefined(); // _meta should not be stored
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('should handle data without _meta field normally', async () => {
|
|
62
|
-
const testData = {
|
|
63
|
-
id: 'test2',
|
|
64
|
-
name: 'Test Item Without Meta',
|
|
65
|
-
value: 99
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// Store the data
|
|
69
|
-
await holoSphere.put(testHolon, testLens, testData);
|
|
70
|
-
|
|
71
|
-
// Wait for Gun to settle
|
|
72
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
73
|
-
|
|
74
|
-
// Retrieve the data
|
|
75
|
-
const retrieved = await holoSphere.get(testHolon, testLens, testData.id);
|
|
76
|
-
|
|
77
|
-
// Verify data exists and matches exactly
|
|
78
|
-
expect(retrieved).toEqual(testData);
|
|
79
|
-
expect(retrieved._meta).toBeUndefined();
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('putGlobal() should strip _meta field', () => {
|
|
84
|
-
test('should not store _meta field when putting global data', async () => {
|
|
85
|
-
const testData = {
|
|
86
|
-
id: 'globaltest1',
|
|
87
|
-
name: 'Global Test Item',
|
|
88
|
-
value: 123,
|
|
89
|
-
_meta: {
|
|
90
|
-
resolvedFromHologram: true,
|
|
91
|
-
hologramSoul: 'app/holon/lens/key',
|
|
92
|
-
federation: { origin: 'someholon' }
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// Store the global data (should strip _meta)
|
|
97
|
-
await holoSphere.putGlobal(testGlobalTable, testData);
|
|
98
|
-
|
|
99
|
-
// Wait for Gun to settle
|
|
100
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
101
|
-
|
|
102
|
-
// Retrieve the data
|
|
103
|
-
const retrieved = await holoSphere.getGlobal(testGlobalTable, testData.id);
|
|
104
|
-
|
|
105
|
-
// Verify data exists and _meta is not stored
|
|
106
|
-
expect(retrieved).not.toBeNull();
|
|
107
|
-
expect(retrieved.id).toBe(testData.id);
|
|
108
|
-
expect(retrieved.name).toBe(testData.name);
|
|
109
|
-
expect(retrieved.value).toBe(testData.value);
|
|
110
|
-
expect(retrieved._meta).toBeUndefined(); // _meta should not be stored
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
test('should handle global data without _meta field normally', async () => {
|
|
114
|
-
const testData = {
|
|
115
|
-
id: 'globaltest2',
|
|
116
|
-
name: 'Global Test Item Without Meta',
|
|
117
|
-
value: 456
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Store the global data
|
|
121
|
-
await holoSphere.putGlobal(testGlobalTable, testData);
|
|
122
|
-
|
|
123
|
-
// Wait for Gun to settle
|
|
124
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
125
|
-
|
|
126
|
-
// Retrieve the data
|
|
127
|
-
const retrieved = await holoSphere.getGlobal(testGlobalTable, testData.id);
|
|
128
|
-
|
|
129
|
-
// Verify data exists and matches exactly
|
|
130
|
-
expect(retrieved).toEqual(testData);
|
|
131
|
-
expect(retrieved._meta).toBeUndefined();
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test('should preserve _meta in original data object (not mutate input)', async () => {
|
|
136
|
-
const testData = {
|
|
137
|
-
id: 'test3',
|
|
138
|
-
name: 'Test Mutation',
|
|
139
|
-
_meta: {
|
|
140
|
-
resolvedFromHologram: true,
|
|
141
|
-
hologramSoul: 'app/holon/lens/key'
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// Store a copy to verify original isn't mutated
|
|
146
|
-
const originalMeta = { ...testData._meta };
|
|
147
|
-
|
|
148
|
-
// Store the data
|
|
149
|
-
await holoSphere.put(testHolon, testLens, testData);
|
|
150
|
-
|
|
151
|
-
// Verify the original object still has _meta (we shouldn't mutate the input)
|
|
152
|
-
expect(testData._meta).toBeDefined();
|
|
153
|
-
expect(testData._meta).toEqual(originalMeta);
|
|
154
|
-
|
|
155
|
-
// But the stored data should not have _meta
|
|
156
|
-
const retrieved = await holoSphere.get(testHolon, testLens, testData.id);
|
|
157
|
-
expect(retrieved._meta).toBeUndefined();
|
|
158
|
-
});
|
|
159
|
-
});
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import HoloSphere from '../holosphere.js';
|
|
2
|
-
|
|
3
|
-
describe('Parent Propagation Tests', () => {
|
|
4
|
-
let holosphere;
|
|
5
|
-
const testPrefix = 'parent_prop_test_';
|
|
6
|
-
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
holosphere = new HoloSphere('parent-propagation-test');
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
afterEach(async () => {
|
|
12
|
-
if (holosphere) {
|
|
13
|
-
await holosphere.close();
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe('propagate with parent propagation', () => {
|
|
18
|
-
test('should propagate to parent hexagons when holon is valid H3 hexagon', async () => {
|
|
19
|
-
// Create a valid H3 hexagon (resolution 7)
|
|
20
|
-
const childHexagon = '87283472bffffff'; // Example H3 hexagon at resolution 7
|
|
21
|
-
const parentHexagon = '86283472fffffff'; // Parent at resolution 6
|
|
22
|
-
|
|
23
|
-
// Test data
|
|
24
|
-
const testData = {
|
|
25
|
-
id: 'test-item-1',
|
|
26
|
-
title: 'Test Item',
|
|
27
|
-
value: 42
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// Propagate with parent propagation enabled
|
|
31
|
-
const result = await holosphere.propagate(childHexagon, 'items', testData, {
|
|
32
|
-
propagateToParents: true,
|
|
33
|
-
maxParentLevels: 5
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Check that parent propagation was attempted
|
|
37
|
-
expect(result.parentPropagation).toBeDefined();
|
|
38
|
-
expect(result.parentPropagation.success).toBeGreaterThan(0);
|
|
39
|
-
expect(result.parentPropagation.messages).toEqual(
|
|
40
|
-
expect.arrayContaining([expect.stringContaining('parent hexagons to propagate to')])
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
// Allow time for propagation
|
|
44
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
45
|
-
|
|
46
|
-
// Verify data was propagated to parent hexagon (check for hologram, not resolved data)
|
|
47
|
-
const parentHologram = await holosphere.get(parentHexagon, 'items', testData.id, null, { resolveHolograms: false });
|
|
48
|
-
expect(parentHologram).toBeDefined();
|
|
49
|
-
expect(parentHologram._federation.propagationType).toBe('parent');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('should skip parent propagation for non-H3 hexagons', async () => {
|
|
53
|
-
// Use a non-H3 hexagon identifier
|
|
54
|
-
const nonHexagonHolon = 'not-a-hexagon';
|
|
55
|
-
|
|
56
|
-
const testData = {
|
|
57
|
-
id: 'test-item-2',
|
|
58
|
-
title: 'Test Item',
|
|
59
|
-
value: 42
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const result = await holosphere.propagate(nonHexagonHolon, 'items', testData, {
|
|
63
|
-
propagateToParents: true
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
expect(result.parentPropagation).toBeDefined();
|
|
67
|
-
expect(result.parentPropagation.skipped).toBe(1);
|
|
68
|
-
expect(result.parentPropagation.messages).toEqual(
|
|
69
|
-
expect.arrayContaining([expect.stringContaining('No parent hexagons found')])
|
|
70
|
-
);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('should respect maxParentLevels option', async () => {
|
|
74
|
-
const childHexagon = '87283472bffffff'; // Resolution 7
|
|
75
|
-
|
|
76
|
-
const testData = {
|
|
77
|
-
id: 'test-item-3',
|
|
78
|
-
title: 'Test Item',
|
|
79
|
-
value: 42
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const result = await holosphere.propagate(childHexagon, 'items', testData, {
|
|
83
|
-
propagateToParents: true,
|
|
84
|
-
maxParentLevels: 2 // Only propagate to 2 parent levels
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
expect(result.parentPropagation).toBeDefined();
|
|
88
|
-
expect(result.parentPropagation.success).toBe(2); // Should propagate to 2 parent levels
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('should disable parent propagation when propagateToParents is false', async () => {
|
|
92
|
-
const childHexagon = '87283472bffffff';
|
|
93
|
-
|
|
94
|
-
const testData = {
|
|
95
|
-
id: 'test-item-4',
|
|
96
|
-
title: 'Test Item',
|
|
97
|
-
value: 42
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const result = await holosphere.propagate(childHexagon, 'items', testData, {
|
|
101
|
-
propagateToParents: false
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
expect(result.parentPropagation).toBeDefined();
|
|
105
|
-
expect(result.parentPropagation.success).toBe(0);
|
|
106
|
-
expect(result.parentPropagation.skipped).toBe(0);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test('should include parent level information in federation metadata', async () => {
|
|
110
|
-
const childHexagon = '87283472bffffff'; // Resolution 7
|
|
111
|
-
const parentHexagon = '86283472fffffff'; // Resolution 6
|
|
112
|
-
|
|
113
|
-
const testData = {
|
|
114
|
-
id: 'test-item-5',
|
|
115
|
-
title: 'Test Item',
|
|
116
|
-
value: 42
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// First, store the original data in the child hexagon
|
|
120
|
-
await holosphere.put(childHexagon, 'items', testData);
|
|
121
|
-
|
|
122
|
-
// Then propagate to parent
|
|
123
|
-
await holosphere.propagate(childHexagon, 'items', testData, {
|
|
124
|
-
propagateToParents: true,
|
|
125
|
-
maxParentLevels: 1
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Allow time for propagation
|
|
129
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
130
|
-
|
|
131
|
-
// Check parent data has correct metadata (check for hologram, not resolved data)
|
|
132
|
-
const parentHologram = await holosphere.get(parentHexagon, 'items', testData.id, null, { resolveHolograms: false });
|
|
133
|
-
expect(parentHologram).toBeDefined();
|
|
134
|
-
expect(parentHologram._federation.propagationType).toBe('parent');
|
|
135
|
-
expect(parentHologram._federation.parentLevel).toBe(1); // 1 level up from resolution 7 to 6
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
});
|