holosphere 1.1.0 → 1.1.2

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/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "holosphere",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Holonic Geospatial Communication Infrastructure",
5
5
  "main": "holosphere.js",
6
6
  "types": "holosphere.d.ts",
7
7
  "type": "module",
8
8
  "scripts": {
9
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
9
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
10
+ "build": "",
11
+ "prepare": "npm run build"
10
12
  },
11
13
  "author": "Roberto Valenti",
12
14
  "license": "GPL-3.0-or-later",
@@ -35,85 +35,34 @@ describe('HoloSphere', () => {
35
35
  };
36
36
 
37
37
  test('should set and get schema', async () => {
38
- // Set the schema
39
- const setResult = await holoSphere.setSchema(testLens, validSchema);
40
- expect(setResult).toBe(true);
41
-
38
+ await holoSphere.setSchema(testLens, validSchema);
39
+
42
40
  // Wait for GunDB to process
43
- await new Promise(resolve => setTimeout(resolve, 100));
41
+ await new Promise(resolve => setTimeout(resolve, 500));
44
42
 
45
- // Get and verify the schema
46
43
  const retrievedSchema = await holoSphere.getSchema(testLens);
47
44
  expect(retrievedSchema).toBeDefined();
48
45
  expect(retrievedSchema).toEqual(validSchema);
49
- }, 5000);
46
+ }, 10000);
50
47
 
51
48
  test('should handle invalid schema parameters', async () => {
52
- const nullResult = await holoSphere.setSchema(null, null);
53
- expect(nullResult).toBe(false);
54
-
55
- const missingLensResult = await holoSphere.setSchema(undefined, validSchema);
56
- expect(missingLensResult).toBe(false);
57
-
58
- const missingSchemaResult = await holoSphere.setSchema(testLens, null);
59
- expect(missingSchemaResult).toBe(false);
60
- });
49
+ await expect(holoSphere.setSchema(null, null))
50
+ .rejects.toThrow('setSchema: Missing required parameters');
51
+ }, 10000);
61
52
 
62
53
  test('should enforce strict mode schema validation', async () => {
63
54
  const strictHoloSphere = new HoloSphere(testAppName, true);
64
55
 
65
- // Test cases for invalid schemas
66
- const invalidSchemas = [
67
- {
68
- // Missing type field
69
- properties: {
70
- id: { type: 'string' }
71
- }
72
- },
73
- {
74
- // Missing properties
75
- type: 'object'
76
- },
77
- {
78
- // Missing required fields
79
- type: 'object',
80
- properties: {
81
- id: { type: 'string' }
82
- }
83
- },
84
- {
85
- // Invalid property type
86
- type: 'object',
87
- properties: {
88
- id: { type: 123 } // Should be string
89
- },
90
- required: ['id']
91
- }
92
- ];
93
-
94
- // Test each invalid schema
95
- for (const invalidSchema of invalidSchemas) {
96
- const setResult = await strictHoloSphere.setSchema(testLens, invalidSchema);
97
- expect(setResult).toBe(false);
98
- }
99
-
100
- // Valid schema should work in strict mode
101
- const validSchema = {
56
+ const invalidSchema = {
102
57
  type: 'object',
103
58
  properties: {
104
- id: { type: 'string' },
105
- data: { type: 'string' }
106
- },
107
- required: ['id', 'data']
59
+ id: { type: 'string' }
60
+ }
108
61
  };
109
62
 
110
- const validResult = await strictHoloSphere.setSchema(testLens, validSchema);
111
- expect(validResult).toBe(true);
112
-
113
- // Verify schema was stored correctly
114
- const retrievedSchema = await strictHoloSphere.getSchema(testLens);
115
- expect(retrievedSchema).toEqual(validSchema);
116
- }, 5000);
63
+ await expect(strictHoloSphere.setSchema(testLens, invalidSchema))
64
+ .rejects.toThrow();
65
+ }, 10000);
117
66
 
118
67
  test('should handle schema retrieval for non-existent lens', async () => {
119
68
  const result = await holoSphere.getSchema('nonexistent-lens');
@@ -123,11 +72,11 @@ describe('HoloSphere', () => {
123
72
  afterEach(async () => {
124
73
  // Clean up schemas after each test
125
74
  await holoSphere.gun.get(holoSphere.appname)
126
- .get(testLens)
127
- .get('schema')
128
- .put(null);
129
-
130
- // Wait for GunDB to process
75
+ .get(testLens)
76
+ .get('schema')
77
+ .put(null);
78
+
79
+ // Wait for GunDB to process
131
80
  await new Promise(resolve => setTimeout(resolve, 100));
132
81
  });
133
82
  });
@@ -152,16 +101,19 @@ describe('HoloSphere', () => {
152
101
  });
153
102
 
154
103
  test('should put and get data with schema validation', async () => {
155
- // Test valid data
156
- const putResult = await holoSphere.put(testHolon, testLens, validData);
157
- expect(putResult).toBe(true);
158
-
159
- const getResult = await holoSphere.get(testHolon, testLens, validData.id);
160
- expect(getResult).toEqual(validData);
104
+ const validData = { id: 'test1', data: 'test data' };
105
+ const invalidData = { id: 'test2' }; // Missing required 'data' field
161
106
 
107
+ // Test valid data
108
+ await holoSphere.put(testHolon, testLens, validData);
109
+
162
110
  // Test invalid data
163
- const invalidPutResult = await holoSphere.put(testHolon, testLens, invalidData);
164
- expect(invalidPutResult).toBe(false);
111
+ try {
112
+ await holoSphere.put(testHolon, testLens, invalidData);
113
+ fail('Expected validation error but operation succeeded');
114
+ } catch (error) {
115
+ expect(error.message).toContain('Schema validation failed');
116
+ }
165
117
  }, 10000);
166
118
 
167
119
  test('should get all data with schema validation', async () => {
@@ -210,17 +162,8 @@ describe('HoloSphere', () => {
210
162
  await strictHoloSphere.setSchema(testLens, strictSchema);
211
163
 
212
164
  // Try to put data without schema in strict mode
213
- const noSchemaResult = await strictHoloSphere.put(testHolon, 'no-schema-lens', validData);
214
- expect(noSchemaResult).toBe(false);
215
-
216
- // Try to get data without schema in strict mode
217
- const noSchemaData = await strictHoloSphere.getAll(testHolon, 'no-schema-lens');
218
- expect(noSchemaData).toEqual([]);
219
-
220
- // Invalid data should be removed in strict mode
221
- await strictHoloSphere.put(testHolon, testLens, invalidData);
222
- const results = await strictHoloSphere.getAll(testHolon, testLens);
223
- expect(results.some(item => item.id === invalidData.id)).toBe(false);
165
+ await expect(strictHoloSphere.put(testHolon, 'no-schema-lens', validData))
166
+ .rejects.toThrow('Schema required in strict mode');
224
167
  }, 10000);
225
168
  });
226
169
 
@@ -231,10 +174,10 @@ describe('HoloSphere', () => {
231
174
 
232
175
  test('should put and get node', async () => {
233
176
  await holoSphere.putNode(testHolon, testLens, testNode);
234
-
177
+
235
178
  // Wait for GunDB to process
236
179
  await new Promise(resolve => setTimeout(resolve, 100));
237
-
180
+
238
181
  const result = await holoSphere.getNode(testHolon, testLens, 'value');
239
182
  expect(result).toBeDefined();
240
183
  expect(result).toBe('test node data');
@@ -244,35 +187,31 @@ describe('HoloSphere', () => {
244
187
  // First put the node
245
188
  await holoSphere.putNode(testHolon, testLens, testNode);
246
189
  await new Promise(resolve => setTimeout(resolve, 100));
247
-
190
+
248
191
  // Verify node exists
249
192
  const beforeDelete = await holoSphere.getNode(testHolon, testLens, 'value');
250
193
  expect(beforeDelete).toBe('test node data');
251
-
194
+
252
195
  // Delete the node
253
196
  const deleteResult = await holoSphere.deleteNode(testHolon, testLens, 'value');
254
197
  expect(deleteResult).toBe(true);
255
-
198
+
256
199
  // Wait for deletion to process
257
200
  await new Promise(resolve => setTimeout(resolve, 100));
258
-
201
+
259
202
  // Verify node is deleted
260
203
  const afterDelete = await holoSphere.getNode(testHolon, testLens, 'value');
261
204
  expect(afterDelete).toBeNull();
262
205
  }, 10000);
263
206
 
264
207
  test('should handle invalid node operations', async () => {
265
- // Test missing parameters
266
- const nullResult = await holoSphere.deleteNode(null, null, null);
267
- expect(nullResult).toBe(false);
268
-
269
- const nullGet = await holoSphere.getNode(null, null, null);
270
- expect(nullGet).toBeNull();
271
- });
208
+ await expect(holoSphere.deleteNode(null, null, null))
209
+ .rejects.toThrow('deleteNode: Missing required parameters');
210
+ }, 10000);
272
211
 
273
212
  afterEach(async () => {
274
213
  // Clean up after each test
275
- await holoSphere.deleteNode(testHolon, testLens, 'value');
214
+ await holoSphere.deleteNode(testHolon, testLens, 'value');
276
215
  await new Promise(resolve => setTimeout(resolve, 100));
277
216
  });
278
217
  });
@@ -302,13 +241,262 @@ describe('HoloSphere', () => {
302
241
  });
303
242
  });
304
243
 
305
- afterAll(async () => {
306
- // Clean up test data
244
+ describe('Subscription Operations', () => {
245
+ const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
307
246
  const testLens = 'testLens';
247
+
248
+ beforeEach(async () => {
249
+ // Clear any existing subscriptions and data
250
+ holoSphere.cleanup();
251
+ await holoSphere.deleteAll(testHolon, testLens);
252
+ // Wait for cleanup to complete
253
+ await new Promise(resolve => setTimeout(resolve, 500));
254
+ });
255
+
256
+ test('should subscribe to changes', async () => {
257
+ const changes = [];
258
+ const subscription = await holoSphere.subscribe(testHolon, testLens, (data) => {
259
+ changes.push(data);
260
+ });
261
+
262
+ expect(subscription.id).toBeDefined();
263
+ expect(typeof subscription.unsubscribe).toBe('function');
264
+
265
+ await holoSphere.put(testHolon, testLens, { id: 'test1', data: 'test data' });
266
+
267
+ // Wait longer for subscription to process
268
+ await new Promise(resolve => setTimeout(resolve, 500));
269
+
270
+ expect(changes.length).toBeGreaterThan(0);
271
+ }, 10000);
272
+
273
+ test('should unsubscribe properly', async () => {
274
+ const changes = [];
275
+ let subscription;
276
+
277
+ // Create a promise that resolves after receiving the first change
278
+ const firstChangePromise = new Promise(resolve => {
279
+ subscription = holoSphere.subscribe(testHolon, testLens, (data) => {
280
+ changes.push(data);
281
+ if (changes.length === 1) resolve();
282
+ });
283
+ });
284
+
285
+ // Put initial data and wait for first change
286
+ await holoSphere.put(testHolon, testLens, { id: 'test1', data: 'test data' });
287
+ await firstChangePromise;
288
+
289
+ // Clear changes and unsubscribe
290
+ changes.length = 0;
291
+ subscription.unsubscribe();
292
+
293
+ // Wait longer for unsubscribe to take effect
294
+ await new Promise(resolve => setTimeout(resolve, 1000));
295
+
296
+ // Put new data
297
+ await holoSphere.put(testHolon, testLens, { id: 'test2', data: 'new data' });
298
+
299
+ // Wait to ensure no new changes are received
300
+ await new Promise(resolve => setTimeout(resolve, 1000));
301
+
302
+ expect(changes.length).toBe(0);
303
+ }, 20000);
304
+
305
+ test('should cleanup all subscriptions', async () => {
306
+ const subs = [];
307
+ for (let i = 0; i < 3; i++) {
308
+ subs.push(await holoSphere.subscribe(testHolon, testLens, () => {}));
309
+ // Wait between subscriptions
310
+ await new Promise(resolve => setTimeout(resolve, 100));
311
+ }
312
+
313
+ expect(holoSphere.subscriptions.size).toBe(3);
314
+ holoSphere.cleanup();
315
+ expect(holoSphere.subscriptions.size).toBe(0);
316
+ }, 10000);
317
+ });
318
+
319
+ describe('Parse Operations', () => {
320
+ test('should handle null input', async () => {
321
+ await expect(holoSphere.parse(null))
322
+ .rejects.toThrow('parse: No data provided');
323
+ });
324
+
325
+ test('should parse valid JSON string', async () => {
326
+ const result = await holoSphere.parse('{"test": "data"}');
327
+ expect(result).toEqual({ test: 'data' });
328
+ });
329
+ });
330
+
331
+ describe('Global Operations', () => {
332
+ test('should put and get global data', async () => {
333
+ const testData = { id: 'global1', value: 'test' };
334
+ await holoSphere.putGlobal('testTable', testData);
335
+
336
+ const result = await holoSphere.getGlobal('testTable', 'global1');
337
+ expect(result).toEqual(testData);
338
+ });
339
+
340
+ test('should handle missing parameters in global operations', async () => {
341
+ await expect(holoSphere.putGlobal(null, null))
342
+ .rejects.toThrow('Table name and data are required');
343
+ });
344
+
345
+ test('should handle getAllGlobal', async () => {
346
+ await holoSphere.putGlobal('testTable', { id: 'g1', value: 'test1' });
347
+ await holoSphere.putGlobal('testTable', { id: 'g2', value: 'test2' });
348
+
349
+ const results = await holoSphere.getAllGlobal('testTable');
350
+ expect(Array.isArray(results)).toBe(true);
351
+ expect(results.length).toBeGreaterThan(0);
352
+ });
353
+ });
354
+
355
+ describe('Compute Operations', () => {
308
356
  const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
309
- await holoSphere.deleteAll(testHolon, testLens);
310
-
311
- // Allow time for Gun to process
357
+ const testLens = 'testLens';
358
+
359
+ beforeEach(async () => {
360
+ // Set up schema for compute tests
361
+ const schema = {
362
+ type: 'object',
363
+ properties: {
364
+ id: { type: 'string' },
365
+ content: { type: 'string' },
366
+ data: { type: 'string' }
367
+ },
368
+ required: ['id', 'data']
369
+ };
370
+ await holoSphere.setSchema(testLens, schema);
371
+ });
372
+
373
+ test('should validate compute parameters', async () => {
374
+ await expect(holoSphere.compute(null, null))
375
+ .rejects.toThrow('compute: Missing required parameters');
376
+ });
377
+
378
+ test('should validate holon resolution', async () => {
379
+ const invalidHolon = 'invalid';
380
+ await expect(holoSphere.compute(invalidHolon, 'testLens'))
381
+ .rejects.toThrow('compute: Invalid holon resolution');
382
+ });
383
+
384
+ test('should compute with valid parameters', async () => {
385
+ await holoSphere.put(testHolon, testLens, {
386
+ id: 'test1',
387
+ data: 'test data',
388
+ content: 'test content'
389
+ });
390
+
391
+ await expect(holoSphere.compute(testHolon, testLens, 'summarize'))
392
+ .resolves.not.toThrow();
393
+ }, 15000);
394
+ });
395
+
396
+ describe('Error Handling', () => {
397
+ const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
398
+ const testLens = 'testLens';
399
+
400
+ beforeEach(async () => {
401
+ // Clear all existing data
402
+ await holoSphere.deleteAll(testHolon, testLens);
403
+ await new Promise(resolve => setTimeout(resolve, 1000));
404
+
405
+ // Set up fresh schema
406
+ const schema = {
407
+ type: 'object',
408
+ properties: {
409
+ id: { type: 'string' },
410
+ data: { type: 'string' }
411
+ },
412
+ required: ['id', 'data']
413
+ };
414
+ await holoSphere.setSchema(testLens, schema);
415
+ await new Promise(resolve => setTimeout(resolve, 500));
416
+ });
417
+
418
+ test('should handle concurrent operations', async () => {
419
+ const numOperations = 10;
420
+ const promises = [];
421
+ const expectedIds = new Set();
422
+
423
+ // Create concurrent put operations
424
+ for (let i = 0; i < numOperations; i++) {
425
+ const id = `concurrent${i}`;
426
+ expectedIds.add(id);
427
+ promises.push(holoSphere.put(testHolon, testLens, {
428
+ id: id,
429
+ data: 'test'
430
+ }));
431
+ }
432
+
433
+ // Wait for all operations to complete
434
+ await Promise.all(promises);
435
+ await new Promise(resolve => setTimeout(resolve, 1000));
436
+
437
+ // Get and verify results
438
+ const results = await holoSphere.getAll(testHolon, testLens);
439
+ const resultIds = new Set(results.map(r => r.id));
440
+
441
+ // Verify we have exactly the expected number of unique results
442
+ expect(resultIds.size).toBe(numOperations);
443
+
444
+ // Verify all expected IDs are present
445
+ expectedIds.forEach(id => {
446
+ expect(resultIds.has(id)).toBe(true);
447
+ });
448
+ }, 20000);
449
+
450
+ test('should handle large data sets', async () => {
451
+ const largeData = {
452
+ id: 'large',
453
+ data: 'x'.repeat(1000000)
454
+ };
455
+
456
+ // Put the data
457
+ await holoSphere.put(testHolon, testLens, largeData);
458
+
459
+ // Wait for data to be stored
460
+ await new Promise(resolve => setTimeout(resolve, 1000));
461
+
462
+ // Get the data back
463
+ const result = await holoSphere.get(testHolon, testLens, 'large');
464
+
465
+ // Verify the data
466
+ expect(result).toBeDefined();
467
+ expect(result.id).toBe(largeData.id);
468
+ expect(result.data).toBe(largeData.data);
469
+ }, 20000);
470
+
471
+ afterEach(async () => {
472
+ // Clean up after each test
473
+ await holoSphere.deleteAll(testHolon, testLens);
474
+ await new Promise(resolve => setTimeout(resolve, 1000));
475
+ });
476
+ });
477
+
478
+ describe('OpenAI Integration', () => {
479
+ test('should handle missing OpenAI key', async () => {
480
+ const noAIHoloSphere = new HoloSphere('test');
481
+ const result = await noAIHoloSphere.summarize('test content');
482
+ expect(result).toBe('OpenAI not initialized, please specify the API key in the constructor.');
483
+ });
484
+
485
+ test.skip('should summarize content with valid OpenAI key', async () => {
486
+ const hsWithAI = new HoloSphere('test', false, process.env.OPENAI_API_KEY);
487
+ const summary = await hsWithAI.summarize('Test content to summarize');
488
+ expect(typeof summary).toBe('string');
489
+ expect(summary.length).toBeGreaterThan(0);
490
+ });
491
+ });
492
+
493
+ afterAll(async () => {
494
+ // Clean up test data
495
+ const testLens = 'testLens';
496
+ const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
497
+ await holoSphere.deleteAll(testHolon, testLens);
498
+
499
+ // Allow time for Gun to process
312
500
  await new Promise(resolve => setTimeout(resolve, 1000));
313
501
  });
314
502
  });