@frontmcp/utils 1.8.6 → 1.9.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/env/browser-env.d.ts +1 -0
- package/env/browser-env.js +5 -0
- package/env/browser-runtime-context.d.ts +2 -1
- package/env/browser-runtime-context.js +104 -0
- package/env/index.d.ts +1 -1
- package/env/node-env.d.ts +11 -0
- package/env/node-env.js +8 -2
- package/env/runtime-context.d.ts +12 -5
- package/env/runtime-context.js +192 -0
- package/esm/async-context/browser-async-context.mjs +3 -2
- package/esm/async-context/node-async-context.mjs +3 -2
- package/esm/crypto/browser.mjs +3 -2
- package/esm/crypto/node.mjs +3 -2
- package/esm/env/browser-env.mjs +7 -2
- package/esm/env/browser-runtime-context.mjs +77 -0
- package/esm/env/node-env.mjs +10 -4
- package/esm/env/runtime-context.mjs +172 -0
- package/esm/event-emitter/browser-event-emitter.mjs +3 -2
- package/esm/event-emitter/node-event-emitter.mjs +3 -2
- package/esm/index.mjs +251 -250
- package/esm/path/browser-path.mjs +50 -0
- package/esm/path/node-path.mjs +16 -0
- package/index.d.ts +3 -3
- package/index.js +261 -274
- package/package.json +26 -8
- package/path/browser-path.js +79 -0
- package/path/node-path.js +45 -0
- package/storage/adapters/base.d.ts +6 -1
- package/storage/adapters/cloudflare-kv.d.ts +1 -0
- package/storage/adapters/index.d.ts +2 -1
- package/storage/adapters/memory.d.ts +2 -1
- package/storage/adapters/redis.d.ts +19 -0
- package/storage/adapters/upstash.d.ts +2 -1
- package/storage/adapters/vercel-kv.d.ts +2 -1
- package/storage/index.d.ts +4 -2
- package/storage/namespace.d.ts +2 -1
- package/storage/redis-error-listener.d.ts +27 -0
- package/storage/types.d.ts +11 -0
- package/storage/utils/compare-and-delete.d.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Shared utility functions for FrontMCP - string manipulation, URI handling, path utilities, and more",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@noble/hashes": "^2.0.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@frontmcp/lazy-zod": "1.
|
|
35
|
+
"@frontmcp/lazy-zod": "1.9.0",
|
|
36
36
|
"@vercel/kv": "^2.0.0 || ^3.0.0",
|
|
37
37
|
"ioredis": "^5.0.0"
|
|
38
38
|
},
|
|
@@ -47,32 +47,50 @@
|
|
|
47
47
|
"imports": {
|
|
48
48
|
"#crypto-provider": {
|
|
49
49
|
"worker": "./crypto/node.js",
|
|
50
|
-
"browser":
|
|
50
|
+
"browser": {
|
|
51
|
+
"import": "./esm/crypto/browser.mjs",
|
|
52
|
+
"default": "./crypto/browser.js"
|
|
53
|
+
},
|
|
51
54
|
"default": "./crypto/node.js"
|
|
52
55
|
},
|
|
53
56
|
"#async-context": {
|
|
54
57
|
"worker": "./async-context/node-async-context.js",
|
|
55
|
-
"browser":
|
|
58
|
+
"browser": {
|
|
59
|
+
"import": "./esm/async-context/browser-async-context.mjs",
|
|
60
|
+
"default": "./async-context/browser-async-context.js"
|
|
61
|
+
},
|
|
56
62
|
"default": "./async-context/node-async-context.js"
|
|
57
63
|
},
|
|
58
64
|
"#event-emitter": {
|
|
59
65
|
"worker": "./event-emitter/node-event-emitter.js",
|
|
60
|
-
"browser":
|
|
66
|
+
"browser": {
|
|
67
|
+
"import": "./esm/event-emitter/browser-event-emitter.mjs",
|
|
68
|
+
"default": "./event-emitter/browser-event-emitter.js"
|
|
69
|
+
},
|
|
61
70
|
"default": "./event-emitter/node-event-emitter.js"
|
|
62
71
|
},
|
|
63
72
|
"#env": {
|
|
64
73
|
"worker": "./env/node-env.js",
|
|
65
|
-
"browser":
|
|
74
|
+
"browser": {
|
|
75
|
+
"import": "./esm/env/browser-env.mjs",
|
|
76
|
+
"default": "./env/browser-env.js"
|
|
77
|
+
},
|
|
66
78
|
"default": "./env/node-env.js"
|
|
67
79
|
},
|
|
68
80
|
"#runtime-context": {
|
|
69
81
|
"worker": "./env/runtime-context.js",
|
|
70
|
-
"browser":
|
|
82
|
+
"browser": {
|
|
83
|
+
"import": "./esm/env/browser-runtime-context.mjs",
|
|
84
|
+
"default": "./env/browser-runtime-context.js"
|
|
85
|
+
},
|
|
71
86
|
"default": "./env/runtime-context.js"
|
|
72
87
|
},
|
|
73
88
|
"#path": {
|
|
74
89
|
"worker": "./path/node-path.js",
|
|
75
|
-
"browser":
|
|
90
|
+
"browser": {
|
|
91
|
+
"import": "./esm/path/browser-path.mjs",
|
|
92
|
+
"default": "./path/browser-path.js"
|
|
93
|
+
},
|
|
76
94
|
"default": "./path/node-path.js"
|
|
77
95
|
}
|
|
78
96
|
},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// libs/utils/src/path/browser-path.ts
|
|
21
|
+
var browser_path_exports = {};
|
|
22
|
+
__export(browser_path_exports, {
|
|
23
|
+
basename: () => basename,
|
|
24
|
+
dirname: () => dirname,
|
|
25
|
+
extname: () => extname,
|
|
26
|
+
isAbsolute: () => isAbsolute,
|
|
27
|
+
join: () => join,
|
|
28
|
+
pathToFileURL: () => pathToFileURL,
|
|
29
|
+
resolve: () => resolve,
|
|
30
|
+
sep: () => sep
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(browser_path_exports);
|
|
33
|
+
function notAvailable(name) {
|
|
34
|
+
throw new Error(`path.${name}() is not available in browser environments`);
|
|
35
|
+
}
|
|
36
|
+
function resolve(..._segments) {
|
|
37
|
+
return notAvailable("resolve");
|
|
38
|
+
}
|
|
39
|
+
function join(..._segments) {
|
|
40
|
+
return notAvailable("join");
|
|
41
|
+
}
|
|
42
|
+
function basename(p, ext) {
|
|
43
|
+
const trimmed = p.replace(/[/\\]+$/, "");
|
|
44
|
+
const lastSep = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
45
|
+
let base = lastSep >= 0 ? trimmed.slice(lastSep + 1) : trimmed;
|
|
46
|
+
if (ext && base.endsWith(ext)) {
|
|
47
|
+
base = base.slice(0, -ext.length);
|
|
48
|
+
}
|
|
49
|
+
return base;
|
|
50
|
+
}
|
|
51
|
+
function dirname(_p) {
|
|
52
|
+
return notAvailable("dirname");
|
|
53
|
+
}
|
|
54
|
+
function extname(p) {
|
|
55
|
+
const base = basename(p);
|
|
56
|
+
const dotIndex = base.lastIndexOf(".");
|
|
57
|
+
return dotIndex > 0 ? base.slice(dotIndex) : "";
|
|
58
|
+
}
|
|
59
|
+
function isAbsolute(p) {
|
|
60
|
+
if (!p) return false;
|
|
61
|
+
if (p.startsWith("/") || p.startsWith("\\")) return true;
|
|
62
|
+
if (/^[A-Za-z]:[\\/]/.test(p)) return true;
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
function pathToFileURL(_p) {
|
|
66
|
+
return notAvailable("pathToFileURL");
|
|
67
|
+
}
|
|
68
|
+
var sep = "/";
|
|
69
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
70
|
+
0 && (module.exports = {
|
|
71
|
+
basename,
|
|
72
|
+
dirname,
|
|
73
|
+
extname,
|
|
74
|
+
isAbsolute,
|
|
75
|
+
join,
|
|
76
|
+
pathToFileURL,
|
|
77
|
+
resolve,
|
|
78
|
+
sep
|
|
79
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// libs/utils/src/path/node-path.ts
|
|
21
|
+
var node_path_exports = {};
|
|
22
|
+
__export(node_path_exports, {
|
|
23
|
+
basename: () => import_path.basename,
|
|
24
|
+
dirname: () => import_path.dirname,
|
|
25
|
+
extname: () => import_path.extname,
|
|
26
|
+
isAbsolute: () => import_path.isAbsolute,
|
|
27
|
+
join: () => import_path.join,
|
|
28
|
+
pathToFileURL: () => import_url.pathToFileURL,
|
|
29
|
+
resolve: () => import_path.resolve,
|
|
30
|
+
sep: () => import_path.sep
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(node_path_exports);
|
|
33
|
+
var import_path = require("path");
|
|
34
|
+
var import_url = require("url");
|
|
35
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
36
|
+
0 && (module.exports = {
|
|
37
|
+
basename,
|
|
38
|
+
dirname,
|
|
39
|
+
extname,
|
|
40
|
+
isAbsolute,
|
|
41
|
+
join,
|
|
42
|
+
pathToFileURL,
|
|
43
|
+
resolve,
|
|
44
|
+
sep
|
|
45
|
+
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Abstract base class for storage adapters.
|
|
5
5
|
* Provides common validation and default implementations.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { MessageHandler, SetEntry, SetOptions, StorageAdapter, Unsubscribe } from '../types';
|
|
8
8
|
/**
|
|
9
9
|
* Abstract base class for storage adapters.
|
|
10
10
|
* Subclasses must implement the abstract methods.
|
|
@@ -63,6 +63,11 @@ export declare abstract class BaseStorageAdapter implements StorageAdapter {
|
|
|
63
63
|
abstract incr(key: string): Promise<number>;
|
|
64
64
|
abstract decr(key: string): Promise<number>;
|
|
65
65
|
abstract incrBy(key: string, amount: number): Promise<number>;
|
|
66
|
+
/**
|
|
67
|
+
* Default: not supported, since a read followed by a delete is not atomic.
|
|
68
|
+
* Override in adapters whose backend can compare and delete in one step.
|
|
69
|
+
*/
|
|
70
|
+
deleteIfEquals(_key: string, _expectedValue: string): Promise<boolean>;
|
|
66
71
|
/**
|
|
67
72
|
* Default: pub/sub not supported.
|
|
68
73
|
* Override in adapters that support it.
|
|
@@ -18,6 +18,7 @@ export declare class CloudflareKvStorageAdapter extends BaseStorageAdapter {
|
|
|
18
18
|
incr(key: string): Promise<number>;
|
|
19
19
|
decr(key: string): Promise<number>;
|
|
20
20
|
incrBy(_key: string, _amount: number): Promise<number>;
|
|
21
|
+
deleteIfEquals(_key: string, _expectedValue: string): Promise<boolean>;
|
|
21
22
|
protected getPubSubSuggestion(): string;
|
|
22
23
|
/** Validate + enforce KV's 60s minimum `expirationTtl`. */
|
|
23
24
|
private toExpirationTtl;
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { BaseStorageAdapter } from './base';
|
|
7
7
|
export { MemoryStorageAdapter } from './memory';
|
|
8
|
-
export { RedisStorageAdapter } from './redis';
|
|
8
|
+
export { RedisStorageAdapter, createRedisClient } from './redis';
|
|
9
|
+
export type { CreateRedisClientOptions } from './redis';
|
|
9
10
|
export { VercelKvStorageAdapter } from './vercel-kv';
|
|
10
11
|
export { UpstashStorageAdapter } from './upstash';
|
|
11
12
|
export { CloudflareKvStorageAdapter } from './cloudflare-kv';
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* In-memory storage implementation for development and testing.
|
|
5
5
|
* Supports TTL, pattern matching, pub/sub via EventEmitter.
|
|
6
6
|
*/
|
|
7
|
+
import type { MemoryAdapterOptions, MessageHandler, SetOptions, Unsubscribe } from '../types';
|
|
7
8
|
import { BaseStorageAdapter } from './base';
|
|
8
|
-
import type { MemoryAdapterOptions, SetOptions, MessageHandler, Unsubscribe } from '../types';
|
|
9
9
|
/**
|
|
10
10
|
* In-memory storage adapter.
|
|
11
11
|
*
|
|
@@ -42,6 +42,7 @@ export declare class MemoryStorageAdapter extends BaseStorageAdapter {
|
|
|
42
42
|
get(key: string): Promise<string | null>;
|
|
43
43
|
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
44
44
|
delete(key: string): Promise<boolean>;
|
|
45
|
+
deleteIfEquals(key: string, expectedValue: string): Promise<boolean>;
|
|
45
46
|
exists(key: string): Promise<boolean>;
|
|
46
47
|
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
47
48
|
ttl(key: string): Promise<number | null>;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Redis-based storage implementation for production use.
|
|
5
5
|
* Uses ioredis with dynamic import for browser compatibility.
|
|
6
6
|
*/
|
|
7
|
+
import { type RedisErrorListenerOptions } from '../redis-error-listener';
|
|
7
8
|
import type { MessageHandler, RedisAdapterOptions, SetOptions, Unsubscribe } from '../types';
|
|
8
9
|
import { BaseStorageAdapter } from './base';
|
|
9
10
|
type Redis = import('ioredis').Redis;
|
|
@@ -34,6 +35,7 @@ export declare class RedisStorageAdapter extends BaseStorageAdapter {
|
|
|
34
35
|
private subscriber?;
|
|
35
36
|
private readonly options;
|
|
36
37
|
private readonly ownsClient;
|
|
38
|
+
private detachErrorListener?;
|
|
37
39
|
private connecting?;
|
|
38
40
|
private readonly keyPrefix;
|
|
39
41
|
private readonly subscriptionHandlers;
|
|
@@ -53,6 +55,7 @@ export declare class RedisStorageAdapter extends BaseStorageAdapter {
|
|
|
53
55
|
get(key: string): Promise<string | null>;
|
|
54
56
|
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
55
57
|
delete(key: string): Promise<boolean>;
|
|
58
|
+
deleteIfEquals(key: string, expectedValue: string): Promise<boolean>;
|
|
56
59
|
exists(key: string): Promise<boolean>;
|
|
57
60
|
mget(keys: string[]): Promise<(string | null)[]>;
|
|
58
61
|
mset(entries: import('../types').SetEntry[]): Promise<void>;
|
|
@@ -87,4 +90,20 @@ export declare class RedisStorageAdapter extends BaseStorageAdapter {
|
|
|
87
90
|
*/
|
|
88
91
|
getClient(): Redis | undefined;
|
|
89
92
|
}
|
|
93
|
+
export interface CreateRedisClientOptions {
|
|
94
|
+
url?: string;
|
|
95
|
+
host?: string;
|
|
96
|
+
port?: number;
|
|
97
|
+
password?: string;
|
|
98
|
+
db?: number;
|
|
99
|
+
tls?: boolean;
|
|
100
|
+
/** Prefix for the rate-limited connection-error log line. */
|
|
101
|
+
label?: string;
|
|
102
|
+
logger?: RedisErrorListenerOptions['logger'];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create a plain ioredis client that reconnects on its own and never emits an unhandled
|
|
106
|
+
* 'error' event. The caller owns the client and must `quit()`/`disconnect()` it.
|
|
107
|
+
*/
|
|
108
|
+
export declare function createRedisClient(options: CreateRedisClientOptions): Redis;
|
|
90
109
|
export {};
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Upstash Redis (REST-based) storage implementation for edge deployment.
|
|
5
5
|
* Supports pub/sub via Upstash's REST API with polling mechanism.
|
|
6
6
|
*/
|
|
7
|
+
import type { MessageHandler, SetOptions, Unsubscribe, UpstashAdapterOptions } from '../types';
|
|
7
8
|
import { BaseStorageAdapter } from './base';
|
|
8
|
-
import type { UpstashAdapterOptions, SetOptions, MessageHandler, Unsubscribe } from '../types';
|
|
9
9
|
/**
|
|
10
10
|
* Upstash Redis storage adapter.
|
|
11
11
|
*
|
|
@@ -52,6 +52,7 @@ export declare class UpstashStorageAdapter extends BaseStorageAdapter {
|
|
|
52
52
|
get(key: string): Promise<string | null>;
|
|
53
53
|
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
54
54
|
delete(key: string): Promise<boolean>;
|
|
55
|
+
deleteIfEquals(key: string, expectedValue: string): Promise<boolean>;
|
|
55
56
|
exists(key: string): Promise<boolean>;
|
|
56
57
|
mget(keys: string[]): Promise<(string | null)[]>;
|
|
57
58
|
mdelete(keys: string[]): Promise<number>;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Vercel KV (REST-based) storage implementation for edge deployment.
|
|
5
5
|
* NOTE: Vercel KV does NOT support pub/sub. Use Upstash adapter instead.
|
|
6
6
|
*/
|
|
7
|
+
import type { SetOptions, VercelKvAdapterOptions } from '../types';
|
|
7
8
|
import { BaseStorageAdapter } from './base';
|
|
8
|
-
import type { VercelKvAdapterOptions, SetOptions } from '../types';
|
|
9
9
|
/**
|
|
10
10
|
* Vercel KV storage adapter.
|
|
11
11
|
*
|
|
@@ -47,6 +47,7 @@ export declare class VercelKvStorageAdapter extends BaseStorageAdapter {
|
|
|
47
47
|
get(key: string): Promise<string | null>;
|
|
48
48
|
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
49
49
|
delete(key: string): Promise<boolean>;
|
|
50
|
+
deleteIfEquals(key: string, expectedValue: string): Promise<boolean>;
|
|
50
51
|
exists(key: string): Promise<boolean>;
|
|
51
52
|
mget(keys: string[]): Promise<(string | null)[]>;
|
|
52
53
|
mdelete(keys: string[]): Promise<number>;
|
package/storage/index.d.ts
CHANGED
|
@@ -6,13 +6,15 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export type { StorageAdapter, NamespacedStorage, RootStorage, SetOptions, SetEntry, MessageHandler, Unsubscribe, MemoryAdapterOptions, RedisAdapterOptions, VercelKvAdapterOptions, UpstashAdapterOptions, StorageType, StorageConfig, } from './types';
|
|
8
8
|
export { createStorage, createMemoryStorage, getDetectedStorageType } from './factory';
|
|
9
|
+
export { attachRedisErrorListener, DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS } from './redis-error-listener';
|
|
10
|
+
export type { RedisErrorListenerOptions, ErrorEmitterClient } from './redis-error-listener';
|
|
9
11
|
export { NamespacedStorageImpl, createRootStorage, createNamespacedStorage, buildPrefix, NAMESPACE_SEPARATOR, } from './namespace';
|
|
10
12
|
export { StorageError, StorageConnectionError, StorageOperationError, StorageNotSupportedError, StorageConfigError, StorageTTLError, StoragePatternError, StorageNotConnectedError, EncryptedStorageError, } from './errors';
|
|
11
13
|
export { TypedStorage } from './typed-storage';
|
|
12
14
|
export type { TypedStorageOptions, TypedSetOptions, TypedSetEntry } from './typed-storage.types';
|
|
13
15
|
export { EncryptedTypedStorage } from './encrypted-typed-storage';
|
|
14
16
|
export type { EncryptedTypedStorageOptions, EncryptedSetOptions, EncryptedSetEntry, EncryptionKey, StoredEncryptedBlob, ClientKeyBinding, } from './encrypted-typed-storage.types';
|
|
15
|
-
export { BaseStorageAdapter, MemoryStorageAdapter, RedisStorageAdapter, VercelKvStorageAdapter, UpstashStorageAdapter, FileSystemStorageAdapter, LocalStorageAdapter, IndexedDBStorageAdapter, } from './adapters';
|
|
16
|
-
export type { FileSystemAdapterOptions, LocalStorageAdapterOptions, IndexedDBAdapterOptions } from './adapters';
|
|
17
|
+
export { BaseStorageAdapter, MemoryStorageAdapter, RedisStorageAdapter, createRedisClient, VercelKvStorageAdapter, UpstashStorageAdapter, FileSystemStorageAdapter, LocalStorageAdapter, IndexedDBStorageAdapter, } from './adapters';
|
|
18
|
+
export type { CreateRedisClientOptions, FileSystemAdapterOptions, LocalStorageAdapterOptions, IndexedDBAdapterOptions, } from './adapters';
|
|
17
19
|
export { globToRegex, matchesPattern, validatePattern, escapeGlob } from './utils/pattern';
|
|
18
20
|
export { MAX_TTL_SECONDS, validateTTL, validateOptionalTTL, ttlToExpiresAt, expiresAtToTTL, isExpired, normalizeTTL, } from './utils/ttl';
|
package/storage/namespace.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Wraps a StorageAdapter to provide namespace prefixing.
|
|
5
5
|
* All operations automatically prefix keys with the namespace path.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { MessageHandler, NamespacedStorage, SetEntry, SetOptions, StorageAdapter, Unsubscribe } from './types';
|
|
8
8
|
/**
|
|
9
9
|
* Separator used between namespace segments.
|
|
10
10
|
*/
|
|
@@ -66,6 +66,7 @@ export declare class NamespacedStorageImpl implements NamespacedStorage {
|
|
|
66
66
|
incr(key: string): Promise<number>;
|
|
67
67
|
decr(key: string): Promise<number>;
|
|
68
68
|
incrBy(key: string, amount: number): Promise<number>;
|
|
69
|
+
deleteIfEquals(key: string, expectedValue: string): Promise<boolean>;
|
|
69
70
|
publish(channel: string, message: string): Promise<number>;
|
|
70
71
|
subscribe(channel: string, handler: MessageHandler): Promise<Unsubscribe>;
|
|
71
72
|
supportsPubSub(): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permanent, rate-limited 'error' listener for ioredis clients.
|
|
3
|
+
*
|
|
4
|
+
* ioredis emits 'error' for every failed reconnect attempt. With no listener it
|
|
5
|
+
* prints "[ioredis] Unhandled error event" once per attempt, which floods logs
|
|
6
|
+
* while Redis is down. This listener swallows the event and logs at most once
|
|
7
|
+
* per interval, counting the errors it suppressed.
|
|
8
|
+
*/
|
|
9
|
+
export interface RedisErrorListenerOptions {
|
|
10
|
+
/** Name used in the log line, e.g. 'HA'. */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Logger to write to. Falls back to `console.warn`. */
|
|
13
|
+
logger?: {
|
|
14
|
+
warn: (message: string, ...meta: unknown[]) => void;
|
|
15
|
+
};
|
|
16
|
+
/** Minimum time between two log lines. Defaults to 30 seconds. */
|
|
17
|
+
intervalMs?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface ErrorEmitterClient {
|
|
20
|
+
on(event: 'error', listener: (error: Error) => void): unknown;
|
|
21
|
+
removeListener(event: 'error', listener: (error: Error) => void): unknown;
|
|
22
|
+
}
|
|
23
|
+
export declare const DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS = 30000;
|
|
24
|
+
/**
|
|
25
|
+
* Attach the listener and return a function that removes it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function attachRedisErrorListener(client: ErrorEmitterClient, options?: RedisErrorListenerOptions): () => void;
|
package/storage/types.d.ts
CHANGED
|
@@ -205,6 +205,15 @@ export interface StorageAdapter {
|
|
|
205
205
|
* @throws StorageOperationError if value is not a valid integer
|
|
206
206
|
*/
|
|
207
207
|
incrBy(key: string, amount: number): Promise<number>;
|
|
208
|
+
/**
|
|
209
|
+
* Atomically delete a key only while it still holds `expectedValue` (compare-and-delete).
|
|
210
|
+
*
|
|
211
|
+
* @param key - Storage key
|
|
212
|
+
* @param expectedValue - The exact value the key must hold
|
|
213
|
+
* @returns true if this call deleted the key, false if it was missing or held another value
|
|
214
|
+
* @throws StorageNotSupportedError if the backend has no atomic compare-and-delete
|
|
215
|
+
*/
|
|
216
|
+
deleteIfEquals?(key: string, expectedValue: string): Promise<boolean>;
|
|
208
217
|
/**
|
|
209
218
|
* Publish a message to a channel.
|
|
210
219
|
* Not all adapters support pub/sub (e.g., Vercel KV doesn't).
|
|
@@ -267,6 +276,8 @@ export interface NamespacedStorage extends StorageAdapter {
|
|
|
267
276
|
* @returns A new NamespacedStorage with extended prefix
|
|
268
277
|
*/
|
|
269
278
|
namespace(name: string, id?: string): NamespacedStorage;
|
|
279
|
+
/** {@link StorageAdapter.deleteIfEquals}; throws StorageNotSupportedError when the adapter has none. */
|
|
280
|
+
deleteIfEquals(key: string, expectedValue: string): Promise<boolean>;
|
|
270
281
|
/**
|
|
271
282
|
* Get the underlying root adapter (for advanced use).
|
|
272
283
|
* Use with caution - operations bypass namespace prefixing.
|