holosphere 2.0.0-alpha0 → 2.0.0-alpha2

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.
Files changed (88) hide show
  1. package/LICENSE +162 -38
  2. package/dist/cjs/holosphere.cjs +2 -0
  3. package/dist/cjs/holosphere.cjs.map +1 -0
  4. package/dist/esm/holosphere.js +56 -0
  5. package/dist/esm/holosphere.js.map +1 -0
  6. package/dist/index-CDfIuXew.js +15974 -0
  7. package/dist/index-CDfIuXew.js.map +1 -0
  8. package/dist/index-ifOgtDvd.cjs +3 -0
  9. package/dist/index-ifOgtDvd.cjs.map +1 -0
  10. package/dist/indexeddb-storage-CMW4qRQS.js +96 -0
  11. package/dist/indexeddb-storage-CMW4qRQS.js.map +1 -0
  12. package/dist/indexeddb-storage-DLZOgetM.cjs +2 -0
  13. package/dist/indexeddb-storage-DLZOgetM.cjs.map +1 -0
  14. package/dist/memory-storage-DQzcAZlf.js +47 -0
  15. package/dist/memory-storage-DQzcAZlf.js.map +1 -0
  16. package/dist/memory-storage-DmePEP2q.cjs +2 -0
  17. package/dist/memory-storage-DmePEP2q.cjs.map +1 -0
  18. package/dist/secp256k1-CP0ZkpAx.cjs +13 -0
  19. package/dist/secp256k1-CP0ZkpAx.cjs.map +1 -0
  20. package/dist/secp256k1-vOXp40Fx.js +2281 -0
  21. package/dist/secp256k1-vOXp40Fx.js.map +1 -0
  22. package/docs/FOSDEM_PROPOSAL.md +388 -0
  23. package/docs/LOCALFIRST.md +266 -0
  24. package/docs/contracts/api-interface.md +793 -0
  25. package/docs/data-model.md +476 -0
  26. package/docs/gun-async-usage.md +338 -0
  27. package/docs/plan.md +349 -0
  28. package/docs/quickstart.md +674 -0
  29. package/docs/research.md +362 -0
  30. package/docs/spec.md +244 -0
  31. package/docs/storage-backends.md +326 -0
  32. package/docs/tasks.md +947 -0
  33. package/package.json +1 -1
  34. package/tests/unit/ai/aggregation.test.js +0 -295
  35. package/tests/unit/ai/breakdown.test.js +0 -446
  36. package/tests/unit/ai/classifier.test.js +0 -294
  37. package/tests/unit/ai/council.test.js +0 -262
  38. package/tests/unit/ai/embeddings.test.js +0 -384
  39. package/tests/unit/ai/federation-ai.test.js +0 -344
  40. package/tests/unit/ai/h3-ai.test.js +0 -458
  41. package/tests/unit/ai/index.test.js +0 -304
  42. package/tests/unit/ai/json-ops.test.js +0 -307
  43. package/tests/unit/ai/llm-service.test.js +0 -390
  44. package/tests/unit/ai/nl-query.test.js +0 -383
  45. package/tests/unit/ai/relationships.test.js +0 -311
  46. package/tests/unit/ai/schema-extractor.test.js +0 -384
  47. package/tests/unit/ai/spatial.test.js +0 -279
  48. package/tests/unit/ai/tts.test.js +0 -279
  49. package/tests/unit/content.test.js +0 -332
  50. package/tests/unit/contract/core.test.js +0 -88
  51. package/tests/unit/contract/crypto.test.js +0 -198
  52. package/tests/unit/contract/data.test.js +0 -223
  53. package/tests/unit/contract/federation.test.js +0 -181
  54. package/tests/unit/contract/hierarchical.test.js +0 -113
  55. package/tests/unit/contract/schema.test.js +0 -114
  56. package/tests/unit/contract/social.test.js +0 -217
  57. package/tests/unit/contract/spatial.test.js +0 -110
  58. package/tests/unit/contract/subscriptions.test.js +0 -128
  59. package/tests/unit/contract/utils.test.js +0 -159
  60. package/tests/unit/core.test.js +0 -152
  61. package/tests/unit/crypto.test.js +0 -328
  62. package/tests/unit/federation.test.js +0 -234
  63. package/tests/unit/gun-async.test.js +0 -252
  64. package/tests/unit/hierarchical.test.js +0 -399
  65. package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
  66. package/tests/unit/integration/scenario-02-federation.test.js +0 -76
  67. package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
  68. package/tests/unit/integration/scenario-04-validation.test.js +0 -129
  69. package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
  70. package/tests/unit/integration/scenario-06-social.test.js +0 -135
  71. package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
  72. package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
  73. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
  74. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
  75. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
  76. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
  77. package/tests/unit/performance/benchmark.test.js +0 -85
  78. package/tests/unit/schema.test.js +0 -213
  79. package/tests/unit/spatial.test.js +0 -158
  80. package/tests/unit/storage.test.js +0 -195
  81. package/tests/unit/subscriptions.test.js +0 -328
  82. package/tests/unit/test-data-permanence-debug.js +0 -197
  83. package/tests/unit/test-data-permanence.js +0 -340
  84. package/tests/unit/test-key-persistence-fixed.js +0 -148
  85. package/tests/unit/test-key-persistence.js +0 -172
  86. package/tests/unit/test-relay-permanence.js +0 -376
  87. package/tests/unit/test-second-node.js +0 -95
  88. package/tests/unit/test-simple-write.js +0 -89
@@ -1,399 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../src/index.js';
3
-
4
- describe('Unit: Hierarchical Module (T033.5)', () => {
5
- let hs;
6
- let testHolonId;
7
-
8
- beforeEach(async () => {
9
- hs = new HoloSphere({ relays: [], appName: 'test-hierarchical-unit' });
10
- testHolonId = await hs.toHolon(37.7749, -122.4194, 10);
11
- });
12
-
13
- describe('Upcast operation with summarize mode', () => {
14
- it('should upcast with summarize operation', async () => {
15
- await hs.write(testHolonId, 'events', {
16
- id: 'event-001',
17
- name: 'Test Event',
18
- attendees: 25
19
- });
20
-
21
- const success = await hs.upcast(testHolonId, 'events', 'event-001', {
22
- operation: 'summarize'
23
- });
24
-
25
- expect(success).toBe(true);
26
- });
27
-
28
- it('should create count summary in parent holons', async () => {
29
- await hs.write(testHolonId, 'items', {
30
- id: 'item-001',
31
- value: 'data'
32
- });
33
-
34
- await hs.upcast(testHolonId, 'items', 'item-001', {
35
- operation: 'summarize',
36
- maxLevel: 1
37
- });
38
-
39
- const parents = await hs.getParents(testHolonId);
40
- if (parents.length > 0) {
41
- const parentData = await hs.read(parents[0], 'items');
42
- expect(Array.isArray(parentData)).toBe(true);
43
- }
44
- });
45
-
46
- it('should increment count on multiple upcasts', async () => {
47
- await hs.write(testHolonId, 'counts', { id: 'c1', value: 1 });
48
- await hs.write(testHolonId, 'counts', { id: 'c2', value: 2 });
49
-
50
- await hs.upcast(testHolonId, 'counts', 'c1', { operation: 'summarize' });
51
- await hs.upcast(testHolonId, 'counts', 'c2', { operation: 'summarize' });
52
-
53
- // Parent should have count of 2
54
- });
55
- });
56
-
57
- describe('Upcast operation with aggregate mode', () => {
58
- it('should upcast with aggregate operation', async () => {
59
- await hs.write(testHolonId, 'stats', {
60
- id: 'stat-001',
61
- total: 100,
62
- count: 5
63
- });
64
-
65
- const success = await hs.upcast(testHolonId, 'stats', 'stat-001', {
66
- operation: 'aggregate'
67
- });
68
-
69
- expect(success).toBe(true);
70
- });
71
-
72
- it('should merge object fields in parent holons', async () => {
73
- await hs.write(testHolonId, 'data', {
74
- id: 'data-001',
75
- values: { a: 1, b: 2 }
76
- });
77
-
78
- await hs.upcast(testHolonId, 'data', 'data-001', {
79
- operation: 'aggregate',
80
- maxLevel: 1
81
- });
82
-
83
- const parents = await hs.getParents(testHolonId);
84
- if (parents.length > 0) {
85
- const parentData = await hs.read(parents[0], 'data');
86
- expect(Array.isArray(parentData)).toBe(true);
87
- }
88
- });
89
-
90
- it('should combine multiple aggregates', async () => {
91
- await hs.write(testHolonId, 'totals', {
92
- id: 't1',
93
- sum: 10,
94
- count: 2
95
- });
96
-
97
- await hs.write(testHolonId, 'totals', {
98
- id: 't2',
99
- sum: 15,
100
- count: 3
101
- });
102
-
103
- await hs.upcast(testHolonId, 'totals', 't1', { operation: 'aggregate' });
104
- await hs.upcast(testHolonId, 'totals', 't2', { operation: 'aggregate' });
105
-
106
- // Parent should have merged aggregates
107
- });
108
- });
109
-
110
- describe('Upcast operation with concatenate mode', () => {
111
- it('should upcast with concatenate operation (default)', async () => {
112
- await hs.write(testHolonId, 'lists', {
113
- id: 'list-001',
114
- items: [1, 2, 3]
115
- });
116
-
117
- const success = await hs.upcast(testHolonId, 'lists', 'list-001', {
118
- operation: 'concatenate'
119
- });
120
-
121
- expect(success).toBe(true);
122
- });
123
-
124
- it('should use concatenate as default operation', async () => {
125
- await hs.write(testHolonId, 'arrays', {
126
- id: 'array-001',
127
- data: ['a', 'b', 'c']
128
- });
129
-
130
- const success = await hs.upcast(testHolonId, 'arrays', 'array-001');
131
-
132
- expect(success).toBe(true);
133
- });
134
-
135
- it('should concatenate arrays in parent holons', async () => {
136
- await hs.write(testHolonId, 'sequences', {
137
- id: 'seq-001',
138
- values: [1, 2]
139
- });
140
-
141
- await hs.upcast(testHolonId, 'sequences', 'seq-001', {
142
- operation: 'concatenate',
143
- maxLevel: 1
144
- });
145
-
146
- const parents = await hs.getParents(testHolonId);
147
- if (parents.length > 0) {
148
- const parentData = await hs.read(parents[0], 'sequences');
149
- expect(Array.isArray(parentData)).toBe(true);
150
- }
151
- });
152
-
153
- it('should handle multiple concatenations', async () => {
154
- await hs.write(testHolonId, 'combined', {
155
- id: 'c1',
156
- items: ['x', 'y']
157
- });
158
-
159
- await hs.write(testHolonId, 'combined', {
160
- id: 'c2',
161
- items: ['z']
162
- });
163
-
164
- await hs.upcast(testHolonId, 'combined', 'c1', { operation: 'concatenate' });
165
- await hs.upcast(testHolonId, 'combined', 'c2', { operation: 'concatenate' });
166
-
167
- // Parent should have concatenated arrays
168
- });
169
- });
170
-
171
- describe('MaxLevel limit enforcement (default: 3 levels)', () => {
172
- it('should respect maxLevel limit', async () => {
173
- await hs.write(testHolonId, 'limited', {
174
- id: 'lim-001',
175
- data: 'test'
176
- });
177
-
178
- const success = await hs.upcast(testHolonId, 'limited', 'lim-001', {
179
- maxLevel: 2
180
- });
181
-
182
- expect(success).toBe(true);
183
- });
184
-
185
- it('should use default maxLevel of 3 when not specified', async () => {
186
- await hs.write(testHolonId, 'default', {
187
- id: 'def-001',
188
- data: 'test'
189
- });
190
-
191
- const success = await hs.upcast(testHolonId, 'default', 'def-001');
192
-
193
- expect(success).toBe(true);
194
- // Should propagate up 3 levels by default
195
- });
196
-
197
- it('should stop at maxLevel', async () => {
198
- await hs.write(testHolonId, 'stop', {
199
- id: 'stop-001',
200
- data: 'test'
201
- });
202
-
203
- await hs.upcast(testHolonId, 'stop', 'stop-001', { maxLevel: 1 });
204
-
205
- const parents = await hs.getParents(testHolonId);
206
-
207
- // Data should be in immediate parent
208
- if (parents.length > 0) {
209
- const parent1Data = await hs.read(parents[0], 'stop');
210
- expect(Array.isArray(parent1Data)).toBe(true);
211
- }
212
-
213
- // Data should NOT be in grandparent (beyond maxLevel)
214
- if (parents.length > 1) {
215
- const parent2Data = await hs.read(parents[1], 'stop');
216
- const hasUpcastData = parent2Data.some(d => d.id === 'stop-001');
217
- expect(hasUpcastData).toBe(false);
218
- }
219
- });
220
-
221
- it('should allow unlimited levels with maxLevel: Infinity', async () => {
222
- await hs.write(testHolonId, 'unlimited', {
223
- id: 'unl-001',
224
- data: 'test'
225
- });
226
-
227
- const success = await hs.upcast(testHolonId, 'unlimited', 'unl-001', {
228
- maxLevel: Infinity
229
- });
230
-
231
- expect(success).toBe(true);
232
- });
233
- });
234
-
235
- describe('Parent hierarchy traversal', () => {
236
- it('should traverse up parent hierarchy', async () => {
237
- await hs.write(testHolonId, 'traverse', {
238
- id: 'trav-001',
239
- data: 'test'
240
- });
241
-
242
- const success = await hs.upcast(testHolonId, 'traverse', 'trav-001', {
243
- maxLevel: 3
244
- });
245
-
246
- expect(success).toBe(true);
247
-
248
- const parents = await hs.getParents(testHolonId);
249
- expect(parents.length).toBeGreaterThan(0);
250
- });
251
-
252
- it('should write to each parent level', async () => {
253
- await hs.write(testHolonId, 'levels', {
254
- id: 'lev-001',
255
- data: 'test'
256
- });
257
-
258
- await hs.upcast(testHolonId, 'levels', 'lev-001', { maxLevel: 2 });
259
-
260
- const parents = await hs.getParents(testHolonId);
261
-
262
- // Check each parent level has data
263
- for (let i = 0; i < Math.min(parents.length, 2); i++) {
264
- const parentData = await hs.read(parents[i], 'levels');
265
- expect(Array.isArray(parentData)).toBe(true);
266
- }
267
- });
268
-
269
- it('should use H3 parent function for traversal', async () => {
270
- const parents = await hs.getParents(testHolonId);
271
-
272
- expect(parents.length).toBeGreaterThan(0);
273
-
274
- // Each parent should be a valid H3 ID
275
- parents.forEach(parent => {
276
- expect(hs.isValidH3(parent)).toBe(true);
277
- });
278
- });
279
- });
280
-
281
- describe('Error: noospheric holons (no spatial hierarchy)', () => {
282
- it('should throw Error for noospheric holon upcast', async () => {
283
- const noospheric = 'nostr://topic/test';
284
-
285
- await hs.write(noospheric, 'content', {
286
- id: 'post-001',
287
- text: 'Test post'
288
- });
289
-
290
- await expect(
291
- hs.upcast(noospheric, 'content', 'post-001')
292
- ).rejects.toThrow(Error);
293
- });
294
-
295
- it('should throw Error for URI-based holons', async () => {
296
- const uriHolon = 'concept://philosophy/ethics';
297
-
298
- await hs.write(uriHolon, 'ideas', {
299
- id: 'idea-001',
300
- text: 'Test idea'
301
- });
302
-
303
- await expect(
304
- hs.upcast(uriHolon, 'ideas', 'idea-001')
305
- ).rejects.toThrow(Error);
306
- });
307
-
308
- it('should throw Error for URL-based holons', async () => {
309
- const urlHolon = 'https://example.com/topic/test';
310
-
311
- await hs.write(urlHolon, 'content', {
312
- id: 'content-001',
313
- data: 'test'
314
- });
315
-
316
- await expect(
317
- hs.upcast(urlHolon, 'content', 'content-001')
318
- ).rejects.toThrow(Error);
319
- });
320
-
321
- it('should work only with geographic (H3) holons', async () => {
322
- const geographic = await hs.toHolon(37.7749, -122.4194, 10);
323
-
324
- await hs.write(geographic, 'geo-data', {
325
- id: 'geo-001',
326
- value: 'test'
327
- });
328
-
329
- await expect(
330
- hs.upcast(geographic, 'geo-data', 'geo-001')
331
- ).resolves.toBe(true);
332
- });
333
- });
334
-
335
- describe('Integration with spatial module', () => {
336
- it('should use spatial module for parent resolution', async () => {
337
- const parents = await hs.getParents(testHolonId);
338
-
339
- expect(parents.length).toBeGreaterThan(0);
340
- parents.forEach(parent => {
341
- expect(hs.isValidH3(parent)).toBe(true);
342
- });
343
- });
344
-
345
- it('should respect H3 hierarchy levels', async () => {
346
- await hs.write(testHolonId, 'h3-test', {
347
- id: 'h3-001',
348
- data: 'test'
349
- });
350
-
351
- await hs.upcast(testHolonId, 'h3-test', 'h3-001', { maxLevel: 2 });
352
-
353
- // Should follow H3 parent-child relationships
354
- const parents = await hs.getParents(testHolonId);
355
- expect(parents.length).toBeGreaterThan(0);
356
- });
357
- });
358
-
359
- describe('Integration with storage module', () => {
360
- it('should write holograms to parent holons', async () => {
361
- await hs.write(testHolonId, 'hologram-test', {
362
- id: 'holo-001',
363
- data: 'test'
364
- });
365
-
366
- await hs.upcast(testHolonId, 'hologram-test', 'holo-001', {
367
- maxLevel: 1
368
- });
369
-
370
- const parents = await hs.getParents(testHolonId);
371
- if (parents.length > 0) {
372
- const parentData = await hs.read(parents[0], 'hologram-test');
373
- expect(Array.isArray(parentData)).toBe(true);
374
- }
375
- });
376
-
377
- it('should create references not copies', async () => {
378
- await hs.write(testHolonId, 'ref-test', {
379
- id: 'ref-001',
380
- value: 'original'
381
- });
382
-
383
- await hs.upcast(testHolonId, 'ref-test', 'ref-001', { maxLevel: 1 });
384
-
385
- // Update original
386
- await hs.update(testHolonId, 'ref-test', 'ref-001', { value: 'updated' });
387
-
388
- // Parent should reflect update (reference, not copy)
389
- const parents = await hs.getParents(testHolonId);
390
- if (parents.length > 0) {
391
- const parentData = await hs.getFederatedData(parents[0], 'ref-test');
392
- const item = parentData.find(d => d.id === 'ref-001');
393
- if (item) {
394
- expect(item.value).toBe('updated');
395
- }
396
- }
397
- });
398
- });
399
- });
@@ -1,74 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Integration: Scenario 1 - Geographic Data Storage and Retrieval', () => {
5
- let hs;
6
-
7
- beforeEach(() => {
8
- hs = new HoloSphere({ relays: [], appName: 'scenario-01' });
9
- });
10
-
11
- it('should complete full geographic storage workflow', async () => {
12
- // Step 1: Convert coordinates to H3 holon at resolution 9 (~1km²)
13
- const sanFrancisco = await hs.toHolon(37.7749, -122.4194, 9);
14
- expect(typeof sanFrancisco).toBe('string');
15
- expect(sanFrancisco).toMatch(/^8[0-9a-f]+$/);
16
-
17
- // Step 2: Store temperature data in "temperature" lens
18
- const success = await hs.write(
19
- sanFrancisco,
20
- 'temperature',
21
- {
22
- id: 'sensor-001',
23
- celsius: 18.5,
24
- timestamp: Date.now(),
25
- source: 'weather-station-1'
26
- }
27
- );
28
- expect(success).toBe(true);
29
-
30
- // Step 3: Retrieve data by location and category
31
- const temp = await hs.read(sanFrancisco, 'temperature', 'sensor-001');
32
- expect(temp).toMatchObject({
33
- id: 'sensor-001',
34
- celsius: 18.5,
35
- source: 'weather-station-1'
36
- });
37
-
38
- // Step 4: Query all temperature data in this holon
39
- const allTemps = await hs.read(sanFrancisco, 'temperature');
40
- expect(Array.isArray(allTemps)).toBe(true);
41
- expect(allTemps.length).toBeGreaterThanOrEqual(1);
42
- expect(allTemps.some(t => t.id === 'sensor-001')).toBe(true);
43
- });
44
-
45
- it('should validate coordinates converted to H3 hexagon', async () => {
46
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
47
- expect(hs.isValidH3(holonId)).toBe(true);
48
- });
49
-
50
- it('should store and retrieve data at specific location with category', async () => {
51
- const holon = await hs.toHolon(40.7128, -74.0060, 9); // New York
52
-
53
- await hs.write(holon, 'events', {
54
- id: 'event-001',
55
- name: 'Concert',
56
- venue: 'Madison Square Garden'
57
- });
58
-
59
- const event = await hs.read(holon, 'events', 'event-001');
60
- expect(event.name).toBe('Concert');
61
- expect(event.venue).toBe('Madison Square Garden');
62
- });
63
-
64
- it('should support multiple data items in same category', async () => {
65
- const holon = await hs.toHolon(37.7749, -122.4194, 9);
66
-
67
- await hs.write(holon, 'temperature', { id: 'sensor-A', celsius: 20 });
68
- await hs.write(holon, 'temperature', { id: 'sensor-B', celsius: 21 });
69
- await hs.write(holon, 'temperature', { id: 'sensor-C', celsius: 19 });
70
-
71
- const all = await hs.read(holon, 'temperature');
72
- expect(all.length).toBeGreaterThanOrEqual(3);
73
- });
74
- });
@@ -1,76 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Integration: Scenario 2 - Hierarchical Federation with Single Source of Truth', () => {
5
- let hs;
6
-
7
- beforeEach(() => {
8
- hs = new HoloSphere({ relays: [], appName: 'scenario-02' });
9
- });
10
-
11
- it('should complete hierarchical federation workflow', async () => {
12
- // Step 1: Create data in local area (resolution 9)
13
- const localHolon = await hs.toHolon(37.7749, -122.4194, 9);
14
- await hs.write(localHolon, 'events', {
15
- id: 'concert-001',
16
- name: 'Jazz Night',
17
- venue: 'Blue Note SF'
18
- });
19
-
20
- // Step 2: Get parent holon (resolution 7 = ~5km² region)
21
- const parents = await hs.getParents(localHolon, 7);
22
- const regionalHolon = parents[0];
23
- expect(typeof regionalHolon).toBe('string');
24
-
25
- // Step 3: Establish federation (local → regional)
26
- const fedSuccess = await hs.federate(localHolon, regionalHolon, 'events', {
27
- direction: 'outbound',
28
- mode: 'reference' // Uses holograms, not copies
29
- });
30
- expect(fedSuccess).toBe(true);
31
-
32
- // Step 4: Query regional holon - sees local data via reference
33
- const regionalEvents = await hs.getFederatedData(regionalHolon, 'events');
34
- expect(Array.isArray(regionalEvents)).toBe(true);
35
- expect(regionalEvents.length).toBeGreaterThanOrEqual(1);
36
- expect(regionalEvents.some(e => e.id === 'concert-001')).toBe(true);
37
-
38
- // Step 5: Update local data
39
- await hs.update(localHolon, 'events', 'concert-001', {
40
- name: 'Jazz Night - SOLD OUT'
41
- });
42
-
43
- // Step 6: Regional view automatically reflects change (single source of truth)
44
- const updatedRegional = await hs.getFederatedData(regionalHolon, 'events');
45
- const updatedEvent = updatedRegional.find(e => e.id === 'concert-001');
46
- expect(updatedEvent.name).toBe('Jazz Night - SOLD OUT');
47
- });
48
-
49
- it('should validate federation uses references (holograms), not copies', async () => {
50
- const local = await hs.toHolon(37.7749, -122.4194, 10);
51
- const parents = await hs.getParents(local);
52
- const regional = parents[0];
53
-
54
- await hs.write(local, 'data', { id: 'item-1', value: 'original' });
55
- await hs.federate(local, regional, 'data', { mode: 'reference' });
56
-
57
- // Update should be reflected immediately
58
- await hs.update(local, 'data', 'item-1', { value: 'updated' });
59
-
60
- const regionalData = await hs.getFederatedData(regional, 'data');
61
- const item = regionalData.find(d => d.id === 'item-1');
62
- expect(item.value).toBe('updated');
63
- });
64
-
65
- it('should validate regional queries include federated local data', async () => {
66
- const local = await hs.toHolon(40.7128, -74.0060, 9);
67
- const parents = await hs.getParents(local);
68
- const regional = parents[0];
69
-
70
- await hs.write(local, 'notes', { id: 'note-1', text: 'Local note' });
71
- await hs.federate(local, regional, 'notes');
72
-
73
- const regionalNotes = await hs.getFederatedData(regional, 'notes');
74
- expect(regionalNotes.some(n => n.id === 'note-1')).toBe(true);
75
- });
76
- });
@@ -1,102 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Integration: Scenario 3 - Real-time Subscriptions', () => {
5
- let hs;
6
-
7
- beforeEach(() => {
8
- hs = new HoloSphere({ relays: [], appName: 'scenario-03' });
9
- });
10
-
11
- it('should complete real-time subscription workflow', async () => {
12
- // Step 1: Subscribe to temperature changes
13
- const holon = await hs.toHolon(37.7749, -122.4194, 9);
14
- const updates = [];
15
-
16
- const subscription = hs.subscribe(holon, 'temperature', (data, key) => {
17
- updates.push({ key, data });
18
- });
19
-
20
- expect(subscription).toHaveProperty('unsubscribe');
21
-
22
- // Step 2: Write new data - subscription fires
23
- await hs.write(holon, 'temperature', {
24
- id: 'sensor-002',
25
- celsius: 19.2
26
- });
27
-
28
- // Wait for async updates
29
- await new Promise(resolve => setTimeout(resolve, 200));
30
-
31
- expect(updates.length).toBeGreaterThanOrEqual(1);
32
-
33
- // Step 3: Update existing data - subscription fires again
34
- await hs.update(holon, 'temperature', 'sensor-002', { celsius: 19.8 });
35
-
36
- await new Promise(resolve => setTimeout(resolve, 200));
37
-
38
- expect(updates.length).toBeGreaterThanOrEqual(2);
39
-
40
- // Step 4: Unsubscribe - no more updates
41
- subscription.unsubscribe();
42
-
43
- const beforeUnsubscribe = updates.length;
44
-
45
- await hs.write(holon, 'temperature', { id: 'sensor-003', celsius: 20.0 });
46
- await new Promise(resolve => setTimeout(resolve, 200));
47
-
48
- expect(updates.length).toBe(beforeUnsubscribe); // No new updates
49
- });
50
-
51
- it('should validate subscriptions receive real-time updates', async () => {
52
- const holon = await hs.toHolon(40.7128, -74.0060, 9);
53
- const callback = vi.fn();
54
-
55
- const sub = hs.subscribe(holon, 'events', callback);
56
-
57
- await hs.write(holon, 'events', { id: 'event-1', name: 'Test Event' });
58
- await new Promise(resolve => setTimeout(resolve, 200));
59
-
60
- expect(callback).toHaveBeenCalled();
61
- sub.unsubscribe();
62
- });
63
-
64
- it('should validate callbacks invoked on data changes', async () => {
65
- const holon = await hs.toHolon(37.7749, -122.4194, 9);
66
- const dataReceived = [];
67
-
68
- const sub = hs.subscribe(holon, 'test', (data) => {
69
- dataReceived.push(data);
70
- });
71
-
72
- await hs.write(holon, 'test', { id: 'item-1', value: 'A' });
73
- await hs.write(holon, 'test', { id: 'item-2', value: 'B' });
74
-
75
- await new Promise(resolve => setTimeout(resolve, 200));
76
-
77
- expect(dataReceived.length).toBeGreaterThanOrEqual(2);
78
- sub.unsubscribe();
79
- });
80
-
81
- it('should validate unsubscribe stops updates', async () => {
82
- const holon = await hs.toHolon(37.7749, -122.4194, 9);
83
- let callCount = 0;
84
-
85
- const sub = hs.subscribe(holon, 'counter', () => {
86
- callCount++;
87
- });
88
-
89
- await hs.write(holon, 'counter', { id: 'c1', value: 1 });
90
- await new Promise(resolve => setTimeout(resolve, 100));
91
-
92
- const countBeforeUnsubscribe = callCount;
93
-
94
- sub.unsubscribe();
95
-
96
- await hs.write(holon, 'counter', { id: 'c2', value: 2 });
97
- await hs.write(holon, 'counter', { id: 'c3', value: 3 });
98
- await new Promise(resolve => setTimeout(resolve, 100));
99
-
100
- expect(callCount).toBe(countBeforeUnsubscribe);
101
- });
102
- });