@aprovan/patchwork 0.1.0-dev.68f15f3 → 0.1.0-dev.9d1cd22

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.
@@ -9,9 +9,9 @@
9
9
  CLI Target: node20
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
- ESM dist/index.js 3.16 KB
13
- ESM dist/index.js.map 10.79 KB
14
- ESM ⚡️ Build success in 62ms
12
+ ESM dist/index.js 3.15 KB
13
+ ESM dist/index.js.map 10.96 KB
14
+ ESM ⚡️ Build success in 79ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 4032ms
17
- DTS dist/index.d.ts 4.79 KB
16
+ DTS ⚡️ Build success in 2228ms
17
+ DTS dist/index.d.ts 4.93 KB
package/dist/index.d.ts CHANGED
@@ -108,7 +108,7 @@ interface CacheConfig {
108
108
  /**
109
109
  * Service backend interface - abstracts the actual service call mechanism
110
110
  *
111
- * Implementations can use MCP, HTTP, or any other protocol.
111
+ * Implementations can use UTCP, MCP, HTTP, or any other protocol.
112
112
  */
113
113
  interface ServiceBackend {
114
114
  /**
@@ -127,6 +127,12 @@ interface ServiceBackend {
127
127
  *
128
128
  * @example
129
129
  * ```typescript
130
+ * // Using with UTCP
131
+ * setServiceBackend({
132
+ * call: (service, procedure, args) =>
133
+ * utcpClient.callTool(`${service}.${procedure}`, args)
134
+ * });
135
+ *
130
136
  * // Using with HTTP proxy
131
137
  * setServiceBackend({
132
138
  * call: async (service, procedure, args) => {
@@ -143,7 +149,7 @@ declare function setServiceBackend(backend: ServiceBackend): void;
143
149
  /**
144
150
  * Create a service proxy that wraps the backend with caching
145
151
  */
146
- declare function createServiceProxy(): ServiceBackend;
152
+ declare function createProxy(): ServiceBackend;
147
153
  /**
148
154
  * Call a service procedure
149
155
  *
@@ -181,4 +187,4 @@ interface BatchCall {
181
187
  }
182
188
  declare function batchCall(calls: BatchCall[]): Promise<ServiceResult[]>;
183
189
 
184
- export { type AggregatedContext, type CacheConfig, type ComposedLayout, type CompositionRules, type ContextManagerOptions, type ContextProvider, DEFAULT_COMPOSITION_RULES, type GitContext, type ProjectContext, type SelectionOptions, type ServiceBackend, type ServiceResult, type ShellContext, type UsagePattern, type UsageRecord, type Viewport, type WidgetSuggestion, batchCall, callProcedure, configureCacheTtl, createServiceProxy, getCacheStats, invalidateCache, setServiceBackend };
190
+ export { type AggregatedContext, type CacheConfig, type ComposedLayout, type CompositionRules, type ContextManagerOptions, type ContextProvider, DEFAULT_COMPOSITION_RULES, type GitContext, type ProjectContext, type SelectionOptions, type ServiceBackend, type ServiceResult, type ShellContext, type UsagePattern, type UsageRecord, type Viewport, type WidgetSuggestion, batchCall, callProcedure, configureCacheTtl, createProxy, getCacheStats, invalidateCache, setServiceBackend };
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var MAX_CACHE_SIZE = 1e3;
14
14
  function setServiceBackend(backend) {
15
15
  currentBackend = backend;
16
16
  }
17
- function createServiceProxy() {
17
+ function createProxy() {
18
18
  return {
19
19
  call: (service, procedure, args) => callProcedure(service, procedure, args).then((r) => {
20
20
  if (!r.success) throw new Error(r.error || "Service call failed");
@@ -111,7 +111,7 @@ export {
111
111
  batchCall,
112
112
  callProcedure,
113
113
  configureCacheTtl,
114
- createServiceProxy,
114
+ createProxy,
115
115
  getCacheStats,
116
116
  invalidateCache,
117
117
  setServiceBackend
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/services/proxy.ts"],"sourcesContent":["// Patchwork Types - Context providers and selection engine types\n\n// ============================================================================\n// Context Provider Types\n// ============================================================================\n\nexport interface ContextProvider {\n name: string;\n schema?: Record<string, unknown>;\n getContext(): Promise<Record<string, unknown>>;\n subscribe?(callback: (context: Record<string, unknown>) => void): () => void;\n}\n\nexport interface AggregatedContext {\n timestamp: string;\n providers: {\n [providerName: string]: Record<string, unknown>;\n };\n}\n\nexport interface ContextManagerOptions {\n debounce_ms?: number;\n}\n\n// ============================================================================\n// Common Context Shapes\n// ============================================================================\n\nexport interface ShellContext {\n cwd: string;\n recent_commands?: string[];\n shell?: string;\n}\n\nexport interface GitContext {\n is_repo: boolean;\n branch?: string;\n remote_url?: string;\n uncommitted_changes?: number;\n staged_files?: number;\n}\n\nexport interface ProjectContext {\n type?: string;\n package_manager?: string;\n scripts?: string[];\n}\n\n// ============================================================================\n// Selection Engine Types\n// ============================================================================\n\nexport interface Viewport {\n width: number;\n height: number;\n}\n\nexport interface SelectionOptions {\n limit?: number;\n strategy?: 'llm' | 'rules';\n minConfidence?: number;\n}\n\nexport interface WidgetSuggestion {\n name: string;\n confidence: number;\n position: 'primary' | 'secondary' | 'ambient';\n reason: string;\n suggested_size: {\n width: number;\n height: number;\n };\n}\n\nexport interface CompositionRules {\n max_primary: number;\n max_secondary: number;\n max_ambient: number;\n ambient_stacking: boolean;\n}\n\nexport const DEFAULT_COMPOSITION_RULES: CompositionRules = {\n max_primary: 1,\n max_secondary: 3,\n max_ambient: 5,\n ambient_stacking: true,\n};\n\nexport interface ComposedLayout {\n widgets: Array<{\n name: string;\n position: 'primary' | 'secondary' | 'ambient';\n bounds: { x: number; y: number; width: number; height: number };\n }>;\n remaining_space: { width: number; height: number };\n}\n\n// ============================================================================\n// Usage Tracking Types\n// ============================================================================\n\nexport interface UsageRecord {\n widget_name: string;\n context_hash: string;\n was_suggested: boolean;\n viewport: Viewport;\n timestamp: string;\n}\n\nexport interface UsagePattern {\n context_hash: string;\n selected_widget: string;\n was_suggested: boolean;\n viewport_size: Viewport;\n timestamp: string;\n}\n","// Service Proxy - Caching layer for service calls\n//\n// Provides a backend-agnostic service proxy with caching.\n// The actual backend (MCP, HTTP, etc.) is set via setServiceBackend().\n\nimport type { ServiceResult, CacheEntry, CacheConfig } from './types';\n\n/**\n * Service backend interface - abstracts the actual service call mechanism\n *\n * Implementations can use MCP, HTTP, or any other protocol.\n */\nexport interface ServiceBackend {\n /**\n * Call a service procedure\n * @param service - Service namespace (e.g., \"git\", \"github\")\n * @param procedure - Procedure name (e.g., \"branch\", \"repos.list\")\n * @param args - Arguments to pass\n */\n call(service: string, procedure: string, args: unknown[]): Promise<unknown>;\n}\n\n// Current backend (must be set before use)\nlet currentBackend: ServiceBackend | null = null;\n\n// Cache storage\nconst cache = new Map<string, CacheEntry>();\nconst cacheConfig = new Map<string, CacheConfig>();\nconst MAX_CACHE_SIZE = 1000;\n\n/**\n * Set the service backend\n *\n * This must be called before making any service calls.\n * The backend handles the actual communication with services.\n *\n * @example\n * ```typescript\n * // Using with HTTP proxy\n * setServiceBackend({\n * call: async (service, procedure, args) => {\n * const res = await fetch(`/api/proxy/${service}/${procedure}`, {\n * method: 'POST',\n * body: JSON.stringify({ args })\n * });\n * return res.json();\n * }\n * });\n * ```\n */\nexport function setServiceBackend(backend: ServiceBackend): void {\n currentBackend = backend;\n}\n\n/**\n * Create a service proxy that wraps the backend with caching\n */\nexport function createServiceProxy(): ServiceBackend {\n return {\n call: (service, procedure, args) =>\n callProcedure(service, procedure, args).then((r) => {\n if (!r.success) throw new Error(r.error || 'Service call failed');\n return r.data;\n }),\n };\n}\n\nfunction getCacheKey(\n service: string,\n procedure: string,\n args: unknown[],\n): string {\n return `${service}:${procedure}:${JSON.stringify(args)}`;\n}\n\nfunction evictOldestCache(): void {\n if (cache.size < MAX_CACHE_SIZE) return;\n const oldest = Array.from(cache.entries())\n .sort(([, a], [, b]) => a.expiresAt - b.expiresAt)\n .slice(0, Math.floor(MAX_CACHE_SIZE * 0.2));\n for (const [key] of oldest) cache.delete(key);\n}\n\nfunction getFromCache(key: string): ServiceResult | null {\n const entry = cache.get(key);\n if (!entry) return null;\n if (Date.now() > entry.expiresAt) {\n cache.delete(key);\n return null;\n }\n return { ...entry.result, cached: true };\n}\n\nfunction setCache(key: string, result: ServiceResult, ttl: number): void {\n evictOldestCache();\n cache.set(key, { result, expiresAt: Date.now() + ttl * 1000 });\n}\n\n/**\n * Call a service procedure\n *\n * @param service - Service namespace (e.g., \"git\", \"github\")\n * @param procedure - Procedure name (e.g., \"branch\", \"repos.get\")\n * @param args - Arguments to pass\n * @param options - Call options\n */\nexport async function callProcedure(\n service: string,\n procedure: string,\n args: unknown[] = [],\n options: { bypassCache?: boolean } = {},\n): Promise<ServiceResult> {\n const cacheKey = getCacheKey(service, procedure, args);\n const ttlConfig = cacheConfig.get(service);\n\n // Check cache first\n if (!options.bypassCache && ttlConfig) {\n const cached = getFromCache(cacheKey);\n if (cached) return cached;\n }\n\n // Check if backend is configured\n if (!currentBackend) {\n return {\n success: false,\n error: 'No service backend configured. Call setServiceBackend() first.',\n durationMs: 0,\n };\n }\n\n const startTime = performance.now();\n\n try {\n const data = await currentBackend.call(service, procedure, args);\n\n const serviceResult: ServiceResult = {\n success: true,\n data,\n durationMs: performance.now() - startTime,\n };\n\n // Cache successful results\n if (ttlConfig) {\n setCache(cacheKey, serviceResult, ttlConfig.ttl);\n }\n\n return serviceResult;\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n durationMs: performance.now() - startTime,\n };\n }\n}\n\n/**\n * Configure cache TTL for a service\n */\nexport function configureCacheTtl(service: string, ttl: number): void {\n cacheConfig.set(service, { ttl });\n}\n\n/**\n * Invalidate cache entries\n */\nexport function invalidateCache(service?: string): void {\n if (service) {\n for (const key of cache.keys()) {\n if (key.startsWith(`${service}:`)) cache.delete(key);\n }\n } else {\n cache.clear();\n }\n}\n\n/**\n * Get cache statistics\n */\nexport function getCacheStats(): { size: number; services: string[] } {\n const services = new Set<string>();\n for (const key of cache.keys()) {\n const service = key.split(':')[0];\n if (service) services.add(service);\n }\n return { size: cache.size, services: [...services] };\n}\n\n/**\n * Batch call multiple procedures\n */\nexport interface BatchCall {\n service: string;\n procedure: string;\n args?: unknown[];\n bypassCache?: boolean;\n}\n\nexport async function batchCall(calls: BatchCall[]): Promise<ServiceResult[]> {\n return Promise.all(\n calls.map((c) =>\n callProcedure(c.service, c.procedure, c.args || [], {\n bypassCache: c.bypassCache,\n }),\n ),\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/types.ts","../src/services/proxy.ts"],"sourcesContent":["// Patchwork Types - Context providers and selection engine types\n\n// ============================================================================\n// Context Provider Types\n// ============================================================================\n\nexport interface ContextProvider {\n name: string;\n schema?: Record<string, unknown>;\n getContext(): Promise<Record<string, unknown>>;\n subscribe?(callback: (context: Record<string, unknown>) => void): () => void;\n}\n\nexport interface AggregatedContext {\n timestamp: string;\n providers: {\n [providerName: string]: Record<string, unknown>;\n };\n}\n\nexport interface ContextManagerOptions {\n debounce_ms?: number;\n}\n\n// ============================================================================\n// Common Context Shapes\n// ============================================================================\n\nexport interface ShellContext {\n cwd: string;\n recent_commands?: string[];\n shell?: string;\n}\n\nexport interface GitContext {\n is_repo: boolean;\n branch?: string;\n remote_url?: string;\n uncommitted_changes?: number;\n staged_files?: number;\n}\n\nexport interface ProjectContext {\n type?: string;\n package_manager?: string;\n scripts?: string[];\n}\n\n// ============================================================================\n// Selection Engine Types\n// ============================================================================\n\nexport interface Viewport {\n width: number;\n height: number;\n}\n\nexport interface SelectionOptions {\n limit?: number;\n strategy?: 'llm' | 'rules';\n minConfidence?: number;\n}\n\nexport interface WidgetSuggestion {\n name: string;\n confidence: number;\n position: 'primary' | 'secondary' | 'ambient';\n reason: string;\n suggested_size: {\n width: number;\n height: number;\n };\n}\n\nexport interface CompositionRules {\n max_primary: number;\n max_secondary: number;\n max_ambient: number;\n ambient_stacking: boolean;\n}\n\nexport const DEFAULT_COMPOSITION_RULES: CompositionRules = {\n max_primary: 1,\n max_secondary: 3,\n max_ambient: 5,\n ambient_stacking: true,\n};\n\nexport interface ComposedLayout {\n widgets: Array<{\n name: string;\n position: 'primary' | 'secondary' | 'ambient';\n bounds: { x: number; y: number; width: number; height: number };\n }>;\n remaining_space: { width: number; height: number };\n}\n\n// ============================================================================\n// Usage Tracking Types\n// ============================================================================\n\nexport interface UsageRecord {\n widget_name: string;\n context_hash: string;\n was_suggested: boolean;\n viewport: Viewport;\n timestamp: string;\n}\n\nexport interface UsagePattern {\n context_hash: string;\n selected_widget: string;\n was_suggested: boolean;\n viewport_size: Viewport;\n timestamp: string;\n}\n","// Service Proxy - Caching layer for service calls\n//\n// Provides a backend-agnostic service proxy with caching.\n// The actual backend (UTCP, MCP, HTTP, etc.) is set via setServiceBackend().\n\nimport type { ServiceResult, CacheEntry, CacheConfig } from \"./types\";\n\n/**\n * Service backend interface - abstracts the actual service call mechanism\n *\n * Implementations can use UTCP, MCP, HTTP, or any other protocol.\n */\nexport interface ServiceBackend {\n /**\n * Call a service procedure\n * @param service - Service namespace (e.g., \"git\", \"github\")\n * @param procedure - Procedure name (e.g., \"branch\", \"repos.list\")\n * @param args - Arguments to pass\n */\n call(service: string, procedure: string, args: unknown[]): Promise<unknown>;\n}\n\n// Current backend (must be set before use)\nlet currentBackend: ServiceBackend | null = null;\n\n// Cache storage\nconst cache = new Map<string, CacheEntry>();\nconst cacheConfig = new Map<string, CacheConfig>();\nconst MAX_CACHE_SIZE = 1000;\n\n/**\n * Set the service backend\n *\n * This must be called before making any service calls.\n * The backend handles the actual communication with services.\n *\n * @example\n * ```typescript\n * // Using with UTCP\n * setServiceBackend({\n * call: (service, procedure, args) =>\n * utcpClient.callTool(`${service}.${procedure}`, args)\n * });\n *\n * // Using with HTTP proxy\n * setServiceBackend({\n * call: async (service, procedure, args) => {\n * const res = await fetch(`/api/proxy/${service}/${procedure}`, {\n * method: 'POST',\n * body: JSON.stringify({ args })\n * });\n * return res.json();\n * }\n * });\n * ```\n */\nexport function setServiceBackend(backend: ServiceBackend): void {\n currentBackend = backend;\n}\n\n/**\n * Create a service proxy that wraps the backend with caching\n */\nexport function createProxy(): ServiceBackend {\n return {\n call: (service, procedure, args) =>\n callProcedure(service, procedure, args).then((r) => {\n if (!r.success) throw new Error(r.error || \"Service call failed\");\n return r.data;\n }),\n };\n}\n\nfunction getCacheKey(\n service: string,\n procedure: string,\n args: unknown[],\n): string {\n return `${service}:${procedure}:${JSON.stringify(args)}`;\n}\n\nfunction evictOldestCache(): void {\n if (cache.size < MAX_CACHE_SIZE) return;\n const oldest = Array.from(cache.entries())\n .sort(([, a], [, b]) => a.expiresAt - b.expiresAt)\n .slice(0, Math.floor(MAX_CACHE_SIZE * 0.2));\n for (const [key] of oldest) cache.delete(key);\n}\n\nfunction getFromCache(key: string): ServiceResult | null {\n const entry = cache.get(key);\n if (!entry) return null;\n if (Date.now() > entry.expiresAt) {\n cache.delete(key);\n return null;\n }\n return { ...entry.result, cached: true };\n}\n\nfunction setCache(key: string, result: ServiceResult, ttl: number): void {\n evictOldestCache();\n cache.set(key, { result, expiresAt: Date.now() + ttl * 1000 });\n}\n\n/**\n * Call a service procedure\n *\n * @param service - Service namespace (e.g., \"git\", \"github\")\n * @param procedure - Procedure name (e.g., \"branch\", \"repos.get\")\n * @param args - Arguments to pass\n * @param options - Call options\n */\nexport async function callProcedure(\n service: string,\n procedure: string,\n args: unknown[] = [],\n options: { bypassCache?: boolean } = {},\n): Promise<ServiceResult> {\n const cacheKey = getCacheKey(service, procedure, args);\n const ttlConfig = cacheConfig.get(service);\n\n // Check cache first\n if (!options.bypassCache && ttlConfig) {\n const cached = getFromCache(cacheKey);\n if (cached) return cached;\n }\n\n // Check if backend is configured\n if (!currentBackend) {\n return {\n success: false,\n error: \"No service backend configured. Call setServiceBackend() first.\",\n durationMs: 0,\n };\n }\n\n const startTime = performance.now();\n\n try {\n const data = await currentBackend.call(service, procedure, args);\n\n const serviceResult: ServiceResult = {\n success: true,\n data,\n durationMs: performance.now() - startTime,\n };\n\n // Cache successful results\n if (ttlConfig) {\n setCache(cacheKey, serviceResult, ttlConfig.ttl);\n }\n\n return serviceResult;\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n durationMs: performance.now() - startTime,\n };\n }\n}\n\n/**\n * Configure cache TTL for a service\n */\nexport function configureCacheTtl(service: string, ttl: number): void {\n cacheConfig.set(service, { ttl });\n}\n\n/**\n * Invalidate cache entries\n */\nexport function invalidateCache(service?: string): void {\n if (service) {\n for (const key of cache.keys()) {\n if (key.startsWith(`${service}:`)) cache.delete(key);\n }\n } else {\n cache.clear();\n }\n}\n\n/**\n * Get cache statistics\n */\nexport function getCacheStats(): { size: number; services: string[] } {\n const services = new Set<string>();\n for (const key of cache.keys()) {\n const service = key.split(\":\")[0];\n if (service) services.add(service);\n }\n return { size: cache.size, services: [...services] };\n}\n\n/**\n * Batch call multiple procedures\n */\nexport interface BatchCall {\n service: string;\n procedure: string;\n args?: unknown[];\n bypassCache?: boolean;\n}\n\nexport async function batchCall(calls: BatchCall[]): Promise<ServiceResult[]> {\n return Promise.all(\n calls.map((c) =>\n callProcedure(c.service, c.procedure, c.args || [], {\n bypassCache: c.bypassCache,\n }),\n ),\n );\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aprovan/patchwork",
3
- "version": "0.1.0-dev.68f15f3",
3
+ "version": "0.1.0-dev.9d1cd22",
4
4
  "description": "Patchwork, a platform for building LLM-powered applications with pluggable UI components and a flexible compiler.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
- export * from './types';
1
+ export * from "./types";
2
2
 
3
- export type { CacheConfig, ServiceResult } from './services/types.js';
3
+ export type { CacheConfig, ServiceResult } from "./services/types.js";
4
4
 
5
5
  // Services
6
6
  export {
7
- createServiceProxy,
7
+ createProxy,
8
8
  callProcedure,
9
9
  batchCall,
10
10
  configureCacheTtl,
@@ -12,4 +12,4 @@ export {
12
12
  getCacheStats,
13
13
  setServiceBackend,
14
14
  type ServiceBackend,
15
- } from './services/index.js';
15
+ } from "./services/index.js";
@@ -1,5 +1,5 @@
1
1
  export {
2
- createServiceProxy,
2
+ createProxy,
3
3
  callProcedure,
4
4
  batchCall,
5
5
  configureCacheTtl,
@@ -8,4 +8,4 @@ export {
8
8
  setServiceBackend,
9
9
  type ServiceBackend,
10
10
  type BatchCall,
11
- } from './proxy';
11
+ } from "./proxy";
@@ -1,14 +1,14 @@
1
1
  // Service Proxy - Caching layer for service calls
2
2
  //
3
3
  // Provides a backend-agnostic service proxy with caching.
4
- // The actual backend (MCP, HTTP, etc.) is set via setServiceBackend().
4
+ // The actual backend (UTCP, MCP, HTTP, etc.) is set via setServiceBackend().
5
5
 
6
- import type { ServiceResult, CacheEntry, CacheConfig } from './types';
6
+ import type { ServiceResult, CacheEntry, CacheConfig } from "./types";
7
7
 
8
8
  /**
9
9
  * Service backend interface - abstracts the actual service call mechanism
10
10
  *
11
- * Implementations can use MCP, HTTP, or any other protocol.
11
+ * Implementations can use UTCP, MCP, HTTP, or any other protocol.
12
12
  */
13
13
  export interface ServiceBackend {
14
14
  /**
@@ -36,6 +36,12 @@ const MAX_CACHE_SIZE = 1000;
36
36
  *
37
37
  * @example
38
38
  * ```typescript
39
+ * // Using with UTCP
40
+ * setServiceBackend({
41
+ * call: (service, procedure, args) =>
42
+ * utcpClient.callTool(`${service}.${procedure}`, args)
43
+ * });
44
+ *
39
45
  * // Using with HTTP proxy
40
46
  * setServiceBackend({
41
47
  * call: async (service, procedure, args) => {
@@ -55,11 +61,11 @@ export function setServiceBackend(backend: ServiceBackend): void {
55
61
  /**
56
62
  * Create a service proxy that wraps the backend with caching
57
63
  */
58
- export function createServiceProxy(): ServiceBackend {
64
+ export function createProxy(): ServiceBackend {
59
65
  return {
60
66
  call: (service, procedure, args) =>
61
67
  callProcedure(service, procedure, args).then((r) => {
62
- if (!r.success) throw new Error(r.error || 'Service call failed');
68
+ if (!r.success) throw new Error(r.error || "Service call failed");
63
69
  return r.data;
64
70
  }),
65
71
  };
@@ -123,7 +129,7 @@ export async function callProcedure(
123
129
  if (!currentBackend) {
124
130
  return {
125
131
  success: false,
126
- error: 'No service backend configured. Call setServiceBackend() first.',
132
+ error: "No service backend configured. Call setServiceBackend() first.",
127
133
  durationMs: 0,
128
134
  };
129
135
  }
@@ -180,7 +186,7 @@ export function invalidateCache(service?: string): void {
180
186
  export function getCacheStats(): { size: number; services: string[] } {
181
187
  const services = new Set<string>();
182
188
  for (const key of cache.keys()) {
183
- const service = key.split(':')[0];
189
+ const service = key.split(":")[0];
184
190
  if (service) services.add(service);
185
191
  }
186
192
  return { size: cache.size, services: [...services] };