@frontmcp/plugins 0.2.5 → 0.3.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/README.md +82 -66
- package/package.json +21 -2
- package/src/cache/cache.plugin.js +2 -3
- package/src/cache/cache.plugin.js.map +1 -1
- package/src/cache/cache.types.js.map +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# FrontMCP Plugins
|
|
2
2
|
|
|
3
|
-
Pluggable extensions for
|
|
3
|
+
Pluggable extensions for FrontMCP live here. Each plugin can contribute **providers**, **hooks**, and optional
|
|
4
|
+
**adapters** that extend the platform.
|
|
4
5
|
|
|
5
|
-
If you want to use a specific plugin, open that plugin’s README for full details. This page serves as an index and a
|
|
6
|
+
If you want to use a specific plugin, open that plugin’s README for full details. This page serves as an index and a
|
|
7
|
+
contributor guide.
|
|
6
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
@@ -13,13 +15,13 @@ If you want to use a specific plugin, open that plugin’s README for full detai
|
|
|
13
15
|
- [Contributor guide: authoring a plugin](#contributor-guide-authoring-a-plugin)
|
|
14
16
|
- [1) Recommended folder layout](#1-recommended-folder-layout)
|
|
15
17
|
- [2) Export surface (`index.ts`)](#2-export-surface-indexts)
|
|
16
|
-
- [3)
|
|
18
|
+
- [3) Extend tool metadata](#3-extend-tool-metadata)
|
|
17
19
|
- [4) Implementing the plugin class](#4-implementing-the-plugin-class)
|
|
18
20
|
- [5) Initialization styles (`DynamicPlugin.init`)](#5-initialization-styles-dynamicplugininit)
|
|
19
21
|
- [6) Hooks contributed by plugins](#6-hooks-contributed-by-plugins)
|
|
20
22
|
- [7) Registering your plugin in an app](#7-registering-your-plugin-in-an-app)
|
|
21
23
|
- [8) Documentation checklist](#8-documentation-checklist)
|
|
22
|
-
- [9)
|
|
24
|
+
- [9) Hook families & roadmap](#9-hook-families--roadmap)
|
|
23
25
|
- [Contributing](#contributing)
|
|
24
26
|
- [License](#license)
|
|
25
27
|
|
|
@@ -27,9 +29,9 @@ If you want to use a specific plugin, open that plugin’s README for full detai
|
|
|
27
29
|
|
|
28
30
|
## Available plugins
|
|
29
31
|
|
|
30
|
-
| Plugin | Description
|
|
31
|
-
|
|
32
|
-
| Cache
|
|
32
|
+
| Plugin | Description | Docs | Path |
|
|
33
|
+
| ------ | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------- |
|
|
34
|
+
| Cache | Transparent caching for tool outputs keyed by input. Supports in-memory and Redis stores; per-tool TTL and sliding windows. | [Cache Plugin README](./src/cache/README.md) | [`src/cache`](./src/cache) |
|
|
33
35
|
|
|
34
36
|
> For configuration and usage examples, follow the plugin’s own README.
|
|
35
37
|
|
|
@@ -39,17 +41,18 @@ If you want to use a specific plugin, open that plugin’s README for full detai
|
|
|
39
41
|
|
|
40
42
|
```ts
|
|
41
43
|
// app.ts
|
|
42
|
-
import {
|
|
43
|
-
import CachePlugin from '@frontmcp/plugins
|
|
44
|
+
import { App } from '@frontmcp/sdk';
|
|
45
|
+
import { CachePlugin } from '@frontmcp/plugins';
|
|
44
46
|
|
|
45
|
-
@
|
|
46
|
-
|
|
47
|
+
@App({
|
|
48
|
+
id: 'my-app',
|
|
49
|
+
name: 'My App',
|
|
47
50
|
plugins: [
|
|
48
51
|
CachePlugin, // or CachePlugin.init({...}) — see below for init styles
|
|
49
52
|
],
|
|
50
53
|
})
|
|
51
54
|
export default class MyApp {}
|
|
52
|
-
|
|
55
|
+
```
|
|
53
56
|
|
|
54
57
|
---
|
|
55
58
|
|
|
@@ -71,7 +74,8 @@ plugins/
|
|
|
71
74
|
└─ README.md # user-facing docs
|
|
72
75
|
```
|
|
73
76
|
|
|
74
|
-
> If your repo uses a monorepo layout like `libs/plugins/src/...`, keep the same structure under that root. Paths in
|
|
77
|
+
> If your repo uses a monorepo layout like `libs/plugins/src/...`, keep the same structure under that root. Paths in
|
|
78
|
+
> this README are relative to the current `plugins` folder.
|
|
75
79
|
|
|
76
80
|
### 2) Export surface (`index.ts`)
|
|
77
81
|
|
|
@@ -82,15 +86,16 @@ export { default } from './<your-plugin>.plugin';
|
|
|
82
86
|
export * from './<your-plugin>.types';
|
|
83
87
|
```
|
|
84
88
|
|
|
85
|
-
### 3)
|
|
89
|
+
### 3) Extend tool metadata
|
|
86
90
|
|
|
87
|
-
If your plugin adds tool-level options (e.g.,
|
|
91
|
+
If your plugin adds tool-level options (e.g., `cache`, `authorization`), augment the ambient
|
|
92
|
+
`ExtendFrontMcpToolMetadata` interface so tool authors get type-safe metadata.
|
|
88
93
|
|
|
89
94
|
```ts
|
|
90
95
|
// src/my-feature/my-feature.types.ts
|
|
91
96
|
|
|
92
97
|
declare global {
|
|
93
|
-
interface
|
|
98
|
+
interface ExtendFrontMcpToolMetadata {
|
|
94
99
|
/** Enables MyFeature for a tool; `true` uses plugin defaults. */
|
|
95
100
|
myFeature?: MyFeatureToolOptions | true;
|
|
96
101
|
}
|
|
@@ -106,24 +111,23 @@ export interface MyFeaturePluginOptions {
|
|
|
106
111
|
}
|
|
107
112
|
```
|
|
108
113
|
|
|
109
|
-
> Why: `declare global` merges into the ambient
|
|
114
|
+
> Why: `declare global` merges into the ambient tool metadata used by `@Tool` / `tool(...)`, so TypeScript validates
|
|
115
|
+
> options wherever tools are defined.
|
|
110
116
|
|
|
111
117
|
### 4) Implementing the plugin class
|
|
112
118
|
|
|
113
|
-
Plugins are classes decorated with `@
|
|
119
|
+
Plugins are classes decorated with `@Plugin(...)`. For plugins that need configuration and/or generated providers,
|
|
120
|
+
extend `DynamicPlugin<TOptions>` so you can support both value and factory initialization while contributing dynamic
|
|
121
|
+
providers.
|
|
114
122
|
|
|
115
123
|
```ts
|
|
116
124
|
// src/my-feature/my-feature.plugin.ts
|
|
117
|
-
import {
|
|
118
|
-
McpPlugin,
|
|
119
|
-
DynamicPlugin,
|
|
120
|
-
ToolHook,
|
|
121
|
-
ToolHookStage,
|
|
122
|
-
McpProviderType,
|
|
123
|
-
} from '@frontmcp/sdk';
|
|
125
|
+
import { Plugin, DynamicPlugin, FlowHooksOf, FlowCtxOf, ProviderType } from '@frontmcp/sdk';
|
|
124
126
|
import { MyFeaturePluginOptions } from './my-feature.types';
|
|
125
127
|
|
|
126
|
-
|
|
128
|
+
const ToolHook = FlowHooksOf('tools:call-tool');
|
|
129
|
+
|
|
130
|
+
@Plugin({
|
|
127
131
|
name: 'plugin:my-feature',
|
|
128
132
|
description: 'Does something useful',
|
|
129
133
|
providers: [
|
|
@@ -137,8 +141,8 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
|
|
|
137
141
|
};
|
|
138
142
|
|
|
139
143
|
// Contribute providers based on resolved options (runs before instance creation)
|
|
140
|
-
static override dynamicProviders(options: MyFeaturePluginOptions): readonly
|
|
141
|
-
const providers:
|
|
144
|
+
static override dynamicProviders(options: MyFeaturePluginOptions): readonly ProviderType[] {
|
|
145
|
+
const providers: ProviderType[] = [];
|
|
142
146
|
// Decide implementations based on options
|
|
143
147
|
// providers.push({ provide: MyToken, useValue: new MyProvider(options) });
|
|
144
148
|
return providers;
|
|
@@ -149,9 +153,9 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
|
|
|
149
153
|
}
|
|
150
154
|
|
|
151
155
|
// Optional: register global tool hooks contributed by the plugin
|
|
152
|
-
@ToolHook(
|
|
153
|
-
async willExecute(ctx:
|
|
154
|
-
// Observe/mutate ctx.
|
|
156
|
+
@ToolHook.Will('execute', { priority: 100 })
|
|
157
|
+
async willExecute(ctx: FlowCtxOf<'tools:call-tool'>) {
|
|
158
|
+
// Observe/mutate ctx.state.toolContext before tool execution
|
|
155
159
|
}
|
|
156
160
|
}
|
|
157
161
|
```
|
|
@@ -160,17 +164,19 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
|
|
|
160
164
|
|
|
161
165
|
`DynamicPlugin` exposes a static `init()` so apps can register your plugin in different ways:
|
|
162
166
|
|
|
163
|
-
|
|
167
|
+
- **Raw class** — zero-arg constructor only; no dynamic providers from options:
|
|
164
168
|
|
|
165
169
|
```ts
|
|
166
|
-
plugins: [MyFeaturePlugin]
|
|
170
|
+
plugins: [MyFeaturePlugin];
|
|
167
171
|
```
|
|
168
|
-
|
|
172
|
+
|
|
173
|
+
- **Value style** — options known upfront; `dynamicProviders(options)` is evaluated and merged:
|
|
169
174
|
|
|
170
175
|
```ts
|
|
171
|
-
plugins: [MyFeaturePlugin.init({ defaultLevel: 'high' })]
|
|
176
|
+
plugins: [MyFeaturePlugin.init({ defaultLevel: 'high' })];
|
|
172
177
|
```
|
|
173
|
-
|
|
178
|
+
|
|
179
|
+
- **Factory style** — compute options from app DI; then merge `dynamicProviders(realOptions)`:
|
|
174
180
|
|
|
175
181
|
```ts
|
|
176
182
|
plugins: [
|
|
@@ -178,35 +184,51 @@ export default class MyFeaturePlugin extends DynamicPlugin<MyFeaturePluginOption
|
|
|
178
184
|
inject: () => [SomeConfig],
|
|
179
185
|
useFactory: (cfg) => ({ defaultLevel: cfg.level }),
|
|
180
186
|
}),
|
|
181
|
-
]
|
|
187
|
+
];
|
|
182
188
|
```
|
|
183
189
|
|
|
184
190
|
Under the hood (high level):
|
|
185
191
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
- Static providers from `@Plugin({ providers: [...] })` are merged first.
|
|
193
|
+
- In **value**/**factory** styles, the registry evaluates `dynamicProviders(...)` and merges results.
|
|
194
|
+
- Provider tokens are de-duplicated to avoid conflicts.
|
|
189
195
|
|
|
190
|
-
> Implementation references (repository paths may vary):
|
|
191
|
-
>
|
|
196
|
+
> Implementation references (repository paths may vary): `libs/sdk/src/common/dynamic/dynamic.plugin.ts` and
|
|
197
|
+
> `libs/sdk/src/plugin/plugin.registry.ts`.
|
|
192
198
|
|
|
193
199
|
### 6) Hooks contributed by plugins
|
|
194
200
|
|
|
195
|
-
Plugins can register global
|
|
201
|
+
Plugins can register global hooks via `FlowHooksOf(...)`. The SDK exports helpers for the most common flows:
|
|
196
202
|
|
|
197
|
-
|
|
198
|
-
|
|
203
|
+
```ts
|
|
204
|
+
import { ToolHook, ListToolsHook, HttpHook } from '@frontmcp/sdk';
|
|
205
|
+
|
|
206
|
+
@ToolHook.Will('validateInput')
|
|
207
|
+
async ensureConstraints(ctx: FlowCtxOf<'tools:call-tool'>) {
|
|
208
|
+
// ...
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Available hook families today include:
|
|
213
|
+
|
|
214
|
+
- `ToolHook` (`tools:call-tool`) — observe or mutate tool execution.
|
|
215
|
+
- `ListToolsHook` (`tools:list-tools`) — filter/augment the tool catalog during discovery.
|
|
216
|
+
- `HttpHook` (`http:request`) — shape raw inbound HTTP requests before flow execution.
|
|
217
|
+
|
|
218
|
+
Within each family you can register `Will`, `Stage`, `Did`, or `Around` hooks. Use `FlowCtxOf<'flow-name'>` to access
|
|
219
|
+
typed context/state for that flow.
|
|
199
220
|
|
|
200
221
|
See the cache example hooks in: [`src/cache/cache.plugin.ts`](./src/cache/cache.plugin.ts).
|
|
201
222
|
|
|
202
223
|
### 7) Registering your plugin in an app
|
|
203
224
|
|
|
204
225
|
```ts
|
|
205
|
-
import {
|
|
206
|
-
import MyFeaturePlugin from '@frontmcp/plugins
|
|
226
|
+
import { App } from '@frontmcp/sdk';
|
|
227
|
+
import { MyFeaturePlugin } from '@frontmcp/plugins';
|
|
207
228
|
|
|
208
|
-
@
|
|
209
|
-
|
|
229
|
+
@App({
|
|
230
|
+
id: 'my-app',
|
|
231
|
+
name: 'My App',
|
|
210
232
|
plugins: [
|
|
211
233
|
MyFeaturePlugin, // or MyFeaturePlugin.init({...})
|
|
212
234
|
],
|
|
@@ -218,26 +240,20 @@ export default class MyApp {}
|
|
|
218
240
|
|
|
219
241
|
Each plugin must ship a `README.md` that explains:
|
|
220
242
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
243
|
+
- **What it does** and **when to use it**
|
|
244
|
+
- **Installation & registration** examples (raw/value/factory)
|
|
245
|
+
- **Configuration options** (plugin-level and tool-level)
|
|
246
|
+
- **Providers** it contributes and any required external services
|
|
247
|
+
- **Hooks** it adds and how they affect tool/app behavior
|
|
248
|
+
- **Examples** (minimal and advanced)
|
|
227
249
|
|
|
228
250
|
For a concrete example, see the [Cache Plugin README](./src/cache/README.md).
|
|
229
251
|
|
|
230
|
-
### 9)
|
|
231
|
-
|
|
232
|
-
These hook families are planned. Design plugins with extension points in mind:
|
|
233
|
-
|
|
234
|
-
* **AppHook** — app bootstrap/shutdown lifecycle.
|
|
235
|
-
* **HttpHook** — inbound/outbound request/response (tracing, auditing, rate limiting, etc.).
|
|
236
|
-
* **AuthHook** — authentication/authorization lifecycle (challenge, success, failure).
|
|
237
|
-
* **AdapterHooks** — participate in adapter initialization/configuration.
|
|
238
|
-
* **IO Hooks** — monitor and optionally block filesystem/native calls (policy/sandbox).
|
|
252
|
+
### 9) Hook families & roadmap
|
|
239
253
|
|
|
240
|
-
|
|
254
|
+
The SDK currently exposes flow hooks for tools (`ToolHook`), tool discovery (`ListToolsHook`), and HTTP requests
|
|
255
|
+
(`HttpHook`). More flows (auth, transports, adapters) will land iteratively. Design plugins so you can adopt new hook
|
|
256
|
+
families by switching to `FlowHooksOf('<future-flow>')` as they ship.
|
|
241
257
|
|
|
242
258
|
---
|
|
243
259
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "FrontMCP plugins to extend the SDK",
|
|
5
|
+
"author": "AgentFront <info@agentfront.dev>",
|
|
6
|
+
"homepage": "https://docs.agentfront.dev",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"plugins",
|
|
11
|
+
"agentfront",
|
|
12
|
+
"frontmcp",
|
|
13
|
+
"framework",
|
|
14
|
+
"typescript"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/agentfront/frontmcp.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/agentfront/frontmcp/issues"
|
|
22
|
+
},
|
|
4
23
|
"main": "./src/index.js",
|
|
5
24
|
"types": "./src/index.d.ts",
|
|
6
25
|
"exports": {
|
|
@@ -13,7 +32,7 @@
|
|
|
13
32
|
},
|
|
14
33
|
"dependencies": {
|
|
15
34
|
"tslib": "^2.3.0",
|
|
16
|
-
"@frontmcp/sdk": "^0.
|
|
35
|
+
"@frontmcp/sdk": "^0.3.0"
|
|
17
36
|
},
|
|
18
37
|
"type": "commonjs"
|
|
19
38
|
}
|
|
@@ -6,7 +6,6 @@ const sdk_1 = require("@frontmcp/sdk");
|
|
|
6
6
|
const cache_redis_provider_1 = tslib_1.__importDefault(require("./providers/cache-redis.provider"));
|
|
7
7
|
const cache_memory_provider_1 = tslib_1.__importDefault(require("./providers/cache-memory.provider"));
|
|
8
8
|
const cache_symbol_1 = require("./cache.symbol");
|
|
9
|
-
const core_1 = require("@frontmcp/core");
|
|
10
9
|
let CachePlugin = CachePlugin_1 = class CachePlugin extends sdk_1.DynamicPlugin {
|
|
11
10
|
constructor(options = CachePlugin_1.defaultOptions) {
|
|
12
11
|
super();
|
|
@@ -74,13 +73,13 @@ CachePlugin.defaultOptions = {
|
|
|
74
73
|
type: 'memory',
|
|
75
74
|
};
|
|
76
75
|
tslib_1.__decorate([
|
|
77
|
-
|
|
76
|
+
sdk_1.ToolHook.Will('execute', { priority: 1000 }),
|
|
78
77
|
tslib_1.__metadata("design:type", Function),
|
|
79
78
|
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
80
79
|
tslib_1.__metadata("design:returntype", Promise)
|
|
81
80
|
], CachePlugin.prototype, "willReadCache", null);
|
|
82
81
|
tslib_1.__decorate([
|
|
83
|
-
|
|
82
|
+
sdk_1.ToolHook.Did('execute', { priority: 1000 }),
|
|
84
83
|
tslib_1.__metadata("design:type", Function),
|
|
85
84
|
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
86
85
|
tslib_1.__metadata("design:returntype", Promise)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.plugin.js","sourceRoot":"","sources":["../../../src/cache/cache.plugin.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"cache.plugin.js","sourceRoot":"","sources":["../../../src/cache/cache.plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import {DynamicPlugin, FlowCtxOf, Plugin, ProviderType, ToolHook} from '@frontmcp/sdk';\nimport CacheRedisProvider from './providers/cache-redis.provider';\nimport CacheMemoryProvider from './providers/cache-memory.provider';\nimport {CachePluginOptions} from './cache.types';\nimport {CacheStoreToken} from './cache.symbol';\n\n\n@Plugin({\n name: 'cache',\n description: 'Cache plugin for caching tool results',\n providers: [\n /* add providers that always loaded with the plugin or default providers */\n {\n // this is default provider for cache, will be overridden if dynamicProviders based on config\n name: 'cache:memory',\n provide: CacheStoreToken,\n useValue: new CacheMemoryProvider(60 * 60 * 24),\n },\n ],\n})\nexport default class CachePlugin extends DynamicPlugin<CachePluginOptions> {\n private readonly defaultTTL: number;\n\n static override dynamicProviders = (options: CachePluginOptions) => {\n const providers: ProviderType[] = [];\n switch (options.type) {\n case 'redis':\n case 'redis-client':\n providers.push({\n name: 'cache:redis',\n provide: CacheStoreToken,\n useValue: new CacheRedisProvider(options),\n });\n break;\n case 'memory':\n providers.push({\n name: 'cache:memory',\n provide: CacheStoreToken,\n useValue: new CacheMemoryProvider(options.defaultTTL),\n });\n break;\n }\n return providers;\n };\n\n static defaultOptions: CachePluginOptions = {\n type: 'memory',\n };\n options: CachePluginOptions;\n\n constructor(options: CachePluginOptions = CachePlugin.defaultOptions) {\n super();\n this.options = {\n defaultTTL: 60 * 60 * 24,\n ...options,\n };\n }\n\n @ToolHook.Will('execute', {priority: 1000})\n async willReadCache(flowCtx: FlowCtxOf<'tools:call-tool'>) {\n const ctx = flowCtx.state.required.toolContext;\n const {cache} = ctx.metadata;\n if (!cache || !ctx.input) {\n return;\n }\n const redis = this.get(CacheStoreToken)\n const hash = hashObject(ctx.input);\n const cached = await redis.getValue(hash);\n\n if (cache == true || (cache.ttl && cache.slideWindow)) {\n const ttl = cache === true ? this.defaultTTL : cache.ttl ?? this.defaultTTL;\n await redis.setValue(hash, cached, ttl);\n }\n\n if (cached) {\n console.log('return from cache', {cached});\n ctx.respond({\n ...cached,\n ___cached__: true,\n });\n }\n }\n\n @ToolHook.Did('execute', {priority: 1000})\n async willWriteCache(flowCtx: FlowCtxOf<'tools:call-tool'>) {\n const ctx = flowCtx.state.required.toolContext;\n const {cache} = ctx.metadata;\n if (!cache) {\n return;\n }\n const redis = this.get(CacheStoreToken)\n console.log('willWriteCache', {cache});\n const ttl = cache === true ? this.defaultTTL : cache.ttl ?? this.defaultTTL;\n\n const hash = hashObject(ctx.input!);\n await redis.setValue(hash, ctx.output, ttl);\n }\n}\n\nfunction hashObject(obj: any) {\n const keys = Object.keys(obj).sort();\n const values = keys.map(key => obj[key]);\n return values.reduce((acc, val) => {\n if (typeof val === 'object' && val !== null) {\n acc += hashObject(val);\n } else {\n acc += val;\n }\n return acc;\n }, '');\n}"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.types.js","sourceRoot":"","sources":["../../../src/cache/cache.types.ts"],"names":[],"mappings":"","sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"cache.types.js","sourceRoot":"","sources":["../../../src/cache/cache.types.ts"],"names":[],"mappings":"","sourcesContent":["import {Redis as RedisClient} from 'ioredis';\n\ndeclare global {\n interface ExtendFrontMcpToolMetadata {\n cache?: CachePluginToolOptions | true;\n }\n}\n\nexport interface CachePluginToolOptions {\n /**\n * Time to live in seconds. Default is 1 day.\n */\n ttl?: number; // default 1 day\n\n /**\n * If true, the cache value will be updated with the new value after the TTL.\n * Default is false.\n */\n slideWindow?: boolean;\n}\n\nexport interface BaseCachePluginOptions {\n defaultTTL?: number; // default 1 day\n}\n\nexport interface RedisClientCachePluginOptions extends BaseCachePluginOptions {\n type: 'redis-client';\n client: RedisClient;\n}\n\nexport interface RedisCachePluginOptions extends BaseCachePluginOptions {\n type: 'redis';\n config: {\n host: string;\n port: number;\n password?: string;\n db?: number;\n };\n}\n\nexport type MemoryCachePluginOptions = BaseCachePluginOptions & {\n type: 'memory';\n};\n\nexport type RedisCacheOptions = RedisClientCachePluginOptions | RedisCachePluginOptions;\n\nexport type CachePluginOptions = MemoryCachePluginOptions | RedisCacheOptions;\n\nexport interface CacheStoreInterface {\n setValue(key: string, value: any, ttlSeconds?: number): Promise<void>;\n\n getValue<T = any>(key: string, defaultValue?: T): Promise<T | undefined>;\n\n delete(key: string): Promise<void>;\n\n exists(key: string): Promise<boolean>;\n\n close(): Promise<void>;\n}\n"]}
|