holosphere 1.1.11 → 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/content.js +175 -26
- package/federation.js +252 -117
- package/global.js +174 -9
- package/holosphere-bundle.esm.js +33184 -0
- package/holosphere-bundle.js +33206 -0
- package/holosphere-bundle.min.js +38 -0
- package/holosphere.d.ts +15 -0
- package/holosphere.js +2 -2
- package/node.js +92 -7
- package/package.json +78 -3
- package/.cursor/rules/futura.mdc +0 -55
- package/examples/federation.js +0 -162
- 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.test.js +0 -316
- package/test/holosphere.test.js +0 -354
- 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
|
-
});
|