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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holosphere",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "description": "Holonic Geospatial Communication Infrastructure",
5
5
  "main": "holosphere.js",
6
6
  "types": "holosphere.d.ts",
@@ -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&parameterCd=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`,
@@ -1,11 +1,5 @@
1
1
  import { jest } from '@jest/globals';
2
2
 
3
- // Mock axios before importing the modules that use it
4
- jest.mock('axios', () => ({
5
- default: {
6
- get: jest.fn()
7
- }
8
- }));
9
3
 
10
4
  // Import axios after mocking
11
5
  import axios from 'axios';
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.propagateToFederation(testHolon, testLens, updatedData);
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.propagateToFederation(testHolon, testLens, testData);
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
+ });
@@ -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('propagateToFederation', () => {
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.propagateToFederation(space, 'items', data);
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