@wener/common 2.0.2 → 2.0.5

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 (410) hide show
  1. package/lib/ai/qwen3vl/index.js +2 -0
  2. package/lib/ai/qwen3vl/index.js.map +1 -0
  3. package/lib/ai/qwen3vl/utils.js +31 -0
  4. package/lib/ai/qwen3vl/utils.js.map +1 -0
  5. package/lib/ai/vision/DocLayoutElementTypeSchema.js +28 -0
  6. package/lib/ai/vision/DocLayoutElementTypeSchema.js.map +1 -0
  7. package/lib/ai/vision/ImageAnnotationSchema.js +50 -0
  8. package/lib/ai/vision/ImageAnnotationSchema.js.map +1 -0
  9. package/lib/ai/vision/index.js +3 -0
  10. package/lib/ai/vision/index.js.map +1 -0
  11. package/lib/ai/vision/resolveImageAnnotation.js +105 -0
  12. package/lib/ai/vision/resolveImageAnnotation.js.map +1 -0
  13. package/lib/cn/ChineseResidentIdNo.js +22 -15
  14. package/lib/cn/ChineseResidentIdNo.js.map +1 -0
  15. package/lib/cn/ChineseResidentIdNo.test.js +1 -1
  16. package/lib/cn/DivisionCode.js +30 -25
  17. package/lib/cn/DivisionCode.js.map +1 -0
  18. package/lib/cn/DivisionCode.test.js +1 -1
  19. package/lib/cn/Mod11.js +38 -81
  20. package/lib/cn/Mod11.js.map +1 -0
  21. package/lib/cn/Mod31.js +41 -90
  22. package/lib/cn/Mod31.js.map +1 -0
  23. package/lib/cn/UnifiedSocialCreditCode.js +43 -34
  24. package/lib/cn/UnifiedSocialCreditCode.js.map +1 -0
  25. package/lib/cn/UnifiedSocialCreditCode.test.js +1 -1
  26. package/lib/cn/formatChineseAmount.js +77 -0
  27. package/lib/cn/formatChineseAmount.js.map +1 -0
  28. package/lib/cn/index.js +7 -1
  29. package/lib/cn/index.js.map +1 -0
  30. package/lib/cn/parseChineseNumber.js +94 -0
  31. package/lib/cn/parseChineseNumber.js.map +1 -0
  32. package/lib/cn/parseChineseNumber.test.js +278 -0
  33. package/lib/cn/pinyin/cartesianProduct.js +22 -0
  34. package/lib/cn/pinyin/cartesianProduct.js.map +1 -0
  35. package/lib/cn/pinyin/cartesianProduct.test.js +179 -0
  36. package/lib/cn/pinyin/data.json +23573 -0
  37. package/lib/cn/pinyin/loader.js +14 -0
  38. package/lib/cn/pinyin/loader.js.map +1 -0
  39. package/lib/cn/pinyin/preload.js +3 -0
  40. package/lib/cn/pinyin/preload.js.map +1 -0
  41. package/lib/cn/pinyin/toPinyin.test.js +167 -0
  42. package/lib/cn/pinyin/toPinyinPure.js +33 -0
  43. package/lib/cn/pinyin/toPinyinPure.js.map +1 -0
  44. package/lib/cn/pinyin/transform.js +14 -0
  45. package/lib/cn/pinyin/transform.js.map +1 -0
  46. package/lib/cn/types.d.js +2 -0
  47. package/lib/cn/types.d.js.map +1 -0
  48. package/lib/consola/createStandardConsolaReporter.js +6 -6
  49. package/lib/consola/createStandardConsolaReporter.js.map +1 -0
  50. package/lib/consola/formatLogObject.js +66 -146
  51. package/lib/consola/formatLogObject.js.map +1 -0
  52. package/lib/consola/formatLogObject.test.js +184 -0
  53. package/lib/consola/index.js +1 -0
  54. package/lib/consola/index.js.map +1 -0
  55. package/lib/data/formatSort.js +6 -5
  56. package/lib/data/formatSort.js.map +1 -0
  57. package/lib/data/index.js +1 -0
  58. package/lib/data/index.js.map +1 -0
  59. package/lib/data/maybeNumber.js +6 -8
  60. package/lib/data/maybeNumber.js.map +1 -0
  61. package/lib/data/parseSort.js +22 -28
  62. package/lib/data/parseSort.js.map +1 -0
  63. package/lib/data/resolvePagination.js +13 -17
  64. package/lib/data/resolvePagination.js.map +1 -0
  65. package/lib/data/types.d.js +2 -0
  66. package/lib/data/types.d.js.map +1 -0
  67. package/lib/dayjs/dayjs.js +21 -19
  68. package/lib/dayjs/dayjs.js.map +1 -0
  69. package/lib/dayjs/formatDuration.js +15 -14
  70. package/lib/dayjs/formatDuration.js.map +1 -0
  71. package/lib/dayjs/index.js +2 -0
  72. package/lib/dayjs/index.js.map +1 -0
  73. package/lib/dayjs/parseDuration.js +5 -8
  74. package/lib/dayjs/parseDuration.js.map +1 -0
  75. package/lib/dayjs/parseRelativeTime.js +90 -0
  76. package/lib/dayjs/parseRelativeTime.js.map +1 -0
  77. package/lib/dayjs/parseRelativeTime.test.js +247 -0
  78. package/lib/dayjs/resolveRelativeTime.js +87 -0
  79. package/lib/dayjs/resolveRelativeTime.js.map +1 -0
  80. package/lib/dayjs/resolveRelativeTime.test.js +310 -0
  81. package/lib/decimal/index.js +1 -0
  82. package/lib/decimal/index.js.map +1 -0
  83. package/lib/decimal/parseDecimal.js +3 -1
  84. package/lib/decimal/parseDecimal.js.map +1 -0
  85. package/lib/drain3/Drain.js +356 -0
  86. package/lib/drain3/Drain.js.map +1 -0
  87. package/lib/drain3/LogCluster.js +38 -0
  88. package/lib/drain3/LogCluster.js.map +1 -0
  89. package/lib/drain3/Node.js +39 -0
  90. package/lib/drain3/Node.js.map +1 -0
  91. package/lib/drain3/TemplateMiner.js +204 -0
  92. package/lib/drain3/TemplateMiner.js.map +1 -0
  93. package/lib/drain3/index.js +31 -0
  94. package/lib/drain3/index.js.map +1 -0
  95. package/lib/drain3/persistence/FilePersistence.js +24 -0
  96. package/lib/drain3/persistence/FilePersistence.js.map +1 -0
  97. package/lib/drain3/persistence/MemoryPersistence.js +18 -0
  98. package/lib/drain3/persistence/MemoryPersistence.js.map +1 -0
  99. package/lib/drain3/persistence/PersistenceHandler.js +5 -0
  100. package/lib/drain3/persistence/PersistenceHandler.js.map +1 -0
  101. package/lib/drain3/types.js +7 -0
  102. package/lib/drain3/types.js.map +1 -0
  103. package/lib/emittery/emitter.js +10 -0
  104. package/lib/emittery/emitter.js.map +1 -0
  105. package/lib/emittery/index.js +2 -0
  106. package/lib/emittery/index.js.map +1 -0
  107. package/lib/foundation/schema/SexType.js +5 -3
  108. package/lib/foundation/schema/SexType.js.map +1 -0
  109. package/lib/foundation/schema/index.js +1 -0
  110. package/lib/foundation/schema/index.js.map +1 -0
  111. package/lib/foundation/schema/parseSexType.js +1 -0
  112. package/lib/foundation/schema/parseSexType.js.map +1 -0
  113. package/lib/foundation/schema/types.js +4 -2
  114. package/lib/foundation/schema/types.js.map +1 -0
  115. package/lib/fs/FileSystemError.js +23 -0
  116. package/lib/fs/FileSystemError.js.map +1 -0
  117. package/lib/fs/IFileSystem.d.js +3 -0
  118. package/lib/fs/IFileSystem.d.js.map +1 -0
  119. package/lib/fs/MemoryFileSystem.test.js +188 -0
  120. package/lib/fs/createBrowserFileSystem.js +250 -0
  121. package/lib/fs/createBrowserFileSystem.js.map +1 -0
  122. package/lib/fs/createMemoryFileSystem.js +517 -0
  123. package/lib/fs/createMemoryFileSystem.js.map +1 -0
  124. package/lib/fs/createSandboxFileSystem.js +108 -0
  125. package/lib/fs/createSandboxFileSystem.js.map +1 -0
  126. package/lib/fs/createWebDavFileSystem.js +154 -0
  127. package/lib/fs/createWebDavFileSystem.js.map +1 -0
  128. package/lib/fs/createWebFileSystem.js +225 -0
  129. package/lib/fs/createWebFileSystem.js.map +1 -0
  130. package/lib/fs/findMimeType.js +17 -0
  131. package/lib/fs/findMimeType.js.map +1 -0
  132. package/lib/fs/index.js +8 -0
  133. package/lib/fs/index.js.map +1 -0
  134. package/lib/fs/minio/createMinioFileSystem.js +974 -0
  135. package/lib/fs/minio/createMinioFileSystem.js.map +1 -0
  136. package/lib/fs/minio/index.js +2 -0
  137. package/lib/fs/minio/index.js.map +1 -0
  138. package/lib/fs/orpc/FileSystemContract.js +93 -0
  139. package/lib/fs/orpc/FileSystemContract.js.map +1 -0
  140. package/lib/fs/orpc/createContractClientFileSystem.js +93 -0
  141. package/lib/fs/orpc/createContractClientFileSystem.js.map +1 -0
  142. package/lib/fs/orpc/index.js +3 -0
  143. package/lib/fs/orpc/index.js.map +1 -0
  144. package/lib/fs/orpc/server/createFileSystemContractImpl.js +63 -0
  145. package/lib/fs/orpc/server/createFileSystemContractImpl.js.map +1 -0
  146. package/lib/fs/orpc/server/index.js +2 -0
  147. package/lib/fs/orpc/server/index.js.map +1 -0
  148. package/lib/fs/s3/createS3MiniFileSystem.js +753 -0
  149. package/lib/fs/s3/createS3MiniFileSystem.js.map +1 -0
  150. package/lib/fs/s3/index.js +2 -0
  151. package/lib/fs/s3/index.js.map +1 -0
  152. package/lib/fs/s3/s3mini.test.js +584 -0
  153. package/lib/fs/scandir.js +59 -0
  154. package/lib/fs/scandir.js.map +1 -0
  155. package/lib/fs/server/createDatabaseFileSystem.js +750 -0
  156. package/lib/fs/server/createDatabaseFileSystem.js.map +1 -0
  157. package/lib/fs/server/createNodeFileSystem.js +426 -0
  158. package/lib/fs/server/createNodeFileSystem.js.map +1 -0
  159. package/lib/fs/server/dbfs.test.js +221 -0
  160. package/lib/fs/server/index.js +2 -0
  161. package/lib/fs/server/index.js.map +1 -0
  162. package/lib/fs/server/loadTestDatabase.js +127 -0
  163. package/lib/fs/server/loadTestDatabase.js.map +1 -0
  164. package/lib/fs/tests/runFileSystemTest.js +319 -0
  165. package/lib/fs/tests/runFileSystemTest.js.map +1 -0
  166. package/lib/fs/types.js +27 -0
  167. package/lib/fs/types.js.map +1 -0
  168. package/lib/fs/utils/getFileUrl.js +35 -0
  169. package/lib/fs/utils/getFileUrl.js.map +1 -0
  170. package/lib/fs/utils.js +22 -0
  171. package/lib/fs/utils.js.map +1 -0
  172. package/lib/fs/webdav/index.js +2 -0
  173. package/lib/fs/webdav/index.js.map +1 -0
  174. package/lib/index.js +1 -0
  175. package/lib/index.js.map +1 -0
  176. package/lib/jsonschema/JsonSchema.js +146 -172
  177. package/lib/jsonschema/JsonSchema.js.map +1 -0
  178. package/lib/jsonschema/forEachJsonSchema.js +44 -0
  179. package/lib/jsonschema/forEachJsonSchema.js.map +1 -0
  180. package/lib/jsonschema/index.js +2 -0
  181. package/lib/jsonschema/index.js.map +1 -0
  182. package/lib/jsonschema/types.d.js +2 -0
  183. package/lib/jsonschema/types.d.js.map +1 -0
  184. package/lib/meta/defineFileType.js +20 -103
  185. package/lib/meta/defineFileType.js.map +1 -0
  186. package/lib/meta/defineInit.js +31 -250
  187. package/lib/meta/defineInit.js.map +1 -0
  188. package/lib/meta/defineMetadata.js +24 -140
  189. package/lib/meta/defineMetadata.js.map +1 -0
  190. package/lib/meta/index.js +1 -0
  191. package/lib/meta/index.js.map +1 -0
  192. package/lib/orpc/createOpenApiContractClient.js +27 -0
  193. package/lib/orpc/createOpenApiContractClient.js.map +1 -0
  194. package/lib/orpc/createRpcContractClient.js +34 -0
  195. package/lib/orpc/createRpcContractClient.js.map +1 -0
  196. package/lib/orpc/index.js +3 -0
  197. package/lib/orpc/index.js.map +1 -0
  198. package/lib/orpc/resolveLinkPlugins.js +28 -0
  199. package/lib/orpc/resolveLinkPlugins.js.map +1 -0
  200. package/lib/password/PHC.js +63 -87
  201. package/lib/password/PHC.js.map +1 -0
  202. package/lib/password/PHC.test.js +11 -3
  203. package/lib/password/Password.js +29 -294
  204. package/lib/password/Password.js.map +1 -0
  205. package/lib/password/Password.test.js +35 -22
  206. package/lib/password/createArgon2PasswordAlgorithm.js +35 -191
  207. package/lib/password/createArgon2PasswordAlgorithm.js.map +1 -0
  208. package/lib/password/createBase64PasswordAlgorithm.js +8 -141
  209. package/lib/password/createBase64PasswordAlgorithm.js.map +1 -0
  210. package/lib/password/createBcryptPasswordAlgorithm.js +13 -168
  211. package/lib/password/createBcryptPasswordAlgorithm.js.map +1 -0
  212. package/lib/password/createPBKDF2PasswordAlgorithm.js +46 -228
  213. package/lib/password/createPBKDF2PasswordAlgorithm.js.map +1 -0
  214. package/lib/password/createScryptPasswordAlgorithm.js +55 -211
  215. package/lib/password/createScryptPasswordAlgorithm.js.map +1 -0
  216. package/lib/password/index.js +1 -0
  217. package/lib/password/index.js.map +1 -0
  218. package/lib/password/server/index.js +1 -0
  219. package/lib/password/server/index.js.map +1 -0
  220. package/lib/resource/Identifiable.js +2 -0
  221. package/lib/resource/Identifiable.js.map +1 -0
  222. package/lib/resource/ListQuery.js +21 -93
  223. package/lib/resource/ListQuery.js.map +1 -0
  224. package/lib/resource/getTitleOfResource.js +3 -5
  225. package/lib/resource/getTitleOfResource.js.map +1 -0
  226. package/lib/resource/index.js +1 -0
  227. package/lib/resource/index.js.map +1 -0
  228. package/lib/resource/schema/AnyResourceSchema.js +2 -1
  229. package/lib/resource/schema/AnyResourceSchema.js.map +1 -0
  230. package/lib/resource/schema/BaseResourceSchema.js +2 -1
  231. package/lib/resource/schema/BaseResourceSchema.js.map +1 -0
  232. package/lib/resource/schema/ResourceActionType.js +6 -4
  233. package/lib/resource/schema/ResourceActionType.js.map +1 -0
  234. package/lib/resource/schema/ResourceStatus.js +5 -3
  235. package/lib/resource/schema/ResourceStatus.js.map +1 -0
  236. package/lib/resource/schema/ResourceType.js +5 -3
  237. package/lib/resource/schema/ResourceType.js.map +1 -0
  238. package/lib/resource/schema/index.js +1 -0
  239. package/lib/resource/schema/index.js.map +1 -0
  240. package/lib/resource/schema/types.js +16 -20
  241. package/lib/resource/schema/types.js.map +1 -0
  242. package/lib/s3/formatS3Url.js +65 -0
  243. package/lib/s3/formatS3Url.js.map +1 -0
  244. package/lib/s3/formatS3Url.test.js +262 -0
  245. package/lib/s3/index.js +3 -0
  246. package/lib/s3/index.js.map +1 -0
  247. package/lib/s3/parseS3Url.js +65 -0
  248. package/lib/s3/parseS3Url.js.map +1 -0
  249. package/lib/s3/parseS3Url.test.js +270 -0
  250. package/lib/schema/SchemaRegistry.js +38 -38
  251. package/lib/schema/SchemaRegistry.js.map +1 -0
  252. package/lib/schema/TypeSchema.d.js +2 -0
  253. package/lib/schema/TypeSchema.d.js.map +1 -0
  254. package/lib/schema/createSchemaData.js +26 -125
  255. package/lib/schema/createSchemaData.js.map +1 -0
  256. package/lib/schema/findJsonSchemaByPath.js +13 -36
  257. package/lib/schema/findJsonSchemaByPath.js.map +1 -0
  258. package/lib/schema/formatZodError.js +138 -0
  259. package/lib/schema/formatZodError.js.map +1 -0
  260. package/lib/schema/formatZodError.test.js +196 -0
  261. package/lib/schema/getSchemaCache.js +5 -5
  262. package/lib/schema/getSchemaCache.js.map +1 -0
  263. package/lib/schema/getSchemaOptions.js +8 -11
  264. package/lib/schema/getSchemaOptions.js.map +1 -0
  265. package/lib/schema/index.js +2 -1
  266. package/lib/schema/index.js.map +1 -0
  267. package/lib/schema/toJsonSchema.js +50 -293
  268. package/lib/schema/toJsonSchema.js.map +1 -0
  269. package/lib/schema/validate.js +34 -46
  270. package/lib/schema/validate.js.map +1 -0
  271. package/lib/tools/generateSchema.js +39 -197
  272. package/lib/tools/generateSchema.js.map +1 -0
  273. package/lib/tools/renderJsonSchemaToMarkdownDoc.js +55 -143
  274. package/lib/tools/renderJsonSchemaToMarkdownDoc.js.map +1 -0
  275. package/lib/utils/buildBaseUrl.js +13 -0
  276. package/lib/utils/buildBaseUrl.js.map +1 -0
  277. package/lib/utils/buildRedactorFormSchema.js +59 -0
  278. package/lib/utils/buildRedactorFormSchema.js.map +1 -0
  279. package/lib/utils/getEstimateProcessTime.js +12 -11
  280. package/lib/utils/getEstimateProcessTime.js.map +1 -0
  281. package/lib/utils/index.js +3 -0
  282. package/lib/utils/index.js.map +1 -0
  283. package/lib/utils/resolveFeatureOptions.js +12 -0
  284. package/lib/utils/resolveFeatureOptions.js.map +1 -0
  285. package/package.json +80 -13
  286. package/src/ai/qwen3vl/index.ts +1 -0
  287. package/src/ai/qwen3vl/utils.ts +36 -0
  288. package/src/ai/vision/DocLayoutElementTypeSchema.ts +30 -0
  289. package/src/ai/vision/ImageAnnotationSchema.ts +60 -0
  290. package/src/ai/vision/index.ts +2 -0
  291. package/src/ai/vision/resolveImageAnnotation.ts +135 -0
  292. package/src/cn/ChineseResidentIdNo.test.ts +1 -1
  293. package/src/cn/ChineseResidentIdNo.ts +9 -1
  294. package/src/cn/DivisionCode.test.ts +1 -1
  295. package/src/cn/DivisionCode.ts +8 -0
  296. package/src/cn/Mod11.ts +1 -1
  297. package/src/cn/UnifiedSocialCreditCode.test.ts +1 -1
  298. package/src/cn/UnifiedSocialCreditCode.ts +15 -0
  299. package/src/cn/__snapshots__/ChineseResidentIdNo.test.ts.snap +1 -1
  300. package/src/cn/formatChineseAmount.ts +61 -0
  301. package/src/cn/index.ts +7 -1
  302. package/src/cn/parseChineseNumber.test.ts +159 -0
  303. package/src/cn/parseChineseNumber.ts +97 -0
  304. package/src/cn/pinyin/cartesianProduct.test.ts +64 -0
  305. package/src/cn/pinyin/cartesianProduct.ts +24 -0
  306. package/src/cn/pinyin/data.json +23573 -0
  307. package/src/cn/pinyin/loader.ts +12 -0
  308. package/src/cn/pinyin/preload.ts +3 -0
  309. package/src/cn/pinyin/toPinyin.test.ts +12 -0
  310. package/src/cn/pinyin/toPinyinPure.ts +43 -0
  311. package/src/cn/pinyin/transform.ts +12 -0
  312. package/src/consola/formatLogObject.test.ts +27 -0
  313. package/src/consola/formatLogObject.ts +40 -12
  314. package/src/data/maybeNumber.ts +1 -1
  315. package/src/data/parseSort.test.ts +0 -1
  316. package/src/data/types.d.ts +2 -2
  317. package/src/dayjs/dayjs.ts +18 -18
  318. package/src/dayjs/formatDuration.ts +2 -2
  319. package/src/dayjs/index.ts +3 -1
  320. package/src/dayjs/parseRelativeTime.test.ts +185 -0
  321. package/src/dayjs/parseRelativeTime.ts +115 -0
  322. package/src/dayjs/resolveRelativeTime.test.ts +357 -0
  323. package/src/dayjs/resolveRelativeTime.ts +164 -0
  324. package/src/drain3/Drain.test.ts +378 -0
  325. package/src/drain3/Drain.ts +394 -0
  326. package/src/drain3/LogCluster.ts +46 -0
  327. package/src/drain3/Node.ts +53 -0
  328. package/src/drain3/TemplateMiner.ts +246 -0
  329. package/src/drain3/index.ts +36 -0
  330. package/src/drain3/persistence/FilePersistence.ts +24 -0
  331. package/src/drain3/persistence/MemoryPersistence.ts +23 -0
  332. package/src/drain3/persistence/PersistenceHandler.ts +19 -0
  333. package/src/drain3/types.ts +75 -0
  334. package/src/emittery/emitter.ts +9 -0
  335. package/src/emittery/index.ts +1 -0
  336. package/src/fs/FileSystemError.ts +26 -0
  337. package/src/fs/IFileSystem.d.ts +101 -0
  338. package/src/fs/MemoryFileSystem.test.ts +37 -0
  339. package/src/fs/createBrowserFileSystem.ts +293 -0
  340. package/src/fs/createMemoryFileSystem.ts +600 -0
  341. package/src/fs/createSandboxFileSystem.ts +136 -0
  342. package/src/fs/createWebDavFileSystem.ts +190 -0
  343. package/src/fs/createWebFileSystem.ts +242 -0
  344. package/src/fs/findMimeType.ts +20 -0
  345. package/src/fs/index.ts +8 -0
  346. package/src/fs/minio/createMinioFileSystem.ts +1148 -0
  347. package/src/fs/minio/index.ts +1 -0
  348. package/src/fs/orpc/FileSystemContract.ts +92 -0
  349. package/src/fs/orpc/createContractClientFileSystem.ts +115 -0
  350. package/src/fs/orpc/index.ts +2 -0
  351. package/src/fs/orpc/server/createFileSystemContractImpl.ts +64 -0
  352. package/src/fs/orpc/server/index.ts +1 -0
  353. package/src/fs/s3/createS3MiniFileSystem.ts +871 -0
  354. package/src/fs/s3/index.ts +1 -0
  355. package/src/fs/s3/s3fs.test.ts +441 -0
  356. package/src/fs/s3/s3mini.test.ts +264 -0
  357. package/src/fs/scandir.ts +75 -0
  358. package/src/fs/server/createDatabaseFileSystem.ts +668 -0
  359. package/src/fs/server/createNodeFileSystem.ts +518 -0
  360. package/src/fs/server/dbfs.test.ts +48 -0
  361. package/src/fs/server/index.ts +1 -0
  362. package/src/fs/server/loadTestDatabase.ts +131 -0
  363. package/src/fs/tests/runFileSystemTest.ts +289 -0
  364. package/src/fs/types.ts +29 -0
  365. package/src/fs/utils/getFileUrl.ts +44 -0
  366. package/src/fs/utils.ts +23 -0
  367. package/src/fs/webdav/index.ts +1 -0
  368. package/src/jsonschema/JsonSchema.ts +118 -110
  369. package/src/jsonschema/forEachJsonSchema.ts +50 -0
  370. package/src/jsonschema/index.ts +1 -0
  371. package/src/jsonschema/types.d.ts +1 -1
  372. package/src/meta/defineMetadata.ts +1 -1
  373. package/src/orpc/createOpenApiContractClient.ts +52 -0
  374. package/src/orpc/createRpcContractClient.ts +50 -0
  375. package/src/orpc/index.ts +2 -0
  376. package/src/orpc/resolveLinkPlugins.ts +29 -0
  377. package/src/password/PHC.ts +6 -6
  378. package/src/password/Password.test.ts +1 -1
  379. package/src/password/createArgon2PasswordAlgorithm.ts +1 -1
  380. package/src/password/createBase64PasswordAlgorithm.ts +2 -2
  381. package/src/password/createBcryptPasswordAlgorithm.ts +4 -2
  382. package/src/password/createPBKDF2PasswordAlgorithm.ts +4 -4
  383. package/src/password/createScryptPasswordAlgorithm.ts +4 -4
  384. package/src/resource/ListQuery.ts +4 -1
  385. package/src/resource/index.ts +2 -2
  386. package/src/resource/schema/AnyResourceSchema.ts +16 -2
  387. package/src/s3/formatS3Url.test.ts +254 -0
  388. package/src/s3/formatS3Url.ts +84 -0
  389. package/src/s3/index.ts +2 -0
  390. package/src/s3/parseS3Url.test.ts +258 -0
  391. package/src/s3/parseS3Url.ts +88 -0
  392. package/src/schema/SchemaRegistry.ts +35 -33
  393. package/src/schema/TypeSchema.d.ts +6 -6
  394. package/src/schema/createSchemaData.ts +4 -4
  395. package/src/schema/findJsonSchemaByPath.ts +4 -4
  396. package/src/schema/formatZodError.test.ts +197 -0
  397. package/src/schema/formatZodError.ts +139 -0
  398. package/src/schema/getSchemaOptions.ts +2 -2
  399. package/src/schema/index.ts +1 -1
  400. package/src/schema/toJsonSchema.ts +6 -6
  401. package/src/schema/validate.ts +1 -1
  402. package/src/utils/buildBaseUrl.ts +12 -0
  403. package/src/utils/buildRedactorFormSchema.ts +85 -0
  404. package/src/utils/index.ts +4 -0
  405. package/src/utils/resolveFeatureOptions.ts +14 -0
  406. package/src/cn/ChineseResidentIdNo.mod.ts +0 -7
  407. package/src/cn/DivisionCode.mod.ts +0 -7
  408. package/src/cn/UnifiedSocialCreditCode.mod.ts +0 -7
  409. package/src/cn/mod.ts +0 -3
  410. package/src/schema/SchemaRegistry.mod.ts +0 -1
@@ -0,0 +1,974 @@
1
+ import { basename, dirname, normalize } from "pathe";
2
+ import { PassThrough, Readable } from "node:stream";
3
+ import { parseS3Url } from "@wener/common/s3";
4
+ import { Client } from "minio";
5
+ export function createMinioFileSystem(options = {}) {
6
+ const parsed = parseS3Url(options);
7
+ if (!parsed) {
8
+ throw new Error('S3 URL or connection options are required');
9
+ }
10
+ const { client, prefix } = options;
11
+ if (!client && (!parsed.endpoint || !parsed.bucket)) {
12
+ throw new Error('S3 endpoint and bucket are required when client is not provided');
13
+ }
14
+ let minioClient;
15
+ let bucket;
16
+ if (client) {
17
+ minioClient = client;
18
+ bucket = parsed.bucket || '';
19
+ } else {
20
+ bucket = parsed.bucket || '';
21
+ // Import Minio dynamically to avoid requiring it as a dependency
22
+ minioClient = new Client({
23
+ endPoint: parsed.endpoint,
24
+ port: parsed.port,
25
+ useSSL: parsed.useSsl ?? true,
26
+ accessKey: parsed.accessKeyId || '',
27
+ secretKey: parsed.secretAccessKey || '',
28
+ region: parsed.region,
29
+ pathStyle: parsed.pathStyle
30
+ });
31
+ }
32
+ // Normalize prefix: remove leading/trailing slashes
33
+ const normalizedPrefix = prefix ? prefix.replace(/^\/+/, '').replace(/\/+$/, '') : '';
34
+ return new MinioFS(minioClient, bucket, normalizedPrefix);
35
+ }
36
+ let MinioFS = class MinioFS {
37
+ client;
38
+ bucket;
39
+ prefix;
40
+ constructor(client, bucket, prefix = ''){
41
+ this.client = client;
42
+ this.bucket = bucket;
43
+ this.prefix = prefix;
44
+ }
45
+ /**
46
+ * Normalize path to S3 key format (remove leading slash, handle relative paths)
47
+ * and prepend the prefix if one is set
48
+ */ normalizeKey(path) {
49
+ if (!path || path === '/') {
50
+ return this.prefix;
51
+ }
52
+ const normalized = normalize(path).replace(/^\/+/, '').replace(/\\/g, '/');
53
+ // Prepend prefix if set
54
+ if (this.prefix) {
55
+ return this.prefix + '/' + normalized;
56
+ }
57
+ return normalized;
58
+ }
59
+ /**
60
+ * Remove prefix from S3 key to get the file system path
61
+ */ stripPrefix(key) {
62
+ if (!key) {
63
+ return '/';
64
+ }
65
+ // If key is just the prefix (or empty after stripping), return root
66
+ if (this.prefix && key === this.prefix) {
67
+ return '/';
68
+ }
69
+ if (!this.prefix || !key.startsWith(this.prefix + '/')) {
70
+ return key.startsWith('/') ? key : '/' + key;
71
+ }
72
+ const withoutPrefix = key.slice(this.prefix.length);
73
+ return withoutPrefix || '/';
74
+ }
75
+ /**
76
+ * Convert S3 key back to file system path (strip prefix and add leading slash)
77
+ */ keyToPath(key) {
78
+ if (!key) {
79
+ return '/';
80
+ }
81
+ return this.stripPrefix(key);
82
+ }
83
+ /**
84
+ * Get directory path from a key
85
+ */ getDirectory(key) {
86
+ if (!key) {
87
+ return '/';
88
+ }
89
+ const dir = dirname(key).replace(/\\/g, '/');
90
+ return dir === '.' ? '/' : '/' + dir;
91
+ }
92
+ /**
93
+ * Check if a key represents a directory (ends with /)
94
+ */ isDirectoryKey(key) {
95
+ return key.endsWith('/');
96
+ }
97
+ /**
98
+ * Convert MinIO object metadata to IFileStat
99
+ */ toFileStat(key, obj) {
100
+ const isDir = this.isDirectoryKey(key);
101
+ const path = this.keyToPath(key);
102
+ const directory = this.getDirectory(key);
103
+ return {
104
+ directory,
105
+ path,
106
+ name: isDir ? basename(key.slice(0, -1)) || basename(directory) || '/' : basename(key),
107
+ kind: isDir ? 'directory' : 'file',
108
+ mtime: obj.lastModified ? new Date(obj.lastModified).getTime() : Date.now(),
109
+ size: obj.size || 0,
110
+ meta: {
111
+ ...obj.etag ? {
112
+ etag: obj.etag.replace(/"/g, '')
113
+ } : {}
114
+ }
115
+ };
116
+ }
117
+ checkAborted(signal) {
118
+ if (signal?.aborted) {
119
+ throw new Error('The operation was aborted');
120
+ }
121
+ }
122
+ async readdir(dir, options = {}) {
123
+ const { glob, recursive, depth = 1, kind, hidden = true, signal } = options;
124
+ this.checkAborted(signal);
125
+ const dirPrefix = this.normalizeKey(dir);
126
+ const prefixWithSlash = dirPrefix ? dirPrefix.endsWith('/') ? dirPrefix : dirPrefix + '/' : '';
127
+ try {
128
+ // MinIO listObjects supports recursive option
129
+ // When recursive=false, MinIO uses delimiter='/' internally to return CommonPrefixes
130
+ const objects = [];
131
+ const commonPrefixes = [];
132
+ // MinIO listObjects returns a stream
133
+ // When recursive=false, it returns both objects and prefixes (CommonPrefixes)
134
+ const objectStream = this.client.listObjects(this.bucket, prefixWithSlash, recursive);
135
+ await new Promise((resolve, reject)=>{
136
+ objectStream.on('data', (obj)=>{
137
+ if (obj.name) {
138
+ objects.push({
139
+ name: obj.name,
140
+ size: obj.size || 0,
141
+ lastModified: obj.lastModified || new Date(),
142
+ etag: obj.etag || ''
143
+ });
144
+ } else if (obj.prefix) {
145
+ // CommonPrefixes from MinIO
146
+ commonPrefixes.push(obj.prefix);
147
+ }
148
+ });
149
+ objectStream.on('end', ()=>{
150
+ resolve();
151
+ });
152
+ objectStream.on('error', (err)=>{
153
+ reject(err);
154
+ });
155
+ if (signal) {
156
+ signal.addEventListener('abort', ()=>{
157
+ objectStream.destroy();
158
+ reject(new Error('The operation was aborted'));
159
+ });
160
+ }
161
+ });
162
+ let results = [];
163
+ // Process CommonPrefixes (directories) first
164
+ for (const prefix of commonPrefixes){
165
+ this.checkAborted(signal);
166
+ // Skip if not under our prefix
167
+ if (prefixWithSlash && !prefix.startsWith(prefixWithSlash)) {
168
+ continue;
169
+ }
170
+ // Get relative path
171
+ const relativePrefix = prefixWithSlash ? prefix.slice(prefixWithSlash.length) : prefix;
172
+ const dirName = relativePrefix.replace(/\/$/, ''); // Remove trailing slash
173
+ if (!dirName) continue;
174
+ // For non-recursive, only show immediate children
175
+ if (!recursive && depth === 1) {
176
+ const firstSlash = dirName.indexOf('/');
177
+ if (firstSlash >= 0) {
178
+ continue;
179
+ }
180
+ }
181
+ const dirKey = prefix.endsWith('/') ? prefix : prefix + '/';
182
+ const stat = this.toFileStat(dirKey, {
183
+ name: dirKey,
184
+ size: 0,
185
+ lastModified: new Date()
186
+ });
187
+ // Filter by hidden
188
+ if (!hidden && stat.name.startsWith('.')) {
189
+ continue;
190
+ }
191
+ // Filter by kind
192
+ if (kind && stat.kind !== kind) {
193
+ continue;
194
+ }
195
+ results.push(stat);
196
+ }
197
+ // Process objects (files) to convert to IFileStat
198
+ const seenDirs = new Set();
199
+ for (const obj of objects){
200
+ this.checkAborted(signal);
201
+ const key = obj.name;
202
+ if (!key) continue;
203
+ // Skip if not under our prefix
204
+ if (prefixWithSlash && !key.startsWith(prefixWithSlash)) {
205
+ continue;
206
+ }
207
+ // Strip the prefix from the key for path conversion
208
+ const relativeKey = prefixWithSlash ? key.slice(prefixWithSlash.length) : key;
209
+ // Calculate depth: count the number of slashes in the relative path
210
+ // depth=1 means immediate children (no slashes), depth=2 means one level deep (one slash), etc.
211
+ const depthLevel = (relativeKey.match(/\//g) || []).length + 1;
212
+ // Filter by depth
213
+ if (depthLevel > depth) {
214
+ continue;
215
+ }
216
+ const isDir = this.isDirectoryKey(key);
217
+ // Track directories to avoid duplicates
218
+ if (isDir) {
219
+ const dirKey = key.slice(0, -1);
220
+ if (seenDirs.has(dirKey)) {
221
+ continue;
222
+ }
223
+ seenDirs.add(dirKey);
224
+ } else {
225
+ // For files in recursive mode, always include them
226
+ // For non-recursive mode, check if parent directory was already added
227
+ if (!recursive) {
228
+ const parentDir = dirname(key).replace(/\\/g, '/') + '/';
229
+ if (seenDirs.has(parentDir.slice(0, -1))) {
230
+ continue;
231
+ }
232
+ }
233
+ }
234
+ const stat = this.toFileStat(key, {
235
+ name: key,
236
+ size: obj.size || 0,
237
+ lastModified: obj.lastModified,
238
+ etag: obj.etag
239
+ });
240
+ // Filter by hidden
241
+ if (!hidden && stat.name.startsWith('.')) {
242
+ continue;
243
+ }
244
+ // Filter by kind
245
+ if (kind && stat.kind !== kind) {
246
+ continue;
247
+ }
248
+ results.push(stat);
249
+ }
250
+ // Handle recursive with depth > 1
251
+ if (!recursive && depth > 1) {
252
+ const subdirs = results.filter((entry)=>entry.kind === 'directory');
253
+ for (const subdir of subdirs){
254
+ this.checkAborted(signal);
255
+ const maxDepth = depth - 1;
256
+ if (maxDepth > 0) {
257
+ const subEntries = await this.readdir(subdir.path, {
258
+ ...options,
259
+ depth: maxDepth
260
+ });
261
+ results = [
262
+ ...results,
263
+ ...subEntries
264
+ ];
265
+ }
266
+ }
267
+ }
268
+ // Handle glob filtering
269
+ if (glob) {
270
+ const { matcher } = await import("micromatch");
271
+ const match = matcher(glob);
272
+ results = results.filter((entry)=>match(entry.path));
273
+ }
274
+ return results;
275
+ } catch (error) {
276
+ if (error.code === 'NoSuchKey' || error.message?.includes('404') || error.code === 'NotFound') {
277
+ throw new Error(`Directory not found: ${dir}`);
278
+ }
279
+ throw error;
280
+ }
281
+ }
282
+ async stat(entry, options = {}) {
283
+ const { signal } = options;
284
+ this.checkAborted(signal);
285
+ const key = this.normalizeKey(entry);
286
+ if (!key) {
287
+ // Root directory
288
+ return {
289
+ directory: '/',
290
+ path: '/',
291
+ name: '/',
292
+ kind: 'directory',
293
+ mtime: Date.now(),
294
+ size: 0,
295
+ meta: {}
296
+ };
297
+ }
298
+ try {
299
+ // Try to get object stat
300
+ const stat = await this.client.statObject(this.bucket, key);
301
+ return this.toFileStat(key, {
302
+ name: key,
303
+ size: stat.size,
304
+ lastModified: stat.lastModified,
305
+ etag: stat.etag
306
+ });
307
+ } catch (error) {
308
+ // If object not found, try checking if it's a directory
309
+ if (error.code === 'NotFound' || error.code === 'NoSuchKey') {
310
+ const dirKey = key.endsWith('/') ? key : key + '/';
311
+ try {
312
+ // List objects with this prefix to check if it's a directory
313
+ const objectStream = this.client.listObjects(this.bucket, dirKey, false);
314
+ let hasObjects = false;
315
+ await new Promise((resolve, reject)=>{
316
+ objectStream.on('data', ()=>{
317
+ hasObjects = true;
318
+ objectStream.destroy();
319
+ resolve();
320
+ });
321
+ objectStream.on('end', ()=>{
322
+ resolve();
323
+ });
324
+ objectStream.on('error', reject);
325
+ if (signal) {
326
+ signal.addEventListener('abort', ()=>{
327
+ objectStream.destroy();
328
+ reject(new Error('The operation was aborted'));
329
+ });
330
+ }
331
+ });
332
+ if (hasObjects) {
333
+ // It's a directory
334
+ return {
335
+ directory: this.getDirectory(key),
336
+ path: this.keyToPath(key),
337
+ name: basename(key.replace(/\/$/, '')) || '/',
338
+ kind: 'directory',
339
+ mtime: Date.now(),
340
+ size: 0,
341
+ meta: {}
342
+ };
343
+ }
344
+ } catch {
345
+ // Ignore listing errors
346
+ }
347
+ throw new Error(`File not found: ${entry}`);
348
+ }
349
+ throw error;
350
+ }
351
+ }
352
+ async mkdir(path, options = {}) {
353
+ const { recursive = false, signal } = options;
354
+ this.checkAborted(signal);
355
+ // In S3, directories don't actually exist - they're just prefixes
356
+ // Optionally create a marker object (empty object with trailing slash)
357
+ const key = this.normalizeKey(path);
358
+ if (!key) {
359
+ return; // Root directory, nothing to do
360
+ }
361
+ // Ensure it ends with / to indicate directory
362
+ const dirKey = key.endsWith('/') ? key : key + '/';
363
+ // Try to create a marker object (0-byte object)
364
+ try {
365
+ const stream = new PassThrough();
366
+ stream.end();
367
+ await this.client.putObject(this.bucket, dirKey, stream, 0, {
368
+ 'Content-Type': 'application/x-directory'
369
+ });
370
+ } catch (error) {
371
+ // If it already exists or we don't have permission, that's okay for mkdir
372
+ if (error.code !== 'NoSuchBucket' && error.code !== 'AccessDenied') {
373
+ // Ignore other errors for mkdir
374
+ }
375
+ }
376
+ }
377
+ async readFile(path, options = {}) {
378
+ const { encoding = 'binary', signal, onDownloadProgress } = options;
379
+ this.checkAborted(signal);
380
+ const key = this.normalizeKey(path);
381
+ if (!key) {
382
+ throw new Error('Cannot read root directory');
383
+ }
384
+ try {
385
+ // MinIO getObject returns Promise<Readable>
386
+ const nodeStream = await this.client.getObject(this.bucket, key);
387
+ const chunks = [];
388
+ let loaded = 0;
389
+ let total = 0;
390
+ // Get object size for progress if available
391
+ try {
392
+ const stat = await this.client.statObject(this.bucket, key);
393
+ total = stat.size;
394
+ } catch {
395
+ // Ignore if stat fails
396
+ }
397
+ return new Promise((resolve, reject)=>{
398
+ nodeStream.on('data', (chunk)=>{
399
+ chunks.push(chunk);
400
+ loaded += chunk.length;
401
+ if (onDownloadProgress) {
402
+ onDownloadProgress({
403
+ loaded,
404
+ total: total || -1
405
+ });
406
+ }
407
+ });
408
+ nodeStream.on('end', ()=>{
409
+ const buffer = Buffer.concat(chunks);
410
+ if (encoding === 'text') {
411
+ resolve(buffer.toString('utf-8'));
412
+ } else {
413
+ resolve(new Uint8Array(buffer));
414
+ }
415
+ });
416
+ nodeStream.on('error', reject);
417
+ if (signal) {
418
+ signal.addEventListener('abort', ()=>{
419
+ if (nodeStream.destroy) {
420
+ nodeStream.destroy(new Error('The operation was aborted'));
421
+ }
422
+ reject(new Error('The operation was aborted'));
423
+ });
424
+ }
425
+ });
426
+ } catch (error) {
427
+ if (error.code === 'NoSuchKey' || error.code === 'NotFound') {
428
+ throw new Error(`File not found: ${path}`);
429
+ }
430
+ throw error;
431
+ }
432
+ }
433
+ async writeFile(path, data, options = {}) {
434
+ const { signal, overwrite = true, onUploadProgress } = options;
435
+ this.checkAborted(signal);
436
+ const key = this.normalizeKey(path);
437
+ if (!key) {
438
+ throw new Error('Cannot write to root directory');
439
+ }
440
+ // Check if file exists and overwrite is false
441
+ if (!overwrite) {
442
+ const exists = await this.exists(path);
443
+ if (exists) {
444
+ throw new Error(`File already exists: ${path}`);
445
+ }
446
+ }
447
+ // Convert data to stream or buffer
448
+ let stream;
449
+ let size;
450
+ if (data instanceof Readable) {
451
+ stream = data;
452
+ size = 0; // Unknown size
453
+ } else if (data instanceof ReadableStream) {
454
+ // Convert Web ReadableStream to Node Readable
455
+ stream = Readable.fromWeb(data);
456
+ size = 0;
457
+ } else {
458
+ let buffer;
459
+ if (data instanceof ArrayBuffer) {
460
+ buffer = Buffer.from(data);
461
+ } else if (Buffer.isBuffer(data)) {
462
+ buffer = data;
463
+ } else if (typeof data === 'string') {
464
+ buffer = Buffer.from(data, 'utf-8');
465
+ } else {
466
+ // ArrayBufferView
467
+ buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
468
+ }
469
+ size = buffer.length;
470
+ stream = new Readable();
471
+ stream.push(buffer);
472
+ stream.push(null);
473
+ }
474
+ // Wrap stream for progress tracking if needed
475
+ if (onUploadProgress) {
476
+ let loaded = 0;
477
+ const progressStream = new PassThrough();
478
+ stream.on('data', (chunk)=>{
479
+ loaded += chunk.length;
480
+ onUploadProgress({
481
+ loaded,
482
+ total: size || -1
483
+ });
484
+ });
485
+ stream.pipe(progressStream);
486
+ stream = progressStream;
487
+ }
488
+ try {
489
+ await this.client.putObject(this.bucket, key, stream, size);
490
+ } catch (error) {
491
+ throw error;
492
+ }
493
+ }
494
+ async rm(path, options = {}) {
495
+ const { recursive = false, force = false, signal } = options;
496
+ this.checkAborted(signal);
497
+ const key = this.normalizeKey(path);
498
+ if (!key) {
499
+ throw new Error('Cannot remove root directory');
500
+ }
501
+ try {
502
+ if (recursive) {
503
+ // List all objects with this prefix
504
+ const prefix = key.endsWith('/') ? key : key + '/';
505
+ const objectStream = this.client.listObjects(this.bucket, prefix, true);
506
+ const keys = [];
507
+ await new Promise((resolve, reject)=>{
508
+ objectStream.on('data', (obj)=>{
509
+ if (obj.name) {
510
+ keys.push(obj.name);
511
+ }
512
+ });
513
+ objectStream.on('end', ()=>{
514
+ resolve();
515
+ });
516
+ objectStream.on('error', reject);
517
+ if (signal) {
518
+ signal.addEventListener('abort', ()=>{
519
+ objectStream.destroy();
520
+ reject(new Error('The operation was aborted'));
521
+ });
522
+ }
523
+ });
524
+ // Delete all objects
525
+ if (keys.length > 0) {
526
+ await this.client.removeObjects(this.bucket, keys);
527
+ }
528
+ // Also delete the marker object if it exists
529
+ const markerKey = prefix;
530
+ try {
531
+ await this.client.removeObject(this.bucket, markerKey);
532
+ } catch {
533
+ // Ignore if marker doesn't exist
534
+ }
535
+ } else {
536
+ // Delete single object
537
+ try {
538
+ await this.client.removeObject(this.bucket, key);
539
+ } catch (error) {
540
+ // Check if it's a directory with files
541
+ if (error.code === 'NoSuchKey' || error.code === 'NotFound') {
542
+ const prefix = key.endsWith('/') ? key : key + '/';
543
+ const objectStream = this.client.listObjects(this.bucket, prefix, false);
544
+ let hasObjects = false;
545
+ await new Promise((resolve)=>{
546
+ objectStream.on('data', ()=>{
547
+ hasObjects = true;
548
+ objectStream.destroy();
549
+ resolve();
550
+ });
551
+ objectStream.on('end', ()=>{
552
+ resolve();
553
+ });
554
+ objectStream.on('error', ()=>{
555
+ resolve();
556
+ });
557
+ });
558
+ if (hasObjects) {
559
+ if (!force) {
560
+ throw new Error('Directory not empty');
561
+ }
562
+ // If force, delete recursively
563
+ const recursiveStream = this.client.listObjects(this.bucket, prefix, true);
564
+ const keys = [];
565
+ await new Promise((resolve)=>{
566
+ recursiveStream.on('data', (obj)=>{
567
+ if (obj.name) {
568
+ keys.push(obj.name);
569
+ }
570
+ });
571
+ recursiveStream.on('end', ()=>resolve());
572
+ recursiveStream.on('error', ()=>resolve());
573
+ });
574
+ if (keys.length > 0) {
575
+ await this.client.removeObjects(this.bucket, keys);
576
+ }
577
+ // Also try to remove the marker
578
+ try {
579
+ await this.client.removeObject(this.bucket, prefix);
580
+ } catch {
581
+ // Ignore
582
+ }
583
+ } else {
584
+ // File doesn't exist
585
+ if (!force) {
586
+ throw new Error('File not found');
587
+ }
588
+ // If force, just return without error
589
+ return;
590
+ }
591
+ } else if (!force) {
592
+ throw error;
593
+ }
594
+ }
595
+ }
596
+ } catch (error) {
597
+ if (force && (error.code === 'NoSuchKey' || error.code === 'NotFound')) {
598
+ return;
599
+ }
600
+ if (force && error.message === 'File not found') {
601
+ return;
602
+ }
603
+ throw error;
604
+ }
605
+ }
606
+ async rename(oldPath, newPath, options = {}) {
607
+ const { signal, overwrite = false } = options;
608
+ this.checkAborted(signal);
609
+ const oldKey = this.normalizeKey(oldPath);
610
+ const newKey = this.normalizeKey(newPath);
611
+ if (!oldKey) {
612
+ throw new Error('Cannot rename root directory');
613
+ }
614
+ // Check if target exists and overwrite is false
615
+ if (!overwrite) {
616
+ const exists = await this.exists(newPath);
617
+ if (exists) {
618
+ throw new Error(`Destination already exists: ${newPath}`);
619
+ }
620
+ }
621
+ try {
622
+ // Check if it's a directory (has objects with prefix)
623
+ const isDir = oldKey.endsWith('/');
624
+ const prefix = isDir ? oldKey : oldKey + '/';
625
+ const objectStream = this.client.listObjects(this.bucket, prefix, true);
626
+ const objects = [];
627
+ await new Promise((resolve, reject)=>{
628
+ objectStream.on('data', (obj)=>{
629
+ if (obj.name) {
630
+ objects.push({
631
+ name: obj.name
632
+ });
633
+ }
634
+ });
635
+ objectStream.on('end', ()=>{
636
+ resolve();
637
+ });
638
+ objectStream.on('error', reject);
639
+ if (signal) {
640
+ signal.addEventListener('abort', ()=>{
641
+ objectStream.destroy();
642
+ reject(new Error('The operation was aborted'));
643
+ });
644
+ }
645
+ });
646
+ if (objects.length > 0) {
647
+ // It's a directory or has multiple objects, move all
648
+ const newPrefix = newKey.endsWith('/') ? newKey : newKey + '/';
649
+ // Move all objects
650
+ await Promise.all(objects.map(async (obj)=>{
651
+ const objKey = obj.name;
652
+ if (!objKey) return;
653
+ const relativeKey = objKey.slice(prefix.length);
654
+ const newObjKey = newPrefix + relativeKey;
655
+ // Copy then delete
656
+ // MinIO copyObject signature: copyObject(bucketName, objectName, sourceObject)
657
+ // sourceObject should be a string in format "bucket/object"
658
+ await this.client.copyObject(this.bucket, newObjKey, `${this.bucket}/${objKey}`);
659
+ await this.client.removeObject(this.bucket, objKey);
660
+ }));
661
+ // Move marker object if it exists (skip if it's a directory marker with data)
662
+ try {
663
+ // Check if it's a directory marker (ends with /)
664
+ if (prefix.endsWith('/')) {
665
+ // Try to copy the marker, but skip if it fails due to "contains data payload"
666
+ try {
667
+ await this.client.copyObject(this.bucket, newPrefix, `${this.bucket}/${prefix}`);
668
+ await this.client.removeObject(this.bucket, prefix);
669
+ } catch (error) {
670
+ // If error is about data payload, just remove the old marker
671
+ // Directory markers are optional in S3
672
+ if (error.message?.includes('data payload') || error.code === 'InvalidRequest') {
673
+ await this.client.removeObject(this.bucket, prefix);
674
+ } else {
675
+ throw error;
676
+ }
677
+ }
678
+ } else {
679
+ await this.client.copyObject(this.bucket, newPrefix, `${this.bucket}/${prefix}`);
680
+ await this.client.removeObject(this.bucket, prefix);
681
+ }
682
+ } catch {
683
+ // Ignore if marker doesn't exist
684
+ }
685
+ } else {
686
+ // Single file - copy then delete
687
+ await this.client.copyObject(this.bucket, newKey, `${this.bucket}/${oldKey}`);
688
+ await this.client.removeObject(this.bucket, oldKey);
689
+ }
690
+ } catch (error) {
691
+ if (error.code === 'NoSuchKey' || error.code === 'NotFound') {
692
+ throw new Error(`Source file not found: ${oldPath}`);
693
+ }
694
+ throw error;
695
+ }
696
+ }
697
+ async exists(path) {
698
+ try {
699
+ const key = this.normalizeKey(path);
700
+ if (!key) {
701
+ return true; // Root always exists
702
+ }
703
+ await this.client.statObject(this.bucket, key);
704
+ return true;
705
+ } catch (error) {
706
+ if (error.code === 'NotFound' || error.code === 'NoSuchKey') {
707
+ // Check if it's a directory
708
+ const key = this.normalizeKey(path);
709
+ const dirKey = key.endsWith('/') ? key : key + '/';
710
+ try {
711
+ const objectStream = this.client.listObjects(this.bucket, dirKey, false);
712
+ let hasObjects = false;
713
+ await new Promise((resolve)=>{
714
+ objectStream.on('data', ()=>{
715
+ hasObjects = true;
716
+ objectStream.destroy();
717
+ resolve();
718
+ });
719
+ objectStream.on('end', ()=>{
720
+ resolve();
721
+ });
722
+ objectStream.on('error', ()=>{
723
+ resolve();
724
+ });
725
+ });
726
+ return hasObjects;
727
+ } catch {
728
+ return false;
729
+ }
730
+ }
731
+ return false;
732
+ }
733
+ }
734
+ async copy(src, dest, options = {}) {
735
+ const { signal, overwrite = true, shallow = false } = options;
736
+ this.checkAborted(signal);
737
+ const srcKey = this.normalizeKey(src);
738
+ const destKey = this.normalizeKey(dest);
739
+ if (!srcKey) {
740
+ throw new Error('Cannot copy root directory');
741
+ }
742
+ // Check if source exists
743
+ try {
744
+ const srcStat = await this.stat(src);
745
+ // Check if destination exists and overwrite is false
746
+ if (!overwrite) {
747
+ const exists = await this.exists(dest);
748
+ if (exists) {
749
+ throw new Error(`Destination already exists: ${dest}`);
750
+ }
751
+ }
752
+ if (srcStat.kind === 'directory') {
753
+ // Copy directory recursively
754
+ const srcPrefix = srcKey.endsWith('/') ? srcKey : srcKey + '/';
755
+ const destPrefix = destKey.endsWith('/') ? destKey : destKey + '/';
756
+ const objectStream = this.client.listObjects(this.bucket, srcPrefix, !shallow);
757
+ const objects = [];
758
+ await new Promise((resolve, reject)=>{
759
+ objectStream.on('data', (obj)=>{
760
+ if (obj.name) {
761
+ objects.push({
762
+ name: obj.name
763
+ });
764
+ }
765
+ });
766
+ objectStream.on('end', ()=>{
767
+ resolve();
768
+ });
769
+ objectStream.on('error', reject);
770
+ if (signal) {
771
+ signal.addEventListener('abort', ()=>{
772
+ objectStream.destroy();
773
+ reject(new Error('The operation was aborted'));
774
+ });
775
+ }
776
+ });
777
+ // Copy all objects
778
+ await Promise.all(objects.map(async (obj)=>{
779
+ const objKey = obj.name;
780
+ if (!objKey) return;
781
+ const relativeKey = objKey.slice(srcPrefix.length);
782
+ const newObjKey = destPrefix + relativeKey;
783
+ await this.client.copyObject(this.bucket, newObjKey, `${this.bucket}/${objKey}`);
784
+ }));
785
+ // Copy marker object if it exists (skip if it's a directory marker with data)
786
+ try {
787
+ // Check if it's a directory marker (ends with /)
788
+ if (srcPrefix.endsWith('/')) {
789
+ // Try to copy the marker, but skip if it fails due to "contains data payload"
790
+ try {
791
+ await this.client.copyObject(this.bucket, destPrefix, `${this.bucket}/${srcPrefix}`);
792
+ } catch (error) {
793
+ // If error is about data payload, just skip copying the marker
794
+ // Directory markers are optional in S3
795
+ if (!error.message?.includes('data payload') && error.code !== 'InvalidRequest') {
796
+ throw error;
797
+ }
798
+ }
799
+ } else {
800
+ await this.client.copyObject(this.bucket, destPrefix, `${this.bucket}/${srcPrefix}`);
801
+ }
802
+ } catch {
803
+ // Ignore if marker doesn't exist
804
+ }
805
+ } else {
806
+ // Copy single file
807
+ await this.client.copyObject(this.bucket, destKey, `${this.bucket}/${srcKey}`);
808
+ }
809
+ } catch (error) {
810
+ if (error.code === 'NoSuchKey' || error.code === 'NotFound') {
811
+ throw new Error(`Source file not found: ${src}`);
812
+ }
813
+ throw error;
814
+ }
815
+ }
816
+ createReadStream(path, options = {}) {
817
+ const key = this.normalizeKey(path);
818
+ if (!key) {
819
+ throw new Error('Cannot read root directory');
820
+ }
821
+ const { range, signal } = options;
822
+ // MinIO getObject and getPartialObject both return Promise<Readable>
823
+ // Create a Readable stream that waits for the promise to resolve
824
+ const client = this.client;
825
+ const bucket = this.bucket;
826
+ const readable = new Readable({
827
+ async read () {
828
+ // Only initialize once
829
+ if (readable._initialized) {
830
+ return;
831
+ }
832
+ readable._initialized = true;
833
+ try {
834
+ let nodeStream;
835
+ if (range) {
836
+ // Use getPartialObject for range requests
837
+ // getPartialObject's length parameter: number of bytes to read (not end position)
838
+ // So for range {start: 0, end: 4}, we need length = end - start + 1 = 5
839
+ const length = range.end !== undefined ? range.end - range.start + 1 : undefined;
840
+ nodeStream = await client.getPartialObject(bucket, key, range.start, length);
841
+ } else {
842
+ nodeStream = await client.getObject(bucket, key);
843
+ }
844
+ // Pipe the actual stream to our readable
845
+ nodeStream.on('data', (chunk)=>{
846
+ if (!readable.push(chunk)) {
847
+ // If push returns false, the stream is backpressured
848
+ nodeStream.pause();
849
+ }
850
+ });
851
+ nodeStream.on('end', ()=>{
852
+ readable.push(null);
853
+ });
854
+ nodeStream.on('error', (err)=>{
855
+ readable.emit('error', err);
856
+ });
857
+ if (signal) {
858
+ signal.addEventListener('abort', ()=>{
859
+ if (nodeStream.destroy) {
860
+ nodeStream.destroy(new Error('The operation was aborted'));
861
+ }
862
+ readable.emit('error', new Error('The operation was aborted'));
863
+ });
864
+ }
865
+ } catch (error) {
866
+ readable.emit('error', error);
867
+ }
868
+ }
869
+ });
870
+ return readable;
871
+ }
872
+ createReadableStream(path, options = {}) {
873
+ const key = this.normalizeKey(path);
874
+ if (!key) {
875
+ throw new Error('Cannot read root directory');
876
+ }
877
+ const { range, signal } = options;
878
+ // MinIO getObject and getPartialObject both return Promise<Readable>
879
+ const client = this.client;
880
+ const bucket = this.bucket;
881
+ return new ReadableStream({
882
+ async start (controller) {
883
+ try {
884
+ let nodeStream;
885
+ if (range) {
886
+ // Use getPartialObject for range requests
887
+ // getPartialObject's length parameter: number of bytes to read (not end position)
888
+ // So for range {start: 0, end: 4}, we need length = end - start + 1 = 5
889
+ const length = range.end !== undefined ? range.end - range.start + 1 : undefined;
890
+ nodeStream = await client.getPartialObject(bucket, key, range.start, length);
891
+ } else {
892
+ nodeStream = await client.getObject(bucket, key);
893
+ }
894
+ nodeStream.on('data', (chunk)=>{
895
+ controller.enqueue(chunk);
896
+ });
897
+ nodeStream.on('end', ()=>{
898
+ controller.close();
899
+ });
900
+ nodeStream.on('error', (err)=>{
901
+ controller.error(err);
902
+ });
903
+ if (signal) {
904
+ signal.addEventListener('abort', ()=>{
905
+ if (nodeStream.destroy) {
906
+ nodeStream.destroy(new Error('The operation was aborted'));
907
+ }
908
+ controller.error(new Error('The operation was aborted'));
909
+ });
910
+ }
911
+ } catch (error) {
912
+ controller.error(error);
913
+ }
914
+ }
915
+ });
916
+ }
917
+ createWriteStream(path, options) {
918
+ throw new Error('Not implemented');
919
+ }
920
+ createWritableStream(path, options = {}) {
921
+ const key = this.normalizeKey(path);
922
+ if (!key) {
923
+ throw new Error('Cannot write to root directory');
924
+ }
925
+ const { signal, overwrite = true } = options;
926
+ this.checkAborted(signal);
927
+ // Create a WritableStream that buffers data and uploads when done
928
+ const buffer = [];
929
+ let controller;
930
+ const client = this.client;
931
+ const bucket = this.bucket;
932
+ const checkAborted = this.checkAborted.bind(this);
933
+ return new WritableStream({
934
+ start (ctrl) {
935
+ controller = ctrl;
936
+ },
937
+ async write (chunk) {
938
+ buffer.push(chunk);
939
+ },
940
+ async close () {
941
+ try {
942
+ checkAborted(signal);
943
+ const data = Buffer.concat(buffer.map((chunk)=>Buffer.from(chunk)));
944
+ const stream = new Readable();
945
+ stream.push(data);
946
+ stream.push(null);
947
+ await client.putObject(bucket, key, stream, data.length);
948
+ // Controller closes automatically when close() completes successfully
949
+ } catch (error) {
950
+ controller.error(error);
951
+ }
952
+ },
953
+ abort (reason) {
954
+ buffer.length = 0;
955
+ controller.error(reason);
956
+ }
957
+ });
958
+ }
959
+ getUrl(path, options) {
960
+ if (typeof path === 'object' && path?.kind !== 'file') {
961
+ return;
962
+ }
963
+ const key = typeof path === 'string' ? this.normalizeKey(path) : this.normalizeKey(path.path);
964
+ if (!key) {
965
+ return;
966
+ }
967
+ // MinIO supports presigned URLs, but getUrl is synchronous
968
+ // We can't generate presigned URLs synchronously, so return undefined
969
+ // For presigned URLs, users should use a separate method or await the promise
970
+ return undefined;
971
+ }
972
+ };
973
+
974
+ //# sourceMappingURL=createMinioFileSystem.js.map