polystore 0.20.0 → 0.21.1
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 +1 -1
- package/package.json +30 -10
- package/readme.md +152 -23
- package/src/integrations/express.d.ts +307 -0
- package/src/integrations/express.js +42 -0
- package/src/integrations/hono-sessions.d.ts +299 -0
- package/src/integrations/hono-sessions.js +36 -0
- package/src/express.js +0 -47
package/index.js
CHANGED
|
@@ -179,7 +179,7 @@ var File = class extends Client {
|
|
|
179
179
|
// Check if this is the right class for the given client
|
|
180
180
|
static test = (client) => {
|
|
181
181
|
if (client instanceof URL) client = client.href;
|
|
182
|
-
return typeof client === "string" && client.startsWith("file://") && client.
|
|
182
|
+
return typeof client === "string" && client.startsWith("file://") && client.endsWith(".json");
|
|
183
183
|
};
|
|
184
184
|
// We want to make sure the file already exists, so attempt to
|
|
185
185
|
// create the folders and the file (but not OVERWRITE it, that's why the x flag)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polystore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.1",
|
|
4
4
|
"description": "A small compatibility layer for many popular KV stores like localStorage, Redis, FileSystem, etc.",
|
|
5
5
|
"homepage": "https://polystore.dev",
|
|
6
6
|
"repository": "https://github.com/franciscop/polystore.git",
|
|
@@ -16,25 +16,36 @@
|
|
|
16
16
|
"types": "./index.d.ts",
|
|
17
17
|
"import": "./index.js"
|
|
18
18
|
},
|
|
19
|
-
"./express":
|
|
19
|
+
"./express": {
|
|
20
|
+
"types": "./src/integrations/express.d.ts",
|
|
21
|
+
"import": "./src/integrations/express.js"
|
|
22
|
+
},
|
|
23
|
+
"./hono-sessions": {
|
|
24
|
+
"types": "./src/integrations/hono-sessions.d.ts",
|
|
25
|
+
"import": "./src/integrations/hono-sessions.js"
|
|
26
|
+
}
|
|
20
27
|
},
|
|
21
28
|
"files": [
|
|
22
29
|
"index.js",
|
|
23
30
|
"index.d.ts",
|
|
24
|
-
"src/express.js"
|
|
31
|
+
"src/integrations/express.js",
|
|
32
|
+
"src/integrations/express.d.ts",
|
|
33
|
+
"src/integrations/hono-sessions.js",
|
|
34
|
+
"src/integrations/hono-sessions.d.ts"
|
|
25
35
|
],
|
|
26
36
|
"scripts": {
|
|
27
37
|
"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",
|
|
28
|
-
"build": "bunx tsup src/index.ts --format esm --dts --out-dir . --target node24",
|
|
38
|
+
"build": "bunx tsup src/index.ts --format esm --dts --out-dir . --target node24 && bunx tsup src/integrations/express.ts src/integrations/hono-sessions.ts --format esm --dts --out-dir src/integrations --target node24 --external polystore --external express-session --external hono-sessions",
|
|
29
39
|
"lint": "npx tsc --noEmit",
|
|
30
40
|
"start": "bun test --watch",
|
|
41
|
+
"service:db": "etcd",
|
|
42
|
+
"service:redis": "brew services start redis",
|
|
43
|
+
"service:postgres": "brew services start postgresql",
|
|
44
|
+
"service:server": "bun ./src/server.ts",
|
|
45
|
+
"services": "concurrently \"npm run service:db\" \"npm run service:redis\" \"npm run service:postgres\" \"npm run service:server\"",
|
|
31
46
|
"test": "npm run test:bun && npm run test:jest",
|
|
32
|
-
"test:bun": "bun test ./test/index.test.ts",
|
|
33
|
-
"test:jest": "jest ./test/index.test.ts --detectOpenHandles --forceExit"
|
|
34
|
-
"run:db": "etcd",
|
|
35
|
-
"run:redis": "brew services start redis",
|
|
36
|
-
"run:postgres": "brew services start postgresql",
|
|
37
|
-
"run:server": "bun ./src/server.ts"
|
|
47
|
+
"test:bun": "bun test ./test/index.test.ts ./src/integrations/",
|
|
48
|
+
"test:jest": "jest ./test/index.test.ts --detectOpenHandles --forceExit"
|
|
38
49
|
},
|
|
39
50
|
"keywords": [
|
|
40
51
|
"kv",
|
|
@@ -49,23 +60,32 @@
|
|
|
49
60
|
"@deno/kv": "^0.8.1",
|
|
50
61
|
"@types/better-sqlite3": "^7.6.13",
|
|
51
62
|
"@types/bun": "^1.3.3",
|
|
63
|
+
"@types/express": "^5.0.6",
|
|
64
|
+
"@types/express-session": "^1.18.2",
|
|
52
65
|
"@types/jest": "^30.0.0",
|
|
53
66
|
"@types/jsdom": "^27.0.0",
|
|
54
67
|
"@types/pg": "^8.11.10",
|
|
68
|
+
"@types/supertest": "^7.2.0",
|
|
55
69
|
"better-sqlite3": "^12.6.0",
|
|
56
70
|
"check-dts": "^0.8.0",
|
|
71
|
+
"concurrently": "^9.2.1",
|
|
57
72
|
"cross-fetch": "^4.1.0",
|
|
58
73
|
"dotenv": "^16.3.1",
|
|
59
74
|
"edge-mock": "^0.0.15",
|
|
60
75
|
"esbuild": "^0.27.0",
|
|
61
76
|
"etcd3": "^1.1.2",
|
|
77
|
+
"express": "^5.2.1",
|
|
78
|
+
"express-session": "^1.19.0",
|
|
62
79
|
"gzip-size-cli": "^5.1.0",
|
|
80
|
+
"hono": "^4.12.10",
|
|
81
|
+
"hono-sessions": "^0.8.1",
|
|
63
82
|
"jest": "^30.2.0",
|
|
64
83
|
"jsdom": "^27.2.0",
|
|
65
84
|
"level": "^8.0.1",
|
|
66
85
|
"localforage": "^1.10.0",
|
|
67
86
|
"pg": "^8.13.1",
|
|
68
87
|
"redis": "^4.6.10",
|
|
88
|
+
"supertest": "^7.2.2",
|
|
69
89
|
"ts-jest": "^29.4.6",
|
|
70
90
|
"ts-node": "^10.9.2",
|
|
71
91
|
"tsup": "^8.5.1",
|
package/readme.md
CHANGED
|
@@ -63,7 +63,7 @@ MyApi({ cache: env.KV_NAMESPACE }); // OR
|
|
|
63
63
|
|
|
64
64
|
First, install `polystore` and whatever [supported client](#clients) that you prefer. Let's see Redis as an example here:
|
|
65
65
|
|
|
66
|
-
```
|
|
66
|
+
```sh
|
|
67
67
|
npm i polystore redis
|
|
68
68
|
```
|
|
69
69
|
|
|
@@ -93,7 +93,7 @@ await store.del(key);
|
|
|
93
93
|
|
|
94
94
|
## API
|
|
95
95
|
|
|
96
|
-
The base `kv()` initialization is shared across clients ([see full clients list](#clients));
|
|
96
|
+
The base `kv()` initialization is shared across clients ([see full clients list](#clients)); an argument that receives the client or a string representing the client and then the options:
|
|
97
97
|
|
|
98
98
|
```js
|
|
99
99
|
import kv from "polystore";
|
|
@@ -107,7 +107,7 @@ const store = kv(MyClientInstance, { expires: null, prefix: "" });
|
|
|
107
107
|
> [!IMPORTANT]
|
|
108
108
|
> The library delivers excellent performance for item-level operations (GET, SET, ADD, HAS, DEL). For other methods or detailed guidance, check the performance considerations and consult your specific client’s documentation.
|
|
109
109
|
|
|
110
|
-
You can enforce **types** for
|
|
110
|
+
You can enforce **types** for the values either at store creation or at the method level:
|
|
111
111
|
|
|
112
112
|
```ts
|
|
113
113
|
const store = kv<number>(new Map());
|
|
@@ -1225,6 +1225,155 @@ This keeps a single table while preserving namespace-style grouping through pref
|
|
|
1225
1225
|
|
|
1226
1226
|
Please see the [creating a store](#creating-a-store) section for all the details!
|
|
1227
1227
|
|
|
1228
|
+
## Integrations
|
|
1229
|
+
|
|
1230
|
+
Polystore has some easy integrations for you to use it as a simple connector.
|
|
1231
|
+
|
|
1232
|
+
### Express
|
|
1233
|
+
|
|
1234
|
+
Use any Polystore-compatible store as an [express-session](https://github.com/expressjs/session) store:
|
|
1235
|
+
|
|
1236
|
+
```js
|
|
1237
|
+
import session from "express-session";
|
|
1238
|
+
import expressStore from "polystore/express";
|
|
1239
|
+
|
|
1240
|
+
app.use(session({
|
|
1241
|
+
secret: "my-secret",
|
|
1242
|
+
store: expressStore(),
|
|
1243
|
+
}));
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
By default it uses an in-memory `Map`, which is fine for development. For production, pass any Polystore client:
|
|
1247
|
+
|
|
1248
|
+
```js
|
|
1249
|
+
import { createClient } from "redis";
|
|
1250
|
+
// `npm install polystore`
|
|
1251
|
+
import expressStore from "polystore/express";
|
|
1252
|
+
|
|
1253
|
+
const store = expressStore(createClient().connect());
|
|
1254
|
+
|
|
1255
|
+
app.use(session({ secret: "my-secret", store }));
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
Any client works — Redis, Postgres, SQLite, file-based, etc. Session TTL is read automatically from `cookie.originalMaxAge` so you don't need to configure it separately.
|
|
1259
|
+
|
|
1260
|
+
Use `.prefix()` to namespace sessions, for example in a multi-tenant app:
|
|
1261
|
+
|
|
1262
|
+
```js
|
|
1263
|
+
const store = expressStore(createClient().connect());
|
|
1264
|
+
|
|
1265
|
+
app.use((req, res, next) => {
|
|
1266
|
+
req.sessionStore = store.prefix(`tenant:${req.params.tenant}:`);
|
|
1267
|
+
next();
|
|
1268
|
+
});
|
|
1269
|
+
```
|
|
1270
|
+
|
|
1271
|
+
### Hono Sessions
|
|
1272
|
+
|
|
1273
|
+
Use any Polystore-compatible store as a [hono-sessions](https://github.com/jcs224/hono_sessions) store:
|
|
1274
|
+
|
|
1275
|
+
```js
|
|
1276
|
+
import { Hono } from "hono";
|
|
1277
|
+
import { sessionMiddleware } from "hono-sessions";
|
|
1278
|
+
import honoStore from "polystore/hono-sessions";
|
|
1279
|
+
|
|
1280
|
+
const app = new Hono();
|
|
1281
|
+
|
|
1282
|
+
app.use("*", sessionMiddleware({
|
|
1283
|
+
store: honoStore(),
|
|
1284
|
+
encryptionKey: process.env.SESSION_KEY,
|
|
1285
|
+
expireAfterSeconds: 3600,
|
|
1286
|
+
}));
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
By default it uses an in-memory `Map`. For production, pass any Polystore client:
|
|
1290
|
+
|
|
1291
|
+
```js
|
|
1292
|
+
import { createClient } from "redis";
|
|
1293
|
+
import honoStore from "polystore/hono-sessions";
|
|
1294
|
+
|
|
1295
|
+
app.use("*", sessionMiddleware({
|
|
1296
|
+
store: honoStore(createClient().connect()),
|
|
1297
|
+
encryptionKey: process.env.SESSION_KEY,
|
|
1298
|
+
expireAfterSeconds: 3600,
|
|
1299
|
+
}));
|
|
1300
|
+
```
|
|
1301
|
+
|
|
1302
|
+
Session TTL is derived automatically from `expireAfterSeconds` — hono-sessions writes it to `_expire` on the session data, and Polystore uses it to set the underlying store TTL for automatic cleanup.
|
|
1303
|
+
|
|
1304
|
+
Use `.prefix()` to namespace sessions per tenant:
|
|
1305
|
+
|
|
1306
|
+
```js
|
|
1307
|
+
const store = honoStore(createClient().connect());
|
|
1308
|
+
|
|
1309
|
+
app.use("*", (c, next) => {
|
|
1310
|
+
const tenant = c.req.param("tenant");
|
|
1311
|
+
return sessionMiddleware({
|
|
1312
|
+
store: store.prefix(`tenant:${tenant}:`),
|
|
1313
|
+
encryptionKey: process.env.SESSION_KEY,
|
|
1314
|
+
})(c, next);
|
|
1315
|
+
});
|
|
1316
|
+
```
|
|
1317
|
+
|
|
1318
|
+
|
|
1319
|
+
### fch
|
|
1320
|
+
|
|
1321
|
+
[Fch](https://www.npmjs.com/package/fch) is a lightweight fetch wrapper that uses Polystore natively for caching. Pass any Polystore store as the `cache` option and GET responses are cached automatically:
|
|
1322
|
+
|
|
1323
|
+
```js
|
|
1324
|
+
import fch from "fch";
|
|
1325
|
+
import kv from "polystore";
|
|
1326
|
+
|
|
1327
|
+
const api = fch.create({
|
|
1328
|
+
baseUrl: "https://api.example.com",
|
|
1329
|
+
cache: kv(new Map(), { expires: "1h" }),
|
|
1330
|
+
});
|
|
1331
|
+
|
|
1332
|
+
await api.get("/users"); // fetched from network, stored in cache
|
|
1333
|
+
await api.get("/users"); // served from cache
|
|
1334
|
+
```
|
|
1335
|
+
|
|
1336
|
+
Swap the backend without changing anything else:
|
|
1337
|
+
|
|
1338
|
+
```js
|
|
1339
|
+
import { createClient } from "redis";
|
|
1340
|
+
|
|
1341
|
+
const api = fch.create({
|
|
1342
|
+
cache: kv(createClient().connect(), { expires: "10min" }),
|
|
1343
|
+
});
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
You can override or skip the cache per request:
|
|
1347
|
+
|
|
1348
|
+
```js
|
|
1349
|
+
const shortCache = kv(new Map(), { expires: "30s" });
|
|
1350
|
+
|
|
1351
|
+
api.get("/realtime", { cache: null }); // skip cache
|
|
1352
|
+
api.get("/prices", { cache: shortCache }); // use a different cache
|
|
1353
|
+
```
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
### @server/next
|
|
1357
|
+
|
|
1358
|
+
> [!WARNING]
|
|
1359
|
+
> @server/next is still experimental, but it's the main reason I created Polystore and so I wanted to document it as well
|
|
1360
|
+
|
|
1361
|
+
Server.js supports Polystore directly:
|
|
1362
|
+
|
|
1363
|
+
```ts
|
|
1364
|
+
import kv from "polystore";
|
|
1365
|
+
import server from "@server/next";
|
|
1366
|
+
|
|
1367
|
+
const session = kv(new Map());
|
|
1368
|
+
|
|
1369
|
+
export default server({ session }).get("/", (ctx) => {
|
|
1370
|
+
if (!ctx.session.counter) ctx.session.counter = 0;
|
|
1371
|
+
ctx.session.counter++;
|
|
1372
|
+
return `User visited ${ctx.session.counter} times`;
|
|
1373
|
+
});
|
|
1374
|
+
```
|
|
1375
|
+
|
|
1376
|
+
|
|
1228
1377
|
## Guides
|
|
1229
1378
|
|
|
1230
1379
|
### Performance
|
|
@@ -1610,23 +1759,3 @@ if (process.env.REDIS_URL) {
|
|
|
1610
1759
|
|
|
1611
1760
|
export default store;
|
|
1612
1761
|
```
|
|
1613
|
-
|
|
1614
|
-
### @server/next
|
|
1615
|
-
|
|
1616
|
-
> [!info]
|
|
1617
|
-
> @server/next is still experimental, but it's the main reason I created Polystore and so I wanted to document it as well
|
|
1618
|
-
|
|
1619
|
-
Server.js supports Polystore directly:
|
|
1620
|
-
|
|
1621
|
-
```ts
|
|
1622
|
-
import kv from "polystore";
|
|
1623
|
-
import server from "../../";
|
|
1624
|
-
|
|
1625
|
-
const session = kv(new Map());
|
|
1626
|
-
|
|
1627
|
-
export default server({ session }).get("/", (ctx) => {
|
|
1628
|
-
if (!ctx.session.counter) ctx.session.counter = 0;
|
|
1629
|
-
ctx.session.counter++;
|
|
1630
|
-
return `User visited ${ctx.session.counter} times`;
|
|
1631
|
-
});
|
|
1632
|
-
```
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
|
|
3
|
+
type Prefix = string;
|
|
4
|
+
type Expires = number | null | string;
|
|
5
|
+
type Options = {
|
|
6
|
+
prefix?: Prefix;
|
|
7
|
+
expires?: Expires;
|
|
8
|
+
};
|
|
9
|
+
type StoreData<T extends Serializable = Serializable> = {
|
|
10
|
+
value: T;
|
|
11
|
+
expires: number | null;
|
|
12
|
+
};
|
|
13
|
+
type Serializable = string | number | boolean | null | (Serializable | null)[] | {
|
|
14
|
+
[key: string]: Serializable | null;
|
|
15
|
+
};
|
|
16
|
+
interface ClientExpires {
|
|
17
|
+
TYPE: string;
|
|
18
|
+
HAS_EXPIRATION: true;
|
|
19
|
+
promise?: Promise<any>;
|
|
20
|
+
test?: (client: any) => boolean;
|
|
21
|
+
get<T extends Serializable>(key: string): Promise<T | null> | T | null;
|
|
22
|
+
set<T extends Serializable>(key: string, value: T, expires?: Expires): Promise<any> | any;
|
|
23
|
+
iterate<T extends Serializable>(prefix: string): AsyncGenerator<[string, T], void, unknown> | Generator<[string, T], void, unknown>;
|
|
24
|
+
add?<T extends Serializable>(prefix: string, value: T, expires?: Expires): Promise<string>;
|
|
25
|
+
has?(key: string): Promise<boolean> | boolean;
|
|
26
|
+
del?(key: string): Promise<any> | any;
|
|
27
|
+
keys?(prefix: string): Promise<string[]> | string[];
|
|
28
|
+
values?<T extends Serializable>(prefix: string): Promise<T[]> | T[];
|
|
29
|
+
entries?<T extends Serializable>(prefix: string): Promise<[string, T][]> | [string, T][];
|
|
30
|
+
all?<T extends Serializable>(prefix: string): Promise<Record<string, T>> | Record<string, T>;
|
|
31
|
+
clear?(prefix: string): Promise<any> | any;
|
|
32
|
+
clearAll?(): Promise<any> | any;
|
|
33
|
+
close?(): Promise<any> | any;
|
|
34
|
+
}
|
|
35
|
+
interface ClientNonExpires {
|
|
36
|
+
TYPE: string;
|
|
37
|
+
HAS_EXPIRATION: false;
|
|
38
|
+
promise?: Promise<any>;
|
|
39
|
+
test?: (client: any) => boolean;
|
|
40
|
+
get<T extends Serializable>(key: string): Promise<StoreData<T> | null> | StoreData<T> | null;
|
|
41
|
+
set<T extends Serializable>(key: string, value: StoreData<T> | null, ttl?: Expires): Promise<any> | any;
|
|
42
|
+
iterate<T extends Serializable>(prefix: string): AsyncGenerator<[string, StoreData<T>], void, unknown> | Generator<[string, StoreData<T>], void, unknown>;
|
|
43
|
+
add?<T extends Serializable>(prefix: string, value: StoreData<T>, ttl?: Expires): Promise<string>;
|
|
44
|
+
has?(key: string): Promise<boolean> | boolean;
|
|
45
|
+
del?(key: string): Promise<any> | any;
|
|
46
|
+
keys?(prefix: string): Promise<string[]> | string[];
|
|
47
|
+
values?<T extends Serializable>(prefix: string): Promise<StoreData<T>[]> | StoreData<T>[];
|
|
48
|
+
entries?<T extends Serializable>(prefix: string): Promise<[string, StoreData<T>][]> | [string, StoreData<T>][];
|
|
49
|
+
all?<T extends Serializable>(prefix: string): Promise<Record<string, StoreData<T>>> | Record<string, StoreData<T>>;
|
|
50
|
+
prune?(): Promise<any> | any;
|
|
51
|
+
clear?(prefix: string): Promise<any> | any;
|
|
52
|
+
clearAll?(): Promise<any> | any;
|
|
53
|
+
close?(): Promise<any> | any;
|
|
54
|
+
}
|
|
55
|
+
type Client = ClientExpires | ClientNonExpires;
|
|
56
|
+
|
|
57
|
+
declare class Store<TD extends Serializable = Serializable> {
|
|
58
|
+
#private;
|
|
59
|
+
PREFIX: Prefix;
|
|
60
|
+
EXPIRES: Expires;
|
|
61
|
+
promise: Promise<Client> | null;
|
|
62
|
+
client: Client;
|
|
63
|
+
type: string;
|
|
64
|
+
constructor(clientPromise?: any, options?: Options);
|
|
65
|
+
/**
|
|
66
|
+
* Save the data on an autogenerated key, can add expiration as well:
|
|
67
|
+
*
|
|
68
|
+
* ```js
|
|
69
|
+
* const key1 = await store.add("value1");
|
|
70
|
+
* const key2 = await store.add({ hello: "world" });
|
|
71
|
+
* const key3 = await store.add("value3", { expires: "1h" });
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* **[→ Full .add() Docs](https://polystore.dev/documentation#add)**
|
|
75
|
+
*/
|
|
76
|
+
add(value: TD, options?: Options): Promise<string>;
|
|
77
|
+
add<T extends TD>(value: T, options?: Options): Promise<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Save the data on the given key, can add expiration as well:
|
|
80
|
+
*
|
|
81
|
+
* ```js
|
|
82
|
+
* const key = await store.set("key1", "value1");
|
|
83
|
+
* await store.set("key2", { hello: "world" });
|
|
84
|
+
* await store.set("key3", "value3", { expires: "1h" });
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* **[→ Full .set() Docs](https://polystore.dev/documentation#set)**
|
|
88
|
+
*/
|
|
89
|
+
set(key: string, value: TD, options?: Options): Promise<string>;
|
|
90
|
+
set<T extends TD>(key: string, value: T, options?: Options): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Read a single value from the KV store:
|
|
93
|
+
*
|
|
94
|
+
* ```js
|
|
95
|
+
* const value1 = await store.get("key1");
|
|
96
|
+
* // null (doesn't exist or has expired)
|
|
97
|
+
* const value2 = await store.get("key2");
|
|
98
|
+
* // "value2"
|
|
99
|
+
* const value3 = await store.get("key3");
|
|
100
|
+
* // { hello: "world" }
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* **[→ Full .get() Docs](https://polystore.dev/documentation#get)**
|
|
104
|
+
*/
|
|
105
|
+
get(key: string): Promise<TD | null>;
|
|
106
|
+
get<T extends TD>(key: string): Promise<T | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Check whether a key exists or not:
|
|
109
|
+
*
|
|
110
|
+
* ```js
|
|
111
|
+
* if (await store.has("key1")) { ... }
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* If you are going to use the value, it's better to just read it:
|
|
115
|
+
*
|
|
116
|
+
* ```js
|
|
117
|
+
* const val = await store.get("key1");
|
|
118
|
+
* if (val) { ... }
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* **[→ Full .has() Docs](https://polystore.dev/documentation#has)**
|
|
122
|
+
*/
|
|
123
|
+
has(key: string): Promise<boolean>;
|
|
124
|
+
/**
|
|
125
|
+
* Remove a single key and its value from the store:
|
|
126
|
+
*
|
|
127
|
+
* ```js
|
|
128
|
+
* const key = await store.del("key1");
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
132
|
+
*/
|
|
133
|
+
del(key: string): Promise<string>;
|
|
134
|
+
/**
|
|
135
|
+
* @alias of .del(key: string)
|
|
136
|
+
* Remove a single key and its value from the store:
|
|
137
|
+
*
|
|
138
|
+
* ```js
|
|
139
|
+
* const key = await store.delete("key1");
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
143
|
+
*/
|
|
144
|
+
delete(key: string): Promise<string>;
|
|
145
|
+
/**
|
|
146
|
+
* An iterator that goes through all of the key:value pairs in the client
|
|
147
|
+
*
|
|
148
|
+
* ```js
|
|
149
|
+
* for await (const [key, value] of store) {
|
|
150
|
+
* console.log(key, value);
|
|
151
|
+
* }
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* **[→ Full Iterator Docs](https://polystore.dev/documentation#iterator)**
|
|
155
|
+
*/
|
|
156
|
+
[Symbol.asyncIterator](): AsyncGenerator<[string, TD], void, unknown>;
|
|
157
|
+
[Symbol.asyncIterator]<T extends TD>(): AsyncGenerator<[
|
|
158
|
+
string,
|
|
159
|
+
T
|
|
160
|
+
], void, unknown>;
|
|
161
|
+
/**
|
|
162
|
+
* Return an array of the entries, in the [key, value] format:
|
|
163
|
+
*
|
|
164
|
+
* ```js
|
|
165
|
+
* const entries = await store.entries();
|
|
166
|
+
* // [["key1", "value1"], ["key2", { hello: "world" }], ...]
|
|
167
|
+
*
|
|
168
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
169
|
+
* const sessions = await store.prefix("session:").entries();
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* **[→ Full .entries() Docs](https://polystore.dev/documentation#entries)**
|
|
173
|
+
*/
|
|
174
|
+
entries(): Promise<[string, TD][]>;
|
|
175
|
+
entries<T extends TD>(): Promise<[string, T][]>;
|
|
176
|
+
/**
|
|
177
|
+
* Return an array of the keys in the store:
|
|
178
|
+
*
|
|
179
|
+
* ```js
|
|
180
|
+
* const keys = await store.keys();
|
|
181
|
+
* // ["key1", "key2", ...]
|
|
182
|
+
*
|
|
183
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
184
|
+
* const sessions = await store.prefix("session:").keys();
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* **[→ Full .keys() Docs](https://polystore.dev/documentation#keys)**
|
|
188
|
+
*/
|
|
189
|
+
keys(): Promise<string[]>;
|
|
190
|
+
/**
|
|
191
|
+
* Return an array of the values in the store:
|
|
192
|
+
*
|
|
193
|
+
* ```js
|
|
194
|
+
* const values = await store.values();
|
|
195
|
+
* // ["value1", { hello: "world" }, ...]
|
|
196
|
+
*
|
|
197
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
198
|
+
* const sessions = await store.prefix("session:").values();
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* **[→ Full .values() Docs](https://polystore.dev/documentation#values)**
|
|
202
|
+
*/
|
|
203
|
+
values(): Promise<TD[]>;
|
|
204
|
+
values<T extends TD>(): Promise<T[]>;
|
|
205
|
+
/**
|
|
206
|
+
* Return an object with the keys:values in the store:
|
|
207
|
+
*
|
|
208
|
+
* ```js
|
|
209
|
+
* const obj = await store.all();
|
|
210
|
+
* // { key1: "value1", key2: { hello: "world" }, ... }
|
|
211
|
+
*
|
|
212
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
213
|
+
* const sessions = await store.prefix("session:").all();
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* **[→ Full .all() Docs](https://polystore.dev/documentation#all)**
|
|
217
|
+
*/
|
|
218
|
+
all(): Promise<Record<string, TD>>;
|
|
219
|
+
all<T extends TD>(): Promise<Record<string, T>>;
|
|
220
|
+
/**
|
|
221
|
+
* Create a substore where all the keys are stored with
|
|
222
|
+
* the given prefix:
|
|
223
|
+
*
|
|
224
|
+
* ```js
|
|
225
|
+
* const session = store.prefix("session:");
|
|
226
|
+
* await session.set("key1", "value1");
|
|
227
|
+
* console.log(await session.entries()); // session.
|
|
228
|
+
* // [["key1", "value1"]]
|
|
229
|
+
* console.log(await store.entries()); // store.
|
|
230
|
+
* // [["session:key1", "value1"]]
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* **[→ Full .prefix() Docs](https://polystore.dev/documentation#prefix)**
|
|
234
|
+
*/
|
|
235
|
+
prefix(prefix?: Prefix): Store<TD>;
|
|
236
|
+
/**
|
|
237
|
+
* Create a substore where all the keys are stored with
|
|
238
|
+
* the given prefix:
|
|
239
|
+
*
|
|
240
|
+
* ```js
|
|
241
|
+
* const session = store.prefix("session:");
|
|
242
|
+
* await session.set("key1", "value1");
|
|
243
|
+
* console.log(await session.entries()); // session.
|
|
244
|
+
* // [["key1", "value1"]]
|
|
245
|
+
* console.log(await store.entries()); // store.
|
|
246
|
+
* // [["session:key1", "value1"]]
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* **[→ Full .prefix() Docs](https://polystore.dev/documentation#prefix)**
|
|
250
|
+
*/
|
|
251
|
+
expires(expires?: Expires): Store<TD>;
|
|
252
|
+
/**
|
|
253
|
+
* Delete all of the records of the store:
|
|
254
|
+
*
|
|
255
|
+
* ```js
|
|
256
|
+
* await store.clear();
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* It's useful for cache invalidation, clearing the data, and testing.
|
|
260
|
+
*
|
|
261
|
+
* **[→ Full .clear() Docs](https://polystore.dev/documentation#clear)**
|
|
262
|
+
*/
|
|
263
|
+
clear(): Promise<void>;
|
|
264
|
+
/**
|
|
265
|
+
* Remove all expired records from the store.
|
|
266
|
+
*
|
|
267
|
+
* ```js
|
|
268
|
+
* await store.prune();
|
|
269
|
+
* ```
|
|
270
|
+
*
|
|
271
|
+
* Only affects stores where expiration is managed by this wrapper.
|
|
272
|
+
*/
|
|
273
|
+
prune(): Promise<void>;
|
|
274
|
+
/**
|
|
275
|
+
* Stop the connection to the store, if any:
|
|
276
|
+
*
|
|
277
|
+
* ```js
|
|
278
|
+
* await session.set("key1", "value1");
|
|
279
|
+
* await store.close();
|
|
280
|
+
* await session.set("key2", "value2"); // error
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* **[→ Full .close() Docs](https://polystore.dev/documentation#close)**
|
|
284
|
+
*/
|
|
285
|
+
close(): Promise<void>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
interface SessionData {
|
|
289
|
+
cookie?: {
|
|
290
|
+
originalMaxAge?: number | null;
|
|
291
|
+
[key: string]: any;
|
|
292
|
+
};
|
|
293
|
+
[key: string]: any;
|
|
294
|
+
}
|
|
295
|
+
type Callback = (err?: any) => void;
|
|
296
|
+
declare class PolystoreSessionStore extends EventEmitter {
|
|
297
|
+
private store;
|
|
298
|
+
constructor(store: Store);
|
|
299
|
+
prefix(prefix?: string): PolystoreSessionStore;
|
|
300
|
+
get(sid: string, cb: (err: any, session?: SessionData | null) => void): void;
|
|
301
|
+
set(sid: string, data: SessionData, cb?: Callback): void;
|
|
302
|
+
destroy(sid: string, cb?: Callback): void;
|
|
303
|
+
touch(sid: string, data: SessionData, cb?: Callback): void;
|
|
304
|
+
}
|
|
305
|
+
declare function expressStore(client?: Map<any, any>): PolystoreSessionStore;
|
|
306
|
+
|
|
307
|
+
export { PolystoreSessionStore, expressStore as default };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/integrations/express.ts
|
|
2
|
+
import session from "express-session";
|
|
3
|
+
import kv from "polystore";
|
|
4
|
+
var ttlFromSession = (data) => {
|
|
5
|
+
const maxAge = data?.cookie?.originalMaxAge;
|
|
6
|
+
return typeof maxAge === "number" ? { expires: Math.ceil(maxAge / 1e3) } : void 0;
|
|
7
|
+
};
|
|
8
|
+
var PolystoreSessionStore = class _PolystoreSessionStore extends session.Store {
|
|
9
|
+
store;
|
|
10
|
+
constructor(store) {
|
|
11
|
+
super();
|
|
12
|
+
this.store = store;
|
|
13
|
+
}
|
|
14
|
+
prefix(prefix = "") {
|
|
15
|
+
return new _PolystoreSessionStore(this.store.prefix(prefix));
|
|
16
|
+
}
|
|
17
|
+
get(sid, cb) {
|
|
18
|
+
this.store.get(sid).then((data) => cb(null, data)).catch((err) => err?.code === "ENOENT" ? cb(null, null) : cb(err));
|
|
19
|
+
}
|
|
20
|
+
set(sid, data, cb) {
|
|
21
|
+
this.store.set(sid, data, ttlFromSession(data)).then(() => cb?.()).catch((err) => cb?.(err));
|
|
22
|
+
}
|
|
23
|
+
destroy(sid, cb) {
|
|
24
|
+
this.store.del(sid).then(() => cb?.()).catch((err) => cb?.(err));
|
|
25
|
+
}
|
|
26
|
+
touch(sid, data, cb) {
|
|
27
|
+
this.store.set(sid, data, ttlFromSession(data)).then(() => cb?.()).catch((err) => cb?.(err));
|
|
28
|
+
}
|
|
29
|
+
all(cb) {
|
|
30
|
+
this.store.values().then((vals) => cb(null, vals)).catch(cb);
|
|
31
|
+
}
|
|
32
|
+
clear(cb) {
|
|
33
|
+
this.store.clear().then(() => cb?.()).catch((err) => cb?.(err));
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
function expressStore(client = /* @__PURE__ */ new Map()) {
|
|
37
|
+
return new PolystoreSessionStore(kv(client));
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
PolystoreSessionStore,
|
|
41
|
+
expressStore as default
|
|
42
|
+
};
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { Store as Store$1, SessionData } from 'hono-sessions';
|
|
2
|
+
|
|
3
|
+
type Prefix = string;
|
|
4
|
+
type Expires = number | null | string;
|
|
5
|
+
type Options = {
|
|
6
|
+
prefix?: Prefix;
|
|
7
|
+
expires?: Expires;
|
|
8
|
+
};
|
|
9
|
+
type StoreData<T extends Serializable = Serializable> = {
|
|
10
|
+
value: T;
|
|
11
|
+
expires: number | null;
|
|
12
|
+
};
|
|
13
|
+
type Serializable = string | number | boolean | null | (Serializable | null)[] | {
|
|
14
|
+
[key: string]: Serializable | null;
|
|
15
|
+
};
|
|
16
|
+
interface ClientExpires {
|
|
17
|
+
TYPE: string;
|
|
18
|
+
HAS_EXPIRATION: true;
|
|
19
|
+
promise?: Promise<any>;
|
|
20
|
+
test?: (client: any) => boolean;
|
|
21
|
+
get<T extends Serializable>(key: string): Promise<T | null> | T | null;
|
|
22
|
+
set<T extends Serializable>(key: string, value: T, expires?: Expires): Promise<any> | any;
|
|
23
|
+
iterate<T extends Serializable>(prefix: string): AsyncGenerator<[string, T], void, unknown> | Generator<[string, T], void, unknown>;
|
|
24
|
+
add?<T extends Serializable>(prefix: string, value: T, expires?: Expires): Promise<string>;
|
|
25
|
+
has?(key: string): Promise<boolean> | boolean;
|
|
26
|
+
del?(key: string): Promise<any> | any;
|
|
27
|
+
keys?(prefix: string): Promise<string[]> | string[];
|
|
28
|
+
values?<T extends Serializable>(prefix: string): Promise<T[]> | T[];
|
|
29
|
+
entries?<T extends Serializable>(prefix: string): Promise<[string, T][]> | [string, T][];
|
|
30
|
+
all?<T extends Serializable>(prefix: string): Promise<Record<string, T>> | Record<string, T>;
|
|
31
|
+
clear?(prefix: string): Promise<any> | any;
|
|
32
|
+
clearAll?(): Promise<any> | any;
|
|
33
|
+
close?(): Promise<any> | any;
|
|
34
|
+
}
|
|
35
|
+
interface ClientNonExpires {
|
|
36
|
+
TYPE: string;
|
|
37
|
+
HAS_EXPIRATION: false;
|
|
38
|
+
promise?: Promise<any>;
|
|
39
|
+
test?: (client: any) => boolean;
|
|
40
|
+
get<T extends Serializable>(key: string): Promise<StoreData<T> | null> | StoreData<T> | null;
|
|
41
|
+
set<T extends Serializable>(key: string, value: StoreData<T> | null, ttl?: Expires): Promise<any> | any;
|
|
42
|
+
iterate<T extends Serializable>(prefix: string): AsyncGenerator<[string, StoreData<T>], void, unknown> | Generator<[string, StoreData<T>], void, unknown>;
|
|
43
|
+
add?<T extends Serializable>(prefix: string, value: StoreData<T>, ttl?: Expires): Promise<string>;
|
|
44
|
+
has?(key: string): Promise<boolean> | boolean;
|
|
45
|
+
del?(key: string): Promise<any> | any;
|
|
46
|
+
keys?(prefix: string): Promise<string[]> | string[];
|
|
47
|
+
values?<T extends Serializable>(prefix: string): Promise<StoreData<T>[]> | StoreData<T>[];
|
|
48
|
+
entries?<T extends Serializable>(prefix: string): Promise<[string, StoreData<T>][]> | [string, StoreData<T>][];
|
|
49
|
+
all?<T extends Serializable>(prefix: string): Promise<Record<string, StoreData<T>>> | Record<string, StoreData<T>>;
|
|
50
|
+
prune?(): Promise<any> | any;
|
|
51
|
+
clear?(prefix: string): Promise<any> | any;
|
|
52
|
+
clearAll?(): Promise<any> | any;
|
|
53
|
+
close?(): Promise<any> | any;
|
|
54
|
+
}
|
|
55
|
+
type Client = ClientExpires | ClientNonExpires;
|
|
56
|
+
|
|
57
|
+
declare class Store<TD extends Serializable = Serializable> {
|
|
58
|
+
#private;
|
|
59
|
+
PREFIX: Prefix;
|
|
60
|
+
EXPIRES: Expires;
|
|
61
|
+
promise: Promise<Client> | null;
|
|
62
|
+
client: Client;
|
|
63
|
+
type: string;
|
|
64
|
+
constructor(clientPromise?: any, options?: Options);
|
|
65
|
+
/**
|
|
66
|
+
* Save the data on an autogenerated key, can add expiration as well:
|
|
67
|
+
*
|
|
68
|
+
* ```js
|
|
69
|
+
* const key1 = await store.add("value1");
|
|
70
|
+
* const key2 = await store.add({ hello: "world" });
|
|
71
|
+
* const key3 = await store.add("value3", { expires: "1h" });
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* **[→ Full .add() Docs](https://polystore.dev/documentation#add)**
|
|
75
|
+
*/
|
|
76
|
+
add(value: TD, options?: Options): Promise<string>;
|
|
77
|
+
add<T extends TD>(value: T, options?: Options): Promise<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Save the data on the given key, can add expiration as well:
|
|
80
|
+
*
|
|
81
|
+
* ```js
|
|
82
|
+
* const key = await store.set("key1", "value1");
|
|
83
|
+
* await store.set("key2", { hello: "world" });
|
|
84
|
+
* await store.set("key3", "value3", { expires: "1h" });
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* **[→ Full .set() Docs](https://polystore.dev/documentation#set)**
|
|
88
|
+
*/
|
|
89
|
+
set(key: string, value: TD, options?: Options): Promise<string>;
|
|
90
|
+
set<T extends TD>(key: string, value: T, options?: Options): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Read a single value from the KV store:
|
|
93
|
+
*
|
|
94
|
+
* ```js
|
|
95
|
+
* const value1 = await store.get("key1");
|
|
96
|
+
* // null (doesn't exist or has expired)
|
|
97
|
+
* const value2 = await store.get("key2");
|
|
98
|
+
* // "value2"
|
|
99
|
+
* const value3 = await store.get("key3");
|
|
100
|
+
* // { hello: "world" }
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* **[→ Full .get() Docs](https://polystore.dev/documentation#get)**
|
|
104
|
+
*/
|
|
105
|
+
get(key: string): Promise<TD | null>;
|
|
106
|
+
get<T extends TD>(key: string): Promise<T | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Check whether a key exists or not:
|
|
109
|
+
*
|
|
110
|
+
* ```js
|
|
111
|
+
* if (await store.has("key1")) { ... }
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* If you are going to use the value, it's better to just read it:
|
|
115
|
+
*
|
|
116
|
+
* ```js
|
|
117
|
+
* const val = await store.get("key1");
|
|
118
|
+
* if (val) { ... }
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* **[→ Full .has() Docs](https://polystore.dev/documentation#has)**
|
|
122
|
+
*/
|
|
123
|
+
has(key: string): Promise<boolean>;
|
|
124
|
+
/**
|
|
125
|
+
* Remove a single key and its value from the store:
|
|
126
|
+
*
|
|
127
|
+
* ```js
|
|
128
|
+
* const key = await store.del("key1");
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
132
|
+
*/
|
|
133
|
+
del(key: string): Promise<string>;
|
|
134
|
+
/**
|
|
135
|
+
* @alias of .del(key: string)
|
|
136
|
+
* Remove a single key and its value from the store:
|
|
137
|
+
*
|
|
138
|
+
* ```js
|
|
139
|
+
* const key = await store.delete("key1");
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
143
|
+
*/
|
|
144
|
+
delete(key: string): Promise<string>;
|
|
145
|
+
/**
|
|
146
|
+
* An iterator that goes through all of the key:value pairs in the client
|
|
147
|
+
*
|
|
148
|
+
* ```js
|
|
149
|
+
* for await (const [key, value] of store) {
|
|
150
|
+
* console.log(key, value);
|
|
151
|
+
* }
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* **[→ Full Iterator Docs](https://polystore.dev/documentation#iterator)**
|
|
155
|
+
*/
|
|
156
|
+
[Symbol.asyncIterator](): AsyncGenerator<[string, TD], void, unknown>;
|
|
157
|
+
[Symbol.asyncIterator]<T extends TD>(): AsyncGenerator<[
|
|
158
|
+
string,
|
|
159
|
+
T
|
|
160
|
+
], void, unknown>;
|
|
161
|
+
/**
|
|
162
|
+
* Return an array of the entries, in the [key, value] format:
|
|
163
|
+
*
|
|
164
|
+
* ```js
|
|
165
|
+
* const entries = await store.entries();
|
|
166
|
+
* // [["key1", "value1"], ["key2", { hello: "world" }], ...]
|
|
167
|
+
*
|
|
168
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
169
|
+
* const sessions = await store.prefix("session:").entries();
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* **[→ Full .entries() Docs](https://polystore.dev/documentation#entries)**
|
|
173
|
+
*/
|
|
174
|
+
entries(): Promise<[string, TD][]>;
|
|
175
|
+
entries<T extends TD>(): Promise<[string, T][]>;
|
|
176
|
+
/**
|
|
177
|
+
* Return an array of the keys in the store:
|
|
178
|
+
*
|
|
179
|
+
* ```js
|
|
180
|
+
* const keys = await store.keys();
|
|
181
|
+
* // ["key1", "key2", ...]
|
|
182
|
+
*
|
|
183
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
184
|
+
* const sessions = await store.prefix("session:").keys();
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* **[→ Full .keys() Docs](https://polystore.dev/documentation#keys)**
|
|
188
|
+
*/
|
|
189
|
+
keys(): Promise<string[]>;
|
|
190
|
+
/**
|
|
191
|
+
* Return an array of the values in the store:
|
|
192
|
+
*
|
|
193
|
+
* ```js
|
|
194
|
+
* const values = await store.values();
|
|
195
|
+
* // ["value1", { hello: "world" }, ...]
|
|
196
|
+
*
|
|
197
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
198
|
+
* const sessions = await store.prefix("session:").values();
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* **[→ Full .values() Docs](https://polystore.dev/documentation#values)**
|
|
202
|
+
*/
|
|
203
|
+
values(): Promise<TD[]>;
|
|
204
|
+
values<T extends TD>(): Promise<T[]>;
|
|
205
|
+
/**
|
|
206
|
+
* Return an object with the keys:values in the store:
|
|
207
|
+
*
|
|
208
|
+
* ```js
|
|
209
|
+
* const obj = await store.all();
|
|
210
|
+
* // { key1: "value1", key2: { hello: "world" }, ... }
|
|
211
|
+
*
|
|
212
|
+
* // To limit it to a given prefix, use `.prefix()`:
|
|
213
|
+
* const sessions = await store.prefix("session:").all();
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* **[→ Full .all() Docs](https://polystore.dev/documentation#all)**
|
|
217
|
+
*/
|
|
218
|
+
all(): Promise<Record<string, TD>>;
|
|
219
|
+
all<T extends TD>(): Promise<Record<string, T>>;
|
|
220
|
+
/**
|
|
221
|
+
* Create a substore where all the keys are stored with
|
|
222
|
+
* the given prefix:
|
|
223
|
+
*
|
|
224
|
+
* ```js
|
|
225
|
+
* const session = store.prefix("session:");
|
|
226
|
+
* await session.set("key1", "value1");
|
|
227
|
+
* console.log(await session.entries()); // session.
|
|
228
|
+
* // [["key1", "value1"]]
|
|
229
|
+
* console.log(await store.entries()); // store.
|
|
230
|
+
* // [["session:key1", "value1"]]
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* **[→ Full .prefix() Docs](https://polystore.dev/documentation#prefix)**
|
|
234
|
+
*/
|
|
235
|
+
prefix(prefix?: Prefix): Store<TD>;
|
|
236
|
+
/**
|
|
237
|
+
* Create a substore where all the keys are stored with
|
|
238
|
+
* the given prefix:
|
|
239
|
+
*
|
|
240
|
+
* ```js
|
|
241
|
+
* const session = store.prefix("session:");
|
|
242
|
+
* await session.set("key1", "value1");
|
|
243
|
+
* console.log(await session.entries()); // session.
|
|
244
|
+
* // [["key1", "value1"]]
|
|
245
|
+
* console.log(await store.entries()); // store.
|
|
246
|
+
* // [["session:key1", "value1"]]
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* **[→ Full .prefix() Docs](https://polystore.dev/documentation#prefix)**
|
|
250
|
+
*/
|
|
251
|
+
expires(expires?: Expires): Store<TD>;
|
|
252
|
+
/**
|
|
253
|
+
* Delete all of the records of the store:
|
|
254
|
+
*
|
|
255
|
+
* ```js
|
|
256
|
+
* await store.clear();
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* It's useful for cache invalidation, clearing the data, and testing.
|
|
260
|
+
*
|
|
261
|
+
* **[→ Full .clear() Docs](https://polystore.dev/documentation#clear)**
|
|
262
|
+
*/
|
|
263
|
+
clear(): Promise<void>;
|
|
264
|
+
/**
|
|
265
|
+
* Remove all expired records from the store.
|
|
266
|
+
*
|
|
267
|
+
* ```js
|
|
268
|
+
* await store.prune();
|
|
269
|
+
* ```
|
|
270
|
+
*
|
|
271
|
+
* Only affects stores where expiration is managed by this wrapper.
|
|
272
|
+
*/
|
|
273
|
+
prune(): Promise<void>;
|
|
274
|
+
/**
|
|
275
|
+
* Stop the connection to the store, if any:
|
|
276
|
+
*
|
|
277
|
+
* ```js
|
|
278
|
+
* await session.set("key1", "value1");
|
|
279
|
+
* await store.close();
|
|
280
|
+
* await session.set("key2", "value2"); // error
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* **[→ Full .close() Docs](https://polystore.dev/documentation#close)**
|
|
284
|
+
*/
|
|
285
|
+
close(): Promise<void>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
declare class PolystoreHonoStore implements Store$1 {
|
|
289
|
+
private store;
|
|
290
|
+
constructor(store: Store);
|
|
291
|
+
prefix(prefix?: string): PolystoreHonoStore;
|
|
292
|
+
getSessionById(sessionId?: string): Promise<SessionData | null | undefined>;
|
|
293
|
+
createSession(sessionId: string, initialData: SessionData): Promise<void>;
|
|
294
|
+
persistSessionData(sessionId: string, sessionData: SessionData): Promise<void>;
|
|
295
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
296
|
+
}
|
|
297
|
+
declare function honoStore(client?: Map<any, any>): PolystoreHonoStore;
|
|
298
|
+
|
|
299
|
+
export { PolystoreHonoStore, honoStore as default };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/integrations/hono-sessions.ts
|
|
2
|
+
import kv from "polystore";
|
|
3
|
+
var ttlFromSession = (data) => {
|
|
4
|
+
if (!data._expire) return void 0;
|
|
5
|
+
const secs = Math.ceil((new Date(data._expire).getTime() - Date.now()) / 1e3);
|
|
6
|
+
return secs > 0 ? { expires: secs } : void 0;
|
|
7
|
+
};
|
|
8
|
+
var PolystoreHonoStore = class _PolystoreHonoStore {
|
|
9
|
+
store;
|
|
10
|
+
constructor(store) {
|
|
11
|
+
this.store = store;
|
|
12
|
+
}
|
|
13
|
+
prefix(prefix = "") {
|
|
14
|
+
return new _PolystoreHonoStore(this.store.prefix(prefix));
|
|
15
|
+
}
|
|
16
|
+
async getSessionById(sessionId) {
|
|
17
|
+
if (!sessionId) return null;
|
|
18
|
+
return this.store.get(sessionId);
|
|
19
|
+
}
|
|
20
|
+
async createSession(sessionId, initialData) {
|
|
21
|
+
await this.store.set(sessionId, initialData, ttlFromSession(initialData));
|
|
22
|
+
}
|
|
23
|
+
async persistSessionData(sessionId, sessionData) {
|
|
24
|
+
await this.store.set(sessionId, sessionData, ttlFromSession(sessionData));
|
|
25
|
+
}
|
|
26
|
+
async deleteSession(sessionId) {
|
|
27
|
+
await this.store.del(sessionId);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
function honoStore(client = /* @__PURE__ */ new Map()) {
|
|
31
|
+
return new PolystoreHonoStore(kv(client));
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
PolystoreHonoStore,
|
|
35
|
+
honoStore as default
|
|
36
|
+
};
|
package/src/express.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import session from "express-session";
|
|
2
|
-
import kv from "../index.js";
|
|
3
|
-
|
|
4
|
-
const ttlFromSession = (data) => {
|
|
5
|
-
const maxAge = data?.cookie?.originalMaxAge;
|
|
6
|
-
return typeof maxAge === "number" ? Math.ceil(maxAge / 1000) : null;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export class PolystoreSessionStore extends session.Store {
|
|
10
|
-
constructor(store) {
|
|
11
|
-
super();
|
|
12
|
-
this.store = store;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
prefix(prefix = "") {
|
|
16
|
-
return new PolystoreSessionStore(this.store.prefix(prefix));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
get(sid, cb) {
|
|
20
|
-
this.store.get(sid).then((data) => cb(null, data)).catch(cb);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
set(sid, data, cb) {
|
|
24
|
-
this.store
|
|
25
|
-
.set(sid, data, ttlFromSession(data))
|
|
26
|
-
.then(() => cb && cb())
|
|
27
|
-
.catch((error) => cb && cb(error));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
destroy(sid, cb) {
|
|
31
|
-
this.store
|
|
32
|
-
.del(sid)
|
|
33
|
-
.then(() => cb && cb())
|
|
34
|
-
.catch((error) => cb && cb(error));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
touch(sid, data, cb) {
|
|
38
|
-
this.store
|
|
39
|
-
.set(sid, data, ttlFromSession(data))
|
|
40
|
-
.then(() => cb && cb())
|
|
41
|
-
.catch((error) => cb && cb(error));
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default function expressStore(client = new Map()) {
|
|
46
|
-
return new PolystoreSessionStore(kv(client));
|
|
47
|
-
}
|