holosphere 2.0.0-alpha0 → 2.0.0-alpha2

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 (88) hide show
  1. package/LICENSE +162 -38
  2. package/dist/cjs/holosphere.cjs +2 -0
  3. package/dist/cjs/holosphere.cjs.map +1 -0
  4. package/dist/esm/holosphere.js +56 -0
  5. package/dist/esm/holosphere.js.map +1 -0
  6. package/dist/index-CDfIuXew.js +15974 -0
  7. package/dist/index-CDfIuXew.js.map +1 -0
  8. package/dist/index-ifOgtDvd.cjs +3 -0
  9. package/dist/index-ifOgtDvd.cjs.map +1 -0
  10. package/dist/indexeddb-storage-CMW4qRQS.js +96 -0
  11. package/dist/indexeddb-storage-CMW4qRQS.js.map +1 -0
  12. package/dist/indexeddb-storage-DLZOgetM.cjs +2 -0
  13. package/dist/indexeddb-storage-DLZOgetM.cjs.map +1 -0
  14. package/dist/memory-storage-DQzcAZlf.js +47 -0
  15. package/dist/memory-storage-DQzcAZlf.js.map +1 -0
  16. package/dist/memory-storage-DmePEP2q.cjs +2 -0
  17. package/dist/memory-storage-DmePEP2q.cjs.map +1 -0
  18. package/dist/secp256k1-CP0ZkpAx.cjs +13 -0
  19. package/dist/secp256k1-CP0ZkpAx.cjs.map +1 -0
  20. package/dist/secp256k1-vOXp40Fx.js +2281 -0
  21. package/dist/secp256k1-vOXp40Fx.js.map +1 -0
  22. package/docs/FOSDEM_PROPOSAL.md +388 -0
  23. package/docs/LOCALFIRST.md +266 -0
  24. package/docs/contracts/api-interface.md +793 -0
  25. package/docs/data-model.md +476 -0
  26. package/docs/gun-async-usage.md +338 -0
  27. package/docs/plan.md +349 -0
  28. package/docs/quickstart.md +674 -0
  29. package/docs/research.md +362 -0
  30. package/docs/spec.md +244 -0
  31. package/docs/storage-backends.md +326 -0
  32. package/docs/tasks.md +947 -0
  33. package/package.json +1 -1
  34. package/tests/unit/ai/aggregation.test.js +0 -295
  35. package/tests/unit/ai/breakdown.test.js +0 -446
  36. package/tests/unit/ai/classifier.test.js +0 -294
  37. package/tests/unit/ai/council.test.js +0 -262
  38. package/tests/unit/ai/embeddings.test.js +0 -384
  39. package/tests/unit/ai/federation-ai.test.js +0 -344
  40. package/tests/unit/ai/h3-ai.test.js +0 -458
  41. package/tests/unit/ai/index.test.js +0 -304
  42. package/tests/unit/ai/json-ops.test.js +0 -307
  43. package/tests/unit/ai/llm-service.test.js +0 -390
  44. package/tests/unit/ai/nl-query.test.js +0 -383
  45. package/tests/unit/ai/relationships.test.js +0 -311
  46. package/tests/unit/ai/schema-extractor.test.js +0 -384
  47. package/tests/unit/ai/spatial.test.js +0 -279
  48. package/tests/unit/ai/tts.test.js +0 -279
  49. package/tests/unit/content.test.js +0 -332
  50. package/tests/unit/contract/core.test.js +0 -88
  51. package/tests/unit/contract/crypto.test.js +0 -198
  52. package/tests/unit/contract/data.test.js +0 -223
  53. package/tests/unit/contract/federation.test.js +0 -181
  54. package/tests/unit/contract/hierarchical.test.js +0 -113
  55. package/tests/unit/contract/schema.test.js +0 -114
  56. package/tests/unit/contract/social.test.js +0 -217
  57. package/tests/unit/contract/spatial.test.js +0 -110
  58. package/tests/unit/contract/subscriptions.test.js +0 -128
  59. package/tests/unit/contract/utils.test.js +0 -159
  60. package/tests/unit/core.test.js +0 -152
  61. package/tests/unit/crypto.test.js +0 -328
  62. package/tests/unit/federation.test.js +0 -234
  63. package/tests/unit/gun-async.test.js +0 -252
  64. package/tests/unit/hierarchical.test.js +0 -399
  65. package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
  66. package/tests/unit/integration/scenario-02-federation.test.js +0 -76
  67. package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
  68. package/tests/unit/integration/scenario-04-validation.test.js +0 -129
  69. package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
  70. package/tests/unit/integration/scenario-06-social.test.js +0 -135
  71. package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
  72. package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
  73. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
  74. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
  75. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
  76. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
  77. package/tests/unit/performance/benchmark.test.js +0 -85
  78. package/tests/unit/schema.test.js +0 -213
  79. package/tests/unit/spatial.test.js +0 -158
  80. package/tests/unit/storage.test.js +0 -195
  81. package/tests/unit/subscriptions.test.js +0 -328
  82. package/tests/unit/test-data-permanence-debug.js +0 -197
  83. package/tests/unit/test-data-permanence.js +0 -340
  84. package/tests/unit/test-key-persistence-fixed.js +0 -148
  85. package/tests/unit/test-key-persistence.js +0 -172
  86. package/tests/unit/test-relay-permanence.js +0 -376
  87. package/tests/unit/test-second-node.js +0 -95
  88. package/tests/unit/test-simple-write.js +0 -89
@@ -1,340 +0,0 @@
1
- /**
2
- * Test Data Permanence Through Relays
3
- *
4
- * This comprehensive test validates:
5
- * 1. Data persistence after writing
6
- * 2. Data synchronization across nodes
7
- * 3. Data permanence after node restart
8
- * 4. Data updates and versioning
9
- * 5. Data recovery from relays
10
- */
11
-
12
- import { HoloSphere } from './dist/esm/holosphere.js';
13
-
14
- // Relay configuration - use env vars or these defaults
15
- const RELAYS = process.env.HOLOSPHERE_RELAYS?.split(',') || [
16
- 'wss://relay.holons.io',
17
- 'wss://relay.nostr.band',
18
- ];
19
-
20
- // Test configuration
21
- const TEST_CONFIG = {
22
- appName: 'permanence-test',
23
- relays: RELAYS,
24
- logLevel: 'INFO'
25
- };
26
-
27
- const TEST_HOLON = 'global://permanence-test';
28
- const WAIT_FOR_SYNC = 3000; // 3 seconds for relay sync
29
-
30
- // Colors for console output
31
- const colors = {
32
- reset: '\x1b[0m',
33
- green: '\x1b[32m',
34
- red: '\x1b[31m',
35
- yellow: '\x1b[33m',
36
- blue: '\x1b[34m',
37
- cyan: '\x1b[36m'
38
- };
39
-
40
- function log(message, color = 'reset') {
41
- console.log(`${colors[color]}${message}${colors.reset}`);
42
- }
43
-
44
- function logSection(title) {
45
- console.log('\n' + '='.repeat(70));
46
- log(` ${title}`, 'cyan');
47
- console.log('='.repeat(70) + '\n');
48
- }
49
-
50
- function logTest(testName, passed, details = '') {
51
- const icon = passed ? '✅' : '❌';
52
- const color = passed ? 'green' : 'red';
53
- log(`${icon} ${testName}`, color);
54
- if (details) {
55
- console.log(` ${details}`);
56
- }
57
- }
58
-
59
- /**
60
- * Test 1: Write data and verify immediate persistence
61
- */
62
- async function test1_WritePersistence(hs) {
63
- logSection('TEST 1: Write and Immediate Persistence');
64
-
65
- const testData = {
66
- id: `test-${Date.now()}`,
67
- timestamp: Date.now(),
68
- message: 'This is a permanence test',
69
- metadata: {
70
- test: 'write-persistence',
71
- version: 1
72
- }
73
- };
74
-
75
- log('Writing test data...', 'yellow');
76
- const writeResult = await hs.write(TEST_HOLON, 'test-data', testData);
77
- logTest('Data written successfully', writeResult, `ID: ${testData.id}`);
78
-
79
- // Immediate read-back
80
- log('\nReading data back immediately...', 'yellow');
81
- const readData = await hs.read(TEST_HOLON, 'test-data');
82
-
83
- const found = readData && readData.some(d => d.id === testData.id);
84
- logTest('Data immediately readable', found, found ? `Found ${readData.length} record(s)` : 'Data not found');
85
-
86
- if (found) {
87
- const record = readData.find(d => d.id === testData.id);
88
- const dataMatches = JSON.stringify(record) === JSON.stringify(testData);
89
- logTest('Data content matches', dataMatches);
90
- }
91
-
92
- return { passed: writeResult && found, testData };
93
- }
94
-
95
- /**
96
- * Test 2: Verify data persists after waiting (relay propagation)
97
- */
98
- async function test2_RelayPersistence(hs, testData) {
99
- logSection('TEST 2: Relay Propagation and Persistence');
100
-
101
- log(`Waiting ${WAIT_FOR_SYNC / 1000} seconds for relay synchronization...`, 'yellow');
102
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_SYNC));
103
-
104
- log('Reading data after relay sync period...', 'yellow');
105
- const readData = await hs.read(TEST_HOLON, 'test-data');
106
-
107
- const found = readData && readData.some(d => d.id === testData.id);
108
- logTest('Data persists after sync period', found, found ? `Found ${readData.length} record(s)` : 'Data not found');
109
-
110
- return { passed: found };
111
- }
112
-
113
- /**
114
- * Test 3: Create second node and verify sync
115
- */
116
- async function test3_CrossNodeSync(testData) {
117
- logSection('TEST 3: Cross-Node Synchronization');
118
-
119
- log('Creating second node instance...', 'yellow');
120
- const hs2 = new HoloSphere(TEST_CONFIG);
121
-
122
- log(`Node 2 Public Key: ${hs2.client.publicKey}`, 'blue');
123
- log(`Waiting ${WAIT_FOR_SYNC / 1000} seconds for relay connection...`, 'yellow');
124
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_SYNC));
125
-
126
- log('Node 2 reading data from relays...', 'yellow');
127
- const readData = await hs2.read(TEST_HOLON, 'test-data');
128
-
129
- const found = readData && readData.some(d => d.id === testData.id);
130
- logTest('Data synced to second node', found, found ? `Found ${readData.length} record(s)` : 'Data not found');
131
-
132
- return { passed: found, hs2 };
133
- }
134
-
135
- /**
136
- * Test 4: Restart node and verify data recovery
137
- */
138
- async function test4_NodeRestart(testData) {
139
- logSection('TEST 4: Node Restart and Data Recovery');
140
-
141
- log('Creating fresh node instance (simulating restart)...', 'yellow');
142
- const hsRestart = new HoloSphere(TEST_CONFIG);
143
-
144
- log(`Restarted Node Public Key: ${hsRestart.client.publicKey}`, 'blue');
145
- log(`Waiting ${WAIT_FOR_SYNC / 1000} seconds for relay connection...`, 'yellow');
146
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_SYNC));
147
-
148
- log('Restarted node reading data from relays...', 'yellow');
149
- const readData = await hsRestart.read(TEST_HOLON, 'test-data');
150
-
151
- const found = readData && readData.some(d => d.id === testData.id);
152
- logTest('Data recovered after restart', found, found ? `Found ${readData.length} record(s)` : 'Data not found');
153
-
154
- return { passed: found, hsRestart };
155
- }
156
-
157
- /**
158
- * Test 5: Update data and verify update persistence
159
- */
160
- async function test5_UpdatePersistence(hs, testData) {
161
- logSection('TEST 5: Update and Update Persistence');
162
-
163
- const updatedData = {
164
- ...testData,
165
- message: 'This data has been updated',
166
- metadata: {
167
- ...testData.metadata,
168
- version: 2,
169
- updatedAt: Date.now()
170
- }
171
- };
172
-
173
- log('Writing updated data...', 'yellow');
174
- const writeResult = await hs.write(TEST_HOLON, 'test-data', updatedData);
175
- logTest('Updated data written', writeResult);
176
-
177
- log(`Waiting ${WAIT_FOR_SYNC / 1000} seconds for update propagation...`, 'yellow');
178
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_SYNC));
179
-
180
- log('Reading updated data...', 'yellow');
181
- const readData = await hs.read(TEST_HOLON, 'test-data');
182
-
183
- const found = readData && readData.find(d => d.id === testData.id);
184
- const updatePersisted = found && found.metadata.version === 2;
185
-
186
- logTest('Update persisted correctly', updatePersisted,
187
- updatePersisted ? `Version: ${found.metadata.version}` : 'Update not found or incorrect');
188
-
189
- return { passed: writeResult && updatePersisted };
190
- }
191
-
192
- /**
193
- * Test 6: Verify update visible on second node
194
- */
195
- async function test6_UpdateSync(hs2, testData) {
196
- logSection('TEST 6: Update Synchronization Across Nodes');
197
-
198
- log(`Waiting ${WAIT_FOR_SYNC / 1000} seconds for update to sync...`, 'yellow');
199
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_SYNC));
200
-
201
- log('Node 2 reading updated data...', 'yellow');
202
- const readData = await hs2.read(TEST_HOLON, 'test-data');
203
-
204
- const found = readData && readData.find(d => d.id === testData.id);
205
- const updateSynced = found && found.metadata.version === 2;
206
-
207
- logTest('Update synced to second node', updateSynced,
208
- updateSynced ? `Version: ${found.metadata.version}, Message: ${found.message}` : 'Update not synced');
209
-
210
- return { passed: updateSynced };
211
- }
212
-
213
- /**
214
- * Test 7: Multiple writes and verify all persist
215
- */
216
- async function test7_MultipleWrites(hs) {
217
- logSection('TEST 7: Multiple Writes and Batch Persistence');
218
-
219
- const records = [];
220
- const count = 5;
221
-
222
- log(`Writing ${count} records...`, 'yellow');
223
- for (let i = 0; i < count; i++) {
224
- const record = {
225
- id: `batch-test-${Date.now()}-${i}`,
226
- index: i,
227
- timestamp: Date.now(),
228
- message: `Batch record ${i}`
229
- };
230
- records.push(record);
231
- await hs.write(TEST_HOLON, 'test-data', record);
232
- log(` Written: ${record.id}`, 'blue');
233
- }
234
-
235
- log(`\nWaiting ${WAIT_FOR_SYNC / 1000} seconds for batch sync...`, 'yellow');
236
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_SYNC));
237
-
238
- log('Reading all records...', 'yellow');
239
- const readData = await hs.read(TEST_HOLON, 'test-data');
240
-
241
- const foundCount = records.filter(r => readData.some(d => d.id === r.id)).length;
242
- const allFound = foundCount === count;
243
-
244
- logTest('All batch records persisted', allFound, `Found ${foundCount}/${count} records`);
245
-
246
- return { passed: allFound, records };
247
- }
248
-
249
- /**
250
- * Main test runner
251
- */
252
- async function runTests() {
253
- log('\n╔═══════════════════════════════════════════════════════════════════╗', 'cyan');
254
- log('║ HOLOSPHERE DATA PERMANENCE TEST SUITE ║', 'cyan');
255
- log('╚═══════════════════════════════════════════════════════════════════╝', 'cyan');
256
-
257
- log(`\nTest Configuration:`, 'yellow');
258
- log(` App Name: ${TEST_CONFIG.appName}`, 'blue');
259
- log(` Relays:`, 'blue');
260
- TEST_CONFIG.relays.forEach(relay => log(` - ${relay}`, 'blue'));
261
- log(` Sync Wait Time: ${WAIT_FOR_SYNC / 1000}s`, 'blue');
262
-
263
- const results = {
264
- passed: 0,
265
- failed: 0,
266
- tests: []
267
- };
268
-
269
- try {
270
- // Initialize primary node
271
- log('\nInitializing primary test node...', 'yellow');
272
- const hs = new HoloSphere(TEST_CONFIG);
273
- log(`Primary Node Public Key: ${hs.client.publicKey}`, 'blue');
274
-
275
- await new Promise(resolve => setTimeout(resolve, 2000));
276
-
277
- // Run tests sequentially
278
- const { passed: t1, testData } = await test1_WritePersistence(hs);
279
- results.tests.push({ name: 'Write Persistence', passed: t1 });
280
-
281
- const { passed: t2 } = await test2_RelayPersistence(hs, testData);
282
- results.tests.push({ name: 'Relay Persistence', passed: t2 });
283
-
284
- const { passed: t3, hs2 } = await test3_CrossNodeSync(testData);
285
- results.tests.push({ name: 'Cross-Node Sync', passed: t3 });
286
-
287
- const { passed: t4 } = await test4_NodeRestart(testData);
288
- results.tests.push({ name: 'Node Restart Recovery', passed: t4 });
289
-
290
- const { passed: t5 } = await test5_UpdatePersistence(hs, testData);
291
- results.tests.push({ name: 'Update Persistence', passed: t5 });
292
-
293
- const { passed: t6 } = await test6_UpdateSync(hs2, testData);
294
- results.tests.push({ name: 'Update Sync', passed: t6 });
295
-
296
- const { passed: t7 } = await test7_MultipleWrites(hs);
297
- results.tests.push({ name: 'Batch Persistence', passed: t7 });
298
-
299
- // Calculate results
300
- results.passed = results.tests.filter(t => t.passed).length;
301
- results.failed = results.tests.filter(t => !t.passed).length;
302
-
303
- } catch (error) {
304
- log('\n❌ TEST SUITE FAILED WITH ERROR:', 'red');
305
- console.error(error);
306
- results.failed++;
307
- }
308
-
309
- // Print summary
310
- logSection('TEST SUMMARY');
311
-
312
- results.tests.forEach(test => {
313
- logTest(test.name, test.passed);
314
- });
315
-
316
- console.log('\n' + '-'.repeat(70));
317
- log(`Total Tests: ${results.tests.length}`, 'blue');
318
- log(`Passed: ${results.passed}`, 'green');
319
- log(`Failed: ${results.failed}`, 'red');
320
- log(`Success Rate: ${((results.passed / results.tests.length) * 100).toFixed(1)}%`,
321
- results.failed === 0 ? 'green' : 'yellow');
322
- console.log('-'.repeat(70) + '\n');
323
-
324
- if (results.failed === 0) {
325
- log('🎉 ALL TESTS PASSED! Data permanence is working correctly.', 'green');
326
- } else {
327
- log('⚠️ SOME TESTS FAILED. Please review the results above.', 'yellow');
328
- }
329
-
330
- log('\nTest complete. Press Ctrl+C to exit.\n');
331
-
332
- // Exit after a moment
333
- setTimeout(() => process.exit(results.failed === 0 ? 0 : 1), 2000);
334
- }
335
-
336
- // Run the test suite
337
- runTests().catch(error => {
338
- console.error('❌ Fatal error running tests:', error);
339
- process.exit(1);
340
- });
@@ -1,148 +0,0 @@
1
- /**
2
- * Test Key Persistence Across Restarts
3
- * Using explicit key management
4
- */
5
-
6
- import { HoloSphere } from './dist/esm/holosphere.js';
7
- import { loadKey, saveKey, getOrCreateKey } from './src/storage/key-storage-simple.js';
8
- import { generateSecretKey } from 'nostr-tools';
9
-
10
- // Relay configuration - use env vars or these defaults
11
- const RELAYS = process.env.HOLOSPHERE_RELAYS?.split(',') || [
12
- 'wss://relay.holons.io',
13
- 'wss://relay.nostr.band',
14
- ];
15
-
16
- const c = {
17
- reset: '\x1b[0m',
18
- green: '\x1b[32m',
19
- red: '\x1b[31m',
20
- yellow: '\x1b[33m',
21
- blue: '\x1b[34m',
22
- cyan: '\x1b[36m',
23
- bold: '\x1b[1m'
24
- };
25
-
26
- function log(msg, color = 'reset') {
27
- console.log(`${c[color]}${msg}${c.reset}`);
28
- }
29
-
30
- console.log('\n╔═══════════════════════════════════════════════════════════════════╗');
31
- log('║ PRIVATE KEY PERSISTENCE TEST (FIXED) ║', 'cyan');
32
- console.log('╚═══════════════════════════════════════════════════════════════════╝\n');
33
-
34
- const APP_NAME = 'key-persist-test';
35
-
36
- // Helper to generate hex key
37
- function generatePrivateKey() {
38
- const secretKey = generateSecretKey();
39
- return Buffer.from(secretKey).toString('hex');
40
- }
41
-
42
- log('TEST 1: Load or create persistent key\n', 'yellow');
43
-
44
- const privateKey = getOrCreateKey(APP_NAME, generatePrivateKey);
45
- log(`Key loaded/created:`, 'blue');
46
- log(` Private Key: ${privateKey.substring(0, 16)}...`, 'blue');
47
-
48
- log('\nTEST 2: Create first instance with persistent key\n', 'yellow');
49
-
50
- const hs1 = new HoloSphere({
51
- appName: APP_NAME,
52
- relays: RELAYS,
53
- privateKey: privateKey, // IMPORTANT: Provide the key explicitly
54
- logLevel: 'WARN'
55
- });
56
-
57
- log(`First Instance Created:`, 'blue');
58
- log(` Public Key: ${hs1.client.publicKey}`, 'blue');
59
-
60
- // Write some data
61
- log('\nWriting test data...', 'yellow');
62
- await new Promise(resolve => setTimeout(resolve, 2000));
63
-
64
- const testData = {
65
- id: 'persist-test-1',
66
- message: 'Testing key persistence',
67
- timestamp: Date.now()
68
- };
69
-
70
- const writeResult = await hs1.write('global://persist', 'data', testData);
71
- log(writeResult ? '✅ Data written' : '❌ Write failed', writeResult ? 'green' : 'red');
72
-
73
- // Simulate restart by creating new instance
74
- log('\n' + '─'.repeat(70), 'cyan');
75
- log('TEST 3: Simulate restart (load same key, create new instance)\n', 'yellow');
76
-
77
- const privateKey2 = loadKey(APP_NAME);
78
- log(`Loaded key from storage: ${privateKey2.substring(0, 16)}...`, 'blue');
79
-
80
- const hs2 = new HoloSphere({
81
- appName: APP_NAME,
82
- relays: RELAYS,
83
- privateKey: privateKey2, // Use loaded key
84
- logLevel: 'WARN'
85
- });
86
-
87
- log(`Second Instance Created:`, 'blue');
88
- log(` Public Key: ${hs2.client.publicKey}`, 'blue');
89
-
90
- // Check if keys match
91
- log('\n' + '─'.repeat(70), 'cyan');
92
- log('TEST 4: Verify keys match\n', 'yellow');
93
-
94
- const keysMatch = (privateKey === privateKey2);
95
- const pubKeysMatch = (hs1.client.publicKey === hs2.client.publicKey);
96
-
97
- log(`Private keys match: ${keysMatch ? '✅ YES' : '❌ NO'}`, keysMatch ? 'green' : 'red');
98
- log(`Public keys match: ${pubKeysMatch ? '✅ YES' : '❌ NO'}`, pubKeysMatch ? 'green' : 'red');
99
-
100
- // Try to read the data from second instance
101
- log('\n' + '─'.repeat(70), 'cyan');
102
- log('TEST 5: Read data from second instance\n', 'yellow');
103
-
104
- await new Promise(resolve => setTimeout(resolve, 3000));
105
-
106
- const readData = await hs2.read('global://persist', 'data');
107
- const found = readData && readData.find(d => d.id === testData.id);
108
-
109
- log(found ? '✅ Data readable from second instance' : '❌ Data not found', found ? 'green' : 'red');
110
-
111
- if (found) {
112
- log(` Message: "${found.message}"`, 'blue');
113
- }
114
-
115
- // Summary
116
- log('\n' + '═'.repeat(70), 'cyan');
117
- log(' TEST SUMMARY', 'cyan');
118
- log('═'.repeat(70), 'cyan');
119
-
120
- const allPassed = keysMatch && pubKeysMatch && found;
121
-
122
- log('', '');
123
- log(`✓ Keys match across instances: ${keysMatch ? 'PASS' : 'FAIL'}`, keysMatch ? 'green' : 'red');
124
- log(`✓ Public keys match: ${pubKeysMatch ? 'PASS' : 'FAIL'}`, pubKeysMatch ? 'green' : 'red');
125
- log(`✓ Data readable across instances: ${found ? 'PASS' : 'FAIL'}`, found ? 'green' : 'red');
126
-
127
- if (allPassed) {
128
- log('\n🎉 ALL TESTS PASSED!', 'bold');
129
- log('✓ Private keys persist across restarts', 'green');
130
- log('✓ Same identity maintained with explicit key management', 'green');
131
- log('\n🔑 Key storage location:', 'blue');
132
-
133
- const os = await import('os');
134
- const path = await import('path');
135
- const keyDir = path.join(os.homedir(), '.config', 'holosphere', 'keys');
136
- log(` ${keyDir}/${APP_NAME}.key`, 'blue');
137
-
138
- log('\n📖 Usage pattern for persistence:', 'yellow');
139
- log(` import { loadKey, saveKey, getOrCreateKey } from 'holosphere/key-storage';`, 'blue');
140
- log(` const key = getOrCreateKey('my-app', generateKey);`, 'blue');
141
- log(` const hs = new HoloSphere({ privateKey: key, ... });`, 'blue');
142
-
143
- log('\n');
144
- process.exit(0);
145
- } else {
146
- log('\n❌ SOME TESTS FAILED', 'red');
147
- process.exit(1);
148
- }
@@ -1,172 +0,0 @@
1
- /**
2
- * Test Key Persistence Across Restarts
3
- * Verifies that private keys are saved and loaded correctly
4
- */
5
-
6
- import { HoloSphere } from './dist/esm/holosphere.js';
7
-
8
- // Relay configuration - use env vars or these defaults
9
- const RELAYS = process.env.HOLOSPHERE_RELAYS?.split(',') || [
10
- 'wss://relay.holons.io',
11
- 'wss://relay.nostr.band',
12
- ];
13
-
14
- const c = {
15
- reset: '\x1b[0m',
16
- green: '\x1b[32m',
17
- red: '\x1b[31m',
18
- yellow: '\x1b[33m',
19
- blue: '\x1b[34m',
20
- cyan: '\x1b[36m',
21
- bold: '\x1b[1m'
22
- };
23
-
24
- function log(msg, color = 'reset') {
25
- console.log(`${c[color]}${msg}${c.reset}`);
26
- }
27
-
28
- console.log('\n╔═══════════════════════════════════════════════════════════════════╗');
29
- log('║ PRIVATE KEY PERSISTENCE TEST ║', 'cyan');
30
- console.log('╚═══════════════════════════════════════════════════════════════════╝\n');
31
-
32
- const APP_NAME = 'key-persist-test';
33
-
34
- log('TEST 1: Create first instance and check key\n', 'yellow');
35
-
36
- const hs1 = new HoloSphere({
37
- appName: APP_NAME,
38
- relays: RELAYS,
39
- logLevel: 'WARN'
40
- });
41
-
42
- const firstKey = hs1.client.privateKey;
43
- const firstPubKey = hs1.client.publicKey;
44
-
45
- log(`First Instance Created:`, 'blue');
46
- log(` App Name: ${APP_NAME}`, 'blue');
47
- log(` Private Key: ${firstKey.substring(0, 16)}...`, 'blue');
48
- log(` Public Key: ${firstPubKey}`, 'blue');
49
-
50
- // Write some data
51
- log('\nWriting test data...', 'yellow');
52
- await new Promise(resolve => setTimeout(resolve, 2000));
53
-
54
- const testData = {
55
- id: 'persist-test-1',
56
- message: 'Testing key persistence',
57
- timestamp: Date.now()
58
- };
59
-
60
- const writeResult = await hs1.write('global://persist', 'data', testData);
61
- log(writeResult ? '✅ Data written' : '❌ Write failed', writeResult ? 'green' : 'red');
62
-
63
- // Create second instance (simulating restart)
64
- log('\n' + '─'.repeat(70), 'cyan');
65
- log('TEST 2: Create second instance (simulating restart)\n', 'yellow');
66
-
67
- const hs2 = new HoloSphere({
68
- appName: APP_NAME, // SAME app name
69
- relays: RELAYS,
70
- logLevel: 'WARN'
71
- });
72
-
73
- const secondKey = hs2.client.privateKey;
74
- const secondPubKey = hs2.client.publicKey;
75
-
76
- log(`Second Instance Created:`, 'blue');
77
- log(` App Name: ${APP_NAME}`, 'blue');
78
- log(` Private Key: ${secondKey.substring(0, 16)}...`, 'blue');
79
- log(` Public Key: ${secondPubKey}`, 'blue');
80
-
81
- // Check if keys match
82
- log('\n' + '─'.repeat(70), 'cyan');
83
- log('TEST 3: Verify keys match\n', 'yellow');
84
-
85
- const keysMatch = (firstKey === secondKey);
86
- const pubKeysMatch = (firstPubKey === secondPubKey);
87
-
88
- log(`Private keys match: ${keysMatch ? '✅ YES' : '❌ NO'}`, keysMatch ? 'green' : 'red');
89
- log(`Public keys match: ${pubKeysMatch ? '✅ YES' : '❌ NO'}`, pubKeysMatch ? 'green' : 'red');
90
-
91
- if (!keysMatch) {
92
- log('\n❌ FAILED: Keys do not match across restarts!', 'red');
93
- log('First key: ' + firstKey, 'red');
94
- log('Second key: ' + secondKey, 'red');
95
- process.exit(1);
96
- }
97
-
98
- // Try to read the data from second instance
99
- log('\n' + '─'.repeat(70), 'cyan');
100
- log('TEST 4: Read data from second instance\n', 'yellow');
101
-
102
- await new Promise(resolve => setTimeout(resolve, 3000));
103
-
104
- const readData = await hs2.read('global://persist', 'data');
105
- const found = readData && readData.find(d => d.id === testData.id);
106
-
107
- log(found ? '✅ Data readable from second instance' : '❌ Data not found', found ? 'green' : 'red');
108
-
109
- if (found) {
110
- log(` Message: "${found.message}"`, 'blue');
111
- log(` Timestamp: ${found.timestamp}`, 'blue');
112
- }
113
-
114
- // Test with different app name (should get different key)
115
- log('\n' + '─'.repeat(70), 'cyan');
116
- log('TEST 5: Different app name should get different key\n', 'yellow');
117
-
118
- const hs3 = new HoloSphere({
119
- appName: 'different-app', // DIFFERENT app name
120
- relays: RELAYS,
121
- logLevel: 'WARN'
122
- });
123
-
124
- const thirdKey = hs3.client.privateKey;
125
- const thirdPubKey = hs3.client.publicKey;
126
-
127
- log(`Third Instance (different app):`, 'blue');
128
- log(` App Name: different-app`, 'blue');
129
- log(` Private Key: ${thirdKey.substring(0, 16)}...`, 'blue');
130
- log(` Public Key: ${thirdPubKey}`, 'blue');
131
-
132
- const differentKeys = (firstKey !== thirdKey);
133
- const differentPubKeys = (firstPubKey !== thirdPubKey);
134
-
135
- log(`\nKeys are different: ${differentKeys ? '✅ YES' : '❌ NO'}`, differentKeys ? 'green' : 'red');
136
- log(`Pub keys different: ${differentPubKeys ? '✅ YES' : '❌ NO'}`, differentPubKeys ? 'green' : 'red');
137
-
138
- // Summary
139
- log('\n' + '═'.repeat(70), 'cyan');
140
- log(' TEST SUMMARY', 'cyan');
141
- log('═'.repeat(70), 'cyan');
142
-
143
- const allPassed = keysMatch && pubKeysMatch && found && differentKeys && differentPubKeys;
144
-
145
- log('', '');
146
- log(`✓ Same app name = same keys: ${keysMatch ? 'PASS' : 'FAIL'}`, keysMatch ? 'green' : 'red');
147
- log(`✓ Data readable across instances: ${found ? 'PASS' : 'FAIL'}`, found ? 'green' : 'red');
148
- log(`✓ Different app = different keys: ${differentKeys ? 'PASS' : 'FAIL'}`, differentKeys ? 'green' : 'red');
149
-
150
- if (allPassed) {
151
- log('\n🎉 ALL TESTS PASSED!', 'bold');
152
- log('✓ Private keys persist across restarts', 'green');
153
- log('✓ Same identity maintained for same app', 'green');
154
- log('✓ Different apps get different identities', 'green');
155
- log('\n🔑 Key storage location:', 'blue');
156
-
157
- if (typeof window === 'undefined') {
158
- const os = require('os');
159
- const path = require('path');
160
- const keyDir = path.join(os.homedir(), '.config', 'holosphere', 'keys');
161
- log(` ${keyDir}`, 'blue');
162
- log(` Files: ${APP_NAME}.key, different-app.key`, 'blue');
163
- } else {
164
- log(` Browser localStorage: holosphere_key_${APP_NAME}`, 'blue');
165
- }
166
-
167
- log('\n');
168
- process.exit(0);
169
- } else {
170
- log('\n❌ SOME TESTS FAILED', 'red');
171
- process.exit(1);
172
- }