@lakutata/cache 3.0.0-beta.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.
Files changed (116) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +175 -0
  3. package/dist/cjs/cache/Cacher.d.ts +446 -0
  4. package/dist/cjs/cache/Cacher.js +523 -0
  5. package/dist/cjs/cache/exceptions/CacheDriverNotFoundException.d.ts +10 -0
  6. package/dist/cjs/cache/exceptions/CacheDriverNotFoundException.js +17 -0
  7. package/dist/cjs/cache/interfaces/CacherOptions.d.ts +42 -0
  8. package/dist/cjs/cache/interfaces/CacherOptions.js +2 -0
  9. package/dist/cjs/cache/lib/LikePrefix.d.ts +5 -0
  10. package/dist/cjs/cache/lib/LikePrefix.js +10 -0
  11. package/dist/cjs/cache/lib/LoadDriver.d.ts +6 -0
  12. package/dist/cjs/cache/lib/LoadDriver.js +66 -0
  13. package/dist/cjs/cache/lib/Serializer.d.ts +18 -0
  14. package/dist/cjs/cache/lib/Serializer.js +46 -0
  15. package/dist/cjs/cache/lib/WithTimeout.d.ts +7 -0
  16. package/dist/cjs/cache/lib/WithTimeout.js +23 -0
  17. package/dist/cjs/cache/options/FileCacheOptions.d.ts +54 -0
  18. package/dist/cjs/cache/options/FileCacheOptions.js +62 -0
  19. package/dist/cjs/cache/options/MemcacheCacheOptions.d.ts +57 -0
  20. package/dist/cjs/cache/options/MemcacheCacheOptions.js +66 -0
  21. package/dist/cjs/cache/options/MemoryCacheOptions.d.ts +39 -0
  22. package/dist/cjs/cache/options/MemoryCacheOptions.js +52 -0
  23. package/dist/cjs/cache/options/MongoCacheOptions.d.ts +72 -0
  24. package/dist/cjs/cache/options/MongoCacheOptions.js +81 -0
  25. package/dist/cjs/cache/options/MysqlCacheOptions.d.ts +73 -0
  26. package/dist/cjs/cache/options/MysqlCacheOptions.js +82 -0
  27. package/dist/cjs/cache/options/PostgresCacheOptions.d.ts +87 -0
  28. package/dist/cjs/cache/options/PostgresCacheOptions.js +92 -0
  29. package/dist/cjs/cache/options/RedisCacheOptions.d.ts +120 -0
  30. package/dist/cjs/cache/options/RedisCacheOptions.js +113 -0
  31. package/dist/cjs/cache/options/SqliteCacheOptions.d.ts +53 -0
  32. package/dist/cjs/cache/options/SqliteCacheOptions.js +61 -0
  33. package/dist/cjs/cache/stores/CacheStore.d.ts +44 -0
  34. package/dist/cjs/cache/stores/CacheStore.js +42 -0
  35. package/dist/cjs/cache/stores/CreateCacheStore.d.ts +7 -0
  36. package/dist/cjs/cache/stores/CreateCacheStore.js +37 -0
  37. package/dist/cjs/cache/stores/FileStore.d.ts +51 -0
  38. package/dist/cjs/cache/stores/FileStore.js +143 -0
  39. package/dist/cjs/cache/stores/MemcacheStore.d.ts +42 -0
  40. package/dist/cjs/cache/stores/MemcacheStore.js +69 -0
  41. package/dist/cjs/cache/stores/MemoryStore.d.ts +34 -0
  42. package/dist/cjs/cache/stores/MemoryStore.js +75 -0
  43. package/dist/cjs/cache/stores/MongoStore.d.ts +55 -0
  44. package/dist/cjs/cache/stores/MongoStore.js +72 -0
  45. package/dist/cjs/cache/stores/MysqlStore.d.ts +27 -0
  46. package/dist/cjs/cache/stores/MysqlStore.js +71 -0
  47. package/dist/cjs/cache/stores/PostgresStore.d.ts +30 -0
  48. package/dist/cjs/cache/stores/PostgresStore.js +85 -0
  49. package/dist/cjs/cache/stores/RedisStore.d.ts +58 -0
  50. package/dist/cjs/cache/stores/RedisStore.js +131 -0
  51. package/dist/cjs/cache/stores/SerializedCacheStore.d.ts +48 -0
  52. package/dist/cjs/cache/stores/SerializedCacheStore.js +80 -0
  53. package/dist/cjs/cache/stores/SqliteStore.d.ts +44 -0
  54. package/dist/cjs/cache/stores/SqliteStore.js +91 -0
  55. package/dist/cjs/cache/types/CacheStoreOptions.d.ts +15 -0
  56. package/dist/cjs/cache/types/CacheStoreOptions.js +2 -0
  57. package/dist/cjs/exports/Cache.d.ts +12 -0
  58. package/dist/cjs/exports/Cache.js +31 -0
  59. package/dist/cjs/package.json +1 -0
  60. package/dist/esm/cache/Cacher.js +518 -0
  61. package/dist/esm/cache/exceptions/CacheDriverNotFoundException.js +13 -0
  62. package/dist/esm/cache/interfaces/CacherOptions.js +1 -0
  63. package/dist/esm/cache/lib/LikePrefix.js +7 -0
  64. package/dist/esm/cache/lib/LoadDriver.js +30 -0
  65. package/dist/esm/cache/lib/Serializer.js +42 -0
  66. package/dist/esm/cache/lib/WithTimeout.js +20 -0
  67. package/dist/esm/cache/options/FileCacheOptions.js +58 -0
  68. package/dist/esm/cache/options/MemcacheCacheOptions.js +62 -0
  69. package/dist/esm/cache/options/MemoryCacheOptions.js +48 -0
  70. package/dist/esm/cache/options/MongoCacheOptions.js +77 -0
  71. package/dist/esm/cache/options/MysqlCacheOptions.js +78 -0
  72. package/dist/esm/cache/options/PostgresCacheOptions.js +88 -0
  73. package/dist/esm/cache/options/RedisCacheOptions.js +109 -0
  74. package/dist/esm/cache/options/SqliteCacheOptions.js +57 -0
  75. package/dist/esm/cache/stores/CacheStore.js +36 -0
  76. package/dist/esm/cache/stores/CreateCacheStore.js +34 -0
  77. package/dist/esm/cache/stores/FileStore.js +136 -0
  78. package/dist/esm/cache/stores/MemcacheStore.js +65 -0
  79. package/dist/esm/cache/stores/MemoryStore.js +71 -0
  80. package/dist/esm/cache/stores/MongoStore.js +68 -0
  81. package/dist/esm/cache/stores/MysqlStore.js +67 -0
  82. package/dist/esm/cache/stores/PostgresStore.js +81 -0
  83. package/dist/esm/cache/stores/RedisStore.js +127 -0
  84. package/dist/esm/cache/stores/SerializedCacheStore.js +76 -0
  85. package/dist/esm/cache/stores/SqliteStore.js +87 -0
  86. package/dist/esm/cache/types/CacheStoreOptions.js +1 -0
  87. package/dist/esm/exports/Cache.js +12 -0
  88. package/dist/types/cache/Cacher.d.ts +446 -0
  89. package/dist/types/cache/exceptions/CacheDriverNotFoundException.d.ts +10 -0
  90. package/dist/types/cache/interfaces/CacherOptions.d.ts +42 -0
  91. package/dist/types/cache/lib/LikePrefix.d.ts +5 -0
  92. package/dist/types/cache/lib/LoadDriver.d.ts +6 -0
  93. package/dist/types/cache/lib/Serializer.d.ts +18 -0
  94. package/dist/types/cache/lib/WithTimeout.d.ts +7 -0
  95. package/dist/types/cache/options/FileCacheOptions.d.ts +54 -0
  96. package/dist/types/cache/options/MemcacheCacheOptions.d.ts +57 -0
  97. package/dist/types/cache/options/MemoryCacheOptions.d.ts +39 -0
  98. package/dist/types/cache/options/MongoCacheOptions.d.ts +72 -0
  99. package/dist/types/cache/options/MysqlCacheOptions.d.ts +73 -0
  100. package/dist/types/cache/options/PostgresCacheOptions.d.ts +87 -0
  101. package/dist/types/cache/options/RedisCacheOptions.d.ts +120 -0
  102. package/dist/types/cache/options/SqliteCacheOptions.d.ts +53 -0
  103. package/dist/types/cache/stores/CacheStore.d.ts +44 -0
  104. package/dist/types/cache/stores/CreateCacheStore.d.ts +7 -0
  105. package/dist/types/cache/stores/FileStore.d.ts +51 -0
  106. package/dist/types/cache/stores/MemcacheStore.d.ts +42 -0
  107. package/dist/types/cache/stores/MemoryStore.d.ts +34 -0
  108. package/dist/types/cache/stores/MongoStore.d.ts +55 -0
  109. package/dist/types/cache/stores/MysqlStore.d.ts +27 -0
  110. package/dist/types/cache/stores/PostgresStore.d.ts +30 -0
  111. package/dist/types/cache/stores/RedisStore.d.ts +58 -0
  112. package/dist/types/cache/stores/SerializedCacheStore.d.ts +48 -0
  113. package/dist/types/cache/stores/SqliteStore.d.ts +44 -0
  114. package/dist/types/cache/types/CacheStoreOptions.d.ts +15 -0
  115. package/dist/types/exports/Cache.d.ts +12 -0
  116. package/package.json +72 -0
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SqliteCacheOptions = void 0;
13
+ const core_1 = require("@lakutata/core");
14
+ const dto_1 = require("@lakutata/core/decorator/dto");
15
+ /**
16
+ * The options of the SQLite store: one row per entry in a table of a SQLite database file. It needs the optional peer
17
+ * dependency `sqlite3` (`npm install sqlite3`): without it, the cache's creation fails with
18
+ * `CacheDriverNotFoundException`.
19
+ *
20
+ * When the cache starts, it opens the database (creating the file) and creates the table when missing:
21
+ * `(key VARCHAR(255) PRIMARY KEY, value TEXT)`. An expired row is a miss; it stays in the table until it is read,
22
+ * overwritten or cleared. The values are kept as JSON.
23
+ * @example
24
+ * ```typescript
25
+ * import {Application} from 'lakutata'
26
+ * import {buildCacherOptions} from 'lakutata/com/cacher'
27
+ *
28
+ * Application.run(() => ({
29
+ * id: 'sqlite-cache.app',
30
+ * name: 'SqliteCache',
31
+ * components: {
32
+ * cache: buildCacherOptions({
33
+ * stores: {type: 'sqlite', database: './cache.db', table: 'cache', namespace: 'app'}
34
+ * })
35
+ * }
36
+ * }))
37
+ * ```
38
+ */
39
+ class SqliteCacheOptions extends core_1.DTO {
40
+ }
41
+ exports.SqliteCacheOptions = SqliteCacheOptions;
42
+ __decorate([
43
+ (0, dto_1.Expect)(core_1.DTO.String().allow('sqlite').only().required()),
44
+ __metadata("design:type", String)
45
+ ], SqliteCacheOptions.prototype, "type", void 0);
46
+ __decorate([
47
+ (0, dto_1.Expect)(core_1.DTO.String().required()),
48
+ __metadata("design:type", String)
49
+ ], SqliteCacheOptions.prototype, "database", void 0);
50
+ __decorate([
51
+ (0, dto_1.Expect)(core_1.DTO.String().required()),
52
+ __metadata("design:type", String)
53
+ ], SqliteCacheOptions.prototype, "table", void 0);
54
+ __decorate([
55
+ (0, dto_1.Expect)(core_1.DTO.Number().positive().integer().optional().default(10000)),
56
+ __metadata("design:type", Number)
57
+ ], SqliteCacheOptions.prototype, "busyTimeout", void 0);
58
+ __decorate([
59
+ (0, dto_1.Expect)(core_1.DTO.String().optional()),
60
+ __metadata("design:type", String)
61
+ ], SqliteCacheOptions.prototype, "namespace", void 0);
@@ -0,0 +1,44 @@
1
+ import { CacheEntry } from '../lib/Serializer.js';
2
+ export type CacheStoreSetEntry = {
3
+ key: string;
4
+ value: unknown;
5
+ ttl?: number;
6
+ };
7
+ /**
8
+ * Whether an entry has expired
9
+ * @param entry
10
+ */
11
+ export declare function isExpired(entry: CacheEntry): boolean;
12
+ /**
13
+ * The expiration time of a ttl
14
+ * @param ttl
15
+ */
16
+ export declare function expiresOf(ttl?: number): number | undefined;
17
+ /**
18
+ * A cache store
19
+ * The ttls are in milliseconds, a missing or zero ttl never expires
20
+ */
21
+ export declare abstract class CacheStore {
22
+ /**
23
+ * Report the errors of the background operations
24
+ */
25
+ onError: (error: Error) => void;
26
+ /**
27
+ * Connect to the backend
28
+ */
29
+ connect(): Promise<void>;
30
+ /**
31
+ * Disconnect from the backend
32
+ */
33
+ disconnect(): Promise<void>;
34
+ abstract get(key: string): Promise<CacheEntry | undefined>;
35
+ abstract getMany(keys: string[]): Promise<(CacheEntry | undefined)[]>;
36
+ abstract set(key: string, value: unknown, ttl?: number): Promise<void>;
37
+ abstract setMany(entries: CacheStoreSetEntry[]): Promise<void>;
38
+ abstract delete(key: string): Promise<boolean>;
39
+ abstract deleteMany(keys: string[]): Promise<boolean>;
40
+ /**
41
+ * Delete the entries of the namespace, or all the entries without namespace
42
+ */
43
+ abstract clear(): Promise<void>;
44
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CacheStore = void 0;
4
+ exports.isExpired = isExpired;
5
+ exports.expiresOf = expiresOf;
6
+ /**
7
+ * Whether an entry has expired
8
+ * @param entry
9
+ */
10
+ function isExpired(entry) {
11
+ return typeof entry.expires === 'number' && Date.now() > entry.expires;
12
+ }
13
+ /**
14
+ * The expiration time of a ttl
15
+ * @param ttl
16
+ */
17
+ function expiresOf(ttl) {
18
+ return ttl ? Date.now() + ttl : undefined;
19
+ }
20
+ /**
21
+ * A cache store
22
+ * The ttls are in milliseconds, a missing or zero ttl never expires
23
+ */
24
+ class CacheStore {
25
+ constructor() {
26
+ /**
27
+ * Report the errors of the background operations
28
+ */
29
+ this.onError = () => undefined;
30
+ }
31
+ /**
32
+ * Connect to the backend
33
+ */
34
+ async connect() {
35
+ }
36
+ /**
37
+ * Disconnect from the backend
38
+ */
39
+ async disconnect() {
40
+ }
41
+ }
42
+ exports.CacheStore = CacheStore;
@@ -0,0 +1,7 @@
1
+ import { CacheStore } from './CacheStore.js';
2
+ import { CacheStoreOptions } from '../types/CacheStoreOptions.js';
3
+ /**
4
+ * Create the store of the options
5
+ * @param options
6
+ */
7
+ export declare function createCacheStore(options: CacheStoreOptions): CacheStore | undefined;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCacheStore = createCacheStore;
4
+ const FileStore_js_1 = require("./FileStore.js");
5
+ const MemoryStore_js_1 = require("./MemoryStore.js");
6
+ const RedisStore_js_1 = require("./RedisStore.js");
7
+ const MemcacheStore_js_1 = require("./MemcacheStore.js");
8
+ const MongoStore_js_1 = require("./MongoStore.js");
9
+ const SqliteStore_js_1 = require("./SqliteStore.js");
10
+ const PostgresStore_js_1 = require("./PostgresStore.js");
11
+ const MysqlStore_js_1 = require("./MysqlStore.js");
12
+ /**
13
+ * Create the store of the options
14
+ * @param options
15
+ */
16
+ function createCacheStore(options) {
17
+ switch (options.type) {
18
+ case 'memory':
19
+ return new MemoryStore_js_1.MemoryStore(options.sweepInterval);
20
+ case 'file':
21
+ return new FileStore_js_1.FileStore(options);
22
+ case 'redis':
23
+ return new RedisStore_js_1.RedisStore(options);
24
+ case 'memcache':
25
+ return new MemcacheStore_js_1.MemcacheStore(options);
26
+ case 'mongo':
27
+ return new MongoStore_js_1.MongoStore(options);
28
+ case 'sqlite':
29
+ return new SqliteStore_js_1.SqliteStore(options);
30
+ case 'postgres':
31
+ return new PostgresStore_js_1.PostgresStore(options);
32
+ case 'mysql':
33
+ return new MysqlStore_js_1.MysqlStore(options);
34
+ default:
35
+ return undefined;
36
+ }
37
+ }
@@ -0,0 +1,51 @@
1
+ import { SerializedCacheStore, SerializedEntry } from './SerializedCacheStore.js';
2
+ import { FileCacheOptions } from '../options/FileCacheOptions.js';
3
+ type FileRecord = {
4
+ expire?: number;
5
+ value: string;
6
+ };
7
+ /**
8
+ * The file store, the entries are kept in memory and written to the file in batches
9
+ * File format: {"cache":[[key,{"expire":ms,"value":serialized entry}]],"lastExpire":ms}
10
+ */
11
+ export declare class FileStore extends SerializedCacheStore {
12
+ protected readonly filename: string;
13
+ protected readonly expiredCheckDelay: number;
14
+ protected readonly writeDelay: number;
15
+ protected records: Map<string, FileRecord>;
16
+ protected lastExpire: number;
17
+ protected saveTimer?: NodeJS.Timeout;
18
+ protected saving: Promise<void>;
19
+ constructor(options: FileCacheOptions);
20
+ /**
21
+ * Whether a record has expired
22
+ * @param record
23
+ * @protected
24
+ */
25
+ protected isExpired(record: FileRecord): boolean;
26
+ /**
27
+ * Remove the expired records, at most once in each expiredCheckDelay
28
+ * @protected
29
+ */
30
+ protected removeExpired(): void;
31
+ /**
32
+ * Save the records after the write delay
33
+ * @protected
34
+ */
35
+ protected scheduleSave(): void;
36
+ /**
37
+ * Write the records to the file, through a temporary file
38
+ * @protected
39
+ */
40
+ protected save(): Promise<void>;
41
+ connect(): Promise<void>;
42
+ disconnect(): Promise<void>;
43
+ protected read(key: string): Promise<string | undefined>;
44
+ protected readMany(keys: string[]): Promise<(string | undefined)[]>;
45
+ protected write(entry: SerializedEntry): Promise<void>;
46
+ protected writeMany(entries: SerializedEntry[]): Promise<void>;
47
+ protected remove(key: string): Promise<boolean>;
48
+ protected removeMany(keys: string[]): Promise<boolean>;
49
+ clear(): Promise<void>;
50
+ }
51
+ export {};
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FileStore = void 0;
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const SerializedCacheStore_js_1 = require("./SerializedCacheStore.js");
10
+ const Serializer_js_1 = require("../lib/Serializer.js");
11
+ /**
12
+ * The file store, the entries are kept in memory and written to the file in batches
13
+ * File format: {"cache":[[key,{"expire":ms,"value":serialized entry}]],"lastExpire":ms}
14
+ */
15
+ class FileStore extends SerializedCacheStore_js_1.SerializedCacheStore {
16
+ constructor(options) {
17
+ super(options.namespace);
18
+ this.records = new Map();
19
+ this.lastExpire = Date.now();
20
+ this.saving = Promise.resolve();
21
+ this.filename = node_path_1.default.resolve(options.filename);
22
+ this.expiredCheckDelay = options.expiredCheckDelay ?? 3600000;
23
+ this.writeDelay = options.writeDelay ?? 100;
24
+ }
25
+ /**
26
+ * Whether a record has expired
27
+ * @param record
28
+ * @protected
29
+ */
30
+ isExpired(record) {
31
+ return typeof record.expire === 'number' && record.expire <= Date.now();
32
+ }
33
+ /**
34
+ * Remove the expired records, at most once in each expiredCheckDelay
35
+ * @protected
36
+ */
37
+ removeExpired() {
38
+ const now = Date.now();
39
+ if (now - this.lastExpire <= this.expiredCheckDelay)
40
+ return;
41
+ this.lastExpire = now;
42
+ for (const [key, record] of this.records)
43
+ if (this.isExpired(record))
44
+ this.records.delete(key);
45
+ }
46
+ /**
47
+ * Save the records after the write delay
48
+ * @protected
49
+ */
50
+ scheduleSave() {
51
+ if (this.saveTimer)
52
+ return;
53
+ this.saveTimer = setTimeout(() => {
54
+ this.saveTimer = undefined;
55
+ this.saving = this.saving.then(() => this.save()).catch((error) => this.onError(error));
56
+ }, this.writeDelay);
57
+ }
58
+ /**
59
+ * Write the records to the file, through a temporary file
60
+ * @protected
61
+ */
62
+ async save() {
63
+ this.removeExpired();
64
+ const content = (0, Serializer_js_1.serialize)({ cache: [...this.records], lastExpire: this.lastExpire });
65
+ const temporary = `${this.filename}.${process.pid}.tmp`;
66
+ await (0, promises_1.mkdir)(node_path_1.default.dirname(this.filename), { recursive: true });
67
+ await (0, promises_1.writeFile)(temporary, content);
68
+ await (0, promises_1.rename)(temporary, this.filename);
69
+ }
70
+ async connect() {
71
+ let text;
72
+ try {
73
+ text = await (0, promises_1.readFile)(this.filename, 'utf8');
74
+ }
75
+ catch (e) {
76
+ if (e.code === 'ENOENT')
77
+ return;
78
+ throw e;
79
+ }
80
+ const content = (0, Serializer_js_1.deserialize)(text);
81
+ this.records = new Map(Array.isArray(content.cache) ? content.cache : Object.entries(content.cache));
82
+ if (typeof content.lastExpire === 'number')
83
+ this.lastExpire = content.lastExpire;
84
+ }
85
+ async disconnect() {
86
+ if (this.saveTimer) {
87
+ clearTimeout(this.saveTimer);
88
+ this.saveTimer = undefined;
89
+ this.saving = this.saving.then(() => this.save());
90
+ }
91
+ await this.saving;
92
+ }
93
+ async read(key) {
94
+ const record = this.records.get(key);
95
+ if (record === undefined)
96
+ return undefined;
97
+ if (this.isExpired(record)) {
98
+ await this.remove(key);
99
+ return undefined;
100
+ }
101
+ return record.value;
102
+ }
103
+ async readMany(keys) {
104
+ return Promise.all(keys.map((key) => this.read(key)));
105
+ }
106
+ async write(entry) {
107
+ this.records.set(entry.key, { expire: entry.expires, value: entry.data });
108
+ this.scheduleSave();
109
+ }
110
+ async writeMany(entries) {
111
+ for (const entry of entries)
112
+ this.records.set(entry.key, { expire: entry.expires, value: entry.data });
113
+ this.scheduleSave();
114
+ }
115
+ async remove(key) {
116
+ if (!this.records.delete(key))
117
+ return false;
118
+ this.scheduleSave();
119
+ return true;
120
+ }
121
+ async removeMany(keys) {
122
+ let removed = false;
123
+ for (const key of keys)
124
+ removed = this.records.delete(key) || removed;
125
+ if (removed)
126
+ this.scheduleSave();
127
+ return removed;
128
+ }
129
+ async clear() {
130
+ if (this.namespace) {
131
+ const prefix = `${this.namespace}:`;
132
+ for (const key of this.records.keys())
133
+ if (key.startsWith(prefix))
134
+ this.records.delete(key);
135
+ }
136
+ else {
137
+ this.records.clear();
138
+ }
139
+ this.lastExpire = Date.now();
140
+ this.scheduleSave();
141
+ }
142
+ }
143
+ exports.FileStore = FileStore;
@@ -0,0 +1,42 @@
1
+ import { SerializedCacheStore, SerializedEntry } from './SerializedCacheStore.js';
2
+ import { MemcacheCacheOptions } from '../options/MemcacheCacheOptions.js';
3
+ interface MemcacheClient {
4
+ get(key: string): Promise<{
5
+ value: Buffer | null;
6
+ }>;
7
+ set(key: string, value: string, options: {
8
+ expires?: number;
9
+ }): Promise<boolean>;
10
+ delete(key: string): Promise<boolean>;
11
+ flush(): Promise<unknown>;
12
+ close(): void;
13
+ }
14
+ /**
15
+ * The Memcache store
16
+ * Key format: "{namespace}:{namespace}:{key}", or "{key}" without namespace
17
+ */
18
+ export declare class MemcacheStore extends SerializedCacheStore {
19
+ protected readonly options: MemcacheCacheOptions;
20
+ protected client: MemcacheClient;
21
+ constructor(options: MemcacheCacheOptions);
22
+ protected storeKey(key: string): string;
23
+ /**
24
+ * The memcached expiration of an entry, the entries expire after their expiration time
25
+ * @param entry
26
+ * @protected
27
+ */
28
+ protected expiration(entry: SerializedEntry): number;
29
+ connect(): Promise<void>;
30
+ disconnect(): Promise<void>;
31
+ protected read(key: string): Promise<string | undefined>;
32
+ protected readMany(keys: string[]): Promise<(string | undefined)[]>;
33
+ protected write(entry: SerializedEntry): Promise<void>;
34
+ protected writeMany(entries: SerializedEntry[]): Promise<void>;
35
+ protected remove(key: string): Promise<boolean>;
36
+ protected removeMany(keys: string[]): Promise<boolean>;
37
+ /**
38
+ * Memcached cannot list the keys, all the entries are flushed
39
+ */
40
+ clear(): Promise<void>;
41
+ }
42
+ export {};
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemcacheStore = void 0;
4
+ const SerializedCacheStore_js_1 = require("./SerializedCacheStore.js");
5
+ const LoadDriver_js_1 = require("../lib/LoadDriver.js");
6
+ //Larger expiration times are unix timestamps for memcached
7
+ const MAX_RELATIVE_EXPIRATION = 60 * 60 * 24 * 30;
8
+ /**
9
+ * The Memcache store
10
+ * Key format: "{namespace}:{namespace}:{key}", or "{key}" without namespace
11
+ */
12
+ class MemcacheStore extends SerializedCacheStore_js_1.SerializedCacheStore {
13
+ constructor(options) {
14
+ super(options.namespace);
15
+ this.options = options;
16
+ }
17
+ storeKey(key) {
18
+ return this.namespace ? `${this.namespace.trim()}:${`${this.namespace}:${key}`.trim()}` : key;
19
+ }
20
+ /**
21
+ * The memcached expiration of an entry, the entries expire after their expiration time
22
+ * @param entry
23
+ * @protected
24
+ */
25
+ expiration(entry) {
26
+ if (!entry.ttl || !entry.expires)
27
+ return 0;
28
+ const seconds = Math.ceil(entry.ttl / 1000) + 1;
29
+ return seconds > MAX_RELATIVE_EXPIRATION ? Math.ceil(entry.expires / 1000) + 1 : seconds;
30
+ }
31
+ async connect() {
32
+ const driver = await (0, LoadDriver_js_1.loadDriver)('Client', 'memjs');
33
+ const options = this.options;
34
+ this.client = driver.Client.create(`${options.host}:${options.port ?? 11211}`, {
35
+ username: options.username,
36
+ password: options.password
37
+ });
38
+ }
39
+ async disconnect() {
40
+ this.client?.close();
41
+ }
42
+ async read(key) {
43
+ const { value } = await this.client.get(key);
44
+ return value === null ? undefined : value.toString();
45
+ }
46
+ async readMany(keys) {
47
+ return Promise.all(keys.map((key) => this.read(key)));
48
+ }
49
+ async write(entry) {
50
+ await this.client.set(entry.key, entry.data, { expires: this.expiration(entry) });
51
+ }
52
+ async writeMany(entries) {
53
+ await Promise.all(entries.map((entry) => this.write(entry)));
54
+ }
55
+ async remove(key) {
56
+ return await this.client.delete(key);
57
+ }
58
+ async removeMany(keys) {
59
+ const removed = await Promise.all(keys.map((key) => this.remove(key)));
60
+ return removed.some((result) => result);
61
+ }
62
+ /**
63
+ * Memcached cannot list the keys, all the entries are flushed
64
+ */
65
+ async clear() {
66
+ await this.client.flush();
67
+ }
68
+ }
69
+ exports.MemcacheStore = MemcacheStore;
@@ -0,0 +1,34 @@
1
+ import { CacheStore, CacheStoreSetEntry } from './CacheStore.js';
2
+ import { CacheEntry } from '../lib/Serializer.js';
3
+ /**
4
+ * The in-memory store, the values are kept by reference
5
+ */
6
+ export declare class MemoryStore extends CacheStore {
7
+ protected readonly sweepInterval: number;
8
+ protected readonly entries: Map<string, CacheEntry>;
9
+ protected sweeper?: NodeJS.Timeout;
10
+ /**
11
+ * @param sweepInterval ms, remove the expired entries in each interval
12
+ */
13
+ constructor(sweepInterval?: number);
14
+ /**
15
+ * Remove the expired entries
16
+ * @protected
17
+ */
18
+ protected sweep(): void;
19
+ connect(): Promise<void>;
20
+ disconnect(): Promise<void>;
21
+ /**
22
+ * Read an entry, the expired entries are removed
23
+ * @param key
24
+ * @protected
25
+ */
26
+ protected read(key: string): CacheEntry | undefined;
27
+ get(key: string): Promise<CacheEntry | undefined>;
28
+ getMany(keys: string[]): Promise<(CacheEntry | undefined)[]>;
29
+ set(key: string, value: unknown, ttl?: number): Promise<void>;
30
+ setMany(entries: CacheStoreSetEntry[]): Promise<void>;
31
+ delete(key: string): Promise<boolean>;
32
+ deleteMany(keys: string[]): Promise<boolean>;
33
+ clear(): Promise<void>;
34
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryStore = void 0;
4
+ const CacheStore_js_1 = require("./CacheStore.js");
5
+ /**
6
+ * The in-memory store, the values are kept by reference
7
+ */
8
+ class MemoryStore extends CacheStore_js_1.CacheStore {
9
+ /**
10
+ * @param sweepInterval ms, remove the expired entries in each interval
11
+ */
12
+ constructor(sweepInterval = 60000) {
13
+ super();
14
+ this.sweepInterval = sweepInterval;
15
+ this.entries = new Map();
16
+ }
17
+ /**
18
+ * Remove the expired entries
19
+ * @protected
20
+ */
21
+ sweep() {
22
+ const now = Date.now();
23
+ for (const [key, entry] of this.entries)
24
+ if (typeof entry.expires === 'number' && now > entry.expires)
25
+ this.entries.delete(key);
26
+ }
27
+ async connect() {
28
+ this.sweeper = setInterval(() => this.sweep(), this.sweepInterval);
29
+ this.sweeper.unref();
30
+ }
31
+ async disconnect() {
32
+ clearInterval(this.sweeper);
33
+ }
34
+ /**
35
+ * Read an entry, the expired entries are removed
36
+ * @param key
37
+ * @protected
38
+ */
39
+ read(key) {
40
+ const entry = this.entries.get(key);
41
+ if (entry === undefined)
42
+ return undefined;
43
+ if ((0, CacheStore_js_1.isExpired)(entry)) {
44
+ this.entries.delete(key);
45
+ return undefined;
46
+ }
47
+ return entry;
48
+ }
49
+ async get(key) {
50
+ return this.read(key);
51
+ }
52
+ async getMany(keys) {
53
+ return keys.map((key) => this.read(key));
54
+ }
55
+ async set(key, value, ttl) {
56
+ this.entries.set(key, { value: value, expires: (0, CacheStore_js_1.expiresOf)(ttl) });
57
+ }
58
+ async setMany(entries) {
59
+ for (const entry of entries)
60
+ this.entries.set(entry.key, { value: entry.value, expires: (0, CacheStore_js_1.expiresOf)(entry.ttl) });
61
+ }
62
+ async delete(key) {
63
+ return this.entries.delete(key);
64
+ }
65
+ async deleteMany(keys) {
66
+ let deleted = false;
67
+ for (const key of keys)
68
+ deleted = this.entries.delete(key) || deleted;
69
+ return deleted;
70
+ }
71
+ async clear() {
72
+ this.entries.clear();
73
+ }
74
+ }
75
+ exports.MemoryStore = MemoryStore;
@@ -0,0 +1,55 @@
1
+ import { SerializedCacheStore, SerializedEntry } from './SerializedCacheStore.js';
2
+ import { MongoCacheOptions } from '../options/MongoCacheOptions.js';
3
+ type MongoDocument = {
4
+ key: string;
5
+ value: string;
6
+ expiresAt?: Date | null;
7
+ };
8
+ interface MongoCollection {
9
+ createIndex(keys: Record<string, number>, options: Record<string, unknown>): Promise<unknown>;
10
+ findOne(filter: Record<string, unknown>, options?: Record<string, unknown>): Promise<MongoDocument | null>;
11
+ find(filter: Record<string, unknown>, options?: Record<string, unknown>): {
12
+ toArray(): Promise<MongoDocument[]>;
13
+ };
14
+ updateOne(filter: Record<string, unknown>, update: Record<string, unknown>, options: Record<string, unknown>): Promise<unknown>;
15
+ bulkWrite(operations: Record<string, unknown>[], options: Record<string, unknown>): Promise<unknown>;
16
+ deleteOne(filter: Record<string, unknown>): Promise<{
17
+ deletedCount: number;
18
+ }>;
19
+ deleteMany(filter: Record<string, unknown>): Promise<{
20
+ deletedCount: number;
21
+ }>;
22
+ }
23
+ interface MongoClient {
24
+ connect(): Promise<unknown>;
25
+ close(): Promise<void>;
26
+ db(name: string): {
27
+ collection(name: string): MongoCollection;
28
+ };
29
+ }
30
+ /**
31
+ * The MongoDB store
32
+ * Document format: {key: "{namespace}:{key}", value: serialized entry, expiresAt: Date | null}, removed by a TTL index
33
+ */
34
+ export declare class MongoStore extends SerializedCacheStore {
35
+ protected readonly options: MongoCacheOptions;
36
+ protected client: MongoClient;
37
+ protected collection: MongoCollection;
38
+ constructor(options: MongoCacheOptions);
39
+ connect(): Promise<void>;
40
+ disconnect(): Promise<void>;
41
+ protected read(key: string): Promise<string | undefined>;
42
+ protected readMany(keys: string[]): Promise<(string | undefined)[]>;
43
+ /**
44
+ * The upsert of an entry
45
+ * @param entry
46
+ * @protected
47
+ */
48
+ protected update(entry: SerializedEntry): [Record<string, unknown>, Record<string, unknown>];
49
+ protected write(entry: SerializedEntry): Promise<void>;
50
+ protected writeMany(entries: SerializedEntry[]): Promise<void>;
51
+ protected remove(key: string): Promise<boolean>;
52
+ protected removeMany(keys: string[]): Promise<boolean>;
53
+ clear(): Promise<void>;
54
+ }
55
+ export {};