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
package/package.json
CHANGED
|
@@ -9,10 +9,79 @@ const logError = (service, error) => {
|
|
|
9
9
|
console.error(`${service} API Error:`, { status, message });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// Mock data responses (for testing without API keys)
|
|
13
|
+
const mockData = {
|
|
14
|
+
airQuality: {
|
|
15
|
+
coord: { lat: 41.9, lon: 12.5 },
|
|
16
|
+
list: [
|
|
17
|
+
{
|
|
18
|
+
main: { aqi: 2 },
|
|
19
|
+
components: {
|
|
20
|
+
co: 201.94,
|
|
21
|
+
no2: 0.78,
|
|
22
|
+
o3: 68.64,
|
|
23
|
+
pm2_5: 0.5,
|
|
24
|
+
pm10: 0.82,
|
|
25
|
+
so2: 0.52
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
carbonSequestration: {
|
|
31
|
+
properties: {
|
|
32
|
+
parameter: {
|
|
33
|
+
T2M: { '20230701': 28.5 },
|
|
34
|
+
PRECTOT: { '20230701': 1.2 },
|
|
35
|
+
PS: { '20230701': 1013.25 },
|
|
36
|
+
WS2M: { '20230701': 3.5 }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
geometry: {
|
|
40
|
+
coordinates: [12.5, 41.9]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
soilCarbon: {
|
|
44
|
+
properties: {
|
|
45
|
+
soilGrids: {
|
|
46
|
+
properties: {
|
|
47
|
+
soc: { mean: 78.4 }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
soilType: 'Clay Loam'
|
|
51
|
+
},
|
|
52
|
+
geometry: {
|
|
53
|
+
coordinates: [12.5, 41.9]
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
biodiversity: {
|
|
57
|
+
results: [
|
|
58
|
+
{ scientificName: 'Quercus ilex', countryCode: 'ITA' },
|
|
59
|
+
{ scientificName: 'Pinus pinea', countryCode: 'ITA' },
|
|
60
|
+
{ scientificName: 'Olea europaea', countryCode: 'ITA' },
|
|
61
|
+
{ scientificName: 'Quercus ilex', countryCode: 'ITA' },
|
|
62
|
+
{ scientificName: 'Pinus pinea', countryCode: 'ITA' },
|
|
63
|
+
{ scientificName: 'Laurus nobilis', countryCode: 'ITA' },
|
|
64
|
+
{ scientificName: 'Quercus ilex', countryCode: 'ITA' },
|
|
65
|
+
{ scientificName: 'Platanus orientalis', countryCode: 'ITA' },
|
|
66
|
+
{ scientificName: 'Cupressus sempervirens', countryCode: 'ITA' },
|
|
67
|
+
{ scientificName: 'Cupressus sempervirens', countryCode: 'ITA' }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Flag to use mock data instead of making real API calls
|
|
73
|
+
const USE_MOCK_DATA = true;
|
|
74
|
+
|
|
12
75
|
/**
|
|
13
76
|
* Fetch Carbon Sequestration Data (Using NASA POWER API)
|
|
14
77
|
*/
|
|
15
78
|
export async function getCarbonSequestration(lat = 41.9, lon = 12.5) {
|
|
79
|
+
// Return mock data if flag is set
|
|
80
|
+
if (USE_MOCK_DATA) {
|
|
81
|
+
console.log('Using mock carbon sequestration data');
|
|
82
|
+
return mockData.carbonSequestration;
|
|
83
|
+
}
|
|
84
|
+
|
|
16
85
|
try {
|
|
17
86
|
const response = await axios.default.get(
|
|
18
87
|
`https://power.larc.nasa.gov/api/temporal/daily/point?parameters=T2M,PRECTOT,PS,WS2M&community=RE&longitude=${lon}&latitude=${lat}&start=20230101&end=20231231&format=JSON`
|
|
@@ -28,6 +97,12 @@ export async function getCarbonSequestration(lat = 41.9, lon = 12.5) {
|
|
|
28
97
|
* Fetch Soil Carbon Data (Using ISRIC World Soil Information)
|
|
29
98
|
*/
|
|
30
99
|
export async function getSoilCarbon(lat = 41.9, lon = 12.5) {
|
|
100
|
+
// Return mock data if flag is set
|
|
101
|
+
if (USE_MOCK_DATA) {
|
|
102
|
+
console.log('Using mock soil carbon data');
|
|
103
|
+
return mockData.soilCarbon;
|
|
104
|
+
}
|
|
105
|
+
|
|
31
106
|
try {
|
|
32
107
|
const response = await axios.default.get(
|
|
33
108
|
`https://rest.isric.org/soilgrids/v2.0/properties/query?lat=${lat}&lon=${lon}&property=soc&depth=0-30cm&value=mean`
|
|
@@ -43,6 +118,12 @@ export async function getSoilCarbon(lat = 41.9, lon = 12.5) {
|
|
|
43
118
|
* Fetch Biodiversity Data (GBIF API)
|
|
44
119
|
*/
|
|
45
120
|
export async function getBiodiversityData(countryCode = "ITA") {
|
|
121
|
+
// Return mock data if flag is set
|
|
122
|
+
if (USE_MOCK_DATA) {
|
|
123
|
+
console.log('Using mock biodiversity data');
|
|
124
|
+
return mockData.biodiversity;
|
|
125
|
+
}
|
|
126
|
+
|
|
46
127
|
try {
|
|
47
128
|
const response = await axios.default.get(`https://api.gbif.org/v1/occurrence/search?country=${countryCode}&limit=100`);
|
|
48
129
|
return response.data;
|
|
@@ -56,6 +137,12 @@ export async function getBiodiversityData(countryCode = "ITA") {
|
|
|
56
137
|
* Fetch Vegetation Cover Data (Using NASA MODIS Vegetation Index)
|
|
57
138
|
*/
|
|
58
139
|
export async function getVegetationCover(lat = 41.9, lon = 12.5) {
|
|
140
|
+
// Return mock data if flag is set
|
|
141
|
+
if (USE_MOCK_DATA) {
|
|
142
|
+
console.log('Using mock vegetation cover data');
|
|
143
|
+
return { ndvi: 0.75 };
|
|
144
|
+
}
|
|
145
|
+
|
|
59
146
|
try {
|
|
60
147
|
const response = await axios.default.get(
|
|
61
148
|
`https://modis.ornl.gov/rst/api/v1/MOD13Q1/subset?latitude=${lat}&longitude=${lon}&band=NDVI&startDate=2023-01-01&endDate=2023-12-31`,
|
|
@@ -76,6 +163,12 @@ export async function getVegetationCover(lat = 41.9, lon = 12.5) {
|
|
|
76
163
|
* Fetch Air Quality Data (OpenWeather API)
|
|
77
164
|
*/
|
|
78
165
|
export async function getAirQuality(lat = 41.9, lon = 12.5) {
|
|
166
|
+
// Return mock data if flag is set
|
|
167
|
+
if (USE_MOCK_DATA) {
|
|
168
|
+
console.log('Using mock air quality data');
|
|
169
|
+
return mockData.airQuality;
|
|
170
|
+
}
|
|
171
|
+
|
|
79
172
|
try {
|
|
80
173
|
const response = await axios.default.get(
|
|
81
174
|
`https://api.openweathermap.org/data/2.5/air_pollution?lat=${lat}&lon=${lon}&appid=${process.env.OPENWEATHER_API_KEY}`
|
|
@@ -91,6 +184,12 @@ export async function getAirQuality(lat = 41.9, lon = 12.5) {
|
|
|
91
184
|
* Fetch Water Retention Data (Using USGS Water Services)
|
|
92
185
|
*/
|
|
93
186
|
export async function getWaterRetention(lat = 41.9, lon = 12.5) {
|
|
187
|
+
// Return mock data if flag is set
|
|
188
|
+
if (USE_MOCK_DATA) {
|
|
189
|
+
console.log('Using mock water retention data');
|
|
190
|
+
return { waterRetention: 85.2 };
|
|
191
|
+
}
|
|
192
|
+
|
|
94
193
|
try {
|
|
95
194
|
const response = await axios.default.get(
|
|
96
195
|
`https://waterservices.usgs.gov/nwis/iv/?format=json&sites=11447650&siteStatus=active`,
|
|
@@ -111,6 +210,12 @@ export async function getWaterRetention(lat = 41.9, lon = 12.5) {
|
|
|
111
210
|
* Fetch Deforestation Data (Using World Bank Forest Data)
|
|
112
211
|
*/
|
|
113
212
|
export async function getDeforestationData(countryCode = "ITA") {
|
|
213
|
+
// Return mock data if flag is set
|
|
214
|
+
if (USE_MOCK_DATA) {
|
|
215
|
+
console.log('Using mock deforestation data');
|
|
216
|
+
return { forestAreaPercentage: 31.6, year: 2020 };
|
|
217
|
+
}
|
|
218
|
+
|
|
114
219
|
try {
|
|
115
220
|
const response = await axios.default.get(
|
|
116
221
|
`https://api.worldbank.org/v2/country/${countryCode}/indicator/AG.LND.FRST.ZS?format=json`
|
|
@@ -126,6 +231,12 @@ export async function getDeforestationData(countryCode = "ITA") {
|
|
|
126
231
|
* Fetch Flood Risk Data (Using USGS Water Services)
|
|
127
232
|
*/
|
|
128
233
|
export async function getFloodRisk(lat = 41.9, lon = 12.5) {
|
|
234
|
+
// Return mock data if flag is set
|
|
235
|
+
if (USE_MOCK_DATA) {
|
|
236
|
+
console.log('Using mock flood risk data');
|
|
237
|
+
return { floodRiskLevel: 'low', probability: 0.15 };
|
|
238
|
+
}
|
|
239
|
+
|
|
129
240
|
try {
|
|
130
241
|
const response = await axios.default.get(
|
|
131
242
|
`https://waterservices.usgs.gov/nwis/iv/?format=json&stateCd=CA¶meterCd=00065&siteStatus=active`,
|
|
@@ -146,6 +257,12 @@ export async function getFloodRisk(lat = 41.9, lon = 12.5) {
|
|
|
146
257
|
* Fetch Food Security Data (World Bank API)
|
|
147
258
|
*/
|
|
148
259
|
export async function getFoodSecurity(countryCode = "ITA") {
|
|
260
|
+
// Return mock data if flag is set
|
|
261
|
+
if (USE_MOCK_DATA) {
|
|
262
|
+
console.log('Using mock food security data');
|
|
263
|
+
return { prevalenceOfUndernourishment: 2.5, year: 2020 };
|
|
264
|
+
}
|
|
265
|
+
|
|
149
266
|
try {
|
|
150
267
|
const response = await axios.default.get(
|
|
151
268
|
`https://api.worldbank.org/v2/country/${countryCode}/indicator/SN.ITK.DEFC.ZS?format=json`
|
|
@@ -161,6 +278,12 @@ export async function getFoodSecurity(countryCode = "ITA") {
|
|
|
161
278
|
* Fetch Local Employment Rate (World Bank API)
|
|
162
279
|
*/
|
|
163
280
|
export async function getEmploymentRate(countryCode = "ITA") {
|
|
281
|
+
// Return mock data if flag is set
|
|
282
|
+
if (USE_MOCK_DATA) {
|
|
283
|
+
console.log('Using mock employment rate data');
|
|
284
|
+
return { employmentRate: 58.2, year: 2020 };
|
|
285
|
+
}
|
|
286
|
+
|
|
164
287
|
try {
|
|
165
288
|
const response = await axios.default.get(
|
|
166
289
|
`https://api.worldbank.org/v2/country/${countryCode}/indicator/SL.EMP.TOTL.SP.ZS?format=json`
|
|
@@ -176,6 +299,12 @@ export async function getEmploymentRate(countryCode = "ITA") {
|
|
|
176
299
|
* Fetch Governance Score (World Bank API)
|
|
177
300
|
*/
|
|
178
301
|
export async function getTransparencyScore(countryCode = "ITA") {
|
|
302
|
+
// Return mock data if flag is set
|
|
303
|
+
if (USE_MOCK_DATA) {
|
|
304
|
+
console.log('Using mock transparency score data');
|
|
305
|
+
return { governanceEffectivenessScore: 0.45, year: 2020 };
|
|
306
|
+
}
|
|
307
|
+
|
|
179
308
|
try {
|
|
180
309
|
const response = await axios.default.get(
|
|
181
310
|
`https://api.worldbank.org/v2/country/${countryCode}/indicator/GE.EST?format=json`
|
|
@@ -191,6 +320,17 @@ export async function getTransparencyScore(countryCode = "ITA") {
|
|
|
191
320
|
* Fetch Blockchain Transactions (Etherscan API)
|
|
192
321
|
*/
|
|
193
322
|
export async function getBlockchainTransactions(address = "0x0000000000000000000000000000000000000000") {
|
|
323
|
+
// Return mock data if flag is set
|
|
324
|
+
if (USE_MOCK_DATA) {
|
|
325
|
+
console.log('Using mock blockchain transactions data');
|
|
326
|
+
return {
|
|
327
|
+
result: [
|
|
328
|
+
{ hash: '0x123...', value: '0.5', timeStamp: '1620000000' },
|
|
329
|
+
{ hash: '0x456...', value: '1.2', timeStamp: '1620100000' }
|
|
330
|
+
]
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
194
334
|
try {
|
|
195
335
|
const response = await axios.default.get(
|
|
196
336
|
`https://api.etherscan.io/api?module=account&action=txlist&address=${address}&startblock=0&endblock=99999999&sort=desc&apikey=${process.env.ETHERSCAN_API_KEY}`
|
|
@@ -206,6 +346,12 @@ export async function getBlockchainTransactions(address = "0x0000000000000000000
|
|
|
206
346
|
* Fetch Circular Economy Data (Using World Bank Development Indicators)
|
|
207
347
|
*/
|
|
208
348
|
export async function getCircularEconomyData(countryCode = "ITA") {
|
|
349
|
+
// Return mock data if flag is set
|
|
350
|
+
if (USE_MOCK_DATA) {
|
|
351
|
+
console.log('Using mock circular economy data');
|
|
352
|
+
return { recyclingRate: 51.3, wasteGeneration: 499.0, year: 2020 };
|
|
353
|
+
}
|
|
354
|
+
|
|
209
355
|
try {
|
|
210
356
|
const response = await axios.default.get(
|
|
211
357
|
`https://api.worldbank.org/v2/country/${countryCode}/indicator/EN.ATM.GHGT.KT.CE?format=json`
|
|
@@ -221,6 +367,12 @@ export async function getCircularEconomyData(countryCode = "ITA") {
|
|
|
221
367
|
* Fetch Renewable Energy Data (World Bank API)
|
|
222
368
|
*/
|
|
223
369
|
export async function getRenewableEnergyData(countryCode = "ITA") {
|
|
370
|
+
// Return mock data if flag is set
|
|
371
|
+
if (USE_MOCK_DATA) {
|
|
372
|
+
console.log('Using mock renewable energy data');
|
|
373
|
+
return { renewableEnergyPercentage: 18.2, year: 2020 };
|
|
374
|
+
}
|
|
375
|
+
|
|
224
376
|
try {
|
|
225
377
|
const response = await axios.default.get(
|
|
226
378
|
`https://api.worldbank.org/v2/country/${countryCode}/indicator/EG.FEC.RNEW.ZS?format=json`
|
|
@@ -236,6 +388,16 @@ export async function getRenewableEnergyData(countryCode = "ITA") {
|
|
|
236
388
|
* Fetch Climate Change Data (NOAA Climate API)
|
|
237
389
|
*/
|
|
238
390
|
export async function getClimateChangeData(lat = 41.9, lon = 12.5) {
|
|
391
|
+
// Return mock data if flag is set
|
|
392
|
+
if (USE_MOCK_DATA) {
|
|
393
|
+
console.log('Using mock climate change data');
|
|
394
|
+
return {
|
|
395
|
+
temperatureTrend: '+1.2C over 50 years',
|
|
396
|
+
extremeWeatherEvents: 5,
|
|
397
|
+
year: 2020
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
239
401
|
try {
|
|
240
402
|
const response = await axios.default.get(
|
|
241
403
|
`https://www.ncdc.noaa.gov/cdo-web/api/v2/data?datasetid=GHCND&latitude=${lat}&longitude=${lon}&startdate=2023-01-01&enddate=2023-12-31&limit=1000`,
|
package/test/ai.test.js
CHANGED
|
@@ -259,7 +259,7 @@ describe('AI Operations', () => {
|
|
|
259
259
|
|
|
260
260
|
// Step 4: Propagate to federated space
|
|
261
261
|
try {
|
|
262
|
-
const result = await holoSphere.
|
|
262
|
+
const result = await holoSphere.propagate(testHolon, testLens, updatedData);
|
|
263
263
|
|
|
264
264
|
// Even if propagation fails due to auth, the function should complete
|
|
265
265
|
expect(result).toBeDefined();
|
|
@@ -383,7 +383,7 @@ describe('AI Operations', () => {
|
|
|
383
383
|
|
|
384
384
|
try {
|
|
385
385
|
// This should complete even if auth fails
|
|
386
|
-
const result = await holoSphere.
|
|
386
|
+
const result = await holoSphere.propagate(testHolon, testLens, testData);
|
|
387
387
|
expect(result).toBeDefined();
|
|
388
388
|
// But might not have successfully propagated
|
|
389
389
|
} catch (error) {
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import HoloSphere from '../holosphere.js';
|
|
2
|
+
import { jest } from '@jest/globals';
|
|
3
|
+
|
|
4
|
+
// Configure Jest
|
|
5
|
+
jest.setTimeout(30000); // 30 second timeout
|
|
6
|
+
|
|
7
|
+
describe('HoloSphere Deletion Tests', () => {
|
|
8
|
+
const testAppName = 'test-app-deletion';
|
|
9
|
+
const testHolon = 'testHolonDeletion';
|
|
10
|
+
const testLens = 'testLensDeletion';
|
|
11
|
+
const testGlobalTable = 'testGlobalTable';
|
|
12
|
+
const testPassword = 'testPassword1234';
|
|
13
|
+
let holoSphere;
|
|
14
|
+
|
|
15
|
+
beforeAll(async () => {
|
|
16
|
+
holoSphere = new HoloSphere(testAppName, false, null);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterAll(async () => {
|
|
20
|
+
// Clean up all test data
|
|
21
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
22
|
+
await holoSphere.deleteAllGlobal(testGlobalTable);
|
|
23
|
+
|
|
24
|
+
// Close Gun connections
|
|
25
|
+
if (holoSphere) {
|
|
26
|
+
await holoSphere.close();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Wait for connections to close
|
|
30
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('Basic Deletion', () => {
|
|
34
|
+
test('should delete a single item properly', async () => {
|
|
35
|
+
// Create test data
|
|
36
|
+
const testData = { id: 'delete-test-1', value: 'delete me' };
|
|
37
|
+
|
|
38
|
+
// Store data
|
|
39
|
+
await holoSphere.put(testHolon, testLens, testData);
|
|
40
|
+
|
|
41
|
+
// Verify data exists
|
|
42
|
+
const storedData = await holoSphere.get(testHolon, testLens, testData.id);
|
|
43
|
+
expect(storedData).toBeDefined();
|
|
44
|
+
expect(storedData.value).toBe(testData.value);
|
|
45
|
+
|
|
46
|
+
// Delete data
|
|
47
|
+
const deleteResult = await holoSphere.delete(testHolon, testLens, testData.id);
|
|
48
|
+
expect(deleteResult).toBe(true);
|
|
49
|
+
|
|
50
|
+
// Verify data is deleted
|
|
51
|
+
const deletedData = await holoSphere.get(testHolon, testLens, testData.id);
|
|
52
|
+
expect(deletedData).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('should delete a node properly', async () => {
|
|
56
|
+
// Create test node data
|
|
57
|
+
const nodeData = { value: 'node-to-delete' };
|
|
58
|
+
const nodeKey = 'test-node-key';
|
|
59
|
+
|
|
60
|
+
// Store node
|
|
61
|
+
await holoSphere.putNode(testHolon, testLens, { id: nodeKey, value: nodeData });
|
|
62
|
+
|
|
63
|
+
// Verify node exists
|
|
64
|
+
const storedNode = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
65
|
+
expect(storedNode).toBeDefined();
|
|
66
|
+
|
|
67
|
+
// Delete node
|
|
68
|
+
const deleteResult = await holoSphere.deleteNode(testHolon, testLens, 'value');
|
|
69
|
+
expect(deleteResult).toBe(true);
|
|
70
|
+
|
|
71
|
+
// Verify node is deleted
|
|
72
|
+
const deletedNode = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
73
|
+
expect(deletedNode).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('Bulk Deletion', () => {
|
|
78
|
+
test('should delete all items in a lens', async () => {
|
|
79
|
+
// Create multiple test items
|
|
80
|
+
const items = [
|
|
81
|
+
{ id: 'bulk-delete-1', value: 'bulk 1' },
|
|
82
|
+
{ id: 'bulk-delete-2', value: 'bulk 2' },
|
|
83
|
+
{ id: 'bulk-delete-3', value: 'bulk 3' }
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
// Store all items
|
|
87
|
+
for (const item of items) {
|
|
88
|
+
await holoSphere.put(testHolon, testLens, item);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Verify items exist
|
|
92
|
+
const allItems = await holoSphere.getAll(testHolon, testLens);
|
|
93
|
+
expect(allItems.length).toBeGreaterThanOrEqual(items.length);
|
|
94
|
+
|
|
95
|
+
// Delete all items
|
|
96
|
+
const deleteAllResult = await holoSphere.deleteAll(testHolon, testLens);
|
|
97
|
+
expect(deleteAllResult).toBe(true);
|
|
98
|
+
|
|
99
|
+
// Verify all items are deleted
|
|
100
|
+
const remainingItems = await holoSphere.getAll(testHolon, testLens);
|
|
101
|
+
expect(remainingItems.length).toBe(0);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('Global Table Deletion', () => {
|
|
106
|
+
test('should delete global items properly', async () => {
|
|
107
|
+
// Create global test data
|
|
108
|
+
const globalData = { id: 'global-delete-test', value: 'global delete me' };
|
|
109
|
+
|
|
110
|
+
// Store global data
|
|
111
|
+
await holoSphere.putGlobal(testGlobalTable, globalData);
|
|
112
|
+
|
|
113
|
+
// Verify global data exists
|
|
114
|
+
const storedGlobalData = await holoSphere.getGlobal(testGlobalTable, globalData.id);
|
|
115
|
+
expect(storedGlobalData).toBeDefined();
|
|
116
|
+
expect(storedGlobalData.value).toBe(globalData.value);
|
|
117
|
+
|
|
118
|
+
// Delete global data
|
|
119
|
+
const deleteResult = await holoSphere.deleteGlobal(testGlobalTable, globalData.id);
|
|
120
|
+
expect(deleteResult).toBe(true);
|
|
121
|
+
|
|
122
|
+
// Verify global data is deleted
|
|
123
|
+
const deletedGlobalData = await holoSphere.getGlobal(testGlobalTable, globalData.id);
|
|
124
|
+
expect(deletedGlobalData).toBeNull();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('should delete all global items in a table', async () => {
|
|
128
|
+
// Create multiple global test items
|
|
129
|
+
const items = [
|
|
130
|
+
{ id: 'global-bulk-1', value: 'global bulk 1' },
|
|
131
|
+
{ id: 'global-bulk-2', value: 'global bulk 2' },
|
|
132
|
+
{ id: 'global-bulk-3', value: 'global bulk 3' }
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
// Store all global items
|
|
136
|
+
for (const item of items) {
|
|
137
|
+
await holoSphere.putGlobal(testGlobalTable, item);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Verify global items exist
|
|
141
|
+
const allGlobalItems = await holoSphere.getAllGlobal(testGlobalTable);
|
|
142
|
+
expect(allGlobalItems.length).toBeGreaterThanOrEqual(items.length);
|
|
143
|
+
|
|
144
|
+
// Delete all global items
|
|
145
|
+
const deleteAllResult = await holoSphere.deleteAllGlobal(testGlobalTable);
|
|
146
|
+
expect(deleteAllResult).toBe(true);
|
|
147
|
+
|
|
148
|
+
// Verify all global items are deleted
|
|
149
|
+
const remainingGlobalItems = await holoSphere.getAllGlobal(testGlobalTable);
|
|
150
|
+
expect(remainingGlobalItems.length).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('Private Data Deletion', () => {
|
|
155
|
+
test('should delete private data properly', async () => {
|
|
156
|
+
// Create private test data
|
|
157
|
+
const privateData = { id: 'private-delete-test', value: 'private delete me' };
|
|
158
|
+
|
|
159
|
+
// Store private data
|
|
160
|
+
await holoSphere.put(testHolon, testLens, privateData, testPassword);
|
|
161
|
+
|
|
162
|
+
// Verify private data exists
|
|
163
|
+
const storedPrivateData = await holoSphere.get(testHolon, testLens, privateData.id, testPassword);
|
|
164
|
+
expect(storedPrivateData).toBeDefined();
|
|
165
|
+
expect(storedPrivateData.value).toBe(privateData.value);
|
|
166
|
+
|
|
167
|
+
// Delete private data
|
|
168
|
+
const deleteResult = await holoSphere.delete(testHolon, testLens, privateData.id, testPassword);
|
|
169
|
+
expect(deleteResult).toBe(true);
|
|
170
|
+
|
|
171
|
+
// Verify private data is deleted
|
|
172
|
+
const deletedPrivateData = await holoSphere.get(testHolon, testLens, privateData.id, testPassword);
|
|
173
|
+
expect(deletedPrivateData).toBeNull();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('should delete all private items in a lens', async () => {
|
|
177
|
+
// Create multiple private test items
|
|
178
|
+
const items = [
|
|
179
|
+
{ id: 'private-bulk-1', value: 'private bulk 1' },
|
|
180
|
+
{ id: 'private-bulk-2', value: 'private bulk 2' },
|
|
181
|
+
{ id: 'private-bulk-3', value: 'private bulk 3' }
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
// Store all private items
|
|
185
|
+
for (const item of items) {
|
|
186
|
+
await holoSphere.put(testHolon, testLens, item, testPassword);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Verify private items exist
|
|
190
|
+
const allPrivateItems = await holoSphere.getAll(testHolon, testLens, testPassword);
|
|
191
|
+
expect(allPrivateItems.length).toBeGreaterThanOrEqual(items.length);
|
|
192
|
+
|
|
193
|
+
// Delete all private items
|
|
194
|
+
const deleteAllResult = await holoSphere.deleteAll(testHolon, testLens, testPassword);
|
|
195
|
+
expect(deleteAllResult).toBe(true);
|
|
196
|
+
|
|
197
|
+
// Verify all private items are deleted
|
|
198
|
+
const remainingPrivateItems = await holoSphere.getAll(testHolon, testLens, testPassword);
|
|
199
|
+
expect(remainingPrivateItems.length).toBe(0);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('Edge Cases', () => {
|
|
204
|
+
test('should handle deletion of non-existent items gracefully', async () => {
|
|
205
|
+
// Try to delete non-existent item
|
|
206
|
+
const deleteResult = await holoSphere.delete(testHolon, testLens, 'non-existent-id');
|
|
207
|
+
expect(deleteResult).toBe(true); // Gun returns success even for non-existent items
|
|
208
|
+
|
|
209
|
+
// Try to delete non-existent global item
|
|
210
|
+
const deleteGlobalResult = await holoSphere.deleteGlobal(testGlobalTable, 'non-existent-global-id');
|
|
211
|
+
expect(deleteGlobalResult).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test('should handle invalid parameters gracefully', async () => {
|
|
215
|
+
// Test with missing parameters
|
|
216
|
+
await expect(holoSphere.delete(null, testLens, 'test-id')).rejects.toThrow();
|
|
217
|
+
await expect(holoSphere.delete(testHolon, null, 'test-id')).rejects.toThrow();
|
|
218
|
+
await expect(holoSphere.delete(testHolon, testLens, null)).rejects.toThrow();
|
|
219
|
+
|
|
220
|
+
// Test with missing global parameters
|
|
221
|
+
await expect(holoSphere.deleteGlobal(null, 'test-id')).rejects.toThrow();
|
|
222
|
+
await expect(holoSphere.deleteGlobal(testGlobalTable, null)).rejects.toThrow();
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
package/test/federation.test.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import HoloSphere from '../holosphere.js';
|
|
2
2
|
import { jest } from '@jest/globals';
|
|
3
3
|
|
|
4
|
+
// Increase the default test timeout for all tests
|
|
5
|
+
jest.setTimeout(30000);
|
|
6
|
+
|
|
4
7
|
describe('Federation Tests', () => {
|
|
5
8
|
let holosphere;
|
|
6
9
|
const testPrefix = `test_${Date.now()}_`;
|
|
@@ -36,6 +39,50 @@ describe('Federation Tests', () => {
|
|
|
36
39
|
}
|
|
37
40
|
});
|
|
38
41
|
|
|
42
|
+
test('should set up the correct notification structure', async () => {
|
|
43
|
+
const space1 = `${testPrefix}notify_space1`;
|
|
44
|
+
const space2 = `${testPrefix}notify_space2`;
|
|
45
|
+
|
|
46
|
+
// Create federation
|
|
47
|
+
await holosphere.federate(space1, space2, null, null);
|
|
48
|
+
|
|
49
|
+
// Allow time for federation to be created
|
|
50
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
51
|
+
|
|
52
|
+
// In the current implementation:
|
|
53
|
+
// space1's federation list should contain space2
|
|
54
|
+
// space2's notify list should contain space1
|
|
55
|
+
const fedInfo1 = await holosphere.getGlobal('federation', space1);
|
|
56
|
+
expect(fedInfo1).toBeTruthy();
|
|
57
|
+
expect(fedInfo1.federation).toContain(space2);
|
|
58
|
+
|
|
59
|
+
const fedInfo2 = await holosphere.getGlobal('federation', space2);
|
|
60
|
+
expect(fedInfo2).toBeTruthy();
|
|
61
|
+
expect(fedInfo2.notify).toContain(space1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('should respect unidirectional settings', async () => {
|
|
65
|
+
const space1 = `${testPrefix}one_way_space1`;
|
|
66
|
+
const space2 = `${testPrefix}one_way_space2`;
|
|
67
|
+
|
|
68
|
+
// Create federation with bidirectional=false
|
|
69
|
+
await holosphere.federate(space1, space2, null, null, false);
|
|
70
|
+
|
|
71
|
+
// Allow time for federation to be created
|
|
72
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
73
|
+
|
|
74
|
+
// Verify federation structure:
|
|
75
|
+
// space1 has space2 in federation list
|
|
76
|
+
// space2 has space1 in notify list (this is different from the original test)
|
|
77
|
+
const fedInfo1 = await holosphere.getGlobal('federation', space1);
|
|
78
|
+
expect(fedInfo1).toBeTruthy();
|
|
79
|
+
expect(fedInfo1.federation).toContain(space2);
|
|
80
|
+
|
|
81
|
+
const fedInfo2 = await holosphere.getGlobal('federation', space2);
|
|
82
|
+
expect(fedInfo2).toBeTruthy();
|
|
83
|
+
expect(fedInfo2.notify).toContain(space1);
|
|
84
|
+
});
|
|
85
|
+
|
|
39
86
|
test('should throw error when trying to federate a space with itself', async () => {
|
|
40
87
|
const space = `${testPrefix}self_fed_space`;
|
|
41
88
|
await expect(holosphere.federate(space, space, null))
|
|
@@ -107,16 +154,17 @@ describe('Federation Tests', () => {
|
|
|
107
154
|
});
|
|
108
155
|
});
|
|
109
156
|
|
|
110
|
-
describe('
|
|
157
|
+
describe('propagate', () => {
|
|
111
158
|
test('should handle propagation to non-federated space gracefully', async () => {
|
|
112
159
|
const space = `${testPrefix}no_fed_space`;
|
|
113
160
|
const data = { id: 'test-item', value: 42 };
|
|
114
161
|
|
|
115
162
|
// Try to propagate to a space with no federation
|
|
116
|
-
const result = await holosphere.
|
|
163
|
+
const result = await holosphere.propagate(space, 'items', data);
|
|
117
164
|
|
|
118
165
|
// Should have a message property but not fail
|
|
119
166
|
expect(result).toBeDefined();
|
|
167
|
+
expect(result.message).toBeDefined();
|
|
120
168
|
});
|
|
121
169
|
});
|
|
122
170
|
});
|
|
File without changes
|