@better-auth/redis-storage 1.6.25 → 1.6.27
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/dist/index.d.mts +29 -0
- package/dist/index.mjs +43 -3
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -38,7 +38,36 @@ declare function redisStorage(config: RedisStorageConfig): {
|
|
|
38
38
|
increment(key: string, ttl: number): Promise<number>;
|
|
39
39
|
set(key: string, value: string, ttl?: number | undefined): Promise<void>;
|
|
40
40
|
delete(key: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Lists the keys under the configured prefix, with the prefix stripped.
|
|
43
|
+
*
|
|
44
|
+
* Keys are enumerated with `SCAN`, a best-effort walk: it may report the
|
|
45
|
+
* same key on more than one page, so the result is de-duplicated, and
|
|
46
|
+
* keys added or removed while the scan runs may or may not appear. Order
|
|
47
|
+
* is not guaranteed.
|
|
48
|
+
*/
|
|
41
49
|
listKeys(): Promise<string[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Deletes keys under the configured prefix.
|
|
52
|
+
*
|
|
53
|
+
* **Not atomic.** Keys are enumerated with `SCAN` and deleted page by
|
|
54
|
+
* page, so if Redis errors or the connection drops mid-iteration the
|
|
55
|
+
* returned promise rejects *after* earlier pages have already been
|
|
56
|
+
* deleted, leaving the store partially cleared. A rejection therefore
|
|
57
|
+
* means "an unknown subset of keys may already be gone", not "nothing
|
|
58
|
+
* changed", unlike a single blocking `DEL`, which either removes
|
|
59
|
+
* everything or nothing.
|
|
60
|
+
*
|
|
61
|
+
* **Best-effort while the keyspace changes.** `SCAN` is a best-effort
|
|
62
|
+
* enumeration: keys added or removed while the scan runs may or may not
|
|
63
|
+
* be returned, and a key may be returned more than once. A resolved call
|
|
64
|
+
* is therefore not proof the store is empty when other clients are
|
|
65
|
+
* writing concurrently.
|
|
66
|
+
*
|
|
67
|
+
* `clear()` is safe to call again: it is idempotent, so callers that need
|
|
68
|
+
* a fully empty store (e.g. revoking every session or rate-limit counter)
|
|
69
|
+
* should retry until it resolves. An already-empty store is a no-op.
|
|
70
|
+
*/
|
|
42
71
|
clear(): Promise<void>;
|
|
43
72
|
};
|
|
44
73
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -41,6 +41,16 @@ return value
|
|
|
41
41
|
return `${keyPrefix}${key}`;
|
|
42
42
|
};
|
|
43
43
|
const isUnknownCommandError = (error) => error instanceof Error && error.message.toLowerCase().includes("unknown command");
|
|
44
|
+
const SCAN_COUNT = 100;
|
|
45
|
+
const escapedPrefix = keyPrefix.replace(/[\\*?[\]]/g, "\\$&");
|
|
46
|
+
async function* scanBatches() {
|
|
47
|
+
let cursor = "0";
|
|
48
|
+
do {
|
|
49
|
+
const [nextCursor, batch] = await client.scan(cursor, "MATCH", `${escapedPrefix}*`, "COUNT", SCAN_COUNT);
|
|
50
|
+
cursor = nextCursor;
|
|
51
|
+
if (batch.length > 0) yield batch;
|
|
52
|
+
} while (cursor !== "0");
|
|
53
|
+
}
|
|
44
54
|
return {
|
|
45
55
|
async get(key) {
|
|
46
56
|
return client.get(prefixKey(key));
|
|
@@ -67,12 +77,42 @@ return value
|
|
|
67
77
|
async delete(key) {
|
|
68
78
|
await client.del(prefixKey(key));
|
|
69
79
|
},
|
|
80
|
+
/**
|
|
81
|
+
* Lists the keys under the configured prefix, with the prefix stripped.
|
|
82
|
+
*
|
|
83
|
+
* Keys are enumerated with `SCAN`, a best-effort walk: it may report the
|
|
84
|
+
* same key on more than one page, so the result is de-duplicated, and
|
|
85
|
+
* keys added or removed while the scan runs may or may not appear. Order
|
|
86
|
+
* is not guaranteed.
|
|
87
|
+
*/
|
|
70
88
|
async listKeys() {
|
|
71
|
-
|
|
89
|
+
const keys = /* @__PURE__ */ new Set();
|
|
90
|
+
for await (const batch of scanBatches()) for (const key of batch) keys.add(key.slice(keyPrefix.length));
|
|
91
|
+
return [...keys];
|
|
72
92
|
},
|
|
93
|
+
/**
|
|
94
|
+
* Deletes keys under the configured prefix.
|
|
95
|
+
*
|
|
96
|
+
* **Not atomic.** Keys are enumerated with `SCAN` and deleted page by
|
|
97
|
+
* page, so if Redis errors or the connection drops mid-iteration the
|
|
98
|
+
* returned promise rejects *after* earlier pages have already been
|
|
99
|
+
* deleted, leaving the store partially cleared. A rejection therefore
|
|
100
|
+
* means "an unknown subset of keys may already be gone", not "nothing
|
|
101
|
+
* changed", unlike a single blocking `DEL`, which either removes
|
|
102
|
+
* everything or nothing.
|
|
103
|
+
*
|
|
104
|
+
* **Best-effort while the keyspace changes.** `SCAN` is a best-effort
|
|
105
|
+
* enumeration: keys added or removed while the scan runs may or may not
|
|
106
|
+
* be returned, and a key may be returned more than once. A resolved call
|
|
107
|
+
* is therefore not proof the store is empty when other clients are
|
|
108
|
+
* writing concurrently.
|
|
109
|
+
*
|
|
110
|
+
* `clear()` is safe to call again: it is idempotent, so callers that need
|
|
111
|
+
* a fully empty store (e.g. revoking every session or rate-limit counter)
|
|
112
|
+
* should retry until it resolves. An already-empty store is a no-op.
|
|
113
|
+
*/
|
|
73
114
|
async clear() {
|
|
74
|
-
const
|
|
75
|
-
await client.del(...keys);
|
|
115
|
+
for await (const batch of scanBatches()) await client.del(...batch);
|
|
76
116
|
}
|
|
77
117
|
};
|
|
78
118
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/redis-storage",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.27",
|
|
4
4
|
"description": "Redis storage for Better Auth secondary storage",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"ioredis": "^5.0.0",
|
|
38
|
-
"@better-auth/core": "^1.6.
|
|
38
|
+
"@better-auth/core": "^1.6.27"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^25.3.2",
|
|
42
42
|
"ioredis": "^5.9.3",
|
|
43
43
|
"tsdown": "0.22.7",
|
|
44
44
|
"typescript": "^6.0.3",
|
|
45
|
-
"vitest": "^4.1.
|
|
46
|
-
"@better-auth/core": "1.6.
|
|
45
|
+
"vitest": "^4.1.10",
|
|
46
|
+
"@better-auth/core": "1.6.27"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "tsdown",
|