polystore 0.16.1 → 0.18.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/index.d.ts +23 -11
- package/index.js +104 -45
- package/package.json +15 -7
- package/readme.md +377 -181
package/index.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
type
|
|
2
|
-
expires?: number | null | string;
|
|
3
|
-
};
|
|
1
|
+
type Expires = number | null | string;
|
|
4
2
|
type StoreData<T extends Serializable = Serializable> = {
|
|
5
3
|
value: T;
|
|
6
4
|
expires: number | null;
|
|
@@ -9,13 +7,14 @@ type Serializable = string | number | boolean | null | (Serializable | null)[] |
|
|
|
9
7
|
[key: string]: Serializable | null;
|
|
10
8
|
};
|
|
11
9
|
interface ClientExpires {
|
|
10
|
+
TYPE: string;
|
|
12
11
|
EXPIRES: true;
|
|
13
12
|
promise?: Promise<any>;
|
|
14
13
|
test?: (client: any) => boolean;
|
|
15
14
|
get<T extends Serializable>(key: string): Promise<T | null> | T | null;
|
|
16
|
-
set<T extends Serializable>(key: string, value: T,
|
|
15
|
+
set<T extends Serializable>(key: string, value: T, expires?: Expires): Promise<any> | any;
|
|
17
16
|
iterate<T extends Serializable>(prefix: string): AsyncGenerator<[string, T], void, unknown> | Generator<[string, T], void, unknown>;
|
|
18
|
-
add?<T extends Serializable>(prefix: string, value: T,
|
|
17
|
+
add?<T extends Serializable>(prefix: string, value: T, expires?: Expires): Promise<string>;
|
|
19
18
|
has?(key: string): Promise<boolean> | boolean;
|
|
20
19
|
del?(key: string): Promise<any> | any;
|
|
21
20
|
keys?(prefix: string): Promise<string[]> | string[];
|
|
@@ -27,13 +26,14 @@ interface ClientExpires {
|
|
|
27
26
|
close?(): Promise<any> | any;
|
|
28
27
|
}
|
|
29
28
|
interface ClientNonExpires {
|
|
29
|
+
TYPE: string;
|
|
30
30
|
EXPIRES: false;
|
|
31
31
|
promise?: Promise<any>;
|
|
32
32
|
test?: (client: any) => boolean;
|
|
33
33
|
get<T extends Serializable>(key: string): Promise<StoreData<T> | null> | StoreData<T> | null;
|
|
34
|
-
set<T extends Serializable>(key: string, value: StoreData<T> | null,
|
|
34
|
+
set<T extends Serializable>(key: string, value: StoreData<T> | null, ttl?: Expires): Promise<any> | any;
|
|
35
35
|
iterate<T extends Serializable>(prefix: string): AsyncGenerator<[string, StoreData<T>], void, unknown> | Generator<[string, StoreData<T>], void, unknown>;
|
|
36
|
-
add?<T extends Serializable>(prefix: string, value: StoreData<T>,
|
|
36
|
+
add?<T extends Serializable>(prefix: string, value: StoreData<T>, ttl?: Expires): Promise<string>;
|
|
37
37
|
has?(key: string): Promise<boolean> | boolean;
|
|
38
38
|
del?(key: string): Promise<any> | any;
|
|
39
39
|
keys?(prefix: string): Promise<string[]> | string[];
|
|
@@ -51,6 +51,7 @@ declare class Store<TDefault extends Serializable = Serializable> {
|
|
|
51
51
|
PREFIX: string;
|
|
52
52
|
promise: Promise<Client> | null;
|
|
53
53
|
client: Client;
|
|
54
|
+
type: string;
|
|
54
55
|
constructor(clientPromise?: any);
|
|
55
56
|
/**
|
|
56
57
|
* Save the data on an autogenerated key, can add expiration as well:
|
|
@@ -63,8 +64,8 @@ declare class Store<TDefault extends Serializable = Serializable> {
|
|
|
63
64
|
*
|
|
64
65
|
* **[→ Full .add() Docs](https://polystore.dev/documentation#add)**
|
|
65
66
|
*/
|
|
66
|
-
add(value: TDefault,
|
|
67
|
-
add<T extends TDefault>(value: T,
|
|
67
|
+
add(value: TDefault, ttl?: Expires): Promise<string>;
|
|
68
|
+
add<T extends TDefault>(value: T, ttl?: Expires): Promise<string>;
|
|
68
69
|
/**
|
|
69
70
|
* Save the data on the given key, can add expiration as well:
|
|
70
71
|
*
|
|
@@ -76,8 +77,8 @@ declare class Store<TDefault extends Serializable = Serializable> {
|
|
|
76
77
|
*
|
|
77
78
|
* **[→ Full .set() Docs](https://polystore.dev/documentation#set)**
|
|
78
79
|
*/
|
|
79
|
-
set(key: string, value: TDefault,
|
|
80
|
-
set<T extends TDefault>(key: string, value: T,
|
|
80
|
+
set(key: string, value: TDefault, ttl?: Expires): Promise<string>;
|
|
81
|
+
set<T extends TDefault>(key: string, value: T, ttl?: Expires): Promise<string>;
|
|
81
82
|
/**
|
|
82
83
|
* Read a single value from the KV store:
|
|
83
84
|
*
|
|
@@ -121,6 +122,17 @@ declare class Store<TDefault extends Serializable = Serializable> {
|
|
|
121
122
|
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
122
123
|
*/
|
|
123
124
|
del(key: string): Promise<string>;
|
|
125
|
+
/**
|
|
126
|
+
* @alias of .del(key: string)
|
|
127
|
+
* Remove a single key and its value from the store:
|
|
128
|
+
*
|
|
129
|
+
* ```js
|
|
130
|
+
* const key = await store.delete("key1");
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
134
|
+
*/
|
|
135
|
+
delete(key: string): Promise<string>;
|
|
124
136
|
/**
|
|
125
137
|
* An iterator that goes through all of the key:value pairs in the client
|
|
126
138
|
*
|
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/clients/Client.ts
|
|
2
2
|
var Client = class {
|
|
3
|
+
TYPE;
|
|
3
4
|
EXPIRES = false;
|
|
4
5
|
client;
|
|
5
6
|
encode = (val) => JSON.stringify(val, null, 2);
|
|
@@ -11,6 +12,7 @@ var Client = class {
|
|
|
11
12
|
|
|
12
13
|
// src/clients/api.ts
|
|
13
14
|
var Api = class extends Client {
|
|
15
|
+
TYPE = "API";
|
|
14
16
|
// Indicate that the file handler DOES handle expirations
|
|
15
17
|
EXPIRES = true;
|
|
16
18
|
static test = (client) => typeof client === "string" && /^https?:\/\//.test(client);
|
|
@@ -25,17 +27,18 @@ var Api = class extends Client {
|
|
|
25
27
|
return this.decode(await res.text());
|
|
26
28
|
};
|
|
27
29
|
get = (key) => this.#api(key);
|
|
28
|
-
set = async (key, value,
|
|
30
|
+
set = async (key, value, expires) => {
|
|
29
31
|
const exp = typeof expires === "number" ? `?expires=${expires}` : "";
|
|
30
32
|
await this.#api(key, exp, "PUT", this.encode(value));
|
|
31
33
|
};
|
|
32
|
-
del =
|
|
33
|
-
await this.#api(key, "", "DELETE");
|
|
34
|
-
};
|
|
34
|
+
del = (key) => this.#api(key, "", "DELETE");
|
|
35
35
|
async *iterate(prefix = "") {
|
|
36
|
-
const data = await this.#api(
|
|
36
|
+
const data = await this.#api(
|
|
37
|
+
"",
|
|
38
|
+
`?prefix=${encodeURIComponent(prefix)}`
|
|
39
|
+
);
|
|
37
40
|
for (let [key, value] of Object.entries(data || {})) {
|
|
38
|
-
if (value !== null
|
|
41
|
+
if (value !== null) {
|
|
39
42
|
yield [prefix + key, value];
|
|
40
43
|
}
|
|
41
44
|
}
|
|
@@ -44,17 +47,20 @@ var Api = class extends Client {
|
|
|
44
47
|
|
|
45
48
|
// src/clients/cloudflare.ts
|
|
46
49
|
var Cloudflare = class extends Client {
|
|
50
|
+
TYPE = "CLOUDFLARE";
|
|
47
51
|
// It handles expirations natively
|
|
48
52
|
EXPIRES = true;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
static testKeys = ["getWithMetadata", "get", "list", "delete"];
|
|
54
|
+
get = async (key) => {
|
|
55
|
+
const value = await this.client.get(key);
|
|
56
|
+
return this.decode(value);
|
|
57
|
+
};
|
|
58
|
+
set = async (key, data, expires) => {
|
|
59
|
+
const expirationTtl = expires ? Math.round(expires) : void 0;
|
|
54
60
|
if (expirationTtl && expirationTtl < 60) {
|
|
55
61
|
throw new Error("Cloudflare's min expiration is '60s'");
|
|
56
62
|
}
|
|
57
|
-
|
|
63
|
+
await this.client.put(key, this.encode(data), { expirationTtl });
|
|
58
64
|
};
|
|
59
65
|
del = (key) => this.client.delete(key);
|
|
60
66
|
// Since we have pagination, we don't want to get all of the
|
|
@@ -84,12 +90,13 @@ var Cloudflare = class extends Client {
|
|
|
84
90
|
entries = async (prefix = "") => {
|
|
85
91
|
const keys = await this.keys(prefix);
|
|
86
92
|
const values = await Promise.all(keys.map((k) => this.get(k)));
|
|
87
|
-
return keys.map((k, i) => [k, values[i]]);
|
|
93
|
+
return keys.map((k, i) => [k, values[i]]).filter((p) => p[1] !== null);
|
|
88
94
|
};
|
|
89
95
|
};
|
|
90
96
|
|
|
91
97
|
// src/clients/cookie.ts
|
|
92
98
|
var Cookie = class extends Client {
|
|
99
|
+
TYPE = "COOKIE";
|
|
93
100
|
// It handles expirations natively
|
|
94
101
|
EXPIRES = true;
|
|
95
102
|
// Check if this is the right class for the given client
|
|
@@ -115,7 +122,7 @@ var Cookie = class extends Client {
|
|
|
115
122
|
const all = this.#read();
|
|
116
123
|
return key in all ? all[key] : null;
|
|
117
124
|
};
|
|
118
|
-
set = (key, data,
|
|
125
|
+
set = (key, data, expires) => {
|
|
119
126
|
const k = encodeURIComponent(key);
|
|
120
127
|
const value = encodeURIComponent(this.encode(data ?? ""));
|
|
121
128
|
let exp = "";
|
|
@@ -125,7 +132,7 @@ var Cookie = class extends Client {
|
|
|
125
132
|
}
|
|
126
133
|
document.cookie = `${k}=${value}${exp}`;
|
|
127
134
|
};
|
|
128
|
-
del = (key) => this.set(key, "",
|
|
135
|
+
del = (key) => this.set(key, "", -100);
|
|
129
136
|
async *iterate(prefix = "") {
|
|
130
137
|
for (let [key, value] of Object.entries(this.#read())) {
|
|
131
138
|
if (!key.startsWith(prefix)) continue;
|
|
@@ -136,12 +143,18 @@ var Cookie = class extends Client {
|
|
|
136
143
|
|
|
137
144
|
// src/clients/etcd.ts
|
|
138
145
|
var Etcd = class extends Client {
|
|
146
|
+
TYPE = "ETCD3";
|
|
139
147
|
// It desn't handle expirations natively
|
|
140
148
|
EXPIRES = false;
|
|
141
149
|
// Check if this is the right class for the given client
|
|
142
|
-
static
|
|
143
|
-
get = (key) =>
|
|
144
|
-
|
|
150
|
+
static testKeys = ["leaseClient", "watchClient", "watchManager"];
|
|
151
|
+
get = async (key) => {
|
|
152
|
+
const data = await this.client.get(key).json();
|
|
153
|
+
return data;
|
|
154
|
+
};
|
|
155
|
+
set = async (key, value) => {
|
|
156
|
+
await this.client.put(key).value(this.encode(value));
|
|
157
|
+
};
|
|
145
158
|
del = (key) => this.client.delete().key(key).exec();
|
|
146
159
|
async *iterate(prefix = "") {
|
|
147
160
|
const keys = await this.client.getAll().prefix(prefix).keys();
|
|
@@ -149,12 +162,6 @@ var Etcd = class extends Client {
|
|
|
149
162
|
yield [key, await this.get(key)];
|
|
150
163
|
}
|
|
151
164
|
}
|
|
152
|
-
keys = (prefix = "") => this.client.getAll().prefix(prefix).keys();
|
|
153
|
-
entries = async (prefix = "") => {
|
|
154
|
-
const keys = await this.keys(prefix);
|
|
155
|
-
const values = await Promise.all(keys.map((k) => this.get(k)));
|
|
156
|
-
return keys.map((k, i) => [k, values[i]]);
|
|
157
|
-
};
|
|
158
165
|
clear = async (prefix = "") => {
|
|
159
166
|
if (!prefix) return this.client.delete().all();
|
|
160
167
|
return this.client.delete().prefix(prefix);
|
|
@@ -163,6 +170,7 @@ var Etcd = class extends Client {
|
|
|
163
170
|
|
|
164
171
|
// src/clients/file.ts
|
|
165
172
|
var File = class extends Client {
|
|
173
|
+
TYPE = "FILE";
|
|
166
174
|
// It desn't handle expirations natively
|
|
167
175
|
EXPIRES = false;
|
|
168
176
|
fsp;
|
|
@@ -256,6 +264,7 @@ var noFileOk = (error) => {
|
|
|
256
264
|
throw error;
|
|
257
265
|
};
|
|
258
266
|
var Folder = class extends Client {
|
|
267
|
+
TYPE = "FOLDER";
|
|
259
268
|
// It desn't handle expirations natively
|
|
260
269
|
EXPIRES = false;
|
|
261
270
|
fsp;
|
|
@@ -274,13 +283,16 @@ var Folder = class extends Client {
|
|
|
274
283
|
});
|
|
275
284
|
})();
|
|
276
285
|
file = (key) => this.folder + key + ".json";
|
|
277
|
-
get = (key) => {
|
|
278
|
-
|
|
286
|
+
get = async (key) => {
|
|
287
|
+
const file = await this.fsp.readFile(this.file(key), "utf8").catch(noFileOk);
|
|
288
|
+
return this.decode(file);
|
|
279
289
|
};
|
|
280
|
-
set = (key, value) => {
|
|
281
|
-
|
|
290
|
+
set = async (key, value) => {
|
|
291
|
+
await this.fsp.writeFile(this.file(key), this.encode(value), "utf8");
|
|
292
|
+
};
|
|
293
|
+
del = async (key) => {
|
|
294
|
+
await this.fsp.unlink(this.file(key)).catch(noFileOk);
|
|
282
295
|
};
|
|
283
|
-
del = (key) => this.fsp.unlink(this.file(key)).catch(noFileOk);
|
|
284
296
|
async *iterate(prefix = "") {
|
|
285
297
|
const all = await this.fsp.readdir(this.folder);
|
|
286
298
|
const keys = all.filter((f) => f.startsWith(prefix) && f.endsWith(".json"));
|
|
@@ -288,7 +300,7 @@ var Folder = class extends Client {
|
|
|
288
300
|
const key = name.slice(0, -".json".length);
|
|
289
301
|
try {
|
|
290
302
|
const data = await this.get(key);
|
|
291
|
-
yield [key, data];
|
|
303
|
+
if (data !== null && data !== void 0) yield [key, data];
|
|
292
304
|
} catch {
|
|
293
305
|
continue;
|
|
294
306
|
}
|
|
@@ -298,6 +310,7 @@ var Folder = class extends Client {
|
|
|
298
310
|
|
|
299
311
|
// src/clients/forage.ts
|
|
300
312
|
var Forage = class extends Client {
|
|
313
|
+
TYPE = "FORAGE";
|
|
301
314
|
// It desn't handle expirations natively
|
|
302
315
|
EXPIRES = false;
|
|
303
316
|
// Check if this is the right class for the given client
|
|
@@ -331,10 +344,11 @@ var notFound = (error) => {
|
|
|
331
344
|
throw error;
|
|
332
345
|
};
|
|
333
346
|
var Level = class extends Client {
|
|
347
|
+
TYPE = "LEVEL";
|
|
334
348
|
// It desn't handle expirations natively
|
|
335
349
|
EXPIRES = false;
|
|
336
350
|
// Check if this is the right class for the given client
|
|
337
|
-
static
|
|
351
|
+
static testKeys = ["attachResource", "detachResource", "prependOnceListener"];
|
|
338
352
|
get = (key) => this.client.get(key, { valueEncoding }).catch(notFound);
|
|
339
353
|
set = (key, value) => this.client.put(key, value, { valueEncoding });
|
|
340
354
|
del = (key) => this.client.del(key);
|
|
@@ -365,6 +379,7 @@ var Level = class extends Client {
|
|
|
365
379
|
|
|
366
380
|
// src/clients/memory.ts
|
|
367
381
|
var Memory = class extends Client {
|
|
382
|
+
TYPE = "MEMORY";
|
|
368
383
|
// It desn't handle expirations natively
|
|
369
384
|
EXPIRES = false;
|
|
370
385
|
// Check if this is the right class for the given client
|
|
@@ -382,12 +397,13 @@ var Memory = class extends Client {
|
|
|
382
397
|
|
|
383
398
|
// src/clients/redis.ts
|
|
384
399
|
var Redis = class extends Client {
|
|
400
|
+
TYPE = "REDIS";
|
|
385
401
|
// Indicate if this client handles expirations (true = it does)
|
|
386
402
|
EXPIRES = true;
|
|
387
403
|
// Check if this is the right class for the given client
|
|
388
404
|
static test = (client) => client && client.pSubscribe && client.sSubscribe;
|
|
389
405
|
get = async (key) => this.decode(await this.client.get(key));
|
|
390
|
-
set = async (key, value,
|
|
406
|
+
set = async (key, value, expires) => {
|
|
391
407
|
const EX = expires ? Math.round(expires) : void 0;
|
|
392
408
|
return this.client.set(key, this.encode(value), { EX });
|
|
393
409
|
};
|
|
@@ -425,12 +441,34 @@ var Redis = class extends Client {
|
|
|
425
441
|
|
|
426
442
|
// src/clients/sqlite.ts
|
|
427
443
|
var SQLite = class extends Client {
|
|
444
|
+
TYPE = "SQLITE";
|
|
428
445
|
// This one is doing manual time management internally even though
|
|
429
446
|
// sqlite does not natively support expirations. This is because it does
|
|
430
447
|
// support creating a `expires_at:Date` column that makes managing
|
|
431
|
-
//
|
|
448
|
+
// expirations much easier, so it's really "somewhere in between"
|
|
432
449
|
EXPIRES = true;
|
|
433
|
-
|
|
450
|
+
// The table name to use
|
|
451
|
+
table = "kv";
|
|
452
|
+
// Make sure the folder already exists, so attempt to create it
|
|
453
|
+
// It fails if it already exists, hence the catch case
|
|
454
|
+
promise = (async () => {
|
|
455
|
+
if (!/^[a-zA-Z_]+$/.test(this.table)) {
|
|
456
|
+
throw new Error(`Invalid table name ${this.table}`);
|
|
457
|
+
}
|
|
458
|
+
this.client.exec(`
|
|
459
|
+
CREATE TABLE IF NOT EXISTS ${this.table} (
|
|
460
|
+
id TEXT PRIMARY KEY,
|
|
461
|
+
value TEXT NOT NULL,
|
|
462
|
+
expires_at INTEGER
|
|
463
|
+
)
|
|
464
|
+
`);
|
|
465
|
+
this.client.exec(
|
|
466
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.table}_expires_at ON ${this.table} (expires_at)`
|
|
467
|
+
);
|
|
468
|
+
})();
|
|
469
|
+
static test = (client) => {
|
|
470
|
+
return typeof client?.prepare === "function" && typeof client?.exec === "function";
|
|
471
|
+
};
|
|
434
472
|
get = (id) => {
|
|
435
473
|
const row = this.client.prepare(`SELECT value, expires_at FROM kv WHERE id = ?`).get(id);
|
|
436
474
|
if (!row) return null;
|
|
@@ -440,7 +478,7 @@ var SQLite = class extends Client {
|
|
|
440
478
|
}
|
|
441
479
|
return this.decode(row.value);
|
|
442
480
|
};
|
|
443
|
-
set = (id, data,
|
|
481
|
+
set = (id, data, expires) => {
|
|
444
482
|
const value = this.encode(data);
|
|
445
483
|
const expires_at = expires ? Date.now() + expires * 1e3 : null;
|
|
446
484
|
this.client.prepare(
|
|
@@ -481,7 +519,7 @@ ${prefix ? "AND id LIKE ?" : ""}
|
|
|
481
519
|
this.client.prepare(`DELETE FROM kv WHERE expires_at < ?`).run(Date.now());
|
|
482
520
|
};
|
|
483
521
|
clearAll = () => {
|
|
484
|
-
this.client.
|
|
522
|
+
this.client.exec(`DELETE FROM kv`);
|
|
485
523
|
};
|
|
486
524
|
close = () => {
|
|
487
525
|
this.client.close?.();
|
|
@@ -490,6 +528,7 @@ ${prefix ? "AND id LIKE ?" : ""}
|
|
|
490
528
|
|
|
491
529
|
// src/clients/storage.ts
|
|
492
530
|
var WebStorage = class extends Client {
|
|
531
|
+
TYPE = "STORAGE";
|
|
493
532
|
// It desn't handle expirations natively
|
|
494
533
|
EXPIRES = false;
|
|
495
534
|
// Check if this is the right class for the given client
|
|
@@ -573,21 +612,28 @@ var Store = class _Store {
|
|
|
573
612
|
PREFIX = "";
|
|
574
613
|
promise;
|
|
575
614
|
client;
|
|
615
|
+
type = "UNKNOWN";
|
|
576
616
|
constructor(clientPromise = /* @__PURE__ */ new Map()) {
|
|
577
617
|
this.promise = Promise.resolve(clientPromise).then(async (client) => {
|
|
578
618
|
this.client = this.#find(client);
|
|
579
619
|
this.#validate(this.client);
|
|
580
620
|
this.promise = null;
|
|
581
621
|
await this.client.promise;
|
|
622
|
+
this.type = this.client?.TYPE || this.type;
|
|
582
623
|
return client;
|
|
583
624
|
});
|
|
584
625
|
}
|
|
585
626
|
#find(store) {
|
|
586
627
|
if (store instanceof _Store) return store.client;
|
|
587
628
|
for (let client of Object.values(clients_default)) {
|
|
588
|
-
if (
|
|
629
|
+
if ("test" in client && client.test(store)) {
|
|
589
630
|
return new client(store);
|
|
590
631
|
}
|
|
632
|
+
if ("testKeys" in client && typeof store === "object") {
|
|
633
|
+
if (client.testKeys.every((key) => store[key])) {
|
|
634
|
+
return new client(store);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
591
637
|
}
|
|
592
638
|
if (typeof store === "function" && /^class\s/.test(Function.prototype.toString.call(store))) {
|
|
593
639
|
return new store();
|
|
@@ -618,29 +664,29 @@ var Store = class _Store {
|
|
|
618
664
|
if (key) this.del(key);
|
|
619
665
|
return false;
|
|
620
666
|
}
|
|
621
|
-
async add(value,
|
|
667
|
+
async add(value, ttl) {
|
|
622
668
|
await this.promise;
|
|
623
|
-
let expires = parse(
|
|
669
|
+
let expires = parse(ttl);
|
|
624
670
|
if (this.client.add) {
|
|
625
671
|
if (this.client.EXPIRES) {
|
|
626
|
-
return await this.client.add(this.PREFIX, value,
|
|
672
|
+
return await this.client.add(this.PREFIX, value, expires);
|
|
627
673
|
}
|
|
628
674
|
expires = unix(expires);
|
|
629
675
|
const key2 = await this.client.add(this.PREFIX, { expires, value });
|
|
630
676
|
return key2;
|
|
631
677
|
}
|
|
632
678
|
const key = createId();
|
|
633
|
-
return this.set(key, value,
|
|
679
|
+
return this.set(key, value, expires);
|
|
634
680
|
}
|
|
635
|
-
async set(key, value,
|
|
681
|
+
async set(key, value, ttl) {
|
|
636
682
|
await this.promise;
|
|
637
683
|
const id = this.PREFIX + key;
|
|
638
|
-
let expires = parse(
|
|
684
|
+
let expires = parse(ttl);
|
|
639
685
|
if (value === null || typeof expires === "number" && expires <= 0) {
|
|
640
686
|
return this.del(key);
|
|
641
687
|
}
|
|
642
688
|
if (this.client.EXPIRES) {
|
|
643
|
-
await this.client.set(id, value,
|
|
689
|
+
await this.client.set(id, value, expires);
|
|
644
690
|
return key;
|
|
645
691
|
}
|
|
646
692
|
expires = unix(expires);
|
|
@@ -702,12 +748,25 @@ var Store = class _Store {
|
|
|
702
748
|
return key;
|
|
703
749
|
}
|
|
704
750
|
if (this.client.EXPIRES) {
|
|
705
|
-
await this.client.set(id, null,
|
|
751
|
+
await this.client.set(id, null, 0);
|
|
706
752
|
} else {
|
|
707
753
|
await this.client.set(id, null);
|
|
708
754
|
}
|
|
709
755
|
return key;
|
|
710
756
|
}
|
|
757
|
+
/**
|
|
758
|
+
* @alias of .del(key: string)
|
|
759
|
+
* Remove a single key and its value from the store:
|
|
760
|
+
*
|
|
761
|
+
* ```js
|
|
762
|
+
* const key = await store.delete("key1");
|
|
763
|
+
* ```
|
|
764
|
+
*
|
|
765
|
+
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
766
|
+
*/
|
|
767
|
+
async delete(key) {
|
|
768
|
+
return this.del(key);
|
|
769
|
+
}
|
|
711
770
|
async *[Symbol.asyncIterator]() {
|
|
712
771
|
await this.promise;
|
|
713
772
|
if (this.client.EXPIRES) {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polystore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "A small compatibility layer for many popular KV stores like localStorage, Redis, FileSystem, etc.",
|
|
5
|
-
"homepage": "https://polystore.dev
|
|
5
|
+
"homepage": "https://polystore.dev",
|
|
6
6
|
"repository": "https://github.com/franciscop/polystore.git",
|
|
7
7
|
"bugs": "https://github.com/franciscop/polystore/issues",
|
|
8
8
|
"funding": "https://www.paypal.me/franciscopresencia/19",
|
|
@@ -16,11 +16,13 @@
|
|
|
16
16
|
"index.d.ts"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"analyze": "npm run build && esbuild src/index.ts --bundle --packages=external --format=esm --minify --outfile=index.min.js && gzip-size index.min.js && rm index.min.js",
|
|
19
|
+
"analyze": "npm run build && esbuild src/index.ts --bundle --packages=external --format=esm --minify --outfile=index.min.js && echo 'Final size:' && gzip-size index.min.js && rm index.min.js",
|
|
20
20
|
"build": "bunx tsup src/index.ts --format esm --dts --out-dir . --target node24",
|
|
21
21
|
"lint": "npx tsc --noEmit",
|
|
22
22
|
"start": "bun test --watch",
|
|
23
|
-
"test": "bun test",
|
|
23
|
+
"test": "npm run test:bun && npm run test:jest",
|
|
24
|
+
"test:bun": "bun test ./test/index.test.ts",
|
|
25
|
+
"test:jest": "jest ./test/index.test.ts --detectOpenHandles --forceExit",
|
|
24
26
|
"run:db": "etcd",
|
|
25
27
|
"run:server": "bun ./src/server.ts"
|
|
26
28
|
},
|
|
@@ -35,21 +37,27 @@
|
|
|
35
37
|
"license": "MIT",
|
|
36
38
|
"devDependencies": {
|
|
37
39
|
"@deno/kv": "^0.8.1",
|
|
40
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
38
41
|
"@types/bun": "^1.3.3",
|
|
42
|
+
"@types/jest": "^30.0.0",
|
|
39
43
|
"@types/jsdom": "^27.0.0",
|
|
40
|
-
"better-sqlite3": "^12.
|
|
44
|
+
"better-sqlite3": "^12.6.0",
|
|
41
45
|
"check-dts": "^0.8.0",
|
|
42
|
-
"cross-fetch": "^4.
|
|
46
|
+
"cross-fetch": "^4.1.0",
|
|
43
47
|
"dotenv": "^16.3.1",
|
|
44
48
|
"edge-mock": "^0.0.15",
|
|
45
49
|
"esbuild": "^0.27.0",
|
|
46
50
|
"etcd3": "^1.1.2",
|
|
47
51
|
"gzip-size-cli": "^5.1.0",
|
|
52
|
+
"jest": "^30.2.0",
|
|
48
53
|
"jsdom": "^27.2.0",
|
|
49
54
|
"level": "^8.0.1",
|
|
50
55
|
"localforage": "^1.10.0",
|
|
51
56
|
"redis": "^4.6.10",
|
|
52
|
-
"
|
|
57
|
+
"ts-jest": "^29.4.6",
|
|
58
|
+
"ts-node": "^10.9.2",
|
|
59
|
+
"tsup": "^8.5.1",
|
|
60
|
+
"typescript": "^5.9.3"
|
|
53
61
|
},
|
|
54
62
|
"documentation": {
|
|
55
63
|
"title": "🏬 Polystore - A universal library for standardizing any KV-store",
|