@ruvector/edge-net 0.3.0 → 0.4.0

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/cli.js CHANGED
@@ -110,6 +110,9 @@ function printHelp() {
110
110
  ${c('bold', 'COMMANDS:')}
111
111
  ${c('green', 'start')} Start an edge-net node in the terminal
112
112
  ${c('green', 'join')} Join network with public key (multi-contributor support)
113
+ ${c('green', 'genesis')} Start a genesis/signaling server for P2P network
114
+ ${c('green', 'firebase')} Setup Firebase (Google Cloud) for P2P bootstrap
115
+ ${c('green', 'p2p')} Start full P2P network node
113
116
  ${c('green', 'benchmark')} Run performance benchmarks
114
117
  ${c('green', 'info')} Show package and WASM information
115
118
  ${c('green', 'demo')} Run interactive demonstration
@@ -123,6 +126,15 @@ ${c('bold', 'EXAMPLES:')}
123
126
  ${c('dim', '# Join with new identity (multi-contributor)')}
124
127
  $ npx @ruvector/edge-net join --generate
125
128
 
129
+ ${c('dim', '# Start genesis/signaling server (for local P2P)')}
130
+ $ npx @ruvector/edge-net genesis --port 8787
131
+
132
+ ${c('dim', '# Setup Firebase for cloud-based P2P bootstrap')}
133
+ $ npx @ruvector/edge-net firebase --project YOUR_PROJECT_ID
134
+
135
+ ${c('dim', '# Start full P2P network node')}
136
+ $ npx @ruvector/edge-net p2p
137
+
126
138
  ${c('dim', '# Run benchmarks')}
127
139
  $ npx @ruvector/edge-net benchmark
128
140
 
@@ -422,6 +434,94 @@ async function runJoin() {
422
434
  child.on('close', (code) => process.exit(code));
423
435
  }
424
436
 
437
+ async function runGenesis() {
438
+ // Delegate to genesis.js
439
+ printBanner();
440
+ console.log(`${c('bold', 'Starting Genesis/Signaling Server...')}\n`);
441
+
442
+ const { spawn } = await import('child_process');
443
+ const args = process.argv.slice(3);
444
+
445
+ // Default to port 8787 if not specified
446
+ if (!args.includes('--port') && !args.includes('-p')) {
447
+ args.push('--port', '8787');
448
+ }
449
+
450
+ const child = spawn('node', [join(__dirname, 'genesis.js'), ...args], {
451
+ stdio: 'inherit'
452
+ });
453
+ child.on('close', (code) => process.exit(code));
454
+ }
455
+
456
+ async function runFirebaseSetup() {
457
+ // Delegate to firebase-setup.js
458
+ printBanner();
459
+ console.log(`${c('bold', 'Firebase Setup (Google Cloud)')}\n`);
460
+
461
+ const { spawn } = await import('child_process');
462
+ const args = process.argv.slice(3);
463
+ const child = spawn('node', [join(__dirname, 'firebase-setup.js'), ...args], {
464
+ stdio: 'inherit'
465
+ });
466
+ child.on('close', (code) => process.exit(code));
467
+ }
468
+
469
+ async function runP2P() {
470
+ printBanner();
471
+ console.log(`${c('bold', 'Starting P2P Network Node...')}\n`);
472
+
473
+ await setupPolyfills();
474
+
475
+ try {
476
+ const { createP2PNetwork } = await import('./p2p.js');
477
+
478
+ // Generate node ID
479
+ const nodeId = `node-${Math.random().toString(36).slice(2, 10)}`;
480
+
481
+ console.log(`${c('cyan', 'Node ID:')} ${nodeId}`);
482
+ console.log(`${c('cyan', 'Mode:')} Firebase bootstrap → DHT → Full P2P\n`);
483
+
484
+ console.log(`${c('dim', 'Initializing components...')}`);
485
+
486
+ const network = await createP2PNetwork(
487
+ { nodeId },
488
+ {
489
+ // Use Firebase bootstrap if configured, fall back to local
490
+ bootstrapStrategy: process.env.FIREBASE_API_KEY ? 'firebase' : 'local',
491
+ }
492
+ );
493
+
494
+ console.log(`\n${c('bold', 'NETWORK STATUS:')}`);
495
+ const stats = network.getStats();
496
+ console.log(` ${c('cyan', 'Mode:')} ${c('green', stats.mode)}`);
497
+ console.log(` ${c('cyan', 'Bootstrap:')} ${stats.bootstrapMode}`);
498
+ console.log(` ${c('cyan', 'Peers:')} ${stats.peers}`);
499
+ console.log(` ${c('cyan', 'Firebase:')} ${stats.firebaseConnected ? c('green', 'Connected') : c('yellow', 'Not configured')}`);
500
+ console.log(` ${c('cyan', 'DHT Peers:')} ${stats.dhtPeers}`);
501
+ console.log(` ${c('cyan', 'Ledger Balance:')} ${stats.ledgerBalance}`);
502
+
503
+ console.log(`\n${c('dim', 'Press Ctrl+C to stop.')}`);
504
+
505
+ // Periodic status updates
506
+ setInterval(() => {
507
+ const s = network.getStats();
508
+ process.stdout.write(`\r${c('dim', `[${new Date().toLocaleTimeString()}]`)} Peers: ${s.peers} | Mode: ${s.mode} | Balance: ${s.ledgerBalance} `);
509
+ }, 5000);
510
+
511
+ process.on('SIGINT', async () => {
512
+ console.log(`\n\n${c('yellow', 'Stopping P2P network...')}`);
513
+ await network.stop();
514
+ console.log(`${c('green', '✓')} Network stopped.`);
515
+ process.exit(0);
516
+ });
517
+
518
+ } catch (err) {
519
+ console.error(`${c('red', '✗ Failed to start P2P network:')}\n`, err.message);
520
+ console.log(`\n${c('dim', 'Tip: Run')} ${c('cyan', 'npx @ruvector/edge-net firebase')} ${c('dim', 'to setup Firebase bootstrap.')}`);
521
+ process.exit(1);
522
+ }
523
+ }
524
+
425
525
  // Main
426
526
  const command = process.argv[2] || 'help';
427
527
 
@@ -432,6 +532,19 @@ switch (command) {
432
532
  case 'join':
433
533
  runJoin();
434
534
  break;
535
+ case 'genesis':
536
+ case 'signaling':
537
+ runGenesis();
538
+ break;
539
+ case 'firebase':
540
+ case 'firebase-setup':
541
+ case 'gcloud':
542
+ runFirebaseSetup();
543
+ break;
544
+ case 'p2p':
545
+ case 'network':
546
+ runP2P();
547
+ break;
435
548
  case 'benchmark':
436
549
  case 'bench':
437
550
  runBenchmark();
@@ -0,0 +1,435 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @ruvector/edge-net Firebase Setup
4
+ *
5
+ * Secure setup using Google Cloud CLI and Application Default Credentials.
6
+ * No API keys stored in environment variables - uses gcloud auth instead.
7
+ *
8
+ * Prerequisites:
9
+ * 1. Install Google Cloud CLI: https://cloud.google.com/sdk/docs/install
10
+ * 2. Login: gcloud auth login
11
+ * 3. Login for application: gcloud auth application-default login
12
+ *
13
+ * Usage:
14
+ * npx edge-net firebase-setup
15
+ * npx edge-net firebase-setup --project my-project-id
16
+ * npx edge-net firebase-setup --check
17
+ *
18
+ * @module @ruvector/edge-net/firebase-setup
19
+ */
20
+
21
+ import { execSync, spawn } from 'child_process';
22
+ import { existsSync, writeFileSync, readFileSync, mkdirSync } from 'fs';
23
+ import { homedir } from 'os';
24
+ import { join } from 'path';
25
+
26
+ // ============================================
27
+ // CONFIGURATION
28
+ // ============================================
29
+
30
+ const CONFIG_DIR = join(homedir(), '.edge-net');
31
+ const CONFIG_FILE = join(CONFIG_DIR, 'firebase.json');
32
+
33
+ // Required Firebase services
34
+ const REQUIRED_APIS = [
35
+ 'firebase.googleapis.com',
36
+ 'firestore.googleapis.com',
37
+ 'firebasedatabase.googleapis.com',
38
+ ];
39
+
40
+ // ============================================
41
+ // GCLOUD HELPERS
42
+ // ============================================
43
+
44
+ /**
45
+ * Check if gcloud CLI is installed
46
+ */
47
+ function checkGcloud() {
48
+ try {
49
+ execSync('gcloud --version', { stdio: 'pipe' });
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Get current gcloud configuration
58
+ */
59
+ function getGcloudConfig() {
60
+ try {
61
+ const account = execSync('gcloud config get-value account', { stdio: 'pipe' }).toString().trim();
62
+ const project = execSync('gcloud config get-value project', { stdio: 'pipe' }).toString().trim();
63
+ return { account, project };
64
+ } catch {
65
+ return { account: null, project: null };
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Check Application Default Credentials
71
+ */
72
+ function checkADC() {
73
+ const adcPath = join(homedir(), '.config', 'gcloud', 'application_default_credentials.json');
74
+ return existsSync(adcPath);
75
+ }
76
+
77
+ /**
78
+ * Enable required APIs
79
+ */
80
+ function enableAPIs(projectId) {
81
+ console.log('\n📦 Enabling required Firebase APIs...');
82
+ for (const api of REQUIRED_APIS) {
83
+ try {
84
+ execSync(`gcloud services enable ${api} --project=${projectId}`, { stdio: 'pipe' });
85
+ console.log(` ✅ ${api}`);
86
+ } catch (err) {
87
+ console.log(` ⚠️ ${api} (may already be enabled)`);
88
+ }
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Create Firestore database
94
+ */
95
+ function createFirestore(projectId) {
96
+ console.log('\n🔥 Setting up Firestore...');
97
+ try {
98
+ // Check if Firestore already exists
99
+ execSync(`gcloud firestore databases describe --project=${projectId}`, { stdio: 'pipe' });
100
+ console.log(' ✅ Firestore database exists');
101
+ } catch {
102
+ // Create Firestore in native mode
103
+ try {
104
+ execSync(`gcloud firestore databases create --location=us-central --project=${projectId}`, { stdio: 'pipe' });
105
+ console.log(' ✅ Firestore database created (us-central)');
106
+ } catch (err) {
107
+ console.log(' ⚠️ Could not create Firestore (may need manual setup)');
108
+ }
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Create Realtime Database
114
+ */
115
+ function createRealtimeDB(projectId) {
116
+ console.log('\n📊 Setting up Realtime Database...');
117
+ try {
118
+ execSync(`firebase database:instances:create ${projectId}-rtdb --project=${projectId} --location=us-central1`, { stdio: 'pipe' });
119
+ console.log(` ✅ Realtime Database created: ${projectId}-rtdb`);
120
+ } catch {
121
+ console.log(' ⚠️ Realtime Database (may need Firebase CLI or manual setup)');
122
+ console.log(' 💡 Run: npm install -g firebase-tools && firebase init database');
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Setup Firestore security rules
128
+ */
129
+ function setupSecurityRules(projectId) {
130
+ const rules = `rules_version = '2';
131
+ service cloud.firestore {
132
+ match /databases/{database}/documents {
133
+ // Edge-net signaling - authenticated users can read/write their signals
134
+ match /edge-net/signals/{signalId} {
135
+ allow read: if request.auth != null && resource.data.to == request.auth.uid;
136
+ allow create: if request.auth != null && request.resource.data.from == request.auth.uid;
137
+ allow delete: if request.auth != null && resource.data.to == request.auth.uid;
138
+ }
139
+
140
+ // Edge-net peers - public read, authenticated write
141
+ match /edge-net/peers/{peerId} {
142
+ allow read: if true;
143
+ allow write: if request.auth != null && request.auth.uid == peerId;
144
+ }
145
+
146
+ // Edge-net ledger - user can only access own ledger
147
+ match /edge-net/ledger/{peerId} {
148
+ allow read, write: if request.auth != null && request.auth.uid == peerId;
149
+ }
150
+ }
151
+ }`;
152
+
153
+ console.log('\n🔒 Firestore Security Rules:');
154
+ console.log(' Store these in firestore.rules and deploy with:');
155
+ console.log(' firebase deploy --only firestore:rules\n');
156
+ console.log(rules);
157
+
158
+ // Save rules file
159
+ const rulesPath = join(process.cwd(), 'firestore.rules');
160
+ writeFileSync(rulesPath, rules);
161
+ console.log(`\n ✅ Saved to: ${rulesPath}`);
162
+ }
163
+
164
+ /**
165
+ * Setup Realtime Database security rules
166
+ */
167
+ function setupRTDBRules(projectId) {
168
+ const rules = {
169
+ "rules": {
170
+ "presence": {
171
+ "$room": {
172
+ "$peerId": {
173
+ ".read": true,
174
+ ".write": "auth != null && auth.uid == $peerId"
175
+ }
176
+ }
177
+ }
178
+ }
179
+ };
180
+
181
+ console.log('\n🔒 Realtime Database Rules:');
182
+ console.log(JSON.stringify(rules, null, 2));
183
+
184
+ // Save rules file
185
+ const rulesPath = join(process.cwd(), 'database.rules.json');
186
+ writeFileSync(rulesPath, JSON.stringify(rules, null, 2));
187
+ console.log(`\n ✅ Saved to: ${rulesPath}`);
188
+ }
189
+
190
+ /**
191
+ * Generate local config (no secrets!)
192
+ */
193
+ function generateConfig(projectId) {
194
+ const config = {
195
+ projectId,
196
+ // These are NOT secrets - they're meant to be public
197
+ // API key restrictions happen in Google Cloud Console
198
+ authDomain: `${projectId}.firebaseapp.com`,
199
+ databaseURL: `https://${projectId}-default-rtdb.firebaseio.com`,
200
+ storageBucket: `${projectId}.appspot.com`,
201
+ // Security note
202
+ _note: 'Use Application Default Credentials for server-side. Generate restricted API key for browser in Google Cloud Console.',
203
+ _adcCommand: 'gcloud auth application-default login',
204
+ };
205
+
206
+ // Create config directory
207
+ if (!existsSync(CONFIG_DIR)) {
208
+ mkdirSync(CONFIG_DIR, { recursive: true });
209
+ }
210
+
211
+ // Save config
212
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
213
+ console.log(`\n📁 Config saved to: ${CONFIG_FILE}`);
214
+
215
+ return config;
216
+ }
217
+
218
+ /**
219
+ * Get API key securely (creates if needed)
220
+ */
221
+ async function setupAPIKey(projectId) {
222
+ console.log('\n🔑 API Key Setup:');
223
+ console.log(' For browser-side Firebase, you need a restricted API key.');
224
+ console.log(' \n Steps:');
225
+ console.log(' 1. Go to: https://console.cloud.google.com/apis/credentials?project=' + projectId);
226
+ console.log(' 2. Create API Key → Restrict to:');
227
+ console.log(' - HTTP referrers (websites): your-domain.com/*');
228
+ console.log(' - APIs: Firebase Realtime Database, Cloud Firestore');
229
+ console.log(' 3. Set environment variable: export FIREBASE_API_KEY=your-key');
230
+ console.log('\n For Node.js server-side, use Application Default Credentials (more secure):');
231
+ console.log(' gcloud auth application-default login');
232
+ }
233
+
234
+ // ============================================
235
+ // MAIN SETUP FLOW
236
+ // ============================================
237
+
238
+ async function setup(options = {}) {
239
+ console.log('🚀 Edge-Net Firebase Setup\n');
240
+ console.log('=' .repeat(50));
241
+
242
+ // Step 1: Check gcloud
243
+ console.log('\n1️⃣ Checking Google Cloud CLI...');
244
+ if (!checkGcloud()) {
245
+ console.error('❌ Google Cloud CLI not found!');
246
+ console.log(' Install from: https://cloud.google.com/sdk/docs/install');
247
+ process.exit(1);
248
+ }
249
+ console.log(' ✅ gcloud CLI found');
250
+
251
+ // Step 2: Check authentication
252
+ console.log('\n2️⃣ Checking authentication...');
253
+ const { account, project } = getGcloudConfig();
254
+ if (!account) {
255
+ console.error('❌ Not logged in to gcloud!');
256
+ console.log(' Run: gcloud auth login');
257
+ process.exit(1);
258
+ }
259
+ console.log(` ✅ Logged in as: ${account}`);
260
+
261
+ // Step 3: Check ADC
262
+ console.log('\n3️⃣ Checking Application Default Credentials...');
263
+ if (!checkADC()) {
264
+ console.log(' ⚠️ ADC not configured');
265
+ console.log(' Run: gcloud auth application-default login');
266
+ console.log('\n Setting up now...');
267
+ try {
268
+ execSync('gcloud auth application-default login', { stdio: 'inherit' });
269
+ } catch {
270
+ console.log(' ⚠️ ADC setup cancelled or failed');
271
+ }
272
+ } else {
273
+ console.log(' ✅ ADC configured');
274
+ }
275
+
276
+ // Step 4: Select project
277
+ const projectId = options.project || project;
278
+ console.log(`\n4️⃣ Using project: ${projectId}`);
279
+ if (!projectId) {
280
+ console.error('❌ No project specified!');
281
+ console.log(' Run: gcloud config set project YOUR_PROJECT_ID');
282
+ console.log(' Or: npx edge-net firebase-setup --project YOUR_PROJECT_ID');
283
+ process.exit(1);
284
+ }
285
+
286
+ // Step 5: Enable APIs
287
+ enableAPIs(projectId);
288
+
289
+ // Step 6: Setup Firestore
290
+ createFirestore(projectId);
291
+
292
+ // Step 7: Setup Realtime Database
293
+ createRealtimeDB(projectId);
294
+
295
+ // Step 8: Generate security rules
296
+ setupSecurityRules(projectId);
297
+ setupRTDBRules(projectId);
298
+
299
+ // Step 9: Generate config
300
+ const config = generateConfig(projectId);
301
+
302
+ // Step 10: API Key guidance
303
+ await setupAPIKey(projectId);
304
+
305
+ // Done!
306
+ console.log('\n' + '='.repeat(50));
307
+ console.log('✅ Firebase setup complete!\n');
308
+ console.log('Next steps:');
309
+ console.log('1. Deploy security rules: firebase deploy --only firestore:rules,database');
310
+ console.log('2. Create restricted API key in Google Cloud Console');
311
+ console.log('3. Set FIREBASE_API_KEY environment variable');
312
+ console.log('4. Test with: npx edge-net join\n');
313
+
314
+ return config;
315
+ }
316
+
317
+ /**
318
+ * Check current status
319
+ */
320
+ function checkStatus() {
321
+ console.log('🔍 Edge-Net Firebase Status\n');
322
+
323
+ // Check gcloud
324
+ const hasGcloud = checkGcloud();
325
+ console.log(`gcloud CLI: ${hasGcloud ? '✅' : '❌'}`);
326
+
327
+ // Check auth
328
+ const { account, project } = getGcloudConfig();
329
+ console.log(`Logged in: ${account ? `✅ ${account}` : '❌'}`);
330
+ console.log(`Project: ${project ? `✅ ${project}` : '❌'}`);
331
+
332
+ // Check ADC
333
+ const hasADC = checkADC();
334
+ console.log(`Application Default Credentials: ${hasADC ? '✅' : '❌'}`);
335
+
336
+ // Check config file
337
+ const hasConfig = existsSync(CONFIG_FILE);
338
+ console.log(`Config file: ${hasConfig ? `✅ ${CONFIG_FILE}` : '❌'}`);
339
+
340
+ // Check env vars
341
+ const hasApiKey = !!process.env.FIREBASE_API_KEY;
342
+ console.log(`FIREBASE_API_KEY: ${hasApiKey ? '✅ (set)' : '⚠️ (not set - needed for browser)'}`);
343
+
344
+ console.log();
345
+
346
+ if (!hasGcloud || !account || !project) {
347
+ console.log('💡 Run setup: npx edge-net firebase-setup');
348
+ } else if (!hasADC) {
349
+ console.log('💡 Run: gcloud auth application-default login');
350
+ } else if (!hasConfig) {
351
+ console.log('💡 Run setup: npx edge-net firebase-setup');
352
+ } else {
353
+ console.log('✅ Ready to use Firebase bootstrap!');
354
+ }
355
+ }
356
+
357
+ /**
358
+ * Load saved config
359
+ */
360
+ export function loadConfig() {
361
+ if (!existsSync(CONFIG_FILE)) {
362
+ return null;
363
+ }
364
+
365
+ try {
366
+ return JSON.parse(readFileSync(CONFIG_FILE, 'utf8'));
367
+ } catch {
368
+ return null;
369
+ }
370
+ }
371
+
372
+ /**
373
+ * Get Firebase config (from env vars or saved config)
374
+ */
375
+ export function getFirebaseConfigSecure() {
376
+ // First try environment variables
377
+ const apiKey = process.env.FIREBASE_API_KEY;
378
+ const projectId = process.env.FIREBASE_PROJECT_ID;
379
+
380
+ if (apiKey && projectId) {
381
+ return {
382
+ apiKey,
383
+ projectId,
384
+ authDomain: process.env.FIREBASE_AUTH_DOMAIN || `${projectId}.firebaseapp.com`,
385
+ databaseURL: process.env.FIREBASE_DATABASE_URL || `https://${projectId}-default-rtdb.firebaseio.com`,
386
+ storageBucket: process.env.FIREBASE_STORAGE_BUCKET || `${projectId}.appspot.com`,
387
+ };
388
+ }
389
+
390
+ // Try saved config (needs API key from env still for security)
391
+ const config = loadConfig();
392
+ if (config && apiKey) {
393
+ return {
394
+ apiKey,
395
+ ...config,
396
+ };
397
+ }
398
+
399
+ return null;
400
+ }
401
+
402
+ // ============================================
403
+ // CLI
404
+ // ============================================
405
+
406
+ const args = process.argv.slice(2);
407
+
408
+ if (args.includes('--check')) {
409
+ checkStatus();
410
+ } else if (args.includes('--help') || args.includes('-h')) {
411
+ console.log(`
412
+ Edge-Net Firebase Setup
413
+
414
+ Usage:
415
+ npx edge-net firebase-setup Setup Firebase with gcloud
416
+ npx edge-net firebase-setup --project ID Use specific project
417
+ npx edge-net firebase-setup --check Check current status
418
+
419
+ Prerequisites:
420
+ 1. Install gcloud: https://cloud.google.com/sdk/docs/install
421
+ 2. Login: gcloud auth login
422
+ 3. Set project: gcloud config set project YOUR_PROJECT_ID
423
+
424
+ Security:
425
+ - Uses Application Default Credentials (no stored secrets)
426
+ - API keys restricted by domain in Google Cloud Console
427
+ - Firestore rules protect user data
428
+ `);
429
+ } else {
430
+ const projectIndex = args.indexOf('--project');
431
+ const project = projectIndex >= 0 ? args[projectIndex + 1] : null;
432
+ setup({ project });
433
+ }
434
+
435
+ export { setup, checkStatus };