pal-explorer-cli 0.4.11 → 0.4.13
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/README.md +149 -149
- package/bin/pal.js +63 -2
- package/extensions/@palexplorer/analytics/extension.json +20 -1
- package/extensions/@palexplorer/analytics/index.js +19 -9
- package/extensions/@palexplorer/audit/extension.json +14 -0
- package/extensions/@palexplorer/auth-email/extension.json +15 -0
- package/extensions/@palexplorer/auth-oauth/extension.json +15 -0
- package/extensions/@palexplorer/chat/extension.json +14 -0
- package/extensions/@palexplorer/discovery/extension.json +17 -0
- package/extensions/@palexplorer/discovery/index.js +1 -1
- package/extensions/@palexplorer/email-notifications/extension.json +23 -0
- package/extensions/@palexplorer/groups/extension.json +15 -0
- package/extensions/@palexplorer/share-links/extension.json +15 -0
- package/extensions/@palexplorer/sync/extension.json +16 -0
- package/extensions/@palexplorer/user-mgmt/extension.json +15 -0
- package/lib/capabilities.js +24 -24
- package/lib/commands/analytics.js +175 -175
- package/lib/commands/api-keys.js +131 -131
- package/lib/commands/audit.js +235 -235
- package/lib/commands/auth.js +137 -137
- package/lib/commands/backup.js +76 -76
- package/lib/commands/billing.js +148 -148
- package/lib/commands/chat.js +217 -217
- package/lib/commands/cloud-backup.js +231 -231
- package/lib/commands/comment.js +99 -99
- package/lib/commands/completion.js +203 -203
- package/lib/commands/compliance.js +218 -218
- package/lib/commands/config.js +136 -136
- package/lib/commands/connect.js +44 -44
- package/lib/commands/dept.js +294 -294
- package/lib/commands/device.js +146 -146
- package/lib/commands/download.js +240 -226
- package/lib/commands/explorer.js +178 -178
- package/lib/commands/extension.js +1060 -970
- package/lib/commands/favorite.js +90 -90
- package/lib/commands/federation.js +270 -270
- package/lib/commands/file.js +533 -533
- package/lib/commands/group.js +271 -271
- package/lib/commands/gui-share.js +29 -29
- package/lib/commands/init.js +61 -61
- package/lib/commands/invite.js +59 -59
- package/lib/commands/list.js +58 -58
- package/lib/commands/log.js +116 -116
- package/lib/commands/nearby.js +108 -108
- package/lib/commands/network.js +251 -251
- package/lib/commands/notify.js +198 -198
- package/lib/commands/org.js +273 -273
- package/lib/commands/pal.js +403 -180
- package/lib/commands/permissions.js +216 -216
- package/lib/commands/pin.js +97 -97
- package/lib/commands/protocol.js +357 -357
- package/lib/commands/rbac.js +147 -147
- package/lib/commands/recover.js +36 -36
- package/lib/commands/register.js +171 -171
- package/lib/commands/relay.js +131 -131
- package/lib/commands/remote.js +368 -368
- package/lib/commands/revoke.js +50 -50
- package/lib/commands/scanner.js +280 -280
- package/lib/commands/schedule.js +344 -344
- package/lib/commands/scim.js +203 -203
- package/lib/commands/search.js +181 -181
- package/lib/commands/serve.js +438 -438
- package/lib/commands/server.js +350 -350
- package/lib/commands/share-link.js +199 -199
- package/lib/commands/share.js +336 -323
- package/lib/commands/sso.js +200 -200
- package/lib/commands/status.js +145 -145
- package/lib/commands/stream.js +562 -562
- package/lib/commands/su.js +187 -187
- package/lib/commands/sync.js +979 -979
- package/lib/commands/transfers.js +152 -152
- package/lib/commands/uninstall.js +188 -188
- package/lib/commands/update.js +204 -204
- package/lib/commands/user.js +276 -276
- package/lib/commands/vfs.js +84 -84
- package/lib/commands/web-login.js +79 -79
- package/lib/commands/web.js +52 -52
- package/lib/commands/webhook.js +180 -180
- package/lib/commands/whoami.js +59 -59
- package/lib/commands/workspace.js +121 -121
- package/lib/core/billing.js +16 -5
- package/lib/core/dhtDiscovery.js +9 -2
- package/lib/core/discoveryClient.js +13 -7
- package/lib/core/extensions.js +142 -1
- package/lib/core/identity.js +33 -2
- package/lib/core/imageProcessor.js +109 -0
- package/lib/core/imageTorrent.js +167 -0
- package/lib/core/permissions.js +1 -1
- package/lib/core/pro.js +11 -4
- package/lib/core/serverList.js +4 -1
- package/lib/core/shares.js +12 -1
- package/lib/core/signalingServer.js +14 -2
- package/lib/core/su.js +1 -1
- package/lib/core/users.js +1 -1
- package/lib/protocol/messages.js +12 -3
- package/lib/utils/explorer.js +1 -1
- package/lib/utils/help.js +357 -357
- package/lib/utils/torrent.js +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
# Pal Explorer (`
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/pal-explorer-cli)
|
|
4
|
-
[](LICENSE)
|
|
5
|
-
[](https://nodejs.org/)
|
|
6
|
-
|
|
7
|
-
> Peer-to-peer file sharing with end-to-end encryption. No cloud. No middleman.
|
|
8
|
-
|
|
9
|
-
Pal Explorer lets you share files directly with friends using P2P protocols. Files are encrypted before leaving your device, transferred via WebTorrent, and only decryptable by intended recipients.
|
|
10
|
-
|
|
11
|
-
**All features free during beta.** Download at [palexplorer.com](https://palexplorer.com).
|
|
12
|
-
|
|
13
|
-
## Quick Start
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# Install CLI globally
|
|
17
|
-
npm install -g pal-explorer-cli
|
|
18
|
-
|
|
19
|
-
# Create your identity
|
|
20
|
-
|
|
21
|
-
# Save the 24-word recovery phrase!
|
|
22
|
-
|
|
23
|
-
# Share a folder with a friend
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# Start seeding
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# Download from a peer
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Adding Friends
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Features
|
|
43
|
-
|
|
44
|
-
### File Sharing
|
|
45
|
-
- Share files, folders, or entire drives via WebTorrent
|
|
46
|
-
- Private shares with per-recipient E2EE (XChaCha20-Poly1305)
|
|
47
|
-
- Public shares with global magnet links
|
|
48
|
-
- Web share links with expiry and download limits
|
|
49
|
-
|
|
50
|
-
### Sync
|
|
51
|
-
- Push/pull directory sync between pals
|
|
52
|
-
- SHA-256 manifest-based delta sync
|
|
53
|
-
- Watch mode for automatic sync on file changes
|
|
54
|
-
- Conflict detection
|
|
55
|
-
|
|
56
|
-
### Chat
|
|
57
|
-
- Real-time encrypted messaging between pals
|
|
58
|
-
- Chat history with conversation list
|
|
59
|
-
|
|
60
|
-
### Groups
|
|
61
|
-
- Create named groups and organize pals
|
|
62
|
-
- Share with entire groups in one command (`--with-group`)
|
|
63
|
-
- Broadcast messages to all group members
|
|
64
|
-
|
|
65
|
-
### Discovery & Presence
|
|
66
|
-
- LAN peer discovery via mDNS
|
|
67
|
-
- Federated handle system (`@alice@server.com`)
|
|
68
|
-
- DHT-based decentralized fallback
|
|
69
|
-
- Online/offline presence status
|
|
70
|
-
|
|
71
|
-
### Security
|
|
72
|
-
- **Ed25519 identities** with private keys stored in OS credential manager
|
|
73
|
-
- **XChaCha20-Poly1305** authenticated encryption for all private shares
|
|
74
|
-
- **Per-recipient key wrapping** -- each recipient gets a uniquely encrypted share key
|
|
75
|
-
- **Key rotation on revocation** -- removing a recipient triggers re-encryption
|
|
76
|
-
- **BIP-39 recovery** -- 24-word mnemonic phrase for identity backup
|
|
77
|
-
- **Zero-knowledge server** -- discovery server never sees your private key or files
|
|
78
|
-
- **Signed server responses** -- clients verify server authenticity
|
|
79
|
-
- **Encrypted inbox** -- message payloads encrypted end-to-end
|
|
80
|
-
- **PIN lock** -- protect the desktop app with a PIN code
|
|
81
|
-
|
|
82
|
-
## CLI
|
|
83
|
-
|
|
84
|
-
The `
|
|
85
|
-
|
|
86
|
-
### Key Commands
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Global Flags
|
|
101
|
-
|
|
102
|
-
| Flag | Description |
|
|
103
|
-
|:---|:---|
|
|
104
|
-
| `--json` | Output as JSON |
|
|
105
|
-
| `--verbose` | Verbose logging |
|
|
106
|
-
| `--quiet` | Suppress non-essential output |
|
|
107
|
-
|
|
108
|
-
Run `pe --help` or `pe <command> --help` for full usage.
|
|
109
|
-
|
|
110
|
-
## Desktop App
|
|
111
|
-
|
|
112
|
-
Download the desktop app at [palexplorer.com/download](https://palexplorer.com/download).
|
|
113
|
-
|
|
114
|
-
Features: setup wizard, dark/light themes, system tray, drag-and-drop sharing, P2P chat, PIN lock, media streaming, extensions, file explorer, command palette (Ctrl+K), and workspaces.
|
|
115
|
-
|
|
116
|
-
## Extensions
|
|
117
|
-
|
|
118
|
-
14 built-in extensions including virtual drive (WebDAV), folder sync, chat, groups, discovery, OAuth login, email notifications, and more. All free during beta.
|
|
119
|
-
|
|
120
|
-
Browse extensions at [palexplorer.com/extensions](https://palexplorer.com/extensions).
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Configuration
|
|
129
|
-
|
|
130
|
-
| Key | Default | Description |
|
|
131
|
-
|:---|:---|:---|
|
|
132
|
-
| `port` | auto | Local seeder port |
|
|
133
|
-
| `storage_path` | `./downloads` | Default download directory |
|
|
134
|
-
| `max_connections` | `50` | Max P2P connections |
|
|
135
|
-
| `bandwidth_cap` | `0` | Upload cap in KB/s (0 = unlimited) |
|
|
136
|
-
|
|
137
|
-
Config file: `~/.config/palexplorer-cli/config.json`
|
|
138
|
-
|
|
139
|
-
## Links
|
|
140
|
-
|
|
141
|
-
- [Website](https://palexplorer.com)
|
|
142
|
-
- [Download](https://palexplorer.com/download)
|
|
143
|
-
- [Extensions](https://palexplorer.com/extensions)
|
|
144
|
-
- [Marketplace](https://palexplorer.com/marketplace)
|
|
145
|
-
- [Discord](https://discord.gg/VrCcGmNJ8Q)
|
|
146
|
-
|
|
147
|
-
## License
|
|
148
|
-
|
|
149
|
-
Proprietary. All rights reserved. See [LICENSE.md](LICENSE.md).
|
|
1
|
+
# Pal Explorer (`pal`)
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/pal-explorer-cli)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
> Peer-to-peer file sharing with end-to-end encryption. No cloud. No middleman.
|
|
8
|
+
|
|
9
|
+
Pal Explorer lets you share files directly with friends using P2P protocols. Files are encrypted before leaving your device, transferred via WebTorrent, and only decryptable by intended recipients.
|
|
10
|
+
|
|
11
|
+
**All features free during beta.** Download at [palexplorer.com](https://palexplorer.com).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Install CLI globally
|
|
17
|
+
npm install -g pal-explorer-cli
|
|
18
|
+
|
|
19
|
+
# Create your identity
|
|
20
|
+
pal init "YourName"
|
|
21
|
+
# Save the 24-word recovery phrase!
|
|
22
|
+
|
|
23
|
+
# Share a folder with a friend
|
|
24
|
+
pal share ~/Documents --visibility private --with Alice
|
|
25
|
+
|
|
26
|
+
# Start seeding
|
|
27
|
+
pal serve
|
|
28
|
+
|
|
29
|
+
# Download from a peer
|
|
30
|
+
pal download "magnet:?xt=urn:btih:..."
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Adding Friends
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pal invite --qr # Generate invite link + QR code
|
|
37
|
+
pal pal add @alice # Add by handle
|
|
38
|
+
pal pal add pal://eyJ... # Add by invite link
|
|
39
|
+
pal nearby --add # Auto-discover on LAN
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
### File Sharing
|
|
45
|
+
- Share files, folders, or entire drives via WebTorrent
|
|
46
|
+
- Private shares with per-recipient E2EE (XChaCha20-Poly1305)
|
|
47
|
+
- Public shares with global magnet links
|
|
48
|
+
- Web share links with expiry and download limits
|
|
49
|
+
|
|
50
|
+
### Sync
|
|
51
|
+
- Push/pull directory sync between pals
|
|
52
|
+
- SHA-256 manifest-based delta sync
|
|
53
|
+
- Watch mode for automatic sync on file changes
|
|
54
|
+
- Conflict detection
|
|
55
|
+
|
|
56
|
+
### Chat
|
|
57
|
+
- Real-time encrypted messaging between pals
|
|
58
|
+
- Chat history with conversation list
|
|
59
|
+
|
|
60
|
+
### Groups
|
|
61
|
+
- Create named groups and organize pals
|
|
62
|
+
- Share with entire groups in one command (`--with-group`)
|
|
63
|
+
- Broadcast messages to all group members
|
|
64
|
+
|
|
65
|
+
### Discovery & Presence
|
|
66
|
+
- LAN peer discovery via mDNS
|
|
67
|
+
- Federated handle system (`@alice@server.com`)
|
|
68
|
+
- DHT-based decentralized fallback
|
|
69
|
+
- Online/offline presence status
|
|
70
|
+
|
|
71
|
+
### Security
|
|
72
|
+
- **Ed25519 identities** with private keys stored in OS credential manager
|
|
73
|
+
- **XChaCha20-Poly1305** authenticated encryption for all private shares
|
|
74
|
+
- **Per-recipient key wrapping** -- each recipient gets a uniquely encrypted share key
|
|
75
|
+
- **Key rotation on revocation** -- removing a recipient triggers re-encryption
|
|
76
|
+
- **BIP-39 recovery** -- 24-word mnemonic phrase for identity backup
|
|
77
|
+
- **Zero-knowledge server** -- discovery server never sees your private key or files
|
|
78
|
+
- **Signed server responses** -- clients verify server authenticity
|
|
79
|
+
- **Encrypted inbox** -- message payloads encrypted end-to-end
|
|
80
|
+
- **PIN lock** -- protect the desktop app with a PIN code
|
|
81
|
+
|
|
82
|
+
## CLI
|
|
83
|
+
|
|
84
|
+
The `pal` CLI includes 100+ subcommands.
|
|
85
|
+
|
|
86
|
+
### Key Commands
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pal init <name> # Create identity
|
|
90
|
+
pal register <handle> # Register on discovery network
|
|
91
|
+
pal share <path> -v private -w bob # Share encrypted with a pal
|
|
92
|
+
pal serve # Start seeding
|
|
93
|
+
pal download <magnet> # Download from magnet link
|
|
94
|
+
pal pal add @alice # Add a pal by handle
|
|
95
|
+
pal sync push ./project alice # Push sync to a pal
|
|
96
|
+
pal status # System health dashboard
|
|
97
|
+
pal ext list # List available extensions
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Global Flags
|
|
101
|
+
|
|
102
|
+
| Flag | Description |
|
|
103
|
+
|:---|:---|
|
|
104
|
+
| `--json` | Output as JSON |
|
|
105
|
+
| `--verbose` | Verbose logging |
|
|
106
|
+
| `--quiet` | Suppress non-essential output |
|
|
107
|
+
|
|
108
|
+
Run `pe --help` or `pe <command> --help` for full usage.
|
|
109
|
+
|
|
110
|
+
## Desktop App
|
|
111
|
+
|
|
112
|
+
Download the desktop app at [palexplorer.com/download](https://palexplorer.com/download).
|
|
113
|
+
|
|
114
|
+
Features: setup wizard, dark/light themes, system tray, drag-and-drop sharing, P2P chat, PIN lock, media streaming, extensions, file explorer, command palette (Ctrl+K), and workspaces.
|
|
115
|
+
|
|
116
|
+
## Extensions
|
|
117
|
+
|
|
118
|
+
14 built-in extensions including virtual drive (WebDAV), folder sync, chat, groups, discovery, OAuth login, email notifications, and more. All free during beta.
|
|
119
|
+
|
|
120
|
+
Browse extensions at [palexplorer.com/extensions](https://palexplorer.com/extensions).
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pal ext list # List all extensions
|
|
124
|
+
pal ext enable @palexplorer/vfs # Enable an extension
|
|
125
|
+
pal ext config @palexplorer/vfs port 1900 # Configure
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Configuration
|
|
129
|
+
|
|
130
|
+
| Key | Default | Description |
|
|
131
|
+
|:---|:---|:---|
|
|
132
|
+
| `port` | auto | Local seeder port |
|
|
133
|
+
| `storage_path` | `./downloads` | Default download directory |
|
|
134
|
+
| `max_connections` | `50` | Max P2P connections |
|
|
135
|
+
| `bandwidth_cap` | `0` | Upload cap in KB/s (0 = unlimited) |
|
|
136
|
+
|
|
137
|
+
Config file: `~/.config/palexplorer-cli/config.json`
|
|
138
|
+
|
|
139
|
+
## Links
|
|
140
|
+
|
|
141
|
+
- [Website](https://palexplorer.com)
|
|
142
|
+
- [Download](https://palexplorer.com/download)
|
|
143
|
+
- [Extensions](https://palexplorer.com/extensions)
|
|
144
|
+
- [Marketplace](https://palexplorer.com/marketplace)
|
|
145
|
+
- [Discord](https://discord.gg/VrCcGmNJ8Q)
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
Proprietary. All rights reserved. See [LICENSE.md](LICENSE.md).
|
package/bin/pal.js
CHANGED
|
@@ -47,7 +47,7 @@ if (logLevelIdx !== -1 && process.argv[logLevelIdx + 1]) {
|
|
|
47
47
|
logger.applyGlobalOverride();
|
|
48
48
|
|
|
49
49
|
program
|
|
50
|
-
.name('
|
|
50
|
+
.name('pal')
|
|
51
51
|
.description('p2p file sharing for friends')
|
|
52
52
|
.version('0.4.0')
|
|
53
53
|
.option('--json', 'output in JSON format')
|
|
@@ -173,10 +173,11 @@ ${chalk.cyan.bold('Command Groups:')}
|
|
|
173
173
|
${chalk.yellow('Pro:')} backup, api-keys
|
|
174
174
|
${chalk.yellow('Streaming:')} stream local/remote/stop/status/broadcast/join/transport
|
|
175
175
|
${chalk.yellow('Extensions:')} ext list/install/remove/enable/disable/info/config/create
|
|
176
|
+
${chalk.yellow('Ext Commands:')} <ext-name> <command> (run commands contributed by extensions)
|
|
176
177
|
${chalk.yellow('Orgs:')} org create/list/info/invite/remove/subscribe/unsubscribe/billing
|
|
177
178
|
${chalk.yellow('Utilities:')} status, log, completion, gui-share, uninstall
|
|
178
179
|
|
|
179
|
-
${chalk.gray('Aliases:
|
|
180
|
+
${chalk.gray('Aliases: pal connect → pal network connect, pal disconnect → pal network disconnect')}
|
|
180
181
|
`);
|
|
181
182
|
|
|
182
183
|
// Load extensions and emit lifecycle hooks
|
|
@@ -193,6 +194,59 @@ if (!isVersionOrHelp) {
|
|
|
193
194
|
const cleaned = cleanStaleTransfers(24);
|
|
194
195
|
if (cleaned > 0) console.log(`[transfers] Cleaned ${cleaned} stale transfer(s)`);
|
|
195
196
|
|
|
197
|
+
// Register extension-contributed CLI commands
|
|
198
|
+
const { getContributedCommands, invokeExtensionCommand } = await import('../lib/core/extensions.js');
|
|
199
|
+
const coreCommandNames = new Set(commands.map(c => c[0]));
|
|
200
|
+
const extCommands = getContributedCommands();
|
|
201
|
+
for (const { extension, commands: cmds } of extCommands) {
|
|
202
|
+
// Prevent namespace collision with core commands
|
|
203
|
+
const shortName = extension.replace(/^@palexplorer\//, '');
|
|
204
|
+
if (coreCommandNames.has(shortName) || coreCommandNames.has(extension)) {
|
|
205
|
+
console.warn(`[extensions] Skipping commands from ${extension}: name conflicts with core command`);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
// Each extension gets a parent command: pal <ext-name> <subcommand>
|
|
209
|
+
const extCmd = program.command(extension).description(`Commands from ${extension} extension`);
|
|
210
|
+
for (const cmd of cmds) {
|
|
211
|
+
const parts = cmd.name.split(' ');
|
|
212
|
+
let target = extCmd;
|
|
213
|
+
// Support nested subcommands like "scan report"
|
|
214
|
+
if (parts.length > 1) {
|
|
215
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
216
|
+
const existing = target.commands.find(c => c.name() === parts[i]);
|
|
217
|
+
target = existing || target.command(parts[i]);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const leafName = parts[parts.length - 1];
|
|
221
|
+
let cmdDef = leafName;
|
|
222
|
+
for (const arg of cmd.args) {
|
|
223
|
+
cmdDef += arg.required ? ` <${arg.name}>` : ` [${arg.name}]`;
|
|
224
|
+
}
|
|
225
|
+
const sub = target.command(cmdDef).description(cmd.description);
|
|
226
|
+
for (const opt of cmd.options) {
|
|
227
|
+
sub.option(opt.flags, opt.description);
|
|
228
|
+
}
|
|
229
|
+
sub.action(async (...actionArgs) => {
|
|
230
|
+
const opts = actionArgs[actionArgs.length - 1]?.opts?.() || actionArgs[actionArgs.length - 1] || {};
|
|
231
|
+
const positional = {};
|
|
232
|
+
cmd.args.forEach((arg, i) => { positional[arg.name] = actionArgs[i]; });
|
|
233
|
+
try {
|
|
234
|
+
const result = await invokeExtensionCommand(extension, cmd.name, positional, opts);
|
|
235
|
+
if (program.opts().json) {
|
|
236
|
+
console.log(JSON.stringify(result, null, 2));
|
|
237
|
+
} else if (result?.message) {
|
|
238
|
+
console.log(result.message);
|
|
239
|
+
} else if (result && typeof result === 'object') {
|
|
240
|
+
console.log(JSON.stringify(result, null, 2));
|
|
241
|
+
}
|
|
242
|
+
} catch (err) {
|
|
243
|
+
console.error(chalk.red(`[${extension}] ${err.message}`));
|
|
244
|
+
process.exitCode = 1;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
196
250
|
const identity = (await import('../lib/utils/config.js')).default.get('identity');
|
|
197
251
|
await hooks.emit('on:app:ready', {
|
|
198
252
|
version: program.version(),
|
|
@@ -227,5 +281,12 @@ if (!process.argv.slice(2).length) {
|
|
|
227
281
|
// keytar's native D-Bus handles block the event loop on headless Linux
|
|
228
282
|
const longRunning = new Set(['serve', 'nearby', 'stream']);
|
|
229
283
|
if (!longRunning.has(currentCmd)) {
|
|
284
|
+
// Flush analytics and run shutdown hooks before exiting
|
|
285
|
+
if (extensionsLoaded) {
|
|
286
|
+
try {
|
|
287
|
+
const { hooks } = await import('../lib/core/extensions.js');
|
|
288
|
+
await hooks.emit('on:app:shutdown', {});
|
|
289
|
+
} catch {}
|
|
290
|
+
}
|
|
230
291
|
process.exit(process.exitCode || 0);
|
|
231
292
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "analytics",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Anonymous usage analytics via PostHog — opt-in, no PII, privacy-safe",
|
|
5
5
|
"author": "Palexplorer Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,6 +22,25 @@
|
|
|
22
22
|
"posthogHost": { "type": "string", "default": "https://us.i.posthog.com", "description": "PostHog ingestion host" },
|
|
23
23
|
"sessionTracking": { "type": "boolean", "default": true, "description": "Track session duration" }
|
|
24
24
|
},
|
|
25
|
+
"help": {
|
|
26
|
+
"summary": "Tracks anonymous usage events (shares, downloads, sessions) via PostHog. No personal data is collected — only platform, version, and event counts.",
|
|
27
|
+
"usage": "Enabled by default. Disable with: pal ext config analytics enabled false",
|
|
28
|
+
"examples": [
|
|
29
|
+
"pal ext config analytics enabled false",
|
|
30
|
+
"pal ext config analytics posthogHost https://eu.posthog.com",
|
|
31
|
+
"pal ext config analytics sessionTracking false"
|
|
32
|
+
],
|
|
33
|
+
"configReference": {
|
|
34
|
+
"enabled": "Enable or disable analytics collection (true/false)",
|
|
35
|
+
"posthogKey": "PostHog project API key. Leave default unless self-hosting PostHog",
|
|
36
|
+
"posthogHost": "PostHog ingestion endpoint URL",
|
|
37
|
+
"sessionTracking": "Track how long the app is open per session (true/false)"
|
|
38
|
+
},
|
|
39
|
+
"links": {
|
|
40
|
+
"PostHog": "https://posthog.com",
|
|
41
|
+
"Privacy Policy": "https://palexplorer.com/privacy"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
25
44
|
"tier": "free",
|
|
26
45
|
"minAppVersion": "0.4.0"
|
|
27
46
|
}
|
|
@@ -23,7 +23,8 @@ function getDeviceId() {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function isEnabled() {
|
|
26
|
-
|
|
26
|
+
const v = ctx.config.get('enabled');
|
|
27
|
+
return v === true || v === undefined;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
function baseProperties() {
|
|
@@ -37,20 +38,24 @@ function baseProperties() {
|
|
|
37
38
|
async function initPostHog() {
|
|
38
39
|
if (posthog) return;
|
|
39
40
|
try {
|
|
40
|
-
// Resolve posthog-node from the app's node_modules (deployed extensions can't resolve from their own path)
|
|
41
41
|
let PostHog;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
const appRoot = ctx.app.appRoot || process.cwd();
|
|
43
|
+
// Try multiple resolution strategies for posthog-node
|
|
44
|
+
const strategies = [
|
|
45
|
+
() => { const r = createRequire(appRoot + '/package.json'); return r('posthog-node').PostHog; },
|
|
46
|
+
() => { const r = createRequire(process.cwd() + '/package.json'); return r('posthog-node').PostHog; },
|
|
47
|
+
];
|
|
48
|
+
for (const strategy of strategies) {
|
|
49
|
+
try { PostHog = strategy(); break; } catch {}
|
|
50
|
+
}
|
|
51
|
+
if (!PostHog) {
|
|
47
52
|
PostHog = (await import('posthog-node')).PostHog;
|
|
48
53
|
}
|
|
49
54
|
const key = ctx.config.get('posthogKey') || DEFAULT_POSTHOG_KEY;
|
|
50
55
|
const host = ctx.config.get('posthogHost') || 'https://us.i.posthog.com';
|
|
51
56
|
posthog = new PostHog(key, { host, flushAt: 20, flushInterval: FLUSH_INTERVAL });
|
|
52
57
|
} catch (err) {
|
|
53
|
-
ctx.logger.warn('PostHog
|
|
58
|
+
ctx.logger.warn('PostHog init failed:', err.message);
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -98,7 +103,12 @@ async function startTracking() {
|
|
|
98
103
|
sessionStart = Date.now();
|
|
99
104
|
initialized = true;
|
|
100
105
|
track('app_open');
|
|
101
|
-
|
|
106
|
+
if (posthog) {
|
|
107
|
+
await posthog.flush().catch(() => {});
|
|
108
|
+
ctx.logger.info('Analytics enabled — PostHog tracking started');
|
|
109
|
+
} else {
|
|
110
|
+
ctx.logger.warn('Analytics enabled but PostHog failed to initialize — events will not be sent');
|
|
111
|
+
}
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
export async function activate(context) {
|
|
@@ -13,5 +13,19 @@
|
|
|
13
13
|
]
|
|
14
14
|
},
|
|
15
15
|
"config": { "enabled": { "type": "boolean", "default": false } },
|
|
16
|
+
"help": {
|
|
17
|
+
"summary": "Records all share, transfer, and access events in a searchable audit trail. View who accessed what and when.",
|
|
18
|
+
"usage": "Enable: pal ext config audit enabled true. View logs: pal audit",
|
|
19
|
+
"examples": [
|
|
20
|
+
"pal ext config audit enabled true",
|
|
21
|
+
"pal audit",
|
|
22
|
+
"pal audit --filter share --after 2026-01-01",
|
|
23
|
+
"pal compliance export --format csv"
|
|
24
|
+
],
|
|
25
|
+
"configReference": {
|
|
26
|
+
"enabled": "Enable or disable audit trail logging (true/false)"
|
|
27
|
+
},
|
|
28
|
+
"links": {}
|
|
29
|
+
},
|
|
16
30
|
"tier": "free"
|
|
17
31
|
}
|
|
@@ -12,6 +12,21 @@
|
|
|
12
12
|
"verifiedEmail": { "type": "string", "default": "", "description": "Currently verified email" },
|
|
13
13
|
"verifiedToken": { "type": "string", "default": "", "description": "Verified JWT token" }
|
|
14
14
|
},
|
|
15
|
+
"help": {
|
|
16
|
+
"summary": "Links your email address to your Palexplorer identity for verification badges and account recovery. Uses the discovery server to send verification codes.",
|
|
17
|
+
"usage": "pal auth link-email <email> — starts the verification flow",
|
|
18
|
+
"examples": [
|
|
19
|
+
"pal auth link-email user@example.com",
|
|
20
|
+
"pal auth verify-email <code>",
|
|
21
|
+
"pal auth status"
|
|
22
|
+
],
|
|
23
|
+
"configReference": {
|
|
24
|
+
"server": "Discovery server URL used for email verification (default: discovery-1.palexplorer.com)",
|
|
25
|
+
"verifiedEmail": "Your currently verified email address (set automatically after verification)",
|
|
26
|
+
"verifiedToken": "JWT verification token (set automatically, do not edit)"
|
|
27
|
+
},
|
|
28
|
+
"links": {}
|
|
29
|
+
},
|
|
15
30
|
"tier": "free",
|
|
16
31
|
"minAppVersion": "0.5.0"
|
|
17
32
|
}
|
|
@@ -11,6 +11,21 @@
|
|
|
11
11
|
"providers": { "type": "array", "default": ["google", "github", "microsoft"], "description": "Enabled OAuth providers" },
|
|
12
12
|
"autoLink": { "type": "boolean", "default": true, "description": "Automatically link OAuth identity to Palexplorer identity" }
|
|
13
13
|
},
|
|
14
|
+
"help": {
|
|
15
|
+
"summary": "Sign in with Google, GitHub, or Microsoft using OAuth 2.0 PKCE flow. Links your social identity to your Palexplorer handle.",
|
|
16
|
+
"usage": "pal auth oauth <provider> — starts OAuth login flow in your browser",
|
|
17
|
+
"examples": [
|
|
18
|
+
"pal auth oauth google",
|
|
19
|
+
"pal auth oauth github",
|
|
20
|
+
"pal ext config auth-oauth providers '[\"google\",\"github\"]'",
|
|
21
|
+
"pal ext config auth-oauth autoLink false"
|
|
22
|
+
],
|
|
23
|
+
"configReference": {
|
|
24
|
+
"providers": "List of enabled OAuth providers: google, github, microsoft",
|
|
25
|
+
"autoLink": "Automatically link the OAuth identity to your Palexplorer handle (true/false)"
|
|
26
|
+
},
|
|
27
|
+
"links": {}
|
|
28
|
+
},
|
|
14
29
|
"tier": "free",
|
|
15
30
|
"minAppVersion": "0.5.0"
|
|
16
31
|
}
|
|
@@ -13,5 +13,19 @@
|
|
|
13
13
|
]
|
|
14
14
|
},
|
|
15
15
|
"config": { "enabled": { "type": "boolean", "default": false } },
|
|
16
|
+
"help": {
|
|
17
|
+
"summary": "End-to-end encrypted 1:1 messaging. Messages transfer directly via WebSocket when both peers are online, or queue through the discovery server inbox when offline.",
|
|
18
|
+
"usage": "pal chat send <handle> <message>",
|
|
19
|
+
"examples": [
|
|
20
|
+
"pal chat send alice 'Hey, check out my new share!'",
|
|
21
|
+
"pal chat history alice",
|
|
22
|
+
"pal chat fetch",
|
|
23
|
+
"pal chat flush"
|
|
24
|
+
],
|
|
25
|
+
"configReference": {
|
|
26
|
+
"enabled": "Enable or disable the chat feature (true/false)"
|
|
27
|
+
},
|
|
28
|
+
"links": {}
|
|
29
|
+
},
|
|
16
30
|
"tier": "free"
|
|
17
31
|
}
|
|
@@ -13,6 +13,23 @@
|
|
|
13
13
|
"refreshInterval": { "type": "number", "default": 1800000, "description": "Server list refresh interval in ms (default: 30 min)" },
|
|
14
14
|
"enableGossip": { "type": "boolean", "default": true, "description": "Exchange server lists with connected peers" }
|
|
15
15
|
},
|
|
16
|
+
"help": {
|
|
17
|
+
"summary": "Connects to discovery servers for @handle registration, online presence, and peer finding. Supports DHT-based gossip to discover additional servers automatically.",
|
|
18
|
+
"usage": "pal ext config discovery enabled true",
|
|
19
|
+
"examples": [
|
|
20
|
+
"pal ext config discovery enabled true",
|
|
21
|
+
"pal server list",
|
|
22
|
+
"pal server add https://my-server.example.com",
|
|
23
|
+
"pal ext config discovery enableGossip false"
|
|
24
|
+
],
|
|
25
|
+
"configReference": {
|
|
26
|
+
"enabled": "Enable or disable discovery server integration (true/false)",
|
|
27
|
+
"bootstrapServers": "List of discovery server URLs to connect to on startup",
|
|
28
|
+
"refreshInterval": "How often to refresh the server list, in milliseconds (default: 30 min)",
|
|
29
|
+
"enableGossip": "Exchange server lists with connected peers for automatic discovery (true/false)"
|
|
30
|
+
},
|
|
31
|
+
"links": {}
|
|
32
|
+
},
|
|
16
33
|
"tier": "free",
|
|
17
34
|
"minAppVersion": "0.4.0"
|
|
18
35
|
}
|
|
@@ -18,6 +18,29 @@
|
|
|
18
18
|
"toAddress": { "type": "string", "default": "", "description": "Recipient email address" },
|
|
19
19
|
"events": { "type": "array", "default": ["share:invite", "transfer:complete", "security:alert"], "description": "Enabled event types" }
|
|
20
20
|
},
|
|
21
|
+
"help": {
|
|
22
|
+
"summary": "Sends email notifications when shares are created, transfers complete, peers connect/disconnect, or security events occur. Supports SMTP, SendGrid, Mailgun, and Resend.",
|
|
23
|
+
"usage": "Configure your email provider, then enable events you want notifications for.",
|
|
24
|
+
"examples": [
|
|
25
|
+
"pal ext config email-notifications provider smtp",
|
|
26
|
+
"pal ext config email-notifications smtpHost smtp.gmail.com",
|
|
27
|
+
"pal ext config email-notifications smtpUser you@gmail.com",
|
|
28
|
+
"pal ext config email-notifications toAddress alerts@example.com",
|
|
29
|
+
"pal ext config email-notifications events '[\"share:invite\",\"security:alert\"]'"
|
|
30
|
+
],
|
|
31
|
+
"configReference": {
|
|
32
|
+
"provider": "Email service: smtp, sendgrid, mailgun, or resend",
|
|
33
|
+
"smtpHost": "SMTP server hostname (e.g. smtp.gmail.com)",
|
|
34
|
+
"smtpPort": "SMTP server port (587 for TLS, 465 for SSL)",
|
|
35
|
+
"smtpUser": "SMTP authentication username",
|
|
36
|
+
"smtpPass": "SMTP authentication password",
|
|
37
|
+
"apiKey": "API key when using SendGrid, Mailgun, or Resend",
|
|
38
|
+
"fromAddress": "Sender email address shown in notifications",
|
|
39
|
+
"toAddress": "Email address to receive notifications",
|
|
40
|
+
"events": "Event types to notify on: share:invite, transfer:complete, peer:connect, peer:disconnect, security:alert"
|
|
41
|
+
},
|
|
42
|
+
"links": {}
|
|
43
|
+
},
|
|
21
44
|
"tier": "free",
|
|
22
45
|
"minAppVersion": "0.5.0"
|
|
23
46
|
}
|
|
@@ -13,5 +13,20 @@
|
|
|
13
13
|
]
|
|
14
14
|
},
|
|
15
15
|
"config": { "enabled": { "type": "boolean", "default": false } },
|
|
16
|
+
"help": {
|
|
17
|
+
"summary": "Organize pals into groups. Share files with entire groups at once — all current and future members get access. Free: 2 groups, Pro: 20, Enterprise: unlimited.",
|
|
18
|
+
"usage": "pal group create <name>",
|
|
19
|
+
"examples": [
|
|
20
|
+
"pal group create 'Team Alpha'",
|
|
21
|
+
"pal group add 'Team Alpha' alice bob charlie",
|
|
22
|
+
"pal group list",
|
|
23
|
+
"pal group broadcast 'Team Alpha' 'Meeting in 10 min'",
|
|
24
|
+
"pal share ./docs --recipients group:Team Alpha"
|
|
25
|
+
],
|
|
26
|
+
"configReference": {
|
|
27
|
+
"enabled": "Enable or disable the groups feature (true/false)"
|
|
28
|
+
},
|
|
29
|
+
"links": {}
|
|
30
|
+
},
|
|
16
31
|
"tier": "free"
|
|
17
32
|
}
|