@jamesaphoenix/tx-test-utils 0.4.2

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 (101) hide show
  1. package/dist/database/index.d.ts +8 -0
  2. package/dist/database/index.d.ts.map +1 -0
  3. package/dist/database/index.js +7 -0
  4. package/dist/database/index.js.map +1 -0
  5. package/dist/database/test-database.d.ts +101 -0
  6. package/dist/database/test-database.d.ts.map +1 -0
  7. package/dist/database/test-database.js +130 -0
  8. package/dist/database/test-database.js.map +1 -0
  9. package/dist/factories/anchor.factory.d.ts +117 -0
  10. package/dist/factories/anchor.factory.d.ts.map +1 -0
  11. package/dist/factories/anchor.factory.js +201 -0
  12. package/dist/factories/anchor.factory.js.map +1 -0
  13. package/dist/factories/candidate.factory.d.ts +151 -0
  14. package/dist/factories/candidate.factory.d.ts.map +1 -0
  15. package/dist/factories/candidate.factory.js +194 -0
  16. package/dist/factories/candidate.factory.js.map +1 -0
  17. package/dist/factories/edge.factory.d.ts +119 -0
  18. package/dist/factories/edge.factory.d.ts.map +1 -0
  19. package/dist/factories/edge.factory.js +191 -0
  20. package/dist/factories/edge.factory.js.map +1 -0
  21. package/dist/factories/factories.test.d.ts +8 -0
  22. package/dist/factories/factories.test.d.ts.map +1 -0
  23. package/dist/factories/factories.test.js +419 -0
  24. package/dist/factories/factories.test.js.map +1 -0
  25. package/dist/factories/index.d.ts +15 -0
  26. package/dist/factories/index.d.ts.map +1 -0
  27. package/dist/factories/index.js +21 -0
  28. package/dist/factories/index.js.map +1 -0
  29. package/dist/factories/learning.factory.d.ts +107 -0
  30. package/dist/factories/learning.factory.d.ts.map +1 -0
  31. package/dist/factories/learning.factory.js +150 -0
  32. package/dist/factories/learning.factory.js.map +1 -0
  33. package/dist/factories/task.factory.d.ts +106 -0
  34. package/dist/factories/task.factory.d.ts.map +1 -0
  35. package/dist/factories/task.factory.js +151 -0
  36. package/dist/factories/task.factory.js.map +1 -0
  37. package/dist/fixtures/index.d.ts +36 -0
  38. package/dist/fixtures/index.d.ts.map +1 -0
  39. package/dist/fixtures/index.js +47 -0
  40. package/dist/fixtures/index.js.map +1 -0
  41. package/dist/helpers/effect.d.ts +186 -0
  42. package/dist/helpers/effect.d.ts.map +1 -0
  43. package/dist/helpers/effect.js +298 -0
  44. package/dist/helpers/effect.js.map +1 -0
  45. package/dist/helpers/effect.test.d.ts +7 -0
  46. package/dist/helpers/effect.test.d.ts.map +1 -0
  47. package/dist/helpers/effect.test.js +271 -0
  48. package/dist/helpers/effect.test.js.map +1 -0
  49. package/dist/helpers/index.d.ts +7 -0
  50. package/dist/helpers/index.d.ts.map +1 -0
  51. package/dist/helpers/index.js +11 -0
  52. package/dist/helpers/index.js.map +1 -0
  53. package/dist/index.d.ts +26 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +52 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/llm-cache/cache.d.ts +152 -0
  58. package/dist/llm-cache/cache.d.ts.map +1 -0
  59. package/dist/llm-cache/cache.js +199 -0
  60. package/dist/llm-cache/cache.js.map +1 -0
  61. package/dist/llm-cache/cache.test.d.ts +7 -0
  62. package/dist/llm-cache/cache.test.d.ts.map +1 -0
  63. package/dist/llm-cache/cache.test.js +310 -0
  64. package/dist/llm-cache/cache.test.js.map +1 -0
  65. package/dist/llm-cache/cli.d.ts +113 -0
  66. package/dist/llm-cache/cli.d.ts.map +1 -0
  67. package/dist/llm-cache/cli.js +248 -0
  68. package/dist/llm-cache/cli.js.map +1 -0
  69. package/dist/llm-cache/index.d.ts +31 -0
  70. package/dist/llm-cache/index.d.ts.map +1 -0
  71. package/dist/llm-cache/index.js +31 -0
  72. package/dist/llm-cache/index.js.map +1 -0
  73. package/dist/mocks/anthropic.mock.d.ts +173 -0
  74. package/dist/mocks/anthropic.mock.d.ts.map +1 -0
  75. package/dist/mocks/anthropic.mock.js +125 -0
  76. package/dist/mocks/anthropic.mock.js.map +1 -0
  77. package/dist/mocks/ast-grep.mock.d.ts +216 -0
  78. package/dist/mocks/ast-grep.mock.d.ts.map +1 -0
  79. package/dist/mocks/ast-grep.mock.js +164 -0
  80. package/dist/mocks/ast-grep.mock.js.map +1 -0
  81. package/dist/mocks/file-system.mock.d.ts +181 -0
  82. package/dist/mocks/file-system.mock.d.ts.map +1 -0
  83. package/dist/mocks/file-system.mock.js +280 -0
  84. package/dist/mocks/file-system.mock.js.map +1 -0
  85. package/dist/mocks/index.d.ts +10 -0
  86. package/dist/mocks/index.d.ts.map +1 -0
  87. package/dist/mocks/index.js +16 -0
  88. package/dist/mocks/index.js.map +1 -0
  89. package/dist/mocks/mocks.test.d.ts +10 -0
  90. package/dist/mocks/mocks.test.d.ts.map +1 -0
  91. package/dist/mocks/mocks.test.js +961 -0
  92. package/dist/mocks/mocks.test.js.map +1 -0
  93. package/dist/mocks/openai.mock.d.ts +205 -0
  94. package/dist/mocks/openai.mock.d.ts.map +1 -0
  95. package/dist/mocks/openai.mock.js +178 -0
  96. package/dist/mocks/openai.mock.js.map +1 -0
  97. package/dist/setup/index.d.ts +7 -0
  98. package/dist/setup/index.d.ts.map +1 -0
  99. package/dist/setup/index.js +9 -0
  100. package/dist/setup/index.js.map +1 -0
  101. package/package.json +80 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/llm-cache/cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAkB,UAAU,EAAE,MAAM,YAAY,CAAA;AAMvD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,8CAA8C;IAC9C,UAAU,EAAE,IAAI,GAAG,IAAI,CAAA;IACvB,8CAA8C;IAC9C,UAAU,EAAE,IAAI,GAAG,IAAI,CAAA;IACvB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yBAAyB;IACzB,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,UAAU,CAqDxD,CAAA;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,UAAU,GAAU,UAAS,iBAAsB,KAAG,OAAO,CAAC,MAAM,CA+ChF,CAAA;AA2BD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,UAAU,KAAG,MA4BpD,CAAA;AAMD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAU,CAAC,GAAG,OAAO,EAAE,MAAM,MAAM,KAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAU3F,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAAa,OAAO,CAAC,MAAM,EAAE,CAWzD,CAAA"}
@@ -0,0 +1,248 @@
1
+ /**
2
+ * CLI utilities for LLM cache management.
3
+ *
4
+ * Provides functions to inspect, clear, and manage the LLM response cache.
5
+ *
6
+ * @module @tx/test-utils/llm-cache/cli
7
+ */
8
+ import * as fs from "fs/promises";
9
+ import * as path from "path";
10
+ import { getCacheConfig } from "./cache.js";
11
+ // =============================================================================
12
+ // Cache Statistics
13
+ // =============================================================================
14
+ /**
15
+ * Get statistics about the LLM cache.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const stats = await getCacheStats()
20
+ * console.log(`Cache has ${stats.count} entries using ${stats.totalBytes} bytes`)
21
+ * console.log(`Models: ${Object.keys(stats.byModel).join(', ')}`)
22
+ * ```
23
+ */
24
+ export const getCacheStats = async () => {
25
+ const config = getCacheConfig();
26
+ const stats = {
27
+ count: 0,
28
+ totalBytes: 0,
29
+ oldestDate: null,
30
+ newestDate: null,
31
+ byModel: {},
32
+ byVersion: {}
33
+ };
34
+ let files;
35
+ try {
36
+ files = await fs.readdir(config.cacheDir);
37
+ }
38
+ catch {
39
+ // Directory doesn't exist - return empty stats
40
+ return stats;
41
+ }
42
+ const jsonFiles = files.filter((f) => f.endsWith(".json"));
43
+ stats.count = jsonFiles.length;
44
+ for (const file of jsonFiles) {
45
+ const filePath = path.join(config.cacheDir, file);
46
+ try {
47
+ const stat = await fs.stat(filePath);
48
+ stats.totalBytes += stat.size;
49
+ const content = await fs.readFile(filePath, "utf-8");
50
+ const entry = JSON.parse(content);
51
+ // Track by model
52
+ stats.byModel[entry.model] = (stats.byModel[entry.model] ?? 0) + 1;
53
+ // Track by version
54
+ stats.byVersion[entry.version] = (stats.byVersion[entry.version] ?? 0) + 1;
55
+ // Track date range
56
+ const date = new Date(entry.cachedAt);
57
+ if (!stats.oldestDate || date < stats.oldestDate) {
58
+ stats.oldestDate = date;
59
+ }
60
+ if (!stats.newestDate || date > stats.newestDate) {
61
+ stats.newestDate = date;
62
+ }
63
+ }
64
+ catch {
65
+ // Skip corrupted files
66
+ continue;
67
+ }
68
+ }
69
+ return stats;
70
+ };
71
+ // =============================================================================
72
+ // Cache Clearing
73
+ // =============================================================================
74
+ /**
75
+ * Clear cache entries based on options.
76
+ *
77
+ * @returns Number of entries deleted (-1 if unknown when using `all`)
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * // Clear all cache
82
+ * await clearCache({ all: true })
83
+ *
84
+ * // Clear entries older than 30 days
85
+ * const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
86
+ * const deleted = await clearCache({ olderThan: thirtyDaysAgo })
87
+ *
88
+ * // Clear entries for specific model
89
+ * await clearCache({ model: 'claude-haiku' })
90
+ *
91
+ * // Clear entries with specific version (useful after schema changes)
92
+ * await clearCache({ version: 1 })
93
+ * ```
94
+ */
95
+ export const clearCache = async (options = {}) => {
96
+ const config = getCacheConfig();
97
+ // Clear all - fastest path
98
+ if (options.all) {
99
+ try {
100
+ await fs.rm(config.cacheDir, { recursive: true, force: true });
101
+ await fs.mkdir(config.cacheDir, { recursive: true });
102
+ }
103
+ catch {
104
+ // Directory may not exist
105
+ }
106
+ return -1; // Unknown count
107
+ }
108
+ let files;
109
+ try {
110
+ files = await fs.readdir(config.cacheDir);
111
+ }
112
+ catch {
113
+ return 0; // Directory doesn't exist
114
+ }
115
+ const jsonFiles = files.filter((f) => f.endsWith(".json"));
116
+ let deleted = 0;
117
+ for (const file of jsonFiles) {
118
+ const filePath = path.join(config.cacheDir, file);
119
+ try {
120
+ const content = await fs.readFile(filePath, "utf-8");
121
+ const entry = JSON.parse(content);
122
+ const shouldDelete = (options.olderThan && new Date(entry.cachedAt) < options.olderThan) ||
123
+ (options.model && entry.model === options.model) ||
124
+ (options.version !== undefined && entry.version === options.version);
125
+ if (shouldDelete) {
126
+ await fs.unlink(filePath);
127
+ deleted++;
128
+ }
129
+ }
130
+ catch {
131
+ // Skip files that can't be read
132
+ continue;
133
+ }
134
+ }
135
+ return deleted;
136
+ };
137
+ // =============================================================================
138
+ // Formatting
139
+ // =============================================================================
140
+ /**
141
+ * Format bytes into human-readable string.
142
+ */
143
+ const formatBytes = (bytes) => {
144
+ if (bytes === 0)
145
+ return "0 B";
146
+ const units = ["B", "KB", "MB", "GB"];
147
+ const k = 1024;
148
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
149
+ return `${(bytes / Math.pow(k, i)).toFixed(1)} ${units[i]}`;
150
+ };
151
+ /**
152
+ * Format date for display.
153
+ */
154
+ const formatDate = (date) => {
155
+ if (!date)
156
+ return "N/A";
157
+ return date.toISOString().split("T")[0];
158
+ };
159
+ /**
160
+ * Format cache statistics for display.
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * const stats = await getCacheStats()
165
+ * console.log(formatCacheStats(stats))
166
+ * // Output:
167
+ * // LLM Cache Statistics:
168
+ * // Entries: 142
169
+ * // Size: 3.2 MB
170
+ * // Date range: 2024-01-15 to 2024-02-01
171
+ * // By model:
172
+ * // claude-sonnet-4: 98
173
+ * // claude-haiku: 44
174
+ * ```
175
+ */
176
+ export const formatCacheStats = (stats) => {
177
+ const lines = [
178
+ "LLM Cache Statistics:",
179
+ ` Entries: ${stats.count}`,
180
+ ` Size: ${formatBytes(stats.totalBytes)}`
181
+ ];
182
+ if (stats.oldestDate && stats.newestDate) {
183
+ lines.push(` Date range: ${formatDate(stats.oldestDate)} to ${formatDate(stats.newestDate)}`);
184
+ }
185
+ const models = Object.entries(stats.byModel);
186
+ if (models.length > 0) {
187
+ lines.push(" By model:");
188
+ for (const [model, count] of models.sort((a, b) => b[1] - a[1])) {
189
+ lines.push(` ${model}: ${count}`);
190
+ }
191
+ }
192
+ const versions = Object.entries(stats.byVersion);
193
+ if (versions.length > 1) {
194
+ lines.push(" By version:");
195
+ for (const [version, count] of versions.sort((a, b) => Number(b[0]) - Number(a[0]))) {
196
+ lines.push(` v${version}: ${count}`);
197
+ }
198
+ }
199
+ return lines.join("\n");
200
+ };
201
+ // =============================================================================
202
+ // Cache Entry Inspection
203
+ // =============================================================================
204
+ /**
205
+ * Get a specific cache entry by hash.
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * const entry = await getCacheEntry('a1b2c3d4...')
210
+ * if (entry) {
211
+ * console.log(`Cached at: ${entry.cachedAt}`)
212
+ * console.log(`Model: ${entry.model}`)
213
+ * }
214
+ * ```
215
+ */
216
+ export const getCacheEntry = async (hash) => {
217
+ const config = getCacheConfig();
218
+ const filePath = path.join(config.cacheDir, `${hash}.json`);
219
+ try {
220
+ const content = await fs.readFile(filePath, "utf-8");
221
+ return JSON.parse(content);
222
+ }
223
+ catch {
224
+ return null;
225
+ }
226
+ };
227
+ /**
228
+ * List all cache entry hashes.
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * const hashes = await listCacheEntries()
233
+ * console.log(`Found ${hashes.length} cached responses`)
234
+ * ```
235
+ */
236
+ export const listCacheEntries = async () => {
237
+ const config = getCacheConfig();
238
+ try {
239
+ const files = await fs.readdir(config.cacheDir);
240
+ return files
241
+ .filter((f) => f.endsWith(".json"))
242
+ .map((f) => f.replace(".json", ""));
243
+ }
244
+ catch {
245
+ return [];
246
+ }
247
+ };
248
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/llm-cache/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * LLM response caching for deterministic tests.
3
+ *
4
+ * Caches expensive LLM API calls by hashing inputs with SHA256.
5
+ * Enables fast, repeatable tests without hitting real APIs.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { cachedLLMCall, withLLMCache, hashInput } from '@tx/test-utils/llm-cache'
10
+ *
11
+ * // Direct caching
12
+ * const result = await cachedLLMCall(
13
+ * "What is 2+2?",
14
+ * "claude-sonnet-4",
15
+ * () => anthropic.messages.create({...})
16
+ * )
17
+ *
18
+ * // Wrapper pattern
19
+ * const cachedExtract = withLLMCache(extractCandidates, {
20
+ * model: "claude-sonnet-4",
21
+ * version: 1
22
+ * })
23
+ * ```
24
+ *
25
+ * @module @tx/test-utils/llm-cache
26
+ */
27
+ export { hashInput, cachedLLMCall, withLLMCache, configureLLMCache, getCacheConfig, resetCacheConfig } from "./cache.js";
28
+ export type { CacheEntry, CachedLLMCallOptions, WithLLMCacheOptions } from "./cache.js";
29
+ export { getCacheStats, clearCache, formatCacheStats, getCacheEntry, listCacheEntries } from "./cli.js";
30
+ export type { CacheStats, ClearCacheOptions } from "./cli.js";
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EACL,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAGnB,YAAY,EACV,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EACjB,MAAM,UAAU,CAAA;AAGjB,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * LLM response caching for deterministic tests.
3
+ *
4
+ * Caches expensive LLM API calls by hashing inputs with SHA256.
5
+ * Enables fast, repeatable tests without hitting real APIs.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { cachedLLMCall, withLLMCache, hashInput } from '@tx/test-utils/llm-cache'
10
+ *
11
+ * // Direct caching
12
+ * const result = await cachedLLMCall(
13
+ * "What is 2+2?",
14
+ * "claude-sonnet-4",
15
+ * () => anthropic.messages.create({...})
16
+ * )
17
+ *
18
+ * // Wrapper pattern
19
+ * const cachedExtract = withLLMCache(extractCandidates, {
20
+ * model: "claude-sonnet-4",
21
+ * version: 1
22
+ * })
23
+ * ```
24
+ *
25
+ * @module @tx/test-utils/llm-cache
26
+ */
27
+ // Core caching functions
28
+ export { hashInput, cachedLLMCall, withLLMCache, configureLLMCache, getCacheConfig, resetCacheConfig } from "./cache.js";
29
+ // CLI utilities
30
+ export { getCacheStats, clearCache, formatCacheStats, getCacheEntry, listCacheEntries } from "./cli.js";
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,yBAAyB;AACzB,OAAO,EACL,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAA;AASnB,gBAAgB;AAChB,OAAO,EACL,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EACjB,MAAM,UAAU,CAAA"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Mock Anthropic client for testing.
3
+ *
4
+ * Provides configurable mock Anthropic clients with call tracking,
5
+ * response fixtures, and failure injection for testing services
6
+ * that depend on the Anthropic API.
7
+ *
8
+ * @module @tx/test-utils/mocks/anthropic
9
+ */
10
+ /**
11
+ * Message structure matching Anthropic SDK format.
12
+ */
13
+ export interface MockMessage {
14
+ role: "user" | "assistant";
15
+ content: string;
16
+ }
17
+ /**
18
+ * Tracked API call parameters.
19
+ */
20
+ export interface MockAnthropicCall {
21
+ model: string;
22
+ messages: Array<{
23
+ role: string;
24
+ content: string;
25
+ }>;
26
+ max_tokens?: number;
27
+ }
28
+ /**
29
+ * Response structure matching Anthropic SDK format.
30
+ */
31
+ export interface MockAnthropicResponse {
32
+ id: string;
33
+ type: "message";
34
+ role: "assistant";
35
+ content: Array<{
36
+ type: string;
37
+ text?: string;
38
+ }>;
39
+ model: string;
40
+ usage?: {
41
+ input_tokens?: number;
42
+ output_tokens?: number;
43
+ };
44
+ }
45
+ /**
46
+ * Configuration options for the mock Anthropic client.
47
+ */
48
+ export interface MockAnthropicConfig {
49
+ /**
50
+ * Map of specific responses keyed by JSON-serialized messages.
51
+ * Allows returning different responses for different inputs.
52
+ */
53
+ responses?: Map<string, MockAnthropicResponse>;
54
+ /**
55
+ * Default response when no specific response matches.
56
+ * If not provided, returns an empty array response.
57
+ */
58
+ defaultResponse?: MockAnthropicResponse;
59
+ /**
60
+ * When true, all API calls will throw an error.
61
+ */
62
+ shouldFail?: boolean;
63
+ /**
64
+ * Custom error message when shouldFail is true.
65
+ * Defaults to "Mock Anthropic API error".
66
+ */
67
+ failureMessage?: string;
68
+ /**
69
+ * Custom error to throw when shouldFail is true.
70
+ * Takes precedence over failureMessage.
71
+ */
72
+ failureError?: Error;
73
+ /**
74
+ * Simulated latency in milliseconds.
75
+ * Useful for testing timeout handling.
76
+ */
77
+ latencyMs?: number;
78
+ }
79
+ /**
80
+ * Result returned by createMockAnthropic.
81
+ */
82
+ export interface MockAnthropicResult {
83
+ /**
84
+ * The mock client that can be used in place of the real Anthropic SDK.
85
+ */
86
+ client: {
87
+ messages: {
88
+ create(params: MockAnthropicCall): Promise<MockAnthropicResponse>;
89
+ };
90
+ };
91
+ /**
92
+ * Array of all calls made to the mock client.
93
+ * Useful for assertions about API usage.
94
+ */
95
+ calls: MockAnthropicCall[];
96
+ /**
97
+ * Reset the calls array to empty.
98
+ */
99
+ reset: () => void;
100
+ /**
101
+ * Get the total number of calls made.
102
+ */
103
+ getCallCount: () => number;
104
+ /**
105
+ * Get the most recent call made, or undefined if no calls.
106
+ */
107
+ getLastCall: () => MockAnthropicCall | undefined;
108
+ }
109
+ /**
110
+ * Create a mock Anthropic client for testing.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * // Basic usage
115
+ * const mock = createMockAnthropic()
116
+ * const response = await mock.client.messages.create({
117
+ * model: "claude-haiku-4-20250514",
118
+ * max_tokens: 256,
119
+ * messages: [{ role: "user", content: "Hello" }]
120
+ * })
121
+ * expect(mock.calls).toHaveLength(1)
122
+ * ```
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * // With custom response
127
+ * const mock = createMockAnthropic({
128
+ * defaultResponse: {
129
+ * id: "test-id",
130
+ * type: "message",
131
+ * role: "assistant",
132
+ * content: [{ type: "text", text: "Custom response" }],
133
+ * model: "claude-haiku-4-20250514",
134
+ * usage: { input_tokens: 10, output_tokens: 5 }
135
+ * }
136
+ * })
137
+ * ```
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * // With failure injection
142
+ * const mock = createMockAnthropic({
143
+ * shouldFail: true,
144
+ * failureMessage: "Rate limit exceeded"
145
+ * })
146
+ * await expect(mock.client.messages.create(params)).rejects.toThrow("Rate limit exceeded")
147
+ * ```
148
+ */
149
+ export declare const createMockAnthropic: (config?: MockAnthropicConfig) => MockAnthropicResult;
150
+ /**
151
+ * Create a mock Anthropic client configured to return specific extraction candidates.
152
+ *
153
+ * This is a convenience factory for testing CandidateExtractorService and similar
154
+ * services that expect JSON array responses from the LLM.
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const mock = createMockAnthropicForExtraction([
159
+ * { content: "Always use transactions", confidence: "high", category: "patterns" },
160
+ * { content: "Test database migrations", confidence: "medium", category: "testing" }
161
+ * ])
162
+ *
163
+ * // The mock will return these candidates as JSON text
164
+ * const response = await mock.client.messages.create({ ... })
165
+ * // response.content[0].text === '[{"content":"Always use transactions",...}]'
166
+ * ```
167
+ */
168
+ export declare const createMockAnthropicForExtraction: (candidates: Array<{
169
+ content: string;
170
+ confidence: string;
171
+ category: string;
172
+ }>) => MockAnthropicResult;
173
+ //# sourceMappingURL=anthropic.mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.mock.d.ts","sourceRoot":"","sources":["../../src/mocks/anthropic.mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC/C,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;IAC9C;;;OAGG;IACH,eAAe,CAAC,EAAE,qBAAqB,CAAA;IACvC;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;SAClE,CAAA;KACF,CAAA;IACD;;;OAGG;IACH,KAAK,EAAE,iBAAiB,EAAE,CAAA;IAC1B;;OAEG;IACH,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB;;OAEG;IACH,YAAY,EAAE,MAAM,MAAM,CAAA;IAC1B;;OAEG;IACH,WAAW,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAAA;CACjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAQ,mBAAwB,KAAG,mBAkDtE,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gCAAgC,GAC3C,YAAY,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,KAC3E,mBAWF,CAAA"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Mock Anthropic client for testing.
3
+ *
4
+ * Provides configurable mock Anthropic clients with call tracking,
5
+ * response fixtures, and failure injection for testing services
6
+ * that depend on the Anthropic API.
7
+ *
8
+ * @module @tx/test-utils/mocks/anthropic
9
+ */
10
+ /**
11
+ * Create a mock Anthropic client for testing.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // Basic usage
16
+ * const mock = createMockAnthropic()
17
+ * const response = await mock.client.messages.create({
18
+ * model: "claude-haiku-4-20250514",
19
+ * max_tokens: 256,
20
+ * messages: [{ role: "user", content: "Hello" }]
21
+ * })
22
+ * expect(mock.calls).toHaveLength(1)
23
+ * ```
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // With custom response
28
+ * const mock = createMockAnthropic({
29
+ * defaultResponse: {
30
+ * id: "test-id",
31
+ * type: "message",
32
+ * role: "assistant",
33
+ * content: [{ type: "text", text: "Custom response" }],
34
+ * model: "claude-haiku-4-20250514",
35
+ * usage: { input_tokens: 10, output_tokens: 5 }
36
+ * }
37
+ * })
38
+ * ```
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // With failure injection
43
+ * const mock = createMockAnthropic({
44
+ * shouldFail: true,
45
+ * failureMessage: "Rate limit exceeded"
46
+ * })
47
+ * await expect(mock.client.messages.create(params)).rejects.toThrow("Rate limit exceeded")
48
+ * ```
49
+ */
50
+ export const createMockAnthropic = (config = {}) => {
51
+ const calls = [];
52
+ const client = {
53
+ messages: {
54
+ create: async (params) => {
55
+ // Track the call
56
+ calls.push(params);
57
+ // Simulate latency if configured
58
+ if (config.latencyMs) {
59
+ await new Promise(resolve => setTimeout(resolve, config.latencyMs));
60
+ }
61
+ // Handle failure injection
62
+ if (config.shouldFail) {
63
+ throw config.failureError || new Error(config.failureMessage || "Mock Anthropic API error");
64
+ }
65
+ // Check for specific response by message content
66
+ if (config.responses) {
67
+ const key = JSON.stringify(params.messages);
68
+ const specificResponse = config.responses.get(key);
69
+ if (specificResponse) {
70
+ return specificResponse;
71
+ }
72
+ }
73
+ // Return default response or a minimal valid response
74
+ return config.defaultResponse || {
75
+ id: "mock-msg-id",
76
+ type: "message",
77
+ role: "assistant",
78
+ content: [{ type: "text", text: "[]" }],
79
+ model: params.model,
80
+ usage: { input_tokens: 10, output_tokens: 5 }
81
+ };
82
+ }
83
+ }
84
+ };
85
+ return {
86
+ client,
87
+ calls,
88
+ reset: () => {
89
+ calls.length = 0;
90
+ },
91
+ getCallCount: () => calls.length,
92
+ getLastCall: () => calls[calls.length - 1]
93
+ };
94
+ };
95
+ /**
96
+ * Create a mock Anthropic client configured to return specific extraction candidates.
97
+ *
98
+ * This is a convenience factory for testing CandidateExtractorService and similar
99
+ * services that expect JSON array responses from the LLM.
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const mock = createMockAnthropicForExtraction([
104
+ * { content: "Always use transactions", confidence: "high", category: "patterns" },
105
+ * { content: "Test database migrations", confidence: "medium", category: "testing" }
106
+ * ])
107
+ *
108
+ * // The mock will return these candidates as JSON text
109
+ * const response = await mock.client.messages.create({ ... })
110
+ * // response.content[0].text === '[{"content":"Always use transactions",...}]'
111
+ * ```
112
+ */
113
+ export const createMockAnthropicForExtraction = (candidates) => {
114
+ return createMockAnthropic({
115
+ defaultResponse: {
116
+ id: "mock-extraction-id",
117
+ type: "message",
118
+ role: "assistant",
119
+ content: [{ type: "text", text: JSON.stringify(candidates) }],
120
+ model: "claude-haiku-4-20250514",
121
+ usage: { input_tokens: 100, output_tokens: 50 }
122
+ }
123
+ });
124
+ };
125
+ //# sourceMappingURL=anthropic.mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.mock.js","sourceRoot":"","sources":["../../src/mocks/anthropic.mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiGH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,SAA8B,EAAE,EAAuB,EAAE;IAC3F,MAAM,KAAK,GAAwB,EAAE,CAAA;IAErC,MAAM,MAAM,GAAG;QACb,QAAQ,EAAE;YACR,MAAM,EAAE,KAAK,EAAE,MAAyB,EAAkC,EAAE;gBAC1E,iBAAiB;gBACjB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAElB,iCAAiC;gBACjC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBACrB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAA;gBACrE,CAAC;gBAED,2BAA2B;gBAC3B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;oBACtB,MAAM,MAAM,CAAC,YAAY,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,cAAc,IAAI,0BAA0B,CAAC,CAAA;gBAC7F,CAAC;gBAED,iDAAiD;gBACjD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBACrB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;oBAC3C,MAAM,gBAAgB,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;oBAClD,IAAI,gBAAgB,EAAE,CAAC;wBACrB,OAAO,gBAAgB,CAAA;oBACzB,CAAC;gBACH,CAAC;gBAED,sDAAsD;gBACtD,OAAO,MAAM,CAAC,eAAe,IAAI;oBAC/B,EAAE,EAAE,aAAa;oBACjB,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;oBACvC,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE;iBAC9C,CAAA;YACH,CAAC;SACF;KACF,CAAA;IAED,OAAO;QACL,MAAM;QACN,KAAK;QACL,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;QAClB,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM;QAChC,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;KAC3C,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,UAA4E,EACvD,EAAE;IACvB,OAAO,mBAAmB,CAAC;QACzB,eAAe,EAAE;YACf,EAAE,EAAE,oBAAoB;YACxB,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7D,KAAK,EAAE,yBAAyB;YAChC,KAAK,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE;SAChD;KACF,CAAC,CAAA;AACJ,CAAC,CAAA"}