jsql-neo 6.3.5 → 6.3.10

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * JSQL-NEO v6.3.5 — Rust-Powered Embedded Database (WASM + HTTP)
2
+ * JSQL-NEO v6.3.10 — Rust-Powered Embedded Database (WASM + HTTP)
3
3
  *
4
4
  * @example
5
5
  * const jsql = require('jsql-neo');
package/lib/cache.js CHANGED
@@ -36,7 +36,8 @@ class Cache {
36
36
  return count;
37
37
  }
38
38
  keys(pattern = '*') {
39
- const regex = new RegExp('^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
39
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.');
40
+ const regex = new RegExp('^' + escaped + '$');
40
41
  const result = [];
41
42
  for (const key of this._getData().keys()) { if (!this._isExpired(key) && regex.test(key)) result.push(key); }
42
43
  return result;
@@ -47,8 +48,9 @@ class Cache {
47
48
  const val = this._getData().get(k);
48
49
  if (val === undefined) return 'none';
49
50
  if (typeof val === 'string') return 'string';
50
- if (Array.isArray(val)) return val._type === 'hash' ? 'hash' : 'list';
51
51
  if (val instanceof Set) return 'set';
52
+ if (Array.isArray(val)) return val._type === 'hash' ? 'hash' : 'list';
53
+ if (typeof val === 'object' && val._type === 'hash') return 'hash';
52
54
  return 'string';
53
55
  }
54
56
  expire(key, seconds) {
@@ -175,6 +177,8 @@ class Cache {
175
177
  if (!list || !Array.isArray(list) || list._type === 'hash') return [];
176
178
  if (start < 0) start = Math.max(list.length + start, 0);
177
179
  if (stop < 0) stop = list.length + stop;
180
+ stop = Math.min(stop, list.length - 1);
181
+ if (start > stop) return [];
178
182
  return list.slice(start, stop + 1);
179
183
  }
180
184
 
@@ -244,32 +248,34 @@ class Cache {
244
248
 
245
249
  save() {
246
250
  if (!this._persistPath) return;
247
- const dump = { version: 1, databases: [] };
248
- for (let i = 0; i < this._dbs.length; i++) {
249
- const db = this._dbs[i];
250
- if (!db || db.size === 0) continue;
251
- const data = {};
252
- for (const [key, val] of db) {
253
- const exp = this._dbsExpires[i];
254
- if (exp && exp.has(key) && exp.get(key) <= Date.now()) continue;
255
- if (val instanceof Set) data[key] = { _t: 'set', _v: [...val] };
256
- else if (Array.isArray(val)) data[key] = { _t: 'list', _v: val };
257
- else if (typeof val === 'object' && val._type === 'hash') {
258
- const clean = {}; for (const [f, v] of Object.entries(val)) { if (f !== '_type') clean[f] = v; }
259
- data[key] = { _t: 'hash', _v: clean };
260
- } else data[key] = { _t: 'string', _v: val };
251
+ try {
252
+ const dump = { version: 1, databases: [] };
253
+ for (let i = 0; i < this._dbs.length; i++) {
254
+ const db = this._dbs[i];
255
+ if (!db || db.size === 0) continue;
256
+ const data = {};
257
+ for (const [key, val] of db) {
258
+ const exp = this._dbsExpires[i];
259
+ if (exp && exp.has(key) && exp.get(key) <= Date.now()) continue;
260
+ if (val instanceof Set) data[key] = { _t: 'set', _v: [...val] };
261
+ else if (Array.isArray(val)) data[key] = { _t: 'list', _v: val };
262
+ else if (typeof val === 'object' && val._type === 'hash') {
263
+ const clean = {}; for (const [f, v] of Object.entries(val)) { if (f !== '_type') clean[f] = v; }
264
+ data[key] = { _t: 'hash', _v: clean };
265
+ } else data[key] = { _t: 'string', _v: val };
266
+ }
267
+ const expires = {};
268
+ const expMap = this._dbsExpires[i];
269
+ if (expMap) { for (const [key, ttl] of expMap) { if (ttl > Date.now()) expires[key] = ttl; } }
270
+ if (Object.keys(data).length > 0 || Object.keys(expires).length > 0) dump.databases.push({ index: i, data, expires });
261
271
  }
262
- const expires = {};
263
- const expMap = this._dbsExpires[i];
264
- if (expMap) { for (const [key, ttl] of expMap) { if (ttl > Date.now()) expires[key] = ttl; } }
265
- if (Object.keys(data).length > 0 || Object.keys(expires).length > 0) dump.databases.push({ index: i, data, expires });
266
- }
267
- const dir = path.dirname(this._persistPath);
268
- if (dir) fs.mkdirSync(dir, { recursive: true });
269
- fs.writeFileSync(this._persistPath + '.tmp', JSON.stringify(dump), 'utf8');
270
- fs.renameSync(this._persistPath + '.tmp', this._persistPath);
271
- this._dirty = false;
272
- return 'OK';
272
+ const dir = path.dirname(this._persistPath);
273
+ if (dir) fs.mkdirSync(dir, { recursive: true });
274
+ fs.writeFileSync(this._persistPath + '.tmp', JSON.stringify(dump), 'utf8');
275
+ fs.renameSync(this._persistPath + '.tmp', this._persistPath);
276
+ this._dirty = false;
277
+ return 'OK';
278
+ } catch (e) { return null; }
273
279
  }
274
280
 
275
281
  _load() {
package/lib/client.js CHANGED
@@ -12,7 +12,8 @@ function binPath() {
12
12
  class JSQL {
13
13
  constructor(opts = {}) {
14
14
  this.host = opts.host || '127.0.0.1';
15
- this.port = opts.port || 6379;
15
+ // P3-5: 默认端口 6379 会与 Redis 冲突,改为 3000
16
+ this.port = opts.port || 3000;
16
17
  this.dataDir = opts.dataDir || null;
17
18
  this._process = null;
18
19
  }
@@ -45,7 +46,8 @@ class JSQL {
45
46
  async stop() {
46
47
  if (!this._process) return;
47
48
  this._process.kill();
48
- await new Promise(r => setTimeout(r, 500));
49
+ // P3-6: 不再硬等 500ms,给进程一点时间退出即可
50
+ await new Promise(r => setTimeout(r, 100));
49
51
  this._process = null;
50
52
  }
51
53
 
@@ -74,6 +76,13 @@ class JSQL {
74
76
  headers: body ? { 'Content-Type': 'application/json' } : {},
75
77
  };
76
78
  const req = http.request(opts, (res) => {
79
+ // P3-7: 未处理 res 错误——非 2xx 状态码应 reject
80
+ if (res.statusCode < 200 || res.statusCode >= 300) {
81
+ let errData = '';
82
+ res.on('data', c => errData += c);
83
+ res.on('end', () => reject(new Error(`HTTP ${res.statusCode}: ${errData}`)));
84
+ return;
85
+ }
77
86
  let data = '';
78
87
  res.on('data', c => data += c);
79
88
  res.on('end', () => {