holosphere 1.1.11 → 1.1.12

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.
@@ -0,0 +1,143 @@
1
+ // hologram-updates.test.js
2
+
3
+ import HoloSphere from '../holosphere.js';
4
+
5
+ describe('Hologram Update Tests', () => {
6
+ let holoSphere;
7
+ const testHolon = 'updateTestHolon';
8
+ const testLens = 'testLens';
9
+ const otherLens = 'otherLens';
10
+ const appName = 'test-hologram-update-app';
11
+
12
+ const waitForGun = (ms = 300) => new Promise(resolve => setTimeout(resolve, ms));
13
+
14
+ beforeEach(async () => {
15
+ holoSphere = new HoloSphere(appName, false);
16
+ // Clean up before each test
17
+ try {
18
+ await holoSphere.deleteAll(testHolon, testLens);
19
+ await holoSphere.deleteAll(testHolon, otherLens);
20
+ } catch (error) {
21
+ // Ignore cleanup errors
22
+ }
23
+
24
+ await waitForGun(100);
25
+ }, 30000);
26
+
27
+ afterEach(async () => {
28
+ if (holoSphere) {
29
+ await holoSphere.close();
30
+ }
31
+ }, 30000);
32
+
33
+ test('should update active holograms when original data is modified', async () => {
34
+ // 1. Store original data
35
+ const originalData = { id: 'update-test-item', value: 'Original Value', count: 1 };
36
+ await holoSphere.put(testHolon, testLens, originalData);
37
+ await waitForGun();
38
+
39
+ // 2. Create and store a hologram pointing to the original data
40
+ const hologram = holoSphere.createHologram(testHolon, testLens, originalData);
41
+ await holoSphere.put(testHolon, otherLens, hologram); // Store hologram in different lens
42
+ await waitForGun(500);
43
+
44
+ // 3. Get the hologram before update (should not have 'updated' field)
45
+ const hologramBeforeUpdate = await holoSphere.get(testHolon, otherLens, originalData.id, null, { resolveHolograms: false });
46
+ expect(hologramBeforeUpdate).toBeDefined();
47
+ expect(hologramBeforeUpdate.soul).toBe(hologram.soul);
48
+ expect(hologramBeforeUpdate.updated).toBeUndefined();
49
+
50
+ // 4. Update the original data
51
+ const updatedData = { id: 'update-test-item', value: 'Updated Value', count: 2 };
52
+ await holoSphere.put(testHolon, testLens, updatedData);
53
+ await waitForGun(1000); // Give time for hologram updates to propagate
54
+
55
+ // 5. Check that the hologram now has an 'updated' timestamp
56
+ const hologramAfterUpdate = await holoSphere.get(testHolon, otherLens, originalData.id, null, { resolveHolograms: false });
57
+ expect(hologramAfterUpdate).toBeDefined();
58
+ expect(hologramAfterUpdate.soul).toBe(hologram.soul);
59
+ expect(hologramAfterUpdate.updated).toBeDefined();
60
+ expect(typeof hologramAfterUpdate.updated).toBe('number');
61
+ expect(hologramAfterUpdate.updated).toBeGreaterThan(Date.now() - 5000); // Should be recent
62
+
63
+ // 6. Verify that resolving the hologram gives the updated data
64
+ const resolvedData = await holoSphere.get(testHolon, otherLens, originalData.id);
65
+ expect(resolvedData).toBeDefined();
66
+ expect(resolvedData.value).toBe('Updated Value');
67
+ expect(resolvedData.count).toBe(2);
68
+ });
69
+
70
+ test('should update multiple holograms pointing to the same data', async () => {
71
+ // 1. Store original data
72
+ const originalData = { id: 'multi-hologram-test', value: 'Original Value' };
73
+ await holoSphere.put(testHolon, testLens, originalData);
74
+ await waitForGun();
75
+
76
+ // 2. Create and store multiple holograms pointing to the same data
77
+ const hologram1 = holoSphere.createHologram(testHolon, testLens, originalData);
78
+ const hologram2 = holoSphere.createHologram(testHolon, testLens, originalData);
79
+
80
+ await holoSphere.put(testHolon, otherLens, { ...hologram1, id: 'hologram-1' });
81
+ await holoSphere.put(testHolon, otherLens, { ...hologram2, id: 'hologram-2' });
82
+ await waitForGun(500);
83
+
84
+ // 3. Update the original data
85
+ const updatedData = { id: 'multi-hologram-test', value: 'Updated Value' };
86
+ await holoSphere.put(testHolon, testLens, updatedData);
87
+ await waitForGun(1000);
88
+
89
+ // 4. Check that both holograms have been updated
90
+ const updatedHologram1 = await holoSphere.get(testHolon, otherLens, 'hologram-1', null, { resolveHolograms: false });
91
+ const updatedHologram2 = await holoSphere.get(testHolon, otherLens, 'hologram-2', null, { resolveHolograms: false });
92
+
93
+ expect(updatedHologram1.updated).toBeDefined();
94
+ expect(updatedHologram2.updated).toBeDefined();
95
+ expect(typeof updatedHologram1.updated).toBe('number');
96
+ expect(typeof updatedHologram2.updated).toBe('number');
97
+ });
98
+
99
+ test('should not update deleted holograms', async () => {
100
+ // 1. Store original data
101
+ const originalData = { id: 'delete-test-item', value: 'Original Value' };
102
+ await holoSphere.put(testHolon, testLens, originalData);
103
+ await waitForGun();
104
+
105
+ // 2. Create and store a hologram
106
+ const hologram = holoSphere.createHologram(testHolon, testLens, originalData);
107
+ await holoSphere.put(testHolon, otherLens, hologram);
108
+ await waitForGun(500);
109
+
110
+ // 3. Delete the hologram
111
+ await holoSphere.delete(testHolon, otherLens, originalData.id);
112
+ await waitForGun(500);
113
+
114
+ // 4. Update the original data
115
+ const updatedData = { id: 'delete-test-item', value: 'Updated Value' };
116
+ await holoSphere.put(testHolon, testLens, updatedData);
117
+ await waitForGun(1000);
118
+
119
+ // 5. Verify the original data was updated
120
+ const retrievedData = await holoSphere.get(testHolon, testLens, originalData.id);
121
+ expect(retrievedData.value).toBe('Updated Value');
122
+
123
+ // 6. Verify the hologram was not updated (since it's deleted)
124
+ const deletedHologram = await holoSphere.get(testHolon, otherLens, originalData.id);
125
+ expect(deletedHologram).toBeNull(); // Should be null since it was deleted
126
+ });
127
+
128
+ test('should work with data that has no holograms', async () => {
129
+ // 1. Store data that has no holograms pointing to it
130
+ const originalData = { id: 'no-holograms-test', value: 'Original Value' };
131
+ await holoSphere.put(testHolon, testLens, originalData);
132
+ await waitForGun();
133
+
134
+ // 2. Update the data (should not cause errors even with no holograms)
135
+ const updatedData = { id: 'no-holograms-test', value: 'Updated Value' };
136
+ await holoSphere.put(testHolon, testLens, updatedData);
137
+ await waitForGun(1000);
138
+
139
+ // 3. Verify the data was updated successfully
140
+ const retrievedData = await holoSphere.get(testHolon, testLens, originalData.id);
141
+ expect(retrievedData.value).toBe('Updated Value');
142
+ });
143
+ });
@@ -297,7 +297,7 @@ describe('HoloSphere Reference System', () => {
297
297
  const targetNodeRef = holoSphere.getNodeRef(targetSoul);
298
298
  let hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
299
299
  expect(hologramsSet).toBeDefined();
300
- expect(hologramsSet[storedHologramSoul]).toBe(true);
300
+ expect(hologramsSet[storedHologramSoul]).toBeDefined(); // Hologram should be tracked initially
301
301
 
302
302
  // 4. Delete the hologram
303
303
  await holoSphere.delete(testHolon, 'otherLens', 'hologram-tracker-2');
@@ -307,9 +307,9 @@ describe('HoloSphere Reference System', () => {
307
307
  // 5. Fetch the _holograms set again directly
308
308
  hologramsSet = await new Promise(resolve => targetNodeRef.get('_holograms').once(resolve));
309
309
 
310
- // 6. Verify the hologram's soul is marked as 'DELETED'
310
+ // 6. Verify the hologram's soul is completely removed (or set to null by Gun)
311
311
  expect(hologramsSet).toBeDefined();
312
- expect(hologramsSet[storedHologramSoul]).toBe('DELETED'); // <-- Expect 'DELETED' string
312
+ expect(hologramsSet[storedHologramSoul]).toBeNull(); // Gun stores null when we put(null)
313
313
  });
314
314
  // --- End tests for _holograms tracking ---
315
315
 
@@ -0,0 +1,159 @@
1
+ // meta-strip.test.js
2
+
3
+ import HoloSphere from '../holosphere.js';
4
+
5
+ describe('Meta Field Stripping Tests', () => {
6
+ let holoSphere;
7
+ const testHolon = 'testHolon';
8
+ const testLens = 'testLens';
9
+ const testGlobalTable = 'testGlobalTable';
10
+
11
+ beforeEach(async () => {
12
+ holoSphere = new HoloSphere('test_app', false);
13
+ // Clean up before each test
14
+ try {
15
+ await holoSphere.deleteAll(testHolon, testLens);
16
+ await holoSphere.deleteAllGlobal(testGlobalTable);
17
+ } catch (error) {
18
+ // Ignore cleanup errors
19
+ }
20
+
21
+ // Small wait for Gun to settle
22
+ await new Promise(resolve => setTimeout(resolve, 100));
23
+ }, 30000);
24
+
25
+ afterEach(async () => {
26
+ if (holoSphere) {
27
+ await holoSphere.close();
28
+ }
29
+ }, 30000);
30
+
31
+ describe('put() should strip _meta field', () => {
32
+ test('should not store _meta field when putting data', async () => {
33
+ const testData = {
34
+ id: 'test1',
35
+ name: 'Test Item',
36
+ value: 42,
37
+ _meta: {
38
+ resolvedFromHologram: true,
39
+ hologramSoul: 'app/holon/lens/key',
40
+ someOtherMeta: 'should not be stored'
41
+ }
42
+ };
43
+
44
+ // Store the data (should strip _meta)
45
+ await holoSphere.put(testHolon, testLens, testData);
46
+
47
+ // Wait for Gun to settle
48
+ await new Promise(resolve => setTimeout(resolve, 500));
49
+
50
+ // Retrieve the data
51
+ const retrieved = await holoSphere.get(testHolon, testLens, testData.id);
52
+
53
+ // Verify data exists and _meta is not stored
54
+ expect(retrieved).not.toBeNull();
55
+ expect(retrieved.id).toBe(testData.id);
56
+ expect(retrieved.name).toBe(testData.name);
57
+ expect(retrieved.value).toBe(testData.value);
58
+ expect(retrieved._meta).toBeUndefined(); // _meta should not be stored
59
+ });
60
+
61
+ test('should handle data without _meta field normally', async () => {
62
+ const testData = {
63
+ id: 'test2',
64
+ name: 'Test Item Without Meta',
65
+ value: 99
66
+ };
67
+
68
+ // Store the data
69
+ await holoSphere.put(testHolon, testLens, testData);
70
+
71
+ // Wait for Gun to settle
72
+ await new Promise(resolve => setTimeout(resolve, 500));
73
+
74
+ // Retrieve the data
75
+ const retrieved = await holoSphere.get(testHolon, testLens, testData.id);
76
+
77
+ // Verify data exists and matches exactly
78
+ expect(retrieved).toEqual(testData);
79
+ expect(retrieved._meta).toBeUndefined();
80
+ });
81
+ });
82
+
83
+ describe('putGlobal() should strip _meta field', () => {
84
+ test('should not store _meta field when putting global data', async () => {
85
+ const testData = {
86
+ id: 'globaltest1',
87
+ name: 'Global Test Item',
88
+ value: 123,
89
+ _meta: {
90
+ resolvedFromHologram: true,
91
+ hologramSoul: 'app/holon/lens/key',
92
+ federation: { origin: 'someholon' }
93
+ }
94
+ };
95
+
96
+ // Store the global data (should strip _meta)
97
+ await holoSphere.putGlobal(testGlobalTable, testData);
98
+
99
+ // Wait for Gun to settle
100
+ await new Promise(resolve => setTimeout(resolve, 500));
101
+
102
+ // Retrieve the data
103
+ const retrieved = await holoSphere.getGlobal(testGlobalTable, testData.id);
104
+
105
+ // Verify data exists and _meta is not stored
106
+ expect(retrieved).not.toBeNull();
107
+ expect(retrieved.id).toBe(testData.id);
108
+ expect(retrieved.name).toBe(testData.name);
109
+ expect(retrieved.value).toBe(testData.value);
110
+ expect(retrieved._meta).toBeUndefined(); // _meta should not be stored
111
+ });
112
+
113
+ test('should handle global data without _meta field normally', async () => {
114
+ const testData = {
115
+ id: 'globaltest2',
116
+ name: 'Global Test Item Without Meta',
117
+ value: 456
118
+ };
119
+
120
+ // Store the global data
121
+ await holoSphere.putGlobal(testGlobalTable, testData);
122
+
123
+ // Wait for Gun to settle
124
+ await new Promise(resolve => setTimeout(resolve, 500));
125
+
126
+ // Retrieve the data
127
+ const retrieved = await holoSphere.getGlobal(testGlobalTable, testData.id);
128
+
129
+ // Verify data exists and matches exactly
130
+ expect(retrieved).toEqual(testData);
131
+ expect(retrieved._meta).toBeUndefined();
132
+ });
133
+ });
134
+
135
+ test('should preserve _meta in original data object (not mutate input)', async () => {
136
+ const testData = {
137
+ id: 'test3',
138
+ name: 'Test Mutation',
139
+ _meta: {
140
+ resolvedFromHologram: true,
141
+ hologramSoul: 'app/holon/lens/key'
142
+ }
143
+ };
144
+
145
+ // Store a copy to verify original isn't mutated
146
+ const originalMeta = { ...testData._meta };
147
+
148
+ // Store the data
149
+ await holoSphere.put(testHolon, testLens, testData);
150
+
151
+ // Verify the original object still has _meta (we shouldn't mutate the input)
152
+ expect(testData._meta).toBeDefined();
153
+ expect(testData._meta).toEqual(originalMeta);
154
+
155
+ // But the stored data should not have _meta
156
+ const retrieved = await holoSphere.get(testHolon, testLens, testData.id);
157
+ expect(retrieved._meta).toBeUndefined();
158
+ });
159
+ });
@@ -0,0 +1,138 @@
1
+ import HoloSphere from '../holosphere.js';
2
+
3
+ describe('Parent Propagation Tests', () => {
4
+ let holosphere;
5
+ const testPrefix = 'parent_prop_test_';
6
+
7
+ beforeEach(() => {
8
+ holosphere = new HoloSphere('parent-propagation-test');
9
+ });
10
+
11
+ afterEach(async () => {
12
+ if (holosphere) {
13
+ await holosphere.close();
14
+ }
15
+ });
16
+
17
+ describe('propagate with parent propagation', () => {
18
+ test('should propagate to parent hexagons when holon is valid H3 hexagon', async () => {
19
+ // Create a valid H3 hexagon (resolution 7)
20
+ const childHexagon = '87283472bffffff'; // Example H3 hexagon at resolution 7
21
+ const parentHexagon = '86283472fffffff'; // Parent at resolution 6
22
+
23
+ // Test data
24
+ const testData = {
25
+ id: 'test-item-1',
26
+ title: 'Test Item',
27
+ value: 42
28
+ };
29
+
30
+ // Propagate with parent propagation enabled
31
+ const result = await holosphere.propagate(childHexagon, 'items', testData, {
32
+ propagateToParents: true,
33
+ maxParentLevels: 5
34
+ });
35
+
36
+ // Check that parent propagation was attempted
37
+ expect(result.parentPropagation).toBeDefined();
38
+ expect(result.parentPropagation.success).toBeGreaterThan(0);
39
+ expect(result.parentPropagation.messages).toEqual(
40
+ expect.arrayContaining([expect.stringContaining('parent hexagons to propagate to')])
41
+ );
42
+
43
+ // Allow time for propagation
44
+ await new Promise(resolve => setTimeout(resolve, 1000));
45
+
46
+ // Verify data was propagated to parent hexagon (check for hologram, not resolved data)
47
+ const parentHologram = await holosphere.get(parentHexagon, 'items', testData.id, null, { resolveHolograms: false });
48
+ expect(parentHologram).toBeDefined();
49
+ expect(parentHologram._federation.propagationType).toBe('parent');
50
+ });
51
+
52
+ test('should skip parent propagation for non-H3 hexagons', async () => {
53
+ // Use a non-H3 hexagon identifier
54
+ const nonHexagonHolon = 'not-a-hexagon';
55
+
56
+ const testData = {
57
+ id: 'test-item-2',
58
+ title: 'Test Item',
59
+ value: 42
60
+ };
61
+
62
+ const result = await holosphere.propagate(nonHexagonHolon, 'items', testData, {
63
+ propagateToParents: true
64
+ });
65
+
66
+ expect(result.parentPropagation).toBeDefined();
67
+ expect(result.parentPropagation.skipped).toBe(1);
68
+ expect(result.parentPropagation.messages).toEqual(
69
+ expect.arrayContaining([expect.stringContaining('No parent hexagons found')])
70
+ );
71
+ });
72
+
73
+ test('should respect maxParentLevels option', async () => {
74
+ const childHexagon = '87283472bffffff'; // Resolution 7
75
+
76
+ const testData = {
77
+ id: 'test-item-3',
78
+ title: 'Test Item',
79
+ value: 42
80
+ };
81
+
82
+ const result = await holosphere.propagate(childHexagon, 'items', testData, {
83
+ propagateToParents: true,
84
+ maxParentLevels: 2 // Only propagate to 2 parent levels
85
+ });
86
+
87
+ expect(result.parentPropagation).toBeDefined();
88
+ expect(result.parentPropagation.success).toBe(2); // Should propagate to 2 parent levels
89
+ });
90
+
91
+ test('should disable parent propagation when propagateToParents is false', async () => {
92
+ const childHexagon = '87283472bffffff';
93
+
94
+ const testData = {
95
+ id: 'test-item-4',
96
+ title: 'Test Item',
97
+ value: 42
98
+ };
99
+
100
+ const result = await holosphere.propagate(childHexagon, 'items', testData, {
101
+ propagateToParents: false
102
+ });
103
+
104
+ expect(result.parentPropagation).toBeDefined();
105
+ expect(result.parentPropagation.success).toBe(0);
106
+ expect(result.parentPropagation.skipped).toBe(0);
107
+ });
108
+
109
+ test('should include parent level information in federation metadata', async () => {
110
+ const childHexagon = '87283472bffffff'; // Resolution 7
111
+ const parentHexagon = '86283472fffffff'; // Resolution 6
112
+
113
+ const testData = {
114
+ id: 'test-item-5',
115
+ title: 'Test Item',
116
+ value: 42
117
+ };
118
+
119
+ // First, store the original data in the child hexagon
120
+ await holosphere.put(childHexagon, 'items', testData);
121
+
122
+ // Then propagate to parent
123
+ await holosphere.propagate(childHexagon, 'items', testData, {
124
+ propagateToParents: true,
125
+ maxParentLevels: 1
126
+ });
127
+
128
+ // Allow time for propagation
129
+ await new Promise(resolve => setTimeout(resolve, 1000));
130
+
131
+ // Check parent data has correct metadata (check for hologram, not resolved data)
132
+ const parentHologram = await holosphere.get(parentHexagon, 'items', testData.id, null, { resolveHolograms: false });
133
+ expect(parentHologram).toBeDefined();
134
+ expect(parentHologram._federation.propagationType).toBe('parent');
135
+ expect(parentHologram._federation.parentLevel).toBe(1); // 1 level up from resolution 7 to 6
136
+ });
137
+ });
138
+ });