holosphere 1.1.12 → 1.1.14

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.
@@ -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
- });
@@ -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
- });