@milaboratories/pl-drivers 1.16.0 → 1.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/dist/clients/constructors.cjs.map +1 -1
  2. package/dist/clients/constructors.js.map +1 -1
  3. package/dist/clients/crc32c.cjs.map +1 -1
  4. package/dist/clients/crc32c.js.map +1 -1
  5. package/dist/clients/download.cjs +56 -5
  6. package/dist/clients/download.cjs.map +1 -1
  7. package/dist/clients/download.d.ts +13 -1
  8. package/dist/clients/download.d.ts.map +1 -1
  9. package/dist/clients/download.js +53 -2
  10. package/dist/clients/download.js.map +1 -1
  11. package/dist/clients/download_url_cache.cjs +3 -1
  12. package/dist/clients/download_url_cache.cjs.map +1 -1
  13. package/dist/clients/download_url_cache.js +2 -1
  14. package/dist/clients/download_url_cache.js.map +1 -1
  15. package/dist/clients/logs.cjs +2 -1
  16. package/dist/clients/logs.cjs.map +1 -1
  17. package/dist/clients/logs.d.ts.map +1 -1
  18. package/dist/clients/logs.js +2 -0
  19. package/dist/clients/logs.js.map +1 -1
  20. package/dist/clients/ls_api.cjs +1 -1
  21. package/dist/clients/ls_api.cjs.map +1 -1
  22. package/dist/clients/ls_api.d.ts.map +1 -1
  23. package/dist/clients/ls_api.js +1 -0
  24. package/dist/clients/ls_api.js.map +1 -1
  25. package/dist/clients/progress.cjs +2 -1
  26. package/dist/clients/progress.cjs.map +1 -1
  27. package/dist/clients/progress.d.ts.map +1 -1
  28. package/dist/clients/progress.js +2 -0
  29. package/dist/clients/progress.js.map +1 -1
  30. package/dist/clients/upload.cjs +7 -5
  31. package/dist/clients/upload.cjs.map +1 -1
  32. package/dist/clients/upload.d.ts.map +1 -1
  33. package/dist/clients/upload.js +6 -4
  34. package/dist/clients/upload.js.map +1 -1
  35. package/dist/drivers/download_blob/blob_key.cjs +1 -1
  36. package/dist/drivers/download_blob/blob_key.cjs.map +1 -1
  37. package/dist/drivers/download_blob/blob_key.js.map +1 -1
  38. package/dist/drivers/download_blob/download_blob.cjs +36 -7
  39. package/dist/drivers/download_blob/download_blob.cjs.map +1 -1
  40. package/dist/drivers/download_blob/download_blob.d.ts +9 -1
  41. package/dist/drivers/download_blob/download_blob.d.ts.map +1 -1
  42. package/dist/drivers/download_blob/download_blob.js +30 -1
  43. package/dist/drivers/download_blob/download_blob.js.map +1 -1
  44. package/dist/drivers/download_blob/download_blob_task.cjs +9 -3
  45. package/dist/drivers/download_blob/download_blob_task.cjs.map +1 -1
  46. package/dist/drivers/download_blob/download_blob_task.js +6 -1
  47. package/dist/drivers/download_blob/download_blob_task.js.map +1 -1
  48. package/dist/drivers/download_blob/sparse_cache/cache.cjs +9 -1
  49. package/dist/drivers/download_blob/sparse_cache/cache.cjs.map +1 -1
  50. package/dist/drivers/download_blob/sparse_cache/cache.js +8 -0
  51. package/dist/drivers/download_blob/sparse_cache/cache.js.map +1 -1
  52. package/dist/drivers/download_blob/sparse_cache/file.cjs +2 -1
  53. package/dist/drivers/download_blob/sparse_cache/file.cjs.map +1 -1
  54. package/dist/drivers/download_blob/sparse_cache/file.js +1 -1
  55. package/dist/drivers/download_blob/sparse_cache/file.js.map +1 -1
  56. package/dist/drivers/download_blob/sparse_cache/ranges.cjs +3 -1
  57. package/dist/drivers/download_blob/sparse_cache/ranges.cjs.map +1 -1
  58. package/dist/drivers/download_blob/sparse_cache/ranges.js +1 -1
  59. package/dist/drivers/download_blob/sparse_cache/ranges.js.map +1 -1
  60. package/dist/drivers/download_blob_url/driver.cjs +6 -1
  61. package/dist/drivers/download_blob_url/driver.cjs.map +1 -1
  62. package/dist/drivers/download_blob_url/driver.d.ts.map +1 -1
  63. package/dist/drivers/download_blob_url/driver.js +5 -0
  64. package/dist/drivers/download_blob_url/driver.js.map +1 -1
  65. package/dist/drivers/download_blob_url/driver_id.cjs +0 -1
  66. package/dist/drivers/download_blob_url/driver_id.cjs.map +1 -1
  67. package/dist/drivers/download_blob_url/driver_id.js.map +1 -1
  68. package/dist/drivers/download_blob_url/snapshot.cjs +0 -1
  69. package/dist/drivers/download_blob_url/snapshot.cjs.map +1 -1
  70. package/dist/drivers/download_blob_url/snapshot.d.ts +1 -2
  71. package/dist/drivers/download_blob_url/snapshot.d.ts.map +1 -1
  72. package/dist/drivers/download_blob_url/snapshot.js.map +1 -1
  73. package/dist/drivers/download_blob_url/task.cjs +14 -6
  74. package/dist/drivers/download_blob_url/task.cjs.map +1 -1
  75. package/dist/drivers/download_blob_url/task.d.ts +1 -1
  76. package/dist/drivers/download_blob_url/task.d.ts.map +1 -1
  77. package/dist/drivers/download_blob_url/task.js +8 -1
  78. package/dist/drivers/download_blob_url/task.js.map +1 -1
  79. package/dist/drivers/download_url/driver.cjs +41 -19
  80. package/dist/drivers/download_url/driver.cjs.map +1 -1
  81. package/dist/drivers/download_url/driver.d.ts +10 -5
  82. package/dist/drivers/download_url/driver.d.ts.map +1 -1
  83. package/dist/drivers/download_url/driver.js +40 -18
  84. package/dist/drivers/download_url/driver.js.map +1 -1
  85. package/dist/drivers/download_url/task.cjs +39 -23
  86. package/dist/drivers/download_url/task.cjs.map +1 -1
  87. package/dist/drivers/download_url/task.d.ts +20 -6
  88. package/dist/drivers/download_url/task.d.ts.map +1 -1
  89. package/dist/drivers/download_url/task.js +36 -20
  90. package/dist/drivers/download_url/task.js.map +1 -1
  91. package/dist/drivers/helpers/download_local_handle.cjs.map +1 -1
  92. package/dist/drivers/helpers/download_local_handle.js.map +1 -1
  93. package/dist/drivers/helpers/download_remote_handle.cjs +0 -1
  94. package/dist/drivers/helpers/download_remote_handle.cjs.map +1 -1
  95. package/dist/drivers/helpers/download_remote_handle.js.map +1 -1
  96. package/dist/drivers/helpers/files_cache.cjs +1 -1
  97. package/dist/drivers/helpers/files_cache.cjs.map +1 -1
  98. package/dist/drivers/helpers/files_cache.js +1 -0
  99. package/dist/drivers/helpers/files_cache.js.map +1 -1
  100. package/dist/drivers/helpers/helpers.cjs +1 -0
  101. package/dist/drivers/helpers/helpers.cjs.map +1 -1
  102. package/dist/drivers/helpers/helpers.d.ts.map +1 -1
  103. package/dist/drivers/helpers/helpers.js +1 -0
  104. package/dist/drivers/helpers/helpers.js.map +1 -1
  105. package/dist/drivers/helpers/logs_handle.cjs +3 -1
  106. package/dist/drivers/helpers/logs_handle.cjs.map +1 -1
  107. package/dist/drivers/helpers/logs_handle.js +1 -1
  108. package/dist/drivers/helpers/logs_handle.js.map +1 -1
  109. package/dist/drivers/helpers/ls_remote_import_handle.cjs.map +1 -1
  110. package/dist/drivers/helpers/ls_remote_import_handle.js.map +1 -1
  111. package/dist/drivers/helpers/ls_storage_entry.cjs +2 -1
  112. package/dist/drivers/helpers/ls_storage_entry.cjs.map +1 -1
  113. package/dist/drivers/helpers/ls_storage_entry.js +1 -1
  114. package/dist/drivers/helpers/ls_storage_entry.js.map +1 -1
  115. package/dist/drivers/helpers/polling_ops.d.ts.map +1 -1
  116. package/dist/drivers/helpers/read_file.cjs +2 -2
  117. package/dist/drivers/helpers/read_file.cjs.map +1 -1
  118. package/dist/drivers/helpers/read_file.js.map +1 -1
  119. package/dist/drivers/logs.cjs +3 -1
  120. package/dist/drivers/logs.cjs.map +1 -1
  121. package/dist/drivers/logs.js +3 -0
  122. package/dist/drivers/logs.js.map +1 -1
  123. package/dist/drivers/logs_stream.cjs +8 -1
  124. package/dist/drivers/logs_stream.cjs.map +1 -1
  125. package/dist/drivers/logs_stream.d.ts.map +1 -1
  126. package/dist/drivers/logs_stream.js +8 -0
  127. package/dist/drivers/logs_stream.js.map +1 -1
  128. package/dist/drivers/ls.cjs +10 -3
  129. package/dist/drivers/ls.cjs.map +1 -1
  130. package/dist/drivers/ls.d.ts.map +1 -1
  131. package/dist/drivers/ls.js +8 -1
  132. package/dist/drivers/ls.js.map +1 -1
  133. package/dist/drivers/types.cjs +10 -1
  134. package/dist/drivers/types.cjs.map +1 -1
  135. package/dist/drivers/types.d.ts +3 -4
  136. package/dist/drivers/types.d.ts.map +1 -1
  137. package/dist/drivers/types.js +10 -0
  138. package/dist/drivers/types.js.map +1 -1
  139. package/dist/drivers/upload.cjs +5 -1
  140. package/dist/drivers/upload.cjs.map +1 -1
  141. package/dist/drivers/upload.d.ts.map +1 -1
  142. package/dist/drivers/upload.js +5 -0
  143. package/dist/drivers/upload.js.map +1 -1
  144. package/dist/drivers/upload_task.cjs +6 -1
  145. package/dist/drivers/upload_task.cjs.map +1 -1
  146. package/dist/drivers/upload_task.d.ts.map +1 -1
  147. package/dist/drivers/upload_task.js +5 -0
  148. package/dist/drivers/upload_task.js.map +1 -1
  149. package/dist/drivers/urls/url.cjs +1 -1
  150. package/dist/drivers/urls/url.cjs.map +1 -1
  151. package/dist/drivers/urls/url.js.map +1 -1
  152. package/dist/drivers/virtual_storages.cjs +3 -3
  153. package/dist/drivers/virtual_storages.cjs.map +1 -1
  154. package/dist/drivers/virtual_storages.d.ts.map +1 -1
  155. package/dist/drivers/virtual_storages.js.map +1 -1
  156. package/dist/helpers/download.cjs +1 -1
  157. package/dist/helpers/download.cjs.map +1 -1
  158. package/dist/helpers/download.d.ts.map +1 -1
  159. package/dist/helpers/download.js +1 -0
  160. package/dist/helpers/download.js.map +1 -1
  161. package/dist/helpers/download_errors.cjs.map +1 -1
  162. package/dist/helpers/download_errors.d.ts.map +1 -1
  163. package/dist/helpers/download_errors.js.map +1 -1
  164. package/dist/helpers/validate.cjs +1 -1
  165. package/dist/helpers/validate.cjs.map +1 -1
  166. package/dist/helpers/validate.d.ts.map +1 -1
  167. package/dist/helpers/validate.js.map +1 -1
  168. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.cjs +4 -2
  169. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.cjs.map +1 -1
  170. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.cjs +1 -1
  171. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.cjs.map +1 -1
  172. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts +3 -5
  173. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts.map +1 -1
  174. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.js +1 -0
  175. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.js.map +1 -1
  176. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts +1 -1
  177. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts.map +1 -1
  178. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.js +7 -3
  179. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.js.map +1 -1
  180. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.cjs +4 -2
  181. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.cjs.map +1 -1
  182. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.cjs +1 -1
  183. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.cjs.map +1 -1
  184. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.js +1 -0
  185. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.js.map +1 -1
  186. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts +1 -1
  187. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts.map +1 -1
  188. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.js +7 -3
  189. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.js.map +1 -1
  190. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.cjs +7 -3
  191. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.cjs.map +1 -1
  192. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.cjs +1 -1
  193. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.cjs.map +1 -1
  194. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts +3 -5
  195. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts.map +1 -1
  196. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.js +1 -0
  197. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.js.map +1 -1
  198. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts +1 -1
  199. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts.map +1 -1
  200. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.js +3 -3
  201. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.js.map +1 -1
  202. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.cjs +8 -5
  203. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.cjs.map +1 -1
  204. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.cjs +1 -1
  205. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.cjs.map +1 -1
  206. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts +3 -5
  207. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts.map +1 -1
  208. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.js +1 -0
  209. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.js.map +1 -1
  210. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts.map +1 -1
  211. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.js +5 -5
  212. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.js.map +1 -1
  213. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs +17 -7
  214. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs.map +1 -1
  215. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.cjs +1 -1
  216. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.cjs.map +1 -1
  217. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.js +1 -0
  218. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.js.map +1 -1
  219. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.d.ts.map +1 -1
  220. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js +7 -7
  221. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js.map +1 -1
  222. package/dist/proto-grpc/google/protobuf/duration.cjs +0 -1
  223. package/dist/proto-grpc/google/protobuf/duration.cjs.map +1 -1
  224. package/dist/proto-grpc/google/protobuf/duration.d.ts.map +1 -1
  225. package/dist/proto-grpc/google/protobuf/duration.js.map +1 -1
  226. package/dist/proto-grpc/google/protobuf/timestamp.cjs +0 -1
  227. package/dist/proto-grpc/google/protobuf/timestamp.cjs.map +1 -1
  228. package/dist/proto-grpc/google/protobuf/timestamp.d.ts.map +1 -1
  229. package/dist/proto-grpc/google/protobuf/timestamp.js.map +1 -1
  230. package/dist/proto-rest/downloadapi.d.ts +1 -1
  231. package/dist/proto-rest/downloadapi.d.ts.map +1 -1
  232. package/dist/proto-rest/index.d.ts +1 -1
  233. package/dist/proto-rest/index.d.ts.map +1 -1
  234. package/dist/proto-rest/progressapi.d.ts +1 -1
  235. package/dist/proto-rest/progressapi.d.ts.map +1 -1
  236. package/dist/proto-rest/streamingapi.d.ts +1 -1
  237. package/dist/proto-rest/streamingapi.d.ts.map +1 -1
  238. package/package.json +7 -7
  239. package/src/clients/download.ts +71 -3
  240. package/src/drivers/download_blob/download_blob.ts +30 -1
  241. package/src/drivers/download_url/driver.ts +44 -19
  242. package/src/drivers/download_url/get_local_tgz.test.ts +106 -0
  243. package/src/drivers/download_url/task.ts +53 -30
@@ -1 +1 @@
1
- {"version":3,"file":"logs.cjs","names":["StreamingClient","RestAPI"],"sources":["../../src/clients/logs.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport { StreamingClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client\";\nimport type { StreamingApiPaths, StreamingRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLogs {\n public readonly wire: WireClientProvider<StreamingRestClientType | StreamingClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new StreamingClient(wire.Transport);\n }\n\n return RestAPI.createClient<StreamingApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** Reads text back and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async lastLines(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the end.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal, signature: rIdSig } = parseSignedResourceId(rId);\n const client = this.wire.get();\n if (client instanceof StreamingClient) {\n return (\n await client.lastLines(\n {\n resourceId: rIdGlobal,\n resourceSignature: rIdSig,\n lineCount: lineCount,\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/last-lines\", {\n body: {\n resourceId: rIdGlobal.toString(),\n resourceSignature: signatureToBase64Url(rIdSig),\n lineCount: lineCount,\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n\n /** Reads the file forward and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async readText(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the beginning.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal2, signature: rIdSig2 } = parseSignedResourceId(rId);\n const client = this.wire.get();\n\n if (client instanceof StreamingClient) {\n return (\n await client.readText(\n {\n resourceId: notEmpty(rIdGlobal2),\n resourceSignature: rIdSig2,\n readLimit: BigInt(lineCount),\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/read/text\", {\n body: {\n resourceId: rIdGlobal2.toString(),\n resourceSignature: signatureToBase64Url(rIdSig2),\n readLimit: lineCount.toString(),\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n}\n"],"mappings":";;;;;AAiBA,IAAa,aAAb,MAAwB;CACtB;CAEA,YACE,2BACA,YACA,QACA;AAFgB,OAAA,aAAA;AACA,OAAA,SAAA;AAEhB,OAAK,OAAO,0BAA0B,0BAA0B,SAAS;AACvE,OAAI,KAAK,SAAS,OAChB,QAAO,IAAIA,wBAAAA,gBAAgB,KAAK,UAAU;AAG5C,UAAOC,0BAAAA,QAAQ,aAAgC;IAC7C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;IACnB,CAAC;IACF;;CAGJ,QAAQ;;;;CAKR,MAAa,UACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,WAAW,WAAW,YAAA,GAAA,0BAAA,uBAAiC,IAAI;EAC7E,MAAM,SAAS,KAAK,KAAK,KAAK;AAC9B,MAAI,kBAAkBD,wBAAAA,gBACpB,SACE,MAAM,OAAO,UACX;GACE,YAAY;GACZ,mBAAmB;GACR;GACX,QAAQ;GACR,QAAQ;GACT,GAAA,GAAA,0BAAA,oBACkB,OAAO,QAAQ,CACnC,EACD;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,kBAAkB;GAClC,MAAM;IACJ,YAAY,UAAU,UAAU;IAChC,oBAAA,GAAA,0BAAA,sBAAwC,OAAO;IACpC;IACX,QAAQ,YAAY,UAAU;IAC9B,QAAQ,aAAa;IACrB,UAAU;IACX;GACD,SAAS,EAAE,IAAA,GAAA,0BAAA,0BAA4B,MAAM,EAAE;GAChD,CAAC,EACF;AAEF,SAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS;GACtC,MAAM,OAAO,KAAK,KAAK;GACvB,WAAW,OAAO,KAAK,UAAU;GAClC;;;;;CAMH,MAAa,SACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,YAAY,WAAW,aAAA,GAAA,0BAAA,uBAAkC,IAAI;EAC/E,MAAM,SAAS,KAAK,KAAK,KAAK;AAE9B,MAAI,kBAAkBA,wBAAAA,gBACpB,SACE,MAAM,OAAO,SACX;GACE,aAAA,GAAA,2BAAA,UAAqB,WAAW;GAChC,mBAAmB;GACnB,WAAW,OAAO,UAAU;GAC5B,QAAQ;GACR,QAAQ;GACT,GAAA,GAAA,0BAAA,oBACkB,OAAO,QAAQ,CACnC,EACD;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,iBAAiB;GACjC,MAAM;IACJ,YAAY,WAAW,UAAU;IACjC,oBAAA,GAAA,0BAAA,sBAAwC,QAAQ;IAChD,WAAW,UAAU,UAAU;IAC/B,QAAQ,YAAY,UAAU;IAC9B,QAAQ,aAAa;IACrB,UAAU;IACX;GACD,SAAS,EAAE,IAAA,GAAA,0BAAA,0BAA4B,MAAM,EAAE;GAChD,CAAC,EACF;AAEF,SAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS;GACtC,MAAM,OAAO,KAAK,KAAK;GACvB,WAAW,OAAO,KAAK,UAAU;GAClC"}
1
+ {"version":3,"file":"logs.cjs","names":["StreamingClient","RestAPI"],"sources":["../../src/clients/logs.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport { StreamingClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client\";\nimport type { StreamingApiPaths, StreamingRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLogs {\n public readonly wire: WireClientProvider<StreamingRestClientType | StreamingClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new StreamingClient(wire.Transport);\n }\n\n return RestAPI.createClient<StreamingApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** Reads text back and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async lastLines(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the end.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal, signature: rIdSig } = parseSignedResourceId(rId);\n const client = this.wire.get();\n if (client instanceof StreamingClient) {\n return (\n await client.lastLines(\n {\n resourceId: rIdGlobal,\n resourceSignature: rIdSig,\n lineCount: lineCount,\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/last-lines\", {\n body: {\n resourceId: rIdGlobal.toString(),\n resourceSignature: signatureToBase64Url(rIdSig),\n lineCount: lineCount,\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n\n /** Reads the file forward and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async readText(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the beginning.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal2, signature: rIdSig2 } = parseSignedResourceId(rId);\n const client = this.wire.get();\n\n if (client instanceof StreamingClient) {\n return (\n await client.readText(\n {\n resourceId: notEmpty(rIdGlobal2),\n resourceSignature: rIdSig2,\n readLimit: BigInt(lineCount),\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/read/text\", {\n body: {\n resourceId: rIdGlobal2.toString(),\n resourceSignature: signatureToBase64Url(rIdSig2),\n readLimit: lineCount.toString(),\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n}\n"],"mappings":";;;;AAiBA,IAAa,aAAb,MAAwB;CAKJ;CACA;CALlB;CAEA,YACE,2BACA,YACA,QACA;EAFgB,KAAA,aAAA;EACA,KAAA,SAAA;EAEhB,KAAK,OAAO,0BAA0B,0BAA0B,SAAS;GACvE,IAAI,KAAK,SAAS,QAChB,OAAO,IAAIA,wBAAAA,gBAAgB,KAAK,SAAS;GAG3C,OAAOC,0BAAAA,QAAQ,aAAgC;IAC7C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;GACpB,CAAC;EACH,CAAC;CACH;CAEA,QAAQ,CAAC;;;;CAKT,MAAa,UACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,WAAW,WAAW,YAAA,GAAA,0BAAA,sBAAA,CAAiC,GAAG;EAC5E,MAAM,SAAS,KAAK,KAAK,IAAI;EAC7B,IAAI,kBAAkBD,wBAAAA,iBACpB,QACE,MAAM,OAAO,UACX;GACE,YAAY;GACZ,mBAAmB;GACR;GACX,QAAQ;GACR,QAAQ;EACV,IAAA,GAAA,0BAAA,mBAAA,CACmB,OAAO,OAAO,CACnC,EAAA,CACA;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,kBAAkB;GAClC,MAAM;IACJ,YAAY,UAAU,SAAS;IAC/B,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,MAAM;IACnC;IACX,QAAQ,YAAY,SAAS;IAC7B,QAAQ,aAAa;IACrB,UAAU;GACZ;GACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,KAAK,EAAE;EAChD,CAAC,EAAA,CACD;EAEF,OAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,QAAQ;GACrC,MAAM,OAAO,KAAK,IAAI;GACtB,WAAW,OAAO,KAAK,SAAS;EAClC;CACF;;;;CAKA,MAAa,SACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,YAAY,WAAW,aAAA,GAAA,0BAAA,sBAAA,CAAkC,GAAG;EAC9E,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,IAAI,kBAAkBA,wBAAAA,iBACpB,QACE,MAAM,OAAO,SACX;GACE,aAAA,GAAA,2BAAA,SAAA,CAAqB,UAAU;GAC/B,mBAAmB;GACnB,WAAW,OAAO,SAAS;GAC3B,QAAQ;GACR,QAAQ;EACV,IAAA,GAAA,0BAAA,mBAAA,CACmB,OAAO,OAAO,CACnC,EAAA,CACA;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,iBAAiB;GACjC,MAAM;IACJ,YAAY,WAAW,SAAS;IAChC,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,OAAO;IAC/C,WAAW,UAAU,SAAS;IAC9B,QAAQ,YAAY,SAAS;IAC7B,QAAQ,aAAa;IACrB,UAAU;GACZ;GACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,KAAK,EAAE;EAChD,CAAC,EAAA,CACD;EAEF,OAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,QAAQ;GACrC,MAAM,OAAO,KAAK,IAAI;GACtB,WAAW,OAAO,KAAK,SAAS;EAClC;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"logs.d.ts","names":[],"sources":["../../src/clients/logs.ts"],"mappings":";;;;;;;;;;cAiBa,UAAA;EAAA,SAKO,UAAA,EAAY,UAAA;EAAA,SACZ,MAAA,EAAQ,QAAA;EAAA,SALV,IAAA,EAAM,kBAAA,CAAmB,uBAAA,GAA0B,eAAA;cAGjE,yBAAA,EAA2B,yBAAA,EACX,UAAA,EAAY,UAAA,EACZ,MAAA,EAAQ,QAAA;EAgB1B,KAAA,CAAA;EAhB0B;;;EAqBb,SAAA,CAAA;IACT,EAAA,EAAI,GAAA;IAAK,IAAA,EAAM;EAAA,GAAS,YAAA,EAC1B,SAAA,UACA,WAAA;EACA,SAAA,WACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,qBAAA;EA5BmB;;;EAsEjB,QAAA,CAAA;IACT,EAAA,EAAI,GAAA;IAAK,IAAA,EAAM;EAAA,GAAS,YAAA,EAC1B,SAAA,UACA,WAAA;EACA,SAAA,WACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,qBAAA;AAAA"}
1
+ {"version":3,"file":"logs.d.ts","names":[],"sources":["../../src/clients/logs.ts"],"mappings":";;;;;;;;;;cAiBa,UAAA;EAAA,SAKO,UAAA,EAAY,UAAA;EAAA,SACZ,MAAA,EAAQ,QAAA;EAAA,SALV,IAAA,EAAM,kBAAA,CAAmB,uBAAA,GAA0B,eAAA;cAGjE,yBAAA,EAA2B,yBAAA,EACX,UAAA,EAAY,UAAA,EACZ,MAAA,EAAQ,QAAA;EAgB1B,KAAA;EAhB0B;;;EAqBb,SAAA;IACT,EAAA,EAAI,GAAA;IAAK,IAAA,EAAM;EAAA,GAAS,YAAA,EAC1B,SAAA,UACA,WAAA;EACA,SAAA,WACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,qBAAA;EA5BmB;;;EAsEjB,QAAA;IACT,EAAA,EAAI,GAAA;IAAK,IAAA,EAAM;EAAA,GAAS,YAAA,EAC1B,SAAA,UACA,WAAA;EACA,SAAA,WACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,qBAAA;AAAA"}
@@ -3,6 +3,8 @@ import { RestAPI, addRTypeToMetadata, createRTypeRoutingHeader, parseSignedResou
3
3
  import { notEmpty } from "@milaboratories/ts-helpers";
4
4
  //#region src/clients/logs.ts
5
5
  var ClientLogs = class {
6
+ httpClient;
7
+ logger;
6
8
  wire;
7
9
  constructor(wireClientProviderFactory, httpClient, logger) {
8
10
  this.httpClient = httpClient;
@@ -1 +1 @@
1
- {"version":3,"file":"logs.js","names":[],"sources":["../../src/clients/logs.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport { StreamingClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client\";\nimport type { StreamingApiPaths, StreamingRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLogs {\n public readonly wire: WireClientProvider<StreamingRestClientType | StreamingClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new StreamingClient(wire.Transport);\n }\n\n return RestAPI.createClient<StreamingApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** Reads text back and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async lastLines(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the end.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal, signature: rIdSig } = parseSignedResourceId(rId);\n const client = this.wire.get();\n if (client instanceof StreamingClient) {\n return (\n await client.lastLines(\n {\n resourceId: rIdGlobal,\n resourceSignature: rIdSig,\n lineCount: lineCount,\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/last-lines\", {\n body: {\n resourceId: rIdGlobal.toString(),\n resourceSignature: signatureToBase64Url(rIdSig),\n lineCount: lineCount,\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n\n /** Reads the file forward and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async readText(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the beginning.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal2, signature: rIdSig2 } = parseSignedResourceId(rId);\n const client = this.wire.get();\n\n if (client instanceof StreamingClient) {\n return (\n await client.readText(\n {\n resourceId: notEmpty(rIdGlobal2),\n resourceSignature: rIdSig2,\n readLimit: BigInt(lineCount),\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/read/text\", {\n body: {\n resourceId: rIdGlobal2.toString(),\n resourceSignature: signatureToBase64Url(rIdSig2),\n readLimit: lineCount.toString(),\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n}\n"],"mappings":";;;;AAiBA,IAAa,aAAb,MAAwB;CACtB;CAEA,YACE,2BACA,YACA,QACA;AAFgB,OAAA,aAAA;AACA,OAAA,SAAA;AAEhB,OAAK,OAAO,0BAA0B,0BAA0B,SAAS;AACvE,OAAI,KAAK,SAAS,OAChB,QAAO,IAAI,gBAAgB,KAAK,UAAU;AAG5C,UAAO,QAAQ,aAAgC;IAC7C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;IACnB,CAAC;IACF;;CAGJ,QAAQ;;;;CAKR,MAAa,UACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,WAAW,WAAW,WAAW,sBAAsB,IAAI;EAC7E,MAAM,SAAS,KAAK,KAAK,KAAK;AAC9B,MAAI,kBAAkB,gBACpB,SACE,MAAM,OAAO,UACX;GACE,YAAY;GACZ,mBAAmB;GACR;GACX,QAAQ;GACR,QAAQ;GACT,EACD,mBAAmB,OAAO,QAAQ,CACnC,EACD;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,kBAAkB;GAClC,MAAM;IACJ,YAAY,UAAU,UAAU;IAChC,mBAAmB,qBAAqB,OAAO;IACpC;IACX,QAAQ,YAAY,UAAU;IAC9B,QAAQ,aAAa;IACrB,UAAU;IACX;GACD,SAAS,EAAE,GAAG,yBAAyB,MAAM,EAAE;GAChD,CAAC,EACF;AAEF,SAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS;GACtC,MAAM,OAAO,KAAK,KAAK;GACvB,WAAW,OAAO,KAAK,UAAU;GAClC;;;;;CAMH,MAAa,SACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,YAAY,WAAW,YAAY,sBAAsB,IAAI;EAC/E,MAAM,SAAS,KAAK,KAAK,KAAK;AAE9B,MAAI,kBAAkB,gBACpB,SACE,MAAM,OAAO,SACX;GACE,YAAY,SAAS,WAAW;GAChC,mBAAmB;GACnB,WAAW,OAAO,UAAU;GAC5B,QAAQ;GACR,QAAQ;GACT,EACD,mBAAmB,OAAO,QAAQ,CACnC,EACD;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,iBAAiB;GACjC,MAAM;IACJ,YAAY,WAAW,UAAU;IACjC,mBAAmB,qBAAqB,QAAQ;IAChD,WAAW,UAAU,UAAU;IAC/B,QAAQ,YAAY,UAAU;IAC9B,QAAQ,aAAa;IACrB,UAAU;IACX;GACD,SAAS,EAAE,GAAG,yBAAyB,MAAM,EAAE;GAChD,CAAC,EACF;AAEF,SAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS;GACtC,MAAM,OAAO,KAAK,KAAK;GACvB,WAAW,OAAO,KAAK,UAAU;GAClC"}
1
+ {"version":3,"file":"logs.js","names":[],"sources":["../../src/clients/logs.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport { StreamingClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client\";\nimport type { StreamingApiPaths, StreamingRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLogs {\n public readonly wire: WireClientProvider<StreamingRestClientType | StreamingClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new StreamingClient(wire.Transport);\n }\n\n return RestAPI.createClient<StreamingApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** Reads text back and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async lastLines(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the end.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal, signature: rIdSig } = parseSignedResourceId(rId);\n const client = this.wire.get();\n if (client instanceof StreamingClient) {\n return (\n await client.lastLines(\n {\n resourceId: rIdGlobal,\n resourceSignature: rIdSig,\n lineCount: lineCount,\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/last-lines\", {\n body: {\n resourceId: rIdGlobal.toString(),\n resourceSignature: signatureToBase64Url(rIdSig),\n lineCount: lineCount,\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n\n /** Reads the file forward and returns the text,\n * the new offset\n * and the total size of the (currently existing) file. */\n public async readText(\n { id: rId, type: rType }: ResourceInfo,\n lineCount: number,\n offsetBytes: bigint = 0n, // if 0n, then start from the beginning.\n searchStr?: string,\n options?: RpcOptions,\n ): Promise<StreamingAPI_Response> {\n const { globalId: rIdGlobal2, signature: rIdSig2 } = parseSignedResourceId(rId);\n const client = this.wire.get();\n\n if (client instanceof StreamingClient) {\n return (\n await client.readText(\n {\n resourceId: notEmpty(rIdGlobal2),\n resourceSignature: rIdSig2,\n readLimit: BigInt(lineCount),\n offset: offsetBytes,\n search: searchStr,\n },\n addRTypeToMetadata(rType, options),\n )\n ).response;\n }\n\n const resp = (\n await client.POST(\"/v1/read/text\", {\n body: {\n resourceId: rIdGlobal2.toString(),\n resourceSignature: signatureToBase64Url(rIdSig2),\n readLimit: lineCount.toString(),\n offset: offsetBytes.toString(),\n search: searchStr ?? \"\",\n searchRe: \"\",\n },\n headers: { ...createRTypeRoutingHeader(rType) },\n })\n ).data!;\n\n return {\n data: Buffer.from(resp.data, \"base64\"),\n size: BigInt(resp.size),\n newOffset: BigInt(resp.newOffset),\n };\n }\n}\n"],"mappings":";;;;AAiBA,IAAa,aAAb,MAAwB;CAKJ;CACA;CALlB;CAEA,YACE,2BACA,YACA,QACA;EAFgB,KAAA,aAAA;EACA,KAAA,SAAA;EAEhB,KAAK,OAAO,0BAA0B,0BAA0B,SAAS;GACvE,IAAI,KAAK,SAAS,QAChB,OAAO,IAAI,gBAAgB,KAAK,SAAS;GAG3C,OAAO,QAAQ,aAAgC;IAC7C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;GACpB,CAAC;EACH,CAAC;CACH;CAEA,QAAQ,CAAC;;;;CAKT,MAAa,UACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,WAAW,WAAW,WAAW,sBAAsB,GAAG;EAC5E,MAAM,SAAS,KAAK,KAAK,IAAI;EAC7B,IAAI,kBAAkB,iBACpB,QACE,MAAM,OAAO,UACX;GACE,YAAY;GACZ,mBAAmB;GACR;GACX,QAAQ;GACR,QAAQ;EACV,GACA,mBAAmB,OAAO,OAAO,CACnC,EAAA,CACA;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,kBAAkB;GAClC,MAAM;IACJ,YAAY,UAAU,SAAS;IAC/B,mBAAmB,qBAAqB,MAAM;IACnC;IACX,QAAQ,YAAY,SAAS;IAC7B,QAAQ,aAAa;IACrB,UAAU;GACZ;GACA,SAAS,EAAE,GAAG,yBAAyB,KAAK,EAAE;EAChD,CAAC,EAAA,CACD;EAEF,OAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,QAAQ;GACrC,MAAM,OAAO,KAAK,IAAI;GACtB,WAAW,OAAO,KAAK,SAAS;EAClC;CACF;;;;CAKA,MAAa,SACX,EAAE,IAAI,KAAK,MAAM,SACjB,WACA,cAAsB,IACtB,WACA,SACgC;EAChC,MAAM,EAAE,UAAU,YAAY,WAAW,YAAY,sBAAsB,GAAG;EAC9E,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,IAAI,kBAAkB,iBACpB,QACE,MAAM,OAAO,SACX;GACE,YAAY,SAAS,UAAU;GAC/B,mBAAmB;GACnB,WAAW,OAAO,SAAS;GAC3B,QAAQ;GACR,QAAQ;EACV,GACA,mBAAmB,OAAO,OAAO,CACnC,EAAA,CACA;EAGJ,MAAM,QACJ,MAAM,OAAO,KAAK,iBAAiB;GACjC,MAAM;IACJ,YAAY,WAAW,SAAS;IAChC,mBAAmB,qBAAqB,OAAO;IAC/C,WAAW,UAAU,SAAS;IAC9B,QAAQ,YAAY,SAAS;IAC7B,QAAQ,aAAa;IACrB,UAAU;GACZ;GACA,SAAS,EAAE,GAAG,yBAAyB,KAAK,EAAE;EAChD,CAAC,EAAA,CACD;EAEF,OAAO;GACL,MAAM,OAAO,KAAK,KAAK,MAAM,QAAQ;GACrC,MAAM,OAAO,KAAK,IAAI;GACtB,WAAW,OAAO,KAAK,SAAS;EAClC;CACF;AACF"}
@@ -1,8 +1,8 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
1
  const require_protocol_client = require("../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.cjs");
3
2
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
4
3
  //#region src/clients/ls_api.ts
5
4
  var ClientLs = class {
5
+ logger;
6
6
  wire;
7
7
  constructor(wireClientProviderFactory, logger) {
8
8
  this.logger = logger;
@@ -1 +1 @@
1
- {"version":3,"file":"ls_api.cjs","names":["LSClient","RestAPI"],"sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport { RestAPI, parseSignedResourceId, signatureToBase64Url } from \"@milaboratories/pl-client\";\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from \"@milaboratories/pl-client\";\nimport type {\n LsAPI_List_Response,\n LsAPI_ListItem,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol\";\nimport { LSClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client\";\nimport type { LsApiPaths, LsRestClientType } from \"../proto-rest\";\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(rInfo.id);\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: globalId,\n resourceSignature: signature,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/list\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })\n ).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n additionalInfo: item.additionalInfo ?? {},\n fullName: item.fullName,\n directory: item.directory,\n lastModified: parseTimestamp(item.lastModified),\n version: item.version,\n }));\n\n return {\n items,\n delimiter: resp.delimiter,\n };\n }\n }\n}\n\nfunction parseTimestamp(timestamp: string): { seconds: bigint; nanos: number } {\n // Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z\n const date = new Date(timestamp);\n const seconds = BigInt(Math.floor(date.getTime() / 1000));\n\n // Extract fractional seconds from the original string\n const fractionalMatch = timestamp.match(/\\.(\\d+)Z?$/);\n let nanos = 0;\n if (fractionalMatch) {\n const fractionalPart = fractionalMatch[1];\n // Pad or truncate to 9 digits (nanoseconds)\n const padded = fractionalPart.padEnd(9, \"0\").slice(0, 9);\n nanos = parseInt(padded, 10);\n }\n\n return { seconds, nanos };\n}\n"],"mappings":";;;;AAcA,IAAa,WAAb,MAAsB;CACpB;CAEA,YACE,2BACA,QACA;AADiB,OAAA,SAAA;AAEjB,OAAK,OAAO,0BAA0B,0BAA0B,SAAS;AACvE,OAAI,KAAK,SAAS,OAChB,QAAO,IAAIA,wBAAAA,SAAS,KAAK,UAAU;AAGrC,UAAOC,0BAAAA,QAAQ,aAAyB;IACtC,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;IACnB,CAAC;IACF;;CAGJ,QAAQ;CAER,MAAa,KACX,OACA,MACA,SAC8B;EAC9B,MAAM,SAAS,KAAK,KAAK,KAAK;EAE9B,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,uBAAoC,MAAM,GAAG;AAC/D,MAAI,kBAAkBD,wBAAAA,SACpB,QAAO,MAAM,OAAO,KAClB;GACE,YAAY;GACZ,mBAAmB;GACnB,UAAU;GACX,GAAA,GAAA,0BAAA,oBACkB,MAAM,MAAM,QAAQ,CACxC,CAAC;OACG;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,YAAY;IAC5B,MAAM;KACJ,YAAY,SAAS,UAAU;KAC/B,oBAAA,GAAA,0BAAA,sBAAwC,UAAU;KAClD,UAAU;KACX;IACD,SAAS,EAAE,IAAA,GAAA,0BAAA,0BAA4B,MAAM,KAAK,EAAE;IACrD,CAAC,EACF;AAaF,UAAO;IACL,OAZ8B,KAAK,MAAM,KAAK,UAAU;KACxD,MAAM,KAAK;KACX,MAAM,OAAO,KAAK,KAAK;KACvB,OAAO,KAAK;KACZ,gBAAgB,KAAK,kBAAkB,EAAE;KACzC,UAAU,KAAK;KACf,WAAW,KAAK;KAChB,cAAc,eAAe,KAAK,aAAa;KAC/C,SAAS,KAAK;KACf,EAAE;IAID,WAAW,KAAK;IACjB;;;;AAKP,SAAS,eAAe,WAAuD;CAE7E,MAAM,OAAO,IAAI,KAAK,UAAU;CAChC,MAAM,UAAU,OAAO,KAAK,MAAM,KAAK,SAAS,GAAG,IAAK,CAAC;CAGzD,MAAM,kBAAkB,UAAU,MAAM,aAAa;CACrD,IAAI,QAAQ;AACZ,KAAI,iBAAiB;EAGnB,MAAM,SAFiB,gBAAgB,GAET,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE;AACxD,UAAQ,SAAS,QAAQ,GAAG;;AAG9B,QAAO;EAAE;EAAS;EAAO"}
1
+ {"version":3,"file":"ls_api.cjs","names":["LSClient","RestAPI"],"sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport { RestAPI, parseSignedResourceId, signatureToBase64Url } from \"@milaboratories/pl-client\";\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from \"@milaboratories/pl-client\";\nimport type {\n LsAPI_List_Response,\n LsAPI_ListItem,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol\";\nimport { LSClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client\";\nimport type { LsApiPaths, LsRestClientType } from \"../proto-rest\";\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(rInfo.id);\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: globalId,\n resourceSignature: signature,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/list\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })\n ).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n additionalInfo: item.additionalInfo ?? {},\n fullName: item.fullName,\n directory: item.directory,\n lastModified: parseTimestamp(item.lastModified),\n version: item.version,\n }));\n\n return {\n items,\n delimiter: resp.delimiter,\n };\n }\n }\n}\n\nfunction parseTimestamp(timestamp: string): { seconds: bigint; nanos: number } {\n // Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z\n const date = new Date(timestamp);\n const seconds = BigInt(Math.floor(date.getTime() / 1000));\n\n // Extract fractional seconds from the original string\n const fractionalMatch = timestamp.match(/\\.(\\d+)Z?$/);\n let nanos = 0;\n if (fractionalMatch) {\n const fractionalPart = fractionalMatch[1];\n // Pad or truncate to 9 digits (nanoseconds)\n const padded = fractionalPart.padEnd(9, \"0\").slice(0, 9);\n nanos = parseInt(padded, 10);\n }\n\n return { seconds, nanos };\n}\n"],"mappings":";;;AAcA,IAAa,WAAb,MAAsB;CAKD;CAJnB;CAEA,YACE,2BACA,QACA;EADiB,KAAA,SAAA;EAEjB,KAAK,OAAO,0BAA0B,0BAA0B,SAAS;GACvE,IAAI,KAAK,SAAS,QAChB,OAAO,IAAIA,wBAAAA,SAAS,KAAK,SAAS;GAGpC,OAAOC,0BAAAA,QAAQ,aAAyB;IACtC,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;GACpB,CAAC;EACH,CAAC;CACH;CAEA,QAAQ,CAAC;CAET,MAAa,KACX,OACA,MACA,SAC8B;EAC9B,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,sBAAA,CAAoC,MAAM,EAAE;EAC9D,IAAI,kBAAkBD,wBAAAA,UACpB,OAAO,MAAM,OAAO,KAClB;GACE,YAAY;GACZ,mBAAmB;GACnB,UAAU;EACZ,IAAA,GAAA,0BAAA,mBAAA,CACmB,MAAM,MAAM,OAAO,CACxC,CAAC,CAAC;OACG;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,YAAY;IAC5B,MAAM;KACJ,YAAY,SAAS,SAAS;KAC9B,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,SAAS;KACjD,UAAU;IACZ;IACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,MAAM,IAAI,EAAE;GACrD,CAAC,EAAA,CACD;GAaF,OAAO;IACL,OAZ8B,KAAK,MAAM,KAAK,UAAU;KACxD,MAAM,KAAK;KACX,MAAM,OAAO,KAAK,IAAI;KACtB,OAAO,KAAK;KACZ,gBAAgB,KAAK,kBAAkB,CAAC;KACxC,UAAU,KAAK;KACf,WAAW,KAAK;KAChB,cAAc,eAAe,KAAK,YAAY;KAC9C,SAAS,KAAK;IAChB,EAGM;IACJ,WAAW,KAAK;GAClB;EACF;CACF;AACF;AAEA,SAAS,eAAe,WAAuD;CAE7E,MAAM,OAAO,IAAI,KAAK,SAAS;CAC/B,MAAM,UAAU,OAAO,KAAK,MAAM,KAAK,QAAQ,IAAI,GAAI,CAAC;CAGxD,MAAM,kBAAkB,UAAU,MAAM,YAAY;CACpD,IAAI,QAAQ;CACZ,IAAI,iBAAiB;EAGnB,MAAM,SAFiB,gBAAgB,EAEV,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;EACvD,QAAQ,SAAS,QAAQ,EAAE;CAC7B;CAEA,OAAO;EAAE;EAAS;CAAM;AAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ls_api.d.ts","names":[],"sources":["../../src/clients/ls_api.ts"],"mappings":";;;;;;;cAca,QAAA;EAAA,iBAKQ,MAAA;EAAA,iBAJF,IAAA;cAGf,yBAAA,EAA2B,yBAAA,EACV,MAAA,EAAQ,QAAA;EAgB3B,KAAA,CAAA;EAEa,IAAA,CACX,KAAA,EAAO,YAAA,EACP,IAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,mBAAA;AAAA"}
1
+ {"version":3,"file":"ls_api.d.ts","names":[],"sources":["../../src/clients/ls_api.ts"],"mappings":";;;;;;;cAca,QAAA;EAAA,iBAKQ,MAAA;EAAA,iBAJF,IAAA;cAGf,yBAAA,EAA2B,yBAAA,EACV,MAAA,EAAQ,QAAA;EAgB3B,KAAA;EAEa,IAAA,CACX,KAAA,EAAO,YAAA,EACP,IAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,mBAAA;AAAA"}
@@ -2,6 +2,7 @@ import { LSClient } from "../proto-grpc/github.com/milaboratory/pl/controllers/s
2
2
  import { RestAPI, addRTypeToMetadata, createRTypeRoutingHeader, parseSignedResourceId, signatureToBase64Url } from "@milaboratories/pl-client";
3
3
  //#region src/clients/ls_api.ts
4
4
  var ClientLs = class {
5
+ logger;
5
6
  wire;
6
7
  constructor(wireClientProviderFactory, logger) {
7
8
  this.logger = logger;
@@ -1 +1 @@
1
- {"version":3,"file":"ls_api.js","names":[],"sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport { RestAPI, parseSignedResourceId, signatureToBase64Url } from \"@milaboratories/pl-client\";\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from \"@milaboratories/pl-client\";\nimport type {\n LsAPI_List_Response,\n LsAPI_ListItem,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol\";\nimport { LSClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client\";\nimport type { LsApiPaths, LsRestClientType } from \"../proto-rest\";\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(rInfo.id);\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: globalId,\n resourceSignature: signature,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/list\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })\n ).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n additionalInfo: item.additionalInfo ?? {},\n fullName: item.fullName,\n directory: item.directory,\n lastModified: parseTimestamp(item.lastModified),\n version: item.version,\n }));\n\n return {\n items,\n delimiter: resp.delimiter,\n };\n }\n }\n}\n\nfunction parseTimestamp(timestamp: string): { seconds: bigint; nanos: number } {\n // Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z\n const date = new Date(timestamp);\n const seconds = BigInt(Math.floor(date.getTime() / 1000));\n\n // Extract fractional seconds from the original string\n const fractionalMatch = timestamp.match(/\\.(\\d+)Z?$/);\n let nanos = 0;\n if (fractionalMatch) {\n const fractionalPart = fractionalMatch[1];\n // Pad or truncate to 9 digits (nanoseconds)\n const padded = fractionalPart.padEnd(9, \"0\").slice(0, 9);\n nanos = parseInt(padded, 10);\n }\n\n return { seconds, nanos };\n}\n"],"mappings":";;;AAcA,IAAa,WAAb,MAAsB;CACpB;CAEA,YACE,2BACA,QACA;AADiB,OAAA,SAAA;AAEjB,OAAK,OAAO,0BAA0B,0BAA0B,SAAS;AACvE,OAAI,KAAK,SAAS,OAChB,QAAO,IAAI,SAAS,KAAK,UAAU;AAGrC,UAAO,QAAQ,aAAyB;IACtC,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;IACnB,CAAC;IACF;;CAGJ,QAAQ;CAER,MAAa,KACX,OACA,MACA,SAC8B;EAC9B,MAAM,SAAS,KAAK,KAAK,KAAK;EAE9B,MAAM,EAAE,UAAU,cAAc,sBAAsB,MAAM,GAAG;AAC/D,MAAI,kBAAkB,SACpB,QAAO,MAAM,OAAO,KAClB;GACE,YAAY;GACZ,mBAAmB;GACnB,UAAU;GACX,EACD,mBAAmB,MAAM,MAAM,QAAQ,CACxC,CAAC;OACG;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,YAAY;IAC5B,MAAM;KACJ,YAAY,SAAS,UAAU;KAC/B,mBAAmB,qBAAqB,UAAU;KAClD,UAAU;KACX;IACD,SAAS,EAAE,GAAG,yBAAyB,MAAM,KAAK,EAAE;IACrD,CAAC,EACF;AAaF,UAAO;IACL,OAZ8B,KAAK,MAAM,KAAK,UAAU;KACxD,MAAM,KAAK;KACX,MAAM,OAAO,KAAK,KAAK;KACvB,OAAO,KAAK;KACZ,gBAAgB,KAAK,kBAAkB,EAAE;KACzC,UAAU,KAAK;KACf,WAAW,KAAK;KAChB,cAAc,eAAe,KAAK,aAAa;KAC/C,SAAS,KAAK;KACf,EAAE;IAID,WAAW,KAAK;IACjB;;;;AAKP,SAAS,eAAe,WAAuD;CAE7E,MAAM,OAAO,IAAI,KAAK,UAAU;CAChC,MAAM,UAAU,OAAO,KAAK,MAAM,KAAK,SAAS,GAAG,IAAK,CAAC;CAGzD,MAAM,kBAAkB,UAAU,MAAM,aAAa;CACrD,IAAI,QAAQ;AACZ,KAAI,iBAAiB;EAGnB,MAAM,SAFiB,gBAAgB,GAET,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE;AACxD,UAAQ,SAAS,QAAQ,GAAG;;AAG9B,QAAO;EAAE;EAAS;EAAO"}
1
+ {"version":3,"file":"ls_api.js","names":[],"sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport { RestAPI, parseSignedResourceId, signatureToBase64Url } from \"@milaboratories/pl-client\";\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from \"@milaboratories/pl-client\";\nimport type {\n LsAPI_List_Response,\n LsAPI_ListItem,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol\";\nimport { LSClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client\";\nimport type { LsApiPaths, LsRestClientType } from \"../proto-rest\";\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(rInfo.id);\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: globalId,\n resourceSignature: signature,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/list\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })\n ).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n additionalInfo: item.additionalInfo ?? {},\n fullName: item.fullName,\n directory: item.directory,\n lastModified: parseTimestamp(item.lastModified),\n version: item.version,\n }));\n\n return {\n items,\n delimiter: resp.delimiter,\n };\n }\n }\n}\n\nfunction parseTimestamp(timestamp: string): { seconds: bigint; nanos: number } {\n // Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z\n const date = new Date(timestamp);\n const seconds = BigInt(Math.floor(date.getTime() / 1000));\n\n // Extract fractional seconds from the original string\n const fractionalMatch = timestamp.match(/\\.(\\d+)Z?$/);\n let nanos = 0;\n if (fractionalMatch) {\n const fractionalPart = fractionalMatch[1];\n // Pad or truncate to 9 digits (nanoseconds)\n const padded = fractionalPart.padEnd(9, \"0\").slice(0, 9);\n nanos = parseInt(padded, 10);\n }\n\n return { seconds, nanos };\n}\n"],"mappings":";;;AAcA,IAAa,WAAb,MAAsB;CAKD;CAJnB;CAEA,YACE,2BACA,QACA;EADiB,KAAA,SAAA;EAEjB,KAAK,OAAO,0BAA0B,0BAA0B,SAAS;GACvE,IAAI,KAAK,SAAS,QAChB,OAAO,IAAI,SAAS,KAAK,SAAS;GAGpC,OAAO,QAAQ,aAAyB;IACtC,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;GACpB,CAAC;EACH,CAAC;CACH;CAEA,QAAQ,CAAC;CAET,MAAa,KACX,OACA,MACA,SAC8B;EAC9B,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,MAAM,EAAE,UAAU,cAAc,sBAAsB,MAAM,EAAE;EAC9D,IAAI,kBAAkB,UACpB,OAAO,MAAM,OAAO,KAClB;GACE,YAAY;GACZ,mBAAmB;GACnB,UAAU;EACZ,GACA,mBAAmB,MAAM,MAAM,OAAO,CACxC,CAAC,CAAC;OACG;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,YAAY;IAC5B,MAAM;KACJ,YAAY,SAAS,SAAS;KAC9B,mBAAmB,qBAAqB,SAAS;KACjD,UAAU;IACZ;IACA,SAAS,EAAE,GAAG,yBAAyB,MAAM,IAAI,EAAE;GACrD,CAAC,EAAA,CACD;GAaF,OAAO;IACL,OAZ8B,KAAK,MAAM,KAAK,UAAU;KACxD,MAAM,KAAK;KACX,MAAM,OAAO,KAAK,IAAI;KACtB,OAAO,KAAK;KACZ,gBAAgB,KAAK,kBAAkB,CAAC;KACxC,UAAU,KAAK;KACf,WAAW,KAAK;KAChB,cAAc,eAAe,KAAK,YAAY;KAC9C,SAAS,KAAK;IAChB,EAGM;IACJ,WAAW,KAAK;GAClB;EACF;CACF;AACF;AAEA,SAAS,eAAe,WAAuD;CAE7E,MAAM,OAAO,IAAI,KAAK,SAAS;CAC/B,MAAM,UAAU,OAAO,KAAK,MAAM,KAAK,QAAQ,IAAI,GAAI,CAAC;CAGxD,MAAM,kBAAkB,UAAU,MAAM,YAAY;CACpD,IAAI,QAAQ;CACZ,IAAI,iBAAiB;EAGnB,MAAM,SAFiB,gBAAgB,EAEV,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;EACvD,QAAQ,SAAS,QAAQ,EAAE;CAC7B;CAEA,OAAO;EAAE;EAAS;CAAM;AAC1B"}
@@ -1,9 +1,10 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
1
  const require_protocol_client = require("../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.cjs");
3
2
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
4
3
  let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
5
4
  //#region src/clients/progress.ts
6
5
  var ClientProgress = class {
6
+ client;
7
+ logger;
7
8
  wire;
8
9
  constructor(wireClientProviderFactory, _, client, logger) {
9
10
  this.client = client;
@@ -1 +1 @@
1
- {"version":3,"file":"progress.cjs","names":["ProgressClient","RestAPI"],"sources":["../../src/clients/progress.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ProgressClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client\";\nimport type { ProgressAPI_Report } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol\";\nimport type { ProgressApiPaths, ProgressRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport type ProgressStatus = {\n done: boolean;\n progress: number;\n bytesProcessed?: string;\n bytesTotal?: string;\n};\n\n// ClientProgress holds a grpc connection to the platform\n// but for Progress API service.\n// When blobs are transfered, one can got a status of transfering\n// using this API.\nexport class ClientProgress {\n public readonly wire: WireClientProvider<ProgressRestClientType | ProgressClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n _: Dispatcher,\n public readonly client: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new ProgressClient(wire.Transport);\n }\n\n return RestAPI.createClient<ProgressApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** getStatus gets a progress status by given rId and rType. */\n async getStatus({ id, type }: ResourceInfo, options?: RpcOptions): Promise<ProgressStatus> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(id);\n let report: ProgressAPI_Report;\n if (client instanceof ProgressClient) {\n report = notEmpty(\n (\n await client.getStatus(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n ).response\n ).report,\n );\n } else {\n const resp = (\n await client.POST(\"/v1/get-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!.report;\n report = {\n done: resp.done,\n progress: resp.progress,\n bytesProcessed: BigInt(resp.bytesProcessed),\n bytesTotal: BigInt(resp.bytesTotal),\n name: resp.name,\n };\n }\n\n return {\n done: report.done,\n progress: report.progress,\n bytesProcessed: String(report.bytesProcessed),\n bytesTotal: String(report.bytesTotal),\n };\n }\n}\n"],"mappings":";;;;;AAgCA,IAAa,iBAAb,MAA4B;CAC1B;CAEA,YACE,2BACA,GACA,QACA,QACA;AAFgB,OAAA,SAAA;AACA,OAAA,SAAA;AAEhB,OAAK,OAAO,0BAA0B,0BAA0B,SAAS;AACvE,OAAI,KAAK,SAAS,OAChB,QAAO,IAAIA,wBAAAA,eAAe,KAAK,UAAU;AAG3C,UAAOC,0BAAAA,QAAQ,aAA+B;IAC5C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;IACnB,CAAC;IACF;;CAGJ,QAAQ;;CAGR,MAAM,UAAU,EAAE,IAAI,QAAsB,SAA+C;EACzF,MAAM,SAAS,KAAK,KAAK,KAAK;EAE9B,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,uBAAoC,GAAG;EACzD,IAAI;AACJ,MAAI,kBAAkBD,wBAAAA,eACpB,WAAA,GAAA,2BAAA,WAEI,MAAM,OAAO,UACX;GAAE,YAAY;GAAU,mBAAmB;GAAW,GAAA,GAAA,0BAAA,oBACnC,MAAM,QAAQ,CAClC,CAAC,UACF,OACH;OACI;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,oBAAoB;IACpC,MAAM;KACJ,YAAY,SAAS,UAAU;KAC/B,oBAAA,GAAA,0BAAA,sBAAwC,UAAU;KACnD;IACD,SAAS,EAAE,IAAA,GAAA,0BAAA,0BAA4B,KAAK,EAAE;IAC/C,CAAC,EACF,KAAM;AACR,YAAS;IACP,MAAM,KAAK;IACX,UAAU,KAAK;IACf,gBAAgB,OAAO,KAAK,eAAe;IAC3C,YAAY,OAAO,KAAK,WAAW;IACnC,MAAM,KAAK;IACZ;;AAGH,SAAO;GACL,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,gBAAgB,OAAO,OAAO,eAAe;GAC7C,YAAY,OAAO,OAAO,WAAW;GACtC"}
1
+ {"version":3,"file":"progress.cjs","names":["ProgressClient","RestAPI"],"sources":["../../src/clients/progress.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ProgressClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client\";\nimport type { ProgressAPI_Report } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol\";\nimport type { ProgressApiPaths, ProgressRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport type ProgressStatus = {\n done: boolean;\n progress: number;\n bytesProcessed?: string;\n bytesTotal?: string;\n};\n\n// ClientProgress holds a grpc connection to the platform\n// but for Progress API service.\n// When blobs are transfered, one can got a status of transfering\n// using this API.\nexport class ClientProgress {\n public readonly wire: WireClientProvider<ProgressRestClientType | ProgressClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n _: Dispatcher,\n public readonly client: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new ProgressClient(wire.Transport);\n }\n\n return RestAPI.createClient<ProgressApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** getStatus gets a progress status by given rId and rType. */\n async getStatus({ id, type }: ResourceInfo, options?: RpcOptions): Promise<ProgressStatus> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(id);\n let report: ProgressAPI_Report;\n if (client instanceof ProgressClient) {\n report = notEmpty(\n (\n await client.getStatus(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n ).response\n ).report,\n );\n } else {\n const resp = (\n await client.POST(\"/v1/get-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!.report;\n report = {\n done: resp.done,\n progress: resp.progress,\n bytesProcessed: BigInt(resp.bytesProcessed),\n bytesTotal: BigInt(resp.bytesTotal),\n name: resp.name,\n };\n }\n\n return {\n done: report.done,\n progress: report.progress,\n bytesProcessed: String(report.bytesProcessed),\n bytesTotal: String(report.bytesTotal),\n };\n }\n}\n"],"mappings":";;;;AAgCA,IAAa,iBAAb,MAA4B;CAMR;CACA;CANlB;CAEA,YACE,2BACA,GACA,QACA,QACA;EAFgB,KAAA,SAAA;EACA,KAAA,SAAA;EAEhB,KAAK,OAAO,0BAA0B,0BAA0B,SAAS;GACvE,IAAI,KAAK,SAAS,QAChB,OAAO,IAAIA,wBAAAA,eAAe,KAAK,SAAS;GAG1C,OAAOC,0BAAAA,QAAQ,aAA+B;IAC5C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;GACpB,CAAC;EACH,CAAC;CACH;CAEA,QAAQ,CAAC;;CAGT,MAAM,UAAU,EAAE,IAAI,QAAsB,SAA+C;EACzF,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,sBAAA,CAAoC,EAAE;EACxD,IAAI;EACJ,IAAI,kBAAkBD,wBAAAA,gBACpB,UAAA,GAAA,2BAAA,SAAA,EAEI,MAAM,OAAO,UACX;GAAE,YAAY;GAAU,mBAAmB;EAAU,IAAA,GAAA,0BAAA,mBAAA,CAClC,MAAM,OAAO,CAClC,CAAC,CAAC,SAAA,CACF,MACJ;OACK;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,oBAAoB;IACpC,MAAM;KACJ,YAAY,SAAS,SAAS;KAC9B,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,SAAS;IACnD;IACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,IAAI,EAAE;GAC/C,CAAC,EAAA,CACD,KAAM;GACR,SAAS;IACP,MAAM,KAAK;IACX,UAAU,KAAK;IACf,gBAAgB,OAAO,KAAK,cAAc;IAC1C,YAAY,OAAO,KAAK,UAAU;IAClC,MAAM,KAAK;GACb;EACF;EAEA,OAAO;GACL,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,gBAAgB,OAAO,OAAO,cAAc;GAC5C,YAAY,OAAO,OAAO,UAAU;EACtC;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"progress.d.ts","names":[],"sources":["../../src/clients/progress.ts"],"mappings":";;;;;;;;;KAqBY,cAAA;EACV,IAAA;EACA,QAAA;EACA,cAAA;EACA,UAAA;AAAA;AAAA,cAOW,cAAA;EAAA,SAMO,MAAA,EAAQ,QAAA;EAAA,SACR,MAAA,EAAQ,QAAA;EAAA,SANV,IAAA,EAAM,kBAAA,CAAmB,sBAAA,GAAyB,cAAA;cAGhE,yBAAA,EAA2B,yBAAA,EAC3B,CAAA,EAAG,UAAA,EACa,MAAA,EAAQ,QAAA,EACR,MAAA,EAAQ,QAAA;EAgB1B,KAAA,CAAA;EAvBW;EA0BL,SAAA,CAAA;IAAY,EAAA;IAAI;EAAA,GAAQ,YAAA,EAAc,OAAA,GAAU,UAAA,GAAa,OAAA,CAAQ,cAAA;AAAA"}
1
+ {"version":3,"file":"progress.d.ts","names":[],"sources":["../../src/clients/progress.ts"],"mappings":";;;;;;;;;KAqBY,cAAA;EACV,IAAA;EACA,QAAA;EACA,cAAA;EACA,UAAA;AAAA;AAAA,cAOW,cAAA;EAAA,SAMO,MAAA,EAAQ,QAAA;EAAA,SACR,MAAA,EAAQ,QAAA;EAAA,SANV,IAAA,EAAM,kBAAA,CAAmB,sBAAA,GAAyB,cAAA;cAGhE,yBAAA,EAA2B,yBAAA,EAC3B,CAAA,EAAG,UAAA,EACa,MAAA,EAAQ,QAAA,EACR,MAAA,EAAQ,QAAA;EAgB1B,KAAA;EAvBW;EA0BL,SAAA;IAAY,EAAA;IAAI;EAAA,GAAQ,YAAA,EAAc,OAAA,GAAU,UAAA,GAAa,OAAA,CAAQ,cAAA;AAAA"}
@@ -3,6 +3,8 @@ import { RestAPI, addRTypeToMetadata, createRTypeRoutingHeader, parseSignedResou
3
3
  import { notEmpty } from "@milaboratories/ts-helpers";
4
4
  //#region src/clients/progress.ts
5
5
  var ClientProgress = class {
6
+ client;
7
+ logger;
6
8
  wire;
7
9
  constructor(wireClientProviderFactory, _, client, logger) {
8
10
  this.client = client;
@@ -1 +1 @@
1
- {"version":3,"file":"progress.js","names":[],"sources":["../../src/clients/progress.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ProgressClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client\";\nimport type { ProgressAPI_Report } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol\";\nimport type { ProgressApiPaths, ProgressRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport type ProgressStatus = {\n done: boolean;\n progress: number;\n bytesProcessed?: string;\n bytesTotal?: string;\n};\n\n// ClientProgress holds a grpc connection to the platform\n// but for Progress API service.\n// When blobs are transfered, one can got a status of transfering\n// using this API.\nexport class ClientProgress {\n public readonly wire: WireClientProvider<ProgressRestClientType | ProgressClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n _: Dispatcher,\n public readonly client: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new ProgressClient(wire.Transport);\n }\n\n return RestAPI.createClient<ProgressApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** getStatus gets a progress status by given rId and rType. */\n async getStatus({ id, type }: ResourceInfo, options?: RpcOptions): Promise<ProgressStatus> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(id);\n let report: ProgressAPI_Report;\n if (client instanceof ProgressClient) {\n report = notEmpty(\n (\n await client.getStatus(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n ).response\n ).report,\n );\n } else {\n const resp = (\n await client.POST(\"/v1/get-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!.report;\n report = {\n done: resp.done,\n progress: resp.progress,\n bytesProcessed: BigInt(resp.bytesProcessed),\n bytesTotal: BigInt(resp.bytesTotal),\n name: resp.name,\n };\n }\n\n return {\n done: report.done,\n progress: report.progress,\n bytesProcessed: String(report.bytesProcessed),\n bytesTotal: String(report.bytesTotal),\n };\n }\n}\n"],"mappings":";;;;AAgCA,IAAa,iBAAb,MAA4B;CAC1B;CAEA,YACE,2BACA,GACA,QACA,QACA;AAFgB,OAAA,SAAA;AACA,OAAA,SAAA;AAEhB,OAAK,OAAO,0BAA0B,0BAA0B,SAAS;AACvE,OAAI,KAAK,SAAS,OAChB,QAAO,IAAI,eAAe,KAAK,UAAU;AAG3C,UAAO,QAAQ,aAA+B;IAC5C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;IACnB,CAAC;IACF;;CAGJ,QAAQ;;CAGR,MAAM,UAAU,EAAE,IAAI,QAAsB,SAA+C;EACzF,MAAM,SAAS,KAAK,KAAK,KAAK;EAE9B,MAAM,EAAE,UAAU,cAAc,sBAAsB,GAAG;EACzD,IAAI;AACJ,MAAI,kBAAkB,eACpB,UAAS,UAEL,MAAM,OAAO,UACX;GAAE,YAAY;GAAU,mBAAmB;GAAW,EACtD,mBAAmB,MAAM,QAAQ,CAClC,CAAC,UACF,OACH;OACI;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,oBAAoB;IACpC,MAAM;KACJ,YAAY,SAAS,UAAU;KAC/B,mBAAmB,qBAAqB,UAAU;KACnD;IACD,SAAS,EAAE,GAAG,yBAAyB,KAAK,EAAE;IAC/C,CAAC,EACF,KAAM;AACR,YAAS;IACP,MAAM,KAAK;IACX,UAAU,KAAK;IACf,gBAAgB,OAAO,KAAK,eAAe;IAC3C,YAAY,OAAO,KAAK,WAAW;IACnC,MAAM,KAAK;IACZ;;AAGH,SAAO;GACL,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,gBAAgB,OAAO,OAAO,eAAe;GAC7C,YAAY,OAAO,OAAO,WAAW;GACtC"}
1
+ {"version":3,"file":"progress.js","names":[],"sources":["../../src/clients/progress.ts"],"sourcesContent":["import type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ProgressClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client\";\nimport type { ProgressAPI_Report } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol\";\nimport type { ProgressApiPaths, ProgressRestClientType } from \"../proto-rest\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\n\nexport type ProgressStatus = {\n done: boolean;\n progress: number;\n bytesProcessed?: string;\n bytesTotal?: string;\n};\n\n// ClientProgress holds a grpc connection to the platform\n// but for Progress API service.\n// When blobs are transfered, one can got a status of transfering\n// using this API.\nexport class ClientProgress {\n public readonly wire: WireClientProvider<ProgressRestClientType | ProgressClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n _: Dispatcher,\n public readonly client: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new ProgressClient(wire.Transport);\n }\n\n return RestAPI.createClient<ProgressApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n /** getStatus gets a progress status by given rId and rType. */\n async getStatus({ id, type }: ResourceInfo, options?: RpcOptions): Promise<ProgressStatus> {\n const client = this.wire.get();\n\n const { globalId, signature } = parseSignedResourceId(id);\n let report: ProgressAPI_Report;\n if (client instanceof ProgressClient) {\n report = notEmpty(\n (\n await client.getStatus(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n ).response\n ).report,\n );\n } else {\n const resp = (\n await client.POST(\"/v1/get-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!.report;\n report = {\n done: resp.done,\n progress: resp.progress,\n bytesProcessed: BigInt(resp.bytesProcessed),\n bytesTotal: BigInt(resp.bytesTotal),\n name: resp.name,\n };\n }\n\n return {\n done: report.done,\n progress: report.progress,\n bytesProcessed: String(report.bytesProcessed),\n bytesTotal: String(report.bytesTotal),\n };\n }\n}\n"],"mappings":";;;;AAgCA,IAAa,iBAAb,MAA4B;CAMR;CACA;CANlB;CAEA,YACE,2BACA,GACA,QACA,QACA;EAFgB,KAAA,SAAA;EACA,KAAA,SAAA;EAEhB,KAAK,OAAO,0BAA0B,0BAA0B,SAAS;GACvE,IAAI,KAAK,SAAS,QAChB,OAAO,IAAI,eAAe,KAAK,SAAS;GAG1C,OAAO,QAAQ,aAA+B;IAC5C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;GACpB,CAAC;EACH,CAAC;CACH;CAEA,QAAQ,CAAC;;CAGT,MAAM,UAAU,EAAE,IAAI,QAAsB,SAA+C;EACzF,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,MAAM,EAAE,UAAU,cAAc,sBAAsB,EAAE;EACxD,IAAI;EACJ,IAAI,kBAAkB,gBACpB,SAAS,UAEL,MAAM,OAAO,UACX;GAAE,YAAY;GAAU,mBAAmB;EAAU,GACrD,mBAAmB,MAAM,OAAO,CAClC,CAAC,CAAC,SAAA,CACF,MACJ;OACK;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,oBAAoB;IACpC,MAAM;KACJ,YAAY,SAAS,SAAS;KAC9B,mBAAmB,qBAAqB,SAAS;IACnD;IACA,SAAS,EAAE,GAAG,yBAAyB,IAAI,EAAE;GAC/C,CAAC,EAAA,CACD,KAAM;GACR,SAAS;IACP,MAAM,KAAK;IACX,UAAU,KAAK;IACf,gBAAgB,OAAO,KAAK,cAAc;IAC1C,YAAY,OAAO,KAAK,UAAU;IAClC,MAAM,KAAK;GACb;EACF;EAEA,OAAO;GACL,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,gBAAgB,OAAO,OAAO,cAAc;GAC5C,YAAY,OAAO,OAAO,UAAU;EACtC;CACF;AACF"}
@@ -1,10 +1,10 @@
1
1
  const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
- const require_protocol = require("../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs");
2
+ require("../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs");
3
3
  const require_protocol_client = require("../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.cjs");
4
4
  const require_crc32c = require("./crc32c.cjs");
5
5
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
6
6
  let node_fs_promises = require("node:fs/promises");
7
- node_fs_promises = require_runtime.__toESM(node_fs_promises);
7
+ node_fs_promises = require_runtime.__toESM(node_fs_promises, 1);
8
8
  let undici = require("undici");
9
9
  //#region src/clients/upload.ts
10
10
  var MTimeError = class extends Error {
@@ -27,6 +27,8 @@ var BadRequestError = class extends Error {
27
27
  * The user should pass here a concrete BlobUpload/<storageId> resource,
28
28
  * it can be got from handle field of BlobUpload. */
29
29
  var ClientUpload = class {
30
+ httpClient;
31
+ logger;
30
32
  wire;
31
33
  constructor(wireClientProviderFactory, httpClient, _, logger) {
32
34
  this.httpClient = httpClient;
@@ -105,7 +107,7 @@ var ClientUpload = class {
105
107
  }
106
108
  const chunk = await readFileChunk(path, info.chunkStart, info.chunkEnd);
107
109
  await checkExpectedMTime(path, expectedMTimeUnix);
108
- if (checksumHeader && checksumAlgorithm === require_protocol.UploadAPI_ChecksumAlgorithm.CRC32C) info.headers.push({
110
+ if (checksumHeader && checksumAlgorithm === 1) info.headers.push({
109
111
  name: checksumHeader,
110
112
  value: calculateCrc32cChecksum(chunk)
111
113
  });
@@ -139,8 +141,8 @@ var ClientUpload = class {
139
141
  if (client instanceof require_protocol_client.UploadClient) await client.finalize({
140
142
  resourceId: globalId,
141
143
  resourceSignature: signature,
142
- checksumAlgorithm: require_protocol.UploadAPI_ChecksumAlgorithm.UNSPECIFIED,
143
- checksum: new Uint8Array(0)
144
+ checksumAlgorithm: 0,
145
+ checksum: /* @__PURE__ */ new Uint8Array(0)
144
146
  }, (0, _milaboratories_pl_client.addRTypeToMetadata)(info.type, options));
145
147
  else await client.POST("/v1/upload/finalize", {
146
148
  body: {
@@ -1 +1 @@
1
- {"version":3,"file":"upload.cjs","names":["UploadClient","RestAPI","UploadAPI_ChecksumAlgorithm","fs","crc32c"],"sources":["../../src/clients/upload.ts"],"sourcesContent":["import type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs/promises\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport {\n UploadAPI_ChecksumAlgorithm,\n type UploadAPI_GetPartURL_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol\";\nimport { UploadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client\";\nimport type { UploadApiPaths, UploadRestClientType } from \"../proto-rest\";\nimport { crc32c } from \"./crc32c\";\n\nimport type { IncomingHttpHeaders } from \"undici/types/header\";\n\nexport class MTimeError extends Error {\n name = \"MTimeError\";\n}\n\nexport class UnexpectedEOF extends Error {\n name = \"UnexpectedEOF\";\n}\n\nexport class NetworkError extends Error {\n name = \"NetworkError\";\n}\n\n/** Happens when the file doesn't exist */\nexport class NoFileForUploading extends Error {\n name = \"NoFileForUploading\";\n}\n\nexport class BadRequestError extends Error {\n name = \"BadRequestError\";\n}\n\n/** Low-level client for grpc uploadapi.\n * The user should pass here a concrete BlobUpload/<storageId> resource,\n * it can be got from handle field of BlobUpload. */\nexport class ClientUpload {\n private readonly wire: WireClientProvider<UploadRestClientType | UploadClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n _: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new UploadClient(wire.Transport);\n }\n\n return RestAPI.createClient<UploadApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async initUpload(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n ): Promise<{\n overall: bigint;\n toUpload: bigint[];\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm;\n checksumHeader: string;\n }> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n const init = (\n await client.init(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n )\n ).response;\n\n return {\n overall: init.partsCount,\n toUpload: this.partsToUpload(init.partsCount, init.uploadedParts),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n const init = (\n await client.POST(\"/v1/upload/init\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n\n return {\n overall: BigInt(init.partsCount),\n toUpload: this.partsToUpload(BigInt(init.partsCount), init.uploadedParts.map(BigInt)),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n public async partUpload(\n { id, type }: ResourceInfo,\n path: string,\n expectedMTimeUnix: bigint,\n partNumber: bigint,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm,\n checksumHeader: string,\n options?: RpcOptions,\n ) {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n let info: UploadAPI_GetPartURL_Response;\n if (client instanceof UploadClient) {\n // partChecksum isn't used for now but protoc requires it to be set\n info = (\n await client.getPartURL(\n {\n resourceId: globalId,\n resourceSignature: signature,\n partNumber,\n uploadedPartSize: 0n,\n isInternalUse: false,\n partChecksum: \"\",\n },\n addRTypeToMetadata(type, options),\n )\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/upload/get-part-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n partNumber: partNumber.toString(),\n uploadedPartSize: \"0\",\n isInternalUse: false,\n partChecksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n info = {\n uploadUrl: resp.uploadUrl,\n method: resp.method,\n headers: resp.headers,\n chunkStart: BigInt(resp.chunkStart),\n chunkEnd: BigInt(resp.chunkEnd),\n };\n }\n\n const chunk = await readFileChunk(path, info.chunkStart, info.chunkEnd);\n await checkExpectedMTime(path, expectedMTimeUnix);\n\n if (checksumHeader && checksumAlgorithm === UploadAPI_ChecksumAlgorithm.CRC32C) {\n info.headers.push({ name: checksumHeader, value: calculateCrc32cChecksum(chunk) });\n }\n\n const contentLength = Number(info.chunkEnd - info.chunkStart);\n if (chunk.length !== contentLength) {\n throw new Error(\n `Chunk size mismatch: expected ${contentLength} bytes, but read ${chunk.length} bytes from file`,\n );\n }\n\n const headers = Object.fromEntries(\n info.headers.map(({ name, value }) => [name.toLowerCase(), value]),\n );\n\n try {\n const {\n body: rawBody,\n statusCode,\n headers: responseHeaders,\n } = await request(info.uploadUrl, {\n dispatcher: this.httpClient,\n body: chunk,\n // We got headers only after we send\n // the whole body (in case of S3 PUT requests it's 5 MB).\n // It might be slow with a slow connection (or with SSH),\n // that's why we got big timeout here.\n headersTimeout: 60000,\n bodyTimeout: 60000,\n // Prevent connection reuse by setting \"Connection: close\" header.\n // This works around an issue with the backend's built-in S3 implementation\n // that caused HTTP/1.1 protocol lines to be included in the uploaded file content.\n reset: true,\n headers,\n method: info.method.toUpperCase() as Dispatcher.HttpMethod,\n });\n\n // always read the body for resources to be garbage collected.\n const body = await rawBody.text();\n checkStatusCodeOk(statusCode, body, responseHeaders, info);\n } catch (e: unknown) {\n if (e instanceof NetworkError) throw e;\n\n if (e instanceof BadRequestError) throw e;\n\n throw new Error(\n `partUpload: error ${JSON.stringify(e)} happened while trying to do part upload to the url ${info.uploadUrl}, headers: ${JSON.stringify(info.headers)}`,\n );\n }\n\n await this.updateProgress({ id, type }, BigInt(info.chunkEnd - info.chunkStart), options);\n }\n\n public async finalize(info: ResourceInfo, options?: RpcOptions) {\n const { globalId, signature } = parseSignedResourceId(info.id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.finalize(\n {\n resourceId: globalId,\n resourceSignature: signature,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm.UNSPECIFIED,\n checksum: new Uint8Array(0),\n },\n addRTypeToMetadata(info.type, options),\n );\n } else {\n await client.POST(\"/v1/upload/finalize\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n checksumAlgorithm: 0,\n checksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(info.type) },\n });\n }\n }\n\n /** Calculates parts that need to be uploaded from the parts that were\n * already uploaded. */\n private partsToUpload(partsCount: bigint, uploadedParts: bigint[]): bigint[] {\n const toUpload: bigint[] = [];\n const uploaded = new Set(uploadedParts);\n\n for (let i = 1n; i <= partsCount; i++) {\n if (!uploaded.has(i)) toUpload.push(i);\n }\n\n return toUpload;\n }\n\n private async updateProgress(\n { id, type }: ResourceInfo,\n bytesProcessed: bigint,\n options?: RpcOptions,\n ): Promise<void> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.updateProgress(\n {\n resourceId: globalId,\n resourceSignature: signature,\n bytesProcessed,\n },\n addRTypeToMetadata(type, options),\n ).response;\n return;\n }\n\n await client.POST(\"/v1/upload/update-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n bytesProcessed: bytesProcessed.toString(),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n });\n return;\n }\n}\n\nasync function readFileChunk(path: string, chunkStart: bigint, chunkEnd: bigint): Promise<Buffer> {\n let f: fs.FileHandle | undefined;\n try {\n f = await fs.open(path);\n const len = Number(chunkEnd - chunkStart);\n const pos = Number(chunkStart);\n const b = Buffer.alloc(len);\n const bytesRead = await readBytesFromPosition(f, b, len, pos);\n\n return b.subarray(0, bytesRead);\n } catch (e: unknown) {\n if (e && typeof e === \"object\" && \"code\" in e && e.code == \"ENOENT\")\n throw new NoFileForUploading(`there is no file ${path} for uploading`);\n throw e;\n } finally {\n await f?.close();\n }\n}\n\n/** Read len bytes from a given position.\n * Without this, `FileHandle.read` can read less bytes than needed. */\nasync function readBytesFromPosition(f: fs.FileHandle, b: Buffer, len: number, position: number) {\n let bytesReadTotal = 0;\n while (bytesReadTotal < len) {\n const { bytesRead } = await f.read(\n b,\n bytesReadTotal,\n len - bytesReadTotal,\n position + bytesReadTotal,\n );\n if (bytesRead === 0) {\n throw new UnexpectedEOF(\"file ended earlier than expected.\");\n }\n bytesReadTotal += bytesRead;\n }\n\n return bytesReadTotal;\n}\n\nasync function checkExpectedMTime(path: string, expectedMTimeUnix: bigint) {\n const mTime = BigInt(Math.floor((await fs.stat(path)).mtimeMs / 1000));\n if (mTime > expectedMTimeUnix) {\n throw new MTimeError(`file was modified, expected mtime: ${expectedMTimeUnix}, got: ${mTime}.`);\n }\n}\n\n/** S3 error codes that indicate expired/invalid temporary credentials.\n * These are transient: a retry with a fresh presigned URL will succeed\n * once the backend refreshes its STS credentials. */\nconst TRANSIENT_S3_ERROR_CODES = [\"ExpiredToken\", \"RequestExpired\", \"TokenRefreshRequired\"];\n\nfunction isTransientS3Error(body: string): boolean {\n return TRANSIENT_S3_ERROR_CODES.some((code) => body.includes(`<Code>${code}</Code>`));\n}\n\nfunction checkStatusCodeOk(\n statusCode: number,\n body: string,\n headers: IncomingHttpHeaders,\n info: UploadAPI_GetPartURL_Response,\n) {\n if (statusCode == 400) {\n if (isTransientS3Error(body)) {\n throw new NetworkError(\n `transient S3 credential error, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n throw new BadRequestError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n\n if (statusCode != 200) {\n throw new NetworkError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n}\n\n/** Calculate CRC32C checksum of a buffer and return as base64 string */\nfunction calculateCrc32cChecksum(data: Buffer): string {\n const checksum = crc32c(data);\n // Convert to unsigned 32-bit integer and then to base64\n const buffer = Buffer.alloc(4);\n\n buffer.writeUInt32BE(checksum, 0);\n return buffer.toString(\"base64\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"upload.cjs","names":["UploadClient","RestAPI","fs","crc32c"],"sources":["../../src/clients/upload.ts"],"sourcesContent":["import type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs/promises\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport {\n UploadAPI_ChecksumAlgorithm,\n type UploadAPI_GetPartURL_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol\";\nimport { UploadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client\";\nimport type { UploadApiPaths, UploadRestClientType } from \"../proto-rest\";\nimport { crc32c } from \"./crc32c\";\n\nimport type { IncomingHttpHeaders } from \"undici/types/header\";\n\nexport class MTimeError extends Error {\n name = \"MTimeError\";\n}\n\nexport class UnexpectedEOF extends Error {\n name = \"UnexpectedEOF\";\n}\n\nexport class NetworkError extends Error {\n name = \"NetworkError\";\n}\n\n/** Happens when the file doesn't exist */\nexport class NoFileForUploading extends Error {\n name = \"NoFileForUploading\";\n}\n\nexport class BadRequestError extends Error {\n name = \"BadRequestError\";\n}\n\n/** Low-level client for grpc uploadapi.\n * The user should pass here a concrete BlobUpload/<storageId> resource,\n * it can be got from handle field of BlobUpload. */\nexport class ClientUpload {\n private readonly wire: WireClientProvider<UploadRestClientType | UploadClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n _: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new UploadClient(wire.Transport);\n }\n\n return RestAPI.createClient<UploadApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async initUpload(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n ): Promise<{\n overall: bigint;\n toUpload: bigint[];\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm;\n checksumHeader: string;\n }> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n const init = (\n await client.init(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n )\n ).response;\n\n return {\n overall: init.partsCount,\n toUpload: this.partsToUpload(init.partsCount, init.uploadedParts),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n const init = (\n await client.POST(\"/v1/upload/init\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n\n return {\n overall: BigInt(init.partsCount),\n toUpload: this.partsToUpload(BigInt(init.partsCount), init.uploadedParts.map(BigInt)),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n public async partUpload(\n { id, type }: ResourceInfo,\n path: string,\n expectedMTimeUnix: bigint,\n partNumber: bigint,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm,\n checksumHeader: string,\n options?: RpcOptions,\n ) {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n let info: UploadAPI_GetPartURL_Response;\n if (client instanceof UploadClient) {\n // partChecksum isn't used for now but protoc requires it to be set\n info = (\n await client.getPartURL(\n {\n resourceId: globalId,\n resourceSignature: signature,\n partNumber,\n uploadedPartSize: 0n,\n isInternalUse: false,\n partChecksum: \"\",\n },\n addRTypeToMetadata(type, options),\n )\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/upload/get-part-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n partNumber: partNumber.toString(),\n uploadedPartSize: \"0\",\n isInternalUse: false,\n partChecksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n info = {\n uploadUrl: resp.uploadUrl,\n method: resp.method,\n headers: resp.headers,\n chunkStart: BigInt(resp.chunkStart),\n chunkEnd: BigInt(resp.chunkEnd),\n };\n }\n\n const chunk = await readFileChunk(path, info.chunkStart, info.chunkEnd);\n await checkExpectedMTime(path, expectedMTimeUnix);\n\n if (checksumHeader && checksumAlgorithm === UploadAPI_ChecksumAlgorithm.CRC32C) {\n info.headers.push({ name: checksumHeader, value: calculateCrc32cChecksum(chunk) });\n }\n\n const contentLength = Number(info.chunkEnd - info.chunkStart);\n if (chunk.length !== contentLength) {\n throw new Error(\n `Chunk size mismatch: expected ${contentLength} bytes, but read ${chunk.length} bytes from file`,\n );\n }\n\n const headers = Object.fromEntries(\n info.headers.map(({ name, value }) => [name.toLowerCase(), value]),\n );\n\n try {\n const {\n body: rawBody,\n statusCode,\n headers: responseHeaders,\n } = await request(info.uploadUrl, {\n dispatcher: this.httpClient,\n body: chunk,\n // We got headers only after we send\n // the whole body (in case of S3 PUT requests it's 5 MB).\n // It might be slow with a slow connection (or with SSH),\n // that's why we got big timeout here.\n headersTimeout: 60000,\n bodyTimeout: 60000,\n // Prevent connection reuse by setting \"Connection: close\" header.\n // This works around an issue with the backend's built-in S3 implementation\n // that caused HTTP/1.1 protocol lines to be included in the uploaded file content.\n reset: true,\n headers,\n method: info.method.toUpperCase() as Dispatcher.HttpMethod,\n });\n\n // always read the body for resources to be garbage collected.\n const body = await rawBody.text();\n checkStatusCodeOk(statusCode, body, responseHeaders, info);\n } catch (e: unknown) {\n if (e instanceof NetworkError) throw e;\n\n if (e instanceof BadRequestError) throw e;\n\n throw new Error(\n `partUpload: error ${JSON.stringify(e)} happened while trying to do part upload to the url ${info.uploadUrl}, headers: ${JSON.stringify(info.headers)}`,\n );\n }\n\n await this.updateProgress({ id, type }, BigInt(info.chunkEnd - info.chunkStart), options);\n }\n\n public async finalize(info: ResourceInfo, options?: RpcOptions) {\n const { globalId, signature } = parseSignedResourceId(info.id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.finalize(\n {\n resourceId: globalId,\n resourceSignature: signature,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm.UNSPECIFIED,\n checksum: new Uint8Array(0),\n },\n addRTypeToMetadata(info.type, options),\n );\n } else {\n await client.POST(\"/v1/upload/finalize\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n checksumAlgorithm: 0,\n checksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(info.type) },\n });\n }\n }\n\n /** Calculates parts that need to be uploaded from the parts that were\n * already uploaded. */\n private partsToUpload(partsCount: bigint, uploadedParts: bigint[]): bigint[] {\n const toUpload: bigint[] = [];\n const uploaded = new Set(uploadedParts);\n\n for (let i = 1n; i <= partsCount; i++) {\n if (!uploaded.has(i)) toUpload.push(i);\n }\n\n return toUpload;\n }\n\n private async updateProgress(\n { id, type }: ResourceInfo,\n bytesProcessed: bigint,\n options?: RpcOptions,\n ): Promise<void> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.updateProgress(\n {\n resourceId: globalId,\n resourceSignature: signature,\n bytesProcessed,\n },\n addRTypeToMetadata(type, options),\n ).response;\n return;\n }\n\n await client.POST(\"/v1/upload/update-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n bytesProcessed: bytesProcessed.toString(),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n });\n return;\n }\n}\n\nasync function readFileChunk(path: string, chunkStart: bigint, chunkEnd: bigint): Promise<Buffer> {\n let f: fs.FileHandle | undefined;\n try {\n f = await fs.open(path);\n const len = Number(chunkEnd - chunkStart);\n const pos = Number(chunkStart);\n const b = Buffer.alloc(len);\n const bytesRead = await readBytesFromPosition(f, b, len, pos);\n\n return b.subarray(0, bytesRead);\n } catch (e: unknown) {\n if (e && typeof e === \"object\" && \"code\" in e && e.code == \"ENOENT\")\n throw new NoFileForUploading(`there is no file ${path} for uploading`);\n throw e;\n } finally {\n await f?.close();\n }\n}\n\n/** Read len bytes from a given position.\n * Without this, `FileHandle.read` can read less bytes than needed. */\nasync function readBytesFromPosition(f: fs.FileHandle, b: Buffer, len: number, position: number) {\n let bytesReadTotal = 0;\n while (bytesReadTotal < len) {\n const { bytesRead } = await f.read(\n b,\n bytesReadTotal,\n len - bytesReadTotal,\n position + bytesReadTotal,\n );\n if (bytesRead === 0) {\n throw new UnexpectedEOF(\"file ended earlier than expected.\");\n }\n bytesReadTotal += bytesRead;\n }\n\n return bytesReadTotal;\n}\n\nasync function checkExpectedMTime(path: string, expectedMTimeUnix: bigint) {\n const mTime = BigInt(Math.floor((await fs.stat(path)).mtimeMs / 1000));\n if (mTime > expectedMTimeUnix) {\n throw new MTimeError(`file was modified, expected mtime: ${expectedMTimeUnix}, got: ${mTime}.`);\n }\n}\n\n/** S3 error codes that indicate expired/invalid temporary credentials.\n * These are transient: a retry with a fresh presigned URL will succeed\n * once the backend refreshes its STS credentials. */\nconst TRANSIENT_S3_ERROR_CODES = [\"ExpiredToken\", \"RequestExpired\", \"TokenRefreshRequired\"];\n\nfunction isTransientS3Error(body: string): boolean {\n return TRANSIENT_S3_ERROR_CODES.some((code) => body.includes(`<Code>${code}</Code>`));\n}\n\nfunction checkStatusCodeOk(\n statusCode: number,\n body: string,\n headers: IncomingHttpHeaders,\n info: UploadAPI_GetPartURL_Response,\n) {\n if (statusCode == 400) {\n if (isTransientS3Error(body)) {\n throw new NetworkError(\n `transient S3 credential error, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n throw new BadRequestError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n\n if (statusCode != 200) {\n throw new NetworkError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n}\n\n/** Calculate CRC32C checksum of a buffer and return as base64 string */\nfunction calculateCrc32cChecksum(data: Buffer): string {\n const checksum = crc32c(data);\n // Convert to unsigned 32-bit integer and then to base64\n const buffer = Buffer.alloc(4);\n\n buffer.writeUInt32BE(checksum, 0);\n return buffer.toString(\"base64\");\n}\n"],"mappings":";;;;;;;;;AA4BA,IAAa,aAAb,cAAgC,MAAM;CACpC,OAAO;AACT;AAEA,IAAa,gBAAb,cAAmC,MAAM;CACvC,OAAO;AACT;AAEA,IAAa,eAAb,cAAkC,MAAM;CACtC,OAAO;AACT;;AAGA,IAAa,qBAAb,cAAwC,MAAM;CAC5C,OAAO;AACT;AAEA,IAAa,kBAAb,cAAqC,MAAM;CACzC,OAAO;AACT;;;;AAKA,IAAa,eAAb,MAA0B;CAKN;CAEA;CANlB;CAEA,YACE,2BACA,YACA,GACA,QACA;EAHgB,KAAA,aAAA;EAEA,KAAA,SAAA;EAEhB,KAAK,OAAO,0BAA0B,0BAA0B,SAAS;GACvE,IAAI,KAAK,SAAS,QAChB,OAAO,IAAIA,wBAAAA,aAAa,KAAK,SAAS;GAGxC,OAAOC,0BAAAA,QAAQ,aAA6B;IAC1C,aAAa,KAAK,OAAO;IACzB,KAAK,KAAK,OAAO;IACjB,YAAY,KAAK;IACjB,aAAa,KAAK;GACpB,CAAC;EACH,CAAC;CACH;CAEA,QAAQ,CAAC;CAET,MAAa,WACX,EAAE,IAAI,QACN,SAMC;EACD,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,sBAAA,CAAoC,EAAE;EACxD,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,IAAI,kBAAkBD,wBAAAA,cAAc;GAClC,MAAM,QACJ,MAAM,OAAO,KACX;IAAE,YAAY;IAAU,mBAAmB;GAAU,IAAA,GAAA,0BAAA,mBAAA,CAClC,MAAM,OAAO,CAClC,EAAA,CACA;GAEF,OAAO;IACL,SAAS,KAAK;IACd,UAAU,KAAK,cAAc,KAAK,YAAY,KAAK,aAAa;IAChE,mBAAmB,KAAK;IACxB,gBAAgB,KAAK;GACvB;EACF;EAEA,MAAM,QACJ,MAAM,OAAO,KAAK,mBAAmB;GACnC,MAAM;IACJ,YAAY,SAAS,SAAS;IAC9B,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,SAAS;GACnD;GACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,IAAI,EAAE;EAC/C,CAAC,EAAA,CACD;EAEF,OAAO;GACL,SAAS,OAAO,KAAK,UAAU;GAC/B,UAAU,KAAK,cAAc,OAAO,KAAK,UAAU,GAAG,KAAK,cAAc,IAAI,MAAM,CAAC;GACpF,mBAAmB,KAAK;GACxB,gBAAgB,KAAK;EACvB;CACF;CAEA,MAAa,WACX,EAAE,IAAI,QACN,MACA,mBACA,YACA,mBACA,gBACA,SACA;EACA,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,sBAAA,CAAoC,EAAE;EACxD,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,IAAI;EACJ,IAAI,kBAAkBA,wBAAAA,cAEpB,QACE,MAAM,OAAO,WACX;GACE,YAAY;GACZ,mBAAmB;GACnB;GACA,kBAAkB;GAClB,eAAe;GACf,cAAc;EAChB,IAAA,GAAA,0BAAA,mBAAA,CACmB,MAAM,OAAO,CAClC,EAAA,CACA;OACG;GACL,MAAM,QACJ,MAAM,OAAO,KAAK,2BAA2B;IAC3C,MAAM;KACJ,YAAY,SAAS,SAAS;KAC9B,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,SAAS;KACjD,YAAY,WAAW,SAAS;KAChC,kBAAkB;KAClB,eAAe;KACf,cAAc;IAChB;IACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,IAAI,EAAE;GAC/C,CAAC,EAAA,CACD;GACF,OAAO;IACL,WAAW,KAAK;IAChB,QAAQ,KAAK;IACb,SAAS,KAAK;IACd,YAAY,OAAO,KAAK,UAAU;IAClC,UAAU,OAAO,KAAK,QAAQ;GAChC;EACF;EAEA,MAAM,QAAQ,MAAM,cAAc,MAAM,KAAK,YAAY,KAAK,QAAQ;EACtE,MAAM,mBAAmB,MAAM,iBAAiB;EAEhD,IAAI,kBAAkB,sBAAA,GACpB,KAAK,QAAQ,KAAK;GAAE,MAAM;GAAgB,OAAO,wBAAwB,KAAK;EAAE,CAAC;EAGnF,MAAM,gBAAgB,OAAO,KAAK,WAAW,KAAK,UAAU;EAC5D,IAAI,MAAM,WAAW,eACnB,MAAM,IAAI,MACR,iCAAiC,cAAc,mBAAmB,MAAM,OAAO,iBACjF;EAGF,MAAM,UAAU,OAAO,YACrB,KAAK,QAAQ,KAAK,EAAE,MAAM,YAAY,CAAC,KAAK,YAAY,GAAG,KAAK,CAAC,CACnE;EAEA,IAAI;GACF,MAAM,EACJ,MAAM,SACN,YACA,SAAS,oBACP,OAAA,GAAA,OAAA,QAAA,CAAc,KAAK,WAAW;IAChC,YAAY,KAAK;IACjB,MAAM;IAKN,gBAAgB;IAChB,aAAa;IAIb,OAAO;IACP;IACA,QAAQ,KAAK,OAAO,YAAY;GAClC,CAAC;GAID,kBAAkB,YAAY,MADX,QAAQ,KAAK,GACI,iBAAiB,IAAI;EAC3D,SAAS,GAAY;GACnB,IAAI,aAAa,cAAc,MAAM;GAErC,IAAI,aAAa,iBAAiB,MAAM;GAExC,MAAM,IAAI,MACR,qBAAqB,KAAK,UAAU,CAAC,EAAE,sDAAsD,KAAK,UAAU,aAAa,KAAK,UAAU,KAAK,OAAO,GACtJ;EACF;EAEA,MAAM,KAAK,eAAe;GAAE;GAAI;EAAK,GAAG,OAAO,KAAK,WAAW,KAAK,UAAU,GAAG,OAAO;CAC1F;CAEA,MAAa,SAAS,MAAoB,SAAsB;EAC9D,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,sBAAA,CAAoC,KAAK,EAAE;EAC7D,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,IAAI,kBAAkBA,wBAAAA,cACpB,MAAM,OAAO,SACX;GACE,YAAY;GACZ,mBAAmB;GACnB,mBAAA;GACA,0BAAU,IAAI,WAAW,CAAC;EAC5B,IAAA,GAAA,0BAAA,mBAAA,CACmB,KAAK,MAAM,OAAO,CACvC;OAEA,MAAM,OAAO,KAAK,uBAAuB;GACvC,MAAM;IACJ,YAAY,SAAS,SAAS;IAC9B,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,SAAS;IACjD,mBAAmB;IACnB,UAAU;GACZ;GACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,KAAK,IAAI,EAAE;EACpD,CAAC;CAEL;;;CAIA,cAAsB,YAAoB,eAAmC;EAC3E,MAAM,WAAqB,CAAC;EAC5B,MAAM,WAAW,IAAI,IAAI,aAAa;EAEtC,KAAK,IAAI,IAAI,IAAI,KAAK,YAAY,KAChC,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,SAAS,KAAK,CAAC;EAGvC,OAAO;CACT;CAEA,MAAc,eACZ,EAAE,IAAI,QACN,gBACA,SACe;EACf,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,sBAAA,CAAoC,EAAE;EACxD,MAAM,SAAS,KAAK,KAAK,IAAI;EAE7B,IAAI,kBAAkBA,wBAAAA,cAAc;GAClC,MAAM,OAAO,eACX;IACE,YAAY;IACZ,mBAAmB;IACnB;GACF,IAAA,GAAA,0BAAA,mBAAA,CACmB,MAAM,OAAO,CAClC,CAAC,CAAC;GACF;EACF;EAEA,MAAM,OAAO,KAAK,8BAA8B;GAC9C,MAAM;IACJ,YAAY,SAAS,SAAS;IAC9B,oBAAA,GAAA,0BAAA,qBAAA,CAAwC,SAAS;IACjD,gBAAgB,eAAe,SAAS;GAC1C;GACA,SAAS,EAAE,IAAA,GAAA,0BAAA,yBAAA,CAA4B,IAAI,EAAE;EAC/C,CAAC;CAEH;AACF;AAEA,eAAe,cAAc,MAAc,YAAoB,UAAmC;CAChG,IAAI;CACJ,IAAI;EACF,IAAI,MAAME,iBAAG,KAAK,IAAI;EACtB,MAAM,MAAM,OAAO,WAAW,UAAU;EACxC,MAAM,MAAM,OAAO,UAAU;EAC7B,MAAM,IAAI,OAAO,MAAM,GAAG;EAC1B,MAAM,YAAY,MAAM,sBAAsB,GAAG,GAAG,KAAK,GAAG;EAE5D,OAAO,EAAE,SAAS,GAAG,SAAS;CAChC,SAAS,GAAY;EACnB,IAAI,KAAK,OAAO,MAAM,YAAY,UAAU,KAAK,EAAE,QAAQ,UACzD,MAAM,IAAI,mBAAmB,oBAAoB,KAAK,eAAe;EACvE,MAAM;CACR,UAAU;EACR,MAAM,GAAG,MAAM;CACjB;AACF;;;AAIA,eAAe,sBAAsB,GAAkB,GAAW,KAAa,UAAkB;CAC/F,IAAI,iBAAiB;CACrB,OAAO,iBAAiB,KAAK;EAC3B,MAAM,EAAE,cAAc,MAAM,EAAE,KAC5B,GACA,gBACA,MAAM,gBACN,WAAW,cACb;EACA,IAAI,cAAc,GAChB,MAAM,IAAI,cAAc,mCAAmC;EAE7D,kBAAkB;CACpB;CAEA,OAAO;AACT;AAEA,eAAe,mBAAmB,MAAc,mBAA2B;CACzE,MAAM,QAAQ,OAAO,KAAK,OAAO,MAAMA,iBAAG,KAAK,IAAI,EAAA,CAAG,UAAU,GAAI,CAAC;CACrE,IAAI,QAAQ,mBACV,MAAM,IAAI,WAAW,sCAAsC,kBAAkB,SAAS,MAAM,EAAE;AAElG;;;;AAKA,MAAM,2BAA2B;CAAC;CAAgB;CAAkB;AAAsB;AAE1F,SAAS,mBAAmB,MAAuB;CACjD,OAAO,yBAAyB,MAAM,SAAS,KAAK,SAAS,SAAS,KAAK,QAAQ,CAAC;AACtF;AAEA,SAAS,kBACP,YACA,MACA,SACA,MACA;CACA,IAAI,cAAc,KAAK;EACrB,IAAI,mBAAmB,IAAI,GACzB,MAAM,IAAI,aACR,+CAA+C,WAAW,UAC9C,KAAK,aAAa,KAAK,UAAU,OAAO,EAAE,SAAS,KAAK,WACtE;EAEF,MAAM,IAAI,gBACR,oCAAoC,WAAW,UACnC,KAAK,aAAa,KAAK,UAAU,OAAO,EAAE,SAAS,KAAK,WACtE;CACF;CAEA,IAAI,cAAc,KAChB,MAAM,IAAI,aACR,oCAAoC,WAAW,UACnC,KAAK,aAAa,KAAK,UAAU,OAAO,EAAE,SAAS,KAAK,WACtE;AAEJ;;AAGA,SAAS,wBAAwB,MAAsB;CACrD,MAAM,WAAWC,eAAAA,OAAO,IAAI;CAE5B,MAAM,SAAS,OAAO,MAAM,CAAC;CAE7B,OAAO,cAAc,UAAU,CAAC;CAChC,OAAO,OAAO,SAAS,QAAQ;AACjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","names":[],"sources":["../../src/clients/upload.ts"],"mappings":";;;;;;;;cA4Ba,UAAA,SAAmB,KAAA;EAC9B,IAAA;AAAA;AAAA,cAGW,aAAA,SAAsB,KAAA;EACjC,IAAA;AAAA;AAAA,cAGW,YAAA,SAAqB,KAAA;EAChC,IAAA;AAAA;;cAIW,kBAAA,SAA2B,KAAA;EACtC,IAAA;AAAA;AAAA,cAGW,eAAA,SAAwB,KAAA;EACnC,IAAA;AAAA;;AALF;;cAWa,YAAA;EAAA,SAKO,UAAA,EAAY,UAAA;EAAA,SAEZ,MAAA,EAAQ,QAAA;EAAA,iBANT,IAAA;cAGf,yBAAA,EAA2B,yBAAA,EACX,UAAA,EAAY,UAAA,EAC5B,CAAA,EAAG,QAAA,EACa,MAAA,EAAQ,QAAA;EAgB1B,KAAA,CAAA;EAEa,UAAA,CAAA;IACT,EAAA;IAAI;EAAA,GAAQ,YAAA,EACd,OAAA,GAAU,UAAA,GACT,OAAA;IACD,OAAA;IACA,QAAA;IACA,iBAAA,EAAmB,2BAAA;IACnB,cAAA;EAAA;EAuCW,UAAA,CAAA;IACT,EAAA;IAAI;EAAA,GAAQ,YAAA,EACd,IAAA,UACA,iBAAA,UACA,UAAA,UACA,iBAAA,EAAmB,2BAAA,EACnB,cAAA,UACA,OAAA,GAAU,UAAA,GAAU,OAAA;EAoGT,QAAA,CAAS,IAAA,EAAM,YAAA,EAAc,OAAA,GAAU,UAAA,GAAU,OAAA;EA7KhC;;EAAA,QA0MtB,aAAA;EAAA,QAWM,cAAA;AAAA"}
1
+ {"version":3,"file":"upload.d.ts","names":[],"sources":["../../src/clients/upload.ts"],"mappings":";;;;;;;;cA4Ba,UAAA,SAAmB,KAAK;EACnC,IAAI;AAAA;AAAA,cAGO,aAAA,SAAsB,KAAK;EACtC,IAAI;AAAA;AAAA,cAGO,YAAA,SAAqB,KAAK;EACrC,IAAI;AAAA;;cAIO,kBAAA,SAA2B,KAAK;EAC3C,IAAI;AAAA;AAAA,cAGO,eAAA,SAAwB,KAAK;EACxC,IAAI;AAAA;AATA;AAIN;;AAJM,cAeO,YAAA;EAAA,SAKO,UAAA,EAAY,UAAA;EAAA,SAEZ,MAAA,EAAQ,QAAA;EAAA,iBANT,IAAA;cAGf,yBAAA,EAA2B,yBAAA,EACX,UAAA,EAAY,UAAA,EAC5B,CAAA,EAAG,QAAA,EACa,MAAA,EAAQ,QAAA;EAgB1B,KAAA;EAEa,UAAA;IACT,EAAA;IAAI;EAAA,GAAQ,YAAA,EACd,OAAA,GAAU,UAAA,GACT,OAAA;IACD,OAAA;IACA,QAAA;IACA,iBAAA,EAAmB,2BAAA;IACnB,cAAA;EAAA;EAuCW,UAAA;IACT,EAAA;IAAI;EAAA,GAAQ,YAAA,EACd,IAAA,UACA,iBAAA,UACA,UAAA,UACA,iBAAA,EAAmB,2BAAA,EACnB,cAAA,UACA,OAAA,GAAU,UAAA,GAAU,OAAA;EAoGT,QAAA,CAAS,IAAA,EAAM,YAAA,EAAc,OAAA,GAAU,UAAA,GAAU,OAAA;EA7KhC;;EAAA,QA0MtB,aAAA;EAAA,QAWM,cAAA;AAAA"}
@@ -1,4 +1,4 @@
1
- import { UploadAPI_ChecksumAlgorithm } from "../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js";
1
+ import "../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js";
2
2
  import { UploadClient } from "../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.js";
3
3
  import { crc32c } from "./crc32c.js";
4
4
  import { RestAPI, addRTypeToMetadata, createRTypeRoutingHeader, parseSignedResourceId, signatureToBase64Url } from "@milaboratories/pl-client";
@@ -25,6 +25,8 @@ var BadRequestError = class extends Error {
25
25
  * The user should pass here a concrete BlobUpload/<storageId> resource,
26
26
  * it can be got from handle field of BlobUpload. */
27
27
  var ClientUpload = class {
28
+ httpClient;
29
+ logger;
28
30
  wire;
29
31
  constructor(wireClientProviderFactory, httpClient, _, logger) {
30
32
  this.httpClient = httpClient;
@@ -103,7 +105,7 @@ var ClientUpload = class {
103
105
  }
104
106
  const chunk = await readFileChunk(path, info.chunkStart, info.chunkEnd);
105
107
  await checkExpectedMTime(path, expectedMTimeUnix);
106
- if (checksumHeader && checksumAlgorithm === UploadAPI_ChecksumAlgorithm.CRC32C) info.headers.push({
108
+ if (checksumHeader && checksumAlgorithm === 1) info.headers.push({
107
109
  name: checksumHeader,
108
110
  value: calculateCrc32cChecksum(chunk)
109
111
  });
@@ -137,8 +139,8 @@ var ClientUpload = class {
137
139
  if (client instanceof UploadClient) await client.finalize({
138
140
  resourceId: globalId,
139
141
  resourceSignature: signature,
140
- checksumAlgorithm: UploadAPI_ChecksumAlgorithm.UNSPECIFIED,
141
- checksum: new Uint8Array(0)
142
+ checksumAlgorithm: 0,
143
+ checksum: /* @__PURE__ */ new Uint8Array(0)
142
144
  }, addRTypeToMetadata(info.type, options));
143
145
  else await client.POST("/v1/upload/finalize", {
144
146
  body: {
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","names":[],"sources":["../../src/clients/upload.ts"],"sourcesContent":["import type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs/promises\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport {\n UploadAPI_ChecksumAlgorithm,\n type UploadAPI_GetPartURL_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol\";\nimport { UploadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client\";\nimport type { UploadApiPaths, UploadRestClientType } from \"../proto-rest\";\nimport { crc32c } from \"./crc32c\";\n\nimport type { IncomingHttpHeaders } from \"undici/types/header\";\n\nexport class MTimeError extends Error {\n name = \"MTimeError\";\n}\n\nexport class UnexpectedEOF extends Error {\n name = \"UnexpectedEOF\";\n}\n\nexport class NetworkError extends Error {\n name = \"NetworkError\";\n}\n\n/** Happens when the file doesn't exist */\nexport class NoFileForUploading extends Error {\n name = \"NoFileForUploading\";\n}\n\nexport class BadRequestError extends Error {\n name = \"BadRequestError\";\n}\n\n/** Low-level client for grpc uploadapi.\n * The user should pass here a concrete BlobUpload/<storageId> resource,\n * it can be got from handle field of BlobUpload. */\nexport class ClientUpload {\n private readonly wire: WireClientProvider<UploadRestClientType | UploadClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n _: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new UploadClient(wire.Transport);\n }\n\n return RestAPI.createClient<UploadApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async initUpload(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n ): Promise<{\n overall: bigint;\n toUpload: bigint[];\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm;\n checksumHeader: string;\n }> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n const init = (\n await client.init(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n )\n ).response;\n\n return {\n overall: init.partsCount,\n toUpload: this.partsToUpload(init.partsCount, init.uploadedParts),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n const init = (\n await client.POST(\"/v1/upload/init\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n\n return {\n overall: BigInt(init.partsCount),\n toUpload: this.partsToUpload(BigInt(init.partsCount), init.uploadedParts.map(BigInt)),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n public async partUpload(\n { id, type }: ResourceInfo,\n path: string,\n expectedMTimeUnix: bigint,\n partNumber: bigint,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm,\n checksumHeader: string,\n options?: RpcOptions,\n ) {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n let info: UploadAPI_GetPartURL_Response;\n if (client instanceof UploadClient) {\n // partChecksum isn't used for now but protoc requires it to be set\n info = (\n await client.getPartURL(\n {\n resourceId: globalId,\n resourceSignature: signature,\n partNumber,\n uploadedPartSize: 0n,\n isInternalUse: false,\n partChecksum: \"\",\n },\n addRTypeToMetadata(type, options),\n )\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/upload/get-part-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n partNumber: partNumber.toString(),\n uploadedPartSize: \"0\",\n isInternalUse: false,\n partChecksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n info = {\n uploadUrl: resp.uploadUrl,\n method: resp.method,\n headers: resp.headers,\n chunkStart: BigInt(resp.chunkStart),\n chunkEnd: BigInt(resp.chunkEnd),\n };\n }\n\n const chunk = await readFileChunk(path, info.chunkStart, info.chunkEnd);\n await checkExpectedMTime(path, expectedMTimeUnix);\n\n if (checksumHeader && checksumAlgorithm === UploadAPI_ChecksumAlgorithm.CRC32C) {\n info.headers.push({ name: checksumHeader, value: calculateCrc32cChecksum(chunk) });\n }\n\n const contentLength = Number(info.chunkEnd - info.chunkStart);\n if (chunk.length !== contentLength) {\n throw new Error(\n `Chunk size mismatch: expected ${contentLength} bytes, but read ${chunk.length} bytes from file`,\n );\n }\n\n const headers = Object.fromEntries(\n info.headers.map(({ name, value }) => [name.toLowerCase(), value]),\n );\n\n try {\n const {\n body: rawBody,\n statusCode,\n headers: responseHeaders,\n } = await request(info.uploadUrl, {\n dispatcher: this.httpClient,\n body: chunk,\n // We got headers only after we send\n // the whole body (in case of S3 PUT requests it's 5 MB).\n // It might be slow with a slow connection (or with SSH),\n // that's why we got big timeout here.\n headersTimeout: 60000,\n bodyTimeout: 60000,\n // Prevent connection reuse by setting \"Connection: close\" header.\n // This works around an issue with the backend's built-in S3 implementation\n // that caused HTTP/1.1 protocol lines to be included in the uploaded file content.\n reset: true,\n headers,\n method: info.method.toUpperCase() as Dispatcher.HttpMethod,\n });\n\n // always read the body for resources to be garbage collected.\n const body = await rawBody.text();\n checkStatusCodeOk(statusCode, body, responseHeaders, info);\n } catch (e: unknown) {\n if (e instanceof NetworkError) throw e;\n\n if (e instanceof BadRequestError) throw e;\n\n throw new Error(\n `partUpload: error ${JSON.stringify(e)} happened while trying to do part upload to the url ${info.uploadUrl}, headers: ${JSON.stringify(info.headers)}`,\n );\n }\n\n await this.updateProgress({ id, type }, BigInt(info.chunkEnd - info.chunkStart), options);\n }\n\n public async finalize(info: ResourceInfo, options?: RpcOptions) {\n const { globalId, signature } = parseSignedResourceId(info.id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.finalize(\n {\n resourceId: globalId,\n resourceSignature: signature,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm.UNSPECIFIED,\n checksum: new Uint8Array(0),\n },\n addRTypeToMetadata(info.type, options),\n );\n } else {\n await client.POST(\"/v1/upload/finalize\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n checksumAlgorithm: 0,\n checksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(info.type) },\n });\n }\n }\n\n /** Calculates parts that need to be uploaded from the parts that were\n * already uploaded. */\n private partsToUpload(partsCount: bigint, uploadedParts: bigint[]): bigint[] {\n const toUpload: bigint[] = [];\n const uploaded = new Set(uploadedParts);\n\n for (let i = 1n; i <= partsCount; i++) {\n if (!uploaded.has(i)) toUpload.push(i);\n }\n\n return toUpload;\n }\n\n private async updateProgress(\n { id, type }: ResourceInfo,\n bytesProcessed: bigint,\n options?: RpcOptions,\n ): Promise<void> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.updateProgress(\n {\n resourceId: globalId,\n resourceSignature: signature,\n bytesProcessed,\n },\n addRTypeToMetadata(type, options),\n ).response;\n return;\n }\n\n await client.POST(\"/v1/upload/update-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n bytesProcessed: bytesProcessed.toString(),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n });\n return;\n }\n}\n\nasync function readFileChunk(path: string, chunkStart: bigint, chunkEnd: bigint): Promise<Buffer> {\n let f: fs.FileHandle | undefined;\n try {\n f = await fs.open(path);\n const len = Number(chunkEnd - chunkStart);\n const pos = Number(chunkStart);\n const b = Buffer.alloc(len);\n const bytesRead = await readBytesFromPosition(f, b, len, pos);\n\n return b.subarray(0, bytesRead);\n } catch (e: unknown) {\n if (e && typeof e === \"object\" && \"code\" in e && e.code == \"ENOENT\")\n throw new NoFileForUploading(`there is no file ${path} for uploading`);\n throw e;\n } finally {\n await f?.close();\n }\n}\n\n/** Read len bytes from a given position.\n * Without this, `FileHandle.read` can read less bytes than needed. */\nasync function readBytesFromPosition(f: fs.FileHandle, b: Buffer, len: number, position: number) {\n let bytesReadTotal = 0;\n while (bytesReadTotal < len) {\n const { bytesRead } = await f.read(\n b,\n bytesReadTotal,\n len - bytesReadTotal,\n position + bytesReadTotal,\n );\n if (bytesRead === 0) {\n throw new UnexpectedEOF(\"file ended earlier than expected.\");\n }\n bytesReadTotal += bytesRead;\n }\n\n return bytesReadTotal;\n}\n\nasync function checkExpectedMTime(path: string, expectedMTimeUnix: bigint) {\n const mTime = BigInt(Math.floor((await fs.stat(path)).mtimeMs / 1000));\n if (mTime > expectedMTimeUnix) {\n throw new MTimeError(`file was modified, expected mtime: ${expectedMTimeUnix}, got: ${mTime}.`);\n }\n}\n\n/** S3 error codes that indicate expired/invalid temporary credentials.\n * These are transient: a retry with a fresh presigned URL will succeed\n * once the backend refreshes its STS credentials. */\nconst TRANSIENT_S3_ERROR_CODES = [\"ExpiredToken\", \"RequestExpired\", \"TokenRefreshRequired\"];\n\nfunction isTransientS3Error(body: string): boolean {\n return TRANSIENT_S3_ERROR_CODES.some((code) => body.includes(`<Code>${code}</Code>`));\n}\n\nfunction checkStatusCodeOk(\n statusCode: number,\n body: string,\n headers: IncomingHttpHeaders,\n info: UploadAPI_GetPartURL_Response,\n) {\n if (statusCode == 400) {\n if (isTransientS3Error(body)) {\n throw new NetworkError(\n `transient S3 credential error, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n throw new BadRequestError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n\n if (statusCode != 200) {\n throw new NetworkError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n}\n\n/** Calculate CRC32C checksum of a buffer and return as base64 string */\nfunction calculateCrc32cChecksum(data: Buffer): string {\n const checksum = crc32c(data);\n // Convert to unsigned 32-bit integer and then to base64\n const buffer = Buffer.alloc(4);\n\n buffer.writeUInt32BE(checksum, 0);\n return buffer.toString(\"base64\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"upload.js","names":[],"sources":["../../src/clients/upload.ts"],"sourcesContent":["import type {\n WireClientProvider,\n WireClientProviderFactory,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n createRTypeRoutingHeader,\n RestAPI,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs/promises\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport {\n UploadAPI_ChecksumAlgorithm,\n type UploadAPI_GetPartURL_Response,\n} from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol\";\nimport { UploadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client\";\nimport type { UploadApiPaths, UploadRestClientType } from \"../proto-rest\";\nimport { crc32c } from \"./crc32c\";\n\nimport type { IncomingHttpHeaders } from \"undici/types/header\";\n\nexport class MTimeError extends Error {\n name = \"MTimeError\";\n}\n\nexport class UnexpectedEOF extends Error {\n name = \"UnexpectedEOF\";\n}\n\nexport class NetworkError extends Error {\n name = \"NetworkError\";\n}\n\n/** Happens when the file doesn't exist */\nexport class NoFileForUploading extends Error {\n name = \"NoFileForUploading\";\n}\n\nexport class BadRequestError extends Error {\n name = \"BadRequestError\";\n}\n\n/** Low-level client for grpc uploadapi.\n * The user should pass here a concrete BlobUpload/<storageId> resource,\n * it can be got from handle field of BlobUpload. */\nexport class ClientUpload {\n private readonly wire: WireClientProvider<UploadRestClientType | UploadClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n _: PlClient,\n public readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wire) => {\n if (wire.type === \"grpc\") {\n return new UploadClient(wire.Transport);\n }\n\n return RestAPI.createClient<UploadApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n });\n }\n\n close() {}\n\n public async initUpload(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n ): Promise<{\n overall: bigint;\n toUpload: bigint[];\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm;\n checksumHeader: string;\n }> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n const init = (\n await client.init(\n { resourceId: globalId, resourceSignature: signature },\n addRTypeToMetadata(type, options),\n )\n ).response;\n\n return {\n overall: init.partsCount,\n toUpload: this.partsToUpload(init.partsCount, init.uploadedParts),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n const init = (\n await client.POST(\"/v1/upload/init\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n\n return {\n overall: BigInt(init.partsCount),\n toUpload: this.partsToUpload(BigInt(init.partsCount), init.uploadedParts.map(BigInt)),\n checksumAlgorithm: init.checksumAlgorithm,\n checksumHeader: init.checksumHeader,\n };\n }\n\n public async partUpload(\n { id, type }: ResourceInfo,\n path: string,\n expectedMTimeUnix: bigint,\n partNumber: bigint,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm,\n checksumHeader: string,\n options?: RpcOptions,\n ) {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n let info: UploadAPI_GetPartURL_Response;\n if (client instanceof UploadClient) {\n // partChecksum isn't used for now but protoc requires it to be set\n info = (\n await client.getPartURL(\n {\n resourceId: globalId,\n resourceSignature: signature,\n partNumber,\n uploadedPartSize: 0n,\n isInternalUse: false,\n partChecksum: \"\",\n },\n addRTypeToMetadata(type, options),\n )\n ).response;\n } else {\n const resp = (\n await client.POST(\"/v1/upload/get-part-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n partNumber: partNumber.toString(),\n uploadedPartSize: \"0\",\n isInternalUse: false,\n partChecksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n info = {\n uploadUrl: resp.uploadUrl,\n method: resp.method,\n headers: resp.headers,\n chunkStart: BigInt(resp.chunkStart),\n chunkEnd: BigInt(resp.chunkEnd),\n };\n }\n\n const chunk = await readFileChunk(path, info.chunkStart, info.chunkEnd);\n await checkExpectedMTime(path, expectedMTimeUnix);\n\n if (checksumHeader && checksumAlgorithm === UploadAPI_ChecksumAlgorithm.CRC32C) {\n info.headers.push({ name: checksumHeader, value: calculateCrc32cChecksum(chunk) });\n }\n\n const contentLength = Number(info.chunkEnd - info.chunkStart);\n if (chunk.length !== contentLength) {\n throw new Error(\n `Chunk size mismatch: expected ${contentLength} bytes, but read ${chunk.length} bytes from file`,\n );\n }\n\n const headers = Object.fromEntries(\n info.headers.map(({ name, value }) => [name.toLowerCase(), value]),\n );\n\n try {\n const {\n body: rawBody,\n statusCode,\n headers: responseHeaders,\n } = await request(info.uploadUrl, {\n dispatcher: this.httpClient,\n body: chunk,\n // We got headers only after we send\n // the whole body (in case of S3 PUT requests it's 5 MB).\n // It might be slow with a slow connection (or with SSH),\n // that's why we got big timeout here.\n headersTimeout: 60000,\n bodyTimeout: 60000,\n // Prevent connection reuse by setting \"Connection: close\" header.\n // This works around an issue with the backend's built-in S3 implementation\n // that caused HTTP/1.1 protocol lines to be included in the uploaded file content.\n reset: true,\n headers,\n method: info.method.toUpperCase() as Dispatcher.HttpMethod,\n });\n\n // always read the body for resources to be garbage collected.\n const body = await rawBody.text();\n checkStatusCodeOk(statusCode, body, responseHeaders, info);\n } catch (e: unknown) {\n if (e instanceof NetworkError) throw e;\n\n if (e instanceof BadRequestError) throw e;\n\n throw new Error(\n `partUpload: error ${JSON.stringify(e)} happened while trying to do part upload to the url ${info.uploadUrl}, headers: ${JSON.stringify(info.headers)}`,\n );\n }\n\n await this.updateProgress({ id, type }, BigInt(info.chunkEnd - info.chunkStart), options);\n }\n\n public async finalize(info: ResourceInfo, options?: RpcOptions) {\n const { globalId, signature } = parseSignedResourceId(info.id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.finalize(\n {\n resourceId: globalId,\n resourceSignature: signature,\n checksumAlgorithm: UploadAPI_ChecksumAlgorithm.UNSPECIFIED,\n checksum: new Uint8Array(0),\n },\n addRTypeToMetadata(info.type, options),\n );\n } else {\n await client.POST(\"/v1/upload/finalize\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n checksumAlgorithm: 0,\n checksum: \"\",\n },\n headers: { ...createRTypeRoutingHeader(info.type) },\n });\n }\n }\n\n /** Calculates parts that need to be uploaded from the parts that were\n * already uploaded. */\n private partsToUpload(partsCount: bigint, uploadedParts: bigint[]): bigint[] {\n const toUpload: bigint[] = [];\n const uploaded = new Set(uploadedParts);\n\n for (let i = 1n; i <= partsCount; i++) {\n if (!uploaded.has(i)) toUpload.push(i);\n }\n\n return toUpload;\n }\n\n private async updateProgress(\n { id, type }: ResourceInfo,\n bytesProcessed: bigint,\n options?: RpcOptions,\n ): Promise<void> {\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n\n if (client instanceof UploadClient) {\n await client.updateProgress(\n {\n resourceId: globalId,\n resourceSignature: signature,\n bytesProcessed,\n },\n addRTypeToMetadata(type, options),\n ).response;\n return;\n }\n\n await client.POST(\"/v1/upload/update-progress\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n bytesProcessed: bytesProcessed.toString(),\n },\n headers: { ...createRTypeRoutingHeader(type) },\n });\n return;\n }\n}\n\nasync function readFileChunk(path: string, chunkStart: bigint, chunkEnd: bigint): Promise<Buffer> {\n let f: fs.FileHandle | undefined;\n try {\n f = await fs.open(path);\n const len = Number(chunkEnd - chunkStart);\n const pos = Number(chunkStart);\n const b = Buffer.alloc(len);\n const bytesRead = await readBytesFromPosition(f, b, len, pos);\n\n return b.subarray(0, bytesRead);\n } catch (e: unknown) {\n if (e && typeof e === \"object\" && \"code\" in e && e.code == \"ENOENT\")\n throw new NoFileForUploading(`there is no file ${path} for uploading`);\n throw e;\n } finally {\n await f?.close();\n }\n}\n\n/** Read len bytes from a given position.\n * Without this, `FileHandle.read` can read less bytes than needed. */\nasync function readBytesFromPosition(f: fs.FileHandle, b: Buffer, len: number, position: number) {\n let bytesReadTotal = 0;\n while (bytesReadTotal < len) {\n const { bytesRead } = await f.read(\n b,\n bytesReadTotal,\n len - bytesReadTotal,\n position + bytesReadTotal,\n );\n if (bytesRead === 0) {\n throw new UnexpectedEOF(\"file ended earlier than expected.\");\n }\n bytesReadTotal += bytesRead;\n }\n\n return bytesReadTotal;\n}\n\nasync function checkExpectedMTime(path: string, expectedMTimeUnix: bigint) {\n const mTime = BigInt(Math.floor((await fs.stat(path)).mtimeMs / 1000));\n if (mTime > expectedMTimeUnix) {\n throw new MTimeError(`file was modified, expected mtime: ${expectedMTimeUnix}, got: ${mTime}.`);\n }\n}\n\n/** S3 error codes that indicate expired/invalid temporary credentials.\n * These are transient: a retry with a fresh presigned URL will succeed\n * once the backend refreshes its STS credentials. */\nconst TRANSIENT_S3_ERROR_CODES = [\"ExpiredToken\", \"RequestExpired\", \"TokenRefreshRequired\"];\n\nfunction isTransientS3Error(body: string): boolean {\n return TRANSIENT_S3_ERROR_CODES.some((code) => body.includes(`<Code>${code}</Code>`));\n}\n\nfunction checkStatusCodeOk(\n statusCode: number,\n body: string,\n headers: IncomingHttpHeaders,\n info: UploadAPI_GetPartURL_Response,\n) {\n if (statusCode == 400) {\n if (isTransientS3Error(body)) {\n throw new NetworkError(\n `transient S3 credential error, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n throw new BadRequestError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n\n if (statusCode != 200) {\n throw new NetworkError(\n `response is not ok, status code: ${statusCode},` +\n ` body: ${body}, headers: ${JSON.stringify(headers)}, url: ${info.uploadUrl}`,\n );\n }\n}\n\n/** Calculate CRC32C checksum of a buffer and return as base64 string */\nfunction calculateCrc32cChecksum(data: Buffer): string {\n const checksum = crc32c(data);\n // Convert to unsigned 32-bit integer and then to base64\n const buffer = Buffer.alloc(4);\n\n buffer.writeUInt32BE(checksum, 0);\n return buffer.toString(\"base64\");\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
2
2
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
3
3
  let node_path = require("node:path");
4
- node_path = require_runtime.__toESM(node_path);
4
+ node_path = require_runtime.__toESM(node_path, 1);
5
5
  //#region src/drivers/download_blob/blob_key.ts
6
6
  function blobKey(rId) {
7
7
  const { globalId } = (0, _milaboratories_pl_client.parseSignedResourceId)(rId);
@@ -1 +1 @@
1
- {"version":3,"file":"blob_key.cjs","names":["path"],"sources":["../../../src/drivers/download_blob/blob_key.ts"],"sourcesContent":["import { parseSignedResourceId, SignedResourceId } from \"@milaboratories/pl-client\";\nimport * as path from \"node:path\";\n\nexport function blobKey(rId: SignedResourceId): string {\n const { globalId } = parseSignedResourceId(rId);\n return `${globalId}`;\n}\n\nexport function pathToKey(fPath: string): string {\n return path.basename(fPath);\n}\n"],"mappings":";;;;;AAGA,SAAgB,QAAQ,KAA+B;CACrD,MAAM,EAAE,cAAA,GAAA,0BAAA,uBAAmC,IAAI;AAC/C,QAAO,GAAG;;AAGZ,SAAgB,UAAU,OAAuB;AAC/C,QAAOA,UAAK,SAAS,MAAM"}
1
+ {"version":3,"file":"blob_key.cjs","names":["path"],"sources":["../../../src/drivers/download_blob/blob_key.ts"],"sourcesContent":["import { parseSignedResourceId, SignedResourceId } from \"@milaboratories/pl-client\";\nimport * as path from \"node:path\";\n\nexport function blobKey(rId: SignedResourceId): string {\n const { globalId } = parseSignedResourceId(rId);\n return `${globalId}`;\n}\n\nexport function pathToKey(fPath: string): string {\n return path.basename(fPath);\n}\n"],"mappings":";;;;;AAGA,SAAgB,QAAQ,KAA+B;CACrD,MAAM,EAAE,cAAA,GAAA,0BAAA,sBAAA,CAAmC,GAAG;CAC9C,OAAO,GAAG;AACZ;AAEA,SAAgB,UAAU,OAAuB;CAC/C,OAAOA,UAAK,SAAS,KAAK;AAC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"blob_key.js","names":["path"],"sources":["../../../src/drivers/download_blob/blob_key.ts"],"sourcesContent":["import { parseSignedResourceId, SignedResourceId } from \"@milaboratories/pl-client\";\nimport * as path from \"node:path\";\n\nexport function blobKey(rId: SignedResourceId): string {\n const { globalId } = parseSignedResourceId(rId);\n return `${globalId}`;\n}\n\nexport function pathToKey(fPath: string): string {\n return path.basename(fPath);\n}\n"],"mappings":";;;AAGA,SAAgB,QAAQ,KAA+B;CACrD,MAAM,EAAE,aAAa,sBAAsB,IAAI;AAC/C,QAAO,GAAG;;AAGZ,SAAgB,UAAU,OAAuB;AAC/C,QAAOA,OAAK,SAAS,MAAM"}
1
+ {"version":3,"file":"blob_key.js","names":["path"],"sources":["../../../src/drivers/download_blob/blob_key.ts"],"sourcesContent":["import { parseSignedResourceId, SignedResourceId } from \"@milaboratories/pl-client\";\nimport * as path from \"node:path\";\n\nexport function blobKey(rId: SignedResourceId): string {\n const { globalId } = parseSignedResourceId(rId);\n return `${globalId}`;\n}\n\nexport function pathToKey(fPath: string): string {\n return path.basename(fPath);\n}\n"],"mappings":";;;AAGA,SAAgB,QAAQ,KAA+B;CACrD,MAAM,EAAE,aAAa,sBAAsB,GAAG;CAC9C,OAAO,GAAG;AACZ;AAEA,SAAgB,UAAU,OAAuB;CAC/C,OAAOA,OAAK,SAAS,KAAK;AAC5B"}