@scriptdb/cli 1.0.8 → 1.1.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/README.md CHANGED
@@ -4,31 +4,20 @@ Command-line interface for ScriptDB - Database management with TypeScript script
4
4
 
5
5
  ## Installation
6
6
 
7
- ### From Binary (Info Only)
8
-
9
- Pre-built binaries are available for download:
10
-
11
- - **Linux x64**: `scriptdb-linux-x64`
12
- - **Linux ARM64**: `scriptdb-linux-arm64`
13
- - **Linux x64 (musl)**: `scriptdb-linux-x64-musl`
14
- - **Linux ARM64 (musl)**: `scriptdb-linux-arm64-musl`
15
- - **macOS x64 (Intel)**: `scriptdb-darwin-x64`
16
- - **macOS ARM64 (Apple Silicon)**: `scriptdb-darwin-arm64`
17
- - **Windows x64**: `scriptdb-windows-x64.exe`
18
-
19
- **Note**: These binaries are standalone info-only builds. They show help/version but don't include server functionality. For full functionality, install from source.
20
-
21
- Make it executable (Linux/macOS):
7
+ Install from npm:
22
8
  ```bash
23
- chmod +x scriptdb-*
24
- sudo mv scriptdb-* /usr/local/bin/scriptdb
9
+ npm install -g @scriptdb/cli
10
+ # or
11
+ bun add -g @scriptdb/cli
25
12
  ```
26
13
 
27
- ### From Source (Recommended for Full Functionality)
28
-
14
+ Install from source:
29
15
  ```bash
16
+ git clone <repo>
17
+ cd scriptdb
30
18
  bun install
31
- bun run build:all
19
+ bun run build
20
+ npm link
32
21
  ```
33
22
 
34
23
  ## Usage
@@ -109,6 +98,55 @@ Example:
109
98
  }
110
99
  ```
111
100
 
101
+ ### Package Management
102
+
103
+ Install packages to ScriptDB:
104
+ ```bash
105
+ # Install to ~/.scriptdb/packages
106
+ scriptdb add lodash
107
+ scriptdb add axios express
108
+
109
+ # Install to current directory
110
+ scriptdb add --local lodash
111
+ ```
112
+
113
+ Remove packages:
114
+ ```bash
115
+ # Remove from ~/.scriptdb/packages
116
+ scriptdb remove lodash
117
+
118
+ # Remove from current directory
119
+ scriptdb remove --local lodash
120
+ ```
121
+
122
+ ### Monitoring
123
+
124
+ View real-time logs:
125
+ ```bash
126
+ scriptdb logs
127
+ ```
128
+
129
+ Monitor performance (CPU, memory, uptime):
130
+ ```bash
131
+ scriptdb monit
132
+ ```
133
+
134
+ ## Commands
135
+
136
+ | Command | Description |
137
+ |---------|-------------|
138
+ | `scriptdb start [-d]` | Start server (`-d` for daemon/PM2 mode) |
139
+ | `scriptdb stop` | Stop the running server |
140
+ | `scriptdb restart [-d]` | Restart the server |
141
+ | `scriptdb status` | Check server status and view metrics |
142
+ | `scriptdb logs` | View real-time logs |
143
+ | `scriptdb monit` | Monitor performance (CPU, memory, uptime) |
144
+ | `scriptdb shell` | Start interactive shell |
145
+ | `scriptdb add <pkg>` | Install packages to ~/.scriptdb |
146
+ | `scriptdb add --local <pkg>` | Install packages to current directory |
147
+ | `scriptdb remove <pkg>` | Remove packages from ~/.scriptdb |
148
+ | `scriptdb remove --local <pkg>` | Remove packages from current directory |
149
+
112
150
  ## Building
113
151
 
114
152
  ### Build for all platforms (local)
@@ -145,10 +183,28 @@ bun run dev
145
183
 
146
184
  ## Files
147
185
 
148
- - PID file: `~/.scriptdb/scriptdb.pid`
149
- - Log file: `~/.scriptdb/scriptdb.log`
150
186
  - Config file: `~/.scriptdb/config.json`
187
+ - Ecosystem config: `~/.scriptdb/ecosystem.config.js` (PM2)
188
+ - PM2 logs: `~/.scriptdb/pm2-*.log`
151
189
  - Databases: `~/.scriptdb/databases/`
190
+ - Packages: `~/.scriptdb/packages/`
191
+
192
+ ## Changelog
193
+
194
+ ### 1.1.0 (2025-01-16)
195
+
196
+ **Added**
197
+ - Native `scriptdb logs` command to view real-time logs
198
+ - Native `scriptdb monit` command to monitor performance
199
+ - Native `scriptdb restart` command to restart the server
200
+ - Native `scriptdb stop` command to stop the server
201
+ - Dynamic version reading from package.json
202
+ - ESLint configuration for TypeScript linting
203
+
204
+ **Fixed**
205
+ - Fixed TypeScript module resolution errors
206
+ - Fixed test command to continue gracefully when packages have no tests
207
+ - Improved error handling and Windows compatibility
152
208
 
153
209
  ## License
154
210
 
package/dist/index.js CHANGED
@@ -93810,6 +93810,7 @@ class Protocal {
93810
93810
  IP_FAIL_WINDOW_MS;
93811
93811
  MAX_LOGIN_ATTEMPTS;
93812
93812
  LOCK_DURATION_MS;
93813
+ ENABLE_IP_LOCKOUT;
93813
93814
  MAX_MESSAGE_BYTES;
93814
93815
  MAX_MESSAGES_PER_CONNECTION;
93815
93816
  CONNECTION_TIMEOUT_MS;
@@ -93923,9 +93924,10 @@ class Protocal {
93923
93924
  });
93924
93925
  this.loginAttemptCache = new Map;
93925
93926
  this.ipAttemptCache = new Map;
93926
- this.IP_FAIL_WINDOW_MS = options2.ipFailWindowMs || 15 * 60 * 1000;
93927
- this.MAX_LOGIN_ATTEMPTS = options2.maxLoginAttempts || 5;
93928
- this.LOCK_DURATION_MS = options2.lockDurationMs || 15 * 60 * 1000;
93927
+ this.IP_FAIL_WINDOW_MS = options2.ipFailWindowMs || fileConfig.ipFailWindowMs || 15 * 60 * 1000;
93928
+ this.MAX_LOGIN_ATTEMPTS = options2.maxLoginAttempts || fileConfig.maxLoginAttempts || 5;
93929
+ this.LOCK_DURATION_MS = options2.lockDurationMs || fileConfig.lockDurationMs || 15 * 60 * 1000;
93930
+ this.ENABLE_IP_LOCKOUT = options2.enableIpLockout !== undefined ? options2.enableIpLockout : fileConfig.enableIpLockout !== undefined ? fileConfig.enableIpLockout : true;
93929
93931
  this.MAX_MESSAGE_BYTES = options2.maxMessageBytes || 64 * 1024;
93930
93932
  this.MAX_MESSAGES_PER_CONNECTION = options2.maxMessagesPerConnection || 1000;
93931
93933
  this.CONNECTION_TIMEOUT_MS = typeof options2.connectionTimeoutMs === "number" ? options2.connectionTimeoutMs : typeof fileConfig.connectionTimeoutMs === "number" ? fileConfig.connectionTimeoutMs : 0;
@@ -94371,32 +94373,34 @@ class Protocal {
94371
94373
  err: e && e.message || String(e)
94372
94374
  });
94373
94375
  }
94374
- const nowTs = Date.now();
94375
- const ipRec = this.ipAttemptCache.get(remoteIP) || {
94376
- attempts: 0,
94377
- lockedUntil: 0,
94378
- expiresAt: nowTs + this._attemptCacheTTL
94379
- };
94380
- ipRec.attempts = (ipRec.attempts || 0) + 1;
94381
- ipRec.expiresAt = nowTs + this._attemptCacheTTL;
94382
- if (ipRec.attempts >= this.MAX_LOGIN_ATTEMPTS) {
94383
- ipRec.lockedUntil = nowTs + this.LOCK_DURATION_MS;
94384
- this.audit("ip.lockout", {
94385
- ip: remoteIP,
94386
- attempts: ipRec.attempts
94387
- });
94388
- }
94389
- this.ipAttemptCache.set(remoteIP, ipRec);
94390
- if (ipRec.lockedUntil && ipRec.lockedUntil > nowTs) {
94391
- this.audit("ip.locked", { ip: remoteIP });
94392
- try {
94393
- sendWithBackpressure({
94394
- command: "login",
94395
- message: "LOCKED_IP",
94396
- data: null
94376
+ if (this.ENABLE_IP_LOCKOUT) {
94377
+ const nowTs = Date.now();
94378
+ const ipRec = this.ipAttemptCache.get(remoteIP) || {
94379
+ attempts: 0,
94380
+ lockedUntil: 0,
94381
+ expiresAt: nowTs + this._attemptCacheTTL
94382
+ };
94383
+ ipRec.attempts = (ipRec.attempts || 0) + 1;
94384
+ ipRec.expiresAt = nowTs + this._attemptCacheTTL;
94385
+ if (ipRec.attempts >= this.MAX_LOGIN_ATTEMPTS) {
94386
+ ipRec.lockedUntil = nowTs + this.LOCK_DURATION_MS;
94387
+ this.audit("ip.lockout", {
94388
+ ip: remoteIP,
94389
+ attempts: ipRec.attempts
94397
94390
  });
94398
- } catch (e) {}
94399
- break;
94391
+ }
94392
+ this.ipAttemptCache.set(remoteIP, ipRec);
94393
+ if (ipRec.lockedUntil && ipRec.lockedUntil > nowTs) {
94394
+ this.audit("ip.locked", { ip: remoteIP });
94395
+ try {
94396
+ sendWithBackpressure({
94397
+ command: "login",
94398
+ message: "LOCKED_IP",
94399
+ data: null
94400
+ });
94401
+ } catch (e) {}
94402
+ break;
94403
+ }
94400
94404
  }
94401
94405
  const now = Date.now();
94402
94406
  const record = this.loginAttemptCache.get(username) || {
@@ -95211,9 +95215,8 @@ export const ${databaseName} = {};
95211
95215
  if (this.users && Array.isArray(this.users) && this.users.length > 0) {
95212
95216
  const u = this.users[0] || { username: "" };
95213
95217
  const uname = u.username || null;
95214
- const pwd = typeof u.password === "string" && u.password ? u.password : null;
95215
- if (uname && pwd) {
95216
- cred = encodeURIComponent(String(uname)) + ":" + encodeURIComponent(String(pwd)) + "@";
95218
+ if (uname && typeof u.password === "string" && u.password) {
95219
+ cred = encodeURIComponent(String(uname)) + ":" + "*****" + "@";
95217
95220
  } else if (uname) {
95218
95221
  cred = encodeURIComponent(String(uname)) + "@";
95219
95222
  }
@@ -95254,7 +95257,7 @@ import { spawn } from "node:child_process";
95254
95257
  import Storage from "@scriptdb/storage";
95255
95258
  var pkgData = `{
95256
95259
  "name": "scriptdb-workspace",
95257
- "version": "1.0.8",
95260
+ "version": "1.1.0",
95258
95261
  "description": "ScriptDB workspace for custom scripts, services, and databases",
95259
95262
  "private": true,
95260
95263
  "devDependencies": {
@@ -95341,6 +95344,10 @@ var configDefault = {
95341
95344
  GITHUB_URL: "",
95342
95345
  GITHUB_TOKEN: "",
95343
95346
  GITHUB_BRANCH: "main",
95347
+ enableIpLockout: true,
95348
+ ipFailWindowMs: 900000,
95349
+ maxLoginAttempts: 5,
95350
+ lockDurationMs: 900000,
95344
95351
  users: [
95345
95352
  {
95346
95353
  username: "admin",
@@ -97296,7 +97303,7 @@ function ensureScriptDBDir() {
97296
97303
  if (!existsSync3(PACKAGE_JSON)) {
97297
97304
  const packageJsonContent = {
97298
97305
  name: "scriptdb-workspace",
97299
- version: "1.0.8",
97306
+ version: "1.1.0",
97300
97307
  description: "ScriptDB workspace for custom scripts, services, and databases",
97301
97308
  private: true,
97302
97309
  devDependencies: {
@@ -0,0 +1,12 @@
1
+ const { parentPort } = require('worker_threads');
2
+ const bcrypt = require('bcryptjs');
3
+
4
+ parentPort.on('message', async (msg) => {
5
+ const { id, password, hash } = msg;
6
+ try {
7
+ const ok = await bcrypt.compare(password, hash);
8
+ parentPort.postMessage({ id, ok });
9
+ } catch (e) {
10
+ parentPort.postMessage({ id, error: (e && e.message) || String(e) });
11
+ }
12
+ });
@@ -0,0 +1,82 @@
1
+ const { parentPort } = require('worker_threads');
2
+
3
+ // Lightweight validation + sanitization worker
4
+ // Expects messages: { id, action: 'validate', payload, options }
5
+
6
+ function shallowValidate(payload, schema, maxDepth = 4, maxNodes = 1000) {
7
+ const out = {};
8
+ let nodes = 0;
9
+ const checkDepth = (obj, depth) => {
10
+ if (depth > maxDepth) return false;
11
+ if (nodes++ > maxNodes) return false;
12
+ if (obj && typeof obj === 'object') {
13
+ for (const k of Object.keys(obj)) {
14
+ const expected = (schema || {})[k];
15
+ if (!expected) continue;
16
+ const val = obj[k];
17
+ if (expected === 'string' && typeof val === 'string') out[k] = val;
18
+ else if (expected === 'number' && typeof val === 'number') out[k] = val;
19
+ else if (expected === 'object' && val && typeof val === 'object') {
20
+ if (depth + 1 <= maxDepth) {
21
+ out[k] = {};
22
+ for (const nk of Object.keys(val)) {
23
+ if ((schema || {})[nk]) out[k][nk] = val[nk];
24
+ }
25
+ }
26
+ }
27
+ }
28
+ return true;
29
+ }
30
+ return false;
31
+ };
32
+ if (!checkDepth(payload, 0)) return {};
33
+ return out;
34
+ }
35
+
36
+ function sanitizeResult(res, opts) {
37
+ const allowedKeys = opts && opts.allowedKeys ? opts.allowedKeys : ['result', 'value', 'items', 'length', 'status', 'message'];
38
+ const maxNodes = opts && opts.maxNodes || 2000;
39
+ const maxDepth = opts && opts.maxDepth || 6;
40
+ const maxString = opts && opts.maxString || 1000;
41
+ let nodes = 0;
42
+ const rec = (input, depth = 0) => {
43
+ if (nodes++ > maxNodes) return '[REDACTED_NODES]';
44
+ if (depth > maxDepth) return '[REDACTED_DEPTH]';
45
+ if (input === null || input === undefined) return input;
46
+ if (typeof input === 'string') {
47
+ if (input.length > maxString) return input.slice(0, maxString) + '...[TRUNC]';
48
+ return input;
49
+ }
50
+ if (typeof input === 'number' || typeof input === 'boolean') return input;
51
+ if (Array.isArray(input)) return input.map((v) => rec(v, depth + 1));
52
+ if (typeof input === 'object') {
53
+ const out = {};
54
+ for (const k of Object.keys(input)) {
55
+ if (allowedKeys.includes(k)) out[k] = rec(input[k], depth + 1);
56
+ else out[k] = '[REDACTED]';
57
+ }
58
+ return out;
59
+ }
60
+ return '[REDACTED]';
61
+ };
62
+ return rec(res, 0);
63
+ }
64
+
65
+ parentPort.on('message', async (m) => {
66
+ if (!m || !m.id) return;
67
+ try {
68
+ if (m.action === 'validate') {
69
+ const allowed = shallowValidate(m.payload, m.options.schema, m.options.maxDepth, m.options.maxNodes);
70
+ parentPort.postMessage({ id: m.id, res: allowed });
71
+ return;
72
+ }
73
+ if (m.action === 'sanitize') {
74
+ const out = sanitizeResult(m.payload, m.options || {});
75
+ parentPort.postMessage({ id: m.id, res: out });
76
+ return;
77
+ }
78
+ parentPort.postMessage({ id: m.id, error: 'unknown action' });
79
+ } catch (e) {
80
+ parentPort.postMessage({ id: m.id, error: (e && e.message) || String(e) });
81
+ }
82
+ });
@@ -0,0 +1,25 @@
1
+ const { parentPort } = require('worker_threads');
2
+ const VMModule = require('@scriptdb/vm');
3
+ const VM = VMModule && VMModule.VM ? VMModule.VM : VMModule;
4
+
5
+ let vmInstance = null;
6
+
7
+ parentPort.on('message', async (msg) => {
8
+ const { id, action, options, payload } = msg;
9
+ try {
10
+ if (action === 'init') {
11
+ vmInstance = new VM(options || {});
12
+ parentPort.postMessage({ id, ok: true });
13
+ return;
14
+ }
15
+ if (action === 'run') {
16
+ if (!vmInstance) throw new Error('vm not initialized');
17
+ const res = await vmInstance.run(payload);
18
+ parentPort.postMessage({ id, res });
19
+ return;
20
+ }
21
+ parentPort.postMessage({ id, error: 'unknown action' });
22
+ } catch (e) {
23
+ parentPort.postMessage({ id, error: (e && e.message) || String(e) });
24
+ }
25
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scriptdb/cli",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "CLI tool to start and manage ScriptDB server",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  ],
14
14
  "scripts": {
15
15
  "dev": "bun --watch src/index.ts",
16
- "build": "bun build src/index.ts --outdir dist --target node --format esm --external '@scriptdb/*'",
16
+ "build": "bun build src/index.ts --outdir dist --target node --format esm --external '@scriptdb/*' && node scripts/copy-workers.cjs",
17
17
  "build:types": "tsc --emitDeclarationOnly",
18
18
  "build:all": "bun run build && bun run build:types",
19
19
  "test": "bun test",
@@ -38,8 +38,8 @@
38
38
  "typescript": "^5.0.0"
39
39
  },
40
40
  "dependencies": {
41
- "@scriptdb/client": "^1.0.8",
42
- "@scriptdb/server": "^1.0.8",
41
+ "@scriptdb/client": "^1.1.0",
42
+ "@scriptdb/server": "^1.1.0",
43
43
  "bcryptjs": "^3.0.3",
44
44
  "bottleneck": "^2.19.5",
45
45
  "jsonwebtoken": "^9.0.3",