@abtnode/db-cache 1.17.3 → 1.17.4-beta-20251201-085909-4ab697bb

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/dist/index.cjs +34 -124
  2. package/dist/index.mjs +34 -121
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -3,12 +3,9 @@
3
3
  const path$1 = require('path');
4
4
  const redis = require('redis');
5
5
  const fs = require('node:fs');
6
- const os = require('node:os');
7
6
  const path = require('node:path');
8
7
  const node_util = require('node:util');
9
8
  const sqlite3 = require('sqlite3');
10
- const crypto = require('node:crypto');
11
- const lockfile = require('proper-lockfile');
12
9
 
13
10
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
14
11
 
@@ -26,11 +23,8 @@ function _interopNamespaceCompat(e) {
26
23
 
27
24
  const path__default = /*#__PURE__*/_interopDefaultCompat(path$1);
28
25
  const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
29
- const os__namespace = /*#__PURE__*/_interopNamespaceCompat(os);
30
26
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
31
27
  const sqlite3__default = /*#__PURE__*/_interopDefaultCompat(sqlite3);
32
- const crypto__namespace = /*#__PURE__*/_interopNamespaceCompat(crypto);
33
- const lockfile__default = /*#__PURE__*/_interopDefaultCompat(lockfile);
34
28
 
35
29
  function ulid() {
36
30
  const alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
@@ -48,20 +42,20 @@ function ulid() {
48
42
  return timeStr + rand;
49
43
  }
50
44
 
51
- var __defProp$5 = Object.defineProperty;
52
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
53
- var __publicField$5 = (obj, key, value) => {
54
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
45
+ var __defProp$4 = Object.defineProperty;
46
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
47
+ var __publicField$4 = (obj, key, value) => {
48
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
55
49
  return value;
56
50
  };
57
51
  const _RedisAdapter = class _RedisAdapter {
58
52
  constructor() {
59
- __publicField$5(this, "opts", null);
60
- __publicField$5(this, "defaultTtl", 1e3 * 60 * 60);
61
- __publicField$5(this, "url", "");
62
- __publicField$5(this, "prefix", "");
63
- __publicField$5(this, "prefixKey", (key) => `${this.prefix}:${key}`);
64
- __publicField$5(this, "prefixKeyGroup", (key) => `${this.prefix}:group:${key}`);
53
+ __publicField$4(this, "opts", null);
54
+ __publicField$4(this, "defaultTtl", 1e3 * 60 * 60);
55
+ __publicField$4(this, "url", "");
56
+ __publicField$4(this, "prefix", "");
57
+ __publicField$4(this, "prefixKey", (key) => `${this.prefix}:${key}`);
58
+ __publicField$4(this, "prefixKeyGroup", (key) => `${this.prefix}:group:${key}`);
65
59
  }
66
60
  clearAll() {
67
61
  throw new Error("Method not implemented.");
@@ -206,8 +200,8 @@ const _RedisAdapter = class _RedisAdapter {
206
200
  }
207
201
  };
208
202
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
209
- __publicField$5(_RedisAdapter, "clients", /* @__PURE__ */ new Map());
210
- __publicField$5(_RedisAdapter, "initPromises", /* @__PURE__ */ new Map());
203
+ __publicField$4(_RedisAdapter, "clients", /* @__PURE__ */ new Map());
204
+ __publicField$4(_RedisAdapter, "initPromises", /* @__PURE__ */ new Map());
211
205
  let RedisAdapter = _RedisAdapter;
212
206
 
213
207
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -236,67 +230,6 @@ async function withRetry(fn, {
236
230
  }
237
231
  }
238
232
 
239
- var __defProp$4 = Object.defineProperty;
240
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
241
- var __publicField$4 = (obj, key, value) => {
242
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
243
- return value;
244
- };
245
- class FileLock {
246
- // 默认 10 分钟
247
- constructor(baseDir, defaultTtl) {
248
- __publicField$4(this, "baseDir");
249
- __publicField$4(this, "defaultTtl", 10 * 60 * 1e3);
250
- this.baseDir = baseDir;
251
- if (defaultTtl !== void 0) {
252
- this.defaultTtl = defaultTtl;
253
- }
254
- }
255
- getLockFilePath(storageKey) {
256
- const lockDir = path__namespace.join(this.baseDir, "locks");
257
- if (!fs__namespace.existsSync(lockDir)) {
258
- fs__namespace.mkdirSync(lockDir, { recursive: true });
259
- }
260
- const safeName = crypto__namespace.createHash("sha256").update(storageKey).digest("hex");
261
- return path__namespace.join(lockDir, `${safeName}.lock`);
262
- }
263
- /**
264
- * acquire 返回 true 代表成功加锁
265
- * 返回 false 代表有其他进程/线程持有锁
266
- */
267
- async acquire(storageKey, ttl) {
268
- const lockPath = this.getLockFilePath(storageKey);
269
- const effectiveTtl = ttl !== void 0 ? ttl : this.defaultTtl;
270
- try {
271
- try {
272
- fs__namespace.writeFileSync(lockPath, "", { flag: "wx" });
273
- } catch (_createErr) {
274
- }
275
- await lockfile__default.lock(lockPath, {
276
- realpath: true,
277
- stale: effectiveTtl,
278
- // 超时自动释放
279
- update: Math.floor(effectiveTtl / 3),
280
- // 定期续租,避免长任务过期
281
- retries: 0
282
- });
283
- return true;
284
- } catch (_err) {
285
- return false;
286
- }
287
- }
288
- /**
289
- * 释放锁
290
- */
291
- async release(storageKey) {
292
- const lockPath = this.getLockFilePath(storageKey);
293
- try {
294
- await lockfile__default.unlock(lockPath);
295
- } catch (_err) {
296
- }
297
- }
298
- }
299
-
300
233
  var __defProp$3 = Object.defineProperty;
301
234
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
302
235
  var __publicField$3 = (obj, key, value) => {
@@ -362,21 +295,20 @@ const _SqliteAdapter = class _SqliteAdapter {
362
295
  __publicField$3(this, "defaultTtl", 1e3 * 60 * 60);
363
296
  __publicField$3(this, "cleanupInterval", 5 * 60 * 1e3);
364
297
  __publicField$3(this, "dbPath", "");
365
- __publicField$3(this, "fileLock", null);
366
298
  }
367
299
  /* ------------------------------- init ------------------------------- */
368
300
  async ensure() {
301
+ const isMemory = this.opts.sqlitePath === ":memory:";
369
302
  if (!this.dbPath) {
370
- this.dbPath = this.opts.sqlitePath === ":memory:" ? ":memory:" : path__namespace.resolve(this.opts.sqlitePath);
303
+ this.dbPath = isMemory ? ":memory:" : path__namespace.resolve(this.opts.sqlitePath);
371
304
  this.prefix = this.opts.prefix;
372
305
  this.defaultTtl = this.opts.ttl;
373
- this.cleanupInterval = this.opts.cleanupInterval ?? 30 * 60 * 1e3;
374
- this.fileLock = new FileLock(os__namespace.tmpdir());
306
+ this.cleanupInterval = this.opts.cleanupInterval ?? 5 * 60 * 1e3;
375
307
  }
376
308
  if (_SqliteAdapter.clients.has(this.dbPath))
377
309
  return;
378
310
  if (!_SqliteAdapter.initPromises.has(this.dbPath)) {
379
- if (this.dbPath !== ":memory:") {
311
+ if (!isMemory) {
380
312
  const dir = path__namespace.dirname(this.dbPath);
381
313
  if (!fs__namespace.existsSync(dir)) {
382
314
  fs__namespace.mkdirSync(dir, { recursive: true });
@@ -434,44 +366,28 @@ const _SqliteAdapter = class _SqliteAdapter {
434
366
  const storageKey = this.prefixKey(key);
435
367
  const effectiveTtl = opts.ttl !== void 0 ? opts.ttl : this.defaultTtl;
436
368
  const expiresAt = effectiveTtl > 0 ? Date.now() + effectiveTtl : null;
437
- let fileLocked = false;
438
- if (opts.nx && this.fileLock) {
439
- fileLocked = await this.fileLock.acquire(storageKey, effectiveTtl);
440
- if (!fileLocked)
441
- return false;
442
- }
443
- try {
444
- if (opts.nx) {
445
- const existing = await dbGet(
446
- client,
447
- "SELECT value FROM kvcache WHERE key = ? AND subKey = ?",
448
- [storageKey, ""]
449
- );
450
- if (existing) {
451
- return false;
452
- }
453
- }
454
- await dbRun(
369
+ if (opts.nx) {
370
+ const existing = await dbGet(
455
371
  client,
456
- `
457
- INSERT INTO kvcache (key, subKey, value, expiresAt)
458
- VALUES (?, ?, ?, ?)
459
- ON CONFLICT(key, subKey) DO UPDATE SET
460
- value = excluded.value,
461
- expiresAt = excluded.expiresAt
462
- `,
463
- [storageKey, "", this.serialize(value), expiresAt]
372
+ "SELECT value FROM kvcache WHERE key = ? AND subKey = ?",
373
+ [storageKey, ""]
464
374
  );
465
- if (fileLocked && this.fileLock) {
466
- await this.fileLock.release(storageKey);
467
- }
468
- return true;
469
- } catch (err) {
470
- if (fileLocked && this.fileLock) {
471
- await this.fileLock.release(storageKey);
375
+ if (existing) {
376
+ return false;
472
377
  }
473
- throw err;
474
378
  }
379
+ await dbRun(
380
+ client,
381
+ `
382
+ INSERT INTO kvcache (key, subKey, value, expiresAt)
383
+ VALUES (?, ?, ?, ?)
384
+ ON CONFLICT(key, subKey) DO UPDATE SET
385
+ value = excluded.value,
386
+ expiresAt = excluded.expiresAt
387
+ `,
388
+ [storageKey, "", this.serialize(value), expiresAt]
389
+ );
390
+ return true;
475
391
  }
476
392
  async get(key) {
477
393
  const client = this.getClient();
@@ -493,9 +409,6 @@ const _SqliteAdapter = class _SqliteAdapter {
493
409
  const client = this.getClient();
494
410
  const storageKey = this.prefixKey(key);
495
411
  await dbRun(client, "DELETE FROM kvcache WHERE key = ?", [storageKey]);
496
- if (this.fileLock) {
497
- await this.fileLock.release(storageKey);
498
- }
499
412
  }
500
413
  async has(key) {
501
414
  const client = this.getClient();
@@ -572,9 +485,6 @@ const _SqliteAdapter = class _SqliteAdapter {
572
485
  const client = this.getClient();
573
486
  const storageKey = this.prefixKey(key);
574
487
  await dbRun(client, "DELETE FROM kvcache WHERE key = ? AND subKey = ?", [storageKey, subKey]);
575
- if (this.fileLock) {
576
- await this.fileLock.release(storageKey);
577
- }
578
488
  }
579
489
  /* ------------------------------- misc ------------------------------- */
580
490
  async close() {
package/dist/index.mjs CHANGED
@@ -1,12 +1,9 @@
1
1
  import path$1 from 'path';
2
2
  import { createClient } from 'redis';
3
3
  import * as fs from 'node:fs';
4
- import * as os from 'node:os';
5
4
  import * as path from 'node:path';
6
5
  import { promisify } from 'node:util';
7
6
  import sqlite3 from 'sqlite3';
8
- import * as crypto from 'node:crypto';
9
- import lockfile from 'proper-lockfile';
10
7
 
11
8
  function ulid() {
12
9
  const alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
@@ -24,20 +21,20 @@ function ulid() {
24
21
  return timeStr + rand;
25
22
  }
26
23
 
27
- var __defProp$5 = Object.defineProperty;
28
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
29
- var __publicField$5 = (obj, key, value) => {
30
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
24
+ var __defProp$4 = Object.defineProperty;
25
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
26
+ var __publicField$4 = (obj, key, value) => {
27
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
31
28
  return value;
32
29
  };
33
30
  const _RedisAdapter = class _RedisAdapter {
34
31
  constructor() {
35
- __publicField$5(this, "opts", null);
36
- __publicField$5(this, "defaultTtl", 1e3 * 60 * 60);
37
- __publicField$5(this, "url", "");
38
- __publicField$5(this, "prefix", "");
39
- __publicField$5(this, "prefixKey", (key) => `${this.prefix}:${key}`);
40
- __publicField$5(this, "prefixKeyGroup", (key) => `${this.prefix}:group:${key}`);
32
+ __publicField$4(this, "opts", null);
33
+ __publicField$4(this, "defaultTtl", 1e3 * 60 * 60);
34
+ __publicField$4(this, "url", "");
35
+ __publicField$4(this, "prefix", "");
36
+ __publicField$4(this, "prefixKey", (key) => `${this.prefix}:${key}`);
37
+ __publicField$4(this, "prefixKeyGroup", (key) => `${this.prefix}:group:${key}`);
41
38
  }
42
39
  clearAll() {
43
40
  throw new Error("Method not implemented.");
@@ -182,8 +179,8 @@ const _RedisAdapter = class _RedisAdapter {
182
179
  }
183
180
  };
184
181
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
185
- __publicField$5(_RedisAdapter, "clients", /* @__PURE__ */ new Map());
186
- __publicField$5(_RedisAdapter, "initPromises", /* @__PURE__ */ new Map());
182
+ __publicField$4(_RedisAdapter, "clients", /* @__PURE__ */ new Map());
183
+ __publicField$4(_RedisAdapter, "initPromises", /* @__PURE__ */ new Map());
187
184
  let RedisAdapter = _RedisAdapter;
188
185
 
189
186
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -212,67 +209,6 @@ async function withRetry(fn, {
212
209
  }
213
210
  }
214
211
 
215
- var __defProp$4 = Object.defineProperty;
216
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
217
- var __publicField$4 = (obj, key, value) => {
218
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
219
- return value;
220
- };
221
- class FileLock {
222
- // 默认 10 分钟
223
- constructor(baseDir, defaultTtl) {
224
- __publicField$4(this, "baseDir");
225
- __publicField$4(this, "defaultTtl", 10 * 60 * 1e3);
226
- this.baseDir = baseDir;
227
- if (defaultTtl !== void 0) {
228
- this.defaultTtl = defaultTtl;
229
- }
230
- }
231
- getLockFilePath(storageKey) {
232
- const lockDir = path.join(this.baseDir, "locks");
233
- if (!fs.existsSync(lockDir)) {
234
- fs.mkdirSync(lockDir, { recursive: true });
235
- }
236
- const safeName = crypto.createHash("sha256").update(storageKey).digest("hex");
237
- return path.join(lockDir, `${safeName}.lock`);
238
- }
239
- /**
240
- * acquire 返回 true 代表成功加锁
241
- * 返回 false 代表有其他进程/线程持有锁
242
- */
243
- async acquire(storageKey, ttl) {
244
- const lockPath = this.getLockFilePath(storageKey);
245
- const effectiveTtl = ttl !== void 0 ? ttl : this.defaultTtl;
246
- try {
247
- try {
248
- fs.writeFileSync(lockPath, "", { flag: "wx" });
249
- } catch (_createErr) {
250
- }
251
- await lockfile.lock(lockPath, {
252
- realpath: true,
253
- stale: effectiveTtl,
254
- // 超时自动释放
255
- update: Math.floor(effectiveTtl / 3),
256
- // 定期续租,避免长任务过期
257
- retries: 0
258
- });
259
- return true;
260
- } catch (_err) {
261
- return false;
262
- }
263
- }
264
- /**
265
- * 释放锁
266
- */
267
- async release(storageKey) {
268
- const lockPath = this.getLockFilePath(storageKey);
269
- try {
270
- await lockfile.unlock(lockPath);
271
- } catch (_err) {
272
- }
273
- }
274
- }
275
-
276
212
  var __defProp$3 = Object.defineProperty;
277
213
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
278
214
  var __publicField$3 = (obj, key, value) => {
@@ -338,21 +274,20 @@ const _SqliteAdapter = class _SqliteAdapter {
338
274
  __publicField$3(this, "defaultTtl", 1e3 * 60 * 60);
339
275
  __publicField$3(this, "cleanupInterval", 5 * 60 * 1e3);
340
276
  __publicField$3(this, "dbPath", "");
341
- __publicField$3(this, "fileLock", null);
342
277
  }
343
278
  /* ------------------------------- init ------------------------------- */
344
279
  async ensure() {
280
+ const isMemory = this.opts.sqlitePath === ":memory:";
345
281
  if (!this.dbPath) {
346
- this.dbPath = this.opts.sqlitePath === ":memory:" ? ":memory:" : path.resolve(this.opts.sqlitePath);
282
+ this.dbPath = isMemory ? ":memory:" : path.resolve(this.opts.sqlitePath);
347
283
  this.prefix = this.opts.prefix;
348
284
  this.defaultTtl = this.opts.ttl;
349
- this.cleanupInterval = this.opts.cleanupInterval ?? 30 * 60 * 1e3;
350
- this.fileLock = new FileLock(os.tmpdir());
285
+ this.cleanupInterval = this.opts.cleanupInterval ?? 5 * 60 * 1e3;
351
286
  }
352
287
  if (_SqliteAdapter.clients.has(this.dbPath))
353
288
  return;
354
289
  if (!_SqliteAdapter.initPromises.has(this.dbPath)) {
355
- if (this.dbPath !== ":memory:") {
290
+ if (!isMemory) {
356
291
  const dir = path.dirname(this.dbPath);
357
292
  if (!fs.existsSync(dir)) {
358
293
  fs.mkdirSync(dir, { recursive: true });
@@ -410,44 +345,28 @@ const _SqliteAdapter = class _SqliteAdapter {
410
345
  const storageKey = this.prefixKey(key);
411
346
  const effectiveTtl = opts.ttl !== void 0 ? opts.ttl : this.defaultTtl;
412
347
  const expiresAt = effectiveTtl > 0 ? Date.now() + effectiveTtl : null;
413
- let fileLocked = false;
414
- if (opts.nx && this.fileLock) {
415
- fileLocked = await this.fileLock.acquire(storageKey, effectiveTtl);
416
- if (!fileLocked)
417
- return false;
418
- }
419
- try {
420
- if (opts.nx) {
421
- const existing = await dbGet(
422
- client,
423
- "SELECT value FROM kvcache WHERE key = ? AND subKey = ?",
424
- [storageKey, ""]
425
- );
426
- if (existing) {
427
- return false;
428
- }
429
- }
430
- await dbRun(
348
+ if (opts.nx) {
349
+ const existing = await dbGet(
431
350
  client,
432
- `
433
- INSERT INTO kvcache (key, subKey, value, expiresAt)
434
- VALUES (?, ?, ?, ?)
435
- ON CONFLICT(key, subKey) DO UPDATE SET
436
- value = excluded.value,
437
- expiresAt = excluded.expiresAt
438
- `,
439
- [storageKey, "", this.serialize(value), expiresAt]
351
+ "SELECT value FROM kvcache WHERE key = ? AND subKey = ?",
352
+ [storageKey, ""]
440
353
  );
441
- if (fileLocked && this.fileLock) {
442
- await this.fileLock.release(storageKey);
443
- }
444
- return true;
445
- } catch (err) {
446
- if (fileLocked && this.fileLock) {
447
- await this.fileLock.release(storageKey);
354
+ if (existing) {
355
+ return false;
448
356
  }
449
- throw err;
450
357
  }
358
+ await dbRun(
359
+ client,
360
+ `
361
+ INSERT INTO kvcache (key, subKey, value, expiresAt)
362
+ VALUES (?, ?, ?, ?)
363
+ ON CONFLICT(key, subKey) DO UPDATE SET
364
+ value = excluded.value,
365
+ expiresAt = excluded.expiresAt
366
+ `,
367
+ [storageKey, "", this.serialize(value), expiresAt]
368
+ );
369
+ return true;
451
370
  }
452
371
  async get(key) {
453
372
  const client = this.getClient();
@@ -469,9 +388,6 @@ const _SqliteAdapter = class _SqliteAdapter {
469
388
  const client = this.getClient();
470
389
  const storageKey = this.prefixKey(key);
471
390
  await dbRun(client, "DELETE FROM kvcache WHERE key = ?", [storageKey]);
472
- if (this.fileLock) {
473
- await this.fileLock.release(storageKey);
474
- }
475
391
  }
476
392
  async has(key) {
477
393
  const client = this.getClient();
@@ -548,9 +464,6 @@ const _SqliteAdapter = class _SqliteAdapter {
548
464
  const client = this.getClient();
549
465
  const storageKey = this.prefixKey(key);
550
466
  await dbRun(client, "DELETE FROM kvcache WHERE key = ? AND subKey = ?", [storageKey, subKey]);
551
- if (this.fileLock) {
552
- await this.fileLock.release(storageKey);
553
- }
554
467
  }
555
468
  /* ------------------------------- misc ------------------------------- */
556
469
  async close() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abtnode/db-cache",
3
- "version": "1.17.3",
3
+ "version": "1.17.4-beta-20251201-085909-4ab697bb",
4
4
  "description": "Db cache use redis or sqlite as backend",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -42,5 +42,5 @@
42
42
  "typescript": "^5.6.3",
43
43
  "unbuild": "^2.0.0"
44
44
  },
45
- "gitHead": "20fc4c3b0c0fdf05a91d995e3f6fda0f38fa1133"
45
+ "gitHead": "4a76a83d2c47b00686c1c0fdd7b78ffddd728f0e"
46
46
  }