@astro-minimax/ai 0.2.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 +223 -0
- package/dist/cache/global-cache.d.ts +31 -0
- package/dist/cache/global-cache.d.ts.map +1 -0
- package/dist/cache/global-cache.js +141 -0
- package/dist/cache/index.d.ts +8 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +62 -0
- package/dist/cache/kv-adapter.d.ts +21 -0
- package/dist/cache/kv-adapter.d.ts.map +1 -0
- package/dist/cache/kv-adapter.js +102 -0
- package/dist/cache/memory-adapter.d.ts +24 -0
- package/dist/cache/memory-adapter.d.ts.map +1 -0
- package/dist/cache/memory-adapter.js +95 -0
- package/dist/cache/response-cache.d.ts +45 -0
- package/dist/cache/response-cache.d.ts.map +1 -0
- package/dist/cache/response-cache.js +85 -0
- package/dist/cache/types.d.ts +118 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +16 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.d.ts.map +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/metadata-loader.d.ts +37 -0
- package/dist/data/metadata-loader.d.ts.map +1 -0
- package/dist/data/metadata-loader.js +54 -0
- package/dist/data/types.d.ts +51 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/data/types.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/intelligence/citation-guard.d.ts +24 -0
- package/dist/intelligence/citation-guard.d.ts.map +1 -0
- package/dist/intelligence/citation-guard.js +82 -0
- package/dist/intelligence/evidence-analysis.d.ts +29 -0
- package/dist/intelligence/evidence-analysis.d.ts.map +1 -0
- package/dist/intelligence/evidence-analysis.js +88 -0
- package/dist/intelligence/index.d.ts +6 -0
- package/dist/intelligence/index.d.ts.map +1 -0
- package/dist/intelligence/index.js +4 -0
- package/dist/intelligence/intent-detect.d.ts +29 -0
- package/dist/intelligence/intent-detect.d.ts.map +1 -0
- package/dist/intelligence/intent-detect.js +64 -0
- package/dist/intelligence/keyword-extract.d.ts +31 -0
- package/dist/intelligence/keyword-extract.d.ts.map +1 -0
- package/dist/intelligence/keyword-extract.js +114 -0
- package/dist/intelligence/types.d.ts +27 -0
- package/dist/intelligence/types.d.ts.map +1 -0
- package/dist/intelligence/types.js +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +1 -0
- package/dist/middleware/rate-limiter.d.ts +26 -0
- package/dist/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/rate-limiter.js +129 -0
- package/dist/prompt/dynamic-layer.d.ts +7 -0
- package/dist/prompt/dynamic-layer.d.ts.map +1 -0
- package/dist/prompt/dynamic-layer.js +40 -0
- package/dist/prompt/index.d.ts +6 -0
- package/dist/prompt/index.d.ts.map +1 -0
- package/dist/prompt/index.js +4 -0
- package/dist/prompt/prompt-builder.d.ts +11 -0
- package/dist/prompt/prompt-builder.d.ts.map +1 -0
- package/dist/prompt/prompt-builder.js +19 -0
- package/dist/prompt/semi-static-layer.d.ts +7 -0
- package/dist/prompt/semi-static-layer.d.ts.map +1 -0
- package/dist/prompt/semi-static-layer.js +32 -0
- package/dist/prompt/static-layer.d.ts +3 -0
- package/dist/prompt/static-layer.d.ts.map +1 -0
- package/dist/prompt/static-layer.js +78 -0
- package/dist/prompt/types.d.ts +25 -0
- package/dist/prompt/types.d.ts.map +1 -0
- package/dist/prompt/types.js +1 -0
- package/dist/provider-manager/base.d.ts +26 -0
- package/dist/provider-manager/base.d.ts.map +1 -0
- package/dist/provider-manager/base.js +47 -0
- package/dist/provider-manager/config.d.ts +7 -0
- package/dist/provider-manager/config.d.ts.map +1 -0
- package/dist/provider-manager/config.js +134 -0
- package/dist/provider-manager/index.d.ts +8 -0
- package/dist/provider-manager/index.d.ts.map +1 -0
- package/dist/provider-manager/index.js +6 -0
- package/dist/provider-manager/manager.d.ts +18 -0
- package/dist/provider-manager/manager.d.ts.map +1 -0
- package/dist/provider-manager/manager.js +121 -0
- package/dist/provider-manager/mock.d.ts +18 -0
- package/dist/provider-manager/mock.d.ts.map +1 -0
- package/dist/provider-manager/mock.js +56 -0
- package/dist/provider-manager/openai.d.ts +20 -0
- package/dist/provider-manager/openai.d.ts.map +1 -0
- package/dist/provider-manager/openai.js +83 -0
- package/dist/provider-manager/types.d.ts +217 -0
- package/dist/provider-manager/types.d.ts.map +1 -0
- package/dist/provider-manager/types.js +6 -0
- package/dist/provider-manager/workers.d.ts +20 -0
- package/dist/provider-manager/workers.d.ts.map +1 -0
- package/dist/provider-manager/workers.js +74 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/mock.d.ts +14 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +234 -0
- package/dist/search/index.d.ts +5 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +3 -0
- package/dist/search/search-api.d.ts +28 -0
- package/dist/search/search-api.d.ts.map +1 -0
- package/dist/search/search-api.js +110 -0
- package/dist/search/search-index.d.ts +6 -0
- package/dist/search/search-index.d.ts.map +1 -0
- package/dist/search/search-index.js +22 -0
- package/dist/search/search-utils.d.ts +43 -0
- package/dist/search/search-utils.d.ts.map +1 -0
- package/dist/search/search-utils.js +114 -0
- package/dist/search/session-cache.d.ts +19 -0
- package/dist/search/session-cache.d.ts.map +1 -0
- package/dist/search/session-cache.js +92 -0
- package/dist/search/types.d.ts +41 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +1 -0
- package/dist/server/chat-handler.d.ts +3 -0
- package/dist/server/chat-handler.d.ts.map +1 -0
- package/dist/server/chat-handler.js +750 -0
- package/dist/server/dev-server.d.ts +18 -0
- package/dist/server/dev-server.d.ts.map +1 -0
- package/dist/server/dev-server.js +294 -0
- package/dist/server/errors.d.ts +17 -0
- package/dist/server/errors.d.ts.map +1 -0
- package/dist/server/errors.js +41 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +5 -0
- package/dist/server/metadata-init.d.ts +11 -0
- package/dist/server/metadata-init.d.ts.map +1 -0
- package/dist/server/metadata-init.js +45 -0
- package/dist/server/notify.d.ts +25 -0
- package/dist/server/notify.d.ts.map +1 -0
- package/dist/server/notify.js +62 -0
- package/dist/server/types.d.ts +56 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +13 -0
- package/dist/stream/index.d.ts +3 -0
- package/dist/stream/index.d.ts.map +1 -0
- package/dist/stream/index.js +2 -0
- package/dist/stream/mock-stream.d.ts +12 -0
- package/dist/stream/mock-stream.d.ts.map +1 -0
- package/dist/stream/mock-stream.js +27 -0
- package/dist/stream/response.d.ts +10 -0
- package/dist/stream/response.d.ts.map +1 -0
- package/dist/stream/response.js +22 -0
- package/dist/utils/i18n.d.ts +18 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +148 -0
- package/package.json +93 -0
- package/src/components/AIChatContainer.tsx +30 -0
- package/src/components/AIChatWidget.astro +30 -0
- package/src/components/ChatPanel.tsx +865 -0
- package/src/styles/source.css +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# @astro-minimax/ai
|
|
2
|
+
|
|
3
|
+
Vendor-agnostic AI integration package with full RAG pipeline for astro-minimax blogs. Supports OpenAI-compatible APIs, Cloudflare Workers AI, and mock fallback.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────────────────┐
|
|
9
|
+
│ Components (ChatPanel / AIChatWidget / AIChatContainer) │
|
|
10
|
+
│ → useChat + DefaultChatTransport │
|
|
11
|
+
└──────────────────────────┬──────────────────────────────┘
|
|
12
|
+
│ POST /api/chat
|
|
13
|
+
┌──────────────────────────▼──────────────────────────────┐
|
|
14
|
+
│ Server (chat-handler.ts) │
|
|
15
|
+
│ Rate Limit → Validate → Search → Evidence → Prompt → │
|
|
16
|
+
│ Provider Manager → streamText → SSE Response │
|
|
17
|
+
└──────────────────────────┬──────────────────────────────┘
|
|
18
|
+
│
|
|
19
|
+
┌─────────────────────┼──────────────────────┐
|
|
20
|
+
│ │ │
|
|
21
|
+
┌───▼───┐ ┌─────▼─────┐ ┌─────▼────┐
|
|
22
|
+
│OpenAI │ │Workers AI │ │ Mock │
|
|
23
|
+
│Compat │ │ Binding │ │ Fallback │
|
|
24
|
+
└───────┘ └───────────┘ └──────────┘
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Modules
|
|
28
|
+
|
|
29
|
+
| Module | Purpose |
|
|
30
|
+
| ------------------- | ---------------------------------------------------------------------- |
|
|
31
|
+
| `server/` | Reusable API handlers (`handleChatRequest`, `initializeMetadata`) |
|
|
32
|
+
| `provider-manager/` | Multi-provider management with priority, failover, health tracking |
|
|
33
|
+
| `search/` | In-memory article/project search with session caching |
|
|
34
|
+
| `intelligence/` | Keyword extraction, evidence analysis, citation guard |
|
|
35
|
+
| `prompt/` | Three-layer system prompt builder (static → semi-static → dynamic) |
|
|
36
|
+
| `data/` | Build-time metadata loading (summaries, author context, voice profile) |
|
|
37
|
+
| `stream/` | Stream helpers and response utilities |
|
|
38
|
+
| `components/` | Preact UI components (ChatPanel, AIChatWidget, AIChatContainer) |
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pnpm add @astro-minimax/ai
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The `@astro-minimax/core` integration auto-detects this package and renders the AI chat widget.
|
|
47
|
+
|
|
48
|
+
## Configuration
|
|
49
|
+
|
|
50
|
+
In `src/config.ts`:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
export const SITE = {
|
|
54
|
+
ai: {
|
|
55
|
+
enabled: true,
|
|
56
|
+
mockMode: false,
|
|
57
|
+
apiEndpoint: "/api/chat",
|
|
58
|
+
welcomeMessage: undefined, // auto-generated
|
|
59
|
+
placeholder: undefined,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Environment Variables
|
|
65
|
+
|
|
66
|
+
| Variable | Required | Description |
|
|
67
|
+
| ------------------- | ----------- | ----------------------------------------------------------- |
|
|
68
|
+
| `AI_BASE_URL` | For OpenAI | Base URL of OpenAI-compatible API |
|
|
69
|
+
| `AI_API_KEY` | For OpenAI | API key |
|
|
70
|
+
| `AI_MODEL` | Recommended | Model name for OpenAI provider (default: `gpt-4o-mini`) |
|
|
71
|
+
| `AI_KEYWORD_MODEL` | Optional | Model for keyword extraction (defaults to `AI_MODEL`) |
|
|
72
|
+
| `AI_EVIDENCE_MODEL` | Optional | Model for evidence analysis (defaults to keyword model) |
|
|
73
|
+
| `AI_BINDING_NAME` | For Workers | Cloudflare AI binding name (default: `minimaxAI`) |
|
|
74
|
+
| `AI_WORKERS_MODEL` | For Workers | Model for Workers AI (default: `@cf/zai-org/glm-4.7-flash`) |
|
|
75
|
+
| `SITE_AUTHOR` | Recommended | Author name for prompts |
|
|
76
|
+
| `SITE_URL` | Recommended | Site URL for article links |
|
|
77
|
+
|
|
78
|
+
### Response Cache Configuration
|
|
79
|
+
|
|
80
|
+
| Variable | Default | Description |
|
|
81
|
+
| ---------------------------------- | ------- | ----------------------------------------- |
|
|
82
|
+
| `AI_RESPONSE_CACHE_ENABLED` | `false` | Enable AI response caching |
|
|
83
|
+
| `AI_RESPONSE_CACHE_TTL` | `3600` | Cache TTL in seconds (1 hour) |
|
|
84
|
+
| `AI_RESPONSE_CACHE_PLAYBACK_DELAY` | `20` | Delay between chunks during playback (ms) |
|
|
85
|
+
| `AI_RESPONSE_CACHE_CHUNK_SIZE` | `15` | Characters per chunk during playback |
|
|
86
|
+
| `AI_RESPONSE_CACHE_THINKING_DELAY` | `5` | Delay for thinking content playback (ms) |
|
|
87
|
+
|
|
88
|
+
When enabled, the system caches complete AI responses (including thinking/reasoning content) for public questions like "What tech stack does this blog use?". Subsequent identical queries are served from cache with simulated streaming playback, reducing API costs and response time.
|
|
89
|
+
|
|
90
|
+
## Server Module
|
|
91
|
+
|
|
92
|
+
The server module provides reusable request handlers, decoupled from any specific runtime (Cloudflare, Node.js, etc.).
|
|
93
|
+
|
|
94
|
+
### Usage in Cloudflare Pages Functions
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// functions/api/chat.ts
|
|
98
|
+
import { handleChatRequest, initializeMetadata } from '@astro-minimax/ai/server';
|
|
99
|
+
import summaries from '../../datas/ai-summaries.json';
|
|
100
|
+
import authorContext from '../../datas/author-context.json';
|
|
101
|
+
import voiceProfile from '../../datas/voice-profile.json';
|
|
102
|
+
|
|
103
|
+
export const onRequest: PagesFunction = async (context) => {
|
|
104
|
+
initializeMetadata({ summaries, authorContext, voiceProfile }, context.env);
|
|
105
|
+
return handleChatRequest({ env: context.env, request: context.request });
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Chat API Contract
|
|
110
|
+
|
|
111
|
+
**Request:** `POST /api/chat`
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"context": {
|
|
116
|
+
"scope": "article",
|
|
117
|
+
"article": {
|
|
118
|
+
"slug": "my-post",
|
|
119
|
+
"title": "My Post Title",
|
|
120
|
+
"summary": "Brief summary...",
|
|
121
|
+
"keyPoints": ["Point 1", "Point 2"],
|
|
122
|
+
"categories": ["tech"]
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"id": "article:my-post",
|
|
126
|
+
"messages": [...]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`context.scope` values:
|
|
131
|
+
|
|
132
|
+
- `"global"` — General blog chat (default)
|
|
133
|
+
- `"article"` — Reading companion mode, focused on a specific article
|
|
134
|
+
|
|
135
|
+
**Response:** UI Message Stream Protocol (SSE)
|
|
136
|
+
|
|
137
|
+
- `text-start` / `text-delta` / `text-end` — Streaming text content
|
|
138
|
+
- `source` — RAG article references
|
|
139
|
+
- `message-metadata` — Processing status updates
|
|
140
|
+
- `finish` — Stream completion
|
|
141
|
+
|
|
142
|
+
**Error Response:**
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"error": "请求太频繁,请稍后再试",
|
|
147
|
+
"code": "RATE_LIMITED",
|
|
148
|
+
"retryable": true,
|
|
149
|
+
"retryAfter": 10
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Code | Status | Retryable | Description |
|
|
154
|
+
| ---------------------- | ------ | --------- | --------------------- |
|
|
155
|
+
| `RATE_LIMITED` | 429 | Yes | Too many requests |
|
|
156
|
+
| `PROVIDER_UNAVAILABLE` | 503 | Yes | All providers failed |
|
|
157
|
+
| `TIMEOUT` | 504 | Yes | Request timeout |
|
|
158
|
+
| `INPUT_TOO_LONG` | 400 | No | Message exceeds limit |
|
|
159
|
+
| `INVALID_REQUEST` | 400 | No | Malformed request |
|
|
160
|
+
| `INTERNAL_ERROR` | 500 | Yes | Server error |
|
|
161
|
+
|
|
162
|
+
## Provider System
|
|
163
|
+
|
|
164
|
+
### Priority & Failover
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
Workers AI (weight: 100) → OpenAI Compatible (weight: 90) → Mock (weight: 0)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
When a provider fails, the next one is tried automatically. Mock fallback ensures users always get a response.
|
|
171
|
+
|
|
172
|
+
### Timeout Budget (per request: 45s total)
|
|
173
|
+
|
|
174
|
+
| Stage | Timeout | Behavior on timeout |
|
|
175
|
+
| ------------------ | ------- | -------------------------------- |
|
|
176
|
+
| Keyword extraction | 5s | Falls back to local search query |
|
|
177
|
+
| Evidence analysis | 8s | Skipped |
|
|
178
|
+
| LLM streaming | 30s | Tries next provider, then mock |
|
|
179
|
+
|
|
180
|
+
## "Read & Chat" (边读边聊)
|
|
181
|
+
|
|
182
|
+
When a user opens the AI chat on an article page, the system enters **reading companion mode**:
|
|
183
|
+
|
|
184
|
+
1. **Article context** flows from `PostDetails.astro` → `Layout.astro` → `AIChatWidget` → `ChatPanel`
|
|
185
|
+
2. **Welcome message** references the current article title
|
|
186
|
+
3. **Quick prompts** are article-specific (summarize, explain, related topics)
|
|
187
|
+
4. **API request** includes `context: { scope: "article", article: {...} }`
|
|
188
|
+
5. **Server** enhances the prompt with article summary, key points, and reading companion instructions
|
|
189
|
+
|
|
190
|
+
## Components
|
|
191
|
+
|
|
192
|
+
### AIChatWidget.astro
|
|
193
|
+
|
|
194
|
+
Astro entry point. Accepts `lang` and optional `articleContext` props. Renders `AIChatContainer` with `client:idle`.
|
|
195
|
+
|
|
196
|
+
### AIChatContainer.tsx
|
|
197
|
+
|
|
198
|
+
Manages open/close state. Exposes `window.__aiChatToggle` for the floating action button.
|
|
199
|
+
|
|
200
|
+
### ChatPanel.tsx
|
|
201
|
+
|
|
202
|
+
Core chat UI built on `useChat` from `@ai-sdk/react`:
|
|
203
|
+
|
|
204
|
+
- `DefaultChatTransport` with `prepareSendMessagesRequest` for context injection
|
|
205
|
+
- Parts-based message rendering (`text`, `source`, custom data parts)
|
|
206
|
+
- Error display with retry button (`regenerate()`)
|
|
207
|
+
- Status indicators from message metadata
|
|
208
|
+
- Mock mode with character-by-character streaming simulation
|
|
209
|
+
|
|
210
|
+
## Exports
|
|
211
|
+
|
|
212
|
+
| Path | Contents |
|
|
213
|
+
| ---------------- | --------------------------------------------------------------- |
|
|
214
|
+
| `.` | All modules |
|
|
215
|
+
| `./server` | `handleChatRequest`, `initializeMetadata`, error helpers, types |
|
|
216
|
+
| `./providers` | Mock response/stream utilities |
|
|
217
|
+
| `./middleware` | Rate limiting |
|
|
218
|
+
| `./search` | Article/project search, session cache |
|
|
219
|
+
| `./intelligence` | Keyword extraction, evidence analysis, citation guard |
|
|
220
|
+
| `./prompt` | System prompt builder |
|
|
221
|
+
| `./data` | Metadata loading |
|
|
222
|
+
| `./stream` | Stream utilities |
|
|
223
|
+
| `./components/*` | Astro/Preact components |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CacheAdapter, CachedSearchContext } from './types.js';
|
|
2
|
+
export type PublicQuestionType = 'tech' | 'recommend' | 'build' | 'summary' | 'author' | 'about';
|
|
3
|
+
export interface PublicQuestionPattern {
|
|
4
|
+
type: PublicQuestionType;
|
|
5
|
+
keywords: string[];
|
|
6
|
+
patterns: RegExp[];
|
|
7
|
+
ttl: number;
|
|
8
|
+
needsContext: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const PUBLIC_QUESTION_PATTERNS: PublicQuestionPattern[];
|
|
11
|
+
export interface DetectedPublicQuestion {
|
|
12
|
+
type: PublicQuestionType;
|
|
13
|
+
confidence: number;
|
|
14
|
+
ttl: number;
|
|
15
|
+
needsContext: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function detectPublicQuestion(query: string): DetectedPublicQuestion | null;
|
|
18
|
+
export declare function buildGlobalCacheKey(type: PublicQuestionType, context?: {
|
|
19
|
+
articleSlug?: string;
|
|
20
|
+
lang?: string;
|
|
21
|
+
}): string;
|
|
22
|
+
export declare function getGlobalSearchCache(cache: CacheAdapter, type: PublicQuestionType, context?: {
|
|
23
|
+
articleSlug?: string;
|
|
24
|
+
lang?: string;
|
|
25
|
+
}): Promise<CachedSearchContext | null>;
|
|
26
|
+
export declare function setGlobalSearchCache(cache: CacheAdapter, type: PublicQuestionType, data: CachedSearchContext, ttl: number, context?: {
|
|
27
|
+
articleSlug?: string;
|
|
28
|
+
lang?: string;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
export declare function getGlobalCacheTTL(type: PublicQuestionType): number;
|
|
31
|
+
//# sourceMappingURL=global-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-cache.d.ts","sourceRoot":"","sources":["../../src/cache/global-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN,WAAW,GACX,OAAO,GACP,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,wBAAwB,EAAE,qBAAqB,EAiF3D,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,kBAAkB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAkCjF;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,kBAAkB,EACxB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,MAAM,CAYR;AAUD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,kBAAkB,EACxB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAIrC;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAGlE"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
export const PUBLIC_QUESTION_PATTERNS = [
|
|
2
|
+
{
|
|
3
|
+
type: 'tech',
|
|
4
|
+
keywords: ['技术栈', '技术', '框架', '用了什么', 'built with', 'tech stack', 'framework'],
|
|
5
|
+
patterns: [
|
|
6
|
+
/这个博客用了什么/,
|
|
7
|
+
/博客.*技术栈/,
|
|
8
|
+
/用了什么技术/,
|
|
9
|
+
/what.*tech.*stack/,
|
|
10
|
+
/built with/,
|
|
11
|
+
/用什么框架/,
|
|
12
|
+
],
|
|
13
|
+
ttl: 86400,
|
|
14
|
+
needsContext: false,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
type: 'recommend',
|
|
18
|
+
keywords: ['推荐', '文章推荐', '好文', 'recommend', 'suggest'],
|
|
19
|
+
patterns: [
|
|
20
|
+
/推荐.*文章/,
|
|
21
|
+
/有哪些推荐/,
|
|
22
|
+
/文章推荐/,
|
|
23
|
+
/recommend.*article/,
|
|
24
|
+
/any.*recommend/,
|
|
25
|
+
],
|
|
26
|
+
ttl: 1800,
|
|
27
|
+
needsContext: false,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'build',
|
|
31
|
+
keywords: ['搭建', '部署', '怎么建', 'how to build', 'deploy', 'setup'],
|
|
32
|
+
patterns: [
|
|
33
|
+
/怎么搭建/,
|
|
34
|
+
/如何搭建/,
|
|
35
|
+
/怎么部署/,
|
|
36
|
+
/how to build/,
|
|
37
|
+
/how to deploy/,
|
|
38
|
+
/搭建.*博客/,
|
|
39
|
+
],
|
|
40
|
+
ttl: 86400,
|
|
41
|
+
needsContext: false,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: 'summary',
|
|
45
|
+
keywords: ['总结', '概括', '摘要', 'summarize', 'summary', 'tl;dr'],
|
|
46
|
+
patterns: [
|
|
47
|
+
/总结(一下|这篇文章)/,
|
|
48
|
+
/概括(一下|这篇文章)/,
|
|
49
|
+
/文章摘要/,
|
|
50
|
+
/summarize/,
|
|
51
|
+
/summary/,
|
|
52
|
+
/主要讲了什么/,
|
|
53
|
+
],
|
|
54
|
+
ttl: 14400,
|
|
55
|
+
needsContext: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: 'author',
|
|
59
|
+
keywords: ['作者', '博主', '谁', 'author', 'who'],
|
|
60
|
+
patterns: [
|
|
61
|
+
/作者是谁/,
|
|
62
|
+
/博主是谁/,
|
|
63
|
+
/关于作者/,
|
|
64
|
+
/who.*author/,
|
|
65
|
+
/about author/,
|
|
66
|
+
],
|
|
67
|
+
ttl: 86400,
|
|
68
|
+
needsContext: false,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: 'about',
|
|
72
|
+
keywords: ['关于', '介绍', 'about', 'intro'],
|
|
73
|
+
patterns: [
|
|
74
|
+
/关于.*博客/,
|
|
75
|
+
/博客介绍/,
|
|
76
|
+
/about.*blog/,
|
|
77
|
+
/介绍一下/,
|
|
78
|
+
],
|
|
79
|
+
ttl: 86400,
|
|
80
|
+
needsContext: false,
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
export function detectPublicQuestion(query) {
|
|
84
|
+
const normalized = normalizeQuery(query);
|
|
85
|
+
let bestMatch = null;
|
|
86
|
+
let bestScore = 0;
|
|
87
|
+
for (const pattern of PUBLIC_QUESTION_PATTERNS) {
|
|
88
|
+
let score = 0;
|
|
89
|
+
for (const keyword of pattern.keywords) {
|
|
90
|
+
if (normalized.includes(keyword.toLowerCase())) {
|
|
91
|
+
score += 1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const regex of pattern.patterns) {
|
|
95
|
+
if (regex.test(normalized)) {
|
|
96
|
+
score += 3;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (score > bestScore && score >= 2) {
|
|
100
|
+
bestScore = score;
|
|
101
|
+
const confidence = Math.min(score / 5, 1);
|
|
102
|
+
bestMatch = {
|
|
103
|
+
type: pattern.type,
|
|
104
|
+
confidence,
|
|
105
|
+
ttl: pattern.ttl,
|
|
106
|
+
needsContext: pattern.needsContext,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return bestMatch;
|
|
111
|
+
}
|
|
112
|
+
export function buildGlobalCacheKey(type, context) {
|
|
113
|
+
const parts = ['global', type];
|
|
114
|
+
if (context?.articleSlug) {
|
|
115
|
+
parts.push(context.articleSlug);
|
|
116
|
+
}
|
|
117
|
+
if (context?.lang) {
|
|
118
|
+
parts.push(context.lang);
|
|
119
|
+
}
|
|
120
|
+
return parts.join(':');
|
|
121
|
+
}
|
|
122
|
+
function normalizeQuery(query) {
|
|
123
|
+
return query
|
|
124
|
+
.toLowerCase()
|
|
125
|
+
.replace(/[??!!。,,.]/g, '')
|
|
126
|
+
.replace(/\s+/g, ' ')
|
|
127
|
+
.trim();
|
|
128
|
+
}
|
|
129
|
+
export async function getGlobalSearchCache(cache, type, context) {
|
|
130
|
+
const key = buildGlobalCacheKey(type, context);
|
|
131
|
+
const entry = await cache.get(key);
|
|
132
|
+
return entry?.value ?? null;
|
|
133
|
+
}
|
|
134
|
+
export async function setGlobalSearchCache(cache, type, data, ttl, context) {
|
|
135
|
+
const key = buildGlobalCacheKey(type, context);
|
|
136
|
+
await cache.set(key, data, { ttl });
|
|
137
|
+
}
|
|
138
|
+
export function getGlobalCacheTTL(type) {
|
|
139
|
+
const pattern = PUBLIC_QUESTION_PATTERNS.find(p => p.type === type);
|
|
140
|
+
return pattern?.ttl ?? 3600;
|
|
141
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { MemoryCacheAdapter, type MemoryCacheOptions, } from './memory-adapter.js';
|
|
2
|
+
export { KVCacheAdapter, type KVCacheOptions, } from './kv-adapter.js';
|
|
3
|
+
export { createCacheKeyBuilder, type CacheAdapter, type CacheEntry, type CacheEntryMetadata, type CacheSetOptions, type CacheGetOptions, type CacheManagerConfig, type CacheEnv, type CachedSearchContext, type CacheResult, type CacheKeyBuilder, } from './types.js';
|
|
4
|
+
export { detectPublicQuestion, buildGlobalCacheKey, getGlobalSearchCache, setGlobalSearchCache, getGlobalCacheTTL, PUBLIC_QUESTION_PATTERNS, type PublicQuestionType, type PublicQuestionPattern, type DetectedPublicQuestion, } from './global-cache.js';
|
|
5
|
+
export { getResponseCache, setResponseCache, deleteResponseCache, getResponseCacheConfig, buildResponseCacheKey, createResponsePlaybackGenerator, DEFAULT_RESPONSE_CACHE_CONFIG, type CachedAIResponse, type ResponseCacheConfig, type ResponseCacheEnv, type PlaybackChunk, } from './response-cache.js';
|
|
6
|
+
import type { CacheAdapter, CacheEnv, CacheManagerConfig } from './types.js';
|
|
7
|
+
export declare function createCacheAdapter(env: CacheEnv, config?: CacheManagerConfig): CacheAdapter;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,qBAAqB,EACrB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,+BAA+B,EAC/B,6BAA6B,EAC7B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAc7E,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,QAAQ,EACb,MAAM,CAAC,EAAE,kBAAkB,GAC1B,YAAY,CAcd"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export { MemoryCacheAdapter, } from './memory-adapter.js';
|
|
2
|
+
export { KVCacheAdapter, } from './kv-adapter.js';
|
|
3
|
+
export { createCacheKeyBuilder, } from './types.js';
|
|
4
|
+
export { detectPublicQuestion, buildGlobalCacheKey, getGlobalSearchCache, setGlobalSearchCache, getGlobalCacheTTL, PUBLIC_QUESTION_PATTERNS, } from './global-cache.js';
|
|
5
|
+
export { getResponseCache, setResponseCache, deleteResponseCache, getResponseCacheConfig, buildResponseCacheKey, createResponsePlaybackGenerator, DEFAULT_RESPONSE_CACHE_CONFIG, } from './response-cache.js';
|
|
6
|
+
import { MemoryCacheAdapter } from './memory-adapter.js';
|
|
7
|
+
import { KVCacheAdapter } from './kv-adapter.js';
|
|
8
|
+
const DEFAULT_TTL = 600;
|
|
9
|
+
const DEFAULT_MAX_ENTRIES = 400;
|
|
10
|
+
let globalMemoryCache = null;
|
|
11
|
+
function getGlobalMemoryCache(ttl, maxEntries) {
|
|
12
|
+
if (!globalMemoryCache) {
|
|
13
|
+
globalMemoryCache = new MemoryCacheAdapter({ defaultTtl: ttl, maxEntries });
|
|
14
|
+
}
|
|
15
|
+
return globalMemoryCache;
|
|
16
|
+
}
|
|
17
|
+
export function createCacheAdapter(env, config) {
|
|
18
|
+
const ttl = config?.defaultTtl ?? parseTtl(env.CACHE_TTL) ?? DEFAULT_TTL;
|
|
19
|
+
const maxEntries = config?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
20
|
+
if (isCacheDisabled(env)) {
|
|
21
|
+
return getGlobalMemoryCache(ttl, maxEntries);
|
|
22
|
+
}
|
|
23
|
+
const kvBinding = getKVBinding(env);
|
|
24
|
+
if (kvBinding) {
|
|
25
|
+
return new KVCacheAdapter(kvBinding, { defaultTtl: ttl });
|
|
26
|
+
}
|
|
27
|
+
return getGlobalMemoryCache(ttl, maxEntries);
|
|
28
|
+
}
|
|
29
|
+
function isCacheDisabled(env) {
|
|
30
|
+
const val = env.CACHE_DISABLED;
|
|
31
|
+
if (val === true || val === 'true' || val === '1') {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
function getKVBinding(env) {
|
|
37
|
+
const customBinding = env.CACHE_KV_BINDING;
|
|
38
|
+
if (customBinding && typeof customBinding === 'string') {
|
|
39
|
+
const binding = env[customBinding];
|
|
40
|
+
return isKVNamespace(binding) ? binding : null;
|
|
41
|
+
}
|
|
42
|
+
if (env.CACHE_KV && isKVNamespace(env.CACHE_KV)) {
|
|
43
|
+
return env.CACHE_KV;
|
|
44
|
+
}
|
|
45
|
+
const defaultBinding = env['CACHE_KV'];
|
|
46
|
+
return isKVNamespace(defaultBinding) ? defaultBinding : null;
|
|
47
|
+
}
|
|
48
|
+
function isKVNamespace(value) {
|
|
49
|
+
return (typeof value === 'object' &&
|
|
50
|
+
value !== null &&
|
|
51
|
+
'get' in value &&
|
|
52
|
+
'put' in value &&
|
|
53
|
+
'delete' in value);
|
|
54
|
+
}
|
|
55
|
+
function parseTtl(value) {
|
|
56
|
+
if (value === undefined)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (typeof value === 'number')
|
|
59
|
+
return value;
|
|
60
|
+
const parsed = parseInt(value, 10);
|
|
61
|
+
return isNaN(parsed) ? undefined : parsed;
|
|
62
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CacheAdapter, CacheEntry, CacheSetOptions, CacheGetOptions } from './types.js';
|
|
2
|
+
export interface KVCacheOptions {
|
|
3
|
+
defaultTtl?: number;
|
|
4
|
+
prefix?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class KVCacheAdapter implements CacheAdapter {
|
|
7
|
+
readonly name = "cloudflare-kv";
|
|
8
|
+
private kv;
|
|
9
|
+
private defaultTtl;
|
|
10
|
+
private prefix;
|
|
11
|
+
constructor(kv: KVNamespace, options?: KVCacheOptions);
|
|
12
|
+
private buildKey;
|
|
13
|
+
get<T>(key: string, options?: CacheGetOptions): Promise<CacheEntry<T> | null>;
|
|
14
|
+
set<T>(key: string, value: T, options?: CacheSetOptions): Promise<void>;
|
|
15
|
+
delete(key: string): Promise<boolean>;
|
|
16
|
+
clear(): Promise<void>;
|
|
17
|
+
has(key: string): Promise<boolean>;
|
|
18
|
+
isAvailable(): Promise<boolean>;
|
|
19
|
+
dispose(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=kv-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv-adapter.d.ts","sourceRoot":"","sources":["../../src/cache/kv-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EAEV,eAAe,EACf,eAAe,EAChB,MAAM,YAAY,CAAC;AAOpB,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,qBAAa,cAAe,YAAW,YAAY;IACjD,QAAQ,CAAC,IAAI,mBAAmB;IAChC,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;gBAEX,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,cAAc;IAMrD,OAAO,CAAC,QAAQ;IAIV,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IA0B7E,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BvE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAerC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IASrC,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const DEFAULT_TTL_SECONDS = 600;
|
|
2
|
+
const MIN_TTL_SECONDS = 60;
|
|
3
|
+
export class KVCacheAdapter {
|
|
4
|
+
name = 'cloudflare-kv';
|
|
5
|
+
kv;
|
|
6
|
+
defaultTtl;
|
|
7
|
+
prefix;
|
|
8
|
+
constructor(kv, options) {
|
|
9
|
+
this.kv = kv;
|
|
10
|
+
this.defaultTtl = options?.defaultTtl ?? DEFAULT_TTL_SECONDS;
|
|
11
|
+
this.prefix = options?.prefix ?? '';
|
|
12
|
+
}
|
|
13
|
+
buildKey(key) {
|
|
14
|
+
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
15
|
+
}
|
|
16
|
+
async get(key, options) {
|
|
17
|
+
try {
|
|
18
|
+
const fullKey = this.buildKey(key);
|
|
19
|
+
const result = await this.kv.getWithMetadata(fullKey, 'json');
|
|
20
|
+
if (!result.value) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const storedEntry = result.value;
|
|
24
|
+
if (!storedEntry.value || !storedEntry.metadata) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
value: storedEntry.value,
|
|
29
|
+
metadata: storedEntry.metadata,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (!options?.silent) {
|
|
34
|
+
console.error('[KVCacheAdapter] Get error:', error);
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async set(key, value, options) {
|
|
40
|
+
try {
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const ttl = options?.ttl ?? this.defaultTtl;
|
|
43
|
+
const entry = {
|
|
44
|
+
value,
|
|
45
|
+
metadata: {
|
|
46
|
+
createdAt: now,
|
|
47
|
+
updatedAt: now,
|
|
48
|
+
custom: options?.metadata,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
const fullKey = this.buildKey(key);
|
|
52
|
+
const effectiveTtl = Math.max(ttl, MIN_TTL_SECONDS);
|
|
53
|
+
await this.kv.put(fullKey, JSON.stringify(entry), {
|
|
54
|
+
expirationTtl: effectiveTtl,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error('[KVCacheAdapter] Set error:', error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async delete(key) {
|
|
63
|
+
try {
|
|
64
|
+
const fullKey = this.buildKey(key);
|
|
65
|
+
const existing = await this.kv.get(fullKey);
|
|
66
|
+
if (existing === null) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
await this.kv.delete(fullKey);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error('[KVCacheAdapter] Delete error:', error);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async clear() {
|
|
78
|
+
console.warn('[KVCacheAdapter] Clear not supported for KV namespace');
|
|
79
|
+
}
|
|
80
|
+
async has(key) {
|
|
81
|
+
try {
|
|
82
|
+
const fullKey = this.buildKey(key);
|
|
83
|
+
const value = await this.kv.get(fullKey);
|
|
84
|
+
return value !== null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async isAvailable() {
|
|
91
|
+
try {
|
|
92
|
+
await this.kv.get('__health_check__');
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
dispose() {
|
|
100
|
+
// KV adapter doesn't hold any resources that need cleanup
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CacheAdapter, CacheEntry, CacheSetOptions, CacheGetOptions } from './types.js';
|
|
2
|
+
export interface MemoryCacheOptions {
|
|
3
|
+
maxEntries?: number;
|
|
4
|
+
defaultTtl?: number;
|
|
5
|
+
cleanupInterval?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class MemoryCacheAdapter implements CacheAdapter {
|
|
8
|
+
readonly name = "memory";
|
|
9
|
+
private cache;
|
|
10
|
+
private maxEntries;
|
|
11
|
+
private defaultTtl;
|
|
12
|
+
private cleanupTimer?;
|
|
13
|
+
constructor(options?: MemoryCacheOptions);
|
|
14
|
+
get<T>(key: string, _options?: CacheGetOptions): Promise<CacheEntry<T> | null>;
|
|
15
|
+
set<T>(key: string, value: T, options?: CacheSetOptions): Promise<void>;
|
|
16
|
+
delete(key: string): Promise<boolean>;
|
|
17
|
+
clear(): Promise<void>;
|
|
18
|
+
has(key: string): Promise<boolean>;
|
|
19
|
+
isAvailable(): Promise<boolean>;
|
|
20
|
+
private cleanup;
|
|
21
|
+
private evictLRU;
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=memory-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-adapter.d.ts","sourceRoot":"","sources":["../../src/cache/memory-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EAEV,eAAe,EACf,eAAe,EAChB,MAAM,YAAY,CAAC;AAQpB,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAKD,qBAAa,kBAAmB,YAAW,YAAY;IACrD,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAC,CAAiC;gBAE1C,OAAO,CAAC,EAAE,kBAAkB;IAYlC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAmB9E,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBvE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYlC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAIrC,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,QAAQ;IAYhB,OAAO,IAAI,IAAI;CAOhB"}
|