holosphere 1.1.6 → 1.1.8
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 +108 -160
- package/README.md +140 -0
- package/examples/federation.js +154 -0
- package/examples/references.js +177 -0
- package/federation.js +637 -372
- package/holosphere.d.ts +445 -20
- package/holosphere.js +343 -126
- package/package.json +1 -4
- package/test/delete.test.js +225 -0
- package/test/federation.test.js +50 -2
- package/config/default.js +0 -1
- package/services/environmentalApi.js +0 -253
- package/services/environmentalApitest.js +0 -164
- package/test/ai.test.js +0 -425
- package/test/sea.html +0 -33
- /package/test/{holonauth.test.js → auth.test.js} +0 -0
package/FEDERATION.md
CHANGED
|
@@ -1,143 +1,111 @@
|
|
|
1
1
|
# HoloSphere Federation
|
|
2
2
|
|
|
3
|
-
|
|
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
4
|
|
|
5
|
-
##
|
|
5
|
+
## Key Concepts
|
|
6
6
|
|
|
7
|
-
Federation
|
|
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).
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
- Propagating data across these networks
|
|
11
|
-
- Subscribing to changes in federated spaces
|
|
12
|
+
## Federation Data Flow
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
The HoloSphere federation system works with a clear source-target relationship:
|
|
14
15
|
|
|
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).
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
## Creating Federation
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
Create federation relationships between spaces:
|
|
20
23
|
|
|
21
24
|
```javascript
|
|
22
|
-
//
|
|
25
|
+
// Create federation between space1 and space2
|
|
23
26
|
await holoSphere.federate('space1', 'space2');
|
|
24
27
|
|
|
25
|
-
//
|
|
26
|
-
|
|
28
|
+
// This sets up:
|
|
29
|
+
// - space1.federation includes space2
|
|
30
|
+
// - space2.notify includes space1
|
|
27
31
|
```
|
|
28
32
|
|
|
29
|
-
|
|
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.
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
## Storing and Propagating Data
|
|
36
|
+
|
|
37
|
+
Data must be explicitly propagated to federated spaces:
|
|
32
38
|
|
|
33
39
|
```javascript
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (!fedSettings1.notify.includes('space2')) {
|
|
40
|
-
fedSettings1.notify.push('space2');
|
|
41
|
-
}
|
|
42
|
-
// 3. Save updated settings
|
|
43
|
-
await holoSphere.putGlobal('federation', fedSettings1);
|
|
44
|
-
}
|
|
40
|
+
const data = {
|
|
41
|
+
id: 'item1',
|
|
42
|
+
title: 'Federation Example',
|
|
43
|
+
value: 42
|
|
44
|
+
};
|
|
45
45
|
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
if (fedSettings2) {
|
|
49
|
-
fedSettings2.notify = fedSettings2.notify || [];
|
|
50
|
-
if (!fedSettings2.notify.includes('space1')) {
|
|
51
|
-
fedSettings2.notify.push('space1');
|
|
52
|
-
}
|
|
53
|
-
await holoSphere.putGlobal('federation', fedSettings2);
|
|
54
|
-
}
|
|
55
|
-
```
|
|
46
|
+
// Store data in space1
|
|
47
|
+
await holoSphere.put('space1', 'items', data);
|
|
56
48
|
|
|
57
|
-
|
|
49
|
+
// Propagate to federated spaces
|
|
50
|
+
await holoSphere.propagate('space1', 'items', data);
|
|
51
|
+
```
|
|
58
52
|
|
|
59
|
-
|
|
53
|
+
You can also enable automatic propagation in the `put()` method:
|
|
60
54
|
|
|
61
55
|
```javascript
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const fedInfo = await holoSphere.getFederation('space1', 'password1');
|
|
56
|
+
// Store data and automatically propagate
|
|
57
|
+
await holoSphere.put('space1', 'items', data, null, {
|
|
58
|
+
autoPropagate: true
|
|
59
|
+
});
|
|
67
60
|
```
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
- `id`: The space ID
|
|
71
|
-
- `name`: The space name
|
|
72
|
-
- `federation`: Array of space IDs that this space is federated with
|
|
73
|
-
- `notify`: Array of space IDs that this space will propagate data to
|
|
62
|
+
## Accessing Federated Data
|
|
74
63
|
|
|
75
|
-
###
|
|
64
|
+
### Direct Retrieval
|
|
76
65
|
|
|
77
|
-
|
|
66
|
+
You can access data directly from any space:
|
|
78
67
|
|
|
79
68
|
```javascript
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// 2. Explicitly propagate to federated spaces
|
|
86
|
-
await holoSphere.propagateToFederation('space1', 'items', data);
|
|
87
|
-
|
|
88
|
-
// 3. (Optional) Add a short delay to ensure propagation completes
|
|
89
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
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
|
+
});
|
|
90
73
|
```
|
|
91
74
|
|
|
92
|
-
###
|
|
75
|
+
### Aggregate Federated Data
|
|
93
76
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
#### Method 1: Using getFederated (Recommended)
|
|
97
|
-
|
|
98
|
-
This retrieves data from both the local space and all federated spaces:
|
|
77
|
+
Use `getFederated()` to get data from multiple federated spaces:
|
|
99
78
|
|
|
100
79
|
```javascript
|
|
101
|
-
// Get
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
//
|
|
105
|
-
|
|
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
|
+
});
|
|
106
85
|
```
|
|
107
86
|
|
|
108
|
-
|
|
87
|
+
## Soul References
|
|
109
88
|
|
|
110
|
-
|
|
89
|
+
HoloSphere uses a simplified reference system based on soul paths:
|
|
111
90
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Subscribing to Federation Changes
|
|
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
|
|
118
94
|
|
|
119
|
-
|
|
95
|
+
By default, federation propagation uses references instead of duplicating data. This can be controlled:
|
|
120
96
|
|
|
121
97
|
```javascript
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
98
|
+
// Propagate with full data copy instead of references
|
|
99
|
+
await holoSphere.propagate('space1', 'items', data, {
|
|
100
|
+
useReferences: false
|
|
125
101
|
});
|
|
126
|
-
|
|
127
|
-
// Later, unsubscribe
|
|
128
|
-
subscription.unsubscribe();
|
|
129
102
|
```
|
|
130
103
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
To remove a federation between two spaces:
|
|
104
|
+
## Removing Federation
|
|
134
105
|
|
|
135
106
|
```javascript
|
|
136
|
-
//
|
|
107
|
+
// Remove federation relationship
|
|
137
108
|
await holoSphere.unfederate('space1', 'space2');
|
|
138
|
-
|
|
139
|
-
// Private federation
|
|
140
|
-
await holoSphere.unfederate('space1', 'space2', 'password1', 'password2');
|
|
141
109
|
```
|
|
142
110
|
|
|
143
111
|
## Complete Example
|
|
@@ -154,61 +122,55 @@ async function federationExample() {
|
|
|
154
122
|
const space1 = 'public-space1';
|
|
155
123
|
const space2 = 'public-space2';
|
|
156
124
|
|
|
157
|
-
// Step 1: Create federation
|
|
125
|
+
// Step 1: Create federation relationship
|
|
158
126
|
await holoSphere.federate(space1, space2);
|
|
159
127
|
|
|
160
|
-
// Step 2:
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
fedSettings1.notify = fedSettings1.notify || [];
|
|
164
|
-
if (!fedSettings1.notify.includes(space2)) {
|
|
165
|
-
fedSettings1.notify.push(space2);
|
|
166
|
-
await holoSphere.putGlobal('federation', fedSettings1);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
128
|
+
// Step 2: Verify federation is set up properly
|
|
129
|
+
const fedInfo1 = await holoSphere.getFederation(space1);
|
|
130
|
+
const fedInfo2 = await holoSphere.getFederation(space2);
|
|
169
131
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
fedSettings2.notify = fedSettings2.notify || [];
|
|
173
|
-
if (!fedSettings2.notify.includes(space1)) {
|
|
174
|
-
fedSettings2.notify.push(space1);
|
|
175
|
-
await holoSphere.putGlobal('federation', fedSettings2);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
132
|
+
console.log(`Federation info for ${space1}:`, fedInfo1);
|
|
133
|
+
// Should include: federation: ['space2']
|
|
178
134
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
console.log(`Federation info for ${space1}:`, updatedFedInfo);
|
|
135
|
+
console.log(`Federation info for ${space2}:`, fedInfo2);
|
|
136
|
+
// Should include: notify: ['space1']
|
|
182
137
|
|
|
183
|
-
// Step
|
|
138
|
+
// Step 3: Store data in space1
|
|
184
139
|
const item = {
|
|
185
140
|
id: 'item1',
|
|
186
141
|
title: 'Federation Test',
|
|
187
142
|
value: 42
|
|
188
143
|
};
|
|
144
|
+
|
|
189
145
|
await holoSphere.put(space1, 'items', item);
|
|
190
146
|
|
|
191
|
-
// Step
|
|
192
|
-
await holoSphere.
|
|
147
|
+
// Step 4: Propagate data to federated spaces
|
|
148
|
+
await holoSphere.propagate(space1, 'items', item);
|
|
193
149
|
|
|
194
|
-
//
|
|
150
|
+
// Allow time for propagation
|
|
195
151
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
196
152
|
|
|
197
|
-
// Step
|
|
198
|
-
const
|
|
199
|
-
console.log('Item from
|
|
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);
|
|
200
165
|
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
const federatedData = await holoSphere.getFederated(space2, 'items');
|
|
204
|
-
const itemFromFederation = federatedData.find(item => item.id === 'item1');
|
|
205
|
-
console.log('Item from federation:', itemFromFederation);
|
|
166
|
+
// Since we're using soul references, the update is immediately visible
|
|
167
|
+
// through the reference without needing to propagate again
|
|
206
168
|
|
|
207
|
-
//
|
|
208
|
-
const
|
|
209
|
-
console.log('
|
|
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);
|
|
210
172
|
|
|
211
|
-
// Step
|
|
173
|
+
// Step 7: Clean up
|
|
212
174
|
await holoSphere.unfederate(space1, space2);
|
|
213
175
|
} finally {
|
|
214
176
|
// Always close the HoloSphere instance
|
|
@@ -219,47 +181,33 @@ async function federationExample() {
|
|
|
219
181
|
federationExample().catch(console.error);
|
|
220
182
|
```
|
|
221
183
|
|
|
222
|
-
## Running the Tests
|
|
223
|
-
|
|
224
|
-
HoloSphere includes test scripts to verify federation functionality:
|
|
225
|
-
|
|
226
|
-
### Public Federation Tests
|
|
227
|
-
|
|
228
|
-
Run the public federation tests with:
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
node test-federation.js
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
This tests:
|
|
235
|
-
- Creating public federations
|
|
236
|
-
- Storing and retrieving data
|
|
237
|
-
- Propagating data to federated spaces
|
|
238
|
-
- Subscribing to federation changes
|
|
239
|
-
- Removing federations
|
|
240
|
-
|
|
241
184
|
## Troubleshooting
|
|
242
185
|
|
|
243
186
|
### Common Issues
|
|
244
187
|
|
|
245
|
-
1. **
|
|
188
|
+
1. **Federation Relationship**: Make sure to check both the federation list and notify list to understand data flow.
|
|
246
189
|
|
|
247
|
-
2. **
|
|
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
|
|
248
194
|
|
|
249
|
-
3. **
|
|
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
|
|
250
198
|
|
|
251
199
|
4. **Timing Issues**: Data propagation is asynchronous. Add small delays (500-1000ms) between operations to allow propagation to complete.
|
|
252
200
|
|
|
253
|
-
5. **Missing Federation Metadata**: After propagation, federated items should have a `federation` property containing the origin space and timestamp.
|
|
254
|
-
|
|
255
201
|
### Best Practices
|
|
256
202
|
|
|
257
|
-
1. **Verify Federation
|
|
258
|
-
|
|
259
|
-
|
|
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
|
|
260
206
|
|
|
261
|
-
|
|
207
|
+
2. **Explicit Propagation**: Unless you're using `autoPropagate`, always call `propagate()` explicitly after storing data that should be shared.
|
|
262
208
|
|
|
263
|
-
|
|
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
|
|
264
212
|
|
|
265
|
-
|
|
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,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Organization Federation Example for HoloSphere
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates a real-world use case where a tech team creates tasks
|
|
5
|
+
* that are federated to the parent organization for visibility.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import HoloSphere from './holosphere.js';
|
|
9
|
+
|
|
10
|
+
async function organizationFederationExample() {
|
|
11
|
+
const holoSphere = new HoloSphere('organization-example');
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
console.log('Starting Organization Federation Example...');
|
|
15
|
+
|
|
16
|
+
// Define our spaces/holons
|
|
17
|
+
const orgHolon = 'acme-organization';
|
|
18
|
+
const techTeamHolon = 'acme-tech-team';
|
|
19
|
+
|
|
20
|
+
// Step 1: Create federation relationship between tech team and organization
|
|
21
|
+
console.log('\nStep 1: Creating federation relationship...');
|
|
22
|
+
|
|
23
|
+
await holoSphere.federate(techTeamHolon, orgHolon);
|
|
24
|
+
console.log('Federation created between tech team and organization');
|
|
25
|
+
|
|
26
|
+
// Step 2: Set up bidirectional notification settings (critical!)
|
|
27
|
+
console.log('\nStep 2: Setting up bidirectional notification...');
|
|
28
|
+
|
|
29
|
+
// First set up tech team to notify organization
|
|
30
|
+
const techTeamFedSettings = await holoSphere.getGlobal('federation', techTeamHolon);
|
|
31
|
+
if (techTeamFedSettings) {
|
|
32
|
+
techTeamFedSettings.notify = techTeamFedSettings.notify || [];
|
|
33
|
+
if (!techTeamFedSettings.notify.includes(orgHolon)) {
|
|
34
|
+
techTeamFedSettings.notify.push(orgHolon);
|
|
35
|
+
await holoSphere.putGlobal('federation', techTeamFedSettings);
|
|
36
|
+
console.log('Tech team set to notify organization');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Then set up organization to notify tech team (if needed)
|
|
41
|
+
const orgFedSettings = await holoSphere.getGlobal('federation', orgHolon);
|
|
42
|
+
if (orgFedSettings) {
|
|
43
|
+
orgFedSettings.notify = orgFedSettings.notify || [];
|
|
44
|
+
if (!orgFedSettings.notify.includes(techTeamHolon)) {
|
|
45
|
+
orgFedSettings.notify.push(techTeamHolon);
|
|
46
|
+
await holoSphere.putGlobal('federation', orgFedSettings);
|
|
47
|
+
console.log('Organization set to notify tech team');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Step 3: Verify federation is set up properly
|
|
52
|
+
console.log('\nStep 3: Verifying federation setup...');
|
|
53
|
+
|
|
54
|
+
const techTeamFedInfo = await holoSphere.getFederation(techTeamHolon);
|
|
55
|
+
console.log('Tech team federation info:', techTeamFedInfo);
|
|
56
|
+
|
|
57
|
+
// Step 4: Create a task in the tech team holon
|
|
58
|
+
console.log('\nStep 4: Creating a task in the tech team holon...');
|
|
59
|
+
|
|
60
|
+
const task = {
|
|
61
|
+
id: 'task-123',
|
|
62
|
+
title: 'Implement new authentication system',
|
|
63
|
+
description: 'Replace the current auth system with OAuth2',
|
|
64
|
+
assignee: 'dev@example.com',
|
|
65
|
+
status: 'in_progress',
|
|
66
|
+
priority: 'high',
|
|
67
|
+
dueDate: '2023-12-31',
|
|
68
|
+
createdAt: new Date().toISOString(),
|
|
69
|
+
tags: ['security', 'infrastructure']
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Store the task in the tech team holon
|
|
73
|
+
await holoSphere.put(techTeamHolon, 'tasks', task);
|
|
74
|
+
console.log('Task created in tech team holon:', task.id);
|
|
75
|
+
|
|
76
|
+
// Step 5: Propagate the task to the organization holon
|
|
77
|
+
console.log('\nStep 5: Propagating task to organization holon...');
|
|
78
|
+
|
|
79
|
+
await holoSphere.propagate(techTeamHolon, 'tasks', task);
|
|
80
|
+
console.log('Task propagated to organization holon');
|
|
81
|
+
|
|
82
|
+
// Step 6: Allow time for propagation
|
|
83
|
+
console.log('\nStep 6: Waiting for propagation to complete...');
|
|
84
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
85
|
+
|
|
86
|
+
// Step 7: Verify task in both holons
|
|
87
|
+
console.log('\nStep 7: Verifying task is in both holons...');
|
|
88
|
+
|
|
89
|
+
// Check tech team holon directly
|
|
90
|
+
const techTeamTask = await holoSphere.get(techTeamHolon, 'tasks', 'task-123');
|
|
91
|
+
console.log('Task in tech team holon:', techTeamTask ? 'Found' : 'Not found');
|
|
92
|
+
if (techTeamTask) console.log('Tech team task status:', techTeamTask.status);
|
|
93
|
+
|
|
94
|
+
// Check organization holon directly
|
|
95
|
+
const orgTask = await holoSphere.get(orgHolon, 'tasks', 'task-123');
|
|
96
|
+
console.log('Task in organization holon:', orgTask ? 'Found' : 'Not found');
|
|
97
|
+
if (orgTask) {
|
|
98
|
+
console.log('Organization task status:', orgTask.status);
|
|
99
|
+
console.log('Federation metadata:', orgTask.federation);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Step 8: Use getFederated to view all tasks across holons
|
|
103
|
+
console.log('\nStep 8: Using getFederated to view all tasks...');
|
|
104
|
+
|
|
105
|
+
const allOrgTasks = await holoSphere.getFederated(orgHolon, 'tasks');
|
|
106
|
+
console.log(`Organization holon has access to ${allOrgTasks.length} tasks`);
|
|
107
|
+
|
|
108
|
+
const allTechTasks = await holoSphere.getFederated(techTeamHolon, 'tasks');
|
|
109
|
+
console.log(`Tech team holon has access to ${allTechTasks.length} tasks`);
|
|
110
|
+
|
|
111
|
+
// Step 9: Update the task in tech team and propagate the change
|
|
112
|
+
console.log('\nStep 9: Updating task in tech team holon...');
|
|
113
|
+
|
|
114
|
+
const updatedTask = {
|
|
115
|
+
...task,
|
|
116
|
+
status: 'completed',
|
|
117
|
+
completedAt: new Date().toISOString()
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
await holoSphere.put(techTeamHolon, 'tasks', updatedTask);
|
|
121
|
+
await holoSphere.propagate(techTeamHolon, 'tasks', updatedTask);
|
|
122
|
+
console.log('Task updated and propagated');
|
|
123
|
+
|
|
124
|
+
// Step 10: Allow time for propagation
|
|
125
|
+
console.log('\nStep 10: Waiting for propagation to complete...');
|
|
126
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
127
|
+
|
|
128
|
+
// Step 11: Verify updates in both holons
|
|
129
|
+
console.log('\nStep 11: Verifying updated task in both holons...');
|
|
130
|
+
|
|
131
|
+
const updatedTechTeamTask = await holoSphere.get(techTeamHolon, 'tasks', 'task-123');
|
|
132
|
+
console.log('Updated task in tech team holon status:', updatedTechTeamTask?.status);
|
|
133
|
+
|
|
134
|
+
const updatedOrgTask = await holoSphere.get(orgHolon, 'tasks', 'task-123');
|
|
135
|
+
console.log('Updated task in organization holon status:', updatedOrgTask?.status);
|
|
136
|
+
|
|
137
|
+
// Step 12: Clean up - remove federation
|
|
138
|
+
console.log('\nStep 12: Cleaning up - removing federation...');
|
|
139
|
+
|
|
140
|
+
await holoSphere.unfederate(techTeamHolon, orgHolon);
|
|
141
|
+
console.log('Federation removed between tech team and organization');
|
|
142
|
+
|
|
143
|
+
console.log('\nOrganization federation example completed successfully!');
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('Error in organization federation example:', error);
|
|
146
|
+
} finally {
|
|
147
|
+
// Always close the HoloSphere instance
|
|
148
|
+
await holoSphere.close();
|
|
149
|
+
console.log('HoloSphere instance closed');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Run the example
|
|
154
|
+
organizationFederationExample().catch(console.error);
|