@use-lattice/litmus 0.121.3

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 (199) hide show
  1. package/LICENSE +19 -0
  2. package/dist/src/accounts-Bt1oJb1Z.cjs +219 -0
  3. package/dist/src/accounts-DjOU8Rm3.js +178 -0
  4. package/dist/src/agentic-utils-D03IiXQc.js +153 -0
  5. package/dist/src/agentic-utils-Dh7xaMQM.cjs +180 -0
  6. package/dist/src/agents-C6BIMlZa.js +231 -0
  7. package/dist/src/agents-DvIpNX1L.cjs +666 -0
  8. package/dist/src/agents-ZP0RP9vV.cjs +231 -0
  9. package/dist/src/agents-maJXdjbR.js +665 -0
  10. package/dist/src/aimlapi-BTbQjG2E.cjs +30 -0
  11. package/dist/src/aimlapi-CwMxqfXP.js +30 -0
  12. package/dist/src/audio-BBUdvsde.cjs +97 -0
  13. package/dist/src/audio-D5DPZ7I-.js +97 -0
  14. package/dist/src/base-BEysXrkq.cjs +222 -0
  15. package/dist/src/base-C451JQfq.js +193 -0
  16. package/dist/src/blobs-BY8MDmpo.js +230 -0
  17. package/dist/src/blobs-BgcNn97m.cjs +256 -0
  18. package/dist/src/cache-BBE_lsTA.cjs +4 -0
  19. package/dist/src/cache-BkrqU5Ba.js +237 -0
  20. package/dist/src/cache-DsCxFlsZ.cjs +297 -0
  21. package/dist/src/chat-CPJWDP6a.cjs +289 -0
  22. package/dist/src/chat-CXX3xzkk.cjs +811 -0
  23. package/dist/src/chat-CcDgZFJ4.js +787 -0
  24. package/dist/src/chat-Dz5ZeGO2.js +289 -0
  25. package/dist/src/chatkit-Dw0mKkML.cjs +1158 -0
  26. package/dist/src/chatkit-swAIVuea.js +1157 -0
  27. package/dist/src/chunk-DEq-mXcV.js +15 -0
  28. package/dist/src/claude-agent-sdk-BXZJtOg6.js +379 -0
  29. package/dist/src/claude-agent-sdk-CkfyjDoG.cjs +383 -0
  30. package/dist/src/cloudflare-ai-BzpJcqUH.js +161 -0
  31. package/dist/src/cloudflare-ai-Cmy_R1y2.cjs +161 -0
  32. package/dist/src/cloudflare-gateway-B9tVQKok.cjs +272 -0
  33. package/dist/src/cloudflare-gateway-DrD3ew3H.js +272 -0
  34. package/dist/src/codex-sdk-Dezj9Nwm.js +1056 -0
  35. package/dist/src/codex-sdk-Dl9D4k5B.cjs +1060 -0
  36. package/dist/src/cometapi-C-9YvCHC.js +54 -0
  37. package/dist/src/cometapi-DHgDKoO2.cjs +54 -0
  38. package/dist/src/completion-B8Ctyxpr.js +120 -0
  39. package/dist/src/completion-Cxrt08sj.cjs +131 -0
  40. package/dist/src/createHash-BwgE13yv.cjs +27 -0
  41. package/dist/src/createHash-DmPQkvBh.js +15 -0
  42. package/dist/src/docker-BiqcTwLv.js +80 -0
  43. package/dist/src/docker-C7tEJnP-.cjs +80 -0
  44. package/dist/src/esm-C62Zofr1.cjs +409 -0
  45. package/dist/src/esm-DMVc93eh.js +379 -0
  46. package/dist/src/evalResult-C3NJPQOo.cjs +301 -0
  47. package/dist/src/evalResult-C7JJAPBb.js +295 -0
  48. package/dist/src/evalResult-DoVTZZWI.cjs +2 -0
  49. package/dist/src/extractor-DnMD3fwt.cjs +391 -0
  50. package/dist/src/extractor-DtlL28vL.js +374 -0
  51. package/dist/src/fetch-BTxakTSg.cjs +1133 -0
  52. package/dist/src/fetch-DQckpUFz.js +928 -0
  53. package/dist/src/fileExtensions-DnqA1y9x.js +85 -0
  54. package/dist/src/fileExtensions-bYh77CN8.cjs +114 -0
  55. package/dist/src/genaiTracer-CyZrmaK0.cjs +268 -0
  56. package/dist/src/genaiTracer-D3fD9dNV.js +256 -0
  57. package/dist/src/graders-BNscxFrU.js +13644 -0
  58. package/dist/src/graders-D2oE9Msq.js +2 -0
  59. package/dist/src/graders-c0Ez_w-9.cjs +2 -0
  60. package/dist/src/graders-d0F2M3e9.cjs +14056 -0
  61. package/dist/src/image-0ZhE0VlR.cjs +280 -0
  62. package/dist/src/image-CWE1pdNv.js +257 -0
  63. package/dist/src/image-D9ZK6hwL.js +163 -0
  64. package/dist/src/image-DKZgZITg.cjs +163 -0
  65. package/dist/src/index.cjs +11366 -0
  66. package/dist/src/index.d.cts +19640 -0
  67. package/dist/src/index.d.ts +19641 -0
  68. package/dist/src/index.js +11306 -0
  69. package/dist/src/invariant-Ddh24eXh.js +25 -0
  70. package/dist/src/invariant-kfQ8Bu82.cjs +30 -0
  71. package/dist/src/knowledgeBase-BgPyGFUd.cjs +122 -0
  72. package/dist/src/knowledgeBase-DyHilYaP.js +122 -0
  73. package/dist/src/litellm-CyMeneHS.js +135 -0
  74. package/dist/src/litellm-DWDF73yF.cjs +135 -0
  75. package/dist/src/logger-C40ZGil9.js +717 -0
  76. package/dist/src/logger-DyfK9PBt.cjs +917 -0
  77. package/dist/src/luma-ray-BAU9X_ep.cjs +315 -0
  78. package/dist/src/luma-ray-nwVseBbv.js +313 -0
  79. package/dist/src/messages-B5ADWTTv.js +245 -0
  80. package/dist/src/messages-BCnZfqrS.cjs +257 -0
  81. package/dist/src/meteor-DLZZ3osF.cjs +134 -0
  82. package/dist/src/meteor-DUiCJRC-.js +134 -0
  83. package/dist/src/modelslab-00cveB8L.cjs +163 -0
  84. package/dist/src/modelslab-D9sCU_L7.js +163 -0
  85. package/dist/src/nova-reel-CTapvqYH.js +276 -0
  86. package/dist/src/nova-reel-DlWuuroF.cjs +278 -0
  87. package/dist/src/nova-sonic-5UPWfeMv.cjs +363 -0
  88. package/dist/src/nova-sonic-BhSwQNym.js +363 -0
  89. package/dist/src/openai-BWrJK9d8.cjs +52 -0
  90. package/dist/src/openai-DumO8WQn.js +47 -0
  91. package/dist/src/openclaw-B8brrjC_.cjs +577 -0
  92. package/dist/src/openclaw-Bkayww9q.js +571 -0
  93. package/dist/src/opencode-sdk-7xjoDNiM.cjs +562 -0
  94. package/dist/src/opencode-sdk-SGwAPxht.js +558 -0
  95. package/dist/src/otlpReceiver-CoAHfAN9.cjs +15 -0
  96. package/dist/src/otlpReceiver-oO3EQwI9.js +14 -0
  97. package/dist/src/providerRegistry-4yjhaEM8.js +45 -0
  98. package/dist/src/providerRegistry-DhV4rJIc.cjs +50 -0
  99. package/dist/src/providers-B5RJVG-7.cjs +33609 -0
  100. package/dist/src/providers-BdmZCLzV.js +33262 -0
  101. package/dist/src/providers-CxtRxn8e.js +2 -0
  102. package/dist/src/providers-DnQLNbx1.cjs +3 -0
  103. package/dist/src/pythonUtils-BD0druiM.cjs +275 -0
  104. package/dist/src/pythonUtils-IBhn5YGR.js +249 -0
  105. package/dist/src/quiverai-BDOwZBsM.cjs +213 -0
  106. package/dist/src/quiverai-D3JTF5lD.js +213 -0
  107. package/dist/src/responses-B2LCDCXZ.js +667 -0
  108. package/dist/src/responses-BvNm4Xv9.cjs +685 -0
  109. package/dist/src/rubyUtils-B0NwnfpY.cjs +245 -0
  110. package/dist/src/rubyUtils-BroxzZ7c.cjs +2 -0
  111. package/dist/src/rubyUtils-hqVw5UvJ.js +222 -0
  112. package/dist/src/sagemaker-Cno2V-Sx.js +689 -0
  113. package/dist/src/sagemaker-fV_KUgs5.cjs +691 -0
  114. package/dist/src/server-BOuAXb06.cjs +238 -0
  115. package/dist/src/server-CtI-EWzm.cjs +2 -0
  116. package/dist/src/server-Cy3DZymt.js +189 -0
  117. package/dist/src/slack-CP8xBePa.js +135 -0
  118. package/dist/src/slack-DSQ1yXVb.cjs +135 -0
  119. package/dist/src/store-BwDDaBjb.cjs +246 -0
  120. package/dist/src/store-DcbLC593.cjs +2 -0
  121. package/dist/src/store-IGpqMIkv.js +240 -0
  122. package/dist/src/tables-3Q2cL7So.cjs +373 -0
  123. package/dist/src/tables-Bi2fjr4W.js +288 -0
  124. package/dist/src/telemetry-Bg2WqF79.js +161 -0
  125. package/dist/src/telemetry-D0x6u5kX.cjs +166 -0
  126. package/dist/src/telemetry-DXNimrI0.cjs +2 -0
  127. package/dist/src/text-B_UCRPp2.js +22 -0
  128. package/dist/src/text-CW1cyrwj.cjs +33 -0
  129. package/dist/src/tokenUsageUtils-NYT-WKS6.js +138 -0
  130. package/dist/src/tokenUsageUtils-bVa1ga6f.cjs +173 -0
  131. package/dist/src/transcription-Cl_W16Pr.js +122 -0
  132. package/dist/src/transcription-yt1EecY8.cjs +124 -0
  133. package/dist/src/transform-BCtGrl_W.cjs +228 -0
  134. package/dist/src/transform-Bv6gG2MJ.cjs +1688 -0
  135. package/dist/src/transform-CY1wbpRy.js +1507 -0
  136. package/dist/src/transform-DU8rUL9P.cjs +2 -0
  137. package/dist/src/transform-yWaShiKr.js +216 -0
  138. package/dist/src/transformersAvailability-BGkzavwb.js +35 -0
  139. package/dist/src/transformersAvailability-DKoRtQLy.cjs +35 -0
  140. package/dist/src/types-5aqHpBwE.cjs +3769 -0
  141. package/dist/src/types-Bn6D9c4U.js +3300 -0
  142. package/dist/src/util-BkKlTkI2.js +293 -0
  143. package/dist/src/util-CTh0bfOm.cjs +1119 -0
  144. package/dist/src/util-D17oBwo7.cjs +328 -0
  145. package/dist/src/util-DsS_-v4p.js +613 -0
  146. package/dist/src/util-DuntT1Ga.js +951 -0
  147. package/dist/src/util-aWjdCYMI.cjs +667 -0
  148. package/dist/src/utils-CisQwpjA.js +94 -0
  149. package/dist/src/utils-yWamDvmz.cjs +123 -0
  150. package/dist/tsconfig.tsbuildinfo +1 -0
  151. package/drizzle/0000_lush_hellion.sql +36 -0
  152. package/drizzle/0001_wide_calypso.sql +3 -0
  153. package/drizzle/0002_tidy_juggernaut.sql +1 -0
  154. package/drizzle/0003_lively_naoko.sql +8 -0
  155. package/drizzle/0004_minor_peter_quill.sql +19 -0
  156. package/drizzle/0005_silky_millenium_guard.sql +2 -0
  157. package/drizzle/0006_harsh_caretaker.sql +42 -0
  158. package/drizzle/0007_cloudy_wong.sql +1 -0
  159. package/drizzle/0008_broad_boomer.sql +2 -0
  160. package/drizzle/0009_strong_marten_broadcloak.sql +19 -0
  161. package/drizzle/0010_needy_bishop.sql +11 -0
  162. package/drizzle/0011_moaning_millenium_guard.sql +1 -0
  163. package/drizzle/0012_late_marten_broadcloak.sql +2 -0
  164. package/drizzle/0013_previous_dormammu.sql +9 -0
  165. package/drizzle/0014_lazy_captain_universe.sql +2 -0
  166. package/drizzle/0015_zippy_wallop.sql +29 -0
  167. package/drizzle/0016_jazzy_zemo.sql +2 -0
  168. package/drizzle/0017_reflective_praxagora.sql +4 -0
  169. package/drizzle/0018_fat_vanisher.sql +22 -0
  170. package/drizzle/0019_new_clint_barton.sql +8 -0
  171. package/drizzle/0020_skinny_maverick.sql +1 -0
  172. package/drizzle/0021_mysterious_madelyne_pryor.sql +13 -0
  173. package/drizzle/0022_sleepy_ultimo.sql +25 -0
  174. package/drizzle/0023_wooden_mandrill.sql +2 -0
  175. package/drizzle/AGENTS.md +68 -0
  176. package/drizzle/CLAUDE.md +1 -0
  177. package/drizzle/meta/0000_snapshot.json +221 -0
  178. package/drizzle/meta/0001_snapshot.json +214 -0
  179. package/drizzle/meta/0002_snapshot.json +221 -0
  180. package/drizzle/meta/0005_snapshot.json +369 -0
  181. package/drizzle/meta/0006_snapshot.json +638 -0
  182. package/drizzle/meta/0007_snapshot.json +640 -0
  183. package/drizzle/meta/0008_snapshot.json +649 -0
  184. package/drizzle/meta/0009_snapshot.json +554 -0
  185. package/drizzle/meta/0010_snapshot.json +619 -0
  186. package/drizzle/meta/0011_snapshot.json +627 -0
  187. package/drizzle/meta/0012_snapshot.json +639 -0
  188. package/drizzle/meta/0013_snapshot.json +717 -0
  189. package/drizzle/meta/0014_snapshot.json +717 -0
  190. package/drizzle/meta/0015_snapshot.json +897 -0
  191. package/drizzle/meta/0016_snapshot.json +1031 -0
  192. package/drizzle/meta/0018_snapshot.json +1210 -0
  193. package/drizzle/meta/0019_snapshot.json +1165 -0
  194. package/drizzle/meta/0020_snapshot.json +1232 -0
  195. package/drizzle/meta/0021_snapshot.json +1311 -0
  196. package/drizzle/meta/0022_snapshot.json +1481 -0
  197. package/drizzle/meta/0023_snapshot.json +1496 -0
  198. package/drizzle/meta/_journal.json +174 -0
  199. package/package.json +240 -0
@@ -0,0 +1,230 @@
1
+ import { _ as getConfigDirectoryPath, r as logger } from "./logger-C40ZGil9.js";
2
+ import { n as blobReferencesTable, p as getDb, t as blobAssetsTable } from "./tables-Bi2fjr4W.js";
3
+ import * as path$1 from "node:path";
4
+ import * as fs$1 from "node:fs";
5
+ import * as fsPromises$1 from "node:fs/promises";
6
+ import { createHash, randomUUID } from "node:crypto";
7
+ import { and, eq } from "drizzle-orm";
8
+ //#region src/blobs/constants.ts
9
+ const BLOB_MIN_SIZE = 1024;
10
+ const BLOB_MAX_SIZE = 52428800;
11
+ const BLOB_SCHEME = "promptfoo://blob/";
12
+ const DEFAULT_FILESYSTEM_SUBDIR = "blobs";
13
+ //#endregion
14
+ //#region src/blobs/filesystemProvider.ts
15
+ const BLOB_HASH_REGEX = /^[a-f0-9]{64}$/i;
16
+ function computeHash(data) {
17
+ return createHash("sha256").update(data).digest("hex");
18
+ }
19
+ function buildUri(hash) {
20
+ return `${BLOB_SCHEME}${hash}`;
21
+ }
22
+ var FilesystemBlobStorageProvider = class {
23
+ providerId = "filesystem";
24
+ basePath;
25
+ constructor(config) {
26
+ const defaultBase = path$1.join(getConfigDirectoryPath(true), DEFAULT_FILESYSTEM_SUBDIR);
27
+ this.basePath = path$1.resolve(config?.basePath || defaultBase);
28
+ this.ensureDirectory();
29
+ }
30
+ ensureDirectory() {
31
+ if (!fs$1.existsSync(this.basePath)) {
32
+ fs$1.mkdirSync(this.basePath, { recursive: true });
33
+ logger.debug("[BlobFS] Created blob directory", { basePath: this.basePath });
34
+ }
35
+ }
36
+ assertValidHash(hash) {
37
+ if (!BLOB_HASH_REGEX.test(hash)) throw new Error(`[BlobFS] Invalid blob hash: "${hash}"`);
38
+ }
39
+ resolvePathInBase(unsafePath) {
40
+ const targetPath = path$1.isAbsolute(unsafePath) ? path$1.resolve(unsafePath) : path$1.resolve(this.basePath, unsafePath);
41
+ const safeBase = path$1.resolve(this.basePath) + path$1.sep;
42
+ if (!targetPath.startsWith(safeBase)) throw new Error("[BlobFS] Path traversal attempt detected");
43
+ return targetPath;
44
+ }
45
+ hashToPath(hash) {
46
+ this.assertValidHash(hash);
47
+ const dirRelative = path$1.join(hash.slice(0, 2), hash.slice(2, 4));
48
+ const fileRelative = path$1.join(dirRelative, hash);
49
+ return this.resolvePathInBase(fileRelative);
50
+ }
51
+ async ensureHashDir(hash) {
52
+ this.assertValidHash(hash);
53
+ const dirRelative = path$1.join(hash.slice(0, 2), hash.slice(2, 4));
54
+ const dirPath = this.resolvePathInBase(dirRelative);
55
+ await fsPromises$1.mkdir(dirPath, { recursive: true });
56
+ }
57
+ metadataPath(filePath) {
58
+ return `${filePath}.meta.json`;
59
+ }
60
+ async store(data, mimeType) {
61
+ const hash = computeHash(data);
62
+ await this.ensureHashDir(hash);
63
+ const filePath = this.hashToPath(hash);
64
+ try {
65
+ await fsPromises$1.access(filePath);
66
+ const meta = await this.readMetadata(filePath);
67
+ return {
68
+ ref: this.buildRef(hash, meta?.mimeType ?? mimeType, meta?.sizeBytes ?? data.length, meta?.provider ?? this.providerId),
69
+ deduplicated: true
70
+ };
71
+ } catch {}
72
+ await fsPromises$1.writeFile(filePath, data);
73
+ const metadata = {
74
+ mimeType,
75
+ sizeBytes: data.length,
76
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
77
+ provider: this.providerId,
78
+ key: filePath
79
+ };
80
+ await fsPromises$1.writeFile(this.metadataPath(filePath), JSON.stringify(metadata, null, 2));
81
+ return {
82
+ ref: this.buildRef(hash, mimeType, data.length, this.providerId),
83
+ deduplicated: false
84
+ };
85
+ }
86
+ async getByHash(hash) {
87
+ const filePath = this.hashToPath(hash);
88
+ let data;
89
+ try {
90
+ data = await fsPromises$1.readFile(filePath);
91
+ } catch (error) {
92
+ if (error.code === "ENOENT") throw new Error(`Blob not found: ${hash}`);
93
+ throw error;
94
+ }
95
+ const metadata = await this.readMetadata(filePath) || {
96
+ mimeType: "application/octet-stream",
97
+ sizeBytes: data.length,
98
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
99
+ provider: this.providerId,
100
+ key: filePath
101
+ };
102
+ return {
103
+ data,
104
+ metadata
105
+ };
106
+ }
107
+ async exists(hash) {
108
+ try {
109
+ const filePath = this.hashToPath(hash);
110
+ await fsPromises$1.access(filePath);
111
+ return true;
112
+ } catch {
113
+ return false;
114
+ }
115
+ }
116
+ async deleteByHash(hash) {
117
+ try {
118
+ const filePath = this.hashToPath(hash);
119
+ const metaPath = this.metadataPath(filePath);
120
+ try {
121
+ await fsPromises$1.unlink(filePath);
122
+ } catch (error) {
123
+ if (error.code !== "ENOENT") throw error;
124
+ }
125
+ try {
126
+ await fsPromises$1.unlink(metaPath);
127
+ } catch (error) {
128
+ if (error.code !== "ENOENT") throw error;
129
+ }
130
+ } catch {}
131
+ }
132
+ async getUrl(_hash, _expiresInSeconds) {
133
+ return null;
134
+ }
135
+ buildRef(hash, mimeType, sizeBytes, provider) {
136
+ return {
137
+ uri: buildUri(hash),
138
+ hash,
139
+ mimeType,
140
+ sizeBytes,
141
+ provider
142
+ };
143
+ }
144
+ async readMetadata(filePath) {
145
+ const safeFilePath = this.resolvePathInBase(filePath);
146
+ const metaPath = this.metadataPath(safeFilePath);
147
+ try {
148
+ const raw = await fsPromises$1.readFile(metaPath, "utf8");
149
+ return JSON.parse(raw);
150
+ } catch (error) {
151
+ if (error.code === "ENOENT") return null;
152
+ logger.warn("[BlobFS] Failed to read metadata", { error });
153
+ return null;
154
+ }
155
+ }
156
+ };
157
+ //#endregion
158
+ //#region src/blobs/index.ts
159
+ let defaultProvider = null;
160
+ function createDefaultProvider() {
161
+ return new FilesystemBlobStorageProvider();
162
+ }
163
+ function getBlobStorageProvider() {
164
+ if (!defaultProvider) {
165
+ defaultProvider = createDefaultProvider();
166
+ logger.debug("[BlobStorage] Initialized provider", { provider: defaultProvider.providerId });
167
+ }
168
+ return defaultProvider;
169
+ }
170
+ async function storeBlob(data, mimeType, refContext) {
171
+ const provider = getBlobStorageProvider();
172
+ const result = await provider.store(data, mimeType);
173
+ const db = getDb();
174
+ try {
175
+ db.transaction(() => {
176
+ const assetInsert = db.insert(blobAssetsTable).values({
177
+ hash: result.ref.hash,
178
+ sizeBytes: result.ref.sizeBytes,
179
+ mimeType: result.ref.mimeType,
180
+ provider: result.ref.provider
181
+ }).onConflictDoNothing().run();
182
+ return (refContext?.evalId && db.insert(blobReferencesTable).values({
183
+ id: randomUUID(),
184
+ blobHash: result.ref.hash,
185
+ evalId: refContext.evalId,
186
+ testIdx: refContext.testIdx,
187
+ promptIdx: refContext.promptIdx,
188
+ location: refContext.location,
189
+ kind: refContext.kind
190
+ }).onConflictDoNothing().run()) ?? assetInsert;
191
+ });
192
+ } catch (error) {
193
+ try {
194
+ await provider.deleteByHash(result.ref.hash);
195
+ } catch (cleanupError) {
196
+ logger.warn("[BlobStorage] Failed to rollback blob after DB error", {
197
+ error: cleanupError,
198
+ hash: result.ref.hash
199
+ });
200
+ }
201
+ throw error;
202
+ }
203
+ return result;
204
+ }
205
+ async function recordBlobReference(hash, refContext) {
206
+ if (!refContext.evalId) return;
207
+ if (!await getBlobStorageProvider().exists(hash).catch(() => false)) {
208
+ logger.debug("[BlobStorage] Attempted to record reference for missing blob", {
209
+ hash,
210
+ evalId: refContext.evalId,
211
+ location: refContext.location
212
+ });
213
+ return;
214
+ }
215
+ const db = getDb();
216
+ if (db.select({ id: blobReferencesTable.id }).from(blobReferencesTable).where(and(eq(blobReferencesTable.blobHash, hash), eq(blobReferencesTable.evalId, refContext.evalId))).get()) return;
217
+ db.insert(blobReferencesTable).values({
218
+ id: randomUUID(),
219
+ blobHash: hash,
220
+ evalId: refContext.evalId,
221
+ testIdx: refContext.testIdx,
222
+ promptIdx: refContext.promptIdx,
223
+ location: refContext.location,
224
+ kind: refContext.kind
225
+ }).run();
226
+ }
227
+ //#endregion
228
+ export { BLOB_MIN_SIZE as i, storeBlob as n, BLOB_MAX_SIZE as r, recordBlobReference as t };
229
+
230
+ //# sourceMappingURL=blobs-BY8MDmpo.js.map
@@ -0,0 +1,256 @@
1
+ const require_logger = require("./logger-DyfK9PBt.cjs");
2
+ const require_tables = require("./tables-3Q2cL7So.cjs");
3
+ let node_fs = require("node:fs");
4
+ node_fs = require_logger.__toESM(node_fs);
5
+ let node_fs_promises = require("node:fs/promises");
6
+ node_fs_promises = require_logger.__toESM(node_fs_promises);
7
+ let node_path = require("node:path");
8
+ node_path = require_logger.__toESM(node_path);
9
+ let node_crypto = require("node:crypto");
10
+ let drizzle_orm = require("drizzle-orm");
11
+ //#region src/blobs/constants.ts
12
+ const BLOB_MIN_SIZE = 1024;
13
+ const BLOB_MAX_SIZE = 52428800;
14
+ const BLOB_SCHEME = "promptfoo://blob/";
15
+ const DEFAULT_FILESYSTEM_SUBDIR = "blobs";
16
+ //#endregion
17
+ //#region src/blobs/filesystemProvider.ts
18
+ const BLOB_HASH_REGEX = /^[a-f0-9]{64}$/i;
19
+ function computeHash(data) {
20
+ return (0, node_crypto.createHash)("sha256").update(data).digest("hex");
21
+ }
22
+ function buildUri(hash) {
23
+ return `${BLOB_SCHEME}${hash}`;
24
+ }
25
+ var FilesystemBlobStorageProvider = class {
26
+ providerId = "filesystem";
27
+ basePath;
28
+ constructor(config) {
29
+ const defaultBase = node_path.join(require_logger.getConfigDirectoryPath(true), DEFAULT_FILESYSTEM_SUBDIR);
30
+ this.basePath = node_path.resolve(config?.basePath || defaultBase);
31
+ this.ensureDirectory();
32
+ }
33
+ ensureDirectory() {
34
+ if (!node_fs.existsSync(this.basePath)) {
35
+ node_fs.mkdirSync(this.basePath, { recursive: true });
36
+ require_logger.logger.debug("[BlobFS] Created blob directory", { basePath: this.basePath });
37
+ }
38
+ }
39
+ assertValidHash(hash) {
40
+ if (!BLOB_HASH_REGEX.test(hash)) throw new Error(`[BlobFS] Invalid blob hash: "${hash}"`);
41
+ }
42
+ resolvePathInBase(unsafePath) {
43
+ const targetPath = node_path.isAbsolute(unsafePath) ? node_path.resolve(unsafePath) : node_path.resolve(this.basePath, unsafePath);
44
+ const safeBase = node_path.resolve(this.basePath) + node_path.sep;
45
+ if (!targetPath.startsWith(safeBase)) throw new Error("[BlobFS] Path traversal attempt detected");
46
+ return targetPath;
47
+ }
48
+ hashToPath(hash) {
49
+ this.assertValidHash(hash);
50
+ const dirRelative = node_path.join(hash.slice(0, 2), hash.slice(2, 4));
51
+ const fileRelative = node_path.join(dirRelative, hash);
52
+ return this.resolvePathInBase(fileRelative);
53
+ }
54
+ async ensureHashDir(hash) {
55
+ this.assertValidHash(hash);
56
+ const dirRelative = node_path.join(hash.slice(0, 2), hash.slice(2, 4));
57
+ const dirPath = this.resolvePathInBase(dirRelative);
58
+ await node_fs_promises.mkdir(dirPath, { recursive: true });
59
+ }
60
+ metadataPath(filePath) {
61
+ return `${filePath}.meta.json`;
62
+ }
63
+ async store(data, mimeType) {
64
+ const hash = computeHash(data);
65
+ await this.ensureHashDir(hash);
66
+ const filePath = this.hashToPath(hash);
67
+ try {
68
+ await node_fs_promises.access(filePath);
69
+ const meta = await this.readMetadata(filePath);
70
+ return {
71
+ ref: this.buildRef(hash, meta?.mimeType ?? mimeType, meta?.sizeBytes ?? data.length, meta?.provider ?? this.providerId),
72
+ deduplicated: true
73
+ };
74
+ } catch {}
75
+ await node_fs_promises.writeFile(filePath, data);
76
+ const metadata = {
77
+ mimeType,
78
+ sizeBytes: data.length,
79
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
80
+ provider: this.providerId,
81
+ key: filePath
82
+ };
83
+ await node_fs_promises.writeFile(this.metadataPath(filePath), JSON.stringify(metadata, null, 2));
84
+ return {
85
+ ref: this.buildRef(hash, mimeType, data.length, this.providerId),
86
+ deduplicated: false
87
+ };
88
+ }
89
+ async getByHash(hash) {
90
+ const filePath = this.hashToPath(hash);
91
+ let data;
92
+ try {
93
+ data = await node_fs_promises.readFile(filePath);
94
+ } catch (error) {
95
+ if (error.code === "ENOENT") throw new Error(`Blob not found: ${hash}`);
96
+ throw error;
97
+ }
98
+ const metadata = await this.readMetadata(filePath) || {
99
+ mimeType: "application/octet-stream",
100
+ sizeBytes: data.length,
101
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
102
+ provider: this.providerId,
103
+ key: filePath
104
+ };
105
+ return {
106
+ data,
107
+ metadata
108
+ };
109
+ }
110
+ async exists(hash) {
111
+ try {
112
+ const filePath = this.hashToPath(hash);
113
+ await node_fs_promises.access(filePath);
114
+ return true;
115
+ } catch {
116
+ return false;
117
+ }
118
+ }
119
+ async deleteByHash(hash) {
120
+ try {
121
+ const filePath = this.hashToPath(hash);
122
+ const metaPath = this.metadataPath(filePath);
123
+ try {
124
+ await node_fs_promises.unlink(filePath);
125
+ } catch (error) {
126
+ if (error.code !== "ENOENT") throw error;
127
+ }
128
+ try {
129
+ await node_fs_promises.unlink(metaPath);
130
+ } catch (error) {
131
+ if (error.code !== "ENOENT") throw error;
132
+ }
133
+ } catch {}
134
+ }
135
+ async getUrl(_hash, _expiresInSeconds) {
136
+ return null;
137
+ }
138
+ buildRef(hash, mimeType, sizeBytes, provider) {
139
+ return {
140
+ uri: buildUri(hash),
141
+ hash,
142
+ mimeType,
143
+ sizeBytes,
144
+ provider
145
+ };
146
+ }
147
+ async readMetadata(filePath) {
148
+ const safeFilePath = this.resolvePathInBase(filePath);
149
+ const metaPath = this.metadataPath(safeFilePath);
150
+ try {
151
+ const raw = await node_fs_promises.readFile(metaPath, "utf8");
152
+ return JSON.parse(raw);
153
+ } catch (error) {
154
+ if (error.code === "ENOENT") return null;
155
+ require_logger.logger.warn("[BlobFS] Failed to read metadata", { error });
156
+ return null;
157
+ }
158
+ }
159
+ };
160
+ //#endregion
161
+ //#region src/blobs/index.ts
162
+ let defaultProvider = null;
163
+ function createDefaultProvider() {
164
+ return new FilesystemBlobStorageProvider();
165
+ }
166
+ function getBlobStorageProvider() {
167
+ if (!defaultProvider) {
168
+ defaultProvider = createDefaultProvider();
169
+ require_logger.logger.debug("[BlobStorage] Initialized provider", { provider: defaultProvider.providerId });
170
+ }
171
+ return defaultProvider;
172
+ }
173
+ async function storeBlob(data, mimeType, refContext) {
174
+ const provider = getBlobStorageProvider();
175
+ const result = await provider.store(data, mimeType);
176
+ const db = require_tables.getDb();
177
+ try {
178
+ db.transaction(() => {
179
+ const assetInsert = db.insert(require_tables.blobAssetsTable).values({
180
+ hash: result.ref.hash,
181
+ sizeBytes: result.ref.sizeBytes,
182
+ mimeType: result.ref.mimeType,
183
+ provider: result.ref.provider
184
+ }).onConflictDoNothing().run();
185
+ return (refContext?.evalId && db.insert(require_tables.blobReferencesTable).values({
186
+ id: (0, node_crypto.randomUUID)(),
187
+ blobHash: result.ref.hash,
188
+ evalId: refContext.evalId,
189
+ testIdx: refContext.testIdx,
190
+ promptIdx: refContext.promptIdx,
191
+ location: refContext.location,
192
+ kind: refContext.kind
193
+ }).onConflictDoNothing().run()) ?? assetInsert;
194
+ });
195
+ } catch (error) {
196
+ try {
197
+ await provider.deleteByHash(result.ref.hash);
198
+ } catch (cleanupError) {
199
+ require_logger.logger.warn("[BlobStorage] Failed to rollback blob after DB error", {
200
+ error: cleanupError,
201
+ hash: result.ref.hash
202
+ });
203
+ }
204
+ throw error;
205
+ }
206
+ return result;
207
+ }
208
+ async function recordBlobReference(hash, refContext) {
209
+ if (!refContext.evalId) return;
210
+ if (!await getBlobStorageProvider().exists(hash).catch(() => false)) {
211
+ require_logger.logger.debug("[BlobStorage] Attempted to record reference for missing blob", {
212
+ hash,
213
+ evalId: refContext.evalId,
214
+ location: refContext.location
215
+ });
216
+ return;
217
+ }
218
+ const db = require_tables.getDb();
219
+ if (db.select({ id: require_tables.blobReferencesTable.id }).from(require_tables.blobReferencesTable).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(require_tables.blobReferencesTable.blobHash, hash), (0, drizzle_orm.eq)(require_tables.blobReferencesTable.evalId, refContext.evalId))).get()) return;
220
+ db.insert(require_tables.blobReferencesTable).values({
221
+ id: (0, node_crypto.randomUUID)(),
222
+ blobHash: hash,
223
+ evalId: refContext.evalId,
224
+ testIdx: refContext.testIdx,
225
+ promptIdx: refContext.promptIdx,
226
+ location: refContext.location,
227
+ kind: refContext.kind
228
+ }).run();
229
+ }
230
+ //#endregion
231
+ Object.defineProperty(exports, "BLOB_MAX_SIZE", {
232
+ enumerable: true,
233
+ get: function() {
234
+ return BLOB_MAX_SIZE;
235
+ }
236
+ });
237
+ Object.defineProperty(exports, "BLOB_MIN_SIZE", {
238
+ enumerable: true,
239
+ get: function() {
240
+ return BLOB_MIN_SIZE;
241
+ }
242
+ });
243
+ Object.defineProperty(exports, "recordBlobReference", {
244
+ enumerable: true,
245
+ get: function() {
246
+ return recordBlobReference;
247
+ }
248
+ });
249
+ Object.defineProperty(exports, "storeBlob", {
250
+ enumerable: true,
251
+ get: function() {
252
+ return storeBlob;
253
+ }
254
+ });
255
+
256
+ //# sourceMappingURL=blobs-BgcNn97m.cjs.map
@@ -0,0 +1,4 @@
1
+ const require_cache = require("./cache-DsCxFlsZ.cjs");
2
+ exports.disableCache = require_cache.disableCache;
3
+ exports.getCache = require_cache.getCache;
4
+ exports.isCacheEnabled = require_cache.isCacheEnabled;