mcp-ts-template 2.2.4 → 2.2.7

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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +934 -88
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -117536,7 +117536,7 @@ var ErrorSchema = z.object({
117536
117536
  // package.json
117537
117537
  var package_default = {
117538
117538
  name: "mcp-ts-template",
117539
- version: "2.2.4",
117539
+ version: "2.2.5",
117540
117540
  mcpName: "io.github.cyanheads/mcp-ts-template",
117541
117541
  description: "The definitive, production-grade template for building powerful and scalable Model Context Protocol (MCP) servers with TypeScript, featuring built-in observability (OpenTelemetry), declarative tooling, robust error handling, and a modular, DI-driven architecture.",
117542
117542
  main: "dist/index.js",
@@ -117619,7 +117619,7 @@ var package_default = {
117619
117619
  jose: "^6.1.0",
117620
117620
  "js-yaml": "^4.1.0",
117621
117621
  "node-cron": "^4.2.1",
117622
- openai: "^5.23.1",
117622
+ openai: "^5.23.2",
117623
117623
  papaparse: "^5.5.3",
117624
117624
  "partial-json": "^0.1.7",
117625
117625
  pino: "^9.12.0",
@@ -117848,7 +117848,26 @@ var ConfigSchema = z.object({
117848
117848
  }
117849
117849
  return str;
117850
117850
  }, z.enum(["NONE", "ERROR", "WARN", "INFO", "DEBUG", "VERBOSE", "ALL"])).default("INFO")
117851
- })
117851
+ }),
117852
+ speech: z.object({
117853
+ tts: z.object({
117854
+ enabled: z.coerce.boolean().default(false),
117855
+ provider: z.enum(["elevenlabs"]).default("elevenlabs"),
117856
+ apiKey: z.string().optional(),
117857
+ baseUrl: z.string().url().optional(),
117858
+ defaultVoiceId: z.string().optional(),
117859
+ defaultModelId: z.string().optional(),
117860
+ timeout: z.coerce.number().optional()
117861
+ }).optional(),
117862
+ stt: z.object({
117863
+ enabled: z.coerce.boolean().default(false),
117864
+ provider: z.enum(["openai-whisper"]).default("openai-whisper"),
117865
+ apiKey: z.string().optional(),
117866
+ baseUrl: z.string().url().optional(),
117867
+ defaultModelId: z.string().optional(),
117868
+ timeout: z.coerce.number().optional()
117869
+ }).optional()
117870
+ }).optional()
117852
117871
  });
117853
117872
  var parseConfig = () => {
117854
117873
  const env = process.env;
@@ -117915,6 +117934,25 @@ var parseConfig = () => {
117915
117934
  samplingRatio: env.OTEL_TRACES_SAMPLER_ARG,
117916
117935
  logLevel: env.OTEL_LOG_LEVEL
117917
117936
  },
117937
+ speech: env.SPEECH_TTS_ENABLED || env.SPEECH_STT_ENABLED ? {
117938
+ tts: env.SPEECH_TTS_ENABLED ? {
117939
+ enabled: env.SPEECH_TTS_ENABLED,
117940
+ provider: env.SPEECH_TTS_PROVIDER,
117941
+ apiKey: env.SPEECH_TTS_API_KEY,
117942
+ baseUrl: env.SPEECH_TTS_BASE_URL,
117943
+ defaultVoiceId: env.SPEECH_TTS_DEFAULT_VOICE_ID,
117944
+ defaultModelId: env.SPEECH_TTS_DEFAULT_MODEL_ID,
117945
+ timeout: env.SPEECH_TTS_TIMEOUT
117946
+ } : undefined,
117947
+ stt: env.SPEECH_STT_ENABLED ? {
117948
+ enabled: env.SPEECH_STT_ENABLED,
117949
+ provider: env.SPEECH_STT_PROVIDER,
117950
+ apiKey: env.SPEECH_STT_API_KEY,
117951
+ baseUrl: env.SPEECH_STT_BASE_URL,
117952
+ defaultModelId: env.SPEECH_STT_DEFAULT_MODEL_ID,
117953
+ timeout: env.SPEECH_STT_TIMEOUT
117954
+ } : undefined
117955
+ } : undefined,
117918
117956
  mcpServerName: env.MCP_SERVER_NAME,
117919
117957
  mcpServerVersion: env.MCP_SERVER_VERSION,
117920
117958
  mcpServerDescription: env.MCP_SERVER_DESCRIPTION
@@ -119310,6 +119348,7 @@ var CreateMcpServerInstance = Symbol("CreateMcpServerInstance");
119310
119348
  var RateLimiterService = Symbol("RateLimiterService");
119311
119349
  var TransportManagerToken = Symbol("TransportManager");
119312
119350
  var SupabaseAdminClient = Symbol("SupabaseAdminClient");
119351
+ var SpeechService = Symbol("SpeechService");
119313
119352
 
119314
119353
  // src/utils/security/rateLimiter.ts
119315
119354
  class RateLimiter {
@@ -119510,10 +119549,10 @@ async function fetchWithTimeout(url, timeoutMs, context, options) {
119510
119549
 
119511
119550
  // src/container/index.ts
119512
119551
  var import_reflect_metadata = __toESM(require_Reflect(), 1);
119513
- var import_tsyringe17 = __toESM(require_cjs3(), 1);
119552
+ var import_tsyringe19 = __toESM(require_cjs3(), 1);
119514
119553
 
119515
119554
  // src/container/registrations/core.ts
119516
- var import_tsyringe6 = __toESM(require_cjs3(), 1);
119555
+ var import_tsyringe8 = __toESM(require_cjs3(), 1);
119517
119556
  var import_supabase_js2 = __toESM(require_main6(), 1);
119518
119557
 
119519
119558
  // node_modules/openai/internal/tslib.mjs
@@ -119744,7 +119783,7 @@ var safeJSON = (text) => {
119744
119783
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
119745
119784
 
119746
119785
  // node_modules/openai/version.mjs
119747
- var VERSION = "5.23.1";
119786
+ var VERSION = "5.23.2";
119748
119787
 
119749
119788
  // node_modules/openai/internal/detect-platform.mjs
119750
119789
  var isRunningInBrowser = () => {
@@ -125145,8 +125184,378 @@ OpenRouterProvider = __legacyDecorateClassTS([
125145
125184
  ])
125146
125185
  ], OpenRouterProvider);
125147
125186
 
125148
- // src/storage/core/StorageService.ts
125187
+ // src/services/speech/providers/elevenlabs.provider.ts
125149
125188
  var import_tsyringe3 = __toESM(require_cjs3(), 1);
125189
+ class ElevenLabsProvider {
125190
+ name = "elevenlabs";
125191
+ supportsTTS = true;
125192
+ supportsSTT = false;
125193
+ apiKey;
125194
+ baseUrl;
125195
+ defaultVoiceId;
125196
+ defaultModelId;
125197
+ timeout;
125198
+ constructor(config2) {
125199
+ if (!config2.apiKey) {
125200
+ throw new McpError(-32602 /* InvalidParams */, "ElevenLabs API key is required");
125201
+ }
125202
+ this.apiKey = config2.apiKey;
125203
+ this.baseUrl = config2.baseUrl || "https://api.elevenlabs.io/v1";
125204
+ this.defaultVoiceId = config2.defaultVoiceId || "EXAVITQu4vr4xnSDxMaL";
125205
+ this.defaultModelId = config2.defaultModelId || "eleven_monolingual_v1";
125206
+ this.timeout = config2.timeout || 30000;
125207
+ logger.info(`ElevenLabs TTS provider initialized: ${this.baseUrl}, voice=${this.defaultVoiceId}`);
125208
+ }
125209
+ async textToSpeech(options) {
125210
+ const context = requestContextService.createRequestContext({
125211
+ operation: "elevenlabs-tts",
125212
+ ...options.context || {}
125213
+ });
125214
+ const voiceId = options.voice?.voiceId || this.defaultVoiceId;
125215
+ const modelId = options.modelId || this.defaultModelId;
125216
+ logger.debug("Converting text to speech with ElevenLabs", context);
125217
+ if (!options.text || options.text.trim().length === 0) {
125218
+ throw new McpError(-32602 /* InvalidParams */, "Text cannot be empty", context);
125219
+ }
125220
+ if (options.text.length > 5000) {
125221
+ throw new McpError(-32602 /* InvalidParams */, "Text exceeds maximum length of 5000 characters", context);
125222
+ }
125223
+ const url = `${this.baseUrl}/text-to-speech/${voiceId}`;
125224
+ const voiceSettings = {
125225
+ stability: options.voice?.stability ?? 0.5,
125226
+ similarity_boost: options.voice?.similarityBoost ?? 0.75,
125227
+ style: options.voice?.style ?? 0,
125228
+ use_speaker_boost: true
125229
+ };
125230
+ const requestBody = {
125231
+ text: options.text,
125232
+ model_id: modelId,
125233
+ voice_settings: voiceSettings
125234
+ };
125235
+ try {
125236
+ const response = await fetchWithTimeout(url, this.timeout, context, {
125237
+ method: "POST",
125238
+ headers: {
125239
+ "Content-Type": "application/json",
125240
+ "xi-api-key": this.apiKey
125241
+ },
125242
+ body: JSON.stringify(requestBody)
125243
+ });
125244
+ if (!response.ok) {
125245
+ const errorText = await response.text();
125246
+ logger.error(`ElevenLabs API error: ${response.status}`, context);
125247
+ throw new McpError(-32603 /* InternalError */, `ElevenLabs API error: ${response.status} - ${errorText}`, context);
125248
+ }
125249
+ const audioBuffer = Buffer.from(await response.arrayBuffer());
125250
+ logger.info(`Text-to-speech conversion successful (voice=${voiceId}, ${audioBuffer.length} bytes)`, context);
125251
+ return {
125252
+ audio: audioBuffer,
125253
+ format: "mp3",
125254
+ characterCount: options.text.length,
125255
+ metadata: {
125256
+ voiceId,
125257
+ modelId,
125258
+ provider: this.name
125259
+ }
125260
+ };
125261
+ } catch (error2) {
125262
+ if (error2 instanceof McpError) {
125263
+ throw error2;
125264
+ }
125265
+ logger.error("Failed to convert text to speech", error2 instanceof Error ? error2 : new Error(String(error2)), context);
125266
+ throw new McpError(-32603 /* InternalError */, `Failed to convert text to speech: ${error2 instanceof Error ? error2.message : "Unknown error"}`, context);
125267
+ }
125268
+ }
125269
+ speechToText(_options) {
125270
+ throw new McpError(-32601 /* MethodNotFound */, "Speech-to-text is not supported by ElevenLabs provider");
125271
+ }
125272
+ async getVoices() {
125273
+ const context = requestContextService.createRequestContext({
125274
+ operation: "elevenlabs-getVoices"
125275
+ });
125276
+ logger.debug("Fetching available voices from ElevenLabs", context);
125277
+ const url = `${this.baseUrl}/voices`;
125278
+ try {
125279
+ const response = await fetchWithTimeout(url, this.timeout, context, {
125280
+ method: "GET",
125281
+ headers: {
125282
+ "xi-api-key": this.apiKey
125283
+ }
125284
+ });
125285
+ if (!response.ok) {
125286
+ const errorText = await response.text();
125287
+ logger.error(`Failed to fetch voices: ${response.status}`, context);
125288
+ throw new McpError(-32603 /* InternalError */, `Failed to fetch voices: ${response.status} - ${errorText}`);
125289
+ }
125290
+ const data = await response.json();
125291
+ const voices = data.voices.map((v) => ({
125292
+ id: v.voice_id,
125293
+ name: v.name,
125294
+ ...v.description !== undefined && { description: v.description },
125295
+ ...v.category !== undefined && { category: v.category },
125296
+ ...v.preview_url !== undefined && { previewUrl: v.preview_url },
125297
+ ...v.labels?.gender !== undefined && {
125298
+ gender: v.labels.gender
125299
+ },
125300
+ metadata: {
125301
+ labels: v.labels
125302
+ }
125303
+ }));
125304
+ logger.info(`Successfully fetched ${voices.length} voices`, context);
125305
+ return voices;
125306
+ } catch (error2) {
125307
+ if (error2 instanceof McpError) {
125308
+ throw error2;
125309
+ }
125310
+ logger.error("Failed to fetch voices", error2 instanceof Error ? error2 : new Error(String(error2)), context);
125311
+ throw new McpError(-32603 /* InternalError */, `Failed to fetch voices: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
125312
+ }
125313
+ }
125314
+ async healthCheck() {
125315
+ try {
125316
+ await this.getVoices();
125317
+ return true;
125318
+ } catch (error2) {
125319
+ const context = requestContextService.createRequestContext({
125320
+ operation: "elevenlabs-healthCheck"
125321
+ });
125322
+ logger.error("ElevenLabs health check failed", error2 instanceof Error ? error2 : new Error(String(error2)), context);
125323
+ return false;
125324
+ }
125325
+ }
125326
+ }
125327
+ ElevenLabsProvider = __legacyDecorateClassTS([
125328
+ import_tsyringe3.injectable(),
125329
+ __legacyMetadataTS("design:paramtypes", [
125330
+ typeof SpeechProviderConfig === "undefined" ? Object : SpeechProviderConfig
125331
+ ])
125332
+ ], ElevenLabsProvider);
125333
+
125334
+ // src/services/speech/providers/whisper.provider.ts
125335
+ var import_tsyringe4 = __toESM(require_cjs3(), 1);
125336
+ class WhisperProvider {
125337
+ name = "openai-whisper";
125338
+ supportsTTS = false;
125339
+ supportsSTT = true;
125340
+ apiKey;
125341
+ baseUrl;
125342
+ defaultModelId;
125343
+ timeout;
125344
+ constructor(config2) {
125345
+ if (!config2.apiKey) {
125346
+ throw new McpError(-32602 /* InvalidParams */, "OpenAI API key is required");
125347
+ }
125348
+ this.apiKey = config2.apiKey;
125349
+ this.baseUrl = config2.baseUrl || "https://api.openai.com/v1";
125350
+ this.defaultModelId = config2.defaultModelId || "whisper-1";
125351
+ this.timeout = config2.timeout || 60000;
125352
+ logger.info(`OpenAI Whisper STT provider initialized: ${this.baseUrl}, model=${this.defaultModelId}`);
125353
+ }
125354
+ textToSpeech(_options) {
125355
+ throw new McpError(-32601 /* MethodNotFound */, "Text-to-speech is not supported by Whisper provider");
125356
+ }
125357
+ async speechToText(options) {
125358
+ const context = requestContextService.createRequestContext({
125359
+ operation: "whisper-stt",
125360
+ ...options.context || {}
125361
+ });
125362
+ const modelId = options.modelId || this.defaultModelId;
125363
+ logger.debug("Converting speech to text with Whisper", context);
125364
+ if (!options.audio) {
125365
+ throw new McpError(-32602 /* InvalidParams */, "Audio data is required", context);
125366
+ }
125367
+ let audioBuffer;
125368
+ if (typeof options.audio === "string") {
125369
+ try {
125370
+ audioBuffer = Buffer.from(options.audio, "base64");
125371
+ } catch (_error) {
125372
+ throw new McpError(-32602 /* InvalidParams */, "Invalid base64 audio data", context);
125373
+ }
125374
+ } else {
125375
+ audioBuffer = options.audio;
125376
+ }
125377
+ const maxSize = 25 * 1024 * 1024;
125378
+ if (audioBuffer.length > maxSize) {
125379
+ throw new McpError(-32602 /* InvalidParams */, `Audio file exceeds maximum size of 25MB (got ${Math.round(audioBuffer.length / 1024 / 1024)}MB)`, context);
125380
+ }
125381
+ const url = `${this.baseUrl}/audio/transcriptions`;
125382
+ const formData = new FormData;
125383
+ const extension = this.getFileExtension(options.format);
125384
+ const blob = new Blob([audioBuffer], {
125385
+ type: this.getMimeType(options.format)
125386
+ });
125387
+ formData.append("file", blob, `audio.${extension}`);
125388
+ formData.append("model", modelId);
125389
+ if (options.language) {
125390
+ formData.append("language", options.language);
125391
+ }
125392
+ if (options.temperature !== undefined) {
125393
+ formData.append("temperature", options.temperature.toString());
125394
+ }
125395
+ if (options.prompt) {
125396
+ formData.append("prompt", options.prompt);
125397
+ }
125398
+ formData.append("response_format", options.timestamps ? "verbose_json" : "json");
125399
+ if (options.timestamps) {
125400
+ formData.append("timestamp_granularities[]", "word");
125401
+ }
125402
+ try {
125403
+ const response = await fetchWithTimeout(url, this.timeout, context, {
125404
+ method: "POST",
125405
+ headers: {
125406
+ Authorization: `Bearer ${this.apiKey}`
125407
+ },
125408
+ body: formData
125409
+ });
125410
+ if (!response.ok) {
125411
+ const errorText = await response.text();
125412
+ logger.error(`Whisper API error: ${response.status}`, context);
125413
+ throw new McpError(-32603 /* InternalError */, `Whisper API error: ${response.status} - ${errorText}`, context);
125414
+ }
125415
+ const data = await response.json();
125416
+ const words = data.words?.map((w) => ({
125417
+ word: w.word,
125418
+ start: w.start,
125419
+ end: w.end
125420
+ }));
125421
+ logger.info(`Speech-to-text transcription successful (${data.text.length} chars)`, context);
125422
+ return {
125423
+ text: data.text,
125424
+ ...data.language !== undefined && { language: data.language },
125425
+ ...data.duration !== undefined && { duration: data.duration },
125426
+ ...words !== undefined && { words },
125427
+ metadata: {
125428
+ modelId,
125429
+ provider: this.name,
125430
+ ...data.task !== undefined && { task: data.task }
125431
+ }
125432
+ };
125433
+ } catch (error2) {
125434
+ if (error2 instanceof McpError) {
125435
+ throw error2;
125436
+ }
125437
+ logger.error("Failed to transcribe audio", error2 instanceof Error ? error2 : new Error(String(error2)), context);
125438
+ throw new McpError(-32603 /* InternalError */, `Failed to transcribe audio: ${error2 instanceof Error ? error2.message : "Unknown error"}`, context);
125439
+ }
125440
+ }
125441
+ getVoices() {
125442
+ throw new McpError(-32601 /* MethodNotFound */, "Voice listing is not supported by Whisper provider (STT only)");
125443
+ }
125444
+ async healthCheck() {
125445
+ try {
125446
+ const context = requestContextService.createRequestContext({
125447
+ operation: "whisper-healthCheck"
125448
+ });
125449
+ const response = await fetchWithTimeout(`${this.baseUrl}/models`, 5000, context, {
125450
+ method: "GET",
125451
+ headers: {
125452
+ Authorization: `Bearer ${this.apiKey}`
125453
+ }
125454
+ });
125455
+ return response.ok;
125456
+ } catch (error2) {
125457
+ const context = requestContextService.createRequestContext({
125458
+ operation: "whisper-healthCheck"
125459
+ });
125460
+ logger.error("Whisper health check failed", error2 instanceof Error ? error2 : new Error(String(error2)), context);
125461
+ return false;
125462
+ }
125463
+ }
125464
+ getFileExtension(format) {
125465
+ const formatMap = {
125466
+ mp3: "mp3",
125467
+ wav: "wav",
125468
+ ogg: "ogg",
125469
+ flac: "flac",
125470
+ webm: "webm",
125471
+ m4a: "m4a"
125472
+ };
125473
+ return format && formatMap[format] ? formatMap[format] : "mp3";
125474
+ }
125475
+ getMimeType(format) {
125476
+ const mimeMap = {
125477
+ mp3: "audio/mpeg",
125478
+ wav: "audio/wav",
125479
+ ogg: "audio/ogg",
125480
+ flac: "audio/flac",
125481
+ webm: "audio/webm",
125482
+ m4a: "audio/mp4"
125483
+ };
125484
+ return format && mimeMap[format] ? mimeMap[format] : "audio/mpeg";
125485
+ }
125486
+ }
125487
+ WhisperProvider = __legacyDecorateClassTS([
125488
+ import_tsyringe4.injectable(),
125489
+ __legacyMetadataTS("design:paramtypes", [
125490
+ typeof SpeechProviderConfig === "undefined" ? Object : SpeechProviderConfig
125491
+ ])
125492
+ ], WhisperProvider);
125493
+
125494
+ // src/services/speech/index.ts
125495
+ function createSpeechProvider(config2) {
125496
+ logger.debug(`Creating speech provider: ${config2.provider}`);
125497
+ switch (config2.provider) {
125498
+ case "elevenlabs":
125499
+ return new ElevenLabsProvider(config2);
125500
+ case "openai-whisper":
125501
+ return new WhisperProvider(config2);
125502
+ case "mock":
125503
+ throw new McpError(-32602 /* InvalidParams */, "Mock provider not yet implemented");
125504
+ default: {
125505
+ const _exhaustive = config2.provider;
125506
+ throw new McpError(-32602 /* InvalidParams */, `Unknown speech provider: ${String(_exhaustive)}`);
125507
+ }
125508
+ }
125509
+ }
125510
+
125511
+ class SpeechService2 {
125512
+ ttsProvider;
125513
+ sttProvider;
125514
+ constructor(ttsConfig, sttConfig) {
125515
+ if (ttsConfig) {
125516
+ this.ttsProvider = createSpeechProvider(ttsConfig);
125517
+ if (!this.ttsProvider.supportsTTS) {
125518
+ logger.warning(`TTS provider ${ttsConfig.provider} does not support text-to-speech`);
125519
+ }
125520
+ }
125521
+ if (sttConfig) {
125522
+ this.sttProvider = createSpeechProvider(sttConfig);
125523
+ if (!this.sttProvider.supportsSTT) {
125524
+ logger.warning(`STT provider ${sttConfig.provider} does not support speech-to-text`);
125525
+ }
125526
+ }
125527
+ logger.info(`Speech service initialized: TTS=${this.ttsProvider?.name ?? "none"}, STT=${this.sttProvider?.name ?? "none"}`);
125528
+ }
125529
+ getTTSProvider() {
125530
+ if (!this.ttsProvider) {
125531
+ throw new McpError(-32600 /* InvalidRequest */, "No TTS provider configured");
125532
+ }
125533
+ return this.ttsProvider;
125534
+ }
125535
+ getSTTProvider() {
125536
+ if (!this.sttProvider) {
125537
+ throw new McpError(-32600 /* InvalidRequest */, "No STT provider configured");
125538
+ }
125539
+ return this.sttProvider;
125540
+ }
125541
+ hasTTS() {
125542
+ return this.ttsProvider?.supportsTTS ?? false;
125543
+ }
125544
+ hasSTT() {
125545
+ return this.sttProvider?.supportsSTT ?? false;
125546
+ }
125547
+ async healthCheck() {
125548
+ const ttsHealth = this.ttsProvider ? await this.ttsProvider.healthCheck() : false;
125549
+ const sttHealth = this.sttProvider ? await this.sttProvider.healthCheck() : false;
125550
+ return {
125551
+ tts: ttsHealth,
125552
+ stt: sttHealth
125553
+ };
125554
+ }
125555
+ }
125556
+
125557
+ // src/storage/core/StorageService.ts
125558
+ var import_tsyringe5 = __toESM(require_cjs3(), 1);
125150
125559
  function requireTenantId(context) {
125151
125560
  if (!context.tenantId) {
125152
125561
  throw new McpError(-32603 /* InternalError */, "Tenant ID is required for storage operations but was not found in the request context.", {
@@ -125174,26 +125583,43 @@ class StorageService2 {
125174
125583
  const tenantId = requireTenantId(context);
125175
125584
  return this.provider.delete(tenantId, key, context);
125176
125585
  }
125177
- list(prefix, context) {
125586
+ list(prefix, context, options) {
125587
+ const tenantId = requireTenantId(context);
125588
+ return this.provider.list(tenantId, prefix, context, options);
125589
+ }
125590
+ getMany(keys, context) {
125591
+ const tenantId = requireTenantId(context);
125592
+ return this.provider.getMany(tenantId, keys, context);
125593
+ }
125594
+ setMany(entries, context, options) {
125178
125595
  const tenantId = requireTenantId(context);
125179
- return this.provider.list(tenantId, prefix, context);
125596
+ return this.provider.setMany(tenantId, entries, context, options);
125597
+ }
125598
+ deleteMany(keys, context) {
125599
+ const tenantId = requireTenantId(context);
125600
+ return this.provider.deleteMany(tenantId, keys, context);
125601
+ }
125602
+ clear(context) {
125603
+ const tenantId = requireTenantId(context);
125604
+ return this.provider.clear(tenantId, context);
125180
125605
  }
125181
125606
  }
125182
125607
  StorageService2 = __legacyDecorateClassTS([
125183
- import_tsyringe3.injectable(),
125184
- __legacyDecorateParamTS(0, import_tsyringe3.inject(StorageProvider)),
125608
+ import_tsyringe5.injectable(),
125609
+ __legacyDecorateParamTS(0, import_tsyringe5.inject(StorageProvider)),
125185
125610
  __legacyMetadataTS("design:paramtypes", [
125186
125611
  typeof IStorageProvider === "undefined" ? Object : IStorageProvider
125187
125612
  ])
125188
125613
  ], StorageService2);
125189
125614
 
125190
125615
  // src/storage/core/storageFactory.ts
125191
- var import_tsyringe5 = __toESM(require_cjs3(), 1);
125616
+ var import_tsyringe7 = __toESM(require_cjs3(), 1);
125192
125617
 
125193
125618
  // src/storage/providers/fileSystem/fileSystemProvider.ts
125194
125619
  import { existsSync, mkdirSync } from "fs";
125195
125620
  import { readFile, readdir, rm, writeFile } from "fs/promises";
125196
125621
  import path2 from "path";
125622
+ var DEFAULT_LIST_LIMIT = 1000;
125197
125623
  var FILE_ENVELOPE_VERSION = 1;
125198
125624
 
125199
125625
  class FileSystemProvider {
@@ -125321,7 +125747,7 @@ class FileSystemProvider {
125321
125747
  }
125322
125748
  return results;
125323
125749
  }
125324
- async list(tenantId, prefix, context) {
125750
+ async list(tenantId, prefix, context, options) {
125325
125751
  return ErrorHandler.tryCatch(async () => {
125326
125752
  const tenantPath = this.getTenantPath(tenantId);
125327
125753
  const allKeys = await this.listFilesRecursively(tenantPath, tenantPath);
@@ -125339,16 +125765,93 @@ class FileSystemProvider {
125339
125765
  continue;
125340
125766
  }
125341
125767
  }
125342
- return validKeys;
125768
+ validKeys.sort();
125769
+ const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT;
125770
+ let startIndex = 0;
125771
+ if (options?.cursor) {
125772
+ const cursorIndex = validKeys.indexOf(options.cursor);
125773
+ if (cursorIndex !== -1) {
125774
+ startIndex = cursorIndex + 1;
125775
+ }
125776
+ }
125777
+ const paginatedKeys = validKeys.slice(startIndex, startIndex + limit2);
125778
+ const nextCursor = startIndex + limit2 < validKeys.length ? paginatedKeys[paginatedKeys.length - 1] : undefined;
125779
+ return {
125780
+ keys: paginatedKeys,
125781
+ nextCursor
125782
+ };
125343
125783
  }, {
125344
125784
  operation: "FileSystemProvider.list",
125345
125785
  context,
125346
125786
  input: { tenantId, prefix }
125347
125787
  });
125348
125788
  }
125789
+ async getMany(tenantId, keys, context) {
125790
+ return ErrorHandler.tryCatch(async () => {
125791
+ const results = new Map;
125792
+ for (const key of keys) {
125793
+ const value = await this.get(tenantId, key, context);
125794
+ if (value !== null) {
125795
+ results.set(key, value);
125796
+ }
125797
+ }
125798
+ return results;
125799
+ }, {
125800
+ operation: "FileSystemProvider.getMany",
125801
+ context,
125802
+ input: { tenantId, keyCount: keys.length }
125803
+ });
125804
+ }
125805
+ async setMany(tenantId, entries, context, options) {
125806
+ return ErrorHandler.tryCatch(async () => {
125807
+ for (const [key, value] of entries.entries()) {
125808
+ await this.set(tenantId, key, value, context, options);
125809
+ }
125810
+ }, {
125811
+ operation: "FileSystemProvider.setMany",
125812
+ context,
125813
+ input: { tenantId, entryCount: entries.size }
125814
+ });
125815
+ }
125816
+ async deleteMany(tenantId, keys, context) {
125817
+ return ErrorHandler.tryCatch(async () => {
125818
+ let deletedCount = 0;
125819
+ for (const key of keys) {
125820
+ const deleted = await this.delete(tenantId, key, context);
125821
+ if (deleted) {
125822
+ deletedCount++;
125823
+ }
125824
+ }
125825
+ return deletedCount;
125826
+ }, {
125827
+ operation: "FileSystemProvider.deleteMany",
125828
+ context,
125829
+ input: { tenantId, keyCount: keys.length }
125830
+ });
125831
+ }
125832
+ async clear(tenantId, context) {
125833
+ return ErrorHandler.tryCatch(async () => {
125834
+ const tenantPath = this.getTenantPath(tenantId);
125835
+ const allKeys = await this.listFilesRecursively(tenantPath, tenantPath);
125836
+ let deletedCount = 0;
125837
+ for (const key of allKeys) {
125838
+ const deleted = await this.delete(tenantId, key, context);
125839
+ if (deleted) {
125840
+ deletedCount++;
125841
+ }
125842
+ }
125843
+ return deletedCount;
125844
+ }, {
125845
+ operation: "FileSystemProvider.clear",
125846
+ context,
125847
+ input: { tenantId }
125848
+ });
125849
+ }
125349
125850
  }
125350
125851
 
125351
125852
  // src/storage/providers/inMemory/inMemoryProvider.ts
125853
+ var DEFAULT_LIST_LIMIT2 = 1000;
125854
+
125352
125855
  class InMemoryProvider {
125353
125856
  store = new Map;
125354
125857
  getTenantStore(tenantId) {
@@ -125388,28 +125891,79 @@ class InMemoryProvider {
125388
125891
  const tenantStore = this.getTenantStore(tenantId);
125389
125892
  return Promise.resolve(tenantStore.delete(key));
125390
125893
  }
125391
- list(tenantId, prefix, context) {
125392
- logger.debug(`[InMemoryProvider] Listing keys with prefix: ${prefix} for tenant: ${tenantId}`, context);
125894
+ list(tenantId, prefix, context, options) {
125895
+ logger.debug(`[InMemoryProvider] Listing keys with prefix: ${prefix} for tenant: ${tenantId}`, { ...context, options });
125393
125896
  const tenantStore = this.getTenantStore(tenantId);
125394
125897
  const now = Date.now();
125395
- const keys = [];
125898
+ const allKeys = [];
125396
125899
  for (const [key, entry] of tenantStore.entries()) {
125397
125900
  if (key.startsWith(prefix)) {
125398
125901
  if (entry.expiresAt && now > entry.expiresAt) {
125399
125902
  tenantStore.delete(key);
125400
125903
  } else {
125401
- keys.push(key);
125904
+ allKeys.push(key);
125402
125905
  }
125403
125906
  }
125404
125907
  }
125405
- return Promise.resolve(keys);
125908
+ allKeys.sort();
125909
+ const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT2;
125910
+ let startIndex = 0;
125911
+ if (options?.cursor) {
125912
+ const cursorIndex = allKeys.indexOf(options.cursor);
125913
+ if (cursorIndex !== -1) {
125914
+ startIndex = cursorIndex + 1;
125915
+ }
125916
+ }
125917
+ const paginatedKeys = allKeys.slice(startIndex, startIndex + limit2);
125918
+ const nextCursor = startIndex + limit2 < allKeys.length ? paginatedKeys[paginatedKeys.length - 1] : undefined;
125919
+ return Promise.resolve({
125920
+ keys: paginatedKeys,
125921
+ nextCursor
125922
+ });
125923
+ }
125924
+ async getMany(tenantId, keys, context) {
125925
+ logger.debug(`[InMemoryProvider] Getting ${keys.length} keys for tenant: ${tenantId}`, context);
125926
+ const results = new Map;
125927
+ for (const key of keys) {
125928
+ const value = await this.get(tenantId, key, context);
125929
+ if (value !== null) {
125930
+ results.set(key, value);
125931
+ }
125932
+ }
125933
+ return results;
125934
+ }
125935
+ async setMany(tenantId, entries, context, options) {
125936
+ logger.debug(`[InMemoryProvider] Setting ${entries.size} keys for tenant: ${tenantId}`, context);
125937
+ for (const [key, value] of entries.entries()) {
125938
+ await this.set(tenantId, key, value, context, options);
125939
+ }
125940
+ }
125941
+ async deleteMany(tenantId, keys, context) {
125942
+ logger.debug(`[InMemoryProvider] Deleting ${keys.length} keys for tenant: ${tenantId}`, context);
125943
+ let deletedCount = 0;
125944
+ for (const key of keys) {
125945
+ const deleted = await this.delete(tenantId, key, context);
125946
+ if (deleted) {
125947
+ deletedCount++;
125948
+ }
125949
+ }
125950
+ return deletedCount;
125951
+ }
125952
+ clear(tenantId, context) {
125953
+ logger.debug(`[InMemoryProvider] Clearing all keys for tenant: ${tenantId}`, context);
125954
+ const tenantStore = this.getTenantStore(tenantId);
125955
+ const count = tenantStore.size;
125956
+ tenantStore.clear();
125957
+ logger.info(`[InMemoryProvider] Cleared ${count} keys for tenant: ${tenantId}`, context);
125958
+ return Promise.resolve(count);
125406
125959
  }
125407
125960
  }
125408
125961
 
125409
125962
  // src/storage/providers/supabase/supabaseProvider.ts
125410
- var import_tsyringe4 = __toESM(require_cjs3(), 1);
125963
+ var import_tsyringe6 = __toESM(require_cjs3(), 1);
125411
125964
  var import_supabase_js = __toESM(require_main6(), 1);
125412
125965
  var TABLE_NAME = "kv_store";
125966
+ var DEFAULT_LIST_LIMIT3 = 1000;
125413
125967
 
125414
125968
  class SupabaseProvider {
125415
125969
  client;
@@ -125469,23 +126023,107 @@ class SupabaseProvider {
125469
126023
  input: { tenantId, key }
125470
126024
  });
125471
126025
  }
125472
- async list(tenantId, prefix, context) {
126026
+ async list(tenantId, prefix, context, options) {
125473
126027
  return ErrorHandler.tryCatch(async () => {
125474
126028
  const now = new Date().toISOString();
125475
- const { data, error: error2 } = await this.getClient().from(TABLE_NAME).select("key").eq("tenant_id", tenantId).like("key", `${prefix}%`).or(`expires_at.is.null,expires_at.gt.${now}`);
126029
+ const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT3;
126030
+ let query = this.getClient().from(TABLE_NAME).select("key").eq("tenant_id", tenantId).like("key", `${prefix}%`).or(`expires_at.is.null,expires_at.gt.${now}`).order("key", { ascending: true }).limit(limit2 + 1);
126031
+ if (options?.cursor) {
126032
+ query = query.gt("key", options.cursor);
126033
+ }
126034
+ const { data, error: error2 } = await query;
125476
126035
  if (error2)
125477
126036
  throw error2;
125478
- return data?.map((item) => item.key) ?? [];
126037
+ const keys = data?.map((item) => item.key) ?? [];
126038
+ const hasMore = keys.length > limit2;
126039
+ const resultKeys = hasMore ? keys.slice(0, limit2) : keys;
126040
+ const nextCursor = hasMore ? resultKeys[resultKeys.length - 1] : undefined;
126041
+ return {
126042
+ keys: resultKeys,
126043
+ nextCursor
126044
+ };
125479
126045
  }, {
125480
126046
  operation: "SupabaseProvider.list",
125481
126047
  context,
125482
- input: { tenantId, prefix }
126048
+ input: { tenantId, prefix, options }
126049
+ });
126050
+ }
126051
+ async getMany(tenantId, keys, context) {
126052
+ return ErrorHandler.tryCatch(async () => {
126053
+ if (keys.length === 0) {
126054
+ return new Map;
126055
+ }
126056
+ const { data, error: error2 } = await this.getClient().from(TABLE_NAME).select("key, value, expires_at").eq("tenant_id", tenantId).in("key", keys);
126057
+ if (error2)
126058
+ throw error2;
126059
+ const results = new Map;
126060
+ for (const row of data ?? []) {
126061
+ if (!row.expires_at || new Date(row.expires_at).getTime() >= Date.now()) {
126062
+ results.set(row.key, row.value);
126063
+ } else {
126064
+ await this.delete(tenantId, row.key, context);
126065
+ }
126066
+ }
126067
+ return results;
126068
+ }, {
126069
+ operation: "SupabaseProvider.getMany",
126070
+ context,
126071
+ input: { tenantId, keyCount: keys.length }
126072
+ });
126073
+ }
126074
+ async setMany(tenantId, entries, context, options) {
126075
+ return ErrorHandler.tryCatch(async () => {
126076
+ if (entries.size === 0) {
126077
+ return;
126078
+ }
126079
+ const expires_at = options?.ttl ? new Date(Date.now() + options.ttl * 1000).toISOString() : null;
126080
+ const rows = Array.from(entries.entries()).map(([key, value]) => ({
126081
+ tenant_id: tenantId,
126082
+ key,
126083
+ value,
126084
+ expires_at
126085
+ }));
126086
+ const { error: error2 } = await this.getClient().from(TABLE_NAME).upsert(rows);
126087
+ if (error2)
126088
+ throw error2;
126089
+ }, {
126090
+ operation: "SupabaseProvider.setMany",
126091
+ context,
126092
+ input: { tenantId, entryCount: entries.size }
126093
+ });
126094
+ }
126095
+ async deleteMany(tenantId, keys, context) {
126096
+ return ErrorHandler.tryCatch(async () => {
126097
+ if (keys.length === 0) {
126098
+ return 0;
126099
+ }
126100
+ const { error: error2, count } = await this.getClient().from(TABLE_NAME).delete({ count: "exact" }).eq("tenant_id", tenantId).in("key", keys);
126101
+ if (error2)
126102
+ throw error2;
126103
+ return count ?? 0;
126104
+ }, {
126105
+ operation: "SupabaseProvider.deleteMany",
126106
+ context,
126107
+ input: { tenantId, keyCount: keys.length }
126108
+ });
126109
+ }
126110
+ async clear(tenantId, context) {
126111
+ return ErrorHandler.tryCatch(async () => {
126112
+ const { error: error2, count } = await this.getClient().from(TABLE_NAME).delete({ count: "exact" }).eq("tenant_id", tenantId);
126113
+ if (error2)
126114
+ throw error2;
126115
+ logger.info(`[SupabaseProvider] Cleared ${count ?? 0} keys for tenant: ${tenantId}`, context);
126116
+ return count ?? 0;
126117
+ }, {
126118
+ operation: "SupabaseProvider.clear",
126119
+ context,
126120
+ input: { tenantId }
125483
126121
  });
125484
126122
  }
125485
126123
  }
125486
126124
  SupabaseProvider = __legacyDecorateClassTS([
125487
- import_tsyringe4.injectable(),
125488
- __legacyDecorateParamTS(0, import_tsyringe4.inject(SupabaseAdminClient)),
126125
+ import_tsyringe6.injectable(),
126126
+ __legacyDecorateParamTS(0, import_tsyringe6.inject(SupabaseAdminClient)),
125489
126127
  __legacyMetadataTS("design:paramtypes", [
125490
126128
  typeof import_supabase_js.SupabaseClient === "undefined" ? Object : import_supabase_js.SupabaseClient
125491
126129
  ])
@@ -125493,10 +126131,14 @@ SupabaseProvider = __legacyDecorateClassTS([
125493
126131
 
125494
126132
  // src/storage/providers/cloudflare/r2Provider.ts
125495
126133
  var R2_ENVELOPE_VERSION = 1;
126134
+ var DEFAULT_LIST_LIMIT4 = 1000;
125496
126135
 
125497
126136
  class R2Provider {
125498
126137
  bucket;
125499
126138
  constructor(bucket) {
126139
+ if (!bucket) {
126140
+ throw new McpError(-32008 /* ConfigurationError */, "R2Provider requires a valid R2Bucket instance.");
126141
+ }
125500
126142
  this.bucket = bucket;
125501
126143
  }
125502
126144
  getR2Key(tenantId, key) {
@@ -125581,27 +126223,115 @@ class R2Provider {
125581
126223
  input: { tenantId, key }
125582
126224
  });
125583
126225
  }
125584
- async list(tenantId, prefix, context) {
126226
+ async list(tenantId, prefix, context, options) {
125585
126227
  const r2Prefix = this.getR2Key(tenantId, prefix);
125586
126228
  return ErrorHandler.tryCatch(async () => {
125587
- logger.debug(`[R2Provider] Listing keys with prefix: ${r2Prefix}`, context);
125588
- const listed = await this.bucket.list({ prefix: r2Prefix });
126229
+ logger.debug(`[R2Provider] Listing keys with prefix: ${r2Prefix}`, {
126230
+ ...context,
126231
+ options
126232
+ });
126233
+ const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT4;
126234
+ const listOptions = {
126235
+ prefix: r2Prefix,
126236
+ limit: limit2 + 1
126237
+ };
126238
+ if (options?.cursor) {
126239
+ listOptions.cursor = options.cursor;
126240
+ }
126241
+ const listed = await this.bucket.list(listOptions);
125589
126242
  const tenantPrefix = `${tenantId}:`;
125590
126243
  const keys = listed.objects.map((obj) => obj.key.startsWith(tenantPrefix) ? obj.key.substring(tenantPrefix.length) : obj.key);
125591
- logger.debug(`[R2Provider] Found ${keys.length} keys with prefix: ${r2Prefix}`, context);
125592
- return keys;
126244
+ const hasMore = keys.length > limit2;
126245
+ const resultKeys = hasMore ? keys.slice(0, limit2) : keys;
126246
+ const nextCursor = "cursor" in listed && listed.truncated ? listed.cursor : undefined;
126247
+ logger.debug(`[R2Provider] Found ${resultKeys.length} keys with prefix: ${r2Prefix}`, context);
126248
+ return {
126249
+ keys: resultKeys,
126250
+ nextCursor
126251
+ };
125593
126252
  }, {
125594
126253
  operation: "R2Provider.list",
125595
126254
  context,
125596
- input: { tenantId, prefix }
126255
+ input: { tenantId, prefix, options }
126256
+ });
126257
+ }
126258
+ async getMany(tenantId, keys, context) {
126259
+ return ErrorHandler.tryCatch(async () => {
126260
+ const results = new Map;
126261
+ for (const key of keys) {
126262
+ const value = await this.get(tenantId, key, context);
126263
+ if (value !== null) {
126264
+ results.set(key, value);
126265
+ }
126266
+ }
126267
+ return results;
126268
+ }, {
126269
+ operation: "R2Provider.getMany",
126270
+ context,
126271
+ input: { tenantId, keyCount: keys.length }
126272
+ });
126273
+ }
126274
+ async setMany(tenantId, entries, context, options) {
126275
+ return ErrorHandler.tryCatch(async () => {
126276
+ const promises = Array.from(entries.entries()).map(([key, value]) => this.set(tenantId, key, value, context, options));
126277
+ await Promise.all(promises);
126278
+ }, {
126279
+ operation: "R2Provider.setMany",
126280
+ context,
126281
+ input: { tenantId, entryCount: entries.size }
126282
+ });
126283
+ }
126284
+ async deleteMany(tenantId, keys, context) {
126285
+ return ErrorHandler.tryCatch(async () => {
126286
+ const promises = keys.map((key) => this.delete(tenantId, key, context));
126287
+ const results = await Promise.all(promises);
126288
+ return results.filter((deleted) => deleted).length;
126289
+ }, {
126290
+ operation: "R2Provider.deleteMany",
126291
+ context,
126292
+ input: { tenantId, keyCount: keys.length }
126293
+ });
126294
+ }
126295
+ async clear(tenantId, context) {
126296
+ return ErrorHandler.tryCatch(async () => {
126297
+ const r2Prefix = `${tenantId}:`;
126298
+ let deletedCount = 0;
126299
+ let cursor;
126300
+ let hasMore = true;
126301
+ while (hasMore) {
126302
+ const listOpts = {
126303
+ prefix: r2Prefix,
126304
+ limit: 1000
126305
+ };
126306
+ if (cursor) {
126307
+ listOpts.cursor = cursor;
126308
+ }
126309
+ const listed = await this.bucket.list(listOpts);
126310
+ const deletePromises = listed.objects.map((obj) => this.bucket.delete(obj.key));
126311
+ await Promise.all(deletePromises);
126312
+ deletedCount += listed.objects.length;
126313
+ hasMore = listed.truncated;
126314
+ cursor = "cursor" in listed ? listed.cursor : undefined;
126315
+ }
126316
+ logger.info(`[R2Provider] Cleared ${deletedCount} keys for tenant: ${tenantId}`, context);
126317
+ return deletedCount;
126318
+ }, {
126319
+ operation: "R2Provider.clear",
126320
+ context,
126321
+ input: { tenantId }
125597
126322
  });
125598
126323
  }
125599
126324
  }
125600
126325
 
125601
126326
  // src/storage/providers/cloudflare/kvProvider.ts
126327
+ var DEFAULT_LIST_LIMIT5 = 1000;
126328
+
125602
126329
  class KvProvider {
125603
126330
  kv;
125604
126331
  constructor(kv) {
126332
+ if (!kv) {
126333
+ throw new McpError(-32008 /* ConfigurationError */, "KvProvider requires a valid KVNamespace instance.");
126334
+ }
125605
126335
  this.kv = kv;
125606
126336
  }
125607
126337
  getKvKey(tenantId, key) {
@@ -125661,19 +126391,100 @@ class KvProvider {
125661
126391
  input: { tenantId, key }
125662
126392
  });
125663
126393
  }
125664
- async list(tenantId, prefix, context) {
126394
+ async list(tenantId, prefix, context, options) {
125665
126395
  const kvPrefix = this.getKvKey(tenantId, prefix);
125666
126396
  return ErrorHandler.tryCatch(async () => {
125667
- logger.debug(`[KvProvider] Listing keys with prefix: ${kvPrefix}`, context);
125668
- const listed = await this.kv.list({ prefix: kvPrefix });
126397
+ logger.debug(`[KvProvider] Listing keys with prefix: ${kvPrefix}`, {
126398
+ ...context,
126399
+ options
126400
+ });
126401
+ const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT5;
126402
+ const listOptions = {
126403
+ prefix: kvPrefix,
126404
+ limit: limit2
126405
+ };
126406
+ if (options?.cursor) {
126407
+ listOptions.cursor = options.cursor;
126408
+ }
126409
+ const listed = await this.kv.list(listOptions);
125669
126410
  const tenantPrefix = `${tenantId}:`;
125670
126411
  const keys = listed.keys.map((keyInfo) => keyInfo.name.startsWith(tenantPrefix) ? keyInfo.name.substring(tenantPrefix.length) : keyInfo.name);
126412
+ const nextCursor = "cursor" in listed && !listed.list_complete ? listed.cursor : undefined;
125671
126413
  logger.debug(`[KvProvider] Found ${keys.length} keys with prefix: ${kvPrefix}`, context);
125672
- return keys;
126414
+ return {
126415
+ keys,
126416
+ nextCursor
126417
+ };
125673
126418
  }, {
125674
126419
  operation: "KvProvider.list",
125675
126420
  context,
125676
- input: { tenantId, prefix }
126421
+ input: { tenantId, prefix, options }
126422
+ });
126423
+ }
126424
+ async getMany(tenantId, keys, context) {
126425
+ return ErrorHandler.tryCatch(async () => {
126426
+ const results = new Map;
126427
+ for (const key of keys) {
126428
+ const value = await this.get(tenantId, key, context);
126429
+ if (value !== null) {
126430
+ results.set(key, value);
126431
+ }
126432
+ }
126433
+ return results;
126434
+ }, {
126435
+ operation: "KvProvider.getMany",
126436
+ context,
126437
+ input: { tenantId, keyCount: keys.length }
126438
+ });
126439
+ }
126440
+ async setMany(tenantId, entries, context, options) {
126441
+ return ErrorHandler.tryCatch(async () => {
126442
+ const promises = Array.from(entries.entries()).map(([key, value]) => this.set(tenantId, key, value, context, options));
126443
+ await Promise.all(promises);
126444
+ }, {
126445
+ operation: "KvProvider.setMany",
126446
+ context,
126447
+ input: { tenantId, entryCount: entries.size }
126448
+ });
126449
+ }
126450
+ async deleteMany(tenantId, keys, context) {
126451
+ return ErrorHandler.tryCatch(async () => {
126452
+ const promises = keys.map((key) => this.delete(tenantId, key, context));
126453
+ const results = await Promise.all(promises);
126454
+ return results.filter((deleted) => deleted).length;
126455
+ }, {
126456
+ operation: "KvProvider.deleteMany",
126457
+ context,
126458
+ input: { tenantId, keyCount: keys.length }
126459
+ });
126460
+ }
126461
+ async clear(tenantId, context) {
126462
+ return ErrorHandler.tryCatch(async () => {
126463
+ const kvPrefix = `${tenantId}:`;
126464
+ let deletedCount = 0;
126465
+ let cursor;
126466
+ let listComplete = false;
126467
+ while (!listComplete) {
126468
+ const listOpts = {
126469
+ prefix: kvPrefix,
126470
+ limit: 1000
126471
+ };
126472
+ if (cursor) {
126473
+ listOpts.cursor = cursor;
126474
+ }
126475
+ const listed = await this.kv.list(listOpts);
126476
+ const deletePromises = listed.keys.map((keyInfo) => this.kv.delete(keyInfo.name));
126477
+ await Promise.all(deletePromises);
126478
+ deletedCount += listed.keys.length;
126479
+ listComplete = listed.list_complete;
126480
+ cursor = "cursor" in listed ? listed.cursor : undefined;
126481
+ }
126482
+ logger.info(`[KvProvider] Cleared ${deletedCount} keys for tenant: ${tenantId}`, context);
126483
+ return deletedCount;
126484
+ }, {
126485
+ operation: "KvProvider.clear",
126486
+ context,
126487
+ input: { tenantId }
125677
126488
  });
125678
126489
  }
125679
126490
  }
@@ -125705,7 +126516,7 @@ function createStorageProvider(config2, deps = {}) {
125705
126516
  if (deps.supabaseClient) {
125706
126517
  return new SupabaseProvider(deps.supabaseClient);
125707
126518
  }
125708
- return import_tsyringe5.container.resolve(SupabaseProvider);
126519
+ return import_tsyringe7.container.resolve(SupabaseProvider);
125709
126520
  case "cloudflare-r2":
125710
126521
  if (isServerless3) {
125711
126522
  const bucket = deps.r2Bucket ?? globalThis.R2_BUCKET;
@@ -125728,9 +126539,9 @@ function createStorageProvider(config2, deps = {}) {
125728
126539
  // src/container/registrations/core.ts
125729
126540
  var registerCoreServices = () => {
125730
126541
  const config2 = parseConfig();
125731
- import_tsyringe6.container.register(AppConfig, { useValue: config2 });
125732
- import_tsyringe6.container.register(Logger2, { useValue: logger });
125733
- import_tsyringe6.container.register(SupabaseAdminClient, {
126542
+ import_tsyringe8.container.register(AppConfig, { useValue: config2 });
126543
+ import_tsyringe8.container.register(Logger2, { useValue: logger });
126544
+ import_tsyringe8.container.register(SupabaseAdminClient, {
125734
126545
  useFactory: (c) => {
125735
126546
  const cfg = c.resolve(AppConfig);
125736
126547
  if (!cfg.supabase?.url || !cfg.supabase?.serviceRoleKey) {
@@ -125741,22 +126552,57 @@ var registerCoreServices = () => {
125741
126552
  });
125742
126553
  }
125743
126554
  });
125744
- import_tsyringe6.container.register(StorageProvider, {
126555
+ import_tsyringe8.container.register(StorageProvider, {
125745
126556
  useFactory: (c) => createStorageProvider(c.resolve(AppConfig))
125746
126557
  });
125747
- import_tsyringe6.container.register(StorageService, { useClass: StorageService2 }, { lifecycle: import_tsyringe6.Lifecycle.Singleton });
125748
- import_tsyringe6.container.register(LlmProvider, {
126558
+ import_tsyringe8.container.register(StorageService, { useClass: StorageService2 }, { lifecycle: import_tsyringe8.Lifecycle.Singleton });
126559
+ import_tsyringe8.container.register(LlmProvider, {
125749
126560
  useClass: OpenRouterProvider
125750
126561
  });
125751
- import_tsyringe6.container.register(RateLimiterService, { useClass: RateLimiter }, { lifecycle: import_tsyringe6.Lifecycle.Singleton });
126562
+ import_tsyringe8.container.register(RateLimiterService, { useClass: RateLimiter }, { lifecycle: import_tsyringe8.Lifecycle.Singleton });
126563
+ import_tsyringe8.container.register(SpeechService, {
126564
+ useFactory: (c) => {
126565
+ const cfg = c.resolve(AppConfig);
126566
+ const ttsConfig = cfg.speech?.tts?.enabled && cfg.speech.tts.apiKey ? {
126567
+ provider: "elevenlabs",
126568
+ apiKey: cfg.speech.tts.apiKey,
126569
+ ...cfg.speech.tts.baseUrl && {
126570
+ baseUrl: cfg.speech.tts.baseUrl
126571
+ },
126572
+ ...cfg.speech.tts.defaultVoiceId && {
126573
+ defaultVoiceId: cfg.speech.tts.defaultVoiceId
126574
+ },
126575
+ ...cfg.speech.tts.defaultModelId && {
126576
+ defaultModelId: cfg.speech.tts.defaultModelId
126577
+ },
126578
+ ...cfg.speech.tts.timeout && {
126579
+ timeout: cfg.speech.tts.timeout
126580
+ }
126581
+ } : undefined;
126582
+ const sttConfig = cfg.speech?.stt?.enabled && cfg.speech.stt.apiKey ? {
126583
+ provider: "openai-whisper",
126584
+ apiKey: cfg.speech.stt.apiKey,
126585
+ ...cfg.speech.stt.baseUrl && {
126586
+ baseUrl: cfg.speech.stt.baseUrl
126587
+ },
126588
+ ...cfg.speech.stt.defaultModelId && {
126589
+ defaultModelId: cfg.speech.stt.defaultModelId
126590
+ },
126591
+ ...cfg.speech.stt.timeout && {
126592
+ timeout: cfg.speech.stt.timeout
126593
+ }
126594
+ } : undefined;
126595
+ return new SpeechService2(ttsConfig, sttConfig);
126596
+ }
126597
+ });
125752
126598
  logger.info("Core services registered with the DI container.");
125753
126599
  };
125754
126600
 
125755
126601
  // src/container/registrations/mcp.ts
125756
- var import_tsyringe16 = __toESM(require_cjs3(), 1);
126602
+ var import_tsyringe18 = __toESM(require_cjs3(), 1);
125757
126603
 
125758
126604
  // src/mcp-server/resources/resource-registration.ts
125759
- var import_tsyringe7 = __toESM(require_cjs3(), 1);
126605
+ var import_tsyringe9 = __toESM(require_cjs3(), 1);
125760
126606
 
125761
126607
  // src/mcp-server/transports/auth/lib/authUtils.ts
125762
126608
  function withRequiredScopes(requiredScopes) {
@@ -129151,8 +129997,8 @@ class ResourceRegistry {
129151
129997
  }
129152
129998
  }
129153
129999
  ResourceRegistry = __legacyDecorateClassTS([
129154
- import_tsyringe7.injectable(),
129155
- __legacyDecorateParamTS(0, import_tsyringe7.injectAll(ResourceDefinitions)),
130000
+ import_tsyringe9.injectable(),
130001
+ __legacyDecorateParamTS(0, import_tsyringe9.injectAll(ResourceDefinitions)),
129156
130002
  __legacyMetadataTS("design:paramtypes", [
129157
130003
  Array
129158
130004
  ])
@@ -129164,10 +130010,10 @@ var registerResources = (container3) => {
129164
130010
  };
129165
130011
 
129166
130012
  // src/mcp-server/server.ts
129167
- var import_tsyringe11 = __toESM(require_cjs3(), 1);
130013
+ var import_tsyringe13 = __toESM(require_cjs3(), 1);
129168
130014
 
129169
130015
  // src/mcp-server/prompts/prompt-registration.ts
129170
- var import_tsyringe8 = __toESM(require_cjs3(), 1);
130016
+ var import_tsyringe10 = __toESM(require_cjs3(), 1);
129171
130017
 
129172
130018
  // src/mcp-server/prompts/definitions/code-review.prompt.ts
129173
130019
  var PROMPT_NAME = "code_review";
@@ -129259,15 +130105,15 @@ class PromptRegistry {
129259
130105
  }
129260
130106
  }
129261
130107
  PromptRegistry = __legacyDecorateClassTS([
129262
- import_tsyringe8.injectable(),
129263
- __legacyDecorateParamTS(0, import_tsyringe8.inject(Logger2)),
130108
+ import_tsyringe10.injectable(),
130109
+ __legacyDecorateParamTS(0, import_tsyringe10.inject(Logger2)),
129264
130110
  __legacyMetadataTS("design:paramtypes", [
129265
130111
  Object
129266
130112
  ])
129267
130113
  ], PromptRegistry);
129268
130114
 
129269
130115
  // src/mcp-server/roots/roots-registration.ts
129270
- var import_tsyringe9 = __toESM(require_cjs3(), 1);
130116
+ var import_tsyringe11 = __toESM(require_cjs3(), 1);
129271
130117
  class RootsRegistry {
129272
130118
  logger;
129273
130119
  constructor(logger2) {
@@ -129282,15 +130128,15 @@ class RootsRegistry {
129282
130128
  }
129283
130129
  }
129284
130130
  RootsRegistry = __legacyDecorateClassTS([
129285
- import_tsyringe9.injectable(),
129286
- __legacyDecorateParamTS(0, import_tsyringe9.inject(Logger2)),
130131
+ import_tsyringe11.injectable(),
130132
+ __legacyDecorateParamTS(0, import_tsyringe11.inject(Logger2)),
129287
130133
  __legacyMetadataTS("design:paramtypes", [
129288
130134
  Object
129289
130135
  ])
129290
130136
  ], RootsRegistry);
129291
130137
 
129292
130138
  // src/mcp-server/tools/tool-registration.ts
129293
- var import_tsyringe10 = __toESM(require_cjs3(), 1);
130139
+ var import_tsyringe12 = __toESM(require_cjs3(), 1);
129294
130140
 
129295
130141
  // src/mcp-server/tools/definitions/template-cat-fact.tool.ts
129296
130142
  var TOOL_NAME = "template_cat_fact";
@@ -129853,8 +130699,8 @@ class ToolRegistry {
129853
130699
  }
129854
130700
  }
129855
130701
  ToolRegistry = __legacyDecorateClassTS([
129856
- import_tsyringe10.injectable(),
129857
- __legacyDecorateParamTS(0, import_tsyringe10.injectAll(ToolDefinitions)),
130702
+ import_tsyringe12.injectable(),
130703
+ __legacyDecorateParamTS(0, import_tsyringe12.injectAll(ToolDefinitions)),
129858
130704
  __legacyMetadataTS("design:paramtypes", [
129859
130705
  Array
129860
130706
  ])
@@ -129893,13 +130739,13 @@ async function createMcpServerInstance() {
129893
130739
  });
129894
130740
  try {
129895
130741
  logger.debug("Registering all MCP capabilities via registries...", context);
129896
- const toolRegistry = import_tsyringe11.container.resolve(ToolRegistry);
130742
+ const toolRegistry = import_tsyringe13.container.resolve(ToolRegistry);
129897
130743
  await toolRegistry.registerAll(server);
129898
- const resourceRegistry = import_tsyringe11.container.resolve(ResourceRegistry);
130744
+ const resourceRegistry = import_tsyringe13.container.resolve(ResourceRegistry);
129899
130745
  await resourceRegistry.registerAll(server);
129900
- const promptRegistry = import_tsyringe11.container.resolve(PromptRegistry);
130746
+ const promptRegistry = import_tsyringe13.container.resolve(PromptRegistry);
129901
130747
  promptRegistry.registerAll(server);
129902
- const rootsRegistry = import_tsyringe11.container.resolve(RootsRegistry);
130748
+ const rootsRegistry = import_tsyringe13.container.resolve(RootsRegistry);
129903
130749
  rootsRegistry.registerAll(server);
129904
130750
  logger.info("All MCP capabilities registered successfully", context);
129905
130751
  } catch (err) {
@@ -129914,7 +130760,7 @@ async function createMcpServerInstance() {
129914
130760
  }
129915
130761
 
129916
130762
  // src/mcp-server/transports/manager.ts
129917
- var import_tsyringe15 = __toESM(require_cjs3(), 1);
130763
+ var import_tsyringe17 = __toESM(require_cjs3(), 1);
129918
130764
 
129919
130765
  // node_modules/hono/dist/http-exception.js
129920
130766
  var HTTPException = class extends Error {
@@ -132582,7 +133428,7 @@ var cors = (options) => {
132582
133428
  import http from "http";
132583
133429
  import { randomUUID } from "node:crypto";
132584
133430
  // src/mcp-server/transports/auth/authFactory.ts
132585
- var import_tsyringe14 = __toESM(require_cjs3(), 1);
133431
+ var import_tsyringe16 = __toESM(require_cjs3(), 1);
132586
133432
 
132587
133433
  // node_modules/jose/dist/webapi/lib/buffer_utils.js
132588
133434
  var encoder = new TextEncoder;
@@ -134100,7 +134946,7 @@ function createRemoteJWKSet(url, options) {
134100
134946
  return remoteJWKSet;
134101
134947
  }
134102
134948
  // src/mcp-server/transports/auth/strategies/jwtStrategy.ts
134103
- var import_tsyringe12 = __toESM(require_cjs3(), 1);
134949
+ var import_tsyringe14 = __toESM(require_cjs3(), 1);
134104
134950
  class JwtStrategy {
134105
134951
  config;
134106
134952
  logger;
@@ -134203,9 +135049,9 @@ class JwtStrategy {
134203
135049
  }
134204
135050
  }
134205
135051
  JwtStrategy = __legacyDecorateClassTS([
134206
- import_tsyringe12.injectable(),
134207
- __legacyDecorateParamTS(0, import_tsyringe12.inject(AppConfig)),
134208
- __legacyDecorateParamTS(1, import_tsyringe12.inject(Logger2)),
135052
+ import_tsyringe14.injectable(),
135053
+ __legacyDecorateParamTS(0, import_tsyringe14.inject(AppConfig)),
135054
+ __legacyDecorateParamTS(1, import_tsyringe14.inject(Logger2)),
134209
135055
  __legacyMetadataTS("design:paramtypes", [
134210
135056
  Object,
134211
135057
  Object
@@ -134213,7 +135059,7 @@ JwtStrategy = __legacyDecorateClassTS([
134213
135059
  ], JwtStrategy);
134214
135060
 
134215
135061
  // src/mcp-server/transports/auth/strategies/oauthStrategy.ts
134216
- var import_tsyringe13 = __toESM(require_cjs3(), 1);
135062
+ var import_tsyringe15 = __toESM(require_cjs3(), 1);
134217
135063
  class OauthStrategy {
134218
135064
  config;
134219
135065
  logger;
@@ -134330,9 +135176,9 @@ class OauthStrategy {
134330
135176
  }
134331
135177
  }
134332
135178
  OauthStrategy = __legacyDecorateClassTS([
134333
- import_tsyringe13.injectable(),
134334
- __legacyDecorateParamTS(0, import_tsyringe13.inject(AppConfig)),
134335
- __legacyDecorateParamTS(1, import_tsyringe13.inject(Logger2)),
135179
+ import_tsyringe15.injectable(),
135180
+ __legacyDecorateParamTS(0, import_tsyringe15.inject(AppConfig)),
135181
+ __legacyDecorateParamTS(1, import_tsyringe15.inject(Logger2)),
134336
135182
  __legacyMetadataTS("design:paramtypes", [
134337
135183
  Object,
134338
135184
  Object
@@ -134340,8 +135186,8 @@ OauthStrategy = __legacyDecorateClassTS([
134340
135186
  ], OauthStrategy);
134341
135187
 
134342
135188
  // src/mcp-server/transports/auth/authFactory.ts
134343
- import_tsyringe14.container.register(JwtStrategy, { useClass: JwtStrategy });
134344
- import_tsyringe14.container.register(OauthStrategy, { useClass: OauthStrategy });
135189
+ import_tsyringe16.container.register(JwtStrategy, { useClass: JwtStrategy });
135190
+ import_tsyringe16.container.register(OauthStrategy, { useClass: OauthStrategy });
134345
135191
  function createAuthStrategy() {
134346
135192
  const context = requestContextService.createRequestContext({
134347
135193
  operation: "createAuthStrategy",
@@ -134351,10 +135197,10 @@ function createAuthStrategy() {
134351
135197
  switch (config.mcpAuthMode) {
134352
135198
  case "jwt":
134353
135199
  logger.debug("Resolving JWT strategy from container.", context);
134354
- return import_tsyringe14.container.resolve(JwtStrategy);
135200
+ return import_tsyringe16.container.resolve(JwtStrategy);
134355
135201
  case "oauth":
134356
135202
  logger.debug("Resolving OAuth strategy from container.", context);
134357
- return import_tsyringe14.container.resolve(OauthStrategy);
135203
+ return import_tsyringe16.container.resolve(OauthStrategy);
134358
135204
  case "none":
134359
135205
  logger.info("Authentication is disabled ('none' mode).", context);
134360
135206
  return null;
@@ -134868,10 +135714,10 @@ class TransportManager {
134868
135714
  }
134869
135715
  }
134870
135716
  TransportManager = __legacyDecorateClassTS([
134871
- import_tsyringe15.injectable(),
134872
- __legacyDecorateParamTS(0, import_tsyringe15.inject(AppConfig)),
134873
- __legacyDecorateParamTS(1, import_tsyringe15.inject(Logger2)),
134874
- __legacyDecorateParamTS(2, import_tsyringe15.inject(CreateMcpServerInstance)),
135717
+ import_tsyringe17.injectable(),
135718
+ __legacyDecorateParamTS(0, import_tsyringe17.inject(AppConfig)),
135719
+ __legacyDecorateParamTS(1, import_tsyringe17.inject(Logger2)),
135720
+ __legacyDecorateParamTS(2, import_tsyringe17.inject(CreateMcpServerInstance)),
134875
135721
  __legacyMetadataTS("design:paramtypes", [
134876
135722
  typeof AppConfigType === "undefined" ? Object : AppConfigType,
134877
135723
  Object,
@@ -134881,14 +135727,14 @@ TransportManager = __legacyDecorateClassTS([
134881
135727
 
134882
135728
  // src/container/registrations/mcp.ts
134883
135729
  var registerMcpServices = () => {
134884
- import_tsyringe16.container.registerSingleton(ToolRegistry);
134885
- import_tsyringe16.container.registerSingleton(ResourceRegistry);
134886
- registerTools(import_tsyringe16.container);
134887
- registerResources(import_tsyringe16.container);
134888
- import_tsyringe16.container.register(CreateMcpServerInstance, {
135730
+ import_tsyringe18.container.registerSingleton(ToolRegistry);
135731
+ import_tsyringe18.container.registerSingleton(ResourceRegistry);
135732
+ registerTools(import_tsyringe18.container);
135733
+ registerResources(import_tsyringe18.container);
135734
+ import_tsyringe18.container.register(CreateMcpServerInstance, {
134889
135735
  useValue: createMcpServerInstance
134890
135736
  });
134891
- import_tsyringe16.container.registerSingleton(TransportManagerToken, TransportManager);
135737
+ import_tsyringe18.container.registerSingleton(TransportManagerToken, TransportManager);
134892
135738
  logger.info("MCP services and factories registered with the DI container.");
134893
135739
  };
134894
135740
 
@@ -134902,7 +135748,7 @@ function composeContainer() {
134902
135748
  registerMcpServices();
134903
135749
  isContainerComposed = true;
134904
135750
  }
134905
- var container_default = import_tsyringe17.container;
135751
+ var container_default = import_tsyringe19.container;
134906
135752
 
134907
135753
  // src/index.ts
134908
135754
  var config2;