holosphere 1.0.7 → 1.1.0
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/README.md +272 -147
- package/babel.config.json +12 -0
- package/holosphere.d.ts +41 -15
- package/holosphere.js +554 -291
- package/package.json +13 -2
- package/test/holosphere.test.js +299 -17
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "holosphere",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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": "
|
|
9
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
|
|
10
10
|
},
|
|
11
11
|
"author": "Roberto Valenti",
|
|
12
12
|
"license": "GPL-3.0-or-later",
|
|
@@ -15,5 +15,16 @@
|
|
|
15
15
|
"gun": "^0.2020.1240",
|
|
16
16
|
"h3-js": "^4.1.0",
|
|
17
17
|
"openai": "^4.29.2"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"jest": "^29.7.0",
|
|
21
|
+
"jest-environment-node": "^29.7.0"
|
|
22
|
+
},
|
|
23
|
+
"jest": {
|
|
24
|
+
"testEnvironment": "node",
|
|
25
|
+
"transform": {},
|
|
26
|
+
"moduleNameMapper": {
|
|
27
|
+
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
28
|
+
}
|
|
18
29
|
}
|
|
19
30
|
}
|
package/test/holosphere.test.js
CHANGED
|
@@ -1,32 +1,314 @@
|
|
|
1
1
|
import HoloSphere from '../holosphere.js';
|
|
2
|
+
import * as h3 from 'h3-js';
|
|
2
3
|
|
|
3
4
|
describe('HoloSphere', () => {
|
|
4
5
|
let holoSphere;
|
|
5
|
-
|
|
6
|
+
const testAppName = 'test-app';
|
|
7
|
+
|
|
6
8
|
beforeEach(() => {
|
|
7
|
-
holoSphere = new HoloSphere(
|
|
8
|
-
|
|
9
|
+
holoSphere = new HoloSphere(testAppName);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe('Constructor', () => {
|
|
13
|
+
test('should create instance with app name', () => {
|
|
14
|
+
expect(holoSphere).toBeInstanceOf(HoloSphere);
|
|
15
|
+
expect(holoSphere.gun).toBeDefined();
|
|
16
|
+
expect(holoSphere.validator).toBeDefined();
|
|
17
|
+
expect(holoSphere.openai).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('should initialize with OpenAI when key provided', () => {
|
|
21
|
+
const hsWithAI = new HoloSphere(testAppName, false, 'fake-key');
|
|
22
|
+
expect(hsWithAI.openai).toBeDefined();
|
|
9
23
|
});
|
|
10
24
|
});
|
|
11
25
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
describe('Schema Operations', () => {
|
|
27
|
+
const testLens = 'testLens';
|
|
28
|
+
const validSchema = {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
id: { type: 'string' },
|
|
32
|
+
data: { type: 'string' }
|
|
33
|
+
},
|
|
34
|
+
required: ['id', 'data']
|
|
35
|
+
};
|
|
36
|
+
|
|
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
|
+
|
|
42
|
+
// Wait for GunDB to process
|
|
43
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
44
|
+
|
|
45
|
+
// Get and verify the schema
|
|
46
|
+
const retrievedSchema = await holoSphere.getSchema(testLens);
|
|
47
|
+
expect(retrievedSchema).toBeDefined();
|
|
48
|
+
expect(retrievedSchema).toEqual(validSchema);
|
|
49
|
+
}, 5000);
|
|
50
|
+
|
|
51
|
+
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
|
+
});
|
|
61
|
+
|
|
62
|
+
test('should enforce strict mode schema validation', async () => {
|
|
63
|
+
const strictHoloSphere = new HoloSphere(testAppName, true);
|
|
64
|
+
|
|
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 = {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
id: { type: 'string' },
|
|
105
|
+
data: { type: 'string' }
|
|
106
|
+
},
|
|
107
|
+
required: ['id', 'data']
|
|
108
|
+
};
|
|
109
|
+
|
|
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);
|
|
117
|
+
|
|
118
|
+
test('should handle schema retrieval for non-existent lens', async () => {
|
|
119
|
+
const result = await holoSphere.getSchema('nonexistent-lens');
|
|
120
|
+
expect(result).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
afterEach(async () => {
|
|
124
|
+
// Clean up schemas after each test
|
|
125
|
+
await holoSphere.gun.get(holoSphere.appname)
|
|
126
|
+
.get(testLens)
|
|
127
|
+
.get('schema')
|
|
128
|
+
.put(null);
|
|
129
|
+
|
|
130
|
+
// Wait for GunDB to process
|
|
131
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
132
|
+
});
|
|
16
133
|
});
|
|
17
134
|
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
135
|
+
describe('Data Operations', () => {
|
|
136
|
+
const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
|
|
137
|
+
const testLens = 'testLens';
|
|
138
|
+
const validData = { id: 'test123', data: 'test data' };
|
|
139
|
+
const invalidData = { id: 'test456', wrongField: 'wrong data' };
|
|
140
|
+
|
|
141
|
+
beforeEach(async () => {
|
|
142
|
+
// Set up schema for validation tests
|
|
143
|
+
const schema = {
|
|
144
|
+
type: 'object',
|
|
145
|
+
properties: {
|
|
146
|
+
id: { type: 'string' },
|
|
147
|
+
data: { type: 'string' }
|
|
148
|
+
},
|
|
149
|
+
required: ['id', 'data']
|
|
150
|
+
};
|
|
151
|
+
await holoSphere.setSchema(testLens, schema);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
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);
|
|
23
158
|
|
|
24
|
-
|
|
25
|
-
|
|
159
|
+
const getResult = await holoSphere.get(testHolon, testLens, validData.id);
|
|
160
|
+
expect(getResult).toEqual(validData);
|
|
26
161
|
|
|
27
|
-
|
|
28
|
-
|
|
162
|
+
// Test invalid data
|
|
163
|
+
const invalidPutResult = await holoSphere.put(testHolon, testLens, invalidData);
|
|
164
|
+
expect(invalidPutResult).toBe(false);
|
|
165
|
+
}, 10000);
|
|
166
|
+
|
|
167
|
+
test('should get all data with schema validation', async () => {
|
|
168
|
+
await holoSphere.put(testHolon, testLens, validData);
|
|
169
|
+
await holoSphere.put(testHolon, testLens, { id: 'test789', data: 'more test data' });
|
|
170
|
+
|
|
171
|
+
const results = await holoSphere.getAll(testHolon, testLens);
|
|
172
|
+
expect(Array.isArray(results)).toBeTruthy();
|
|
173
|
+
expect(results.length).toBeGreaterThan(0);
|
|
174
|
+
expect(results.some(item => item.id === validData.id)).toBeTruthy();
|
|
175
|
+
}, 10000);
|
|
176
|
+
|
|
177
|
+
test('should delete data', async () => {
|
|
178
|
+
await holoSphere.put(testHolon, testLens, validData);
|
|
179
|
+
await holoSphere.delete(testHolon, testLens, validData.id);
|
|
180
|
+
|
|
181
|
+
const result = await holoSphere.get(testHolon, testLens, validData.id);
|
|
182
|
+
expect(result).toBeNull();
|
|
183
|
+
}, 10000);
|
|
184
|
+
|
|
185
|
+
test('should delete all data', async () => {
|
|
186
|
+
await holoSphere.put(testHolon, testLens, validData);
|
|
187
|
+
await holoSphere.put(testHolon, testLens, { id: 'test789', data: 'more test data' });
|
|
188
|
+
|
|
189
|
+
const deleteResult = await holoSphere.deleteAll(testHolon, testLens);
|
|
190
|
+
expect(deleteResult).toBe(true);
|
|
191
|
+
|
|
192
|
+
const results = await holoSphere.getAll(testHolon, testLens);
|
|
193
|
+
expect(results).toEqual([]);
|
|
194
|
+
}, 10000);
|
|
195
|
+
|
|
196
|
+
test('should enforce strict mode data validation', async () => {
|
|
197
|
+
const strictHoloSphere = new HoloSphere(testAppName, true);
|
|
198
|
+
|
|
199
|
+
// Define schema for strict mode tests
|
|
200
|
+
const strictSchema = {
|
|
201
|
+
type: 'object',
|
|
202
|
+
properties: {
|
|
203
|
+
id: { type: 'string' },
|
|
204
|
+
data: { type: 'string' }
|
|
205
|
+
},
|
|
206
|
+
required: ['id', 'data']
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Set up schema
|
|
210
|
+
await strictHoloSphere.setSchema(testLens, strictSchema);
|
|
211
|
+
|
|
212
|
+
// 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);
|
|
224
|
+
}, 10000);
|
|
29
225
|
});
|
|
30
226
|
|
|
31
|
-
|
|
227
|
+
describe('Node Operations', () => {
|
|
228
|
+
const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
|
|
229
|
+
const testLens = 'testLens';
|
|
230
|
+
const testNode = { value: 'test node data' };
|
|
231
|
+
|
|
232
|
+
test('should put and get node', async () => {
|
|
233
|
+
await holoSphere.putNode(testHolon, testLens, testNode);
|
|
234
|
+
|
|
235
|
+
// Wait for GunDB to process
|
|
236
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
237
|
+
|
|
238
|
+
const result = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
239
|
+
expect(result).toBeDefined();
|
|
240
|
+
expect(result).toBe('test node data');
|
|
241
|
+
}, 10000);
|
|
242
|
+
|
|
243
|
+
test('should delete node', async () => {
|
|
244
|
+
// First put the node
|
|
245
|
+
await holoSphere.putNode(testHolon, testLens, testNode);
|
|
246
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
247
|
+
|
|
248
|
+
// Verify node exists
|
|
249
|
+
const beforeDelete = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
250
|
+
expect(beforeDelete).toBe('test node data');
|
|
251
|
+
|
|
252
|
+
// Delete the node
|
|
253
|
+
const deleteResult = await holoSphere.deleteNode(testHolon, testLens, 'value');
|
|
254
|
+
expect(deleteResult).toBe(true);
|
|
255
|
+
|
|
256
|
+
// Wait for deletion to process
|
|
257
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
258
|
+
|
|
259
|
+
// Verify node is deleted
|
|
260
|
+
const afterDelete = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
261
|
+
expect(afterDelete).toBeNull();
|
|
262
|
+
}, 10000);
|
|
263
|
+
|
|
264
|
+
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
|
+
});
|
|
272
|
+
|
|
273
|
+
afterEach(async () => {
|
|
274
|
+
// Clean up after each test
|
|
275
|
+
await holoSphere.deleteNode(testHolon, testLens, 'value');
|
|
276
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
describe('Geospatial Operations', () => {
|
|
281
|
+
const lat = 40.7128;
|
|
282
|
+
const lng = -74.0060;
|
|
283
|
+
const resolution = 7;
|
|
284
|
+
|
|
285
|
+
test('should get holon from coordinates', async () => {
|
|
286
|
+
const holon = await holoSphere.getHolon(lat, lng, resolution);
|
|
287
|
+
expect(holon).toBeDefined();
|
|
288
|
+
expect(typeof holon).toBe('string');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test('should get scalespace from coordinates', () => {
|
|
292
|
+
const scales = holoSphere.getScalespace(lat, lng);
|
|
293
|
+
expect(Array.isArray(scales)).toBeTruthy();
|
|
294
|
+
expect(scales.length).toBe(15); // 0-14 resolution levels
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('should get holon scalespace', () => {
|
|
298
|
+
const holon = h3.latLngToCell(lat, lng, resolution);
|
|
299
|
+
const scales = holoSphere.getHolonScalespace(holon);
|
|
300
|
+
expect(Array.isArray(scales)).toBeTruthy();
|
|
301
|
+
expect(scales.length).toBe(resolution + 1);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
afterAll(async () => {
|
|
306
|
+
// Clean up test data
|
|
307
|
+
const testLens = 'testLens';
|
|
308
|
+
const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
|
|
309
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
310
|
+
|
|
311
|
+
// Allow time for Gun to process
|
|
312
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
313
|
+
});
|
|
32
314
|
});
|