holosphere 1.1.5 → 1.1.6
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 +265 -0
- package/babel.config.js +5 -0
- package/federation.js +723 -0
- package/holosphere.js +855 -987
- package/package.json +3 -6
- package/test/ai.test.js +268 -76
- package/test/federation.test.js +115 -356
- package/test/holonauth.test.js +241 -0
- package/test/holosphere.test.js +109 -955
- package/test/sea.html +33 -0
- package/test/jest.setup.js +0 -5
- package/test/spacesauth.test.js +0 -335
- /package/services/{environmentalApi.test.js → environmentalApitest.js} +0 -0
package/FEDERATION.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# HoloSphere Federation
|
|
2
|
+
|
|
3
|
+
This document explains how to use the federation functionality in HoloSphere, which allows different spaces to share data with each other.
|
|
4
|
+
|
|
5
|
+
## What is Federation?
|
|
6
|
+
|
|
7
|
+
Federation in HoloSphere allows different spaces (data stores) to connect and share data with each other. This enables:
|
|
8
|
+
|
|
9
|
+
- Creating networks of connected spaces
|
|
10
|
+
- Propagating data across these networks
|
|
11
|
+
- Subscribing to changes in federated spaces
|
|
12
|
+
|
|
13
|
+
Federation can be either public (no authentication required) or private (password-protected).
|
|
14
|
+
|
|
15
|
+
## Core Federation Functions
|
|
16
|
+
|
|
17
|
+
### Creating a Federation
|
|
18
|
+
|
|
19
|
+
To create a federation between two spaces:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// Public federation (no passwords)
|
|
23
|
+
await holoSphere.federate('space1', 'space2');
|
|
24
|
+
|
|
25
|
+
// Private federation (with passwords)
|
|
26
|
+
await holoSphere.federate('space1', 'space2', 'password1', 'password2');
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Setting Up Bidirectional Notification (Important!)
|
|
30
|
+
|
|
31
|
+
After creating a federation, you need to set up the notification settings for proper bidirectional data propagation:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
// 1. Get federation settings for first space
|
|
35
|
+
const fedSettings1 = await holoSphere.getGlobal('federation', 'space1');
|
|
36
|
+
if (fedSettings1) {
|
|
37
|
+
// 2. Configure notify settings
|
|
38
|
+
fedSettings1.notify = fedSettings1.notify || [];
|
|
39
|
+
if (!fedSettings1.notify.includes('space2')) {
|
|
40
|
+
fedSettings1.notify.push('space2');
|
|
41
|
+
}
|
|
42
|
+
// 3. Save updated settings
|
|
43
|
+
await holoSphere.putGlobal('federation', fedSettings1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Repeat for the second space
|
|
47
|
+
const fedSettings2 = await holoSphere.getGlobal('federation', 'space2');
|
|
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
|
+
```
|
|
56
|
+
|
|
57
|
+
### Getting Federation Information
|
|
58
|
+
|
|
59
|
+
To retrieve information about a space's federation:
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
// Public space
|
|
63
|
+
const fedInfo = await holoSphere.getFederation('space1');
|
|
64
|
+
|
|
65
|
+
// Private space
|
|
66
|
+
const fedInfo = await holoSphere.getFederation('space1', 'password1');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The returned object contains:
|
|
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
|
|
74
|
+
|
|
75
|
+
### Propagating Data to Federated Spaces
|
|
76
|
+
|
|
77
|
+
To propagate data to all federated spaces:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
const data = { id: 'item1', value: 42 };
|
|
81
|
+
|
|
82
|
+
// 1. Store data locally first
|
|
83
|
+
await holoSphere.put('space1', 'items', data);
|
|
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));
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Accessing Data Across Federated Spaces
|
|
93
|
+
|
|
94
|
+
There are multiple ways to access data across federated spaces:
|
|
95
|
+
|
|
96
|
+
#### Method 1: Using getFederated (Recommended)
|
|
97
|
+
|
|
98
|
+
This retrieves data from both the local space and all federated spaces:
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// Get all items from local and federated spaces
|
|
102
|
+
const allItems = await holoSphere.getFederated('space2', 'items');
|
|
103
|
+
|
|
104
|
+
// Find a specific item by ID
|
|
105
|
+
const item1 = allItems.find(item => item.id === 'item1');
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### Method 2: Direct Access
|
|
109
|
+
|
|
110
|
+
After propagation, data may also be accessible directly:
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
// Attempt to get item1 from space2 directly
|
|
114
|
+
const item1FromSpace2 = await holoSphere.get('space2', 'items', 'item1');
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Subscribing to Federation Changes
|
|
118
|
+
|
|
119
|
+
To subscribe to changes in a federation:
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
// Subscribe
|
|
123
|
+
const subscription = await holoSphere.subscribeFederation('space1', null, (data, originSpace, lens) => {
|
|
124
|
+
console.log(`Received data from ${originSpace}/${lens}:`, data);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Later, unsubscribe
|
|
128
|
+
subscription.unsubscribe();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Removing a Federation
|
|
132
|
+
|
|
133
|
+
To remove a federation between two spaces:
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
// Public federation
|
|
137
|
+
await holoSphere.unfederate('space1', 'space2');
|
|
138
|
+
|
|
139
|
+
// Private federation
|
|
140
|
+
await holoSphere.unfederate('space1', 'space2', 'password1', 'password2');
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Complete Example
|
|
144
|
+
|
|
145
|
+
Here's a complete example showing the proper way to set up and use federation:
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
import HoloSphere from './holosphere.js';
|
|
149
|
+
|
|
150
|
+
async function federationExample() {
|
|
151
|
+
const holoSphere = new HoloSphere('example-app');
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const space1 = 'public-space1';
|
|
155
|
+
const space2 = 'public-space2';
|
|
156
|
+
|
|
157
|
+
// Step 1: Create federation
|
|
158
|
+
await holoSphere.federate(space1, space2);
|
|
159
|
+
|
|
160
|
+
// Step 2: Set up bidirectional notify settings (critical!)
|
|
161
|
+
const fedSettings1 = await holoSphere.getGlobal('federation', space1);
|
|
162
|
+
if (fedSettings1) {
|
|
163
|
+
fedSettings1.notify = fedSettings1.notify || [];
|
|
164
|
+
if (!fedSettings1.notify.includes(space2)) {
|
|
165
|
+
fedSettings1.notify.push(space2);
|
|
166
|
+
await holoSphere.putGlobal('federation', fedSettings1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const fedSettings2 = await holoSphere.getGlobal('federation', space2);
|
|
171
|
+
if (fedSettings2) {
|
|
172
|
+
fedSettings2.notify = fedSettings2.notify || [];
|
|
173
|
+
if (!fedSettings2.notify.includes(space1)) {
|
|
174
|
+
fedSettings2.notify.push(space1);
|
|
175
|
+
await holoSphere.putGlobal('federation', fedSettings2);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Step 3: Verify federation is set up properly
|
|
180
|
+
const updatedFedInfo = await holoSphere.getFederation(space1);
|
|
181
|
+
console.log(`Federation info for ${space1}:`, updatedFedInfo);
|
|
182
|
+
|
|
183
|
+
// Step 4: Store data in space1
|
|
184
|
+
const item = {
|
|
185
|
+
id: 'item1',
|
|
186
|
+
title: 'Federation Test',
|
|
187
|
+
value: 42
|
|
188
|
+
};
|
|
189
|
+
await holoSphere.put(space1, 'items', item);
|
|
190
|
+
|
|
191
|
+
// Step 5: Propagate to federation
|
|
192
|
+
await holoSphere.propagateToFederation(space1, 'items', item);
|
|
193
|
+
|
|
194
|
+
// Step 6: Allow time for propagation
|
|
195
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
196
|
+
|
|
197
|
+
// Step 7: Access data from both spaces
|
|
198
|
+
const itemFromSpace1 = await holoSphere.get(space1, 'items', 'item1');
|
|
199
|
+
console.log('Item from space1:', itemFromSpace1);
|
|
200
|
+
|
|
201
|
+
// Step 8: Access federated data
|
|
202
|
+
// Method 1: Using getFederated
|
|
203
|
+
const federatedData = await holoSphere.getFederated(space2, 'items');
|
|
204
|
+
const itemFromFederation = federatedData.find(item => item.id === 'item1');
|
|
205
|
+
console.log('Item from federation:', itemFromFederation);
|
|
206
|
+
|
|
207
|
+
// Method 2: Direct access (if propagation worked correctly)
|
|
208
|
+
const directAccess = await holoSphere.get(space2, 'items', 'item1');
|
|
209
|
+
console.log('Direct access from space2:', directAccess);
|
|
210
|
+
|
|
211
|
+
// Step 9: Clean up
|
|
212
|
+
await holoSphere.unfederate(space1, space2);
|
|
213
|
+
} finally {
|
|
214
|
+
// Always close the HoloSphere instance
|
|
215
|
+
await holoSphere.close();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
federationExample().catch(console.error);
|
|
220
|
+
```
|
|
221
|
+
|
|
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
|
+
## Troubleshooting
|
|
242
|
+
|
|
243
|
+
### Common Issues
|
|
244
|
+
|
|
245
|
+
1. **Missing Notify Settings**: The most common issue is not properly configuring notify settings. Always ensure both spaces have each other in their notify arrays.
|
|
246
|
+
|
|
247
|
+
2. **No Explicit Propagation**: Data doesn't automatically propagate between spaces. You must explicitly call `propagateToFederation()` after storing data.
|
|
248
|
+
|
|
249
|
+
3. **Authentication Errors**: When working with private federations, ensure passwords are correct and consistent.
|
|
250
|
+
|
|
251
|
+
4. **Timing Issues**: Data propagation is asynchronous. Add small delays (500-1000ms) between operations to allow propagation to complete.
|
|
252
|
+
|
|
253
|
+
5. **Missing Federation Metadata**: After propagation, federated items should have a `federation` property containing the origin space and timestamp.
|
|
254
|
+
|
|
255
|
+
### Best Practices
|
|
256
|
+
|
|
257
|
+
1. **Verify Federation Setup**: After creating a federation, always check the federation info to ensure it includes both the federation relationship and notify settings.
|
|
258
|
+
|
|
259
|
+
2. **Error Handling**: Wrap federation operations in try/catch blocks and handle errors gracefully.
|
|
260
|
+
|
|
261
|
+
3. **Bidirectional Setup**: For proper data sharing, both spaces need notify settings pointing to each other.
|
|
262
|
+
|
|
263
|
+
4. **Propagation Timing**: Allow sufficient time for propagation operations to complete before attempting to access data.
|
|
264
|
+
|
|
265
|
+
5. **Cleanup**: Always close the HoloSphere instance when done to prevent resource leaks.
|