vectra 0.12.2 → 0.14.0

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 (392) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +92 -100
  3. package/bin/vectra.js +3 -0
  4. package/lib/BrowserWebFetcher.d.ts +75 -0
  5. package/lib/BrowserWebFetcher.d.ts.map +1 -0
  6. package/lib/BrowserWebFetcher.js +290 -0
  7. package/lib/BrowserWebFetcher.js.map +1 -0
  8. package/lib/FileFetcher.d.ts +5 -0
  9. package/lib/FileFetcher.d.ts.map +1 -0
  10. package/lib/FileFetcher.js +89 -0
  11. package/lib/FileFetcher.js.map +1 -0
  12. package/lib/FileFetcher.spec.d.ts +2 -0
  13. package/lib/FileFetcher.spec.d.ts.map +1 -0
  14. package/lib/FileFetcher.spec.js +244 -0
  15. package/lib/FileFetcher.spec.js.map +1 -0
  16. package/lib/FolderWatcher.d.ts +91 -0
  17. package/lib/FolderWatcher.d.ts.map +1 -0
  18. package/lib/FolderWatcher.js +304 -0
  19. package/lib/FolderWatcher.js.map +1 -0
  20. package/lib/FolderWatcher.spec.d.ts +2 -0
  21. package/lib/FolderWatcher.spec.d.ts.map +1 -0
  22. package/lib/FolderWatcher.spec.js +308 -0
  23. package/lib/FolderWatcher.spec.js.map +1 -0
  24. package/lib/GPT3Tokenizer.d.ts +9 -0
  25. package/lib/GPT3Tokenizer.spec.d.ts +2 -0
  26. package/lib/GPT3Tokenizer.spec.d.ts.map +1 -0
  27. package/lib/GPT3Tokenizer.spec.js +45 -0
  28. package/lib/GPT3Tokenizer.spec.js.map +1 -0
  29. package/lib/ItemSelector.d.ts +41 -0
  30. package/lib/ItemSelector.d.ts.map +1 -0
  31. package/lib/ItemSelector.js +179 -0
  32. package/lib/ItemSelector.js.map +1 -0
  33. package/lib/ItemSelector.spec.d.ts +2 -0
  34. package/lib/ItemSelector.spec.d.ts.map +1 -0
  35. package/lib/ItemSelector.spec.js +204 -0
  36. package/lib/ItemSelector.spec.js.map +1 -0
  37. package/lib/LocalDocument.d.ts +54 -0
  38. package/lib/LocalDocument.d.ts.map +1 -1
  39. package/lib/LocalDocument.js +116 -0
  40. package/lib/LocalDocument.js.map +1 -0
  41. package/lib/LocalDocument.spec.d.ts +2 -0
  42. package/lib/LocalDocument.spec.d.ts.map +1 -0
  43. package/lib/LocalDocument.spec.js +214 -0
  44. package/lib/LocalDocument.spec.js.map +1 -0
  45. package/lib/LocalDocumentIndex.d.ts +152 -0
  46. package/lib/LocalDocumentIndex.d.ts.map +1 -1
  47. package/lib/LocalDocumentIndex.js +420 -0
  48. package/lib/LocalDocumentIndex.js.map +1 -0
  49. package/lib/LocalDocumentIndex.spec.d.ts +2 -0
  50. package/lib/LocalDocumentIndex.spec.d.ts.map +1 -0
  51. package/lib/LocalDocumentIndex.spec.js +494 -0
  52. package/lib/LocalDocumentIndex.spec.js.map +1 -0
  53. package/lib/LocalDocumentResult.d.ts +66 -0
  54. package/lib/LocalDocumentResult.d.ts.map +1 -1
  55. package/lib/LocalDocumentResult.js +376 -0
  56. package/lib/LocalDocumentResult.js.map +1 -0
  57. package/lib/LocalDocumentResult.spec.d.ts +2 -0
  58. package/lib/LocalDocumentResult.spec.d.ts.map +1 -0
  59. package/lib/LocalDocumentResult.spec.js +373 -0
  60. package/lib/LocalDocumentResult.spec.js.map +1 -0
  61. package/lib/LocalEmbeddings.d.ts +59 -0
  62. package/lib/LocalEmbeddings.d.ts.map +1 -0
  63. package/lib/LocalEmbeddings.js +101 -0
  64. package/lib/LocalEmbeddings.js.map +1 -0
  65. package/lib/LocalEmbeddings.spec.d.ts +2 -0
  66. package/lib/LocalEmbeddings.spec.d.ts.map +1 -0
  67. package/lib/LocalEmbeddings.spec.js +155 -0
  68. package/lib/LocalEmbeddings.spec.js.map +1 -0
  69. package/lib/LocalIndex.d.ts +159 -0
  70. package/lib/LocalIndex.d.ts.map +1 -1
  71. package/lib/LocalIndex.js +519 -0
  72. package/lib/LocalIndex.js.map +1 -0
  73. package/lib/LocalIndex.spec.d.ts +2 -0
  74. package/lib/LocalIndex.spec.js +611 -9
  75. package/lib/LocalIndex.spec.js.map +1 -1
  76. package/lib/OpenAIEmbeddings.d.ts +124 -0
  77. package/lib/OpenAIEmbeddings.d.ts.map +1 -0
  78. package/lib/OpenAIEmbeddings.js +166 -0
  79. package/lib/OpenAIEmbeddings.js.map +1 -0
  80. package/lib/OpenAIEmbeddings.spec.d.ts +2 -0
  81. package/lib/OpenAIEmbeddings.spec.d.ts.map +1 -0
  82. package/lib/OpenAIEmbeddings.spec.js +298 -0
  83. package/lib/OpenAIEmbeddings.spec.js.map +1 -0
  84. package/lib/TextSplitter.d.ts +21 -0
  85. package/lib/TextSplitter.d.ts.map +1 -1
  86. package/lib/TextSplitter.js +500 -0
  87. package/lib/TextSplitter.js.map +1 -0
  88. package/lib/TextSplitter.spec.d.ts +2 -0
  89. package/lib/TextSplitter.spec.d.ts.map +1 -0
  90. package/lib/TextSplitter.spec.js +337 -0
  91. package/lib/TextSplitter.spec.js.map +1 -0
  92. package/lib/TransformersEmbeddings.d.ts +121 -0
  93. package/lib/TransformersEmbeddings.d.ts.map +1 -0
  94. package/lib/TransformersEmbeddings.js +176 -0
  95. package/lib/TransformersEmbeddings.js.map +1 -0
  96. package/lib/TransformersEmbeddings.spec.d.ts +2 -0
  97. package/lib/TransformersEmbeddings.spec.d.ts.map +1 -0
  98. package/lib/TransformersEmbeddings.spec.js +198 -0
  99. package/lib/TransformersEmbeddings.spec.js.map +1 -0
  100. package/lib/TransformersTokenizer.d.ts +33 -0
  101. package/lib/TransformersTokenizer.d.ts.map +1 -0
  102. package/lib/TransformersTokenizer.js +44 -0
  103. package/lib/TransformersTokenizer.js.map +1 -0
  104. package/lib/TransformersTokenizer.spec.d.ts +2 -0
  105. package/lib/TransformersTokenizer.spec.d.ts.map +1 -0
  106. package/lib/TransformersTokenizer.spec.js +112 -0
  107. package/lib/TransformersTokenizer.spec.js.map +1 -0
  108. package/lib/WebFetcher.d.ts +14 -0
  109. package/lib/WebFetcher.d.ts.map +1 -0
  110. package/lib/WebFetcher.js +238 -0
  111. package/lib/WebFetcher.js.map +1 -0
  112. package/lib/WebFetcher.spec.d.ts +2 -0
  113. package/lib/WebFetcher.spec.d.ts.map +1 -0
  114. package/lib/WebFetcher.spec.js +263 -0
  115. package/lib/WebFetcher.spec.js.map +1 -0
  116. package/lib/browser.d.ts +30 -0
  117. package/lib/browser.d.ts.map +1 -0
  118. package/lib/browser.js +52 -0
  119. package/lib/browser.js.map +1 -0
  120. package/lib/codecs/IndexCodec.d.ts +37 -0
  121. package/lib/codecs/IndexCodec.d.ts.map +1 -0
  122. package/lib/codecs/IndexCodec.js +3 -0
  123. package/lib/codecs/IndexCodec.js.map +1 -0
  124. package/lib/codecs/JsonCodec.d.ts +19 -0
  125. package/lib/codecs/JsonCodec.d.ts.map +1 -0
  126. package/lib/codecs/JsonCodec.js +35 -0
  127. package/lib/codecs/JsonCodec.js.map +1 -0
  128. package/lib/codecs/JsonCodec.spec.d.ts +2 -0
  129. package/lib/codecs/JsonCodec.spec.d.ts.map +1 -0
  130. package/lib/codecs/JsonCodec.spec.js +66 -0
  131. package/lib/codecs/JsonCodec.spec.js.map +1 -0
  132. package/lib/codecs/LocalIndex.protobuf.spec.d.ts +2 -0
  133. package/lib/codecs/LocalIndex.protobuf.spec.d.ts.map +1 -0
  134. package/lib/codecs/LocalIndex.protobuf.spec.js +108 -0
  135. package/lib/codecs/LocalIndex.protobuf.spec.js.map +1 -0
  136. package/lib/codecs/ProtobufCodec.d.ts +20 -0
  137. package/lib/codecs/ProtobufCodec.d.ts.map +1 -0
  138. package/lib/codecs/ProtobufCodec.js +225 -0
  139. package/lib/codecs/ProtobufCodec.js.map +1 -0
  140. package/lib/codecs/ProtobufCodec.spec.d.ts +2 -0
  141. package/lib/codecs/ProtobufCodec.spec.d.ts.map +1 -0
  142. package/lib/codecs/ProtobufCodec.spec.js +155 -0
  143. package/lib/codecs/ProtobufCodec.spec.js.map +1 -0
  144. package/lib/codecs/index.d.ts +5 -0
  145. package/lib/codecs/index.d.ts.map +1 -0
  146. package/lib/codecs/index.js +21 -0
  147. package/lib/codecs/index.js.map +1 -0
  148. package/lib/codecs/migrateIndex.d.ts +24 -0
  149. package/lib/codecs/migrateIndex.d.ts.map +1 -0
  150. package/lib/codecs/migrateIndex.js +119 -0
  151. package/lib/codecs/migrateIndex.js.map +1 -0
  152. package/lib/codecs/migrateIndex.spec.d.ts +2 -0
  153. package/lib/codecs/migrateIndex.spec.d.ts.map +1 -0
  154. package/lib/codecs/migrateIndex.spec.js +151 -0
  155. package/lib/codecs/migrateIndex.spec.js.map +1 -0
  156. package/lib/codecs/schemas/index.proto +34 -0
  157. package/lib/index.d.ts +20 -0
  158. package/lib/index.d.ts.map +1 -1
  159. package/lib/index.js +36 -0
  160. package/lib/index.js.map +1 -0
  161. package/lib/internals/Colorize.d.ts +14 -0
  162. package/lib/internals/Colorize.d.ts.map +1 -0
  163. package/lib/internals/Colorize.js +69 -0
  164. package/lib/internals/Colorize.js.map +1 -0
  165. package/lib/internals/index.d.ts +3 -0
  166. package/lib/internals/index.d.ts.map +1 -0
  167. package/lib/internals/index.js +19 -0
  168. package/lib/internals/index.js.map +1 -0
  169. package/lib/internals/types.d.ts +43 -0
  170. package/lib/internals/types.d.ts.map +1 -0
  171. package/lib/internals/types.js +3 -0
  172. package/lib/internals/types.js.map +1 -0
  173. package/lib/server/IndexManager.d.ts +78 -0
  174. package/lib/server/IndexManager.d.ts.map +1 -0
  175. package/lib/server/IndexManager.js +259 -0
  176. package/lib/server/IndexManager.js.map +1 -0
  177. package/lib/server/VectraServer.d.ts +40 -0
  178. package/lib/server/VectraServer.d.ts.map +1 -0
  179. package/lib/server/VectraServer.js +151 -0
  180. package/lib/server/VectraServer.js.map +1 -0
  181. package/lib/server/VectraServer.spec.d.ts +2 -0
  182. package/lib/server/VectraServer.spec.d.ts.map +1 -0
  183. package/lib/server/VectraServer.spec.js +322 -0
  184. package/lib/server/VectraServer.spec.js.map +1 -0
  185. package/lib/server/handlers/documentHandlers.d.ts +15 -0
  186. package/lib/server/handlers/documentHandlers.d.ts.map +1 -0
  187. package/lib/server/handlers/documentHandlers.js +95 -0
  188. package/lib/server/handlers/documentHandlers.js.map +1 -0
  189. package/lib/server/handlers/helpers.d.ts +23 -0
  190. package/lib/server/handlers/helpers.d.ts.map +1 -0
  191. package/lib/server/handlers/helpers.js +138 -0
  192. package/lib/server/handlers/helpers.js.map +1 -0
  193. package/lib/server/handlers/index.d.ts +8 -0
  194. package/lib/server/handlers/index.d.ts.map +1 -0
  195. package/lib/server/handlers/index.js +22 -0
  196. package/lib/server/handlers/index.js.map +1 -0
  197. package/lib/server/handlers/indexHandlers.d.ts +14 -0
  198. package/lib/server/handlers/indexHandlers.d.ts.map +1 -0
  199. package/lib/server/handlers/indexHandlers.js +85 -0
  200. package/lib/server/handlers/indexHandlers.js.map +1 -0
  201. package/lib/server/handlers/itemHandlers.d.ts +34 -0
  202. package/lib/server/handlers/itemHandlers.d.ts.map +1 -0
  203. package/lib/server/handlers/itemHandlers.js +166 -0
  204. package/lib/server/handlers/itemHandlers.js.map +1 -0
  205. package/lib/server/handlers/lifecycleHandlers.d.ts +11 -0
  206. package/lib/server/handlers/lifecycleHandlers.d.ts.map +1 -0
  207. package/lib/server/handlers/lifecycleHandlers.js +31 -0
  208. package/lib/server/handlers/lifecycleHandlers.js.map +1 -0
  209. package/lib/server/handlers/queryHandlers.d.ts +27 -0
  210. package/lib/server/handlers/queryHandlers.d.ts.map +1 -0
  211. package/lib/server/handlers/queryHandlers.js +135 -0
  212. package/lib/server/handlers/queryHandlers.js.map +1 -0
  213. package/lib/server/handlers/statsHandlers.d.ts +17 -0
  214. package/lib/server/handlers/statsHandlers.d.ts.map +1 -0
  215. package/lib/server/handlers/statsHandlers.js +81 -0
  216. package/lib/server/handlers/statsHandlers.js.map +1 -0
  217. package/lib/server/index.d.ts +4 -0
  218. package/lib/server/index.d.ts.map +1 -0
  219. package/lib/server/index.js +23 -0
  220. package/lib/server/index.js.map +1 -0
  221. package/lib/storage/FileStorage.d.ts +92 -0
  222. package/lib/storage/FileStorage.d.ts.map +1 -0
  223. package/lib/storage/FileStorage.js +3 -0
  224. package/lib/storage/FileStorage.js.map +1 -0
  225. package/lib/storage/FileStorageUtilities.d.ts +36 -0
  226. package/lib/storage/FileStorageUtilities.d.ts.map +1 -0
  227. package/lib/storage/FileStorageUtilities.js +91 -0
  228. package/lib/storage/FileStorageUtilities.js.map +1 -0
  229. package/lib/storage/FileStorageUtilities.spec.d.ts +2 -0
  230. package/lib/storage/FileStorageUtilities.spec.d.ts.map +1 -0
  231. package/lib/storage/FileStorageUtilities.spec.js +98 -0
  232. package/lib/storage/FileStorageUtilities.spec.js.map +1 -0
  233. package/lib/storage/FileType.d.ts +29 -0
  234. package/lib/storage/FileType.d.ts.map +1 -0
  235. package/lib/storage/FileType.js +38 -0
  236. package/lib/storage/FileType.js.map +1 -0
  237. package/lib/storage/IndexedDBStorage.d.ts +47 -0
  238. package/lib/storage/IndexedDBStorage.d.ts.map +1 -0
  239. package/lib/storage/IndexedDBStorage.js +347 -0
  240. package/lib/storage/IndexedDBStorage.js.map +1 -0
  241. package/lib/storage/LocalFileStorage.browser.d.ts +19 -0
  242. package/lib/storage/LocalFileStorage.browser.d.ts.map +1 -0
  243. package/lib/storage/LocalFileStorage.browser.js +43 -0
  244. package/lib/storage/LocalFileStorage.browser.js.map +1 -0
  245. package/lib/storage/LocalFileStorage.d.ts +23 -0
  246. package/lib/storage/LocalFileStorage.d.ts.map +1 -0
  247. package/lib/storage/LocalFileStorage.js +152 -0
  248. package/lib/storage/LocalFileStorage.js.map +1 -0
  249. package/lib/storage/LocalFileStorage.spec.d.ts +2 -0
  250. package/lib/storage/LocalFileStorage.spec.d.ts.map +1 -0
  251. package/lib/storage/LocalFileStorage.spec.js +249 -0
  252. package/lib/storage/LocalFileStorage.spec.js.map +1 -0
  253. package/lib/storage/VirtualFileStorage.d.ts +18 -0
  254. package/lib/storage/VirtualFileStorage.d.ts.map +1 -0
  255. package/lib/storage/VirtualFileStorage.js +178 -0
  256. package/lib/storage/VirtualFileStorage.js.map +1 -0
  257. package/lib/storage/VirtualFileStorage.spec.d.ts +2 -0
  258. package/lib/storage/VirtualFileStorage.spec.d.ts.map +1 -0
  259. package/lib/storage/VirtualFileStorage.spec.js +302 -0
  260. package/lib/storage/VirtualFileStorage.spec.js.map +1 -0
  261. package/lib/storage/index.d.ts +6 -0
  262. package/lib/storage/index.d.ts.map +1 -0
  263. package/lib/storage/index.js +22 -0
  264. package/lib/storage/index.js.map +1 -0
  265. package/lib/templates/templates/csharp/README.md +48 -0
  266. package/lib/templates/templates/csharp/VectraClient.cs +234 -0
  267. package/lib/templates/templates/go/README.md +71 -0
  268. package/lib/templates/templates/go/vectra_client.go +322 -0
  269. package/lib/templates/templates/java/README.md +81 -0
  270. package/lib/templates/templates/java/VectraClient.java +232 -0
  271. package/lib/templates/templates/python/README.md +37 -0
  272. package/lib/templates/templates/python/vectra_client.py +279 -0
  273. package/lib/templates/templates/rust/Cargo.toml +14 -0
  274. package/lib/templates/templates/rust/README.md +39 -0
  275. package/lib/templates/templates/rust/build.rs +4 -0
  276. package/lib/templates/templates/rust/lib.rs +284 -0
  277. package/lib/templates/templates/typescript/README.md +96 -0
  278. package/lib/templates/templates/typescript/VectraClient.ts +374 -0
  279. package/lib/templates/typescript/VectraClient.d.ts +114 -0
  280. package/lib/templates/typescript/VectraClient.d.ts.map +1 -0
  281. package/lib/templates/typescript/VectraClient.js +328 -0
  282. package/lib/templates/typescript/VectraClient.js.map +1 -0
  283. package/lib/types.d.ts +153 -0
  284. package/lib/types.d.ts.map +1 -0
  285. package/lib/types.js +3 -0
  286. package/lib/types.js.map +1 -0
  287. package/lib/utils/index.d.ts +2 -0
  288. package/lib/utils/index.d.ts.map +1 -0
  289. package/lib/utils/index.js +18 -0
  290. package/lib/utils/index.js.map +1 -0
  291. package/lib/utils/pathUtils.d.ts +40 -0
  292. package/lib/utils/pathUtils.d.ts.map +1 -0
  293. package/lib/utils/pathUtils.js +98 -0
  294. package/lib/utils/pathUtils.js.map +1 -0
  295. package/lib/vectra-cli.d.ts +2 -0
  296. package/lib/vectra-cli.d.ts.map +1 -1
  297. package/lib/vectra-cli.generate.spec.d.ts +2 -0
  298. package/lib/vectra-cli.generate.spec.d.ts.map +1 -0
  299. package/lib/vectra-cli.generate.spec.js +112 -0
  300. package/lib/vectra-cli.generate.spec.js.map +1 -0
  301. package/lib/vectra-cli.js +760 -0
  302. package/lib/vectra-cli.js.map +1 -0
  303. package/lib/vectra-cli.spec.d.ts +1 -0
  304. package/lib/vectra-cli.spec.d.ts.map +1 -0
  305. package/lib/vectra-cli.spec.js +2 -0
  306. package/lib/vectra-cli.spec.js.map +1 -0
  307. package/package.json +91 -16
  308. package/proto/vectra_service.proto +276 -0
  309. package/src/BrowserWebFetcher.ts +345 -0
  310. package/src/FileFetcher.spec.ts +234 -0
  311. package/src/FileFetcher.ts +37 -25
  312. package/src/FolderWatcher.spec.ts +288 -0
  313. package/src/FolderWatcher.ts +304 -0
  314. package/src/GPT3Tokenizer.spec.ts +50 -0
  315. package/src/ItemSelector.spec.ts +252 -0
  316. package/src/ItemSelector.ts +163 -150
  317. package/src/LocalDocument.spec.ts +211 -0
  318. package/src/LocalDocument.ts +88 -94
  319. package/src/LocalDocumentIndex.spec.ts +481 -0
  320. package/src/LocalDocumentIndex.ts +39 -40
  321. package/src/LocalDocumentResult.spec.ts +373 -0
  322. package/src/LocalDocumentResult.ts +489 -319
  323. package/src/LocalEmbeddings.spec.ts +138 -0
  324. package/src/LocalEmbeddings.ts +120 -0
  325. package/src/LocalIndex.spec.ts +808 -66
  326. package/src/LocalIndex.ts +479 -429
  327. package/src/OpenAIEmbeddings.spec.ts +354 -0
  328. package/src/OpenAIEmbeddings.ts +26 -27
  329. package/src/TextSplitter.spec.ts +342 -0
  330. package/src/TextSplitter.ts +517 -532
  331. package/src/TransformersEmbeddings.spec.ts +188 -0
  332. package/src/TransformersEmbeddings.ts +232 -0
  333. package/src/TransformersTokenizer.spec.ts +143 -0
  334. package/src/TransformersTokenizer.ts +45 -0
  335. package/src/WebFetcher.spec.ts +288 -0
  336. package/src/WebFetcher.ts +184 -186
  337. package/src/browser.ts +69 -0
  338. package/src/codecs/IndexCodec.ts +40 -0
  339. package/src/codecs/JsonCodec.spec.ts +70 -0
  340. package/src/codecs/JsonCodec.ts +37 -0
  341. package/src/codecs/LocalIndex.protobuf.spec.ts +115 -0
  342. package/src/codecs/ProtobufCodec.spec.ts +166 -0
  343. package/src/codecs/ProtobufCodec.ts +193 -0
  344. package/src/codecs/index.ts +4 -0
  345. package/src/codecs/migrateIndex.spec.ts +176 -0
  346. package/src/codecs/migrateIndex.ts +125 -0
  347. package/src/codecs/schemas/index.proto +34 -0
  348. package/src/index.ts +9 -1
  349. package/src/internals/Colorize.ts +19 -16
  350. package/src/server/IndexManager.ts +243 -0
  351. package/src/server/VectraServer.spec.ts +303 -0
  352. package/src/server/VectraServer.ts +156 -0
  353. package/src/server/handlers/documentHandlers.ts +59 -0
  354. package/src/server/handlers/helpers.ts +93 -0
  355. package/src/server/handlers/index.ts +7 -0
  356. package/src/server/handlers/indexHandlers.ts +44 -0
  357. package/src/server/handlers/itemHandlers.ts +140 -0
  358. package/src/server/handlers/lifecycleHandlers.ts +26 -0
  359. package/src/server/handlers/queryHandlers.ts +96 -0
  360. package/src/server/handlers/statsHandlers.ts +38 -0
  361. package/src/server/index.ts +3 -0
  362. package/src/storage/FileStorage.ts +105 -0
  363. package/src/storage/FileStorageUtilities.spec.ts +106 -0
  364. package/src/storage/FileStorageUtilities.ts +77 -0
  365. package/src/storage/FileType.ts +61 -0
  366. package/src/storage/IndexedDBStorage.ts +365 -0
  367. package/src/storage/LocalFileStorage.browser.ts +52 -0
  368. package/src/storage/LocalFileStorage.spec.ts +292 -0
  369. package/src/storage/LocalFileStorage.ts +98 -0
  370. package/src/storage/VirtualFileStorage.spec.ts +307 -0
  371. package/src/storage/VirtualFileStorage.ts +169 -0
  372. package/src/storage/index.ts +5 -0
  373. package/src/templates/csharp/README.md +48 -0
  374. package/src/templates/csharp/VectraClient.cs +234 -0
  375. package/src/templates/go/README.md +71 -0
  376. package/src/templates/go/vectra_client.go +322 -0
  377. package/src/templates/java/README.md +81 -0
  378. package/src/templates/java/VectraClient.java +232 -0
  379. package/src/templates/python/README.md +37 -0
  380. package/src/templates/python/vectra_client.py +279 -0
  381. package/src/templates/rust/Cargo.toml +14 -0
  382. package/src/templates/rust/README.md +39 -0
  383. package/src/templates/rust/build.rs +4 -0
  384. package/src/templates/rust/lib.rs +284 -0
  385. package/src/templates/typescript/README.md +96 -0
  386. package/src/templates/typescript/VectraClient.ts +374 -0
  387. package/src/types.ts +131 -123
  388. package/src/utils/index.ts +1 -0
  389. package/src/utils/pathUtils.ts +106 -0
  390. package/src/vectra-cli.generate.spec.ts +72 -0
  391. package/src/vectra-cli.spec.ts +0 -0
  392. package/src/vectra-cli.ts +687 -246
@@ -0,0 +1,292 @@
1
+ import assert from 'node:assert';
2
+ import sinon from 'sinon';
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ import { LocalFileStorage } from './LocalFileStorage';
6
+ import { FileStorageUtilities } from './FileStorageUtilities';
7
+
8
+ describe('LocalFileStorage', () => {
9
+ let storage: LocalFileStorage;
10
+
11
+ afterEach(async () => {
12
+ sinon.restore();
13
+ });
14
+
15
+ describe('constructor and getFullPath', () => {
16
+ it('returns relativePath if no rootFolder and relativePath non-empty', () => {
17
+ storage = new LocalFileStorage();
18
+ // @ts-ignore access private for test
19
+ assert.strictEqual(storage['getFullPath']('some/path'), 'some/path');
20
+ });
21
+
22
+ it("returns '.' if no rootFolder and relativePath empty", () => {
23
+ storage = new LocalFileStorage();
24
+ // @ts-ignore access private for test
25
+ assert.strictEqual(storage['getFullPath'](''), '.');
26
+ });
27
+
28
+ it('returns rootFolder if rootFolder set and relativePath empty', () => {
29
+ storage = new LocalFileStorage('/root');
30
+ // @ts-ignore access private for test
31
+ assert.strictEqual(storage['getFullPath'](''), '/root');
32
+ });
33
+
34
+ it('joins rootFolder and relativePath if both set', () => {
35
+ storage = new LocalFileStorage('/root');
36
+ // @ts-ignore access private for test
37
+ assert.strictEqual(storage['getFullPath']('sub/folder'), path.join('/root', 'sub/folder'));
38
+ });
39
+ });
40
+
41
+ describe('createFile', () => {
42
+ beforeEach(() => {
43
+ storage = new LocalFileStorage('/root');
44
+ });
45
+
46
+ it('writes a new file with Buffer content', async () => {
47
+ const writeFileStub = sinon.stub(fs, 'writeFile').resolves();
48
+ const content = Buffer.from('hello');
49
+ await storage.createFile('file.txt', content);
50
+ sinon.assert.calledWith(writeFileStub, path.join('/root', 'file.txt'), content, { flag: 'wx' });
51
+ });
52
+
53
+ it('writes a new file with string content as UTF-8', async () => {
54
+ const writeFileStub = sinon.stub(fs, 'writeFile').resolves();
55
+ const content = 'hello';
56
+ await storage.createFile('file.txt', content);
57
+ sinon.assert.calledWith(
58
+ writeFileStub,
59
+ path.join('/root', 'file.txt'),
60
+ Buffer.from(content, 'utf8'),
61
+ { flag: 'wx' }
62
+ );
63
+ });
64
+
65
+ it('bubbles up error if file already exists', async () => {
66
+ sinon.stub(fs, 'writeFile').rejects(new Error('EEXIST'));
67
+ await assert.rejects(async () => {
68
+ await storage.createFile('file.txt', 'content');
69
+ });
70
+ });
71
+
72
+ it('bubbles up error if parent directory does not exist', async () => {
73
+ sinon.stub(fs, 'writeFile').rejects(new Error('ENOENT'));
74
+ await assert.rejects(async () => {
75
+ await storage.createFile('nonexistent/file.txt', 'content');
76
+ });
77
+ });
78
+ });
79
+
80
+ describe('createFolder', () => {
81
+ beforeEach(() => {
82
+ storage = new LocalFileStorage('/root');
83
+ });
84
+
85
+ it('creates nested directory structure recursively', async () => {
86
+ const mkdirStub = sinon.stub(fs, 'mkdir').resolves();
87
+ await storage.createFolder('nested/folder');
88
+ sinon.assert.calledWith(mkdirStub, path.join('/root', 'nested/folder'), { recursive: true });
89
+ });
90
+
91
+ it('calling again on same path still calls mkdir (idempotent due to recursive:true)', async () => {
92
+ const mkdirStub = sinon.stub(fs, 'mkdir').resolves();
93
+ await storage.createFolder('nested/folder');
94
+ await storage.createFolder('nested/folder');
95
+ sinon.assert.calledTwice(mkdirStub);
96
+ });
97
+ });
98
+
99
+ describe('deleteFile', () => {
100
+ beforeEach(() => {
101
+ storage = new LocalFileStorage('/root');
102
+ });
103
+
104
+ it('deletes existing file', async () => {
105
+ const unlinkStub = sinon.stub(fs, 'unlink').resolves();
106
+ await storage.deleteFile('file.txt');
107
+ sinon.assert.calledWith(unlinkStub, path.join('/root', 'file.txt'));
108
+ });
109
+
110
+ it('bubbles up error when file does not exist', async () => {
111
+ sinon.stub(fs, 'unlink').rejects(new Error('ENOENT'));
112
+ await assert.rejects(async () => {
113
+ await storage.deleteFile('missing.txt');
114
+ });
115
+ });
116
+ });
117
+
118
+ describe('deleteFolder', () => {
119
+ beforeEach(() => {
120
+ storage = new LocalFileStorage('/root');
121
+ });
122
+
123
+ it('deletes existing folder recursively', async () => {
124
+ const rmStub = sinon.stub(fs, 'rm').resolves();
125
+ await storage.deleteFolder('folder');
126
+ sinon.assert.calledWith(rmStub, path.join('/root', 'folder'), { recursive: true });
127
+ });
128
+
129
+ it('bubbles up error when folder does not exist', async () => {
130
+ sinon.stub(fs, 'rm').rejects(new Error('ENOENT'));
131
+ await assert.rejects(async () => {
132
+ await storage.deleteFolder('missing');
133
+ });
134
+ });
135
+ });
136
+
137
+ describe('getDetails', () => {
138
+ beforeEach(() => {
139
+ storage = new LocalFileStorage('/root');
140
+ });
141
+
142
+ it('returns correct details for file', async () => {
143
+ const statStub = sinon.stub(fs, 'stat').resolves({
144
+ isDirectory: () => false,
145
+ isFile: () => true,
146
+ } as any);
147
+ const getFileTypeStub = sinon.stub(FileStorageUtilities, 'getFileType').returns('txt');
148
+
149
+ const details = await storage.getDetails('file.txt');
150
+ assert.strictEqual(details.name, 'file.txt');
151
+ assert.strictEqual(details.path, 'file.txt');
152
+ assert.strictEqual(details.isFolder, false);
153
+ assert.strictEqual(details.fileType, 'txt');
154
+
155
+ sinon.assert.calledWith(statStub, path.join('/root', 'file.txt'));
156
+ sinon.assert.calledWith(getFileTypeStub, 'file.txt');
157
+ });
158
+
159
+ it('returns correct details for folder', async () => {
160
+ sinon.stub(fs, 'stat').resolves({
161
+ isDirectory: () => true,
162
+ isFile: () => false,
163
+ } as any);
164
+
165
+ const details = await storage.getDetails('folder');
166
+ assert.strictEqual(details.name, 'folder');
167
+ assert.strictEqual(details.path, 'folder');
168
+ assert.strictEqual(details.isFolder, true);
169
+ assert.strictEqual(details.fileType, undefined);
170
+ });
171
+
172
+ it('bubbles up error for non-existent path', async () => {
173
+ sinon.stub(fs, 'stat').rejects(new Error('ENOENT'));
174
+ await assert.rejects(async () => {
175
+ await storage.getDetails('missing');
176
+ });
177
+ });
178
+ });
179
+
180
+ describe('listFiles', () => {
181
+ beforeEach(() => {
182
+ storage = new LocalFileStorage('/root');
183
+ });
184
+
185
+ it('returns entries for folder with files and subfolders', async () => {
186
+ const dirents = [
187
+ { name: 'file1.txt', isDirectory: () => false, isFile: () => true },
188
+ { name: 'subfolder', isDirectory: () => true, isFile: () => false },
189
+ ];
190
+ sinon.stub(fs, 'readdir').resolves(dirents as any);
191
+ const getFileTypeStub = sinon.stub(FileStorageUtilities, 'getFileType').callsFake((name: string) => {
192
+ if (name === 'file1.txt') return 'txt';
193
+ return undefined;
194
+ });
195
+
196
+ const results = await storage.listFiles('folder');
197
+ assert.strictEqual(results.length, 2);
198
+
199
+ assert.strictEqual(results[0].name, 'file1.txt');
200
+ assert.strictEqual(results[0].path, path.join('/root', 'folder', 'file1.txt'));
201
+ assert.strictEqual(results[0].isFolder, false);
202
+ assert.strictEqual(results[0].fileType, 'txt');
203
+
204
+ assert.strictEqual(results[1].name, 'subfolder');
205
+ assert.strictEqual(results[1].path, path.join('/root', 'folder', 'subfolder'));
206
+ assert.strictEqual(results[1].isFolder, true);
207
+ assert.strictEqual(results[1].fileType, undefined);
208
+
209
+ sinon.assert.calledWith(getFileTypeStub, 'file1.txt');
210
+ });
211
+
212
+ it('ignores filter argument', async () => {
213
+ sinon.stub(fs, 'readdir').resolves([]);
214
+ const results = await storage.listFiles('folder', { any: true } as any);
215
+ assert.ok(Array.isArray(results));
216
+ assert.strictEqual(results.length, 0);
217
+ });
218
+ });
219
+
220
+ describe('pathExists', () => {
221
+ beforeEach(() => {
222
+ storage = new LocalFileStorage('/root');
223
+ });
224
+
225
+ it('returns true for existing file or folder', async () => {
226
+ sinon.stub(fs, 'access').resolves();
227
+ const exists = await storage.pathExists('file.txt');
228
+ assert.strictEqual(exists, true);
229
+ });
230
+
231
+ it('returns false for non-existent path', async () => {
232
+ sinon.stub(fs, 'access').rejects(new Error('ENOENT'));
233
+ const exists = await storage.pathExists('missing');
234
+ assert.strictEqual(exists, false);
235
+ });
236
+ });
237
+
238
+ describe('readFile', () => {
239
+ beforeEach(() => {
240
+ storage = new LocalFileStorage('/root');
241
+ });
242
+
243
+ it('reads and returns exact bytes', async () => {
244
+ const content = Buffer.from('hello');
245
+ sinon.stub(fs, 'readFile').resolves(content);
246
+ const result = await storage.readFile('file.txt');
247
+ assert.strictEqual(result, content);
248
+ });
249
+
250
+ it('bubbles up error when file does not exist', async () => {
251
+ sinon.stub(fs, 'readFile').rejects(new Error('ENOENT'));
252
+ await assert.rejects(async () => {
253
+ await storage.readFile('missing.txt');
254
+ });
255
+ });
256
+ });
257
+
258
+ describe('upsertFile', () => {
259
+ beforeEach(() => {
260
+ storage = new LocalFileStorage('/root');
261
+ });
262
+
263
+ it('creates new file when absent', async () => {
264
+ const writeFileStub = sinon.stub(fs, 'writeFile').resolves();
265
+ await storage.upsertFile('file.txt', 'content');
266
+ sinon.assert.calledWith(
267
+ writeFileStub,
268
+ path.join('/root', 'file.txt'),
269
+ Buffer.from('content', 'utf8'),
270
+ { flag: 'w' }
271
+ );
272
+ });
273
+
274
+ it('overwrites existing file', async () => {
275
+ const writeFileStub = sinon.stub(fs, 'writeFile').resolves();
276
+ await storage.upsertFile('file.txt', Buffer.from('new content'));
277
+ sinon.assert.calledWith(
278
+ writeFileStub,
279
+ path.join('/root', 'file.txt'),
280
+ Buffer.from('new content'),
281
+ { flag: 'w' }
282
+ );
283
+ });
284
+
285
+ it('bubbles up error if parent directory does not exist', async () => {
286
+ sinon.stub(fs, 'writeFile').rejects(new Error('ENOENT'));
287
+ await assert.rejects(async () => {
288
+ await storage.upsertFile('nonexistent/file.txt', 'content');
289
+ });
290
+ });
291
+ });
292
+ });
@@ -0,0 +1,98 @@
1
+ import { FileDetails, FileStorage, ListFilesFilter } from "./FileStorage";
2
+ import { FileStorageUtilities } from "./FileStorageUtilities";
3
+ import fs from "fs/promises";
4
+ import * as path from "node:path";
5
+
6
+ /**
7
+ * A `FileStorage` implementation that uses the local file system.
8
+ */
9
+ export class LocalFileStorage implements FileStorage {
10
+ private _rootFolder: string | undefined;
11
+
12
+ /**
13
+ * Creates a new `LocalFileStorage` instance.
14
+ * @param rootFolder Optional. Root folder to use for file operations. If not provided, paths passed to operations should be fully qualified.
15
+ */
16
+ constructor(rootFolder?: string) {
17
+ this._rootFolder = rootFolder;
18
+ }
19
+
20
+ async createFile(filePath: string, content: Buffer|string): Promise<void> {
21
+ // Convert content to buffer if it's a string
22
+ if (typeof content == 'string') {
23
+ content = Buffer.from(content, 'utf8');
24
+ }
25
+
26
+ // Write the file
27
+ await fs.writeFile(this.getFullPath(filePath), content, { flag: 'wx' });
28
+ }
29
+
30
+ async createFolder(folderPath: string): Promise<void> {
31
+ await fs.mkdir(this.getFullPath(folderPath), { recursive: true });
32
+ }
33
+
34
+ async deleteFile(filePath: string): Promise<void> {
35
+ await fs.unlink(this.getFullPath(filePath));
36
+ }
37
+
38
+ async deleteFolder(folderPath: string): Promise<void> {
39
+ await fs.rm(this.getFullPath(folderPath), { recursive: true });
40
+ }
41
+
42
+ async getDetails(fileOrFolderPath: string): Promise<FileDetails> {
43
+ const stats = await fs.stat(this.getFullPath(fileOrFolderPath));
44
+ return {
45
+ name: path.basename(fileOrFolderPath),
46
+ path: fileOrFolderPath,
47
+ isFolder: stats.isDirectory(),
48
+ fileType: stats.isFile() ? FileStorageUtilities.getFileType(fileOrFolderPath) : undefined
49
+ };
50
+ }
51
+
52
+ async listFiles(folderPath: string, _filter?: ListFilesFilter | undefined): Promise<FileDetails[]> {
53
+ const folder = this.getFullPath(folderPath);
54
+ const list = await fs.readdir(folder, { withFileTypes: true });
55
+ return list.map((entry) => {
56
+ return {
57
+ name: entry.name,
58
+ path: path.join(folder, entry.name),
59
+ isFolder: entry.isDirectory(),
60
+ fileType: entry.isFile() ? FileStorageUtilities.getFileType(entry.name) : undefined
61
+ };
62
+ });
63
+ }
64
+
65
+ async pathExists(fileOrFolderPath: string): Promise<boolean> {
66
+ try {
67
+ await fs.access(this.getFullPath(fileOrFolderPath));
68
+ return true;
69
+ } catch (err: unknown) {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ async readFile(filePath: string): Promise<Buffer> {
75
+ return await fs.readFile(this.getFullPath(filePath));
76
+ }
77
+
78
+ async upsertFile(filePath: string, content: Buffer|string): Promise<void> {
79
+ // Convert content to buffer if it's a string
80
+ if (typeof content == 'string') {
81
+ content = Buffer.from(content, 'utf8');
82
+ }
83
+
84
+ // Write the file
85
+ await fs.writeFile(this.getFullPath(filePath), content, { flag: 'w' });
86
+ }
87
+
88
+ private getFullPath(relativePath: string): string {
89
+ if (!this._rootFolder) {
90
+ return relativePath.length > 0 ? relativePath : '.';
91
+ } else if (relativePath.length == 0) {
92
+ return this._rootFolder;
93
+ } else {
94
+ return path.join(this._rootFolder, relativePath);
95
+ }
96
+ }
97
+
98
+ }
@@ -0,0 +1,307 @@
1
+ import assert from 'node:assert';
2
+ import * as path from 'path';
3
+ import { VirtualFileStorage } from './VirtualFileStorage';
4
+ import { FileStorageUtilities } from './FileStorageUtilities';
5
+
6
+ describe('VirtualFileStorage', () => {
7
+ let storage: VirtualFileStorage;
8
+
9
+ beforeEach(() => {
10
+ storage = new VirtualFileStorage();
11
+ });
12
+
13
+ describe('createFile', () => {
14
+ it('creates a new file with string content', async () => {
15
+ await storage.createFile('file.txt', 'hello');
16
+ const details = await storage.getDetails('file.txt');
17
+ assert.strictEqual(details.name, 'file.txt');
18
+ assert.strictEqual(details.path, path.normalize('file.txt'));
19
+ assert.strictEqual(details.isFolder, false);
20
+ assert.strictEqual(
21
+ details.fileType,
22
+ FileStorageUtilities.getFileType(path.normalize('file.txt'))
23
+ );
24
+ const content = await storage.readFile('file.txt');
25
+ assert.deepStrictEqual(content, Buffer.from('hello', 'utf8'));
26
+ });
27
+
28
+ it('creates a new file with Buffer content', async () => {
29
+ const buf = Buffer.from('buffer content');
30
+ await storage.createFile('bufferfile.bin', buf);
31
+ const content = await storage.readFile('bufferfile.bin');
32
+ assert.deepStrictEqual(content, buf);
33
+ });
34
+
35
+ it('throws when file already exists (including folder at path)', async () => {
36
+ await storage.createFile('dup.txt', 'content');
37
+ await assert.rejects(async () => {
38
+ await storage.createFile('dup.txt', 'new content');
39
+ }, /File already exists/);
40
+
41
+ await storage.createFolder('folder');
42
+ await assert.rejects(async () => {
43
+ await storage.createFile('folder', 'content');
44
+ }, /File already exists/);
45
+ });
46
+
47
+ it('throws when creating file with normalized duplicate path', async () => {
48
+ await storage.createFile('a/../b/file.txt', 'content');
49
+ await assert.rejects(async () => {
50
+ await storage.createFile('b/file.txt', 'content');
51
+ }, /File already exists/);
52
+ });
53
+ });
54
+
55
+ describe('createFolder', () => {
56
+ it('creates a new folder', async () => {
57
+ await storage.createFolder('myfolder');
58
+ const details = await storage.getDetails('myfolder');
59
+ assert.strictEqual(details.name, 'myfolder');
60
+ assert.strictEqual(details.isFolder, true);
61
+ assert.strictEqual(details.fileType, undefined);
62
+ });
63
+
64
+ it('is idempotent when folder already exists', async () => {
65
+ await storage.createFolder('myfolder');
66
+ await storage.createFolder('myfolder'); // no error
67
+ });
68
+
69
+ it('throws when a file exists at that path', async () => {
70
+ await storage.createFile('file.txt', 'content');
71
+ await assert.rejects(async () => {
72
+ await storage.createFolder('file.txt');
73
+ }, /Cannot create folder/);
74
+ });
75
+
76
+ it('does not create parent folders automatically', async () => {
77
+ // Implementation creates only the explicit folder entry
78
+ await storage.createFolder('parent/child');
79
+
80
+ // Only 'parent/child' exists, not 'parent'
81
+ await assert.rejects(async () => {
82
+ await storage.getDetails('parent');
83
+ }, /Path not found/);
84
+
85
+ const details = await storage.getDetails('parent/child');
86
+ assert.strictEqual(details.isFolder, true);
87
+ });
88
+ });
89
+
90
+ describe('deleteFile', () => {
91
+ it('deletes an existing file', async () => {
92
+ await storage.createFile('file.txt', 'content');
93
+ await storage.deleteFile('file.txt');
94
+ const exists = await storage.pathExists('file.txt');
95
+ assert.strictEqual(exists, false);
96
+ await assert.rejects(async () => {
97
+ await storage.readFile('file.txt');
98
+ }, /File not found/);
99
+ });
100
+
101
+ it('throws when deleting a folder as file', async () => {
102
+ await storage.createFolder('folder');
103
+ await assert.rejects(async () => {
104
+ await storage.deleteFile('folder');
105
+ }, /Cannot delete file/);
106
+ });
107
+
108
+ it('no error when deleting non-existent file', async () => {
109
+ await storage.deleteFile('nonexistent');
110
+ });
111
+ });
112
+
113
+ describe('deleteFolder', () => {
114
+ it('deletes an existing folder', async () => {
115
+ await storage.createFolder('folder');
116
+ await storage.deleteFolder('folder');
117
+ const exists = await storage.pathExists('folder');
118
+ assert.strictEqual(exists, false);
119
+ });
120
+
121
+ it('throws when deleting a file as folder', async () => {
122
+ await storage.createFile('file.txt', 'content');
123
+ await assert.rejects(async () => {
124
+ await storage.deleteFolder('file.txt');
125
+ }, /Cannot delete folder/);
126
+ });
127
+
128
+ it('no error when deleting non-existent folder', async () => {
129
+ await storage.deleteFolder('nonexistent');
130
+ });
131
+
132
+ it('does not delete children when deleting folder', async () => {
133
+ await storage.createFolder('parent');
134
+ await storage.createFile('parent/child.txt', 'content');
135
+ await storage.deleteFolder('parent');
136
+
137
+ // Parent deleted
138
+ const parentExists = await storage.pathExists('parent');
139
+ assert.strictEqual(parentExists, false);
140
+
141
+ // Child still exists
142
+ const childExists = await storage.pathExists('parent/child.txt');
143
+ assert.strictEqual(childExists, true);
144
+ });
145
+ });
146
+
147
+ describe('getDetails', () => {
148
+ it('returns details for existing file', async () => {
149
+ await storage.createFile('file.txt', 'content');
150
+ const details = await storage.getDetails('file.txt');
151
+ assert.strictEqual(details.name, 'file.txt');
152
+ assert.strictEqual(details.path, path.normalize('file.txt'));
153
+ assert.strictEqual(details.isFolder, false);
154
+ assert.strictEqual(
155
+ details.fileType,
156
+ FileStorageUtilities.getFileType(path.normalize('file.txt'))
157
+ );
158
+ });
159
+
160
+ it('returns details for existing folder', async () => {
161
+ await storage.createFolder('folder');
162
+ const details = await storage.getDetails('folder');
163
+ assert.strictEqual(details.name, 'folder');
164
+ assert.strictEqual(details.path, path.normalize('folder'));
165
+ assert.strictEqual(details.isFolder, true);
166
+ assert.strictEqual(details.fileType, undefined);
167
+ });
168
+
169
+ it('throws for non-existent path', async () => {
170
+ await assert.rejects(async () => {
171
+ await storage.getDetails('missing');
172
+ }, /Path not found/);
173
+ });
174
+ });
175
+
176
+ describe('listFiles', () => {
177
+ beforeEach(async () => {
178
+ await storage.createFolder('a');
179
+ await storage.createFolder('a/b');
180
+ await storage.createFile('a/file1.txt', 'content1');
181
+ await storage.createFile('a/b/file2.txt', 'content2');
182
+ await storage.createFolder('c');
183
+ await storage.createFile('fileRoot.txt', 'root');
184
+ });
185
+
186
+ it('returns immediate children only', async () => {
187
+ const listA = await storage.listFiles('a');
188
+ assert(listA.some(e => e.name === 'file1.txt'));
189
+ assert(listA.some(e => e.name === 'b'));
190
+ assert(!listA.some(e => e.name === 'file2.txt'));
191
+
192
+ const listRoot = await storage.listFiles('');
193
+ assert(listRoot.some(e => e.name === 'a'));
194
+ assert(listRoot.some(e => e.name === 'c'));
195
+ assert(listRoot.some(e => e.name === 'fileRoot.txt'));
196
+ });
197
+
198
+ it('respects filter "all"', async () => {
199
+ const all = await storage.listFiles('a', 'all');
200
+ assert(all.some(e => e.isFolder));
201
+ assert(all.some(e => !e.isFolder));
202
+ });
203
+
204
+ it('respects filter "files"', async () => {
205
+ const files = await storage.listFiles('a', 'files');
206
+ assert(files.every(e => !e.isFolder));
207
+ assert(files.some(e => e.name === 'file1.txt'));
208
+ assert(!files.some(e => e.name === 'b'));
209
+ });
210
+
211
+ it('respects filter "folders"', async () => {
212
+ const folders = await storage.listFiles('a', 'folders');
213
+ assert(folders.every(e => e.isFolder));
214
+ assert(folders.some(e => e.name === 'b'));
215
+ assert(!folders.some(e => e.name === 'file1.txt'));
216
+ });
217
+
218
+ it('normalizes folderPath', async () => {
219
+ const list1 = await storage.listFiles('a/');
220
+ const list2 = await storage.listFiles('a');
221
+ assert.deepStrictEqual(list1, list2);
222
+ });
223
+ });
224
+
225
+ describe('pathExists', () => {
226
+ it('returns true for existing file and folder', async () => {
227
+ await storage.createFile('file.txt', 'content');
228
+ await storage.createFolder('folder');
229
+ assert.strictEqual(await storage.pathExists('file.txt'), true);
230
+ assert.strictEqual(await storage.pathExists('folder'), true);
231
+ });
232
+
233
+ it('returns false for missing path', async () => {
234
+ assert.strictEqual(await storage.pathExists('missing'), false);
235
+ });
236
+ });
237
+
238
+ describe('readFile', () => {
239
+ it('returns exact Buffer written', async () => {
240
+ const buf = Buffer.from('data');
241
+ await storage.createFile('file.txt', buf);
242
+ const read = await storage.readFile('file.txt');
243
+ assert.deepStrictEqual(read, buf);
244
+ });
245
+
246
+ it('throws when path does not exist', async () => {
247
+ await assert.rejects(async () => {
248
+ await storage.readFile('missing.txt');
249
+ }, /File not found/);
250
+ });
251
+
252
+ it('throws when path is a folder', async () => {
253
+ await storage.createFolder('folder');
254
+ await assert.rejects(async () => {
255
+ await storage.readFile('folder');
256
+ }, /Cannot read file/);
257
+ });
258
+
259
+ it('returns empty buffer if content is undefined (forced)', async () => {
260
+ // Force an entry with undefined content to hit the fallback branch
261
+ (storage as any)._entries.set('emptyfile.txt', {
262
+ details: {
263
+ name: 'emptyfile.txt',
264
+ path: path.normalize('emptyfile.txt'),
265
+ isFolder: false,
266
+ fileType: FileStorageUtilities.getFileType(path.normalize('emptyfile.txt')),
267
+ },
268
+ content: undefined,
269
+ });
270
+ const content = await storage.readFile('emptyfile.txt');
271
+ assert.deepStrictEqual(content, Buffer.from('', 'utf8'));
272
+ });
273
+ });
274
+
275
+ describe('upsertFile', () => {
276
+ it('creates new file when missing with string content', async () => {
277
+ await storage.upsertFile('newfile.txt', 'content');
278
+ const details = await storage.getDetails('newfile.txt');
279
+ assert.strictEqual(details.isFolder, false);
280
+ assert.strictEqual(
281
+ details.fileType,
282
+ FileStorageUtilities.getFileType(path.normalize('newfile.txt'))
283
+ );
284
+ const content = await storage.readFile('newfile.txt');
285
+ assert.deepStrictEqual(content, Buffer.from('content', 'utf8'));
286
+ });
287
+
288
+ it('replaces content of existing file and keeps correct fileType', async () => {
289
+ await storage.createFile('file.txt', 'old');
290
+ await storage.upsertFile('file.txt', Buffer.from('new'));
291
+ const content = await storage.readFile('file.txt');
292
+ assert.deepStrictEqual(content, Buffer.from('new'));
293
+ const details = await storage.getDetails('file.txt');
294
+ assert.strictEqual(
295
+ details.fileType,
296
+ FileStorageUtilities.getFileType(path.normalize('file.txt'))
297
+ );
298
+ });
299
+
300
+ it('throws when a folder exists at that path', async () => {
301
+ await storage.createFolder('folder');
302
+ await assert.rejects(async () => {
303
+ await storage.upsertFile('folder', 'content');
304
+ }, /Cannot write file/);
305
+ });
306
+ });
307
+ });