holosphere 1.1.6 → 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 +108 -160
- package/README.md +140 -0
- package/examples/README-environmental.md +158 -0
- package/examples/environmentalData.js +380 -0
- package/examples/federation.js +154 -0
- package/examples/queryEnvironmentalData.js +147 -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 -1
- package/services/environmentalApi.js +162 -0
- package/services/{environmentalApitest.js → environmentalApi.test.js} +0 -6
- package/test/ai.test.js +2 -2
- package/test/delete.test.js +225 -0
- package/test/federation.test.js +50 -2
- /package/test/{holonauth.test.js → auth.test.js} +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import HoloSphere from '../holosphere.js';
|
|
2
|
+
import * as environmentalApi from '../services/environmentalApi.js';
|
|
3
|
+
import * as h3 from 'h3-js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Example script demonstrating how to save environmental data to HoloSphere
|
|
7
|
+
* This creates a structured dataset that can be federated across different holons
|
|
8
|
+
*/
|
|
9
|
+
async function storeEnvironmentalData() {
|
|
10
|
+
// Initialize HoloSphere
|
|
11
|
+
const holosphere = new HoloSphere('environmental-data', true);
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Define schemas for different environmental data types
|
|
15
|
+
await setupSchemas(holosphere);
|
|
16
|
+
|
|
17
|
+
// Example coordinates (Rome, Italy)
|
|
18
|
+
const lat = 41.9;
|
|
19
|
+
const lon = 12.5;
|
|
20
|
+
const countryCode = 'ITA';
|
|
21
|
+
|
|
22
|
+
// Get the H3 index for this location at different resolutions
|
|
23
|
+
const cityHolon = await holosphere.getHolon(lat, lon, 7); // City level
|
|
24
|
+
const regionHolon = await holosphere.getHolon(lat, lon, 5); // Region level
|
|
25
|
+
const countryHolon = await holosphere.getHolon(lat, lon, 3); // Country level
|
|
26
|
+
|
|
27
|
+
console.log(`Processing data for holons:
|
|
28
|
+
- City: ${cityHolon}
|
|
29
|
+
- Region: ${regionHolon}
|
|
30
|
+
- Country: ${countryHolon}`);
|
|
31
|
+
|
|
32
|
+
// Set up federation between different levels
|
|
33
|
+
await holosphere.federate(cityHolon, regionHolon);
|
|
34
|
+
await holosphere.federate(regionHolon, countryHolon);
|
|
35
|
+
|
|
36
|
+
// Fetch environmental data
|
|
37
|
+
console.log('Fetching environmental data...');
|
|
38
|
+
|
|
39
|
+
// Air quality data (city level)
|
|
40
|
+
let airQualityRecord;
|
|
41
|
+
const airQualityData = await environmentalApi.getAirQuality(lat, lon);
|
|
42
|
+
if (airQualityData) {
|
|
43
|
+
airQualityRecord = transformAirQualityData(airQualityData, cityHolon);
|
|
44
|
+
await holosphere.put(cityHolon, 'air-quality', airQualityRecord);
|
|
45
|
+
console.log('Stored air quality data in city holon');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Carbon sequestration data (region level)
|
|
49
|
+
const carbonData = await environmentalApi.getCarbonSequestration(lat, lon);
|
|
50
|
+
if (carbonData) {
|
|
51
|
+
const carbonRecord = transformCarbonData(carbonData, regionHolon);
|
|
52
|
+
await holosphere.put(regionHolon, 'carbon-sequestration', carbonRecord);
|
|
53
|
+
console.log('Stored carbon sequestration data in region holon');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Soil carbon data (region level)
|
|
57
|
+
const soilCarbonData = await environmentalApi.getSoilCarbon(lat, lon);
|
|
58
|
+
if (soilCarbonData) {
|
|
59
|
+
const soilCarbonRecord = transformSoilCarbonData(soilCarbonData, regionHolon);
|
|
60
|
+
await holosphere.put(regionHolon, 'soil-data', soilCarbonRecord);
|
|
61
|
+
console.log('Stored soil carbon data in region holon');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Biodiversity data (country level)
|
|
65
|
+
const biodiversityData = await environmentalApi.getBiodiversityData(countryCode);
|
|
66
|
+
if (biodiversityData) {
|
|
67
|
+
const biodiversityRecord = transformBiodiversityData(biodiversityData, countryHolon);
|
|
68
|
+
await holosphere.put(countryHolon, 'biodiversity', biodiversityRecord);
|
|
69
|
+
console.log('Stored biodiversity data in country holon');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Define and add the environmental metrics schema
|
|
73
|
+
const metricsSchema = {
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
id: { type: 'string' },
|
|
77
|
+
holon: { type: 'string' },
|
|
78
|
+
timestamp: { type: 'number' },
|
|
79
|
+
metrics: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: {
|
|
82
|
+
airQualityIndex: { type: 'number' },
|
|
83
|
+
carbonSequestration: { type: 'number' },
|
|
84
|
+
soilCarbon: { type: 'number' },
|
|
85
|
+
biodiversityCount: { type: 'number' }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
required: ['id', 'holon', 'timestamp', 'metrics']
|
|
90
|
+
};
|
|
91
|
+
await holosphere.setSchema('environmental-metrics', metricsSchema);
|
|
92
|
+
console.log('Set schema for environmental metrics');
|
|
93
|
+
|
|
94
|
+
// Create initial empty metrics object
|
|
95
|
+
const metricsRecord = {
|
|
96
|
+
id: `env-metrics-${Date.now()}`,
|
|
97
|
+
holon: countryHolon,
|
|
98
|
+
timestamp: Date.now(),
|
|
99
|
+
metrics: {
|
|
100
|
+
airQualityIndex: 0,
|
|
101
|
+
carbonSequestration: 0,
|
|
102
|
+
soilCarbon: 0,
|
|
103
|
+
biodiversityCount: 0
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
await holosphere.put(countryHolon, 'environmental-metrics', metricsRecord);
|
|
107
|
+
console.log('Added initial environmental metrics record');
|
|
108
|
+
|
|
109
|
+
// Propagate data to create federation references
|
|
110
|
+
console.log('Setting up data federation...');
|
|
111
|
+
|
|
112
|
+
// Propagate air quality data up to region
|
|
113
|
+
if (airQualityRecord) {
|
|
114
|
+
await holosphere.propagate(cityHolon, 'air-quality', airQualityRecord, {
|
|
115
|
+
targetSpaces: [regionHolon]
|
|
116
|
+
});
|
|
117
|
+
console.log('Propagated air quality data to region holon');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Aggregate environmental metrics at country level - manual approach since compute has issues
|
|
121
|
+
console.log('Manually updating environmental metrics...');
|
|
122
|
+
try {
|
|
123
|
+
// Get data from various sources
|
|
124
|
+
const airData = airQualityRecord || { airQualityIndex: 0 };
|
|
125
|
+
const carbonData = await holosphere.get(regionHolon, 'carbon-sequestration');
|
|
126
|
+
const soilData = await holosphere.get(regionHolon, 'soil-data');
|
|
127
|
+
const bioData = await holosphere.get(countryHolon, 'biodiversity');
|
|
128
|
+
|
|
129
|
+
// Update metrics manually
|
|
130
|
+
const updatedMetrics = {
|
|
131
|
+
id: metricsRecord.id,
|
|
132
|
+
holon: countryHolon,
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
metrics: {
|
|
135
|
+
airQualityIndex: airData.airQualityIndex || 0,
|
|
136
|
+
carbonSequestration: carbonData?.carbonSequestration || 0,
|
|
137
|
+
soilCarbon: soilData?.soilCarbon || 0,
|
|
138
|
+
biodiversityCount: bioData?.biodiversityCount || 0
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
await holosphere.put(countryHolon, 'environmental-metrics', updatedMetrics);
|
|
143
|
+
console.log('Updated environmental metrics at country level:', updatedMetrics);
|
|
144
|
+
} catch (updateError) {
|
|
145
|
+
console.error('Error updating environmental metrics:', updateError);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Get and display the metrics directly instead of using getFederated
|
|
149
|
+
console.log('Retrieving environmental metrics...');
|
|
150
|
+
try {
|
|
151
|
+
const environmentalMetrics = await holosphere.get(countryHolon, 'environmental-metrics');
|
|
152
|
+
console.log('Environmental metrics:', environmentalMetrics);
|
|
153
|
+
} catch (getError) {
|
|
154
|
+
console.error('Error retrieving metrics:', getError);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('Error storing environmental data:', error);
|
|
159
|
+
} finally {
|
|
160
|
+
// Close HoloSphere instance
|
|
161
|
+
await holosphere.close();
|
|
162
|
+
console.log('HoloSphere instance closed successfully');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Set up schemas for environmental data
|
|
168
|
+
*/
|
|
169
|
+
async function setupSchemas(holosphere) {
|
|
170
|
+
// Air quality schema
|
|
171
|
+
const airQualitySchema = {
|
|
172
|
+
type: 'object',
|
|
173
|
+
properties: {
|
|
174
|
+
id: { type: 'string' },
|
|
175
|
+
holon: { type: 'string' },
|
|
176
|
+
timestamp: { type: 'number' },
|
|
177
|
+
coordinates: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
properties: {
|
|
180
|
+
lat: { type: 'number' },
|
|
181
|
+
lon: { type: 'number' }
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
airQualityIndex: { type: 'number' },
|
|
185
|
+
pollutants: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
properties: {
|
|
188
|
+
co: { type: 'number' },
|
|
189
|
+
no2: { type: 'number' },
|
|
190
|
+
o3: { type: 'number' },
|
|
191
|
+
pm2_5: { type: 'number' },
|
|
192
|
+
pm10: { type: 'number' },
|
|
193
|
+
so2: { type: 'number' }
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
required: ['id', 'holon', 'timestamp', 'coordinates', 'airQualityIndex']
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Carbon sequestration schema
|
|
201
|
+
const carbonSchema = {
|
|
202
|
+
type: 'object',
|
|
203
|
+
properties: {
|
|
204
|
+
id: { type: 'string' },
|
|
205
|
+
holon: { type: 'string' },
|
|
206
|
+
timestamp: { type: 'number' },
|
|
207
|
+
coordinates: {
|
|
208
|
+
type: 'object',
|
|
209
|
+
properties: {
|
|
210
|
+
lat: { type: 'number' },
|
|
211
|
+
lon: { type: 'number' }
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
carbonSequestration: { type: 'number' },
|
|
215
|
+
temperature: { type: 'number' },
|
|
216
|
+
precipitation: { type: 'number' }
|
|
217
|
+
},
|
|
218
|
+
required: ['id', 'holon', 'timestamp', 'coordinates', 'carbonSequestration']
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// Soil carbon schema
|
|
222
|
+
const soilSchema = {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
id: { type: 'string' },
|
|
226
|
+
holon: { type: 'string' },
|
|
227
|
+
timestamp: { type: 'number' },
|
|
228
|
+
coordinates: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
properties: {
|
|
231
|
+
lat: { type: 'number' },
|
|
232
|
+
lon: { type: 'number' }
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
soilCarbon: { type: 'number' },
|
|
236
|
+
soilType: { type: 'string' },
|
|
237
|
+
soilDepth: { type: 'string' }
|
|
238
|
+
},
|
|
239
|
+
required: ['id', 'holon', 'timestamp', 'coordinates', 'soilCarbon']
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// Biodiversity schema
|
|
243
|
+
const biodiversitySchema = {
|
|
244
|
+
type: 'object',
|
|
245
|
+
properties: {
|
|
246
|
+
id: { type: 'string' },
|
|
247
|
+
holon: { type: 'string' },
|
|
248
|
+
timestamp: { type: 'number' },
|
|
249
|
+
countryCode: { type: 'string' },
|
|
250
|
+
biodiversityCount: { type: 'number' },
|
|
251
|
+
species: {
|
|
252
|
+
type: 'array',
|
|
253
|
+
items: {
|
|
254
|
+
type: 'object',
|
|
255
|
+
properties: {
|
|
256
|
+
scientificName: { type: 'string' },
|
|
257
|
+
count: { type: 'number' }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
required: ['id', 'holon', 'timestamp', 'countryCode', 'biodiversityCount']
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// Set schemas
|
|
266
|
+
await holosphere.setSchema('air-quality', airQualitySchema);
|
|
267
|
+
await holosphere.setSchema('carbon-sequestration', carbonSchema);
|
|
268
|
+
await holosphere.setSchema('soil-data', soilSchema);
|
|
269
|
+
await holosphere.setSchema('biodiversity', biodiversitySchema);
|
|
270
|
+
|
|
271
|
+
console.log('Environmental data schemas set up successfully');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Transform air quality data from API into our schema
|
|
276
|
+
*/
|
|
277
|
+
function transformAirQualityData(apiData, holon) {
|
|
278
|
+
const components = apiData.list?.[0]?.components || {};
|
|
279
|
+
const main = apiData.list?.[0]?.main || {};
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
id: `air-quality-${Date.now()}`,
|
|
283
|
+
holon: holon,
|
|
284
|
+
timestamp: Date.now(),
|
|
285
|
+
coordinates: {
|
|
286
|
+
lat: apiData.coord?.lat || 0,
|
|
287
|
+
lon: apiData.coord?.lon || 0
|
|
288
|
+
},
|
|
289
|
+
airQualityIndex: main.aqi || 0,
|
|
290
|
+
pollutants: {
|
|
291
|
+
co: components.co || 0,
|
|
292
|
+
no2: components.no2 || 0,
|
|
293
|
+
o3: components.o3 || 0,
|
|
294
|
+
pm2_5: components.pm2_5 || 0,
|
|
295
|
+
pm10: components.pm10 || 0,
|
|
296
|
+
so2: components.so2 || 0
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Transform carbon sequestration data from API into our schema
|
|
303
|
+
*/
|
|
304
|
+
function transformCarbonData(apiData, holon) {
|
|
305
|
+
const parameters = apiData.properties?.parameter || {};
|
|
306
|
+
const temperature = parameters.T2M?.['20230701'] || 0;
|
|
307
|
+
const precipitation = parameters.PRECTOT?.['20230701'] || 0;
|
|
308
|
+
|
|
309
|
+
// Calculate a simplified carbon sequestration estimate
|
|
310
|
+
// (In a real app, use actual models based on temperature, precipitation, etc.)
|
|
311
|
+
const carbonSequestration = (temperature * 0.5) + (precipitation * 2);
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
id: `carbon-seq-${Date.now()}`,
|
|
315
|
+
holon: holon,
|
|
316
|
+
timestamp: Date.now(),
|
|
317
|
+
coordinates: {
|
|
318
|
+
lat: apiData.geometry?.coordinates[1] || 0,
|
|
319
|
+
lon: apiData.geometry?.coordinates[0] || 0
|
|
320
|
+
},
|
|
321
|
+
carbonSequestration: carbonSequestration,
|
|
322
|
+
temperature: temperature,
|
|
323
|
+
precipitation: precipitation
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Transform soil carbon data from API into our schema
|
|
329
|
+
*/
|
|
330
|
+
function transformSoilCarbonData(apiData, holon) {
|
|
331
|
+
const properties = apiData.properties || {};
|
|
332
|
+
const soilCarbon = properties.soilGrids?.properties?.soc?.mean || 0;
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
id: `soil-carbon-${Date.now()}`,
|
|
336
|
+
holon: holon,
|
|
337
|
+
timestamp: Date.now(),
|
|
338
|
+
coordinates: {
|
|
339
|
+
lat: apiData.geometry?.coordinates[1] || 0,
|
|
340
|
+
lon: apiData.geometry?.coordinates[0] || 0
|
|
341
|
+
},
|
|
342
|
+
soilCarbon: soilCarbon,
|
|
343
|
+
soilType: properties.soilType || 'Unknown',
|
|
344
|
+
soilDepth: '0-30cm'
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Transform biodiversity data from API into our schema
|
|
350
|
+
*/
|
|
351
|
+
function transformBiodiversityData(apiData, holon) {
|
|
352
|
+
const results = apiData.results || [];
|
|
353
|
+
const species = {};
|
|
354
|
+
|
|
355
|
+
// Count species occurrences
|
|
356
|
+
results.forEach(occurrence => {
|
|
357
|
+
const name = occurrence.scientificName || 'Unknown';
|
|
358
|
+
species[name] = (species[name] || 0) + 1;
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Convert to array format
|
|
362
|
+
const speciesArray = Object.keys(species).map(name => ({
|
|
363
|
+
scientificName: name,
|
|
364
|
+
count: species[name]
|
|
365
|
+
}));
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
id: `biodiversity-${Date.now()}`,
|
|
369
|
+
holon: holon,
|
|
370
|
+
timestamp: Date.now(),
|
|
371
|
+
countryCode: results[0]?.countryCode || 'Unknown',
|
|
372
|
+
biodiversityCount: results.length,
|
|
373
|
+
species: speciesArray
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Execute the example
|
|
378
|
+
storeEnvironmentalData()
|
|
379
|
+
.then(() => console.log('Environmental data example completed'))
|
|
380
|
+
.catch(error => console.error('Error in environmental data example:', error));
|
|
@@ -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);
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import HoloSphere from '../holosphere.js';
|
|
2
|
+
import * as h3 from 'h3-js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Example demonstrating how to query environmental data from HoloSphere
|
|
6
|
+
* This shows how to access data across federated holons at different scales
|
|
7
|
+
*/
|
|
8
|
+
async function queryEnvironmentalData() {
|
|
9
|
+
// Initialize HoloSphere with the same appname used to store the data
|
|
10
|
+
const holosphere = new HoloSphere('environmental-data');
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// Example coordinates (Rome, Italy)
|
|
14
|
+
const lat = 41.9;
|
|
15
|
+
const lon = 12.5;
|
|
16
|
+
|
|
17
|
+
// Get the holons at different resolutions
|
|
18
|
+
const cityHolon = await holosphere.getHolon(lat, lon, 7); // City level
|
|
19
|
+
const regionHolon = await holosphere.getHolon(lat, lon, 5); // Region level
|
|
20
|
+
const countryHolon = await holosphere.getHolon(lat, lon, 3); // Country level
|
|
21
|
+
|
|
22
|
+
console.log(`Querying environmental data for location (${lat}, ${lon})`);
|
|
23
|
+
console.log(` - City: ${cityHolon}`);
|
|
24
|
+
console.log(` - Region: ${regionHolon}`);
|
|
25
|
+
console.log(` - Country: ${countryHolon}`);
|
|
26
|
+
|
|
27
|
+
// Query 1: Get air quality data from the city level
|
|
28
|
+
console.log('\n=== CITY LEVEL: Air Quality Data ===');
|
|
29
|
+
const airQualityData = await holosphere.getAll(cityHolon, 'air-quality');
|
|
30
|
+
if (airQualityData.length > 0) {
|
|
31
|
+
const latest = airQualityData.sort((a, b) => b.timestamp - a.timestamp)[0];
|
|
32
|
+
console.log(`Latest Air Quality Index: ${latest.airQualityIndex}`);
|
|
33
|
+
console.log('Pollutant levels:');
|
|
34
|
+
Object.entries(latest.pollutants).forEach(([pollutant, value]) => {
|
|
35
|
+
console.log(` - ${pollutant}: ${value}`);
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
console.log('No air quality data available for this location');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Query 2: Use federation to get soil data referenced at the region level
|
|
42
|
+
console.log('\n=== REGION LEVEL: Soil Carbon Data ===');
|
|
43
|
+
const soilData = await holosphere.getAll(regionHolon, 'soil-data');
|
|
44
|
+
if (soilData.length > 0) {
|
|
45
|
+
const latest = soilData.sort((a, b) => b.timestamp - a.timestamp)[0];
|
|
46
|
+
console.log(`Soil Carbon: ${latest.soilCarbon} g/kg`);
|
|
47
|
+
console.log(`Soil Type: ${latest.soilType}`);
|
|
48
|
+
console.log(`Soil Depth: ${latest.soilDepth}`);
|
|
49
|
+
} else {
|
|
50
|
+
console.log('No soil data available for this region');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Query 3: Get carbon sequestration data at region level
|
|
54
|
+
console.log('\n=== REGION LEVEL: Carbon Sequestration ===');
|
|
55
|
+
const carbonData = await holosphere.getAll(regionHolon, 'carbon-sequestration');
|
|
56
|
+
if (carbonData.length > 0) {
|
|
57
|
+
const latest = carbonData.sort((a, b) => b.timestamp - a.timestamp)[0];
|
|
58
|
+
console.log(`Carbon Sequestration: ${latest.carbonSequestration} tons/hectare/year`);
|
|
59
|
+
console.log(`Temperature: ${latest.temperature}°C`);
|
|
60
|
+
console.log(`Precipitation: ${latest.precipitation} mm`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log('No carbon sequestration data available for this region');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Query 4: Get biodiversity data at country level
|
|
66
|
+
console.log('\n=== COUNTRY LEVEL: Biodiversity ===');
|
|
67
|
+
const biodiversityData = await holosphere.getAll(countryHolon, 'biodiversity');
|
|
68
|
+
if (biodiversityData.length > 0) {
|
|
69
|
+
const latest = biodiversityData.sort((a, b) => b.timestamp - a.timestamp)[0];
|
|
70
|
+
console.log(`Biodiversity Count: ${latest.biodiversityCount} species`);
|
|
71
|
+
console.log(`Country Code: ${latest.countryCode}`);
|
|
72
|
+
console.log(`Top 5 Species:`);
|
|
73
|
+
|
|
74
|
+
// Sort species by count and show top 5
|
|
75
|
+
const topSpecies = latest.species.sort((a, b) => b.count - a.count).slice(0, 5);
|
|
76
|
+
topSpecies.forEach((species, index) => {
|
|
77
|
+
console.log(` ${index + 1}. ${species.scientificName}: ${species.count} occurrences`);
|
|
78
|
+
});
|
|
79
|
+
} else {
|
|
80
|
+
console.log('No biodiversity data available for this country');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Query 5: Get federated data across all levels
|
|
84
|
+
console.log('\n=== FEDERATED DATA: Environmental Metrics ===');
|
|
85
|
+
const federatedData = await holosphere.getFederated(countryHolon, 'environmental-metrics', {
|
|
86
|
+
resolveReferences: true,
|
|
87
|
+
aggregate: true,
|
|
88
|
+
idField: 'id'
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (federatedData.length > 0) {
|
|
92
|
+
console.log('Aggregated Environmental Metrics:');
|
|
93
|
+
federatedData.forEach(data => {
|
|
94
|
+
if (data.metrics) {
|
|
95
|
+
Object.entries(data.metrics).forEach(([metric, value]) => {
|
|
96
|
+
console.log(` - ${metric}: ${value}`);
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
console.log('No metrics available in federated data');
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
console.log('No federated environmental metrics available');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Query 6: Get references to air quality data from the region level
|
|
107
|
+
// This demonstrates accessing data via federation references
|
|
108
|
+
console.log('\n=== FEDERATION REFERENCES: Air Quality Data from Region ===');
|
|
109
|
+
const airQualityRefs = await holosphere.getAll(regionHolon, 'air-quality');
|
|
110
|
+
if (airQualityRefs.length > 0) {
|
|
111
|
+
console.log(`Found ${airQualityRefs.length} air quality references in region`);
|
|
112
|
+
|
|
113
|
+
// Get the first reference and resolve it
|
|
114
|
+
const ref = airQualityRefs[0];
|
|
115
|
+
console.log('Reference details:');
|
|
116
|
+
|
|
117
|
+
if (ref.soul) {
|
|
118
|
+
console.log(` - Soul path: ${ref.soul}`);
|
|
119
|
+
|
|
120
|
+
// Resolve reference manually to show the process
|
|
121
|
+
const resolvedData = await holosphere.getNodeBySoul(ref.soul);
|
|
122
|
+
if (resolvedData) {
|
|
123
|
+
console.log('Successfully resolved reference to original air quality data:');
|
|
124
|
+
console.log(` - Air Quality Index: ${resolvedData.airQualityIndex}`);
|
|
125
|
+
console.log(` - Source Holon: ${resolvedData.holon}`);
|
|
126
|
+
} else {
|
|
127
|
+
console.log('Could not resolve reference - original data not found');
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
console.log('Not a soul reference:', ref);
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
console.log('No air quality references found at region level');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error('Error querying environmental data:', error);
|
|
138
|
+
} finally {
|
|
139
|
+
// Always close the HoloSphere instance
|
|
140
|
+
await holosphere.close();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Execute the example
|
|
145
|
+
queryEnvironmentalData()
|
|
146
|
+
.then(() => console.log('\nEnvironmental data query example completed'))
|
|
147
|
+
.catch(error => console.error('Error in environmental data query example:', error));
|