@sylphx/flow 1.8.0 → 1.8.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/CHANGELOG.md +52 -0
- package/assets/output-styles/silent.md +141 -8
- package/assets/rules/core.md +19 -2
- package/package.json +2 -12
- package/src/commands/flow/execute.ts +470 -0
- package/src/commands/flow/index.ts +11 -0
- package/src/commands/flow/prompt.ts +35 -0
- package/src/commands/flow/setup.ts +312 -0
- package/src/commands/flow/targets.ts +18 -0
- package/src/commands/flow/types.ts +47 -0
- package/src/commands/flow-command.ts +18 -967
- package/src/commands/flow-orchestrator.ts +14 -5
- package/src/commands/hook-command.ts +1 -1
- package/src/commands/init-core.ts +12 -3
- package/src/commands/run-command.ts +1 -1
- package/src/config/rules.ts +1 -1
- package/src/core/error-handling.ts +1 -1
- package/src/core/loop-controller.ts +1 -1
- package/src/core/state-detector.ts +1 -1
- package/src/core/target-manager.ts +1 -1
- package/src/index.ts +1 -1
- package/src/shared/files/index.ts +1 -1
- package/src/shared/processing/index.ts +1 -1
- package/src/targets/claude-code.ts +3 -3
- package/src/targets/opencode.ts +3 -3
- package/src/utils/agent-enhancer.ts +2 -2
- package/src/utils/{mcp-config.ts → config/mcp-config.ts} +4 -4
- package/src/utils/{paths.ts → config/paths.ts} +1 -1
- package/src/utils/{settings.ts → config/settings.ts} +1 -1
- package/src/utils/{target-config.ts → config/target-config.ts} +5 -5
- package/src/utils/{target-utils.ts → config/target-utils.ts} +3 -3
- package/src/utils/display/banner.ts +25 -0
- package/src/utils/display/status.ts +55 -0
- package/src/utils/{file-operations.ts → files/file-operations.ts} +2 -2
- package/src/utils/files/jsonc.ts +36 -0
- package/src/utils/{sync-utils.ts → files/sync-utils.ts} +3 -3
- package/src/utils/index.ts +42 -61
- package/src/utils/version.ts +47 -0
- package/src/components/benchmark-monitor.tsx +0 -331
- package/src/components/reindex-progress.tsx +0 -261
- package/src/composables/functional/index.ts +0 -14
- package/src/composables/functional/useEnvironment.ts +0 -171
- package/src/composables/functional/useFileSystem.ts +0 -139
- package/src/composables/index.ts +0 -4
- package/src/composables/useEnv.ts +0 -13
- package/src/composables/useRuntimeConfig.ts +0 -27
- package/src/core/ai-sdk.ts +0 -603
- package/src/core/app-factory.ts +0 -381
- package/src/core/builtin-agents.ts +0 -9
- package/src/core/command-system.ts +0 -550
- package/src/core/config-system.ts +0 -550
- package/src/core/connection-pool.ts +0 -390
- package/src/core/di-container.ts +0 -155
- package/src/core/headless-display.ts +0 -96
- package/src/core/interfaces/index.ts +0 -22
- package/src/core/interfaces/repository.interface.ts +0 -91
- package/src/core/interfaces/service.interface.ts +0 -133
- package/src/core/interfaces.ts +0 -96
- package/src/core/result.ts +0 -351
- package/src/core/service-config.ts +0 -252
- package/src/core/session-service.ts +0 -121
- package/src/core/storage-factory.ts +0 -115
- package/src/core/stream-handler.ts +0 -288
- package/src/core/type-utils.ts +0 -427
- package/src/core/unified-storage.ts +0 -456
- package/src/core/validation/limit.ts +0 -46
- package/src/core/validation/query.ts +0 -20
- package/src/db/auto-migrate.ts +0 -322
- package/src/db/base-database-client.ts +0 -144
- package/src/db/cache-db.ts +0 -218
- package/src/db/cache-schema.ts +0 -75
- package/src/db/database.ts +0 -70
- package/src/db/index.ts +0 -252
- package/src/db/memory-db.ts +0 -153
- package/src/db/memory-schema.ts +0 -29
- package/src/db/schema.ts +0 -289
- package/src/db/session-repository.ts +0 -733
- package/src/domains/index.ts +0 -6
- package/src/domains/utilities/index.ts +0 -6
- package/src/domains/utilities/time/index.ts +0 -5
- package/src/domains/utilities/time/tools.ts +0 -291
- package/src/services/agent-service.ts +0 -273
- package/src/services/evaluation-service.ts +0 -271
- package/src/services/functional/evaluation-logic.ts +0 -296
- package/src/services/functional/file-processor.ts +0 -273
- package/src/services/functional/index.ts +0 -12
- package/src/services/memory.service.ts +0 -476
- package/src/types/api/batch.ts +0 -108
- package/src/types/api/errors.ts +0 -118
- package/src/types/api/index.ts +0 -55
- package/src/types/api/requests.ts +0 -76
- package/src/types/api/responses.ts +0 -180
- package/src/types/api/websockets.ts +0 -85
- package/src/types/benchmark.ts +0 -49
- package/src/types/database.types.ts +0 -510
- package/src/types/memory-types.ts +0 -63
- package/src/utils/advanced-tokenizer.ts +0 -191
- package/src/utils/ai-model-fetcher.ts +0 -19
- package/src/utils/async-file-operations.ts +0 -516
- package/src/utils/audio-player.ts +0 -345
- package/src/utils/codebase-helpers.ts +0 -211
- package/src/utils/console-ui.ts +0 -79
- package/src/utils/database-errors.ts +0 -140
- package/src/utils/debug-logger.ts +0 -49
- package/src/utils/file-scanner.ts +0 -259
- package/src/utils/help.ts +0 -20
- package/src/utils/immutable-cache.ts +0 -106
- package/src/utils/jsonc.ts +0 -158
- package/src/utils/memory-tui.ts +0 -414
- package/src/utils/models-dev.ts +0 -91
- package/src/utils/parallel-operations.ts +0 -487
- package/src/utils/process-manager.ts +0 -155
- package/src/utils/prompts.ts +0 -120
- package/src/utils/search-tool-builder.ts +0 -214
- package/src/utils/session-manager.ts +0 -168
- package/src/utils/session-title.ts +0 -87
- package/src/utils/simplified-errors.ts +0 -410
- package/src/utils/template-engine.ts +0 -94
- package/src/utils/test-audio.ts +0 -71
- package/src/utils/todo-context.ts +0 -46
- package/src/utils/token-counter.ts +0 -288
- /package/src/utils/{cli-output.ts → display/cli-output.ts} +0 -0
- /package/src/utils/{logger.ts → display/logger.ts} +0 -0
- /package/src/utils/{notifications.ts → display/notifications.ts} +0 -0
- /package/src/utils/{secret-utils.ts → security/secret-utils.ts} +0 -0
- /package/src/utils/{security.ts → security/security.ts} +0 -0
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory Service Layer
|
|
3
|
-
*
|
|
4
|
-
* Business logic layer for memory operations
|
|
5
|
-
* Handles memory management with validation, caching, and business rules
|
|
6
|
-
* Uses functional Result type for error handling
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { type Result, tryCatchAsync } from '../core/functional/result.js';
|
|
10
|
-
import type { ILogger } from '../core/interfaces.js';
|
|
11
|
-
import {
|
|
12
|
-
MemoryError,
|
|
13
|
-
type MemoryErrorType,
|
|
14
|
-
MemoryNotFoundError,
|
|
15
|
-
MemorySizeError,
|
|
16
|
-
MemoryValidationError,
|
|
17
|
-
} from '../errors/memory-errors.js';
|
|
18
|
-
import type {
|
|
19
|
-
CreateMemoryData,
|
|
20
|
-
MemoryEntry,
|
|
21
|
-
MemoryRepository,
|
|
22
|
-
MemorySearchParams,
|
|
23
|
-
} from '../repositories/memory.repository.js';
|
|
24
|
-
import type { MemoryStatsResult, MemoryValue } from '../types/memory-types.js';
|
|
25
|
-
import {
|
|
26
|
-
type CacheState,
|
|
27
|
-
cacheDelete,
|
|
28
|
-
cacheDeleteWhere,
|
|
29
|
-
cacheEnforceLimit,
|
|
30
|
-
cacheGet,
|
|
31
|
-
cacheSet,
|
|
32
|
-
createCache,
|
|
33
|
-
} from '../utils/immutable-cache.js';
|
|
34
|
-
|
|
35
|
-
export interface MemoryServiceConfig {
|
|
36
|
-
defaultNamespace?: string;
|
|
37
|
-
maxEntrySize?: number;
|
|
38
|
-
enableCaching?: boolean;
|
|
39
|
-
cacheMaxSize?: number;
|
|
40
|
-
retentionPolicy?: {
|
|
41
|
-
enabled: boolean;
|
|
42
|
-
maxAge: number; // milliseconds
|
|
43
|
-
cleanupInterval?: number; // milliseconds
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Dependencies for MemoryService
|
|
49
|
-
*/
|
|
50
|
-
export interface MemoryServiceDeps {
|
|
51
|
-
readonly repository: MemoryRepository;
|
|
52
|
-
readonly logger: ILogger;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Internal state for MemoryService
|
|
57
|
-
*/
|
|
58
|
-
interface MemoryServiceState {
|
|
59
|
-
readonly cache: CacheState<string, MemoryEntry>;
|
|
60
|
-
readonly cleanupTimer?: NodeJS.Timeout;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* MemoryService Interface
|
|
65
|
-
* Business logic layer for memory operations
|
|
66
|
-
*/
|
|
67
|
-
export interface MemoryService {
|
|
68
|
-
readonly get: (key: string, namespace?: string) => Promise<Result<MemoryValue, MemoryErrorType>>;
|
|
69
|
-
readonly set: (
|
|
70
|
-
key: string,
|
|
71
|
-
value: string,
|
|
72
|
-
namespace?: string
|
|
73
|
-
) => Promise<Result<MemoryEntry, MemoryErrorType>>;
|
|
74
|
-
readonly delete: (key: string, namespace?: string) => Promise<Result<boolean, MemoryError>>;
|
|
75
|
-
readonly list: (namespace?: string) => Promise<Result<string[], MemoryError>>;
|
|
76
|
-
readonly search: (params: MemorySearchParams) => Promise<Result<MemoryEntry[], MemoryError>>;
|
|
77
|
-
readonly clear: (namespace?: string) => Promise<Result<number, MemoryError>>;
|
|
78
|
-
readonly getStats: () => Promise<Result<MemoryStatsResult, MemoryError>>;
|
|
79
|
-
readonly bulkSet: (
|
|
80
|
-
entries: Array<{ key: string; value: string; namespace?: string }>,
|
|
81
|
-
namespace?: string
|
|
82
|
-
) => Promise<Result<MemoryEntry[], MemoryError>>;
|
|
83
|
-
readonly dispose: () => Promise<void>;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Create Memory Service (Factory Function)
|
|
88
|
-
* Handles memory management with validation, caching, and business rules
|
|
89
|
-
*/
|
|
90
|
-
export const createMemoryService = (
|
|
91
|
-
deps: MemoryServiceDeps,
|
|
92
|
-
config: MemoryServiceConfig = {}
|
|
93
|
-
): MemoryService => {
|
|
94
|
-
// Service configuration in closure
|
|
95
|
-
const serviceConfig: MemoryServiceConfig = {
|
|
96
|
-
defaultNamespace: 'default',
|
|
97
|
-
enableCaching: true,
|
|
98
|
-
cacheMaxSize: 1000,
|
|
99
|
-
...config,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// Mutable state in closure (will be updated immutably)
|
|
103
|
-
let state: MemoryServiceState = {
|
|
104
|
-
cache: createCache(),
|
|
105
|
-
cleanupTimer: undefined,
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// Helper: Update state immutably
|
|
109
|
-
const updateState = (updates: Partial<MemoryServiceState>): void => {
|
|
110
|
-
state = { ...state, ...updates };
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Get a memory value
|
|
115
|
-
*/
|
|
116
|
-
const get = async (
|
|
117
|
-
key: string,
|
|
118
|
-
namespace: string = serviceConfig.defaultNamespace || 'default'
|
|
119
|
-
): Promise<Result<MemoryValue, MemoryErrorType>> => {
|
|
120
|
-
return await tryCatchAsync(
|
|
121
|
-
async () => {
|
|
122
|
-
// Check cache first if enabled
|
|
123
|
-
if (serviceConfig.enableCaching) {
|
|
124
|
-
const cacheKey = `${namespace}:${key}`;
|
|
125
|
-
// FUNCTIONAL: Use immutable cache get
|
|
126
|
-
const cached = cacheGet(state.cache, cacheKey);
|
|
127
|
-
if (cached) {
|
|
128
|
-
return {
|
|
129
|
-
value: cached.value,
|
|
130
|
-
metadata: {
|
|
131
|
-
namespace,
|
|
132
|
-
timestamp: cached.timestamp,
|
|
133
|
-
size: cached.value.length,
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Fetch from repository
|
|
140
|
-
const entry = await deps.repository.getByKey(key, namespace);
|
|
141
|
-
|
|
142
|
-
if (!entry) {
|
|
143
|
-
throw new MemoryNotFoundError(key, namespace);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Cache the result if enabled
|
|
147
|
-
if (serviceConfig.enableCaching) {
|
|
148
|
-
updateCache(entry);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
value: entry.value,
|
|
153
|
-
metadata: {
|
|
154
|
-
namespace,
|
|
155
|
-
timestamp: entry.timestamp,
|
|
156
|
-
size: entry.value.length,
|
|
157
|
-
},
|
|
158
|
-
};
|
|
159
|
-
},
|
|
160
|
-
(error) => {
|
|
161
|
-
if (error instanceof MemoryNotFoundError) {
|
|
162
|
-
return error;
|
|
163
|
-
}
|
|
164
|
-
deps.logger.error(`Failed to get memory entry: ${key}`, error);
|
|
165
|
-
return new MemoryError(`Failed to get memory entry: ${key}`, error);
|
|
166
|
-
}
|
|
167
|
-
);
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Set a memory value
|
|
172
|
-
*/
|
|
173
|
-
const set = async (
|
|
174
|
-
key: string,
|
|
175
|
-
value: string,
|
|
176
|
-
namespace: string = serviceConfig.defaultNamespace || 'default'
|
|
177
|
-
): Promise<Result<MemoryEntry, MemoryErrorType>> => {
|
|
178
|
-
return await tryCatchAsync(
|
|
179
|
-
async () => {
|
|
180
|
-
// Validate inputs
|
|
181
|
-
const validationError = validateMemoryEntry(key, value);
|
|
182
|
-
if (validationError) {
|
|
183
|
-
throw validationError;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const timestamp = Date.now();
|
|
187
|
-
const data: CreateMemoryData = {
|
|
188
|
-
key,
|
|
189
|
-
namespace,
|
|
190
|
-
value,
|
|
191
|
-
timestamp,
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// Store in repository
|
|
195
|
-
const entry = await deps.repository.setMemory(data);
|
|
196
|
-
|
|
197
|
-
// Update cache if enabled
|
|
198
|
-
if (serviceConfig.enableCaching) {
|
|
199
|
-
updateCache(entry);
|
|
200
|
-
enforceCacheLimit();
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
deps.logger.debug(`Memory entry set: ${key} in namespace: ${namespace}`);
|
|
204
|
-
|
|
205
|
-
return entry;
|
|
206
|
-
},
|
|
207
|
-
(error) => {
|
|
208
|
-
if (error instanceof MemoryValidationError || error instanceof MemorySizeError) {
|
|
209
|
-
return error;
|
|
210
|
-
}
|
|
211
|
-
deps.logger.error(`Failed to set memory entry: ${key}`, error);
|
|
212
|
-
return new MemoryError(`Failed to set memory entry: ${key}`, error);
|
|
213
|
-
}
|
|
214
|
-
);
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Delete a memory entry
|
|
219
|
-
*/
|
|
220
|
-
const deleteEntry = async (
|
|
221
|
-
key: string,
|
|
222
|
-
namespace: string = serviceConfig.defaultNamespace || 'default'
|
|
223
|
-
): Promise<Result<boolean, MemoryError>> => {
|
|
224
|
-
return await tryCatchAsync(
|
|
225
|
-
async () => {
|
|
226
|
-
const deleted = await deps.repository.deleteMemory(key, namespace);
|
|
227
|
-
|
|
228
|
-
// Remove from cache if present
|
|
229
|
-
if (serviceConfig.enableCaching) {
|
|
230
|
-
const cacheKey = `${namespace}:${key}`;
|
|
231
|
-
// FUNCTIONAL: Use immutable cache delete, returns new state
|
|
232
|
-
updateState({ cache: cacheDelete(state.cache, cacheKey) });
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
deps.logger.debug(`Memory entry deleted: ${key} in namespace: ${namespace}`);
|
|
236
|
-
|
|
237
|
-
return deleted;
|
|
238
|
-
},
|
|
239
|
-
(error) => {
|
|
240
|
-
deps.logger.error(`Failed to delete memory entry: ${key}`, error);
|
|
241
|
-
return new MemoryError(`Failed to delete memory entry: ${key}`, error);
|
|
242
|
-
}
|
|
243
|
-
);
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* List all keys in a namespace
|
|
248
|
-
*/
|
|
249
|
-
const list = async (
|
|
250
|
-
namespace: string = serviceConfig.defaultNamespace || 'default'
|
|
251
|
-
): Promise<Result<string[], MemoryError>> => {
|
|
252
|
-
return await tryCatchAsync(
|
|
253
|
-
async () => {
|
|
254
|
-
const keys = await deps.repository.listKeys(namespace);
|
|
255
|
-
return keys;
|
|
256
|
-
},
|
|
257
|
-
(error) => {
|
|
258
|
-
deps.logger.error(`Failed to list keys in namespace: ${namespace}`, error);
|
|
259
|
-
return new MemoryError(`Failed to list keys in namespace: ${namespace}`, error);
|
|
260
|
-
}
|
|
261
|
-
);
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Search memory entries
|
|
266
|
-
*/
|
|
267
|
-
const search = async (
|
|
268
|
-
params: MemorySearchParams
|
|
269
|
-
): Promise<Result<MemoryEntry[], MemoryError>> => {
|
|
270
|
-
return await tryCatchAsync(
|
|
271
|
-
async () => {
|
|
272
|
-
const entries = await deps.repository.searchMemory(params);
|
|
273
|
-
return entries;
|
|
274
|
-
},
|
|
275
|
-
(error) => {
|
|
276
|
-
deps.logger.error('Failed to search memory entries', error);
|
|
277
|
-
return new MemoryError('Failed to search memory entries', error);
|
|
278
|
-
}
|
|
279
|
-
);
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Clear all entries in a namespace
|
|
284
|
-
*/
|
|
285
|
-
const clear = async (
|
|
286
|
-
namespace: string = serviceConfig.defaultNamespace || 'default'
|
|
287
|
-
): Promise<Result<number, MemoryError>> => {
|
|
288
|
-
return await tryCatchAsync(
|
|
289
|
-
async () => {
|
|
290
|
-
const deletedCount = await deps.repository.clearNamespace(namespace);
|
|
291
|
-
|
|
292
|
-
// Clear cache entries for this namespace
|
|
293
|
-
if (serviceConfig.enableCaching) {
|
|
294
|
-
// FUNCTIONAL: Use immutable cache deleteWhere, returns new state
|
|
295
|
-
updateState({
|
|
296
|
-
cache: cacheDeleteWhere(state.cache, (key) => key.startsWith(`${namespace}:`)),
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
deps.logger.info(`Cleared ${deletedCount} entries from namespace: ${namespace}`);
|
|
301
|
-
|
|
302
|
-
return deletedCount;
|
|
303
|
-
},
|
|
304
|
-
(error) => {
|
|
305
|
-
deps.logger.error(`Failed to clear namespace: ${namespace}`, error);
|
|
306
|
-
return new MemoryError(`Failed to clear namespace: ${namespace}`, error);
|
|
307
|
-
}
|
|
308
|
-
);
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Get memory statistics
|
|
313
|
-
*/
|
|
314
|
-
const getStats = async (): Promise<Result<MemoryStatsResult, MemoryError>> => {
|
|
315
|
-
return await tryCatchAsync(
|
|
316
|
-
async () => {
|
|
317
|
-
const stats = await deps.repository.getStats();
|
|
318
|
-
|
|
319
|
-
return {
|
|
320
|
-
totalEntries: stats.totalEntries,
|
|
321
|
-
totalSize: stats.totalSize,
|
|
322
|
-
namespaces: stats.namespaces,
|
|
323
|
-
oldestEntry: stats.oldestEntry,
|
|
324
|
-
newestEntry: stats.newestEntry,
|
|
325
|
-
};
|
|
326
|
-
},
|
|
327
|
-
(error) => {
|
|
328
|
-
deps.logger.error('Failed to get memory statistics', error);
|
|
329
|
-
return new MemoryError('Failed to get memory statistics', error);
|
|
330
|
-
}
|
|
331
|
-
);
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Perform bulk operations
|
|
336
|
-
*/
|
|
337
|
-
const bulkSet = async (
|
|
338
|
-
entries: Array<{ key: string; value: string; namespace?: string }>,
|
|
339
|
-
namespace: string = serviceConfig.defaultNamespace || 'default'
|
|
340
|
-
): Promise<Result<MemoryEntry[], MemoryError>> => {
|
|
341
|
-
return await tryCatchAsync(
|
|
342
|
-
async () => {
|
|
343
|
-
const results: MemoryEntry[] = [];
|
|
344
|
-
const errors: string[] = [];
|
|
345
|
-
|
|
346
|
-
for (const entry of entries) {
|
|
347
|
-
const result = await set(entry.key, entry.value, entry.namespace || namespace);
|
|
348
|
-
if (result._tag === 'Success') {
|
|
349
|
-
results.push(result.value);
|
|
350
|
-
} else {
|
|
351
|
-
errors.push(`${entry.key}: ${result.error.message}`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (errors.length > 0) {
|
|
356
|
-
deps.logger.warn(`Bulk set completed with ${errors.length} errors`, { errors });
|
|
357
|
-
throw new MemoryError(`Bulk set completed with errors: ${errors.join('; ')}`);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return results;
|
|
361
|
-
},
|
|
362
|
-
(error) => {
|
|
363
|
-
if (error instanceof MemoryError) {
|
|
364
|
-
return error;
|
|
365
|
-
}
|
|
366
|
-
deps.logger.error('Failed to perform bulk set', error);
|
|
367
|
-
return new MemoryError('Failed to perform bulk set', error);
|
|
368
|
-
}
|
|
369
|
-
);
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Validate memory entry data
|
|
374
|
-
*/
|
|
375
|
-
const validateMemoryEntry = (
|
|
376
|
-
key: string,
|
|
377
|
-
value: string
|
|
378
|
-
): MemoryValidationError | MemorySizeError | null => {
|
|
379
|
-
if (!key || key.trim().length === 0) {
|
|
380
|
-
return new MemoryValidationError('Key cannot be empty', 'key', key);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
if (key.length > 255) {
|
|
384
|
-
return new MemoryValidationError('Key cannot exceed 255 characters', 'key', key);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (serviceConfig.maxEntrySize && value.length > serviceConfig.maxEntrySize) {
|
|
388
|
-
return new MemorySizeError(value.length, serviceConfig.maxEntrySize);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Validate key format (no special characters that could cause issues)
|
|
392
|
-
if (!/^[a-zA-Z0-9._-]+$/.test(key)) {
|
|
393
|
-
return new MemoryValidationError(
|
|
394
|
-
'Key can only contain alphanumeric characters, dots, hyphens, and underscores',
|
|
395
|
-
'key',
|
|
396
|
-
key
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return null;
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Update cache with new entry
|
|
405
|
-
* FUNCTIONAL: Returns new cache state instead of mutating
|
|
406
|
-
*/
|
|
407
|
-
const updateCache = (entry: MemoryEntry): void => {
|
|
408
|
-
const cacheKey = `${entry.namespace}:${entry.key}`;
|
|
409
|
-
// FUNCTIONAL: Use immutable cache set, returns new state
|
|
410
|
-
updateState({ cache: cacheSet(state.cache, cacheKey, entry) });
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Enforce cache size limit
|
|
415
|
-
* FUNCTIONAL: Uses immutable cache operations
|
|
416
|
-
*/
|
|
417
|
-
const enforceCacheLimit = (): void => {
|
|
418
|
-
if (serviceConfig.cacheMaxSize && state.cache.size > serviceConfig.cacheMaxSize) {
|
|
419
|
-
// FUNCTIONAL: Use immutable cache enforceLimit, returns new state
|
|
420
|
-
const entriesToRemove = state.cache.size - serviceConfig.cacheMaxSize;
|
|
421
|
-
updateState({ cache: cacheEnforceLimit(state.cache, serviceConfig.cacheMaxSize) });
|
|
422
|
-
deps.logger.debug(`Cache eviction: removed ${entriesToRemove} entries`);
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Setup cleanup timer for retention policy
|
|
428
|
-
*/
|
|
429
|
-
const setupCleanupTimer = (): void => {
|
|
430
|
-
if (serviceConfig.retentionPolicy?.enabled && serviceConfig.retentionPolicy.cleanupInterval) {
|
|
431
|
-
const timer = setInterval(async () => {
|
|
432
|
-
try {
|
|
433
|
-
const deletedCount = await deps.repository.cleanupOldEntries(
|
|
434
|
-
serviceConfig.retentionPolicy?.maxAge
|
|
435
|
-
);
|
|
436
|
-
if (deletedCount > 0) {
|
|
437
|
-
deps.logger.info(`Automatic cleanup: removed ${deletedCount} old entries`);
|
|
438
|
-
}
|
|
439
|
-
} catch (error) {
|
|
440
|
-
deps.logger.error('Automatic cleanup failed', error);
|
|
441
|
-
}
|
|
442
|
-
}, serviceConfig.retentionPolicy.cleanupInterval);
|
|
443
|
-
updateState({ cleanupTimer: timer });
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Cleanup resources
|
|
449
|
-
*/
|
|
450
|
-
const dispose = async (): Promise<void> => {
|
|
451
|
-
if (state.cleanupTimer) {
|
|
452
|
-
clearInterval(state.cleanupTimer);
|
|
453
|
-
updateState({ cleanupTimer: undefined });
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// FUNCTIONAL: Replace cache with new empty cache instead of clearing
|
|
457
|
-
updateState({ cache: createCache() });
|
|
458
|
-
deps.logger.info('Memory service disposed');
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
// Initialize cleanup timer
|
|
462
|
-
setupCleanupTimer();
|
|
463
|
-
|
|
464
|
-
// Return service interface
|
|
465
|
-
return {
|
|
466
|
-
get,
|
|
467
|
-
set,
|
|
468
|
-
delete: deleteEntry,
|
|
469
|
-
list,
|
|
470
|
-
search,
|
|
471
|
-
clear,
|
|
472
|
-
getStats,
|
|
473
|
-
bulkSet,
|
|
474
|
-
dispose,
|
|
475
|
-
};
|
|
476
|
-
};
|
package/src/types/api/batch.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { ApiError } from './errors.js';
|
|
3
|
-
|
|
4
|
-
// ============================================================================
|
|
5
|
-
// BATCH API INTERFACES
|
|
6
|
-
// ============================================================================
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Batch API result for processing multiple operations
|
|
10
|
-
*/
|
|
11
|
-
export interface BatchApiResult<T = unknown> {
|
|
12
|
-
/** Batch operation ID */
|
|
13
|
-
batchId: string;
|
|
14
|
-
/** Total number of operations */
|
|
15
|
-
total: number;
|
|
16
|
-
/** Number of successful operations */
|
|
17
|
-
successful: number;
|
|
18
|
-
/** Number of failed operations */
|
|
19
|
-
failed: number;
|
|
20
|
-
/** Results for individual operations */
|
|
21
|
-
results: BatchOperationResult<T>[];
|
|
22
|
-
/** Batch operation metadata */
|
|
23
|
-
metadata?: {
|
|
24
|
-
/** Batch start timestamp */
|
|
25
|
-
startedAt: string;
|
|
26
|
-
/** Batch completion timestamp */
|
|
27
|
-
completedAt?: string;
|
|
28
|
-
/** Total processing time in milliseconds */
|
|
29
|
-
duration?: number;
|
|
30
|
-
/** Processing batch size */
|
|
31
|
-
batchSize?: number;
|
|
32
|
-
/** Number of concurrent operations */
|
|
33
|
-
concurrency?: number;
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Individual batch operation result
|
|
39
|
-
*/
|
|
40
|
-
export interface BatchOperationResult<T = unknown> {
|
|
41
|
-
/** Operation index in the batch */
|
|
42
|
-
index: number;
|
|
43
|
-
/** Operation ID */
|
|
44
|
-
id: string;
|
|
45
|
-
/** Operation success status */
|
|
46
|
-
success: boolean;
|
|
47
|
-
/** Operation result data */
|
|
48
|
-
data?: T;
|
|
49
|
-
/** Operation error (if failed) */
|
|
50
|
-
error?: ApiError;
|
|
51
|
-
/** Operation processing time in milliseconds */
|
|
52
|
-
processingTime?: number;
|
|
53
|
-
/** Operation retry attempts */
|
|
54
|
-
retryCount?: number;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ============================================================================
|
|
58
|
-
// ZOD SCHEMAS
|
|
59
|
-
// ============================================================================
|
|
60
|
-
|
|
61
|
-
export const BatchOperationResultSchema = z.object({
|
|
62
|
-
index: z.number().min(0),
|
|
63
|
-
id: z.string(),
|
|
64
|
-
success: z.boolean(),
|
|
65
|
-
data: z.unknown().optional(),
|
|
66
|
-
error: z
|
|
67
|
-
.object({
|
|
68
|
-
code: z.string(),
|
|
69
|
-
message: z.string(),
|
|
70
|
-
statusCode: z.number().optional(),
|
|
71
|
-
type: z.enum([
|
|
72
|
-
'validation',
|
|
73
|
-
'authentication',
|
|
74
|
-
'authorization',
|
|
75
|
-
'not_found',
|
|
76
|
-
'conflict',
|
|
77
|
-
'rate_limit',
|
|
78
|
-
'server_error',
|
|
79
|
-
'network',
|
|
80
|
-
'timeout',
|
|
81
|
-
]),
|
|
82
|
-
description: z.string().optional(),
|
|
83
|
-
fieldErrors: z.record(z.array(z.string())).optional(),
|
|
84
|
-
stack: z.string().optional(),
|
|
85
|
-
context: z.record(z.unknown()).optional(),
|
|
86
|
-
suggestions: z.array(z.string()).optional(),
|
|
87
|
-
})
|
|
88
|
-
.optional(),
|
|
89
|
-
processingTime: z.number().min(0).optional(),
|
|
90
|
-
retryCount: z.number().min(0).optional(),
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
export const BatchApiResultSchema = z.object({
|
|
94
|
-
batchId: z.string(),
|
|
95
|
-
total: z.number().min(0),
|
|
96
|
-
successful: z.number().min(0),
|
|
97
|
-
failed: z.number().min(0),
|
|
98
|
-
results: z.array(BatchOperationResultSchema),
|
|
99
|
-
metadata: z
|
|
100
|
-
.object({
|
|
101
|
-
startedAt: z.string(),
|
|
102
|
-
completedAt: z.string().optional(),
|
|
103
|
-
duration: z.number().min(0).optional(),
|
|
104
|
-
batchSize: z.number().positive().optional(),
|
|
105
|
-
concurrency: z.number().positive().optional(),
|
|
106
|
-
})
|
|
107
|
-
.optional(),
|
|
108
|
-
});
|
package/src/types/api/errors.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
// ============================================================================
|
|
4
|
-
// API ERROR INTERFACES
|
|
5
|
-
// ============================================================================
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* API error information
|
|
9
|
-
*/
|
|
10
|
-
export interface ApiError {
|
|
11
|
-
/** Error code */
|
|
12
|
-
code: string;
|
|
13
|
-
/** Error message */
|
|
14
|
-
message: string;
|
|
15
|
-
/** HTTP status code */
|
|
16
|
-
statusCode?: number;
|
|
17
|
-
/** Error type for categorization */
|
|
18
|
-
type:
|
|
19
|
-
| 'validation'
|
|
20
|
-
| 'authentication'
|
|
21
|
-
| 'authorization'
|
|
22
|
-
| 'not_found'
|
|
23
|
-
| 'conflict'
|
|
24
|
-
| 'rate_limit'
|
|
25
|
-
| 'server_error'
|
|
26
|
-
| 'network'
|
|
27
|
-
| 'timeout';
|
|
28
|
-
/** Detailed error description */
|
|
29
|
-
description?: string;
|
|
30
|
-
/** Field-specific errors (for validation errors) */
|
|
31
|
-
fieldErrors?: Record<string, string[]>;
|
|
32
|
-
/** Stack trace (development only) */
|
|
33
|
-
stack?: string;
|
|
34
|
-
/** Error context information */
|
|
35
|
-
context?: Record<string, unknown>;
|
|
36
|
-
/** Suggestions for resolution */
|
|
37
|
-
suggestions?: string[];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Enhanced error with additional context
|
|
42
|
-
*/
|
|
43
|
-
export interface EnhancedError extends Error {
|
|
44
|
-
/** Error code */
|
|
45
|
-
code: string;
|
|
46
|
-
/** HTTP status code */
|
|
47
|
-
statusCode?: number;
|
|
48
|
-
/** Error type */
|
|
49
|
-
type: ApiError['type'];
|
|
50
|
-
/** Error context */
|
|
51
|
-
context?: ErrorContext;
|
|
52
|
-
/** Suggestions for resolution */
|
|
53
|
-
suggestions?: string[];
|
|
54
|
-
/** Original error that caused this error */
|
|
55
|
-
originalError?: Error;
|
|
56
|
-
/** Timestamp when error occurred */
|
|
57
|
-
timestamp: string;
|
|
58
|
-
/** Request ID for tracing */
|
|
59
|
-
requestId?: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Error context information
|
|
64
|
-
*/
|
|
65
|
-
export interface ErrorContext {
|
|
66
|
-
/** User ID if available */
|
|
67
|
-
userId?: string;
|
|
68
|
-
/** Session ID if available */
|
|
69
|
-
sessionId?: string;
|
|
70
|
-
/** IP address if available */
|
|
71
|
-
ipAddress?: string;
|
|
72
|
-
/** User agent if available */
|
|
73
|
-
userAgent?: string;
|
|
74
|
-
/** Request path */
|
|
75
|
-
path?: string;
|
|
76
|
-
/** HTTP method */
|
|
77
|
-
method?: string;
|
|
78
|
-
/** Additional context data */
|
|
79
|
-
data?: Record<string, unknown>;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ============================================================================
|
|
83
|
-
// ZOD SCHEMAS
|
|
84
|
-
// ============================================================================
|
|
85
|
-
|
|
86
|
-
export const ErrorContextSchema = z.object({
|
|
87
|
-
userId: z.string().optional(),
|
|
88
|
-
sessionId: z.string().optional(),
|
|
89
|
-
ipAddress: z.string().optional(),
|
|
90
|
-
userAgent: z.string().optional(),
|
|
91
|
-
path: z.string().optional(),
|
|
92
|
-
method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']).optional(),
|
|
93
|
-
data: z.record(z.unknown()).optional(),
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
export const EnhancedErrorSchema = z.object({
|
|
97
|
-
name: z.string(),
|
|
98
|
-
message: z.string(),
|
|
99
|
-
code: z.string(),
|
|
100
|
-
statusCode: z.number().optional(),
|
|
101
|
-
type: z.enum([
|
|
102
|
-
'validation',
|
|
103
|
-
'authentication',
|
|
104
|
-
'authorization',
|
|
105
|
-
'not_found',
|
|
106
|
-
'conflict',
|
|
107
|
-
'rate_limit',
|
|
108
|
-
'server_error',
|
|
109
|
-
'network',
|
|
110
|
-
'timeout',
|
|
111
|
-
]),
|
|
112
|
-
context: ErrorContextSchema.optional(),
|
|
113
|
-
suggestions: z.array(z.string()).optional(),
|
|
114
|
-
originalError: z.instanceof(Error).optional(),
|
|
115
|
-
timestamp: z.string(),
|
|
116
|
-
requestId: z.string().optional(),
|
|
117
|
-
stack: z.string().optional(),
|
|
118
|
-
});
|