phonepod 0.0.1

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 (3) hide show
  1. package/README.md +88 -0
  2. package/bin/phonepod.js +214 -0
  3. package/package.json +35 -0
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # PhonePod
2
+
3
+ Solid pod on your phone. One command install for Android/Termux.
4
+
5
+ ## Features
6
+
7
+ - **Solid Pod** - Full LDP server with WebID, WAC
8
+ - **Nostr Relay** - Built-in NIP-01 relay
9
+ - **Git Server** - Clone and push via HTTP
10
+ - **~100MB RAM** - Lighter than a browser tab
11
+
12
+ ## Quick Install (Termux)
13
+
14
+ ```bash
15
+ pkg install nodejs-lts
16
+ npm install -g phonepod
17
+ phonepod start
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```bash
23
+ phonepod start # Start the pod
24
+ phonepod start --port 3000 # Custom port
25
+ phonepod tunnel user@host # Setup SSH tunnel for public access
26
+ phonepod status # Show configuration
27
+ ```
28
+
29
+ ## Public Access
30
+
31
+ To make your pod publicly accessible, you need a relay server:
32
+
33
+ ```bash
34
+ # Setup tunnel (generates SSH key, creates tunnel script)
35
+ phonepod tunnel ubuntu@relay.example.com
36
+
37
+ # Add the printed SSH key to your relay server
38
+ # Then start tunnel with PM2:
39
+ pm2 start ~/.phonepod/tunnel.sh --name tunnel
40
+ pm2 save
41
+ ```
42
+
43
+ ## Boot Persistence
44
+
45
+ Install Termux:Boot from F-Droid, then:
46
+
47
+ ```bash
48
+ mkdir -p ~/.termux/boot
49
+ echo '#!/bin/bash
50
+ termux-wake-lock
51
+ pm2 resurrect' > ~/.termux/boot/start.sh
52
+ chmod +x ~/.termux/boot/start.sh
53
+
54
+ # Save current processes
55
+ pm2 start phonepod -- start
56
+ pm2 save
57
+ ```
58
+
59
+ ## Endpoints
60
+
61
+ | Endpoint | Description |
62
+ |----------|-------------|
63
+ | `http://localhost:8080/` | Solid pod root |
64
+ | `ws://localhost:8080/relay` | Nostr relay |
65
+ | `http://localhost:8080/relay/info` | NIP-11 relay info |
66
+ | `git clone http://localhost:8080/` | Git clone |
67
+
68
+ ## Configuration
69
+
70
+ Config stored in `~/.phonepod/config.json`:
71
+
72
+ ```json
73
+ {
74
+ "port": 8080,
75
+ "nostr": true,
76
+ "git": true
77
+ }
78
+ ```
79
+
80
+ ## Requirements
81
+
82
+ - Android with Termux
83
+ - Node.js 18+
84
+ - For public access: relay server with SSH access
85
+
86
+ ## License
87
+
88
+ MIT
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * PhonePod CLI
5
+ *
6
+ * Solid pod on your phone - Android/Termux
7
+ *
8
+ * Usage:
9
+ * phonepod start [options] Start the pod
10
+ * phonepod setup Interactive setup
11
+ * phonepod tunnel <host> Setup SSH tunnel to relay
12
+ * phonepod status Show status
13
+ */
14
+
15
+ import { spawn } from 'child_process';
16
+ import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
17
+ import { join } from 'path';
18
+ import { homedir } from 'os';
19
+ import { createInterface } from 'readline';
20
+
21
+ const args = process.argv.slice(2);
22
+ const command = args[0];
23
+
24
+ // Config directory
25
+ const CONFIG_DIR = join(homedir(), '.phonepod');
26
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
27
+
28
+ // Ensure config dir exists
29
+ if (!existsSync(CONFIG_DIR)) {
30
+ mkdirSync(CONFIG_DIR, { recursive: true });
31
+ }
32
+
33
+ // Load or create config
34
+ function loadConfig() {
35
+ if (existsSync(CONFIG_FILE)) {
36
+ return JSON.parse(readFileSync(CONFIG_FILE, 'utf8'));
37
+ }
38
+ return { port: 8080, nostr: true, git: true };
39
+ }
40
+
41
+ function saveConfig(config) {
42
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
43
+ }
44
+
45
+ // Run JSS with phonepod defaults
46
+ function startPod(options = {}) {
47
+ const config = loadConfig();
48
+ const jssArgs = [
49
+ 'start',
50
+ '--port', String(options.port || config.port || 8080),
51
+ ];
52
+
53
+ if (options.nostr ?? config.nostr) jssArgs.push('--nostr');
54
+ if (options.git ?? config.git) jssArgs.push('--git');
55
+ if (options.root) jssArgs.push('--root', options.root);
56
+
57
+ console.log('Starting PhonePod...');
58
+ console.log(` Port: ${options.port || config.port || 8080}`);
59
+ console.log(` Nostr: ${(options.nostr ?? config.nostr) ? 'enabled' : 'disabled'}`);
60
+ console.log(` Git: ${(options.git ?? config.git) ? 'enabled' : 'disabled'}`);
61
+ console.log('');
62
+
63
+ // Find jss binary
64
+ const jss = spawn('jss', jssArgs, { stdio: 'inherit' });
65
+
66
+ jss.on('error', (err) => {
67
+ if (err.code === 'ENOENT') {
68
+ console.error('Error: jss not found. Run: npm install -g javascript-solid-server');
69
+ } else {
70
+ console.error('Error:', err.message);
71
+ }
72
+ process.exit(1);
73
+ });
74
+
75
+ jss.on('exit', (code) => process.exit(code || 0));
76
+ }
77
+
78
+ // Setup tunnel
79
+ async function setupTunnel(relayHost) {
80
+ if (!relayHost) {
81
+ console.error('Usage: phonepod tunnel <relay-host>');
82
+ console.error('Example: phonepod tunnel relay.example.com');
83
+ process.exit(1);
84
+ }
85
+
86
+ const config = loadConfig();
87
+ const port = config.port || 8080;
88
+
89
+ console.log('');
90
+ console.log('Setting up SSH tunnel to', relayHost);
91
+ console.log('');
92
+
93
+ // Check for SSH key
94
+ const sshKeyPath = join(homedir(), '.ssh', 'id_ed25519');
95
+ const sshPubKeyPath = sshKeyPath + '.pub';
96
+
97
+ if (!existsSync(sshKeyPath)) {
98
+ console.log('Generating SSH key...');
99
+ const keygen = spawn('ssh-keygen', ['-t', 'ed25519', '-f', sshKeyPath, '-N', ''], { stdio: 'inherit' });
100
+ await new Promise(resolve => keygen.on('exit', resolve));
101
+ }
102
+
103
+ // Show public key
104
+ if (existsSync(sshPubKeyPath)) {
105
+ const pubKey = readFileSync(sshPubKeyPath, 'utf8').trim();
106
+ console.log('');
107
+ console.log('Add this SSH key to your relay server:');
108
+ console.log('');
109
+ console.log(pubKey);
110
+ console.log('');
111
+ }
112
+
113
+ // Create tunnel script
114
+ const tunnelScript = join(CONFIG_DIR, 'tunnel.sh');
115
+ writeFileSync(tunnelScript, `#!/bin/bash
116
+ exec autossh -M 0 -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -N -R ${port}:localhost:${port} ${relayHost}
117
+ `);
118
+ spawn('chmod', ['+x', tunnelScript]);
119
+
120
+ console.log(`Tunnel script created: ${tunnelScript}`);
121
+ console.log('');
122
+ console.log('To start tunnel manually:');
123
+ console.log(` ${tunnelScript}`);
124
+ console.log('');
125
+ console.log('To add to PM2:');
126
+ console.log(` pm2 start ${tunnelScript} --name tunnel`);
127
+ console.log(' pm2 save');
128
+ console.log('');
129
+
130
+ // Save relay host to config
131
+ config.relayHost = relayHost;
132
+ saveConfig(config);
133
+ }
134
+
135
+ // Show status
136
+ function showStatus() {
137
+ const config = loadConfig();
138
+ console.log('');
139
+ console.log('PhonePod Configuration:');
140
+ console.log('');
141
+ console.log(` Port: ${config.port || 8080}`);
142
+ console.log(` Nostr: ${config.nostr ? 'enabled' : 'disabled'}`);
143
+ console.log(` Git: ${config.git ? 'enabled' : 'disabled'}`);
144
+ if (config.relayHost) {
145
+ console.log(` Relay: ${config.relayHost}`);
146
+ }
147
+ console.log('');
148
+ console.log(` Config: ${CONFIG_FILE}`);
149
+ console.log('');
150
+ }
151
+
152
+ // Help
153
+ function showHelp() {
154
+ console.log(`
155
+ PhonePod - Solid pod on your phone
156
+
157
+ Usage:
158
+ phonepod start [options] Start the pod
159
+ phonepod tunnel <host> Setup SSH tunnel to relay
160
+ phonepod status Show configuration
161
+ phonepod help Show this help
162
+
163
+ Start Options:
164
+ --port <n> Port to listen on (default: 8080)
165
+ --no-nostr Disable Nostr relay
166
+ --no-git Disable Git server
167
+
168
+ Examples:
169
+ phonepod start
170
+ phonepod start --port 3000
171
+ phonepod tunnel ubuntu@relay.example.com
172
+ `);
173
+ }
174
+
175
+ // Parse start options
176
+ function parseStartOptions() {
177
+ const options = {};
178
+ for (let i = 1; i < args.length; i++) {
179
+ if (args[i] === '--port' && args[i + 1]) {
180
+ options.port = parseInt(args[++i], 10);
181
+ } else if (args[i] === '--no-nostr') {
182
+ options.nostr = false;
183
+ } else if (args[i] === '--no-git') {
184
+ options.git = false;
185
+ } else if (args[i] === '--root' && args[i + 1]) {
186
+ options.root = args[++i];
187
+ }
188
+ }
189
+ return options;
190
+ }
191
+
192
+ // Main
193
+ switch (command) {
194
+ case 'start':
195
+ startPod(parseStartOptions());
196
+ break;
197
+ case 'tunnel':
198
+ setupTunnel(args[1]);
199
+ break;
200
+ case 'status':
201
+ showStatus();
202
+ break;
203
+ case 'help':
204
+ case '--help':
205
+ case '-h':
206
+ showHelp();
207
+ break;
208
+ default:
209
+ if (command) {
210
+ console.error(`Unknown command: ${command}`);
211
+ }
212
+ showHelp();
213
+ process.exit(command ? 1 : 0);
214
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "phonepod",
3
+ "version": "0.0.1",
4
+ "description": "Solid pod on your phone - one command install for Android/Termux",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "phonepod": "./bin/phonepod.js"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"No tests yet\""
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/JavaScriptSolidServer/phonepod.git"
16
+ },
17
+ "keywords": [
18
+ "solid",
19
+ "pod",
20
+ "phone",
21
+ "android",
22
+ "termux",
23
+ "nostr",
24
+ "decentralized"
25
+ ],
26
+ "author": "",
27
+ "license": "MIT",
28
+ "bugs": {
29
+ "url": "https://github.com/JavaScriptSolidServer/phonepod/issues"
30
+ },
31
+ "homepage": "https://github.com/JavaScriptSolidServer/phonepod#readme",
32
+ "dependencies": {
33
+ "javascript-solid-server": "^0.0.60"
34
+ }
35
+ }