@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.
- package/dist/clients/constructors.cjs.map +1 -1
- package/dist/clients/constructors.js.map +1 -1
- package/dist/clients/crc32c.cjs.map +1 -1
- package/dist/clients/crc32c.js.map +1 -1
- package/dist/clients/download.cjs +56 -5
- package/dist/clients/download.cjs.map +1 -1
- package/dist/clients/download.d.ts +13 -1
- package/dist/clients/download.d.ts.map +1 -1
- package/dist/clients/download.js +53 -2
- package/dist/clients/download.js.map +1 -1
- package/dist/clients/download_url_cache.cjs +3 -1
- package/dist/clients/download_url_cache.cjs.map +1 -1
- package/dist/clients/download_url_cache.js +2 -1
- package/dist/clients/download_url_cache.js.map +1 -1
- package/dist/clients/logs.cjs +2 -1
- package/dist/clients/logs.cjs.map +1 -1
- package/dist/clients/logs.d.ts.map +1 -1
- package/dist/clients/logs.js +2 -0
- package/dist/clients/logs.js.map +1 -1
- package/dist/clients/ls_api.cjs +1 -1
- package/dist/clients/ls_api.cjs.map +1 -1
- package/dist/clients/ls_api.d.ts.map +1 -1
- package/dist/clients/ls_api.js +1 -0
- package/dist/clients/ls_api.js.map +1 -1
- package/dist/clients/progress.cjs +2 -1
- package/dist/clients/progress.cjs.map +1 -1
- package/dist/clients/progress.d.ts.map +1 -1
- package/dist/clients/progress.js +2 -0
- package/dist/clients/progress.js.map +1 -1
- package/dist/clients/upload.cjs +7 -5
- package/dist/clients/upload.cjs.map +1 -1
- package/dist/clients/upload.d.ts.map +1 -1
- package/dist/clients/upload.js +6 -4
- package/dist/clients/upload.js.map +1 -1
- package/dist/drivers/download_blob/blob_key.cjs +1 -1
- package/dist/drivers/download_blob/blob_key.cjs.map +1 -1
- package/dist/drivers/download_blob/blob_key.js.map +1 -1
- package/dist/drivers/download_blob/download_blob.cjs +36 -7
- package/dist/drivers/download_blob/download_blob.cjs.map +1 -1
- package/dist/drivers/download_blob/download_blob.d.ts +9 -1
- package/dist/drivers/download_blob/download_blob.d.ts.map +1 -1
- package/dist/drivers/download_blob/download_blob.js +30 -1
- package/dist/drivers/download_blob/download_blob.js.map +1 -1
- package/dist/drivers/download_blob/download_blob_task.cjs +9 -3
- package/dist/drivers/download_blob/download_blob_task.cjs.map +1 -1
- package/dist/drivers/download_blob/download_blob_task.js +6 -1
- package/dist/drivers/download_blob/download_blob_task.js.map +1 -1
- package/dist/drivers/download_blob/sparse_cache/cache.cjs +9 -1
- package/dist/drivers/download_blob/sparse_cache/cache.cjs.map +1 -1
- package/dist/drivers/download_blob/sparse_cache/cache.js +8 -0
- package/dist/drivers/download_blob/sparse_cache/cache.js.map +1 -1
- package/dist/drivers/download_blob/sparse_cache/file.cjs +2 -1
- package/dist/drivers/download_blob/sparse_cache/file.cjs.map +1 -1
- package/dist/drivers/download_blob/sparse_cache/file.js +1 -1
- package/dist/drivers/download_blob/sparse_cache/file.js.map +1 -1
- package/dist/drivers/download_blob/sparse_cache/ranges.cjs +3 -1
- package/dist/drivers/download_blob/sparse_cache/ranges.cjs.map +1 -1
- package/dist/drivers/download_blob/sparse_cache/ranges.js +1 -1
- package/dist/drivers/download_blob/sparse_cache/ranges.js.map +1 -1
- package/dist/drivers/download_blob_url/driver.cjs +6 -1
- package/dist/drivers/download_blob_url/driver.cjs.map +1 -1
- package/dist/drivers/download_blob_url/driver.d.ts.map +1 -1
- package/dist/drivers/download_blob_url/driver.js +5 -0
- package/dist/drivers/download_blob_url/driver.js.map +1 -1
- package/dist/drivers/download_blob_url/driver_id.cjs +0 -1
- package/dist/drivers/download_blob_url/driver_id.cjs.map +1 -1
- package/dist/drivers/download_blob_url/driver_id.js.map +1 -1
- package/dist/drivers/download_blob_url/snapshot.cjs +0 -1
- package/dist/drivers/download_blob_url/snapshot.cjs.map +1 -1
- package/dist/drivers/download_blob_url/snapshot.d.ts +1 -2
- package/dist/drivers/download_blob_url/snapshot.d.ts.map +1 -1
- package/dist/drivers/download_blob_url/snapshot.js.map +1 -1
- package/dist/drivers/download_blob_url/task.cjs +14 -6
- package/dist/drivers/download_blob_url/task.cjs.map +1 -1
- package/dist/drivers/download_blob_url/task.d.ts +1 -1
- package/dist/drivers/download_blob_url/task.d.ts.map +1 -1
- package/dist/drivers/download_blob_url/task.js +8 -1
- package/dist/drivers/download_blob_url/task.js.map +1 -1
- package/dist/drivers/download_url/driver.cjs +41 -19
- package/dist/drivers/download_url/driver.cjs.map +1 -1
- package/dist/drivers/download_url/driver.d.ts +10 -5
- package/dist/drivers/download_url/driver.d.ts.map +1 -1
- package/dist/drivers/download_url/driver.js +40 -18
- package/dist/drivers/download_url/driver.js.map +1 -1
- package/dist/drivers/download_url/task.cjs +39 -23
- package/dist/drivers/download_url/task.cjs.map +1 -1
- package/dist/drivers/download_url/task.d.ts +20 -6
- package/dist/drivers/download_url/task.d.ts.map +1 -1
- package/dist/drivers/download_url/task.js +36 -20
- package/dist/drivers/download_url/task.js.map +1 -1
- package/dist/drivers/helpers/download_local_handle.cjs.map +1 -1
- package/dist/drivers/helpers/download_local_handle.js.map +1 -1
- package/dist/drivers/helpers/download_remote_handle.cjs +0 -1
- package/dist/drivers/helpers/download_remote_handle.cjs.map +1 -1
- package/dist/drivers/helpers/download_remote_handle.js.map +1 -1
- package/dist/drivers/helpers/files_cache.cjs +1 -1
- package/dist/drivers/helpers/files_cache.cjs.map +1 -1
- package/dist/drivers/helpers/files_cache.js +1 -0
- package/dist/drivers/helpers/files_cache.js.map +1 -1
- package/dist/drivers/helpers/helpers.cjs +1 -0
- package/dist/drivers/helpers/helpers.cjs.map +1 -1
- package/dist/drivers/helpers/helpers.d.ts.map +1 -1
- package/dist/drivers/helpers/helpers.js +1 -0
- package/dist/drivers/helpers/helpers.js.map +1 -1
- package/dist/drivers/helpers/logs_handle.cjs +3 -1
- package/dist/drivers/helpers/logs_handle.cjs.map +1 -1
- package/dist/drivers/helpers/logs_handle.js +1 -1
- package/dist/drivers/helpers/logs_handle.js.map +1 -1
- package/dist/drivers/helpers/ls_remote_import_handle.cjs.map +1 -1
- package/dist/drivers/helpers/ls_remote_import_handle.js.map +1 -1
- package/dist/drivers/helpers/ls_storage_entry.cjs +2 -1
- package/dist/drivers/helpers/ls_storage_entry.cjs.map +1 -1
- package/dist/drivers/helpers/ls_storage_entry.js +1 -1
- package/dist/drivers/helpers/ls_storage_entry.js.map +1 -1
- package/dist/drivers/helpers/polling_ops.d.ts.map +1 -1
- package/dist/drivers/helpers/read_file.cjs +2 -2
- package/dist/drivers/helpers/read_file.cjs.map +1 -1
- package/dist/drivers/helpers/read_file.js.map +1 -1
- package/dist/drivers/logs.cjs +3 -1
- package/dist/drivers/logs.cjs.map +1 -1
- package/dist/drivers/logs.js +3 -0
- package/dist/drivers/logs.js.map +1 -1
- package/dist/drivers/logs_stream.cjs +8 -1
- package/dist/drivers/logs_stream.cjs.map +1 -1
- package/dist/drivers/logs_stream.d.ts.map +1 -1
- package/dist/drivers/logs_stream.js +8 -0
- package/dist/drivers/logs_stream.js.map +1 -1
- package/dist/drivers/ls.cjs +10 -3
- package/dist/drivers/ls.cjs.map +1 -1
- package/dist/drivers/ls.d.ts.map +1 -1
- package/dist/drivers/ls.js +8 -1
- package/dist/drivers/ls.js.map +1 -1
- package/dist/drivers/types.cjs +10 -1
- package/dist/drivers/types.cjs.map +1 -1
- package/dist/drivers/types.d.ts +3 -4
- package/dist/drivers/types.d.ts.map +1 -1
- package/dist/drivers/types.js +10 -0
- package/dist/drivers/types.js.map +1 -1
- package/dist/drivers/upload.cjs +5 -1
- package/dist/drivers/upload.cjs.map +1 -1
- package/dist/drivers/upload.d.ts.map +1 -1
- package/dist/drivers/upload.js +5 -0
- package/dist/drivers/upload.js.map +1 -1
- package/dist/drivers/upload_task.cjs +6 -1
- package/dist/drivers/upload_task.cjs.map +1 -1
- package/dist/drivers/upload_task.d.ts.map +1 -1
- package/dist/drivers/upload_task.js +5 -0
- package/dist/drivers/upload_task.js.map +1 -1
- package/dist/drivers/urls/url.cjs +1 -1
- package/dist/drivers/urls/url.cjs.map +1 -1
- package/dist/drivers/urls/url.js.map +1 -1
- package/dist/drivers/virtual_storages.cjs +3 -3
- package/dist/drivers/virtual_storages.cjs.map +1 -1
- package/dist/drivers/virtual_storages.d.ts.map +1 -1
- package/dist/drivers/virtual_storages.js.map +1 -1
- package/dist/helpers/download.cjs +1 -1
- package/dist/helpers/download.cjs.map +1 -1
- package/dist/helpers/download.d.ts.map +1 -1
- package/dist/helpers/download.js +1 -0
- package/dist/helpers/download.js.map +1 -1
- package/dist/helpers/download_errors.cjs.map +1 -1
- package/dist/helpers/download_errors.d.ts.map +1 -1
- package/dist/helpers/download_errors.js.map +1 -1
- package/dist/helpers/validate.cjs +1 -1
- package/dist/helpers/validate.cjs.map +1 -1
- package/dist/helpers/validate.d.ts.map +1 -1
- package/dist/helpers/validate.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.cjs +4 -2
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.cjs +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts +3 -5
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.js +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.js +7 -3
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.cjs +4 -2
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.cjs +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.js +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.js +7 -3
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.cjs +7 -3
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.cjs +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts +3 -5
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.js +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.js +3 -3
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.cjs +8 -5
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.cjs +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts +3 -5
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.js +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.js +5 -5
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs +17 -7
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.cjs +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.js +1 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js +7 -7
- package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js.map +1 -1
- package/dist/proto-grpc/google/protobuf/duration.cjs +0 -1
- package/dist/proto-grpc/google/protobuf/duration.cjs.map +1 -1
- package/dist/proto-grpc/google/protobuf/duration.d.ts.map +1 -1
- package/dist/proto-grpc/google/protobuf/duration.js.map +1 -1
- package/dist/proto-grpc/google/protobuf/timestamp.cjs +0 -1
- package/dist/proto-grpc/google/protobuf/timestamp.cjs.map +1 -1
- package/dist/proto-grpc/google/protobuf/timestamp.d.ts.map +1 -1
- package/dist/proto-grpc/google/protobuf/timestamp.js.map +1 -1
- package/dist/proto-rest/downloadapi.d.ts +1 -1
- package/dist/proto-rest/downloadapi.d.ts.map +1 -1
- package/dist/proto-rest/index.d.ts +1 -1
- package/dist/proto-rest/index.d.ts.map +1 -1
- package/dist/proto-rest/progressapi.d.ts +1 -1
- package/dist/proto-rest/progressapi.d.ts.map +1 -1
- package/dist/proto-rest/streamingapi.d.ts +1 -1
- package/dist/proto-rest/streamingapi.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/clients/download.ts +71 -3
- package/src/drivers/download_blob/download_blob.ts +30 -1
- package/src/drivers/download_url/driver.ts +44 -19
- package/src/drivers/download_url/get_local_tgz.test.ts +106 -0
- package/src/drivers/download_url/task.ts +53 -30
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructors.cjs","names":["ClientDownload","ClientLogs","ClientProgress","ClientUpload","ClientLs"],"sources":["../../src/clients/constructors.ts"],"sourcesContent":["import type { WireClientProviderFactory, PlClient } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ClientDownload } from \"./download\";\nimport { ClientLogs } from \"./logs\";\nimport { ClientProgress } from \"./progress\";\nimport { ClientUpload } from \"./upload\";\nimport { ClientLs } from \"./ls_api\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\n\nexport function createDownloadClient(\n logger: MiLogger,\n client: PlClient,\n localProjections: LocalStorageProjection[],\n) {\n return client.getDriver({\n name: \"DownloadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientDownload(wireClientFactory, httpDispatcher, logger, localProjections),\n });\n}\n\nexport function createLogsClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"StreamLogs\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientLogs(wireClientFactory, httpDispatcher, logger),\n });\n}\n\nexport function createUploadProgressClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadProgress\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientProgress(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createUploadBlobClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientUpload(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createLsFilesClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"LsFiles\",\n init: (\n _client: PlClient,\n wireClientFactory: WireClientProviderFactory,\n _httpDispatcher: Dispatcher,\n ) => new ClientLs(wireClientFactory, logger),\n });\n}\n"],"mappings":";;;;;;AAUA,SAAgB,qBACd,QACA,QACA,kBACA;
|
|
1
|
+
{"version":3,"file":"constructors.cjs","names":["ClientDownload","ClientLogs","ClientProgress","ClientUpload","ClientLs"],"sources":["../../src/clients/constructors.ts"],"sourcesContent":["import type { WireClientProviderFactory, PlClient } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ClientDownload } from \"./download\";\nimport { ClientLogs } from \"./logs\";\nimport { ClientProgress } from \"./progress\";\nimport { ClientUpload } from \"./upload\";\nimport { ClientLs } from \"./ls_api\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\n\nexport function createDownloadClient(\n logger: MiLogger,\n client: PlClient,\n localProjections: LocalStorageProjection[],\n) {\n return client.getDriver({\n name: \"DownloadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientDownload(wireClientFactory, httpDispatcher, logger, localProjections),\n });\n}\n\nexport function createLogsClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"StreamLogs\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientLogs(wireClientFactory, httpDispatcher, logger),\n });\n}\n\nexport function createUploadProgressClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadProgress\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientProgress(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createUploadBlobClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientUpload(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createLsFilesClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"LsFiles\",\n init: (\n _client: PlClient,\n wireClientFactory: WireClientProviderFactory,\n _httpDispatcher: Dispatcher,\n ) => new ClientLs(wireClientFactory, logger),\n });\n}\n"],"mappings":";;;;;;AAUA,SAAgB,qBACd,QACA,QACA,kBACA;CACA,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAIA,iBAAAA,eAAe,mBAAmB,gBAAgB,QAAQ,gBAAgB;CAClF,CAAC;AACH;AAEA,SAAgB,iBAAiB,QAAkB,QAAkB;CACnE,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAIC,aAAAA,WAAW,mBAAmB,gBAAgB,MAAM;CAC5D,CAAC;AACH;AAEA,SAAgB,2BAA2B,QAAkB,QAAkB;CAC7E,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAIC,iBAAAA,eAAe,mBAAmB,gBAAgB,QAAQ,MAAM;CACxE,CAAC;AACH;AAEA,SAAgB,uBAAuB,QAAkB,QAAkB;CACzE,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAIC,eAAAA,aAAa,mBAAmB,gBAAgB,QAAQ,MAAM;CACtE,CAAC;AACH;AAEA,SAAgB,oBAAoB,QAAkB,QAAkB;CACtE,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OACE,SACA,mBACA,oBACG,IAAIC,eAAAA,SAAS,mBAAmB,MAAM;CAC7C,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructors.js","names":[],"sources":["../../src/clients/constructors.ts"],"sourcesContent":["import type { WireClientProviderFactory, PlClient } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ClientDownload } from \"./download\";\nimport { ClientLogs } from \"./logs\";\nimport { ClientProgress } from \"./progress\";\nimport { ClientUpload } from \"./upload\";\nimport { ClientLs } from \"./ls_api\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\n\nexport function createDownloadClient(\n logger: MiLogger,\n client: PlClient,\n localProjections: LocalStorageProjection[],\n) {\n return client.getDriver({\n name: \"DownloadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientDownload(wireClientFactory, httpDispatcher, logger, localProjections),\n });\n}\n\nexport function createLogsClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"StreamLogs\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientLogs(wireClientFactory, httpDispatcher, logger),\n });\n}\n\nexport function createUploadProgressClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadProgress\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientProgress(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createUploadBlobClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientUpload(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createLsFilesClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"LsFiles\",\n init: (\n _client: PlClient,\n wireClientFactory: WireClientProviderFactory,\n _httpDispatcher: Dispatcher,\n ) => new ClientLs(wireClientFactory, logger),\n });\n}\n"],"mappings":";;;;;;AAUA,SAAgB,qBACd,QACA,QACA,kBACA;
|
|
1
|
+
{"version":3,"file":"constructors.js","names":[],"sources":["../../src/clients/constructors.ts"],"sourcesContent":["import type { WireClientProviderFactory, PlClient } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { Dispatcher } from \"undici\";\nimport { ClientDownload } from \"./download\";\nimport { ClientLogs } from \"./logs\";\nimport { ClientProgress } from \"./progress\";\nimport { ClientUpload } from \"./upload\";\nimport { ClientLs } from \"./ls_api\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\n\nexport function createDownloadClient(\n logger: MiLogger,\n client: PlClient,\n localProjections: LocalStorageProjection[],\n) {\n return client.getDriver({\n name: \"DownloadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientDownload(wireClientFactory, httpDispatcher, logger, localProjections),\n });\n}\n\nexport function createLogsClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"StreamLogs\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientLogs(wireClientFactory, httpDispatcher, logger),\n });\n}\n\nexport function createUploadProgressClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadProgress\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientProgress(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createUploadBlobClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"UploadBlob\",\n init: (_: PlClient, wireClientFactory: WireClientProviderFactory, httpDispatcher: Dispatcher) =>\n new ClientUpload(wireClientFactory, httpDispatcher, client, logger),\n });\n}\n\nexport function createLsFilesClient(client: PlClient, logger: MiLogger) {\n return client.getDriver({\n name: \"LsFiles\",\n init: (\n _client: PlClient,\n wireClientFactory: WireClientProviderFactory,\n _httpDispatcher: Dispatcher,\n ) => new ClientLs(wireClientFactory, logger),\n });\n}\n"],"mappings":";;;;;;AAUA,SAAgB,qBACd,QACA,QACA,kBACA;CACA,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAI,eAAe,mBAAmB,gBAAgB,QAAQ,gBAAgB;CAClF,CAAC;AACH;AAEA,SAAgB,iBAAiB,QAAkB,QAAkB;CACnE,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAI,WAAW,mBAAmB,gBAAgB,MAAM;CAC5D,CAAC;AACH;AAEA,SAAgB,2BAA2B,QAAkB,QAAkB;CAC7E,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAI,eAAe,mBAAmB,gBAAgB,QAAQ,MAAM;CACxE,CAAC;AACH;AAEA,SAAgB,uBAAuB,QAAkB,QAAkB;CACzE,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OAAO,GAAa,mBAA8C,mBAChE,IAAI,aAAa,mBAAmB,gBAAgB,QAAQ,MAAM;CACtE,CAAC;AACH;AAEA,SAAgB,oBAAoB,QAAkB,QAAkB;CACtE,OAAO,OAAO,UAAU;EACtB,MAAM;EACN,OACE,SACA,mBACA,oBACG,IAAI,SAAS,mBAAmB,MAAM;CAC7C,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crc32c.cjs","names":[],"sources":["../../src/clients/crc32c.ts"],"sourcesContent":["// copy from https://github.com/ashi009/node-fast-crc32c/blob/master/impls/js_crc32c.js\n// can not use fast-crc32c because it try to use native solution that brokes in electron\nconst kCRCTable = Int32Array.of(\n 0x00000000,\n 0xf26b8303,\n 0xe13b70f7,\n 0x1350f3f4,\n 0xc79a971f,\n 0x35f1141c,\n 0x26a1e7e8,\n 0xd4ca64eb,\n 0x8ad958cf,\n 0x78b2dbcc,\n 0x6be22838,\n 0x9989ab3b,\n 0x4d43cfd0,\n 0xbf284cd3,\n 0xac78bf27,\n 0x5e133c24,\n 0x105ec76f,\n 0xe235446c,\n 0xf165b798,\n 0x030e349b,\n 0xd7c45070,\n 0x25afd373,\n 0x36ff2087,\n 0xc494a384,\n 0x9a879fa0,\n 0x68ec1ca3,\n 0x7bbcef57,\n 0x89d76c54,\n 0x5d1d08bf,\n 0xaf768bbc,\n 0xbc267848,\n 0x4e4dfb4b,\n 0x20bd8ede,\n 0xd2d60ddd,\n 0xc186fe29,\n 0x33ed7d2a,\n 0xe72719c1,\n 0x154c9ac2,\n 0x061c6936,\n 0xf477ea35,\n 0xaa64d611,\n 0x580f5512,\n 0x4b5fa6e6,\n 0xb93425e5,\n 0x6dfe410e,\n 0x9f95c20d,\n 0x8cc531f9,\n 0x7eaeb2fa,\n 0x30e349b1,\n 0xc288cab2,\n 0xd1d83946,\n 0x23b3ba45,\n 0xf779deae,\n 0x05125dad,\n 0x1642ae59,\n 0xe4292d5a,\n 0xba3a117e,\n 0x4851927d,\n 0x5b016189,\n 0xa96ae28a,\n 0x7da08661,\n 0x8fcb0562,\n 0x9c9bf696,\n 0x6ef07595,\n 0x417b1dbc,\n 0xb3109ebf,\n 0xa0406d4b,\n 0x522bee48,\n 0x86e18aa3,\n 0x748a09a0,\n 0x67dafa54,\n 0x95b17957,\n 0xcba24573,\n 0x39c9c670,\n 0x2a993584,\n 0xd8f2b687,\n 0x0c38d26c,\n 0xfe53516f,\n 0xed03a29b,\n 0x1f682198,\n 0x5125dad3,\n 0xa34e59d0,\n 0xb01eaa24,\n 0x42752927,\n 0x96bf4dcc,\n 0x64d4cecf,\n 0x77843d3b,\n 0x85efbe38,\n 0xdbfc821c,\n 0x2997011f,\n 0x3ac7f2eb,\n 0xc8ac71e8,\n 0x1c661503,\n 0xee0d9600,\n 0xfd5d65f4,\n 0x0f36e6f7,\n 0x61c69362,\n 0x93ad1061,\n 0x80fde395,\n 0x72966096,\n 0xa65c047d,\n 0x5437877e,\n 0x4767748a,\n 0xb50cf789,\n 0xeb1fcbad,\n 0x197448ae,\n 0x0a24bb5a,\n 0xf84f3859,\n 0x2c855cb2,\n 0xdeeedfb1,\n 0xcdbe2c45,\n 0x3fd5af46,\n 0x7198540d,\n 0x83f3d70e,\n 0x90a324fa,\n 0x62c8a7f9,\n 0xb602c312,\n 0x44694011,\n 0x5739b3e5,\n 0xa55230e6,\n 0xfb410cc2,\n 0x092a8fc1,\n 0x1a7a7c35,\n 0xe811ff36,\n 0x3cdb9bdd,\n 0xceb018de,\n 0xdde0eb2a,\n 0x2f8b6829,\n 0x82f63b78,\n 0x709db87b,\n 0x63cd4b8f,\n 0x91a6c88c,\n 0x456cac67,\n 0xb7072f64,\n 0xa457dc90,\n 0x563c5f93,\n 0x082f63b7,\n 0xfa44e0b4,\n 0xe9141340,\n 0x1b7f9043,\n 0xcfb5f4a8,\n 0x3dde77ab,\n 0x2e8e845f,\n 0xdce5075c,\n 0x92a8fc17,\n 0x60c37f14,\n 0x73938ce0,\n 0x81f80fe3,\n 0x55326b08,\n 0xa759e80b,\n 0xb4091bff,\n 0x466298fc,\n 0x1871a4d8,\n 0xea1a27db,\n 0xf94ad42f,\n 0x0b21572c,\n 0xdfeb33c7,\n 0x2d80b0c4,\n 0x3ed04330,\n 0xccbbc033,\n 0xa24bb5a6,\n 0x502036a5,\n 0x4370c551,\n 0xb11b4652,\n 0x65d122b9,\n 0x97baa1ba,\n 0x84ea524e,\n 0x7681d14d,\n 0x2892ed69,\n 0xdaf96e6a,\n 0xc9a99d9e,\n 0x3bc21e9d,\n 0xef087a76,\n 0x1d63f975,\n 0x0e330a81,\n 0xfc588982,\n 0xb21572c9,\n 0x407ef1ca,\n 0x532e023e,\n 0xa145813d,\n 0x758fe5d6,\n 0x87e466d5,\n 0x94b49521,\n 0x66df1622,\n 0x38cc2a06,\n 0xcaa7a905,\n 0xd9f75af1,\n 0x2b9cd9f2,\n 0xff56bd19,\n 0x0d3d3e1a,\n 0x1e6dcdee,\n 0xec064eed,\n 0xc38d26c4,\n 0x31e6a5c7,\n 0x22b65633,\n 0xd0ddd530,\n 0x0417b1db,\n 0xf67c32d8,\n 0xe52cc12c,\n 0x1747422f,\n 0x49547e0b,\n 0xbb3ffd08,\n 0xa86f0efc,\n 0x5a048dff,\n 0x8ecee914,\n 0x7ca56a17,\n 0x6ff599e3,\n 0x9d9e1ae0,\n 0xd3d3e1ab,\n 0x21b862a8,\n 0x32e8915c,\n 0xc083125f,\n 0x144976b4,\n 0xe622f5b7,\n 0xf5720643,\n 0x07198540,\n 0x590ab964,\n 0xab613a67,\n 0xb831c993,\n 0x4a5a4a90,\n 0x9e902e7b,\n 0x6cfbad78,\n 0x7fab5e8c,\n 0x8dc0dd8f,\n 0xe330a81a,\n 0x115b2b19,\n 0x020bd8ed,\n 0xf0605bee,\n 0x24aa3f05,\n 0xd6c1bc06,\n 0xc5914ff2,\n 0x37faccf1,\n 0x69e9f0d5,\n 0x9b8273d6,\n 0x88d28022,\n 0x7ab90321,\n 0xae7367ca,\n 0x5c18e4c9,\n 0x4f48173d,\n 0xbd23943e,\n 0xf36e6f75,\n 0x0105ec76,\n 0x12551f82,\n 0xe03e9c81,\n 0x34f4f86a,\n 0xc69f7b69,\n 0xd5cf889d,\n 0x27a40b9e,\n 0x79b737ba,\n 0x8bdcb4b9,\n 0x988c474d,\n 0x6ae7c44e,\n 0xbe2da0a5,\n 0x4c4623a6,\n 0x5f16d052,\n 0xad7d5351,\n);\n\nexport function crc32c(buf: Buffer | string, initial: number = 0) {\n if (!Buffer.isBuffer(buf)) {\n buf = Buffer.from(buf);\n }\n let crc = (initial | 0) ^ -1;\n for (let i = 0; i < buf.length; i++) {\n crc = kCRCTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ -1) >>> 0;\n}\n"],"mappings":";AAEA,MAAM,YAAY,WAAW,GAC3B,GACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,UACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,UACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,WACA,WACA,YACA,UACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,UACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,UACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,
|
|
1
|
+
{"version":3,"file":"crc32c.cjs","names":[],"sources":["../../src/clients/crc32c.ts"],"sourcesContent":["// copy from https://github.com/ashi009/node-fast-crc32c/blob/master/impls/js_crc32c.js\n// can not use fast-crc32c because it try to use native solution that brokes in electron\nconst kCRCTable = Int32Array.of(\n 0x00000000,\n 0xf26b8303,\n 0xe13b70f7,\n 0x1350f3f4,\n 0xc79a971f,\n 0x35f1141c,\n 0x26a1e7e8,\n 0xd4ca64eb,\n 0x8ad958cf,\n 0x78b2dbcc,\n 0x6be22838,\n 0x9989ab3b,\n 0x4d43cfd0,\n 0xbf284cd3,\n 0xac78bf27,\n 0x5e133c24,\n 0x105ec76f,\n 0xe235446c,\n 0xf165b798,\n 0x030e349b,\n 0xd7c45070,\n 0x25afd373,\n 0x36ff2087,\n 0xc494a384,\n 0x9a879fa0,\n 0x68ec1ca3,\n 0x7bbcef57,\n 0x89d76c54,\n 0x5d1d08bf,\n 0xaf768bbc,\n 0xbc267848,\n 0x4e4dfb4b,\n 0x20bd8ede,\n 0xd2d60ddd,\n 0xc186fe29,\n 0x33ed7d2a,\n 0xe72719c1,\n 0x154c9ac2,\n 0x061c6936,\n 0xf477ea35,\n 0xaa64d611,\n 0x580f5512,\n 0x4b5fa6e6,\n 0xb93425e5,\n 0x6dfe410e,\n 0x9f95c20d,\n 0x8cc531f9,\n 0x7eaeb2fa,\n 0x30e349b1,\n 0xc288cab2,\n 0xd1d83946,\n 0x23b3ba45,\n 0xf779deae,\n 0x05125dad,\n 0x1642ae59,\n 0xe4292d5a,\n 0xba3a117e,\n 0x4851927d,\n 0x5b016189,\n 0xa96ae28a,\n 0x7da08661,\n 0x8fcb0562,\n 0x9c9bf696,\n 0x6ef07595,\n 0x417b1dbc,\n 0xb3109ebf,\n 0xa0406d4b,\n 0x522bee48,\n 0x86e18aa3,\n 0x748a09a0,\n 0x67dafa54,\n 0x95b17957,\n 0xcba24573,\n 0x39c9c670,\n 0x2a993584,\n 0xd8f2b687,\n 0x0c38d26c,\n 0xfe53516f,\n 0xed03a29b,\n 0x1f682198,\n 0x5125dad3,\n 0xa34e59d0,\n 0xb01eaa24,\n 0x42752927,\n 0x96bf4dcc,\n 0x64d4cecf,\n 0x77843d3b,\n 0x85efbe38,\n 0xdbfc821c,\n 0x2997011f,\n 0x3ac7f2eb,\n 0xc8ac71e8,\n 0x1c661503,\n 0xee0d9600,\n 0xfd5d65f4,\n 0x0f36e6f7,\n 0x61c69362,\n 0x93ad1061,\n 0x80fde395,\n 0x72966096,\n 0xa65c047d,\n 0x5437877e,\n 0x4767748a,\n 0xb50cf789,\n 0xeb1fcbad,\n 0x197448ae,\n 0x0a24bb5a,\n 0xf84f3859,\n 0x2c855cb2,\n 0xdeeedfb1,\n 0xcdbe2c45,\n 0x3fd5af46,\n 0x7198540d,\n 0x83f3d70e,\n 0x90a324fa,\n 0x62c8a7f9,\n 0xb602c312,\n 0x44694011,\n 0x5739b3e5,\n 0xa55230e6,\n 0xfb410cc2,\n 0x092a8fc1,\n 0x1a7a7c35,\n 0xe811ff36,\n 0x3cdb9bdd,\n 0xceb018de,\n 0xdde0eb2a,\n 0x2f8b6829,\n 0x82f63b78,\n 0x709db87b,\n 0x63cd4b8f,\n 0x91a6c88c,\n 0x456cac67,\n 0xb7072f64,\n 0xa457dc90,\n 0x563c5f93,\n 0x082f63b7,\n 0xfa44e0b4,\n 0xe9141340,\n 0x1b7f9043,\n 0xcfb5f4a8,\n 0x3dde77ab,\n 0x2e8e845f,\n 0xdce5075c,\n 0x92a8fc17,\n 0x60c37f14,\n 0x73938ce0,\n 0x81f80fe3,\n 0x55326b08,\n 0xa759e80b,\n 0xb4091bff,\n 0x466298fc,\n 0x1871a4d8,\n 0xea1a27db,\n 0xf94ad42f,\n 0x0b21572c,\n 0xdfeb33c7,\n 0x2d80b0c4,\n 0x3ed04330,\n 0xccbbc033,\n 0xa24bb5a6,\n 0x502036a5,\n 0x4370c551,\n 0xb11b4652,\n 0x65d122b9,\n 0x97baa1ba,\n 0x84ea524e,\n 0x7681d14d,\n 0x2892ed69,\n 0xdaf96e6a,\n 0xc9a99d9e,\n 0x3bc21e9d,\n 0xef087a76,\n 0x1d63f975,\n 0x0e330a81,\n 0xfc588982,\n 0xb21572c9,\n 0x407ef1ca,\n 0x532e023e,\n 0xa145813d,\n 0x758fe5d6,\n 0x87e466d5,\n 0x94b49521,\n 0x66df1622,\n 0x38cc2a06,\n 0xcaa7a905,\n 0xd9f75af1,\n 0x2b9cd9f2,\n 0xff56bd19,\n 0x0d3d3e1a,\n 0x1e6dcdee,\n 0xec064eed,\n 0xc38d26c4,\n 0x31e6a5c7,\n 0x22b65633,\n 0xd0ddd530,\n 0x0417b1db,\n 0xf67c32d8,\n 0xe52cc12c,\n 0x1747422f,\n 0x49547e0b,\n 0xbb3ffd08,\n 0xa86f0efc,\n 0x5a048dff,\n 0x8ecee914,\n 0x7ca56a17,\n 0x6ff599e3,\n 0x9d9e1ae0,\n 0xd3d3e1ab,\n 0x21b862a8,\n 0x32e8915c,\n 0xc083125f,\n 0x144976b4,\n 0xe622f5b7,\n 0xf5720643,\n 0x07198540,\n 0x590ab964,\n 0xab613a67,\n 0xb831c993,\n 0x4a5a4a90,\n 0x9e902e7b,\n 0x6cfbad78,\n 0x7fab5e8c,\n 0x8dc0dd8f,\n 0xe330a81a,\n 0x115b2b19,\n 0x020bd8ed,\n 0xf0605bee,\n 0x24aa3f05,\n 0xd6c1bc06,\n 0xc5914ff2,\n 0x37faccf1,\n 0x69e9f0d5,\n 0x9b8273d6,\n 0x88d28022,\n 0x7ab90321,\n 0xae7367ca,\n 0x5c18e4c9,\n 0x4f48173d,\n 0xbd23943e,\n 0xf36e6f75,\n 0x0105ec76,\n 0x12551f82,\n 0xe03e9c81,\n 0x34f4f86a,\n 0xc69f7b69,\n 0xd5cf889d,\n 0x27a40b9e,\n 0x79b737ba,\n 0x8bdcb4b9,\n 0x988c474d,\n 0x6ae7c44e,\n 0xbe2da0a5,\n 0x4c4623a6,\n 0x5f16d052,\n 0xad7d5351,\n);\n\nexport function crc32c(buf: Buffer | string, initial: number = 0) {\n if (!Buffer.isBuffer(buf)) {\n buf = Buffer.from(buf);\n }\n let crc = (initial | 0) ^ -1;\n for (let i = 0; i < buf.length; i++) {\n crc = kCRCTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ -1) >>> 0;\n}\n"],"mappings":";AAEA,MAAM,YAAY,WAAW,GAC3B,GACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,UACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,UACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,WACA,WACA,YACA,UACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,UACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,UACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,UACF;AAEA,SAAgB,OAAO,KAAsB,UAAkB,GAAG;CAChE,IAAI,CAAC,OAAO,SAAS,GAAG,GACtB,MAAM,OAAO,KAAK,GAAG;CAEvB,IAAI,OAAO,UAAU,KAAK;CAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAC9B,MAAM,WAAW,MAAM,IAAI,MAAM,OAAS,QAAQ;CAEpD,QAAQ,MAAM,QAAQ;AACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crc32c.js","names":[],"sources":["../../src/clients/crc32c.ts"],"sourcesContent":["// copy from https://github.com/ashi009/node-fast-crc32c/blob/master/impls/js_crc32c.js\n// can not use fast-crc32c because it try to use native solution that brokes in electron\nconst kCRCTable = Int32Array.of(\n 0x00000000,\n 0xf26b8303,\n 0xe13b70f7,\n 0x1350f3f4,\n 0xc79a971f,\n 0x35f1141c,\n 0x26a1e7e8,\n 0xd4ca64eb,\n 0x8ad958cf,\n 0x78b2dbcc,\n 0x6be22838,\n 0x9989ab3b,\n 0x4d43cfd0,\n 0xbf284cd3,\n 0xac78bf27,\n 0x5e133c24,\n 0x105ec76f,\n 0xe235446c,\n 0xf165b798,\n 0x030e349b,\n 0xd7c45070,\n 0x25afd373,\n 0x36ff2087,\n 0xc494a384,\n 0x9a879fa0,\n 0x68ec1ca3,\n 0x7bbcef57,\n 0x89d76c54,\n 0x5d1d08bf,\n 0xaf768bbc,\n 0xbc267848,\n 0x4e4dfb4b,\n 0x20bd8ede,\n 0xd2d60ddd,\n 0xc186fe29,\n 0x33ed7d2a,\n 0xe72719c1,\n 0x154c9ac2,\n 0x061c6936,\n 0xf477ea35,\n 0xaa64d611,\n 0x580f5512,\n 0x4b5fa6e6,\n 0xb93425e5,\n 0x6dfe410e,\n 0x9f95c20d,\n 0x8cc531f9,\n 0x7eaeb2fa,\n 0x30e349b1,\n 0xc288cab2,\n 0xd1d83946,\n 0x23b3ba45,\n 0xf779deae,\n 0x05125dad,\n 0x1642ae59,\n 0xe4292d5a,\n 0xba3a117e,\n 0x4851927d,\n 0x5b016189,\n 0xa96ae28a,\n 0x7da08661,\n 0x8fcb0562,\n 0x9c9bf696,\n 0x6ef07595,\n 0x417b1dbc,\n 0xb3109ebf,\n 0xa0406d4b,\n 0x522bee48,\n 0x86e18aa3,\n 0x748a09a0,\n 0x67dafa54,\n 0x95b17957,\n 0xcba24573,\n 0x39c9c670,\n 0x2a993584,\n 0xd8f2b687,\n 0x0c38d26c,\n 0xfe53516f,\n 0xed03a29b,\n 0x1f682198,\n 0x5125dad3,\n 0xa34e59d0,\n 0xb01eaa24,\n 0x42752927,\n 0x96bf4dcc,\n 0x64d4cecf,\n 0x77843d3b,\n 0x85efbe38,\n 0xdbfc821c,\n 0x2997011f,\n 0x3ac7f2eb,\n 0xc8ac71e8,\n 0x1c661503,\n 0xee0d9600,\n 0xfd5d65f4,\n 0x0f36e6f7,\n 0x61c69362,\n 0x93ad1061,\n 0x80fde395,\n 0x72966096,\n 0xa65c047d,\n 0x5437877e,\n 0x4767748a,\n 0xb50cf789,\n 0xeb1fcbad,\n 0x197448ae,\n 0x0a24bb5a,\n 0xf84f3859,\n 0x2c855cb2,\n 0xdeeedfb1,\n 0xcdbe2c45,\n 0x3fd5af46,\n 0x7198540d,\n 0x83f3d70e,\n 0x90a324fa,\n 0x62c8a7f9,\n 0xb602c312,\n 0x44694011,\n 0x5739b3e5,\n 0xa55230e6,\n 0xfb410cc2,\n 0x092a8fc1,\n 0x1a7a7c35,\n 0xe811ff36,\n 0x3cdb9bdd,\n 0xceb018de,\n 0xdde0eb2a,\n 0x2f8b6829,\n 0x82f63b78,\n 0x709db87b,\n 0x63cd4b8f,\n 0x91a6c88c,\n 0x456cac67,\n 0xb7072f64,\n 0xa457dc90,\n 0x563c5f93,\n 0x082f63b7,\n 0xfa44e0b4,\n 0xe9141340,\n 0x1b7f9043,\n 0xcfb5f4a8,\n 0x3dde77ab,\n 0x2e8e845f,\n 0xdce5075c,\n 0x92a8fc17,\n 0x60c37f14,\n 0x73938ce0,\n 0x81f80fe3,\n 0x55326b08,\n 0xa759e80b,\n 0xb4091bff,\n 0x466298fc,\n 0x1871a4d8,\n 0xea1a27db,\n 0xf94ad42f,\n 0x0b21572c,\n 0xdfeb33c7,\n 0x2d80b0c4,\n 0x3ed04330,\n 0xccbbc033,\n 0xa24bb5a6,\n 0x502036a5,\n 0x4370c551,\n 0xb11b4652,\n 0x65d122b9,\n 0x97baa1ba,\n 0x84ea524e,\n 0x7681d14d,\n 0x2892ed69,\n 0xdaf96e6a,\n 0xc9a99d9e,\n 0x3bc21e9d,\n 0xef087a76,\n 0x1d63f975,\n 0x0e330a81,\n 0xfc588982,\n 0xb21572c9,\n 0x407ef1ca,\n 0x532e023e,\n 0xa145813d,\n 0x758fe5d6,\n 0x87e466d5,\n 0x94b49521,\n 0x66df1622,\n 0x38cc2a06,\n 0xcaa7a905,\n 0xd9f75af1,\n 0x2b9cd9f2,\n 0xff56bd19,\n 0x0d3d3e1a,\n 0x1e6dcdee,\n 0xec064eed,\n 0xc38d26c4,\n 0x31e6a5c7,\n 0x22b65633,\n 0xd0ddd530,\n 0x0417b1db,\n 0xf67c32d8,\n 0xe52cc12c,\n 0x1747422f,\n 0x49547e0b,\n 0xbb3ffd08,\n 0xa86f0efc,\n 0x5a048dff,\n 0x8ecee914,\n 0x7ca56a17,\n 0x6ff599e3,\n 0x9d9e1ae0,\n 0xd3d3e1ab,\n 0x21b862a8,\n 0x32e8915c,\n 0xc083125f,\n 0x144976b4,\n 0xe622f5b7,\n 0xf5720643,\n 0x07198540,\n 0x590ab964,\n 0xab613a67,\n 0xb831c993,\n 0x4a5a4a90,\n 0x9e902e7b,\n 0x6cfbad78,\n 0x7fab5e8c,\n 0x8dc0dd8f,\n 0xe330a81a,\n 0x115b2b19,\n 0x020bd8ed,\n 0xf0605bee,\n 0x24aa3f05,\n 0xd6c1bc06,\n 0xc5914ff2,\n 0x37faccf1,\n 0x69e9f0d5,\n 0x9b8273d6,\n 0x88d28022,\n 0x7ab90321,\n 0xae7367ca,\n 0x5c18e4c9,\n 0x4f48173d,\n 0xbd23943e,\n 0xf36e6f75,\n 0x0105ec76,\n 0x12551f82,\n 0xe03e9c81,\n 0x34f4f86a,\n 0xc69f7b69,\n 0xd5cf889d,\n 0x27a40b9e,\n 0x79b737ba,\n 0x8bdcb4b9,\n 0x988c474d,\n 0x6ae7c44e,\n 0xbe2da0a5,\n 0x4c4623a6,\n 0x5f16d052,\n 0xad7d5351,\n);\n\nexport function crc32c(buf: Buffer | string, initial: number = 0) {\n if (!Buffer.isBuffer(buf)) {\n buf = Buffer.from(buf);\n }\n let crc = (initial | 0) ^ -1;\n for (let i = 0; i < buf.length; i++) {\n crc = kCRCTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ -1) >>> 0;\n}\n"],"mappings":";AAEA,MAAM,YAAY,WAAW,GAC3B,GACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,UACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,UACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,WACA,WACA,YACA,UACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,UACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,UACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,
|
|
1
|
+
{"version":3,"file":"crc32c.js","names":[],"sources":["../../src/clients/crc32c.ts"],"sourcesContent":["// copy from https://github.com/ashi009/node-fast-crc32c/blob/master/impls/js_crc32c.js\n// can not use fast-crc32c because it try to use native solution that brokes in electron\nconst kCRCTable = Int32Array.of(\n 0x00000000,\n 0xf26b8303,\n 0xe13b70f7,\n 0x1350f3f4,\n 0xc79a971f,\n 0x35f1141c,\n 0x26a1e7e8,\n 0xd4ca64eb,\n 0x8ad958cf,\n 0x78b2dbcc,\n 0x6be22838,\n 0x9989ab3b,\n 0x4d43cfd0,\n 0xbf284cd3,\n 0xac78bf27,\n 0x5e133c24,\n 0x105ec76f,\n 0xe235446c,\n 0xf165b798,\n 0x030e349b,\n 0xd7c45070,\n 0x25afd373,\n 0x36ff2087,\n 0xc494a384,\n 0x9a879fa0,\n 0x68ec1ca3,\n 0x7bbcef57,\n 0x89d76c54,\n 0x5d1d08bf,\n 0xaf768bbc,\n 0xbc267848,\n 0x4e4dfb4b,\n 0x20bd8ede,\n 0xd2d60ddd,\n 0xc186fe29,\n 0x33ed7d2a,\n 0xe72719c1,\n 0x154c9ac2,\n 0x061c6936,\n 0xf477ea35,\n 0xaa64d611,\n 0x580f5512,\n 0x4b5fa6e6,\n 0xb93425e5,\n 0x6dfe410e,\n 0x9f95c20d,\n 0x8cc531f9,\n 0x7eaeb2fa,\n 0x30e349b1,\n 0xc288cab2,\n 0xd1d83946,\n 0x23b3ba45,\n 0xf779deae,\n 0x05125dad,\n 0x1642ae59,\n 0xe4292d5a,\n 0xba3a117e,\n 0x4851927d,\n 0x5b016189,\n 0xa96ae28a,\n 0x7da08661,\n 0x8fcb0562,\n 0x9c9bf696,\n 0x6ef07595,\n 0x417b1dbc,\n 0xb3109ebf,\n 0xa0406d4b,\n 0x522bee48,\n 0x86e18aa3,\n 0x748a09a0,\n 0x67dafa54,\n 0x95b17957,\n 0xcba24573,\n 0x39c9c670,\n 0x2a993584,\n 0xd8f2b687,\n 0x0c38d26c,\n 0xfe53516f,\n 0xed03a29b,\n 0x1f682198,\n 0x5125dad3,\n 0xa34e59d0,\n 0xb01eaa24,\n 0x42752927,\n 0x96bf4dcc,\n 0x64d4cecf,\n 0x77843d3b,\n 0x85efbe38,\n 0xdbfc821c,\n 0x2997011f,\n 0x3ac7f2eb,\n 0xc8ac71e8,\n 0x1c661503,\n 0xee0d9600,\n 0xfd5d65f4,\n 0x0f36e6f7,\n 0x61c69362,\n 0x93ad1061,\n 0x80fde395,\n 0x72966096,\n 0xa65c047d,\n 0x5437877e,\n 0x4767748a,\n 0xb50cf789,\n 0xeb1fcbad,\n 0x197448ae,\n 0x0a24bb5a,\n 0xf84f3859,\n 0x2c855cb2,\n 0xdeeedfb1,\n 0xcdbe2c45,\n 0x3fd5af46,\n 0x7198540d,\n 0x83f3d70e,\n 0x90a324fa,\n 0x62c8a7f9,\n 0xb602c312,\n 0x44694011,\n 0x5739b3e5,\n 0xa55230e6,\n 0xfb410cc2,\n 0x092a8fc1,\n 0x1a7a7c35,\n 0xe811ff36,\n 0x3cdb9bdd,\n 0xceb018de,\n 0xdde0eb2a,\n 0x2f8b6829,\n 0x82f63b78,\n 0x709db87b,\n 0x63cd4b8f,\n 0x91a6c88c,\n 0x456cac67,\n 0xb7072f64,\n 0xa457dc90,\n 0x563c5f93,\n 0x082f63b7,\n 0xfa44e0b4,\n 0xe9141340,\n 0x1b7f9043,\n 0xcfb5f4a8,\n 0x3dde77ab,\n 0x2e8e845f,\n 0xdce5075c,\n 0x92a8fc17,\n 0x60c37f14,\n 0x73938ce0,\n 0x81f80fe3,\n 0x55326b08,\n 0xa759e80b,\n 0xb4091bff,\n 0x466298fc,\n 0x1871a4d8,\n 0xea1a27db,\n 0xf94ad42f,\n 0x0b21572c,\n 0xdfeb33c7,\n 0x2d80b0c4,\n 0x3ed04330,\n 0xccbbc033,\n 0xa24bb5a6,\n 0x502036a5,\n 0x4370c551,\n 0xb11b4652,\n 0x65d122b9,\n 0x97baa1ba,\n 0x84ea524e,\n 0x7681d14d,\n 0x2892ed69,\n 0xdaf96e6a,\n 0xc9a99d9e,\n 0x3bc21e9d,\n 0xef087a76,\n 0x1d63f975,\n 0x0e330a81,\n 0xfc588982,\n 0xb21572c9,\n 0x407ef1ca,\n 0x532e023e,\n 0xa145813d,\n 0x758fe5d6,\n 0x87e466d5,\n 0x94b49521,\n 0x66df1622,\n 0x38cc2a06,\n 0xcaa7a905,\n 0xd9f75af1,\n 0x2b9cd9f2,\n 0xff56bd19,\n 0x0d3d3e1a,\n 0x1e6dcdee,\n 0xec064eed,\n 0xc38d26c4,\n 0x31e6a5c7,\n 0x22b65633,\n 0xd0ddd530,\n 0x0417b1db,\n 0xf67c32d8,\n 0xe52cc12c,\n 0x1747422f,\n 0x49547e0b,\n 0xbb3ffd08,\n 0xa86f0efc,\n 0x5a048dff,\n 0x8ecee914,\n 0x7ca56a17,\n 0x6ff599e3,\n 0x9d9e1ae0,\n 0xd3d3e1ab,\n 0x21b862a8,\n 0x32e8915c,\n 0xc083125f,\n 0x144976b4,\n 0xe622f5b7,\n 0xf5720643,\n 0x07198540,\n 0x590ab964,\n 0xab613a67,\n 0xb831c993,\n 0x4a5a4a90,\n 0x9e902e7b,\n 0x6cfbad78,\n 0x7fab5e8c,\n 0x8dc0dd8f,\n 0xe330a81a,\n 0x115b2b19,\n 0x020bd8ed,\n 0xf0605bee,\n 0x24aa3f05,\n 0xd6c1bc06,\n 0xc5914ff2,\n 0x37faccf1,\n 0x69e9f0d5,\n 0x9b8273d6,\n 0x88d28022,\n 0x7ab90321,\n 0xae7367ca,\n 0x5c18e4c9,\n 0x4f48173d,\n 0xbd23943e,\n 0xf36e6f75,\n 0x0105ec76,\n 0x12551f82,\n 0xe03e9c81,\n 0x34f4f86a,\n 0xc69f7b69,\n 0xd5cf889d,\n 0x27a40b9e,\n 0x79b737ba,\n 0x8bdcb4b9,\n 0x988c474d,\n 0x6ae7c44e,\n 0xbe2da0a5,\n 0x4c4623a6,\n 0x5f16d052,\n 0xad7d5351,\n);\n\nexport function crc32c(buf: Buffer | string, initial: number = 0) {\n if (!Buffer.isBuffer(buf)) {\n buf = Buffer.from(buf);\n }\n let crc = (initial | 0) ^ -1;\n for (let i = 0; i < buf.length; i++) {\n crc = kCRCTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ -1) >>> 0;\n}\n"],"mappings":";AAEA,MAAM,YAAY,WAAW,GAC3B,GACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,UACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,UACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,YACA,YACA,WACA,YACA,WACA,WACA,YACA,YACA,WACA,WACA,YACA,UACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,WACA,UACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,UACA,WACA,YACA,WACA,YACA,YACA,WACA,YACA,YACA,YACA,YACA,YACA,YACA,YACA,UACF;AAEA,SAAgB,OAAO,KAAsB,UAAkB,GAAG;CAChE,IAAI,CAAC,OAAO,SAAS,GAAG,GACtB,MAAM,OAAO,KAAK,GAAG;CAEvB,IAAI,OAAO,UAAU,KAAK;CAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAC9B,MAAM,WAAW,MAAM,IAAI,MAAM,OAAS,QAAQ;CAEpD,QAAQ,MAAM,QAAQ;AACxB"}
|
|
@@ -6,18 +6,20 @@ const require_protocol_client = require("../proto-grpc/github.com/milaboratory/p
|
|
|
6
6
|
const require_download_url_cache = require("./download_url_cache.cjs");
|
|
7
7
|
let _milaboratories_pl_client = require("@milaboratories/pl-client");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
|
-
node_fs_promises = require_runtime.__toESM(node_fs_promises);
|
|
9
|
+
node_fs_promises = require_runtime.__toESM(node_fs_promises, 1);
|
|
10
10
|
let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
|
|
11
11
|
let _milaboratories_helpers = require("@milaboratories/helpers");
|
|
12
12
|
let node_fs = require("node:fs");
|
|
13
|
-
node_fs = require_runtime.__toESM(node_fs);
|
|
13
|
+
node_fs = require_runtime.__toESM(node_fs, 1);
|
|
14
14
|
let node_path = require("node:path");
|
|
15
|
-
node_path = require_runtime.__toESM(node_path);
|
|
15
|
+
node_path = require_runtime.__toESM(node_path, 1);
|
|
16
16
|
let node_stream = require("node:stream");
|
|
17
17
|
//#region src/clients/download.ts
|
|
18
18
|
/** Gets URLs for downloading from pl-core, parses them and reads or downloads
|
|
19
19
|
* files locally and from the web. */
|
|
20
20
|
var ClientDownload = class {
|
|
21
|
+
httpClient;
|
|
22
|
+
logger;
|
|
21
23
|
wire;
|
|
22
24
|
remoteFileDownloader;
|
|
23
25
|
/** Helps to find a storage root directory by a storage id from URL scheme. */
|
|
@@ -26,6 +28,12 @@ var ClientDownload = class {
|
|
|
26
28
|
localFileReadLimiter = new _milaboratories_ts_helpers.ConcurrencyLimitingExecutor(32);
|
|
27
29
|
/** Caches presigned download URLs by resource id until they (almost) expire. */
|
|
28
30
|
urlCache;
|
|
31
|
+
/** Active remote downloads; in-flight gauges are summed over this set on read. */
|
|
32
|
+
inFlight = /* @__PURE__ */ new Set();
|
|
33
|
+
presignedUrlCacheHits = 0;
|
|
34
|
+
presignedUrlCacheMisses = 0;
|
|
35
|
+
presignedUrlStaleHits = 0;
|
|
36
|
+
presignedUrlRequestSumLatencyMs = 0;
|
|
29
37
|
constructor(wireClientProviderFactory, httpClient, logger, localProjections) {
|
|
30
38
|
this.httpClient = httpClient;
|
|
31
39
|
this.logger = logger;
|
|
@@ -54,22 +62,65 @@ var ClientDownload = class {
|
|
|
54
62
|
const remoteHeaders = Object.fromEntries(headers.map(({ name, value }) => [name, value]));
|
|
55
63
|
this.logger.info(`blob ${(0, _milaboratories_pl_client.stringifyWithResourceId)(info)} download started, url: ${downloadUrl}, range: ${JSON.stringify(ops.range ?? null)}`);
|
|
56
64
|
const timer = _milaboratories_helpers.PerfTimer.start();
|
|
57
|
-
const result = isLocal(downloadUrl) ? await this.withLocalFileContent(downloadUrl, ops, handler) : await this.
|
|
65
|
+
const result = isLocal(downloadUrl) ? await this.withLocalFileContent(downloadUrl, ops, handler) : await this.withTrackedRemoteContent(downloadUrl, remoteHeaders, ops, handler);
|
|
58
66
|
this.logger.info(`blob ${(0, _milaboratories_pl_client.stringifyWithResourceId)(info)} download finished, took: ${timer.elapsed()}`);
|
|
59
67
|
return result;
|
|
60
68
|
};
|
|
61
69
|
const cached = this.urlCache.get(info.id);
|
|
62
70
|
if (cached !== void 0) try {
|
|
63
|
-
|
|
71
|
+
const result = await attempt(cached);
|
|
72
|
+
this.presignedUrlCacheHits++;
|
|
73
|
+
return result;
|
|
64
74
|
} catch (error) {
|
|
65
75
|
if (!require_download_errors.isDownloadNetworkError400(error)) throw error;
|
|
66
76
|
this.urlCache.delete(info.id);
|
|
77
|
+
this.presignedUrlStaleHits++;
|
|
67
78
|
this.logger.info(`cached download URL for blob ${(0, _milaboratories_pl_client.stringifyWithResourceId)(info)} rejected (status ${error.statusCode}), re-fetching`);
|
|
68
79
|
}
|
|
80
|
+
else this.presignedUrlCacheMisses++;
|
|
81
|
+
const urlFetchStartMs = performance.now();
|
|
69
82
|
const fresh = await this.grpcGetDownloadUrl(info, options, ops.signal);
|
|
83
|
+
this.presignedUrlRequestSumLatencyMs += performance.now() - urlFetchStartMs;
|
|
70
84
|
this.urlCache.set(info.id, fresh);
|
|
71
85
|
return await attempt(fresh);
|
|
72
86
|
}
|
|
87
|
+
/** Download-client-owned slice of {@link BlobDriverMetrics}: presigned-URL cache + in-flight downloads. */
|
|
88
|
+
metrics() {
|
|
89
|
+
let inFlightBytesTotal = 0;
|
|
90
|
+
let inFlightBytesReceived = 0;
|
|
91
|
+
for (const rec of this.inFlight) {
|
|
92
|
+
inFlightBytesTotal += rec.size;
|
|
93
|
+
inFlightBytesReceived += rec.received;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
downloadsInFlight: this.inFlight.size,
|
|
97
|
+
inFlightBytesTotal,
|
|
98
|
+
inFlightBytesReceived,
|
|
99
|
+
presignedUrlCacheHits: this.presignedUrlCacheHits,
|
|
100
|
+
presignedUrlCacheMisses: this.presignedUrlCacheMisses,
|
|
101
|
+
presignedUrlStaleHits: this.presignedUrlStaleHits,
|
|
102
|
+
presignedUrlRequestSumLatencyMs: this.presignedUrlRequestSumLatencyMs
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Wraps a remote download so it appears in the in-flight gauges and its received bytes are counted live. */
|
|
106
|
+
async withTrackedRemoteContent(url, headers, ops, handler) {
|
|
107
|
+
const rec = {
|
|
108
|
+
size: 0,
|
|
109
|
+
received: 0
|
|
110
|
+
};
|
|
111
|
+
this.inFlight.add(rec);
|
|
112
|
+
try {
|
|
113
|
+
return await this.remoteFileDownloader.withContent(url, headers, ops, async (content, size) => {
|
|
114
|
+
rec.size = size;
|
|
115
|
+
return await handler(content.pipeThrough(new TransformStream({ transform: (chunk, controller) => {
|
|
116
|
+
rec.received += chunk.byteLength;
|
|
117
|
+
controller.enqueue(chunk);
|
|
118
|
+
} })), size);
|
|
119
|
+
});
|
|
120
|
+
} finally {
|
|
121
|
+
this.inFlight.delete(rec);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
73
124
|
async withLocalFileContent(url, ops, handler) {
|
|
74
125
|
const { storageId, relativePath } = parseLocalUrl(url);
|
|
75
126
|
const fullPath = getFullPath(storageId, this.localStorageIdsToRoot, relativePath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.cjs","names":["ConcurrencyLimitingExecutor","DownloadClient","RestAPI","RemoteFileDownloader","DownloadUrlCache","PerfTimer","isDownloadNetworkError400","fsp","fs","Readable","path"],"sources":["../../src/clients/download.ts"],"sourcesContent":["/* eslint-disable n/no-unsupported-features/node-builtins */\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n stringifyWithResourceId,\n RestAPI,\n createRTypeRoutingHeader,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { PerfTimer } from \"@milaboratories/helpers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConcurrencyLimitingExecutor } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs\";\nimport * as fsp from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport type { Dispatcher } from \"undici\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\nimport { type ContentHandler, RemoteFileDownloader } from \"../helpers/download\";\nimport { isDownloadNetworkError400 } from \"../helpers/download_errors\";\nimport { validateAbsolute } from \"../helpers/validate\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\nimport { DownloadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client\";\nimport type { DownloadApiPaths, DownloadRestClientType } from \"../proto-rest\";\nimport { type GetContentOptions } from \"@milaboratories/pl-model-common\";\nimport { DownloadUrlCache } from \"./download_url_cache\";\n\n/** Gets URLs for downloading from pl-core, parses them and reads or downloads\n * files locally and from the web. */\nexport class ClientDownload {\n public readonly wire: WireClientProvider<DownloadRestClientType | DownloadClient>;\n private readonly remoteFileDownloader: RemoteFileDownloader;\n\n /** Helps to find a storage root directory by a storage id from URL scheme. */\n private readonly localStorageIdsToRoot: Map<string, string>;\n\n /** Concurrency limiter for local file reads - limit to 32 parallel reads */\n private readonly localFileReadLimiter = new ConcurrencyLimitingExecutor(32);\n\n /** Caches presigned download URLs by resource id until they (almost) expire. */\n private readonly urlCache: DownloadUrlCache;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n /** Pl storages available locally */\n localProjections: LocalStorageProjection[],\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wireConn) => {\n if (wireConn.type === \"grpc\") {\n return new DownloadClient(wireConn.Transport);\n } else {\n return RestAPI.createClient<DownloadApiPaths>({\n hostAndPort: wireConn.Config.hostAndPort,\n ssl: wireConn.Config.ssl,\n dispatcher: wireConn.Dispatcher,\n middlewares: wireConn.Middlewares,\n });\n }\n });\n this.remoteFileDownloader = new RemoteFileDownloader(httpClient);\n this.localStorageIdsToRoot = newLocalStorageIdsToRoot(localProjections);\n this.urlCache = new DownloadUrlCache(logger);\n }\n\n close() {}\n\n /**\n * Gets a presign URL and downloads the file.\n * An optional range with 2 numbers from what byte and to what byte to download can be provided.\n * @param fromBytes - from byte including this byte\n * @param toBytes - to byte excluding this byte\n */\n async withBlobContent<T>(\n info: ResourceInfo,\n options: RpcOptions | undefined,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const attempt = async ({\n downloadUrl,\n headers,\n }: DownloadAPI_GetDownloadURL_Response): Promise<T> => {\n const remoteHeaders = Object.fromEntries(headers.map(({ name, value }) => [name, value]));\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download started, ` +\n `url: ${downloadUrl}, ` +\n `range: ${JSON.stringify(ops.range ?? null)}`,\n );\n\n const timer = PerfTimer.start();\n const result = isLocal(downloadUrl)\n ? await this.withLocalFileContent(downloadUrl, ops, handler)\n : await this.remoteFileDownloader.withContent(downloadUrl, remoteHeaders, ops, handler);\n\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download finished, ` + `took: ${timer.elapsed()}`,\n );\n return result;\n };\n\n const cached = this.urlCache.get(info.id);\n if (cached !== undefined) {\n try {\n return await attempt(cached);\n } catch (error) {\n if (!isDownloadNetworkError400(error)) throw error;\n this.urlCache.delete(info.id);\n this.logger.info(\n `cached download URL for blob ${stringifyWithResourceId(info)} rejected ` +\n `(status ${error.statusCode}), re-fetching`,\n );\n }\n }\n\n const fresh = await this.grpcGetDownloadUrl(info, options, ops.signal);\n this.urlCache.set(info.id, fresh);\n return await attempt(fresh);\n }\n\n async withLocalFileContent<T>(\n url: string,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const { storageId, relativePath } = parseLocalUrl(url);\n const fullPath = getFullPath(storageId, this.localStorageIdsToRoot, relativePath);\n\n return await this.localFileReadLimiter.run(async () => {\n const readOps = {\n start: ops.range?.from,\n end: ops.range?.to !== undefined ? ops.range.to - 1 : undefined,\n signal: ops.signal,\n };\n let stream: fs.ReadStream | undefined;\n let handlerSuccess = false;\n\n try {\n const stat = await fsp.stat(fullPath);\n stream = fs.createReadStream(fullPath, readOps);\n const webStream = Readable.toWeb(stream);\n\n const result = await handler(webStream, stat.size);\n handlerSuccess = true;\n return result;\n } catch (error) {\n // Cleanup on error (including handler errors)\n if (!handlerSuccess && stream && !stream.destroyed) {\n stream.destroy();\n }\n throw error;\n }\n });\n }\n\n private async grpcGetDownloadUrl(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n signal?: AbortSignal,\n ): Promise<DownloadAPI_GetDownloadURL_Response> {\n const withAbort = options ?? {};\n withAbort.abort = signal;\n\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n if (client instanceof DownloadClient) {\n return await client.getDownloadURL(\n { resourceId: globalId, resourceSignature: signature, isInternalUse: false },\n addRTypeToMetadata(type, withAbort),\n ).response;\n } else {\n return (\n await client.POST(\"/v1/get-download-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n isInternalUse: false,\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n }\n }\n}\n\nexport function parseLocalUrl(url: string) {\n const parsed = new URL(url);\n if (parsed.pathname == \"\")\n throw new WrongLocalFileUrl(`url for local filepath ${url} does not match url scheme`);\n\n return {\n storageId: parsed.host,\n relativePath: decodeURIComponent(parsed.pathname.slice(1)),\n };\n}\n\nexport function getFullPath(\n storageId: string,\n localStorageIdsToRoot: Map<string, string>,\n relativePath: string,\n) {\n const root = localStorageIdsToRoot.get(storageId);\n if (root === undefined) throw new UnknownStorageError(`Unknown storage location: ${storageId}`);\n\n if (root === \"\") return relativePath;\n\n return path.join(root, relativePath);\n}\n\nconst storageProtocol = \"storage://\";\nfunction isLocal(url: string) {\n return url.startsWith(storageProtocol);\n}\n\n/** Throws when a local URL have invalid scheme. */\nexport class WrongLocalFileUrl extends Error {\n name = \"WrongLocalFileUrl\";\n}\n\n/** Happens when a storage for a local file can't be found. */\nexport class UnknownStorageError extends Error {\n name = \"UnknownStorageError\";\n}\n\nexport function newLocalStorageIdsToRoot(projections: LocalStorageProjection[]) {\n const idToRoot: Map<string, string> = new Map();\n for (const lp of projections) {\n // Empty string means no prefix, i.e. any file on this machine can be got from the storage.\n if (lp.localPath !== \"\") {\n validateAbsolute(lp.localPath);\n }\n idToRoot.set(lp.storageId, lp.localPath);\n }\n\n return idToRoot;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"download.cjs","names":["ConcurrencyLimitingExecutor","DownloadClient","RestAPI","RemoteFileDownloader","DownloadUrlCache","PerfTimer","isDownloadNetworkError400","fsp","fs","Readable","path"],"sources":["../../src/clients/download.ts"],"sourcesContent":["/* eslint-disable n/no-unsupported-features/node-builtins */\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n stringifyWithResourceId,\n RestAPI,\n createRTypeRoutingHeader,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { PerfTimer } from \"@milaboratories/helpers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConcurrencyLimitingExecutor } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs\";\nimport * as fsp from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport type { Dispatcher } from \"undici\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\nimport { type ContentHandler, RemoteFileDownloader } from \"../helpers/download\";\nimport { isDownloadNetworkError400 } from \"../helpers/download_errors\";\nimport { validateAbsolute } from \"../helpers/validate\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\nimport { DownloadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client\";\nimport type { DownloadApiPaths, DownloadRestClientType } from \"../proto-rest\";\nimport { type GetContentOptions, type BlobDriverMetrics } from \"@milaboratories/pl-model-common\";\nimport { DownloadUrlCache } from \"./download_url_cache\";\n\n/** Subset of {@link BlobDriverMetrics} owned by the download client (presigned cache + in-flight downloads). */\ntype ClientDownloadMetrics = Omit<BlobDriverMetrics, \"uncachedRequests\" | \"uncachedRequestBytes\">;\n\n/** Gets URLs for downloading from pl-core, parses them and reads or downloads\n * files locally and from the web. */\nexport class ClientDownload {\n public readonly wire: WireClientProvider<DownloadRestClientType | DownloadClient>;\n private readonly remoteFileDownloader: RemoteFileDownloader;\n\n /** Helps to find a storage root directory by a storage id from URL scheme. */\n private readonly localStorageIdsToRoot: Map<string, string>;\n\n /** Concurrency limiter for local file reads - limit to 32 parallel reads */\n private readonly localFileReadLimiter = new ConcurrencyLimitingExecutor(32);\n\n /** Caches presigned download URLs by resource id until they (almost) expire. */\n private readonly urlCache: DownloadUrlCache;\n\n /** Active remote downloads; in-flight gauges are summed over this set on read. */\n private readonly inFlight = new Set<{ size: number; received: number }>();\n private presignedUrlCacheHits = 0;\n private presignedUrlCacheMisses = 0;\n private presignedUrlStaleHits = 0;\n private presignedUrlRequestSumLatencyMs = 0;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n /** Pl storages available locally */\n localProjections: LocalStorageProjection[],\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wireConn) => {\n if (wireConn.type === \"grpc\") {\n return new DownloadClient(wireConn.Transport);\n } else {\n return RestAPI.createClient<DownloadApiPaths>({\n hostAndPort: wireConn.Config.hostAndPort,\n ssl: wireConn.Config.ssl,\n dispatcher: wireConn.Dispatcher,\n middlewares: wireConn.Middlewares,\n });\n }\n });\n this.remoteFileDownloader = new RemoteFileDownloader(httpClient);\n this.localStorageIdsToRoot = newLocalStorageIdsToRoot(localProjections);\n this.urlCache = new DownloadUrlCache(logger);\n }\n\n close() {}\n\n /**\n * Gets a presign URL and downloads the file.\n * An optional range with 2 numbers from what byte and to what byte to download can be provided.\n * @param fromBytes - from byte including this byte\n * @param toBytes - to byte excluding this byte\n */\n async withBlobContent<T>(\n info: ResourceInfo,\n options: RpcOptions | undefined,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const attempt = async ({\n downloadUrl,\n headers,\n }: DownloadAPI_GetDownloadURL_Response): Promise<T> => {\n const remoteHeaders = Object.fromEntries(headers.map(({ name, value }) => [name, value]));\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download started, ` +\n `url: ${downloadUrl}, ` +\n `range: ${JSON.stringify(ops.range ?? null)}`,\n );\n\n const timer = PerfTimer.start();\n const result = isLocal(downloadUrl)\n ? await this.withLocalFileContent(downloadUrl, ops, handler)\n : await this.withTrackedRemoteContent(downloadUrl, remoteHeaders, ops, handler);\n\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download finished, ` + `took: ${timer.elapsed()}`,\n );\n return result;\n };\n\n const cached = this.urlCache.get(info.id);\n if (cached !== undefined) {\n try {\n const result = await attempt(cached);\n this.presignedUrlCacheHits++;\n return result;\n } catch (error) {\n if (!isDownloadNetworkError400(error)) throw error;\n this.urlCache.delete(info.id);\n this.presignedUrlStaleHits++;\n this.logger.info(\n `cached download URL for blob ${stringifyWithResourceId(info)} rejected ` +\n `(status ${error.statusCode}), re-fetching`,\n );\n }\n } else {\n this.presignedUrlCacheMisses++;\n }\n\n const urlFetchStartMs = performance.now();\n const fresh = await this.grpcGetDownloadUrl(info, options, ops.signal);\n this.presignedUrlRequestSumLatencyMs += performance.now() - urlFetchStartMs;\n this.urlCache.set(info.id, fresh);\n return await attempt(fresh);\n }\n\n /** Download-client-owned slice of {@link BlobDriverMetrics}: presigned-URL cache + in-flight downloads. */\n metrics(): ClientDownloadMetrics {\n let inFlightBytesTotal = 0;\n let inFlightBytesReceived = 0;\n for (const rec of this.inFlight) {\n inFlightBytesTotal += rec.size;\n inFlightBytesReceived += rec.received;\n }\n return {\n downloadsInFlight: this.inFlight.size,\n inFlightBytesTotal,\n inFlightBytesReceived,\n presignedUrlCacheHits: this.presignedUrlCacheHits,\n presignedUrlCacheMisses: this.presignedUrlCacheMisses,\n presignedUrlStaleHits: this.presignedUrlStaleHits,\n presignedUrlRequestSumLatencyMs: this.presignedUrlRequestSumLatencyMs,\n };\n }\n\n /** Wraps a remote download so it appears in the in-flight gauges and its received bytes are counted live. */\n private async withTrackedRemoteContent<T>(\n url: string,\n headers: Record<string, string>,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const rec = { size: 0, received: 0 };\n this.inFlight.add(rec);\n try {\n return await this.remoteFileDownloader.withContent(\n url,\n headers,\n ops,\n async (content, size) => {\n rec.size = size;\n const counted = content.pipeThrough(\n new TransformStream<Uint8Array, Uint8Array>({\n transform: (chunk, controller) => {\n rec.received += chunk.byteLength;\n controller.enqueue(chunk);\n },\n }),\n );\n return await handler(counted, size);\n },\n );\n } finally {\n this.inFlight.delete(rec);\n }\n }\n\n async withLocalFileContent<T>(\n url: string,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const { storageId, relativePath } = parseLocalUrl(url);\n const fullPath = getFullPath(storageId, this.localStorageIdsToRoot, relativePath);\n\n return await this.localFileReadLimiter.run(async () => {\n const readOps = {\n start: ops.range?.from,\n end: ops.range?.to !== undefined ? ops.range.to - 1 : undefined,\n signal: ops.signal,\n };\n let stream: fs.ReadStream | undefined;\n let handlerSuccess = false;\n\n try {\n const stat = await fsp.stat(fullPath);\n stream = fs.createReadStream(fullPath, readOps);\n const webStream = Readable.toWeb(stream);\n\n const result = await handler(webStream, stat.size);\n handlerSuccess = true;\n return result;\n } catch (error) {\n // Cleanup on error (including handler errors)\n if (!handlerSuccess && stream && !stream.destroyed) {\n stream.destroy();\n }\n throw error;\n }\n });\n }\n\n private async grpcGetDownloadUrl(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n signal?: AbortSignal,\n ): Promise<DownloadAPI_GetDownloadURL_Response> {\n const withAbort = options ?? {};\n withAbort.abort = signal;\n\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n if (client instanceof DownloadClient) {\n return await client.getDownloadURL(\n { resourceId: globalId, resourceSignature: signature, isInternalUse: false },\n addRTypeToMetadata(type, withAbort),\n ).response;\n } else {\n return (\n await client.POST(\"/v1/get-download-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n isInternalUse: false,\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n }\n }\n}\n\nexport function parseLocalUrl(url: string) {\n const parsed = new URL(url);\n if (parsed.pathname == \"\")\n throw new WrongLocalFileUrl(`url for local filepath ${url} does not match url scheme`);\n\n return {\n storageId: parsed.host,\n relativePath: decodeURIComponent(parsed.pathname.slice(1)),\n };\n}\n\nexport function getFullPath(\n storageId: string,\n localStorageIdsToRoot: Map<string, string>,\n relativePath: string,\n) {\n const root = localStorageIdsToRoot.get(storageId);\n if (root === undefined) throw new UnknownStorageError(`Unknown storage location: ${storageId}`);\n\n if (root === \"\") return relativePath;\n\n return path.join(root, relativePath);\n}\n\nconst storageProtocol = \"storage://\";\nfunction isLocal(url: string) {\n return url.startsWith(storageProtocol);\n}\n\n/** Throws when a local URL have invalid scheme. */\nexport class WrongLocalFileUrl extends Error {\n name = \"WrongLocalFileUrl\";\n}\n\n/** Happens when a storage for a local file can't be found. */\nexport class UnknownStorageError extends Error {\n name = \"UnknownStorageError\";\n}\n\nexport function newLocalStorageIdsToRoot(projections: LocalStorageProjection[]) {\n const idToRoot: Map<string, string> = new Map();\n for (const lp of projections) {\n // Empty string means no prefix, i.e. any file on this machine can be got from the storage.\n if (lp.localPath !== \"\") {\n validateAbsolute(lp.localPath);\n }\n idToRoot.set(lp.storageId, lp.localPath);\n }\n\n return idToRoot;\n}\n"],"mappings":"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"}
|
|
@@ -6,10 +6,12 @@ import { WireClientProvider, WireClientProviderFactory } from "@milaboratories/p
|
|
|
6
6
|
import { Dispatcher } from "undici";
|
|
7
7
|
import { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
|
8
8
|
import { MiLogger } from "@milaboratories/ts-helpers";
|
|
9
|
-
import { GetContentOptions } from "@milaboratories/pl-model-common";
|
|
9
|
+
import { BlobDriverMetrics, GetContentOptions } from "@milaboratories/pl-model-common";
|
|
10
10
|
import { ResourceInfo } from "@milaboratories/pl-tree";
|
|
11
11
|
|
|
12
12
|
//#region src/clients/download.d.ts
|
|
13
|
+
/** Subset of {@link BlobDriverMetrics} owned by the download client (presigned cache + in-flight downloads). */
|
|
14
|
+
type ClientDownloadMetrics = Omit<BlobDriverMetrics, "uncachedRequests" | "uncachedRequestBytes">;
|
|
13
15
|
/** Gets URLs for downloading from pl-core, parses them and reads or downloads
|
|
14
16
|
* files locally and from the web. */
|
|
15
17
|
declare class ClientDownload {
|
|
@@ -23,6 +25,12 @@ declare class ClientDownload {
|
|
|
23
25
|
private readonly localFileReadLimiter;
|
|
24
26
|
/** Caches presigned download URLs by resource id until they (almost) expire. */
|
|
25
27
|
private readonly urlCache;
|
|
28
|
+
/** Active remote downloads; in-flight gauges are summed over this set on read. */
|
|
29
|
+
private readonly inFlight;
|
|
30
|
+
private presignedUrlCacheHits;
|
|
31
|
+
private presignedUrlCacheMisses;
|
|
32
|
+
private presignedUrlStaleHits;
|
|
33
|
+
private presignedUrlRequestSumLatencyMs;
|
|
26
34
|
constructor(wireClientProviderFactory: WireClientProviderFactory, httpClient: Dispatcher, logger: MiLogger, /** Pl storages available locally */
|
|
27
35
|
|
|
28
36
|
localProjections: LocalStorageProjection[]);
|
|
@@ -34,6 +42,10 @@ declare class ClientDownload {
|
|
|
34
42
|
* @param toBytes - to byte excluding this byte
|
|
35
43
|
*/
|
|
36
44
|
withBlobContent<T>(info: ResourceInfo, options: RpcOptions | undefined, ops: GetContentOptions, handler: ContentHandler$1<T>): Promise<T>;
|
|
45
|
+
/** Download-client-owned slice of {@link BlobDriverMetrics}: presigned-URL cache + in-flight downloads. */
|
|
46
|
+
metrics(): ClientDownloadMetrics;
|
|
47
|
+
/** Wraps a remote download so it appears in the in-flight gauges and its received bytes are counted live. */
|
|
48
|
+
private withTrackedRemoteContent;
|
|
37
49
|
withLocalFileContent<T>(url: string, ops: GetContentOptions, handler: ContentHandler$1<T>): Promise<T>;
|
|
38
50
|
private grpcGetDownloadUrl;
|
|
39
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.d.ts","names":[],"sources":["../../src/clients/download.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"download.d.ts","names":[],"sources":["../../src/clients/download.ts"],"mappings":";;;;;;;;;;;;;KA+BK,qBAAA,GAAwB,IAAI,CAAC,iBAAA;AAJ+D;;AAAA,cAQpF,cAAA;EAAA,SAsBO,UAAA,EAAY,UAAA;EAAA,SACZ,MAAA,EAAQ,QAAA;EAAA,SAtBV,IAAA,EAAM,kBAAA,CAAmB,sBAAA,GAAyB,cAAA;EAAA,iBACjD,oBAAA;EAFQ;EAAA,iBAKR,qBAAA;EAkBS;EAAA,iBAfT,oBAAA;EAPiD;EAAA,iBAUjD,QAAA;EAUY;EAAA,iBAPZ,QAAA;EAAA,QACT,qBAAA;EAAA,QACA,uBAAA;EAAA,QACA,qBAAA;EAAA,QACA,+BAAA;cAGN,yBAAA,EAA2B,yBAAA,EACX,UAAA,EAAY,UAAA,EACZ,MAAA,EAAQ,QAAA,EAiCA;;EA/BxB,gBAAA,EAAkB,sBAAA;EAmBpB,KAAA;EAaG;;;;;;EALG,eAAA,IACJ,IAAA,EAAM,YAAA,EACN,OAAA,EAAS,UAAA,cACT,GAAA,EAAK,iBAAA,EACL,OAAA,EAAS,gBAAA,CAAe,CAAA,IACvB,OAAA,CAAQ,CAAA;EAwGD;EAtDV,OAAA,IAAW,qBAAA;EArFO;EAAA,QAwGJ,wBAAA;EA+BR,oBAAA,IACJ,GAAA,UACA,GAAA,EAAK,iBAAA,EACL,OAAA,EAAS,gBAAA,CAAe,CAAA,IACvB,OAAA,CAAQ,CAAA;EAAA,QA+BG,kBAAA;AAAA;AAAA,iBA8BA,aAAA,CAAc,GAAA;;;;iBAWd,WAAA,CACd,SAAA,UACA,qBAAA,EAAuB,GAAG,kBAC1B,YAAA;;cAgBW,iBAAA,SAA0B,KAAK;EAC1C,IAAI;AAAA;;cAIO,mBAAA,SAA4B,KAAK;EAC5C,IAAI;AAAA;AAAA,iBAGU,wBAAA,CAAyB,WAAA,EAAa,sBAAA,KAAwB,GAAA"}
|
package/dist/clients/download.js
CHANGED
|
@@ -14,6 +14,8 @@ import { Readable } from "node:stream";
|
|
|
14
14
|
/** Gets URLs for downloading from pl-core, parses them and reads or downloads
|
|
15
15
|
* files locally and from the web. */
|
|
16
16
|
var ClientDownload = class {
|
|
17
|
+
httpClient;
|
|
18
|
+
logger;
|
|
17
19
|
wire;
|
|
18
20
|
remoteFileDownloader;
|
|
19
21
|
/** Helps to find a storage root directory by a storage id from URL scheme. */
|
|
@@ -22,6 +24,12 @@ var ClientDownload = class {
|
|
|
22
24
|
localFileReadLimiter = new ConcurrencyLimitingExecutor(32);
|
|
23
25
|
/** Caches presigned download URLs by resource id until they (almost) expire. */
|
|
24
26
|
urlCache;
|
|
27
|
+
/** Active remote downloads; in-flight gauges are summed over this set on read. */
|
|
28
|
+
inFlight = /* @__PURE__ */ new Set();
|
|
29
|
+
presignedUrlCacheHits = 0;
|
|
30
|
+
presignedUrlCacheMisses = 0;
|
|
31
|
+
presignedUrlStaleHits = 0;
|
|
32
|
+
presignedUrlRequestSumLatencyMs = 0;
|
|
25
33
|
constructor(wireClientProviderFactory, httpClient, logger, localProjections) {
|
|
26
34
|
this.httpClient = httpClient;
|
|
27
35
|
this.logger = logger;
|
|
@@ -50,22 +58,65 @@ var ClientDownload = class {
|
|
|
50
58
|
const remoteHeaders = Object.fromEntries(headers.map(({ name, value }) => [name, value]));
|
|
51
59
|
this.logger.info(`blob ${stringifyWithResourceId(info)} download started, url: ${downloadUrl}, range: ${JSON.stringify(ops.range ?? null)}`);
|
|
52
60
|
const timer = PerfTimer.start();
|
|
53
|
-
const result = isLocal(downloadUrl) ? await this.withLocalFileContent(downloadUrl, ops, handler) : await this.
|
|
61
|
+
const result = isLocal(downloadUrl) ? await this.withLocalFileContent(downloadUrl, ops, handler) : await this.withTrackedRemoteContent(downloadUrl, remoteHeaders, ops, handler);
|
|
54
62
|
this.logger.info(`blob ${stringifyWithResourceId(info)} download finished, took: ${timer.elapsed()}`);
|
|
55
63
|
return result;
|
|
56
64
|
};
|
|
57
65
|
const cached = this.urlCache.get(info.id);
|
|
58
66
|
if (cached !== void 0) try {
|
|
59
|
-
|
|
67
|
+
const result = await attempt(cached);
|
|
68
|
+
this.presignedUrlCacheHits++;
|
|
69
|
+
return result;
|
|
60
70
|
} catch (error) {
|
|
61
71
|
if (!isDownloadNetworkError400(error)) throw error;
|
|
62
72
|
this.urlCache.delete(info.id);
|
|
73
|
+
this.presignedUrlStaleHits++;
|
|
63
74
|
this.logger.info(`cached download URL for blob ${stringifyWithResourceId(info)} rejected (status ${error.statusCode}), re-fetching`);
|
|
64
75
|
}
|
|
76
|
+
else this.presignedUrlCacheMisses++;
|
|
77
|
+
const urlFetchStartMs = performance.now();
|
|
65
78
|
const fresh = await this.grpcGetDownloadUrl(info, options, ops.signal);
|
|
79
|
+
this.presignedUrlRequestSumLatencyMs += performance.now() - urlFetchStartMs;
|
|
66
80
|
this.urlCache.set(info.id, fresh);
|
|
67
81
|
return await attempt(fresh);
|
|
68
82
|
}
|
|
83
|
+
/** Download-client-owned slice of {@link BlobDriverMetrics}: presigned-URL cache + in-flight downloads. */
|
|
84
|
+
metrics() {
|
|
85
|
+
let inFlightBytesTotal = 0;
|
|
86
|
+
let inFlightBytesReceived = 0;
|
|
87
|
+
for (const rec of this.inFlight) {
|
|
88
|
+
inFlightBytesTotal += rec.size;
|
|
89
|
+
inFlightBytesReceived += rec.received;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
downloadsInFlight: this.inFlight.size,
|
|
93
|
+
inFlightBytesTotal,
|
|
94
|
+
inFlightBytesReceived,
|
|
95
|
+
presignedUrlCacheHits: this.presignedUrlCacheHits,
|
|
96
|
+
presignedUrlCacheMisses: this.presignedUrlCacheMisses,
|
|
97
|
+
presignedUrlStaleHits: this.presignedUrlStaleHits,
|
|
98
|
+
presignedUrlRequestSumLatencyMs: this.presignedUrlRequestSumLatencyMs
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Wraps a remote download so it appears in the in-flight gauges and its received bytes are counted live. */
|
|
102
|
+
async withTrackedRemoteContent(url, headers, ops, handler) {
|
|
103
|
+
const rec = {
|
|
104
|
+
size: 0,
|
|
105
|
+
received: 0
|
|
106
|
+
};
|
|
107
|
+
this.inFlight.add(rec);
|
|
108
|
+
try {
|
|
109
|
+
return await this.remoteFileDownloader.withContent(url, headers, ops, async (content, size) => {
|
|
110
|
+
rec.size = size;
|
|
111
|
+
return await handler(content.pipeThrough(new TransformStream({ transform: (chunk, controller) => {
|
|
112
|
+
rec.received += chunk.byteLength;
|
|
113
|
+
controller.enqueue(chunk);
|
|
114
|
+
} })), size);
|
|
115
|
+
});
|
|
116
|
+
} finally {
|
|
117
|
+
this.inFlight.delete(rec);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
69
120
|
async withLocalFileContent(url, ops, handler) {
|
|
70
121
|
const { storageId, relativePath } = parseLocalUrl(url);
|
|
71
122
|
const fullPath = getFullPath(storageId, this.localStorageIdsToRoot, relativePath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.js","names":["fs","path"],"sources":["../../src/clients/download.ts"],"sourcesContent":["/* eslint-disable n/no-unsupported-features/node-builtins */\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n stringifyWithResourceId,\n RestAPI,\n createRTypeRoutingHeader,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { PerfTimer } from \"@milaboratories/helpers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConcurrencyLimitingExecutor } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs\";\nimport * as fsp from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport type { Dispatcher } from \"undici\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\nimport { type ContentHandler, RemoteFileDownloader } from \"../helpers/download\";\nimport { isDownloadNetworkError400 } from \"../helpers/download_errors\";\nimport { validateAbsolute } from \"../helpers/validate\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\nimport { DownloadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client\";\nimport type { DownloadApiPaths, DownloadRestClientType } from \"../proto-rest\";\nimport { type GetContentOptions } from \"@milaboratories/pl-model-common\";\nimport { DownloadUrlCache } from \"./download_url_cache\";\n\n/** Gets URLs for downloading from pl-core, parses them and reads or downloads\n * files locally and from the web. */\nexport class ClientDownload {\n public readonly wire: WireClientProvider<DownloadRestClientType | DownloadClient>;\n private readonly remoteFileDownloader: RemoteFileDownloader;\n\n /** Helps to find a storage root directory by a storage id from URL scheme. */\n private readonly localStorageIdsToRoot: Map<string, string>;\n\n /** Concurrency limiter for local file reads - limit to 32 parallel reads */\n private readonly localFileReadLimiter = new ConcurrencyLimitingExecutor(32);\n\n /** Caches presigned download URLs by resource id until they (almost) expire. */\n private readonly urlCache: DownloadUrlCache;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n /** Pl storages available locally */\n localProjections: LocalStorageProjection[],\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wireConn) => {\n if (wireConn.type === \"grpc\") {\n return new DownloadClient(wireConn.Transport);\n } else {\n return RestAPI.createClient<DownloadApiPaths>({\n hostAndPort: wireConn.Config.hostAndPort,\n ssl: wireConn.Config.ssl,\n dispatcher: wireConn.Dispatcher,\n middlewares: wireConn.Middlewares,\n });\n }\n });\n this.remoteFileDownloader = new RemoteFileDownloader(httpClient);\n this.localStorageIdsToRoot = newLocalStorageIdsToRoot(localProjections);\n this.urlCache = new DownloadUrlCache(logger);\n }\n\n close() {}\n\n /**\n * Gets a presign URL and downloads the file.\n * An optional range with 2 numbers from what byte and to what byte to download can be provided.\n * @param fromBytes - from byte including this byte\n * @param toBytes - to byte excluding this byte\n */\n async withBlobContent<T>(\n info: ResourceInfo,\n options: RpcOptions | undefined,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const attempt = async ({\n downloadUrl,\n headers,\n }: DownloadAPI_GetDownloadURL_Response): Promise<T> => {\n const remoteHeaders = Object.fromEntries(headers.map(({ name, value }) => [name, value]));\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download started, ` +\n `url: ${downloadUrl}, ` +\n `range: ${JSON.stringify(ops.range ?? null)}`,\n );\n\n const timer = PerfTimer.start();\n const result = isLocal(downloadUrl)\n ? await this.withLocalFileContent(downloadUrl, ops, handler)\n : await this.remoteFileDownloader.withContent(downloadUrl, remoteHeaders, ops, handler);\n\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download finished, ` + `took: ${timer.elapsed()}`,\n );\n return result;\n };\n\n const cached = this.urlCache.get(info.id);\n if (cached !== undefined) {\n try {\n return await attempt(cached);\n } catch (error) {\n if (!isDownloadNetworkError400(error)) throw error;\n this.urlCache.delete(info.id);\n this.logger.info(\n `cached download URL for blob ${stringifyWithResourceId(info)} rejected ` +\n `(status ${error.statusCode}), re-fetching`,\n );\n }\n }\n\n const fresh = await this.grpcGetDownloadUrl(info, options, ops.signal);\n this.urlCache.set(info.id, fresh);\n return await attempt(fresh);\n }\n\n async withLocalFileContent<T>(\n url: string,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const { storageId, relativePath } = parseLocalUrl(url);\n const fullPath = getFullPath(storageId, this.localStorageIdsToRoot, relativePath);\n\n return await this.localFileReadLimiter.run(async () => {\n const readOps = {\n start: ops.range?.from,\n end: ops.range?.to !== undefined ? ops.range.to - 1 : undefined,\n signal: ops.signal,\n };\n let stream: fs.ReadStream | undefined;\n let handlerSuccess = false;\n\n try {\n const stat = await fsp.stat(fullPath);\n stream = fs.createReadStream(fullPath, readOps);\n const webStream = Readable.toWeb(stream);\n\n const result = await handler(webStream, stat.size);\n handlerSuccess = true;\n return result;\n } catch (error) {\n // Cleanup on error (including handler errors)\n if (!handlerSuccess && stream && !stream.destroyed) {\n stream.destroy();\n }\n throw error;\n }\n });\n }\n\n private async grpcGetDownloadUrl(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n signal?: AbortSignal,\n ): Promise<DownloadAPI_GetDownloadURL_Response> {\n const withAbort = options ?? {};\n withAbort.abort = signal;\n\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n if (client instanceof DownloadClient) {\n return await client.getDownloadURL(\n { resourceId: globalId, resourceSignature: signature, isInternalUse: false },\n addRTypeToMetadata(type, withAbort),\n ).response;\n } else {\n return (\n await client.POST(\"/v1/get-download-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n isInternalUse: false,\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n }\n }\n}\n\nexport function parseLocalUrl(url: string) {\n const parsed = new URL(url);\n if (parsed.pathname == \"\")\n throw new WrongLocalFileUrl(`url for local filepath ${url} does not match url scheme`);\n\n return {\n storageId: parsed.host,\n relativePath: decodeURIComponent(parsed.pathname.slice(1)),\n };\n}\n\nexport function getFullPath(\n storageId: string,\n localStorageIdsToRoot: Map<string, string>,\n relativePath: string,\n) {\n const root = localStorageIdsToRoot.get(storageId);\n if (root === undefined) throw new UnknownStorageError(`Unknown storage location: ${storageId}`);\n\n if (root === \"\") return relativePath;\n\n return path.join(root, relativePath);\n}\n\nconst storageProtocol = \"storage://\";\nfunction isLocal(url: string) {\n return url.startsWith(storageProtocol);\n}\n\n/** Throws when a local URL have invalid scheme. */\nexport class WrongLocalFileUrl extends Error {\n name = \"WrongLocalFileUrl\";\n}\n\n/** Happens when a storage for a local file can't be found. */\nexport class UnknownStorageError extends Error {\n name = \"UnknownStorageError\";\n}\n\nexport function newLocalStorageIdsToRoot(projections: LocalStorageProjection[]) {\n const idToRoot: Map<string, string> = new Map();\n for (const lp of projections) {\n // Empty string means no prefix, i.e. any file on this machine can be got from the storage.\n if (lp.localPath !== \"\") {\n validateAbsolute(lp.localPath);\n }\n idToRoot.set(lp.storageId, lp.localPath);\n }\n\n return idToRoot;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"download.js","names":["fs","path"],"sources":["../../src/clients/download.ts"],"sourcesContent":["/* eslint-disable n/no-unsupported-features/node-builtins */\nimport type { WireClientProvider, WireClientProviderFactory } from \"@milaboratories/pl-client\";\nimport {\n addRTypeToMetadata,\n stringifyWithResourceId,\n RestAPI,\n createRTypeRoutingHeader,\n parseSignedResourceId,\n signatureToBase64Url,\n} from \"@milaboratories/pl-client\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { PerfTimer } from \"@milaboratories/helpers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConcurrencyLimitingExecutor } from \"@milaboratories/ts-helpers\";\nimport type { RpcOptions } from \"@protobuf-ts/runtime-rpc\";\nimport * as fs from \"node:fs\";\nimport * as fsp from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport type { Dispatcher } from \"undici\";\nimport type { LocalStorageProjection } from \"../drivers/types\";\nimport { type ContentHandler, RemoteFileDownloader } from \"../helpers/download\";\nimport { isDownloadNetworkError400 } from \"../helpers/download_errors\";\nimport { validateAbsolute } from \"../helpers/validate\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\nimport { DownloadClient } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client\";\nimport type { DownloadApiPaths, DownloadRestClientType } from \"../proto-rest\";\nimport { type GetContentOptions, type BlobDriverMetrics } from \"@milaboratories/pl-model-common\";\nimport { DownloadUrlCache } from \"./download_url_cache\";\n\n/** Subset of {@link BlobDriverMetrics} owned by the download client (presigned cache + in-flight downloads). */\ntype ClientDownloadMetrics = Omit<BlobDriverMetrics, \"uncachedRequests\" | \"uncachedRequestBytes\">;\n\n/** Gets URLs for downloading from pl-core, parses them and reads or downloads\n * files locally and from the web. */\nexport class ClientDownload {\n public readonly wire: WireClientProvider<DownloadRestClientType | DownloadClient>;\n private readonly remoteFileDownloader: RemoteFileDownloader;\n\n /** Helps to find a storage root directory by a storage id from URL scheme. */\n private readonly localStorageIdsToRoot: Map<string, string>;\n\n /** Concurrency limiter for local file reads - limit to 32 parallel reads */\n private readonly localFileReadLimiter = new ConcurrencyLimitingExecutor(32);\n\n /** Caches presigned download URLs by resource id until they (almost) expire. */\n private readonly urlCache: DownloadUrlCache;\n\n /** Active remote downloads; in-flight gauges are summed over this set on read. */\n private readonly inFlight = new Set<{ size: number; received: number }>();\n private presignedUrlCacheHits = 0;\n private presignedUrlCacheMisses = 0;\n private presignedUrlStaleHits = 0;\n private presignedUrlRequestSumLatencyMs = 0;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n public readonly httpClient: Dispatcher,\n public readonly logger: MiLogger,\n /** Pl storages available locally */\n localProjections: LocalStorageProjection[],\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider((wireConn) => {\n if (wireConn.type === \"grpc\") {\n return new DownloadClient(wireConn.Transport);\n } else {\n return RestAPI.createClient<DownloadApiPaths>({\n hostAndPort: wireConn.Config.hostAndPort,\n ssl: wireConn.Config.ssl,\n dispatcher: wireConn.Dispatcher,\n middlewares: wireConn.Middlewares,\n });\n }\n });\n this.remoteFileDownloader = new RemoteFileDownloader(httpClient);\n this.localStorageIdsToRoot = newLocalStorageIdsToRoot(localProjections);\n this.urlCache = new DownloadUrlCache(logger);\n }\n\n close() {}\n\n /**\n * Gets a presign URL and downloads the file.\n * An optional range with 2 numbers from what byte and to what byte to download can be provided.\n * @param fromBytes - from byte including this byte\n * @param toBytes - to byte excluding this byte\n */\n async withBlobContent<T>(\n info: ResourceInfo,\n options: RpcOptions | undefined,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const attempt = async ({\n downloadUrl,\n headers,\n }: DownloadAPI_GetDownloadURL_Response): Promise<T> => {\n const remoteHeaders = Object.fromEntries(headers.map(({ name, value }) => [name, value]));\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download started, ` +\n `url: ${downloadUrl}, ` +\n `range: ${JSON.stringify(ops.range ?? null)}`,\n );\n\n const timer = PerfTimer.start();\n const result = isLocal(downloadUrl)\n ? await this.withLocalFileContent(downloadUrl, ops, handler)\n : await this.withTrackedRemoteContent(downloadUrl, remoteHeaders, ops, handler);\n\n this.logger.info(\n `blob ${stringifyWithResourceId(info)} download finished, ` + `took: ${timer.elapsed()}`,\n );\n return result;\n };\n\n const cached = this.urlCache.get(info.id);\n if (cached !== undefined) {\n try {\n const result = await attempt(cached);\n this.presignedUrlCacheHits++;\n return result;\n } catch (error) {\n if (!isDownloadNetworkError400(error)) throw error;\n this.urlCache.delete(info.id);\n this.presignedUrlStaleHits++;\n this.logger.info(\n `cached download URL for blob ${stringifyWithResourceId(info)} rejected ` +\n `(status ${error.statusCode}), re-fetching`,\n );\n }\n } else {\n this.presignedUrlCacheMisses++;\n }\n\n const urlFetchStartMs = performance.now();\n const fresh = await this.grpcGetDownloadUrl(info, options, ops.signal);\n this.presignedUrlRequestSumLatencyMs += performance.now() - urlFetchStartMs;\n this.urlCache.set(info.id, fresh);\n return await attempt(fresh);\n }\n\n /** Download-client-owned slice of {@link BlobDriverMetrics}: presigned-URL cache + in-flight downloads. */\n metrics(): ClientDownloadMetrics {\n let inFlightBytesTotal = 0;\n let inFlightBytesReceived = 0;\n for (const rec of this.inFlight) {\n inFlightBytesTotal += rec.size;\n inFlightBytesReceived += rec.received;\n }\n return {\n downloadsInFlight: this.inFlight.size,\n inFlightBytesTotal,\n inFlightBytesReceived,\n presignedUrlCacheHits: this.presignedUrlCacheHits,\n presignedUrlCacheMisses: this.presignedUrlCacheMisses,\n presignedUrlStaleHits: this.presignedUrlStaleHits,\n presignedUrlRequestSumLatencyMs: this.presignedUrlRequestSumLatencyMs,\n };\n }\n\n /** Wraps a remote download so it appears in the in-flight gauges and its received bytes are counted live. */\n private async withTrackedRemoteContent<T>(\n url: string,\n headers: Record<string, string>,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const rec = { size: 0, received: 0 };\n this.inFlight.add(rec);\n try {\n return await this.remoteFileDownloader.withContent(\n url,\n headers,\n ops,\n async (content, size) => {\n rec.size = size;\n const counted = content.pipeThrough(\n new TransformStream<Uint8Array, Uint8Array>({\n transform: (chunk, controller) => {\n rec.received += chunk.byteLength;\n controller.enqueue(chunk);\n },\n }),\n );\n return await handler(counted, size);\n },\n );\n } finally {\n this.inFlight.delete(rec);\n }\n }\n\n async withLocalFileContent<T>(\n url: string,\n ops: GetContentOptions,\n handler: ContentHandler<T>,\n ): Promise<T> {\n const { storageId, relativePath } = parseLocalUrl(url);\n const fullPath = getFullPath(storageId, this.localStorageIdsToRoot, relativePath);\n\n return await this.localFileReadLimiter.run(async () => {\n const readOps = {\n start: ops.range?.from,\n end: ops.range?.to !== undefined ? ops.range.to - 1 : undefined,\n signal: ops.signal,\n };\n let stream: fs.ReadStream | undefined;\n let handlerSuccess = false;\n\n try {\n const stat = await fsp.stat(fullPath);\n stream = fs.createReadStream(fullPath, readOps);\n const webStream = Readable.toWeb(stream);\n\n const result = await handler(webStream, stat.size);\n handlerSuccess = true;\n return result;\n } catch (error) {\n // Cleanup on error (including handler errors)\n if (!handlerSuccess && stream && !stream.destroyed) {\n stream.destroy();\n }\n throw error;\n }\n });\n }\n\n private async grpcGetDownloadUrl(\n { id, type }: ResourceInfo,\n options?: RpcOptions,\n signal?: AbortSignal,\n ): Promise<DownloadAPI_GetDownloadURL_Response> {\n const withAbort = options ?? {};\n withAbort.abort = signal;\n\n const { globalId, signature } = parseSignedResourceId(id);\n const client = this.wire.get();\n if (client instanceof DownloadClient) {\n return await client.getDownloadURL(\n { resourceId: globalId, resourceSignature: signature, isInternalUse: false },\n addRTypeToMetadata(type, withAbort),\n ).response;\n } else {\n return (\n await client.POST(\"/v1/get-download-url\", {\n body: {\n resourceId: globalId.toString(),\n resourceSignature: signatureToBase64Url(signature),\n isInternalUse: false,\n },\n headers: { ...createRTypeRoutingHeader(type) },\n })\n ).data!;\n }\n }\n}\n\nexport function parseLocalUrl(url: string) {\n const parsed = new URL(url);\n if (parsed.pathname == \"\")\n throw new WrongLocalFileUrl(`url for local filepath ${url} does not match url scheme`);\n\n return {\n storageId: parsed.host,\n relativePath: decodeURIComponent(parsed.pathname.slice(1)),\n };\n}\n\nexport function getFullPath(\n storageId: string,\n localStorageIdsToRoot: Map<string, string>,\n relativePath: string,\n) {\n const root = localStorageIdsToRoot.get(storageId);\n if (root === undefined) throw new UnknownStorageError(`Unknown storage location: ${storageId}`);\n\n if (root === \"\") return relativePath;\n\n return path.join(root, relativePath);\n}\n\nconst storageProtocol = \"storage://\";\nfunction isLocal(url: string) {\n return url.startsWith(storageProtocol);\n}\n\n/** Throws when a local URL have invalid scheme. */\nexport class WrongLocalFileUrl extends Error {\n name = \"WrongLocalFileUrl\";\n}\n\n/** Happens when a storage for a local file can't be found. */\nexport class UnknownStorageError extends Error {\n name = \"UnknownStorageError\";\n}\n\nexport function newLocalStorageIdsToRoot(projections: LocalStorageProjection[]) {\n const idToRoot: Map<string, string> = new Map();\n for (const lp of projections) {\n // Empty string means no prefix, i.e. any file on this machine can be got from the storage.\n if (lp.localPath !== \"\") {\n validateAbsolute(lp.localPath);\n }\n idToRoot.set(lp.storageId, lp.localPath);\n }\n\n return idToRoot;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
1
|
let lru_cache = require("lru-cache");
|
|
3
2
|
//#region src/clients/download_url_cache.ts
|
|
4
3
|
/**
|
|
@@ -76,6 +75,7 @@ function downloadUrlCacheTtlMs(url) {
|
|
|
76
75
|
* always requests `isInternalUse: false`. Revisit if that ever varies.
|
|
77
76
|
*/
|
|
78
77
|
var DownloadUrlCache = class {
|
|
78
|
+
logger;
|
|
79
79
|
cache;
|
|
80
80
|
constructor(logger, maxEntries = DEFAULT_MAX_ENTRIES) {
|
|
81
81
|
this.logger = logger;
|
|
@@ -98,5 +98,7 @@ var DownloadUrlCache = class {
|
|
|
98
98
|
};
|
|
99
99
|
//#endregion
|
|
100
100
|
exports.DownloadUrlCache = DownloadUrlCache;
|
|
101
|
+
exports.downloadUrlCacheTtlMs = downloadUrlCacheTtlMs;
|
|
102
|
+
exports.extractUrlExpiryMs = extractUrlExpiryMs;
|
|
101
103
|
|
|
102
104
|
//# sourceMappingURL=download_url_cache.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download_url_cache.cjs","names":["LRUCache"],"sources":["../../src/clients/download_url_cache.ts"],"sourcesContent":["import { LRUCache } from \"lru-cache\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\n\n/**\n * Safety margin subtracted from the encoded URL expiry. Covers clock skew\n * between this host and pl-core (the timestamp is the server's signing clock,\n * not ours) plus in-flight time between signing and use.\n */\nconst SAFETY_MARGIN_MS = 30_000;\n\n/**\n * TTL applied to download URLs that carry no expiry in their query string -\n * notably local `storage://` URLs, which are deterministic for a given resource\n * and effectively never expire. Bounded so a changed storage projection is\n * eventually re-resolved.\n */\nconst NO_EXPIRY_DEFAULT_TTL_MS = 60 * 60 * 1000; // 1h\n\n/** Max number of cached {url, headers} entries. Each entry is tiny. */\nconst DEFAULT_MAX_ENTRIES = 4096;\n\n/**\n * Extracts the absolute expiry time (epoch ms) encoded in a presigned download\n * URL, or `undefined` if the URL carries no expiry.\n *\n * Supports AWS SigV4 (`X-Amz-Date` + `X-Amz-Expires`, used by pl's S3 and FS\n * remote drivers) and GCS V4 (`X-Goog-Date` + `X-Goog-Expires`). Both encode\n * the date as a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` (trailing `Z`\n * = Zulu/UTC; verified against pl `util/storage/v4sign/presigner.go`) and the\n * lifetime as integer seconds.\n */\nexport function extractUrlExpiryMs(url: string): number | null | undefined {\n let query: URLSearchParams;\n try {\n query = new URL(url).searchParams;\n } catch {\n return undefined;\n }\n\n for (const prefix of [\"X-Amz\", \"X-Goog\"]) {\n const date = query.get(`${prefix}-Date`);\n const expires = query.get(`${prefix}-Expires`);\n if (date === null || expires === null) continue;\n\n const signedAtMs = parseCompactIso8601Utc(date);\n const expiresSec = Number(expires);\n if (signedAtMs === undefined || !Number.isFinite(expiresSec) || expiresSec <= 0) return null;\n\n return signedAtMs + expiresSec * 1000;\n }\n\n return undefined;\n}\n\n/**\n * Parses a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` into epoch ms.\n * `new Date()` cannot parse the compact form, so we expand it to the extended\n * form `YYYY-MM-DDTHH:MM:SSZ`; the trailing `Z` makes it UTC regardless of the\n * host's local timezone.\n */\nfunction parseCompactIso8601Utc(value: string): number | undefined {\n const m = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(value);\n if (m === null) return undefined;\n const [, y, mo, d, h, mi, s] = m;\n const ms = Date.parse(`${y}-${mo}-${d}T${h}:${mi}:${s}Z`);\n return Number.isNaN(ms) ? undefined : ms;\n}\n\n/**\n * Computes the cache TTL (ms from now) for a download URL, with the safety\n * margin already subtracted. Returns a non-positive number when the URL is\n * already within the margin of expiring - the caller should then skip caching.\n */\nexport function downloadUrlCacheTtlMs(url: string): number {\n const expiry = extractUrlExpiryMs(url);\n if (expiry === null) return 0;\n if (expiry === undefined) return NO_EXPIRY_DEFAULT_TTL_MS;\n return expiry - Date.now() - SAFETY_MARGIN_MS;\n}\n\n/**\n * LRU cache of `GetDownloadURL` responses keyed by `SignedResourceId`. Each\n * entry's TTL is derived from the expiry encoded in the presigned URL (minus a\n * safety margin), so an entry never outlives the URL it holds.\n *\n * Note: the key intentionally omits `isInternalUse` because the only caller\n * always requests `isInternalUse: false`. Revisit if that ever varies.\n */\nexport class DownloadUrlCache {\n private readonly cache: LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>;\n\n constructor(\n private readonly logger: MiLogger,\n maxEntries: number = DEFAULT_MAX_ENTRIES,\n ) {\n this.cache = new LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>({\n max: maxEntries,\n // URL expiry is absolute, not sliding - do not extend TTL on access.\n updateAgeOnGet: false,\n });\n }\n\n get(key: SignedResourceId): DownloadAPI_GetDownloadURL_Response | undefined {\n return this.cache.get(key);\n }\n\n set(key: SignedResourceId, value: DownloadAPI_GetDownloadURL_Response): void {\n const ttl = downloadUrlCacheTtlMs(value.downloadUrl);\n if (ttl <= 0) return; // Cache miss.\n this.cache.set(key, value, { ttl });\n }\n\n delete(key: SignedResourceId): void {\n this.cache.delete(key);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"download_url_cache.cjs","names":["LRUCache"],"sources":["../../src/clients/download_url_cache.ts"],"sourcesContent":["import { LRUCache } from \"lru-cache\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\n\n/**\n * Safety margin subtracted from the encoded URL expiry. Covers clock skew\n * between this host and pl-core (the timestamp is the server's signing clock,\n * not ours) plus in-flight time between signing and use.\n */\nconst SAFETY_MARGIN_MS = 30_000;\n\n/**\n * TTL applied to download URLs that carry no expiry in their query string -\n * notably local `storage://` URLs, which are deterministic for a given resource\n * and effectively never expire. Bounded so a changed storage projection is\n * eventually re-resolved.\n */\nconst NO_EXPIRY_DEFAULT_TTL_MS = 60 * 60 * 1000; // 1h\n\n/** Max number of cached {url, headers} entries. Each entry is tiny. */\nconst DEFAULT_MAX_ENTRIES = 4096;\n\n/**\n * Extracts the absolute expiry time (epoch ms) encoded in a presigned download\n * URL, or `undefined` if the URL carries no expiry.\n *\n * Supports AWS SigV4 (`X-Amz-Date` + `X-Amz-Expires`, used by pl's S3 and FS\n * remote drivers) and GCS V4 (`X-Goog-Date` + `X-Goog-Expires`). Both encode\n * the date as a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` (trailing `Z`\n * = Zulu/UTC; verified against pl `util/storage/v4sign/presigner.go`) and the\n * lifetime as integer seconds.\n */\nexport function extractUrlExpiryMs(url: string): number | null | undefined {\n let query: URLSearchParams;\n try {\n query = new URL(url).searchParams;\n } catch {\n return undefined;\n }\n\n for (const prefix of [\"X-Amz\", \"X-Goog\"]) {\n const date = query.get(`${prefix}-Date`);\n const expires = query.get(`${prefix}-Expires`);\n if (date === null || expires === null) continue;\n\n const signedAtMs = parseCompactIso8601Utc(date);\n const expiresSec = Number(expires);\n if (signedAtMs === undefined || !Number.isFinite(expiresSec) || expiresSec <= 0) return null;\n\n return signedAtMs + expiresSec * 1000;\n }\n\n return undefined;\n}\n\n/**\n * Parses a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` into epoch ms.\n * `new Date()` cannot parse the compact form, so we expand it to the extended\n * form `YYYY-MM-DDTHH:MM:SSZ`; the trailing `Z` makes it UTC regardless of the\n * host's local timezone.\n */\nfunction parseCompactIso8601Utc(value: string): number | undefined {\n const m = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(value);\n if (m === null) return undefined;\n const [, y, mo, d, h, mi, s] = m;\n const ms = Date.parse(`${y}-${mo}-${d}T${h}:${mi}:${s}Z`);\n return Number.isNaN(ms) ? undefined : ms;\n}\n\n/**\n * Computes the cache TTL (ms from now) for a download URL, with the safety\n * margin already subtracted. Returns a non-positive number when the URL is\n * already within the margin of expiring - the caller should then skip caching.\n */\nexport function downloadUrlCacheTtlMs(url: string): number {\n const expiry = extractUrlExpiryMs(url);\n if (expiry === null) return 0;\n if (expiry === undefined) return NO_EXPIRY_DEFAULT_TTL_MS;\n return expiry - Date.now() - SAFETY_MARGIN_MS;\n}\n\n/**\n * LRU cache of `GetDownloadURL` responses keyed by `SignedResourceId`. Each\n * entry's TTL is derived from the expiry encoded in the presigned URL (minus a\n * safety margin), so an entry never outlives the URL it holds.\n *\n * Note: the key intentionally omits `isInternalUse` because the only caller\n * always requests `isInternalUse: false`. Revisit if that ever varies.\n */\nexport class DownloadUrlCache {\n private readonly cache: LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>;\n\n constructor(\n private readonly logger: MiLogger,\n maxEntries: number = DEFAULT_MAX_ENTRIES,\n ) {\n this.cache = new LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>({\n max: maxEntries,\n // URL expiry is absolute, not sliding - do not extend TTL on access.\n updateAgeOnGet: false,\n });\n }\n\n get(key: SignedResourceId): DownloadAPI_GetDownloadURL_Response | undefined {\n return this.cache.get(key);\n }\n\n set(key: SignedResourceId, value: DownloadAPI_GetDownloadURL_Response): void {\n const ttl = downloadUrlCacheTtlMs(value.downloadUrl);\n if (ttl <= 0) return; // Cache miss.\n this.cache.set(key, value, { ttl });\n }\n\n delete(key: SignedResourceId): void {\n this.cache.delete(key);\n }\n}\n"],"mappings":";;;;;;;AAUA,MAAM,mBAAmB;;;;;;;AAQzB,MAAM,2BAA2B,OAAU;;AAG3C,MAAM,sBAAsB;;;;;;;;;;;AAY5B,SAAgB,mBAAmB,KAAwC;CACzE,IAAI;CACJ,IAAI;EACF,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC;CACvB,QAAQ;EACN;CACF;CAEA,KAAK,MAAM,UAAU,CAAC,SAAS,QAAQ,GAAG;EACxC,MAAM,OAAO,MAAM,IAAI,GAAG,OAAO,MAAM;EACvC,MAAM,UAAU,MAAM,IAAI,GAAG,OAAO,SAAS;EAC7C,IAAI,SAAS,QAAQ,YAAY,MAAM;EAEvC,MAAM,aAAa,uBAAuB,IAAI;EAC9C,MAAM,aAAa,OAAO,OAAO;EACjC,IAAI,eAAe,KAAA,KAAa,CAAC,OAAO,SAAS,UAAU,KAAK,cAAc,GAAG,OAAO;EAExF,OAAO,aAAa,aAAa;CACnC;AAGF;;;;;;;AAQA,SAAS,uBAAuB,OAAmC;CACjE,MAAM,IAAI,iDAAiD,KAAK,KAAK;CACrE,IAAI,MAAM,MAAM,OAAO,KAAA;CACvB,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK;CAC/B,MAAM,KAAK,KAAK,MAAM,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,EAAE;CACxD,OAAO,OAAO,MAAM,EAAE,IAAI,KAAA,IAAY;AACxC;;;;;;AAOA,SAAgB,sBAAsB,KAAqB;CACzD,MAAM,SAAS,mBAAmB,GAAG;CACrC,IAAI,WAAW,MAAM,OAAO;CAC5B,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,OAAO,SAAS,KAAK,IAAI,IAAI;AAC/B;;;;;;;;;AAUA,IAAa,mBAAb,MAA8B;CAIT;CAHnB;CAEA,YACE,QACA,aAAqB,qBACrB;EAFiB,KAAA,SAAA;EAGjB,KAAK,QAAQ,IAAIA,UAAAA,SAAgE;GAC/E,KAAK;GAEL,gBAAgB;EAClB,CAAC;CACH;CAEA,IAAI,KAAwE;EAC1E,OAAO,KAAK,MAAM,IAAI,GAAG;CAC3B;CAEA,IAAI,KAAuB,OAAkD;EAC3E,MAAM,MAAM,sBAAsB,MAAM,WAAW;EACnD,IAAI,OAAO,GAAG;EACd,KAAK,MAAM,IAAI,KAAK,OAAO,EAAE,IAAI,CAAC;CACpC;CAEA,OAAO,KAA6B;EAClC,KAAK,MAAM,OAAO,GAAG;CACvB;AACF"}
|
|
@@ -75,6 +75,7 @@ function downloadUrlCacheTtlMs(url) {
|
|
|
75
75
|
* always requests `isInternalUse: false`. Revisit if that ever varies.
|
|
76
76
|
*/
|
|
77
77
|
var DownloadUrlCache = class {
|
|
78
|
+
logger;
|
|
78
79
|
cache;
|
|
79
80
|
constructor(logger, maxEntries = DEFAULT_MAX_ENTRIES) {
|
|
80
81
|
this.logger = logger;
|
|
@@ -96,6 +97,6 @@ var DownloadUrlCache = class {
|
|
|
96
97
|
}
|
|
97
98
|
};
|
|
98
99
|
//#endregion
|
|
99
|
-
export { DownloadUrlCache };
|
|
100
|
+
export { DownloadUrlCache, downloadUrlCacheTtlMs, extractUrlExpiryMs };
|
|
100
101
|
|
|
101
102
|
//# sourceMappingURL=download_url_cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download_url_cache.js","names":[],"sources":["../../src/clients/download_url_cache.ts"],"sourcesContent":["import { LRUCache } from \"lru-cache\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\n\n/**\n * Safety margin subtracted from the encoded URL expiry. Covers clock skew\n * between this host and pl-core (the timestamp is the server's signing clock,\n * not ours) plus in-flight time between signing and use.\n */\nconst SAFETY_MARGIN_MS = 30_000;\n\n/**\n * TTL applied to download URLs that carry no expiry in their query string -\n * notably local `storage://` URLs, which are deterministic for a given resource\n * and effectively never expire. Bounded so a changed storage projection is\n * eventually re-resolved.\n */\nconst NO_EXPIRY_DEFAULT_TTL_MS = 60 * 60 * 1000; // 1h\n\n/** Max number of cached {url, headers} entries. Each entry is tiny. */\nconst DEFAULT_MAX_ENTRIES = 4096;\n\n/**\n * Extracts the absolute expiry time (epoch ms) encoded in a presigned download\n * URL, or `undefined` if the URL carries no expiry.\n *\n * Supports AWS SigV4 (`X-Amz-Date` + `X-Amz-Expires`, used by pl's S3 and FS\n * remote drivers) and GCS V4 (`X-Goog-Date` + `X-Goog-Expires`). Both encode\n * the date as a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` (trailing `Z`\n * = Zulu/UTC; verified against pl `util/storage/v4sign/presigner.go`) and the\n * lifetime as integer seconds.\n */\nexport function extractUrlExpiryMs(url: string): number | null | undefined {\n let query: URLSearchParams;\n try {\n query = new URL(url).searchParams;\n } catch {\n return undefined;\n }\n\n for (const prefix of [\"X-Amz\", \"X-Goog\"]) {\n const date = query.get(`${prefix}-Date`);\n const expires = query.get(`${prefix}-Expires`);\n if (date === null || expires === null) continue;\n\n const signedAtMs = parseCompactIso8601Utc(date);\n const expiresSec = Number(expires);\n if (signedAtMs === undefined || !Number.isFinite(expiresSec) || expiresSec <= 0) return null;\n\n return signedAtMs + expiresSec * 1000;\n }\n\n return undefined;\n}\n\n/**\n * Parses a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` into epoch ms.\n * `new Date()` cannot parse the compact form, so we expand it to the extended\n * form `YYYY-MM-DDTHH:MM:SSZ`; the trailing `Z` makes it UTC regardless of the\n * host's local timezone.\n */\nfunction parseCompactIso8601Utc(value: string): number | undefined {\n const m = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(value);\n if (m === null) return undefined;\n const [, y, mo, d, h, mi, s] = m;\n const ms = Date.parse(`${y}-${mo}-${d}T${h}:${mi}:${s}Z`);\n return Number.isNaN(ms) ? undefined : ms;\n}\n\n/**\n * Computes the cache TTL (ms from now) for a download URL, with the safety\n * margin already subtracted. Returns a non-positive number when the URL is\n * already within the margin of expiring - the caller should then skip caching.\n */\nexport function downloadUrlCacheTtlMs(url: string): number {\n const expiry = extractUrlExpiryMs(url);\n if (expiry === null) return 0;\n if (expiry === undefined) return NO_EXPIRY_DEFAULT_TTL_MS;\n return expiry - Date.now() - SAFETY_MARGIN_MS;\n}\n\n/**\n * LRU cache of `GetDownloadURL` responses keyed by `SignedResourceId`. Each\n * entry's TTL is derived from the expiry encoded in the presigned URL (minus a\n * safety margin), so an entry never outlives the URL it holds.\n *\n * Note: the key intentionally omits `isInternalUse` because the only caller\n * always requests `isInternalUse: false`. Revisit if that ever varies.\n */\nexport class DownloadUrlCache {\n private readonly cache: LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>;\n\n constructor(\n private readonly logger: MiLogger,\n maxEntries: number = DEFAULT_MAX_ENTRIES,\n ) {\n this.cache = new LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>({\n max: maxEntries,\n // URL expiry is absolute, not sliding - do not extend TTL on access.\n updateAgeOnGet: false,\n });\n }\n\n get(key: SignedResourceId): DownloadAPI_GetDownloadURL_Response | undefined {\n return this.cache.get(key);\n }\n\n set(key: SignedResourceId, value: DownloadAPI_GetDownloadURL_Response): void {\n const ttl = downloadUrlCacheTtlMs(value.downloadUrl);\n if (ttl <= 0) return; // Cache miss.\n this.cache.set(key, value, { ttl });\n }\n\n delete(key: SignedResourceId): void {\n this.cache.delete(key);\n }\n}\n"],"mappings":";;;;;;;AAUA,MAAM,mBAAmB;;;;;;;AAQzB,MAAM,2BAA2B,OAAU;;AAG3C,MAAM,sBAAsB;;;;;;;;;;;AAY5B,SAAgB,mBAAmB,KAAwC;CACzE,IAAI;
|
|
1
|
+
{"version":3,"file":"download_url_cache.js","names":[],"sources":["../../src/clients/download_url_cache.ts"],"sourcesContent":["import { LRUCache } from \"lru-cache\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { DownloadAPI_GetDownloadURL_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol\";\n\n/**\n * Safety margin subtracted from the encoded URL expiry. Covers clock skew\n * between this host and pl-core (the timestamp is the server's signing clock,\n * not ours) plus in-flight time between signing and use.\n */\nconst SAFETY_MARGIN_MS = 30_000;\n\n/**\n * TTL applied to download URLs that carry no expiry in their query string -\n * notably local `storage://` URLs, which are deterministic for a given resource\n * and effectively never expire. Bounded so a changed storage projection is\n * eventually re-resolved.\n */\nconst NO_EXPIRY_DEFAULT_TTL_MS = 60 * 60 * 1000; // 1h\n\n/** Max number of cached {url, headers} entries. Each entry is tiny. */\nconst DEFAULT_MAX_ENTRIES = 4096;\n\n/**\n * Extracts the absolute expiry time (epoch ms) encoded in a presigned download\n * URL, or `undefined` if the URL carries no expiry.\n *\n * Supports AWS SigV4 (`X-Amz-Date` + `X-Amz-Expires`, used by pl's S3 and FS\n * remote drivers) and GCS V4 (`X-Goog-Date` + `X-Goog-Expires`). Both encode\n * the date as a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` (trailing `Z`\n * = Zulu/UTC; verified against pl `util/storage/v4sign/presigner.go`) and the\n * lifetime as integer seconds.\n */\nexport function extractUrlExpiryMs(url: string): number | null | undefined {\n let query: URLSearchParams;\n try {\n query = new URL(url).searchParams;\n } catch {\n return undefined;\n }\n\n for (const prefix of [\"X-Amz\", \"X-Goog\"]) {\n const date = query.get(`${prefix}-Date`);\n const expires = query.get(`${prefix}-Expires`);\n if (date === null || expires === null) continue;\n\n const signedAtMs = parseCompactIso8601Utc(date);\n const expiresSec = Number(expires);\n if (signedAtMs === undefined || !Number.isFinite(expiresSec) || expiresSec <= 0) return null;\n\n return signedAtMs + expiresSec * 1000;\n }\n\n return undefined;\n}\n\n/**\n * Parses a compact ISO-8601 UTC timestamp `YYYYMMDDTHHMMSSZ` into epoch ms.\n * `new Date()` cannot parse the compact form, so we expand it to the extended\n * form `YYYY-MM-DDTHH:MM:SSZ`; the trailing `Z` makes it UTC regardless of the\n * host's local timezone.\n */\nfunction parseCompactIso8601Utc(value: string): number | undefined {\n const m = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(value);\n if (m === null) return undefined;\n const [, y, mo, d, h, mi, s] = m;\n const ms = Date.parse(`${y}-${mo}-${d}T${h}:${mi}:${s}Z`);\n return Number.isNaN(ms) ? undefined : ms;\n}\n\n/**\n * Computes the cache TTL (ms from now) for a download URL, with the safety\n * margin already subtracted. Returns a non-positive number when the URL is\n * already within the margin of expiring - the caller should then skip caching.\n */\nexport function downloadUrlCacheTtlMs(url: string): number {\n const expiry = extractUrlExpiryMs(url);\n if (expiry === null) return 0;\n if (expiry === undefined) return NO_EXPIRY_DEFAULT_TTL_MS;\n return expiry - Date.now() - SAFETY_MARGIN_MS;\n}\n\n/**\n * LRU cache of `GetDownloadURL` responses keyed by `SignedResourceId`. Each\n * entry's TTL is derived from the expiry encoded in the presigned URL (minus a\n * safety margin), so an entry never outlives the URL it holds.\n *\n * Note: the key intentionally omits `isInternalUse` because the only caller\n * always requests `isInternalUse: false`. Revisit if that ever varies.\n */\nexport class DownloadUrlCache {\n private readonly cache: LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>;\n\n constructor(\n private readonly logger: MiLogger,\n maxEntries: number = DEFAULT_MAX_ENTRIES,\n ) {\n this.cache = new LRUCache<SignedResourceId, DownloadAPI_GetDownloadURL_Response>({\n max: maxEntries,\n // URL expiry is absolute, not sliding - do not extend TTL on access.\n updateAgeOnGet: false,\n });\n }\n\n get(key: SignedResourceId): DownloadAPI_GetDownloadURL_Response | undefined {\n return this.cache.get(key);\n }\n\n set(key: SignedResourceId, value: DownloadAPI_GetDownloadURL_Response): void {\n const ttl = downloadUrlCacheTtlMs(value.downloadUrl);\n if (ttl <= 0) return; // Cache miss.\n this.cache.set(key, value, { ttl });\n }\n\n delete(key: SignedResourceId): void {\n this.cache.delete(key);\n }\n}\n"],"mappings":";;;;;;;AAUA,MAAM,mBAAmB;;;;;;;AAQzB,MAAM,2BAA2B,OAAU;;AAG3C,MAAM,sBAAsB;;;;;;;;;;;AAY5B,SAAgB,mBAAmB,KAAwC;CACzE,IAAI;CACJ,IAAI;EACF,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC;CACvB,QAAQ;EACN;CACF;CAEA,KAAK,MAAM,UAAU,CAAC,SAAS,QAAQ,GAAG;EACxC,MAAM,OAAO,MAAM,IAAI,GAAG,OAAO,MAAM;EACvC,MAAM,UAAU,MAAM,IAAI,GAAG,OAAO,SAAS;EAC7C,IAAI,SAAS,QAAQ,YAAY,MAAM;EAEvC,MAAM,aAAa,uBAAuB,IAAI;EAC9C,MAAM,aAAa,OAAO,OAAO;EACjC,IAAI,eAAe,KAAA,KAAa,CAAC,OAAO,SAAS,UAAU,KAAK,cAAc,GAAG,OAAO;EAExF,OAAO,aAAa,aAAa;CACnC;AAGF;;;;;;;AAQA,SAAS,uBAAuB,OAAmC;CACjE,MAAM,IAAI,iDAAiD,KAAK,KAAK;CACrE,IAAI,MAAM,MAAM,OAAO,KAAA;CACvB,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK;CAC/B,MAAM,KAAK,KAAK,MAAM,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,EAAE;CACxD,OAAO,OAAO,MAAM,EAAE,IAAI,KAAA,IAAY;AACxC;;;;;;AAOA,SAAgB,sBAAsB,KAAqB;CACzD,MAAM,SAAS,mBAAmB,GAAG;CACrC,IAAI,WAAW,MAAM,OAAO;CAC5B,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,OAAO,SAAS,KAAK,IAAI,IAAI;AAC/B;;;;;;;;;AAUA,IAAa,mBAAb,MAA8B;CAIT;CAHnB;CAEA,YACE,QACA,aAAqB,qBACrB;EAFiB,KAAA,SAAA;EAGjB,KAAK,QAAQ,IAAI,SAAgE;GAC/E,KAAK;GAEL,gBAAgB;EAClB,CAAC;CACH;CAEA,IAAI,KAAwE;EAC1E,OAAO,KAAK,MAAM,IAAI,GAAG;CAC3B;CAEA,IAAI,KAAuB,OAAkD;EAC3E,MAAM,MAAM,sBAAsB,MAAM,WAAW;EACnD,IAAI,OAAO,GAAG;EACd,KAAK,MAAM,IAAI,KAAK,OAAO,EAAE,IAAI,CAAC;CACpC;CAEA,OAAO,KAA6B;EAClC,KAAK,MAAM,OAAO,GAAG;CACvB;AACF"}
|
package/dist/clients/logs.cjs
CHANGED
|
@@ -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/streamingapi/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/logs.ts
|
|
6
5
|
var ClientLogs = class {
|
|
6
|
+
httpClient;
|
|
7
|
+
logger;
|
|
7
8
|
wire;
|
|
8
9
|
constructor(wireClientProviderFactory, httpClient, logger) {
|
|
9
10
|
this.httpClient = httpClient;
|