electerm-data-tool 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 electerm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,264 @@
1
+ # Electerm Data Tool
2
+
3
+ A command-line utility for managing Electerm application data, including database migration from v1 (NeDB) to v2 (SQLite) and data export functionality.
4
+
5
+ ## Features
6
+
7
+ - 🔄 **Database Migration**: Migrate Electerm data from v1 (NeDB) to v2 (SQLite)
8
+ - 📤 **Data Export**: Export all Electerm data to a single JSON file with decrypted passwords
9
+ - 📊 **Database Info**: Display information about your current Electerm database
10
+ - 🔐 **Password Decryption**: Automatically decrypt passwords during export for readable backups
11
+
12
+ ## Installation
13
+
14
+ ### Quick Start with npx (Recommended)
15
+
16
+ No installation required! Run the tool directly using `npx`:
17
+
18
+ ```bash
19
+ npx electerm-data-tool migrate
20
+ npx electerm-data-tool export ~/backup.json
21
+ npx electerm-data-tool info
22
+ ```
23
+
24
+ ### Global Installation
25
+
26
+ ```bash
27
+ npm install -g electerm-data-tool
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ### Command Overview
33
+
34
+ **Using npx (no installation required):**
35
+ ```bash
36
+ npx electerm-data-tool [command] [options]
37
+ ```
38
+
39
+ **Using globally installed version:**
40
+ ```bash
41
+ electerm-data-tool [command] [options]
42
+ ```
43
+
44
+ Available commands:
45
+
46
+ - `migrate` - Migrate database from v1 to v2
47
+ - `export <path>` - Export all data to JSON file
48
+ - `info` - Display database information
49
+ - `--help` - Show help information
50
+ - `--version` - Show version number
51
+
52
+ ### 1. Database Migration
53
+
54
+ Migrate your Electerm database from v1 (NeDB) to v2 (SQLite):
55
+
56
+ ```bash
57
+ electerm-data-tool migrate
58
+ ```
59
+
60
+ This command will:
61
+ - Check if migration is needed
62
+ - Migrate all data from NeDB files to SQLite database
63
+ - Create backups of original NeDB files with timestamp
64
+ - Perform any necessary data upgrades
65
+
66
+ **Note**: Requires Node.js 22.0.0 or higher for SQLite support.
67
+
68
+ ### 2. Data Export
69
+
70
+ Export all Electerm data to a JSON file with decrypted passwords:
71
+
72
+ ```bash
73
+ electerm-data-tool export /path/to/backup.json
74
+ ```
75
+
76
+ Example:
77
+ ```bash
78
+ electerm-data-tool export ~/electerm-backup-2025-09-03.json
79
+ ```
80
+
81
+ The exported JSON will contain:
82
+ - All bookmarks with decrypted passwords
83
+ - Bookmark groups and folder structure
84
+ - Terminal themes
85
+ - Quick commands
86
+ - Profiles
87
+ - Configuration settings
88
+ - And all other Electerm data
89
+
90
+ **Important**: The exported file contains plain-text passwords. Store it securely and delete when no longer needed.
91
+
92
+ ### 3. Database Information
93
+
94
+ View information about your current Electerm database:
95
+
96
+ ```bash
97
+ electerm-data-tool info
98
+ ```
99
+
100
+ This will show:
101
+ - Database type (v1 NeDB or v2 SQLite)
102
+ - Number of records in each table
103
+ - Migration recommendations if applicable
104
+
105
+ ## Database Detection
106
+
107
+ The tool automatically detects whether you're using:
108
+
109
+ - **v1 Database (NeDB)**: Original file-based database format
110
+ - **v2 Database (SQLite)**: New SQLite-based format (Node.js 22+ required)
111
+
112
+ When exporting data:
113
+ - If v1 database is detected, uses NeDB module for data access
114
+ - If v2 database is detected, uses SQLite module for data access
115
+ - Passwords are automatically decrypted in both cases
116
+
117
+ ## Data Structure
118
+
119
+ ### Export Format
120
+
121
+ The exported JSON follows this structure:
122
+
123
+ ```json
124
+ {
125
+ "bookmarks": [...],
126
+ "bookmarkGroups": [...],
127
+ "terminalThemes": [...],
128
+ "quickCommands": [...],
129
+ "profiles": [...],
130
+ "config": {...},
131
+ "addressBookmarks": [...],
132
+ "lastStates": [...],
133
+ "data": [...],
134
+ "log": [...],
135
+ "dbUpgradeLog": [...]
136
+ }
137
+ ```
138
+
139
+ ### Password Handling
140
+
141
+ - Passwords stored in Electerm are encrypted using a simple character-based encryption
142
+ - During export, passwords are automatically decrypted to plain text
143
+ - The `passwordEncrypted` flag is removed from exported data
144
+ - Exported passwords are human-readable for backup purposes
145
+
146
+ ## Requirements
147
+
148
+ - **Node.js**: 16.0.0 or higher
149
+ - **For SQLite (v2)**: Node.js 22.0.0 or higher
150
+ - **Dependencies**:
151
+ - `commander` - CLI framework
152
+ - `@yetzt/nedb` - NeDB database support
153
+ - `nanoid` - ID generation
154
+
155
+ ## File Locations
156
+
157
+ The tool operates on Electerm data stored in the standard locations:
158
+
159
+ **Database Files:**
160
+ - NeDB (v1): `~/.electerm/users/{username}/electerm.{table}.nedb`
161
+ - SQLite (v2): `~/.electerm/users/{username}/electerm.db`
162
+
163
+ **Backup Files:**
164
+ During migration, original NeDB files are renamed with timestamp:
165
+ - `electerm.bookmarks.nedb-{timestamp}.bak`
166
+
167
+ ## Examples
168
+
169
+ ### Complete Migration Workflow
170
+
171
+ **Using npx (recommended):**
172
+ ```bash
173
+ # 1. Check current database status
174
+ npx electerm-data-tool info
175
+
176
+ # 2. Export current data as backup
177
+ npx electerm-data-tool export ~/electerm-backup-before-migration.json
178
+
179
+ # 3. Perform migration
180
+ npx electerm-data-tool migrate
181
+
182
+ # 4. Verify migration succeeded
183
+ npx electerm-data-tool info
184
+
185
+ # 5. Export migrated data to verify
186
+ npx electerm-data-tool export ~/electerm-backup-after-migration.json
187
+ ```
188
+
189
+ **Using globally installed version:**
190
+ ```bash
191
+ # 1. Check current database status
192
+ electerm-data-tool info
193
+
194
+ # 2. Export current data as backup
195
+ electerm-data-tool export ~/electerm-backup-before-migration.json
196
+
197
+ # 3. Perform migration
198
+ electerm-data-tool migrate
199
+
200
+ # 4. Verify migration succeeded
201
+ electerm-data-tool info
202
+
203
+ # 5. Export migrated data to verify
204
+ electerm-data-tool export ~/electerm-backup-after-migration.json
205
+ ```
206
+
207
+ ### Using with npm scripts
208
+
209
+ ```bash
210
+ # Quick migration
211
+ npm run migrate
212
+
213
+ # Quick export
214
+ npm run export ~/backup.json
215
+
216
+ # Quick info
217
+ npm run info
218
+ ```
219
+
220
+ ## Troubleshooting
221
+
222
+ ### Migration Issues
223
+
224
+ **"Migration not needed"**: Your database is already v2 or no v1 files exist.
225
+
226
+ **SQLite errors**: Ensure you're using Node.js 22.0.0 or higher.
227
+
228
+ **Permission errors**: Ensure you have read/write access to Electerm data directory.
229
+
230
+ ### Export Issues
231
+
232
+ **Empty export**: Check that Electerm has been run and contains data.
233
+
234
+ **Encrypted passwords in export**: The tool should automatically decrypt passwords. If you see encrypted text, there may be an issue with the decryption module.
235
+
236
+ ### General Issues
237
+
238
+ **Command not found**: If installed globally, ensure npm global bin directory is in your PATH.
239
+
240
+ **Module errors**: Run `npm install` to ensure all dependencies are installed.
241
+
242
+ ## Security Considerations
243
+
244
+ - **Exported files contain plain-text passwords** - store securely
245
+ - **Delete export files** after use if they're temporary backups
246
+ - **File permissions** - exported files inherit system default permissions
247
+ - **Local processing only** - no data is transmitted over network
248
+
249
+ ## Contributing
250
+
251
+ 1. Fork the repository
252
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
253
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
254
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
255
+ 5. Open a Pull Request
256
+
257
+ ## Related Projects
258
+
259
+ - [Electerm](https://github.com/electerm/electerm) - The main Electerm terminal application
260
+ - [Electerm Documentation](https://electerm.html5beta.com/) - Official documentation
261
+
262
+ ## License
263
+
264
+ MIT License - see [LICENSE](LICENSE) file for details.
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "electerm-data-tool",
3
+ "version": "1.0.0",
4
+ "description": "electerm data export/migrate tool",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "electerm-data-tool": "./src/index.js"
8
+ },
9
+ "scripts": {
10
+ "migrate": "node src/index.js migrate",
11
+ "export": "node src/index.js export",
12
+ "info": "node src/index.js info",
13
+ "update": "node -r dotenv/config bin/update-version.js",
14
+ "lint": "standard",
15
+ "fix": "standard --fix"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/electerm/electerm-data-tool.git"
20
+ },
21
+ "keywords": [
22
+ "electerm",
23
+ "data",
24
+ "tool",
25
+ "migrate",
26
+ "export"
27
+ ],
28
+ "author": "ZHAO Xudong <zxdong@gmail.com>",
29
+ "license": "MIT",
30
+ "bugs": {
31
+ "url": "https://github.com/electerm/electerm-data-tool/issues"
32
+ },
33
+ "files": [
34
+ "src",
35
+ "LICENSE",
36
+ "README.md"
37
+ ],
38
+ "homepage": "https://github.com/electerm/electerm-data-tool#readme",
39
+ "dependencies": {
40
+ "@yetzt/nedb": "^1.8.0",
41
+ "commander": "^14.0.0",
42
+ "lodash": "^4.17.21",
43
+ "nanoid": "^3.3.8"
44
+ },
45
+ "standard": {
46
+ "ignore": [
47
+ "*.html",
48
+ "/res/",
49
+ "/temp",
50
+ "/data",
51
+ "/public"
52
+ ],
53
+ "parserOptions": {
54
+ "requireConfigFile": false,
55
+ "sourceType": "module"
56
+ }
57
+ },
58
+ "devDependencies": {
59
+ "axios": "^1.11.0",
60
+ "dotenv": "^17.2.2",
61
+ "standard": "^17.1.2"
62
+ }
63
+ }
@@ -0,0 +1,24 @@
1
+ const path = require('path')
2
+ const os = require('os')
3
+ const version = '1.101.16'
4
+
5
+ function getAppPath () {
6
+ const home = os.homedir()
7
+ const platform = process.platform
8
+ if (platform === 'darwin') {
9
+ // macOS
10
+ return path.join(home, 'Library', 'Application Support')
11
+ } else if (platform === 'win32') {
12
+ // Windows
13
+ return process.env.APPDATA || path.join(home, 'AppData', 'Roaming')
14
+ } else {
15
+ // Linux and others
16
+ return path.join(home, '.config')
17
+ }
18
+ }
19
+
20
+ exports.appPath = process.env.APP_PATH || getAppPath()
21
+ exports.defaultUserName = 'default_user'
22
+ exports.packInfo = {
23
+ version
24
+ }
@@ -0,0 +1 @@
1
+ module.exports = console
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Password encryption/decryption utilities
3
+ * Based on electerm's pass-enc.js
4
+ */
5
+
6
+ const enc = (str) => {
7
+ if (typeof str !== 'string') {
8
+ return str
9
+ }
10
+ return str.split('').map((s, i) => {
11
+ return String.fromCharCode((s.charCodeAt(0) + i + 1) % 65536)
12
+ }).join('')
13
+ }
14
+
15
+ const dec = (str) => {
16
+ if (typeof str !== 'string') {
17
+ return str
18
+ }
19
+ return str.split('').map((s, i) => {
20
+ return String.fromCharCode((s.charCodeAt(0) - i - 1 + 65536) % 65536)
21
+ }).join('')
22
+ }
23
+
24
+ /**
25
+ * Decrypt password in an object
26
+ * @param {object} obj
27
+ */
28
+ function decObj (obj) {
29
+ if (obj.passwordEncrypted && obj.password) {
30
+ obj.password = dec(obj.password)
31
+ delete obj.passwordEncrypted
32
+ }
33
+ return obj
34
+ }
35
+
36
+ /**
37
+ * Encrypt password in an object
38
+ * @param {object} obj
39
+ */
40
+ function encObj (obj) {
41
+ if (!obj.passwordEncrypted && obj.password) {
42
+ obj.password = enc(obj.password)
43
+ obj.passwordEncrypted = true
44
+ }
45
+ return obj
46
+ }
47
+
48
+ module.exports = {
49
+ enc,
50
+ dec,
51
+ encObj,
52
+ decObj
53
+ }
@@ -0,0 +1,5 @@
1
+ const { nanoid } = require('nanoid')
2
+
3
+ module.exports = () => {
4
+ return nanoid(7)
5
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * version compare
3
+ * @param {string} a
4
+ * @param {string} b
5
+ * @return {number}
6
+ */
7
+ // compare version '1.0.0' '12.0.3'
8
+ // return 1 when a > b
9
+ // return -1 when a < b
10
+ // return 0 when a === b
11
+ module.exports = exports.default = function (a, b) {
12
+ const ar = a.split('.').map(n => Number(n.replace('v', '')))
13
+ const br = b.split('.').map(n => Number(n.replace('v', '')))
14
+ let res = 0
15
+ for (let i = 0, len = br.length; i < len; i++) {
16
+ if (br[i] < ar[i]) {
17
+ res = 1
18
+ break
19
+ } else if (br[i] > ar[i]) {
20
+ res = -1
21
+ break
22
+ }
23
+ }
24
+ return res
25
+ }
package/src/index.js ADDED
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Electerm Data Tool - Command Line Interface
5
+ * Provides tools to migrate and export electerm data
6
+ */
7
+
8
+ const { Command } = require('commander')
9
+ const { writeFileSync } = require('fs')
10
+ const { resolve } = require('path')
11
+ const { migrate } = require('./migrate/migrate-1-to-2')
12
+ const log = require('./common/log')
13
+ const pkg = require('../package.json')
14
+
15
+ const program = new Command()
16
+
17
+ /**
18
+ * Get the major version number from Node.js version string
19
+ * @returns {number} Major version number
20
+ */
21
+ function getNodeMajorVersion () {
22
+ const nodeVersion = process.version
23
+ return parseInt(nodeVersion.slice(1).split('.')[0])
24
+ }
25
+
26
+ program
27
+ .name('electerm-data-tool')
28
+ .description('CLI tool for electerm data migration and export')
29
+ .version(pkg.version)
30
+
31
+ /**
32
+ * Migration command - migrates from NeDB (v1) to SQLite (v2)
33
+ */
34
+ program
35
+ .command('migrate')
36
+ .description('Migrate electerm database from v1 (NeDB) to v2 (SQLite)')
37
+ .action(async () => {
38
+ try {
39
+ // Check Node.js version requirement for SQLite
40
+ const majorVersion = getNodeMajorVersion()
41
+
42
+ if (majorVersion < 22) {
43
+ console.error('❌ Migration requires Node.js v22.0.0 or higher for SQLite support')
44
+ console.error(` Current version: ${process.version}`)
45
+ console.error(' Please upgrade Node.js and try again.')
46
+ console.error(' You can still use the export function with your current Node.js version.')
47
+ process.exit(1)
48
+ }
49
+
50
+ log.info('Starting migration process...')
51
+ await migrate()
52
+ log.info('Migration completed successfully!')
53
+ console.log('✅ Migration from NeDB to SQLite completed successfully!')
54
+ } catch (error) {
55
+ log.error('Migration failed:', error)
56
+ console.error('❌ Migration failed:', error.message)
57
+ process.exit(1)
58
+ }
59
+ })
60
+
61
+ /**
62
+ * Export command - exports all electerm data to a JSON file
63
+ */
64
+ program
65
+ .command('export')
66
+ .description('Export all electerm data to a JSON file')
67
+ .argument('<output-path>', 'Path to the output JSON file')
68
+ .action(async (outputPath) => {
69
+ try {
70
+ log.info('Starting data export...')
71
+
72
+ // Check if migration is needed to determine which database to use
73
+ const { checkMigrate } = require('./migrate/migrate-1-to-2')
74
+ const shouldMigrate = checkMigrate()
75
+
76
+ let dbModule
77
+ let dbType
78
+
79
+ if (shouldMigrate) {
80
+ // v1 database (NeDB) detected
81
+ dbModule = require('./nedb')
82
+ dbType = 'NeDB (v1)'
83
+ log.info('Detected v1 database, using NeDB for export')
84
+ } else {
85
+ // v2 database (SQLite) or no data
86
+ try {
87
+ dbModule = require('./sqlite')
88
+ dbType = 'SQLite (v2)'
89
+ log.info('Using SQLite database for export')
90
+ } catch (error) {
91
+ log.error('Failed to load SQLite module:', error.message)
92
+ console.error('❌ Failed to load database module')
93
+ process.exit(1)
94
+ }
95
+ }
96
+
97
+ const { dbAction, tables } = dbModule
98
+ const exportData = {}
99
+
100
+ // Import password decryption utilities
101
+ const { decObj } = require('./common/pass-enc')
102
+
103
+ // Helper function to decrypt passwords in data objects
104
+ const decryptPasswords = (data) => {
105
+ if (Array.isArray(data)) {
106
+ return data.map(item => {
107
+ if (item && typeof item === 'object') {
108
+ return decObj({ ...item })
109
+ }
110
+ return item
111
+ })
112
+ }
113
+ return data
114
+ }
115
+
116
+ // Export all tables
117
+ for (const table of tables) {
118
+ try {
119
+ log.info(`Exporting table: ${table}`)
120
+ const data = await dbAction(table, 'find', {})
121
+
122
+ // Decrypt passwords in the data
123
+ const decryptedData = decryptPasswords(data)
124
+
125
+ exportData[table] = decryptedData || []
126
+ log.info(`Exported ${decryptedData?.length || 0} records from ${table}`)
127
+ } catch (error) {
128
+ log.warn(`Failed to export table ${table}:`, error.message)
129
+ exportData[table] = []
130
+ }
131
+ }
132
+
133
+ // Also try to export config if it exists in the data table
134
+ try {
135
+ const configData = await dbAction('data', 'findOne', { _id: 'config' })
136
+ if (configData && configData.value) {
137
+ exportData.config = configData.value
138
+ log.info('Exported config data')
139
+ }
140
+ } catch (error) {
141
+ log.warn('Failed to export config data:', error.message)
142
+ }
143
+
144
+ console.log(`📊 Database Type: ${dbType}`)
145
+
146
+ // Resolve the output path
147
+ const resolvedPath = resolve(process.cwd(), outputPath)
148
+
149
+ // Write the JSON file
150
+ const jsonString = JSON.stringify(exportData, null, 2)
151
+ writeFileSync(resolvedPath, jsonString, 'utf8')
152
+
153
+ const totalRecords = Object.values(exportData).reduce((sum, table) => {
154
+ return sum + (Array.isArray(table) ? table.length : 0)
155
+ }, 0)
156
+
157
+ log.info(`Export completed. ${totalRecords} total records exported to ${resolvedPath}`)
158
+ console.log('✅ Export completed successfully!')
159
+ console.log(`📄 ${totalRecords} total records exported to: ${resolvedPath}`)
160
+ } catch (error) {
161
+ log.error('Export failed:', error)
162
+ console.error('❌ Export failed:', error.message)
163
+ process.exit(1)
164
+ }
165
+ })
166
+
167
+ /**
168
+ * Info command - displays information about the current electerm data
169
+ */
170
+ program
171
+ .command('info')
172
+ .description('Display information about the current electerm data')
173
+ .action(async () => {
174
+ try {
175
+ // Check if migration is needed to determine which database to use
176
+ const { checkMigrate } = require('./migrate/migrate-1-to-2')
177
+ const shouldMigrate = checkMigrate()
178
+
179
+ let dbModule
180
+ let dbType
181
+
182
+ if (shouldMigrate) {
183
+ // v1 database (NeDB) detected
184
+ dbModule = require('./nedb')
185
+ dbType = 'NeDB (v1) - Migration recommended'
186
+
187
+ // Check Node.js version for migration capability
188
+ const majorVersion = getNodeMajorVersion()
189
+
190
+ console.log('⚠️ v1 database detected.')
191
+ if (majorVersion >= 22) {
192
+ console.log(' Run \'electerm-data-tool migrate\' to upgrade to v2')
193
+ } else {
194
+ console.log(` Migration requires Node.js v22.0.0+ (current: ${process.version})`)
195
+ console.log(' Please upgrade Node.js to enable migration to v2')
196
+ }
197
+ } else {
198
+ // v2 database (SQLite) or no data
199
+ try {
200
+ dbModule = require('./sqlite')
201
+ dbType = 'SQLite (v2)'
202
+ } catch (error) {
203
+ console.error('❌ Failed to read database:', error.message)
204
+ process.exit(1)
205
+ }
206
+ }
207
+
208
+ const { dbAction, tables } = dbModule
209
+ console.log('📊 Electerm Data Information')
210
+ console.log(`Database Type: ${dbType}`)
211
+ console.log('='.repeat(40))
212
+
213
+ let totalRecords = 0
214
+ for (const table of tables) {
215
+ try {
216
+ const data = await dbAction(table, 'find', {})
217
+ const count = data?.length || 0
218
+ totalRecords += count
219
+ console.log(`${table.padEnd(20)}: ${count} records`)
220
+ } catch (error) {
221
+ console.log(`${table.padEnd(20)}: Error reading table`)
222
+ }
223
+ }
224
+
225
+ console.log('='.repeat(40))
226
+ console.log(`Total Records: ${totalRecords}`)
227
+ } catch (error) {
228
+ console.error('❌ Failed to read data:', error.message)
229
+ process.exit(1)
230
+ }
231
+ })
232
+
233
+ // Parse command line arguments
234
+ program.parse()