holosphere 2.0.0-alpha1 → 2.0.0-alpha4

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.
Files changed (154) hide show
  1. package/dist/2019-D2OG2idw.js +6680 -0
  2. package/dist/2019-D2OG2idw.js.map +1 -0
  3. package/dist/2019-EION3wKo.cjs +8 -0
  4. package/dist/2019-EION3wKo.cjs.map +1 -0
  5. package/dist/_commonjsHelpers-C37NGDzP.cjs +2 -0
  6. package/dist/_commonjsHelpers-C37NGDzP.cjs.map +1 -0
  7. package/dist/_commonjsHelpers-CUmg6egw.js +7 -0
  8. package/dist/_commonjsHelpers-CUmg6egw.js.map +1 -0
  9. package/dist/browser-BSniCNqO.js +3058 -0
  10. package/dist/browser-BSniCNqO.js.map +1 -0
  11. package/dist/browser-Cq59Ij19.cjs +2 -0
  12. package/dist/browser-Cq59Ij19.cjs.map +1 -0
  13. package/dist/cjs/holosphere.cjs +2 -0
  14. package/dist/cjs/holosphere.cjs.map +1 -0
  15. package/dist/esm/holosphere.js +53 -0
  16. package/dist/esm/holosphere.js.map +1 -0
  17. package/dist/index-BB_vVJgv.cjs +5 -0
  18. package/dist/index-BB_vVJgv.cjs.map +1 -0
  19. package/dist/index-CBitK71M.cjs +12 -0
  20. package/dist/index-CBitK71M.cjs.map +1 -0
  21. package/dist/index-CV0eOogK.js +37423 -0
  22. package/dist/index-CV0eOogK.js.map +1 -0
  23. package/dist/index-Cz-PLCUR.js +15104 -0
  24. package/dist/index-Cz-PLCUR.js.map +1 -0
  25. package/dist/indexeddb-storage-CRsZyB2f.cjs +2 -0
  26. package/dist/indexeddb-storage-CRsZyB2f.cjs.map +1 -0
  27. package/dist/indexeddb-storage-DZaGlY_a.js +132 -0
  28. package/dist/indexeddb-storage-DZaGlY_a.js.map +1 -0
  29. package/dist/memory-storage-BkUi6sZG.js +51 -0
  30. package/dist/memory-storage-BkUi6sZG.js.map +1 -0
  31. package/dist/memory-storage-C0DuUsdY.cjs +2 -0
  32. package/dist/memory-storage-C0DuUsdY.cjs.map +1 -0
  33. package/dist/secp256k1-0kPdAVkK.cjs +12 -0
  34. package/dist/secp256k1-0kPdAVkK.cjs.map +1 -0
  35. package/dist/secp256k1-DN4FVXcv.js +1890 -0
  36. package/dist/secp256k1-DN4FVXcv.js.map +1 -0
  37. package/docs/CONTRACTS.md +797 -0
  38. package/docs/FOSDEM_PROPOSAL.md +388 -0
  39. package/docs/LOCALFIRST.md +266 -0
  40. package/docs/contracts/api-interface.md +793 -0
  41. package/docs/data-model.md +476 -0
  42. package/docs/gun-async-usage.md +338 -0
  43. package/docs/plan.md +349 -0
  44. package/docs/quickstart.md +674 -0
  45. package/docs/research.md +362 -0
  46. package/docs/spec.md +244 -0
  47. package/docs/storage-backends.md +326 -0
  48. package/docs/tasks.md +947 -0
  49. package/examples/demo.html +47 -0
  50. package/package.json +10 -5
  51. package/src/contracts/abis/Appreciative.json +1280 -0
  52. package/src/contracts/abis/AppreciativeFactory.json +101 -0
  53. package/src/contracts/abis/Bundle.json +1435 -0
  54. package/src/contracts/abis/BundleFactory.json +106 -0
  55. package/src/contracts/abis/Holon.json +881 -0
  56. package/src/contracts/abis/Holons.json +330 -0
  57. package/src/contracts/abis/Managed.json +1262 -0
  58. package/src/contracts/abis/ManagedFactory.json +149 -0
  59. package/src/contracts/abis/Membrane.json +261 -0
  60. package/src/contracts/abis/Splitter.json +1624 -0
  61. package/src/contracts/abis/SplitterFactory.json +220 -0
  62. package/src/contracts/abis/TestToken.json +321 -0
  63. package/src/contracts/abis/Zoned.json +1461 -0
  64. package/src/contracts/abis/ZonedFactory.json +154 -0
  65. package/src/contracts/chain-manager.js +375 -0
  66. package/src/contracts/deployer.js +443 -0
  67. package/src/contracts/event-listener.js +507 -0
  68. package/src/contracts/holon-contracts.js +344 -0
  69. package/src/contracts/index.js +83 -0
  70. package/src/contracts/networks.js +224 -0
  71. package/src/contracts/operations.js +670 -0
  72. package/src/contracts/queries.js +589 -0
  73. package/src/core/holosphere.js +453 -1
  74. package/src/crypto/nostr-utils.js +263 -0
  75. package/src/federation/handshake.js +455 -0
  76. package/src/federation/hologram.js +1 -1
  77. package/src/hierarchical/upcast.js +6 -5
  78. package/src/index.js +463 -1939
  79. package/src/lib/ai-methods.js +308 -0
  80. package/src/lib/contract-methods.js +293 -0
  81. package/src/lib/errors.js +23 -0
  82. package/src/lib/federation-methods.js +238 -0
  83. package/src/lib/index.js +26 -0
  84. package/src/spatial/h3-operations.js +2 -2
  85. package/src/storage/backends/gundb-backend.js +377 -46
  86. package/src/storage/global-tables.js +28 -1
  87. package/src/storage/gun-auth.js +303 -0
  88. package/src/storage/gun-federation.js +776 -0
  89. package/src/storage/gun-references.js +198 -0
  90. package/src/storage/gun-schema.js +291 -0
  91. package/src/storage/gun-wrapper.js +347 -31
  92. package/src/storage/indexeddb-storage.js +49 -11
  93. package/src/storage/memory-storage.js +5 -0
  94. package/src/storage/nostr-async.js +45 -23
  95. package/src/storage/nostr-client.js +11 -5
  96. package/src/storage/persistent-storage.js +6 -1
  97. package/src/storage/unified-storage.js +119 -0
  98. package/src/subscriptions/manager.js +1 -1
  99. package/types/index.d.ts +133 -0
  100. package/tests/unit/ai/aggregation.test.js +0 -295
  101. package/tests/unit/ai/breakdown.test.js +0 -446
  102. package/tests/unit/ai/classifier.test.js +0 -294
  103. package/tests/unit/ai/council.test.js +0 -262
  104. package/tests/unit/ai/embeddings.test.js +0 -384
  105. package/tests/unit/ai/federation-ai.test.js +0 -344
  106. package/tests/unit/ai/h3-ai.test.js +0 -458
  107. package/tests/unit/ai/index.test.js +0 -304
  108. package/tests/unit/ai/json-ops.test.js +0 -307
  109. package/tests/unit/ai/llm-service.test.js +0 -390
  110. package/tests/unit/ai/nl-query.test.js +0 -383
  111. package/tests/unit/ai/relationships.test.js +0 -311
  112. package/tests/unit/ai/schema-extractor.test.js +0 -384
  113. package/tests/unit/ai/spatial.test.js +0 -279
  114. package/tests/unit/ai/tts.test.js +0 -279
  115. package/tests/unit/content.test.js +0 -332
  116. package/tests/unit/contract/core.test.js +0 -88
  117. package/tests/unit/contract/crypto.test.js +0 -198
  118. package/tests/unit/contract/data.test.js +0 -223
  119. package/tests/unit/contract/federation.test.js +0 -181
  120. package/tests/unit/contract/hierarchical.test.js +0 -113
  121. package/tests/unit/contract/schema.test.js +0 -114
  122. package/tests/unit/contract/social.test.js +0 -217
  123. package/tests/unit/contract/spatial.test.js +0 -110
  124. package/tests/unit/contract/subscriptions.test.js +0 -128
  125. package/tests/unit/contract/utils.test.js +0 -159
  126. package/tests/unit/core.test.js +0 -152
  127. package/tests/unit/crypto.test.js +0 -328
  128. package/tests/unit/federation.test.js +0 -234
  129. package/tests/unit/gun-async.test.js +0 -252
  130. package/tests/unit/hierarchical.test.js +0 -399
  131. package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
  132. package/tests/unit/integration/scenario-02-federation.test.js +0 -76
  133. package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
  134. package/tests/unit/integration/scenario-04-validation.test.js +0 -129
  135. package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
  136. package/tests/unit/integration/scenario-06-social.test.js +0 -135
  137. package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
  138. package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
  139. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
  140. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
  141. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
  142. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
  143. package/tests/unit/performance/benchmark.test.js +0 -85
  144. package/tests/unit/schema.test.js +0 -213
  145. package/tests/unit/spatial.test.js +0 -158
  146. package/tests/unit/storage.test.js +0 -195
  147. package/tests/unit/subscriptions.test.js +0 -328
  148. package/tests/unit/test-data-permanence-debug.js +0 -197
  149. package/tests/unit/test-data-permanence.js +0 -340
  150. package/tests/unit/test-key-persistence-fixed.js +0 -148
  151. package/tests/unit/test-key-persistence.js +0 -172
  152. package/tests/unit/test-relay-permanence.js +0 -376
  153. package/tests/unit/test-second-node.js +0 -95
  154. package/tests/unit/test-simple-write.js +0 -89
@@ -1,234 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../src/index.js';
3
-
4
- describe('Unit: Federation Module', () => {
5
- let hs;
6
- let sourceHolon;
7
- let targetHolon;
8
-
9
- beforeEach(async () => {
10
- hs = new HoloSphere({ relays: [], appName: 'test-federation-unit', persistence: false });
11
- sourceHolon = await hs.toHolon(37.7749, -122.4194, 10);
12
- targetHolon = await hs.toHolon(37.7749, -122.4194, 8);
13
- });
14
-
15
- describe('Hologram creation (reference structure)', () => {
16
- it('should create hologram with reference structure', async () => {
17
- await hs.write(sourceHolon, 'test', { id: 'item-1', value: 'data' });
18
-
19
- await hs.federate(sourceHolon, targetHolon, 'test', {
20
- mode: 'reference'
21
- });
22
-
23
- // Hologram should reference original data
24
- const fedData = await hs.getFederatedData(targetHolon, 'test');
25
- expect(Array.isArray(fedData)).toBe(true);
26
- });
27
-
28
- it('should include source holon in hologram metadata', async () => {
29
- await hs.write(sourceHolon, 'test', { id: 'item-1', value: 'data' });
30
- await hs.federate(sourceHolon, targetHolon, 'test');
31
-
32
- const fedData = await hs.getFederatedData(targetHolon, 'test');
33
- const hologram = fedData.find(d => d._meta?.source);
34
-
35
- if (hologram) {
36
- expect(hologram._meta.source).toBe(sourceHolon);
37
- }
38
- });
39
-
40
- it('should create hologram not copy in reference mode', async () => {
41
- const lensName = 'test-ref-' + Date.now();
42
- await hs.write(sourceHolon, lensName, { id: 'item-1', value: 'original' });
43
- await hs.federate(sourceHolon, targetHolon, lensName, { mode: 'reference' });
44
-
45
- // Small delay to ensure federation is complete
46
- await new Promise(resolve => setTimeout(resolve, 10));
47
-
48
- // Update source
49
- await hs.update(sourceHolon, lensName, 'item-1', { value: 'updated' });
50
-
51
- // Small delay to ensure update is complete
52
- await new Promise(resolve => setTimeout(resolve, 10));
53
-
54
- // Target should reflect update (reference, not copy)
55
- const fedData = await hs.getFederatedData(targetHolon, lensName);
56
- const item = fedData.find(d => d.id === 'item-1');
57
- expect(item?.value).toBe('updated');
58
- });
59
- });
60
-
61
- describe('Hologram resolution (dereference)', () => {
62
- it('should resolve holograms to actual data', async () => {
63
- const lensName = 'test-resolve-' + Date.now();
64
- await hs.write(sourceHolon, lensName, { id: 'item-1', value: 'data' });
65
- await hs.federate(sourceHolon, targetHolon, lensName);
66
-
67
- // Small delay to ensure federation is complete
68
- await new Promise(resolve => setTimeout(resolve, 10));
69
-
70
- const fedData = await hs.getFederatedData(targetHolon, lensName, {
71
- resolveHolograms: true
72
- });
73
-
74
- const item = fedData.find(d => d.id === 'item-1');
75
- expect(item?.value).toBe('data');
76
- });
77
-
78
- it('should return hologram references when resolveHolograms is false', async () => {
79
- await hs.write(sourceHolon, 'test', { id: 'item-1', value: 'data' });
80
- await hs.federate(sourceHolon, targetHolon, 'test');
81
-
82
- const fedData = await hs.getFederatedData(targetHolon, 'test', {
83
- resolveHolograms: false
84
- });
85
-
86
- // Should return hologram structure, not resolved data
87
- expect(Array.isArray(fedData)).toBe(true);
88
- });
89
- });
90
-
91
- describe('Circular reference detection', () => {
92
- it('should detect circular federation references', async () => {
93
- const holonA = await hs.toHolon(37.7749, -122.4194, 9);
94
- const holonB = await hs.toHolon(40.7128, -74.0060, 9);
95
-
96
- await hs.federate(holonA, holonB, 'test');
97
-
98
- // Circular: B -> A (when A -> B already exists)
99
- await hs.federate(holonB, holonA, 'test');
100
-
101
- // Should not cause infinite loop
102
- const dataA = await hs.getFederatedData(holonA, 'test');
103
- expect(Array.isArray(dataA)).toBe(true);
104
- });
105
-
106
- it('should enforce max depth limit (10 levels)', async () => {
107
- // Create a chain longer than max depth
108
- const holons = [];
109
- for (let i = 0; i < 12; i++) {
110
- holons.push(await hs.toHolon(37.7749 + i * 0.01, -122.4194, 9));
111
- }
112
-
113
- // Create federation chain
114
- for (let i = 0; i < holons.length - 1; i++) {
115
- await hs.federate(holons[i], holons[i + 1], 'chain');
116
- }
117
-
118
- // Should not traverse beyond max depth
119
- const lastData = await hs.getFederatedData(holons[holons.length - 1], 'chain');
120
- expect(Array.isArray(lastData)).toBe(true);
121
- });
122
-
123
- it('should prevent infinite loops in hologram resolution', async () => {
124
- const holonA = await hs.toHolon(37.7749, -122.4194, 9);
125
- const holonB = await hs.toHolon(40.7128, -74.0060, 9);
126
-
127
- await hs.write(holonA, 'circular', { id: 'a1', ref: 'b1' });
128
- await hs.write(holonB, 'circular', { id: 'b1', ref: 'a1' });
129
-
130
- await hs.federate(holonA, holonB, 'circular', { direction: 'bidirectional' });
131
-
132
- // Should handle circular references gracefully
133
- await expect(
134
- hs.getFederatedData(holonA, 'circular')
135
- ).resolves.toBeDefined();
136
- });
137
- });
138
-
139
- describe('Federation config validation', () => {
140
- it('should validate direction option', async () => {
141
- await expect(
142
- hs.federate(sourceHolon, targetHolon, 'test', { direction: 'outbound', propagateExisting: false })
143
- ).resolves.toBe(true);
144
-
145
- await expect(
146
- hs.federate(sourceHolon, targetHolon, 'test', { direction: 'inbound', propagateExisting: false })
147
- ).resolves.toBe(true);
148
-
149
- await expect(
150
- hs.federate(sourceHolon, targetHolon, 'test', { direction: 'bidirectional', propagateExisting: false })
151
- ).resolves.toBe(true);
152
- });
153
-
154
- it('should throw error for invalid direction', async () => {
155
- await expect(
156
- hs.federate(sourceHolon, targetHolon, 'test', { direction: 'invalid' })
157
- ).rejects.toThrow(Error);
158
- });
159
-
160
- it('should validate mode option', async () => {
161
- await expect(
162
- hs.federate(sourceHolon, targetHolon, 'test', { mode: 'reference', propagateExisting: false })
163
- ).resolves.toBe(true);
164
-
165
- await expect(
166
- hs.federate(sourceHolon, targetHolon, 'test', { mode: 'copy', propagateExisting: false })
167
- ).resolves.toBe(true);
168
- });
169
-
170
- it('should throw error for self-federation', async () => {
171
- await expect(
172
- hs.federate(sourceHolon, sourceHolon, 'test')
173
- ).rejects.toThrow(Error);
174
- });
175
- });
176
-
177
- describe('Inbound/outbound/bidirectional modes', () => {
178
- it('should handle outbound federation (source -> target)', async () => {
179
- await hs.write(sourceHolon, 'test', { id: 'item-1', value: 'data' });
180
-
181
- await hs.federate(sourceHolon, targetHolon, 'test', {
182
- direction: 'outbound'
183
- });
184
-
185
- const targetData = await hs.getFederatedData(targetHolon, 'test');
186
- expect(targetData.some(d => d.id === 'item-1')).toBe(true);
187
- });
188
-
189
- it('should handle inbound federation (target <- source)', async () => {
190
- await hs.write(targetHolon, 'test', { id: 'item-1', value: 'data' });
191
-
192
- await hs.federate(sourceHolon, targetHolon, 'test', {
193
- direction: 'inbound'
194
- });
195
-
196
- const sourceData = await hs.getFederatedData(sourceHolon, 'test');
197
- expect(sourceData.some(d => d.id === 'item-1')).toBe(true);
198
- });
199
-
200
- it('should handle bidirectional federation (source <-> target)', async () => {
201
- // Use unique lens name to avoid interference from other tests
202
- const lensName = 'test-bidir-' + Date.now();
203
-
204
- await hs.write(sourceHolon, lensName, { id: 'source-item', value: 'source' });
205
- await hs.write(targetHolon, lensName, { id: 'target-item', value: 'target' });
206
-
207
- await hs.federate(sourceHolon, targetHolon, lensName, {
208
- direction: 'bidirectional'
209
- });
210
-
211
- const sourceData = await hs.getFederatedData(sourceHolon, lensName);
212
- const targetData = await hs.getFederatedData(targetHolon, lensName);
213
-
214
- expect(sourceData.some(d => d.id === 'target-item')).toBe(true);
215
- expect(targetData.some(d => d.id === 'source-item')).toBe(true);
216
- });
217
-
218
- it('should apply filter function in federation', async () => {
219
- // Use unique lens name to avoid interference from other tests
220
- const lensName = 'test-filter-' + Date.now();
221
-
222
- await hs.write(sourceHolon, lensName, { id: 'item-1', priority: 'high' });
223
- await hs.write(sourceHolon, lensName, { id: 'item-2', priority: 'low' });
224
-
225
- await hs.federate(sourceHolon, targetHolon, lensName, {
226
- filter: (data) => data.priority === 'high'
227
- });
228
-
229
- const targetData = await hs.getFederatedData(targetHolon, lensName);
230
- expect(targetData.some(d => d.id === 'item-1')).toBe(true);
231
- expect(targetData.some(d => d.id === 'item-2')).toBe(false);
232
- });
233
- });
234
- });
@@ -1,252 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, beforeAll } from 'vitest';
2
-
3
- // Dynamically import Gun (optional dependency)
4
- let Gun;
5
- let gunAvailable = false;
6
-
7
- // Import gun-async utilities
8
- let gunPromise, gunPut, gunMap, gunMapIterator, gunCollect, gunWaitFor, gunBatchGet, gunBatchPut, gunRetry, gunStream;
9
-
10
- beforeAll(async () => {
11
- try {
12
- Gun = (await import('gun')).default;
13
- const gunAsync = await import('../../src/storage/gun-async.js');
14
- gunPromise = gunAsync.gunPromise;
15
- gunPut = gunAsync.gunPut;
16
- gunMap = gunAsync.gunMap;
17
- gunMapIterator = gunAsync.gunMapIterator;
18
- gunCollect = gunAsync.gunCollect;
19
- gunWaitFor = gunAsync.gunWaitFor;
20
- gunBatchGet = gunAsync.gunBatchGet;
21
- gunBatchPut = gunAsync.gunBatchPut;
22
- gunRetry = gunAsync.gunRetry;
23
- gunStream = gunAsync.gunStream;
24
- gunAvailable = true;
25
- } catch (e) {
26
- console.log('Gun not available, skipping gun-async tests');
27
- }
28
- });
29
-
30
- describe('Gun Async Utilities', () => {
31
- let gun;
32
-
33
- beforeEach(() => {
34
- if (!gunAvailable) return;
35
- gun = Gun({ radisk: false, localStorage: false });
36
- });
37
-
38
- afterEach(() => {
39
- // Cleanup
40
- });
41
-
42
- describe('gunPromise', () => {
43
- it('should resolve with data from once()', async () => {
44
- if (!gunAvailable) return;
45
- const testData = { id: 'test1', value: 'hello' };
46
- await gunPut(gun.get('test1'), testData);
47
-
48
- const result = await gunPromise(gun.get('test1'));
49
- expect(result.id).toBe('test1');
50
- expect(result.value).toBe('hello');
51
- });
52
-
53
- it('should resolve with null for non-existent data', async () => {
54
- if (!gunAvailable) return;
55
- const result = await gunPromise(gun.get('nonexistent'));
56
- expect(result).toBeNull();
57
- });
58
- });
59
-
60
- describe('gunPut', () => {
61
- it('should write data and resolve ack', async () => {
62
- if (!gunAvailable) return;
63
- const data = { id: 'test2', name: 'Test' };
64
- const ack = await gunPut(gun.get('test2'), data);
65
-
66
- expect(ack).toBeDefined();
67
- expect(ack.err).toBeUndefined();
68
- });
69
-
70
- it('should reject on write error', async () => {
71
- if (!gunAvailable) return;
72
- // Gun typically doesn't error on put, but this tests the pattern
73
- const data = { id: 'test3' };
74
- const ack = await gunPut(gun.get('test3'), data);
75
- expect(ack.err).toBeUndefined();
76
- });
77
- });
78
-
79
- describe('gunMap', () => {
80
- it('should collect map items', async () => {
81
- if (!gunAvailable) return;
82
- const base = gun.get('testmap');
83
- await gunPut(base.get('item1'), { id: 'item1', value: 'a' });
84
- await gunPut(base.get('item2'), { id: 'item2', value: 'b' });
85
- await gunPut(base.get('item3'), { id: 'item3', value: 'c' });
86
-
87
- // Wait a bit for Gun to sync
88
- await new Promise((r) => setTimeout(r, 100));
89
-
90
- const items = await gunMap(base, 800);
91
-
92
- // Gun may or may not have items in memory-only mode
93
- expect(Object.keys(items).length).toBeGreaterThanOrEqual(0);
94
- });
95
- });
96
-
97
- describe('gunMapIterator', () => {
98
- it('should iterate over map items', async () => {
99
- if (!gunAvailable) return;
100
- const base = gun.get('testiterator');
101
- await gunPut(base.get('a'), { id: 'a', val: 1 });
102
- await gunPut(base.get('b'), { id: 'b', val: 2 });
103
-
104
- // Wait for Gun to sync
105
- await new Promise((r) => setTimeout(r, 100));
106
-
107
- const items = [];
108
- for await (const [key, value] of gunMapIterator(base)) {
109
- items.push({ key, value });
110
- }
111
-
112
- // Gun may or may not have items in memory-only mode
113
- expect(items.length).toBeGreaterThanOrEqual(0);
114
- });
115
- });
116
-
117
- describe('gunCollect', () => {
118
- it('should collect on() stream data', async () => {
119
- if (!gunAvailable) return;
120
- const base = gun.get('testcollect');
121
-
122
- // Write data
123
- await gunPut(base, { id: 'collect1', value: 'test' });
124
-
125
- // Collect updates
126
- const results = await gunCollect(base, 300);
127
-
128
- expect(results.length).toBeGreaterThan(0);
129
- expect(results[0].data).toBeDefined();
130
- });
131
- });
132
-
133
- describe('gunWaitFor', () => {
134
- it('should resolve when condition is met', async () => {
135
- if (!gunAvailable) return;
136
- const ref = gun.get('testwait');
137
-
138
- // Start waiting
139
- const waitPromise = gunWaitFor(
140
- ref,
141
- (data) => data && data.ready === true,
142
- 2000
143
- );
144
-
145
- // Set data after a delay
146
- setTimeout(async () => {
147
- await gunPut(ref, { id: 'testwait', ready: true });
148
- }, 100);
149
-
150
- const result = await waitPromise;
151
- expect(result.ready).toBe(true);
152
- });
153
-
154
- it('should timeout if condition not met', async () => {
155
- if (!gunAvailable) return;
156
- const ref = gun.get('testtimeout');
157
-
158
- await expect(
159
- gunWaitFor(ref, (data) => data && data.never === true, 500)
160
- ).rejects.toThrow('Timeout');
161
- });
162
- });
163
-
164
- describe('gunBatchGet', () => {
165
- it('should read multiple paths', async () => {
166
- if (!gunAvailable) return;
167
- await gunPut(gun.get('batch1'), { id: 'batch1', val: 1 });
168
- await gunPut(gun.get('batch2'), { id: 'batch2', val: 2 });
169
- await gunPut(gun.get('batch3'), { id: 'batch3', val: 3 });
170
-
171
- const results = await gunBatchGet(gun, ['batch1', 'batch2', 'batch3']);
172
-
173
- expect(results.batch1.id).toBe('batch1');
174
- expect(results.batch2.id).toBe('batch2');
175
- expect(results.batch3.id).toBe('batch3');
176
- });
177
- });
178
-
179
- describe('gunBatchPut', () => {
180
- it('should write multiple paths', async () => {
181
- if (!gunAvailable) return;
182
- const data = {
183
- batchput1: { id: 'batchput1', val: 'a' },
184
- batchput2: { id: 'batchput2', val: 'b' },
185
- batchput3: { id: 'batchput3', val: 'c' },
186
- };
187
-
188
- const results = await gunBatchPut(gun, data);
189
-
190
- expect(results.batchput1).toBeDefined();
191
- expect(results.batchput2).toBeDefined();
192
- expect(results.batchput3).toBeDefined();
193
-
194
- // Verify writes
195
- const read1 = await gunPromise(gun.get('batchput1'));
196
- expect(read1.val).toBe('a');
197
- });
198
- });
199
-
200
- describe('gunRetry', () => {
201
- it('should retry failed operations', async () => {
202
- if (!gunAvailable) return;
203
- let attempts = 0;
204
-
205
- const operation = async () => {
206
- attempts++;
207
- if (attempts < 3) {
208
- throw new Error('Not ready');
209
- }
210
- return 'success';
211
- };
212
-
213
- const result = await gunRetry(operation, 5, 50);
214
- expect(result).toBe('success');
215
- expect(attempts).toBe(3);
216
- });
217
-
218
- it('should throw after max retries', async () => {
219
- if (!gunAvailable) return;
220
- const operation = async () => {
221
- throw new Error('Always fails');
222
- };
223
-
224
- await expect(gunRetry(operation, 2, 10)).rejects.toThrow('Always fails');
225
- });
226
- });
227
-
228
- describe('gunStream', () => {
229
- it('should create async iterable stream', async () => {
230
- if (!gunAvailable) return;
231
- const ref = gun.get('teststream');
232
- const stream = gunStream(ref);
233
-
234
- // Write data
235
- setTimeout(async () => {
236
- await gunPut(ref, { id: 'stream1', value: 'test' });
237
- }, 50);
238
-
239
- setTimeout(() => {
240
- stream.stop();
241
- }, 300);
242
-
243
- const items = [];
244
- for await (const item of stream) {
245
- items.push(item);
246
- if (items.length >= 1) break; // Prevent infinite loop
247
- }
248
-
249
- expect(items.length).toBeGreaterThan(0);
250
- });
251
- });
252
- });