holosphere 1.1.5 → 1.1.7

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/FEDERATION.md ADDED
@@ -0,0 +1,213 @@
1
+ # HoloSphere Federation
2
+
3
+ HoloSphere's federation system allows different holons (spaces) to share and access data from each other. Federation creates a relationship between spaces that enables data propagation and cross-space access.
4
+
5
+ ## Key Concepts
6
+
7
+ - **Federation Relationship**: A connection between two spaces that allows data to flow between them.
8
+ - **Soul References**: Lightweight references that point to data in its original location (single source of truth).
9
+ - **Notification Flow**: Data notifications flow from source spaces to target spaces that are in the notify list.
10
+ - **Source-Target Relationship**: Each federation sets up a source space (federation list) and a target space (notify list).
11
+
12
+ ## Federation Data Flow
13
+
14
+ The HoloSphere federation system works with a clear source-target relationship:
15
+
16
+ 1. **Federation List**: When space A federates with space B, space A adds B to its federation list.
17
+ 2. **Notify List**: Space B adds space A to its notify list.
18
+ 3. **Data Flow**: When space A changes, space B gets notified (but not vice versa unless bidirectional).
19
+
20
+ ## Creating Federation
21
+
22
+ Create federation relationships between spaces:
23
+
24
+ ```javascript
25
+ // Create federation between space1 and space2
26
+ await holoSphere.federate('space1', 'space2');
27
+
28
+ // This sets up:
29
+ // - space1.federation includes space2
30
+ // - space2.notify includes space1
31
+ ```
32
+
33
+ The bidirectional parameter is largely unused in the current implementation since the federation system naturally sets up the correct notification flow. The default relationship allows space2 to be notified of changes in space1.
34
+
35
+ ## Storing and Propagating Data
36
+
37
+ Data must be explicitly propagated to federated spaces:
38
+
39
+ ```javascript
40
+ const data = {
41
+ id: 'item1',
42
+ title: 'Federation Example',
43
+ value: 42
44
+ };
45
+
46
+ // Store data in space1
47
+ await holoSphere.put('space1', 'items', data);
48
+
49
+ // Propagate to federated spaces
50
+ await holoSphere.propagate('space1', 'items', data);
51
+ ```
52
+
53
+ You can also enable automatic propagation in the `put()` method:
54
+
55
+ ```javascript
56
+ // Store data and automatically propagate
57
+ await holoSphere.put('space1', 'items', data, null, {
58
+ autoPropagate: true
59
+ });
60
+ ```
61
+
62
+ ## Accessing Federated Data
63
+
64
+ ### Direct Retrieval
65
+
66
+ You can access data directly from any space:
67
+
68
+ ```javascript
69
+ // Retrieve data from space2 (will resolve reference if it's a reference)
70
+ const data = await holoSphere.get('space2', 'items', 'item1', null, {
71
+ resolveReferences: true // Default is true
72
+ });
73
+ ```
74
+
75
+ ### Aggregate Federated Data
76
+
77
+ Use `getFederated()` to get data from multiple federated spaces:
78
+
79
+ ```javascript
80
+ // Get combined data from the local space and all its federated spaces
81
+ const federatedData = await holoSphere.getFederated('space2', 'items', {
82
+ resolveReferences: true, // Default: true
83
+ idField: 'id' // Field to use as the unique identifier
84
+ });
85
+ ```
86
+
87
+ ## Soul References
88
+
89
+ HoloSphere uses a simplified reference system based on soul paths:
90
+
91
+ 1. A reference contains only an `id` and a `soul` property
92
+ 2. The soul path is in the format: `appname/holon/lens/key`
93
+ 3. When resolving a reference, HoloSphere follows the soul path to retrieve the original data
94
+
95
+ By default, federation propagation uses references instead of duplicating data. This can be controlled:
96
+
97
+ ```javascript
98
+ // Propagate with full data copy instead of references
99
+ await holoSphere.propagate('space1', 'items', data, {
100
+ useReferences: false
101
+ });
102
+ ```
103
+
104
+ ## Removing Federation
105
+
106
+ ```javascript
107
+ // Remove federation relationship
108
+ await holoSphere.unfederate('space1', 'space2');
109
+ ```
110
+
111
+ ## Complete Example
112
+
113
+ Here's a complete example showing the proper way to set up and use federation:
114
+
115
+ ```javascript
116
+ import HoloSphere from './holosphere.js';
117
+
118
+ async function federationExample() {
119
+ const holoSphere = new HoloSphere('example-app');
120
+
121
+ try {
122
+ const space1 = 'public-space1';
123
+ const space2 = 'public-space2';
124
+
125
+ // Step 1: Create federation relationship
126
+ await holoSphere.federate(space1, space2);
127
+
128
+ // Step 2: Verify federation is set up properly
129
+ const fedInfo1 = await holoSphere.getFederation(space1);
130
+ const fedInfo2 = await holoSphere.getFederation(space2);
131
+
132
+ console.log(`Federation info for ${space1}:`, fedInfo1);
133
+ // Should include: federation: ['space2']
134
+
135
+ console.log(`Federation info for ${space2}:`, fedInfo2);
136
+ // Should include: notify: ['space1']
137
+
138
+ // Step 3: Store data in space1
139
+ const item = {
140
+ id: 'item1',
141
+ title: 'Federation Test',
142
+ value: 42
143
+ };
144
+
145
+ await holoSphere.put(space1, 'items', item);
146
+
147
+ // Step 4: Propagate data to federated spaces
148
+ await holoSphere.propagate(space1, 'items', item);
149
+
150
+ // Allow time for propagation
151
+ await new Promise(resolve => setTimeout(resolve, 1000));
152
+
153
+ // Step 5: Access data from space2 (resolves reference)
154
+ const itemFromSpace2 = await holoSphere.get(space2, 'items', 'item1');
155
+ console.log('Item from space2:', itemFromSpace2);
156
+
157
+ // Step 6: Update item in space1
158
+ const updatedItem = {
159
+ ...item,
160
+ value: 100,
161
+ updated: true
162
+ };
163
+
164
+ await holoSphere.put(space1, 'items', updatedItem);
165
+
166
+ // Since we're using soul references, the update is immediately visible
167
+ // through the reference without needing to propagate again
168
+
169
+ // Verify update is visible through the reference
170
+ const updatedItemFromSpace2 = await holoSphere.get(space2, 'items', 'item1');
171
+ console.log('Updated item from space2:', updatedItemFromSpace2);
172
+
173
+ // Step 7: Clean up
174
+ await holoSphere.unfederate(space1, space2);
175
+ } finally {
176
+ // Always close the HoloSphere instance
177
+ await holoSphere.close();
178
+ }
179
+ }
180
+
181
+ federationExample().catch(console.error);
182
+ ```
183
+
184
+ ## Troubleshooting
185
+
186
+ ### Common Issues
187
+
188
+ 1. **Federation Relationship**: Make sure to check both the federation list and notify list to understand data flow.
189
+
190
+ 2. **Data Propagation**: If data isn't appearing in federated spaces, check:
191
+ - The federation relationship was created correctly
192
+ - The data was propagated explicitly or `autoPropagate` was set to `true`
193
+ - The notify list includes the target space
194
+
195
+ 3. **Reference Resolution**: If you're getting reference objects instead of the actual data:
196
+ - Make sure `resolveReferences` is set to `true` (it's the default)
197
+ - Check that the original data still exists at the referenced location
198
+
199
+ 4. **Timing Issues**: Data propagation is asynchronous. Add small delays (500-1000ms) between operations to allow propagation to complete.
200
+
201
+ ### Best Practices
202
+
203
+ 1. **Verify Federation Structure**: After creating a federation, check both spaces to ensure:
204
+ - Source space has the target in its federation list
205
+ - Target space has the source in its notify list
206
+
207
+ 2. **Explicit Propagation**: Unless you're using `autoPropagate`, always call `propagate()` explicitly after storing data that should be shared.
208
+
209
+ 3. **Choose the Right Propagation Method**:
210
+ - Use `useReferences: true` (default) to keep a single source of truth
211
+ - Use `useReferences: false` only when you need independent copies
212
+
213
+ 4. **Cleanup**: Always close the HoloSphere instance when done to prevent resource leaks.
package/README.md CHANGED
@@ -329,3 +329,143 @@ Data in HoloSphere is organized by:
329
329
 
330
330
  GPL-3.0-or-later
331
331
 
332
+ # HoloSphere Federation
333
+
334
+ HoloSphere provides a federation system that allows spaces to share data and messages across different holons. This document outlines the federation functionality and how to use it.
335
+
336
+ ## Core Federation Features
337
+
338
+ ### Space Federation
339
+ - Create relationships between spaces with clear source-target connections
340
+ - Use soul references to maintain a single source of truth
341
+ - Control data propagation between federated spaces
342
+ - Manage notification settings for each space
343
+
344
+ ### Message Federation
345
+ - Track messages across federated spaces
346
+ - Maintain message relationships between original and federated copies
347
+ - Update messages consistently across all federated spaces
348
+
349
+ ## API Reference
350
+
351
+ ### Space Federation
352
+
353
+ #### `federate(spaceId1, spaceId2, password1, password2, bidirectional)`
354
+ Creates a federation relationship between two spaces.
355
+
356
+ ```javascript
357
+ await holosphere.federate('space1', 'space2', 'pass1', 'pass2');
358
+ ```
359
+
360
+ This sets up:
361
+ - space1.federation includes space2
362
+ - space2.notify includes space1
363
+
364
+ Parameters:
365
+ - `spaceId1`: First space ID (source space)
366
+ - `spaceId2`: Second space ID (target space)
367
+ - `password1`: Optional password for first space
368
+ - `password2`: Optional password for second space
369
+ - `bidirectional`: Whether to set up bidirectional notifications (default: true, but generally not needed)
370
+
371
+ ### Data Propagation
372
+
373
+ #### `propagate(holon, lens, data, options)`
374
+ Propagates data to federated spaces.
375
+
376
+ ```javascript
377
+ await holosphere.propagate('space1', 'items', data, {
378
+ useReferences: true, // Default: uses soul references
379
+ targetSpaces: ['space2'] // Optional: specific targets
380
+ });
381
+ ```
382
+
383
+ Parameters:
384
+ - `holon`: The holon identifier
385
+ - `lens`: The lens identifier
386
+ - `data`: The data to propagate
387
+ - `options`: Propagation options
388
+
389
+ Alternatively, you can use auto-propagation:
390
+
391
+ ```javascript
392
+ await holosphere.put('space1', 'items', data, null, {
393
+ autoPropagate: true // Enable auto-propagation
394
+ });
395
+ ```
396
+
397
+ ### Message Federation
398
+
399
+ #### `federateMessage(originalChatId, messageId, federatedChatId, federatedMessageId, type)`
400
+ Tracks a federated message across different chats.
401
+
402
+ ```javascript
403
+ await holosphere.federateMessage('chat1', 'msg1', 'chat2', 'msg2', 'quest');
404
+ ```
405
+
406
+ #### `getFederatedMessages(originalChatId, messageId)`
407
+ Gets all federated messages for a given original message.
408
+
409
+ ```javascript
410
+ const messages = await holosphere.getFederatedMessages('chat1', 'msg1');
411
+ ```
412
+
413
+ #### `updateFederatedMessages(originalChatId, messageId, updateCallback)`
414
+ Updates a message across all federated chats.
415
+
416
+ ```javascript
417
+ await holosphere.updateFederatedMessages('chat1', 'msg1', async (chatId, messageId) => {
418
+ // Update message in this chat
419
+ });
420
+ ```
421
+
422
+ ## Usage Example
423
+
424
+ ```javascript
425
+ // Create federation between spaces
426
+ await holosphere.federate('space1', 'space2');
427
+
428
+ // Store data in space1
429
+ const data = { id: 'item1', value: 42 };
430
+ await holosphere.put('space1', 'items', data);
431
+
432
+ // Propagate to federated spaces
433
+ await holosphere.propagate('space1', 'items', data);
434
+
435
+ // Retrieve data from space2 (will resolve the reference)
436
+ const item = await holosphere.get('space2', 'items', 'item1');
437
+
438
+ // Track a federated message
439
+ await holosphere.federateMessage('chat1', 'msg1', 'chat2', 'msg2', 'quest');
440
+
441
+ // Update message across all federated chats
442
+ await holosphere.updateFederatedMessages('chat1', 'msg1', async (chatId, messageId) => {
443
+ await updateMessageInChat(chatId, messageId);
444
+ });
445
+ ```
446
+
447
+ ## Soul References
448
+
449
+ When using the default `useReferences: true` with propagation:
450
+
451
+ 1. Only a lightweight reference is stored in the federated space
452
+ 2. The reference contains the original item's ID and soul path
453
+ 3. When accessed, the reference is automatically resolved to the original data
454
+ 4. Changes to the original data are immediately visible through references
455
+
456
+ This maintains a single source of truth while keeping storage efficient.
457
+
458
+ ## Federation Structure
459
+
460
+ The federation system uses two key arrays to manage relationships:
461
+
462
+ ```javascript
463
+ {
464
+ id: string,
465
+ name: string,
466
+ federation: string[], // Source spaces this holon federates with
467
+ notify: string[], // Target spaces to notify of changes
468
+ timestamp: number
469
+ }
470
+ ```
471
+
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ presets: [
3
+ ['@babel/preset-env', {targets: {node: 'current'}}],
4
+ ],
5
+ };
@@ -0,0 +1,158 @@
1
+ # HoloSphere Environmental Data Examples
2
+
3
+ This directory contains examples demonstrating how to use HoloSphere for storing, federating, and querying environmental data across different geographical scales.
4
+
5
+ ## Overview
6
+
7
+ The examples show how to:
8
+
9
+ 1. Store environmental data from various APIs into hierarchical holons
10
+ 2. Create federation relationships between holons at different scales
11
+ 3. Use soul references to efficiently share data between holons
12
+ 4. Query environmental data, including resolving federation references
13
+ 5. Compute aggregated metrics across holons
14
+
15
+ ## Files
16
+
17
+ - `environmentalData.js` - Shows how to fetch, transform and store environmental data in HoloSphere
18
+ - `queryEnvironmentalData.js` - Demonstrates how to query the stored data across federated holons
19
+
20
+ ## Environmental Data Structure
21
+
22
+ The examples organize environmental data into a hierarchical structure:
23
+
24
+ - **City level (H3 resolution 7)**: Air quality data
25
+ - **Region level (H3 resolution 5)**: Carbon sequestration and soil data
26
+ - **Country level (H3 resolution 3)**: Biodiversity data
27
+
28
+ Federation relationships are established between these levels, allowing data to flow from smaller to larger scales while maintaining a single source of truth through soul references.
29
+
30
+ ## Data Schemas
31
+
32
+ The examples define several schemas for environmental data:
33
+
34
+ ### Air Quality Schema
35
+ ```json
36
+ {
37
+ "id": "string",
38
+ "holon": "string",
39
+ "timestamp": "number",
40
+ "coordinates": {
41
+ "lat": "number",
42
+ "lon": "number"
43
+ },
44
+ "airQualityIndex": "number",
45
+ "pollutants": {
46
+ "co": "number",
47
+ "no2": "number",
48
+ "o3": "number",
49
+ "pm2_5": "number",
50
+ "pm10": "number",
51
+ "so2": "number"
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Carbon Sequestration Schema
57
+ ```json
58
+ {
59
+ "id": "string",
60
+ "holon": "string",
61
+ "timestamp": "number",
62
+ "coordinates": {
63
+ "lat": "number",
64
+ "lon": "number"
65
+ },
66
+ "carbonSequestration": "number",
67
+ "temperature": "number",
68
+ "precipitation": "number"
69
+ }
70
+ ```
71
+
72
+ ### Soil Carbon Schema
73
+ ```json
74
+ {
75
+ "id": "string",
76
+ "holon": "string",
77
+ "timestamp": "number",
78
+ "coordinates": {
79
+ "lat": "number",
80
+ "lon": "number"
81
+ },
82
+ "soilCarbon": "number",
83
+ "soilType": "string",
84
+ "soilDepth": "string"
85
+ }
86
+ ```
87
+
88
+ ### Biodiversity Schema
89
+ ```json
90
+ {
91
+ "id": "string",
92
+ "holon": "string",
93
+ "timestamp": "number",
94
+ "countryCode": "string",
95
+ "biodiversityCount": "number",
96
+ "species": [
97
+ {
98
+ "scientificName": "string",
99
+ "count": "number"
100
+ }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ ## Running the Examples
106
+
107
+ 1. Make sure you have all required API keys in your `.env` file:
108
+ - `OPENWEATHER_API_KEY` - For air quality data
109
+ - `NOAA_API_KEY` - For climate data
110
+
111
+ 2. Run the data storage example:
112
+ ```
113
+ node examples/environmentalData.js
114
+ ```
115
+
116
+ 3. Run the query example:
117
+ ```
118
+ node examples/queryEnvironmentalData.js
119
+ ```
120
+
121
+ ## Federation in Practice
122
+
123
+ These examples demonstrate several key federation concepts:
124
+
125
+ 1. **Hierarchical Data Organization**: Environmental data is organized by geographical scale, with relationships between scales.
126
+
127
+ 2. **Soul References**: When propagating data from city to region level, soul references are used instead of duplicating data.
128
+
129
+ 3. **Automatic Reference Resolution**: When querying data, references are automatically resolved to their original source.
130
+
131
+ 4. **Cross-Scale Aggregation**: The compute function is used to aggregate metrics from different scales.
132
+
133
+ ## Example Output
134
+
135
+ Running the query example should produce output similar to:
136
+
137
+ ```
138
+ Querying environmental data for location (41.9, 12.5)
139
+ - City: 8773237a267ffff
140
+ - Region: 852e3ffffffffffffff
141
+ - Country: 832ffffffffffffffff
142
+
143
+ === CITY LEVEL: Air Quality Data ===
144
+ Latest Air Quality Index: 2
145
+ Pollutant levels:
146
+ - co: 201.94
147
+ - no2: 0.78
148
+ - o3: 68.64
149
+ - pm2_5: 0.5
150
+ - pm10: 0.82
151
+ - so2: 0.52
152
+
153
+ === REGION LEVEL: Soil Carbon Data ===
154
+ Soil Carbon: 78.4 g/kg
155
+ Soil Type: Clay Loam
156
+ Soil Depth: 0-30cm
157
+
158
+ ...