@milaboratories/pl-drivers 1.13.1 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/clients/download.cjs +5 -3
  2. package/dist/clients/download.cjs.map +1 -1
  3. package/dist/clients/download.d.ts.map +1 -1
  4. package/dist/clients/download.js +6 -4
  5. package/dist/clients/download.js.map +1 -1
  6. package/dist/clients/logs.cjs +10 -6
  7. package/dist/clients/logs.cjs.map +1 -1
  8. package/dist/clients/logs.d.ts.map +1 -1
  9. package/dist/clients/logs.js +11 -7
  10. package/dist/clients/logs.js.map +1 -1
  11. package/dist/clients/ls_api.cjs +5 -3
  12. package/dist/clients/ls_api.cjs.map +1 -1
  13. package/dist/clients/ls_api.js +6 -4
  14. package/dist/clients/ls_api.js.map +1 -1
  15. package/dist/clients/progress.cjs +7 -3
  16. package/dist/clients/progress.cjs.map +1 -1
  17. package/dist/clients/progress.d.ts.map +1 -1
  18. package/dist/clients/progress.js +8 -4
  19. package/dist/clients/progress.js.map +1 -1
  20. package/dist/clients/upload.cjs +22 -12
  21. package/dist/clients/upload.cjs.map +1 -1
  22. package/dist/clients/upload.d.ts.map +1 -1
  23. package/dist/clients/upload.js +23 -13
  24. package/dist/clients/upload.js.map +1 -1
  25. package/dist/drivers/download_blob/blob_key.cjs +3 -2
  26. package/dist/drivers/download_blob/blob_key.cjs.map +1 -1
  27. package/dist/drivers/download_blob/blob_key.js +3 -2
  28. package/dist/drivers/download_blob/blob_key.js.map +1 -1
  29. package/dist/drivers/download_blob/download_blob.cjs.map +1 -1
  30. package/dist/drivers/download_blob/download_blob.js.map +1 -1
  31. package/dist/drivers/download_blob_url/driver.cjs +2 -1
  32. package/dist/drivers/download_blob_url/driver.cjs.map +1 -1
  33. package/dist/drivers/download_blob_url/driver.d.ts +2 -2
  34. package/dist/drivers/download_blob_url/driver.d.ts.map +1 -1
  35. package/dist/drivers/download_blob_url/driver.js +3 -2
  36. package/dist/drivers/download_blob_url/driver.js.map +1 -1
  37. package/dist/drivers/download_blob_url/driver_id.cjs +4 -1
  38. package/dist/drivers/download_blob_url/driver_id.cjs.map +1 -1
  39. package/dist/drivers/download_blob_url/driver_id.js +3 -1
  40. package/dist/drivers/download_blob_url/driver_id.js.map +1 -1
  41. package/dist/drivers/download_url/task.cjs +1 -1
  42. package/dist/drivers/download_url/task.cjs.map +1 -1
  43. package/dist/drivers/download_url/task.d.ts.map +1 -1
  44. package/dist/drivers/download_url/task.js +1 -1
  45. package/dist/drivers/download_url/task.js.map +1 -1
  46. package/dist/drivers/helpers/download_remote_handle.cjs +7 -4
  47. package/dist/drivers/helpers/download_remote_handle.cjs.map +1 -1
  48. package/dist/drivers/helpers/download_remote_handle.js +8 -5
  49. package/dist/drivers/helpers/download_remote_handle.js.map +1 -1
  50. package/dist/drivers/helpers/logs_handle.cjs +9 -6
  51. package/dist/drivers/helpers/logs_handle.cjs.map +1 -1
  52. package/dist/drivers/helpers/logs_handle.js +10 -7
  53. package/dist/drivers/helpers/logs_handle.js.map +1 -1
  54. package/dist/drivers/helpers/ls_remote_import_handle.cjs +2 -2
  55. package/dist/drivers/helpers/ls_remote_import_handle.cjs.map +1 -1
  56. package/dist/drivers/helpers/ls_remote_import_handle.js +2 -2
  57. package/dist/drivers/helpers/ls_remote_import_handle.js.map +1 -1
  58. package/dist/drivers/helpers/ls_storage_entry.cjs +10 -16
  59. package/dist/drivers/helpers/ls_storage_entry.cjs.map +1 -1
  60. package/dist/drivers/helpers/ls_storage_entry.js +11 -17
  61. package/dist/drivers/helpers/ls_storage_entry.js.map +1 -1
  62. package/dist/drivers/logs_stream.cjs.map +1 -1
  63. package/dist/drivers/logs_stream.js.map +1 -1
  64. package/dist/drivers/ls.cjs +31 -29
  65. package/dist/drivers/ls.cjs.map +1 -1
  66. package/dist/drivers/ls.d.ts +10 -10
  67. package/dist/drivers/ls.d.ts.map +1 -1
  68. package/dist/drivers/ls.js +31 -29
  69. package/dist/drivers/ls.js.map +1 -1
  70. package/dist/drivers/types.cjs.map +1 -1
  71. package/dist/drivers/types.d.ts +2 -1
  72. package/dist/drivers/types.d.ts.map +1 -1
  73. package/dist/drivers/types.js.map +1 -1
  74. package/dist/drivers/upload.cjs.map +1 -1
  75. package/dist/drivers/upload.js.map +1 -1
  76. package/dist/drivers/virtual_storages.cjs +3 -0
  77. package/dist/drivers/virtual_storages.cjs.map +1 -1
  78. package/dist/drivers/virtual_storages.js +3 -0
  79. package/dist/drivers/virtual_storages.js.map +1 -1
  80. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.cjs +2 -2
  81. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.cjs.map +1 -1
  82. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts +2 -2
  83. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts.map +1 -1
  84. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.js +2 -2
  85. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.js.map +1 -1
  86. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.cjs +2 -2
  87. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.cjs.map +1 -1
  88. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts.map +1 -1
  89. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.js +2 -2
  90. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.js.map +1 -1
  91. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.cjs +4 -4
  92. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.cjs.map +1 -1
  93. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts +4 -4
  94. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts.map +1 -1
  95. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.js +4 -4
  96. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.js.map +1 -1
  97. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.cjs +6 -6
  98. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.cjs.map +1 -1
  99. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts +6 -6
  100. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts.map +1 -1
  101. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.js +6 -6
  102. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.js.map +1 -1
  103. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs +10 -10
  104. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.cjs.map +1 -1
  105. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js +10 -10
  106. package/dist/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.js.map +1 -1
  107. package/dist/proto-rest/downloadapi.d.ts +6 -6
  108. package/dist/proto-rest/downloadapi.d.ts.map +1 -1
  109. package/dist/proto-rest/progressapi.d.ts +19 -19
  110. package/dist/proto-rest/progressapi.d.ts.map +1 -1
  111. package/package.json +7 -7
  112. package/src/clients/download.ts +6 -3
  113. package/src/clients/logs.ts +22 -7
  114. package/src/clients/ls_api.ts +6 -4
  115. package/src/clients/progress.ts +18 -4
  116. package/src/clients/upload.ts +31 -14
  117. package/src/drivers/download_blob/blob_key.ts +4 -8
  118. package/src/drivers/download_blob/download_blob.ts +2 -2
  119. package/src/drivers/download_blob_url/driver.ts +10 -5
  120. package/src/drivers/download_blob_url/driver_id.ts +5 -3
  121. package/src/drivers/download_url/task.ts +5 -1
  122. package/src/drivers/helpers/download_remote_handle.ts +16 -5
  123. package/src/drivers/helpers/logs_handle.ts +16 -7
  124. package/src/drivers/helpers/ls_remote_import_handle.ts +2 -2
  125. package/src/drivers/helpers/ls_storage_entry.ts +15 -17
  126. package/src/drivers/logs_stream.ts +5 -5
  127. package/src/drivers/ls.test.ts +4 -4
  128. package/src/drivers/ls.ts +44 -58
  129. package/src/drivers/types.ts +3 -1
  130. package/src/drivers/upload.ts +3 -3
  131. package/src/drivers/virtual_storages.ts +3 -0
  132. package/src/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.ts +7 -6
  133. package/src/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.ts +7 -6
  134. package/src/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.ts +14 -12
  135. package/src/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.ts +21 -18
  136. package/src/proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.ts +35 -30
  137. package/src/proto-grpc/google/protobuf/descriptor.ts +5 -2
  138. package/src/proto-rest/downloadapi.ts +6 -6
  139. package/src/proto-rest/lsapi.ts +30 -30
  140. package/src/proto-rest/progressapi.ts +21 -21
  141. package/src/proto-rest/uploadapi.ts +41 -41
@@ -2,18 +2,20 @@ require("../../_virtual/_rolldown/runtime.cjs");
2
2
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
3
3
  //#region src/drivers/helpers/logs_handle.ts
4
4
  function newLogHandle(live, rInfo) {
5
- if (live) return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}`;
6
- return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}`;
5
+ const { globalId, signature } = (0, _milaboratories_pl_client.parseSignedResourceId)(rInfo.id);
6
+ const sigSegment = (0, _milaboratories_pl_client.signatureToBase64Url)(signature);
7
+ if (live) return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}`;
8
+ return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}`;
7
9
  }
8
10
  /** Handle of the live logs of a program.
9
11
  * The resource that represents a log can be deleted,
10
12
  * in this case the handle should be refreshed. */
11
- const liveHandleRegex = /^log\+live:\/\/log\/(?<resourceType>.*)\/(?<resourceVersion>.*)\/(?<resourceId>.*)$/;
13
+ const liveHandleRegex = /^log\+live:\/\/log\/(?<resourceType>.+)\/(?<resourceVersion>[^/]+)\/(?<resourceId>\d+)\/(?<resourceSig>[A-Za-z0-9_\-=]*)$/;
12
14
  function isLiveLogHandle(handle) {
13
15
  return liveHandleRegex.test(handle);
14
16
  }
15
17
  /** Handle of the ready logs of a program. */
16
- const readyHandleRegex = /^log\+ready:\/\/log\/(?<resourceType>.*)\/(?<resourceVersion>.*)\/(?<resourceId>.*)$/;
18
+ const readyHandleRegex = /^log\+ready:\/\/log\/(?<resourceType>.+)\/(?<resourceVersion>.+)\/(?<resourceId>\d+)\/(?<resourceSig>[A-Za-z0-9_\-=]*)$/;
17
19
  function isReadyLogHandle(handle) {
18
20
  return readyHandleRegex.test(handle);
19
21
  }
@@ -23,9 +25,10 @@ function getResourceInfoFromLogHandle(handle) {
23
25
  else if (isReadyLogHandle(handle)) parsed = handle.match(readyHandleRegex);
24
26
  else throw new Error(`Log handle is malformed: ${handle}`);
25
27
  if (parsed == null) throw new Error(`Log handle wasn't parsed: ${handle}`);
26
- const { resourceType, resourceVersion, resourceId } = parsed.groups;
28
+ const { resourceType, resourceVersion, resourceId, resourceSig } = parsed.groups;
29
+ const sig = resourceSig ? (0, _milaboratories_pl_client.base64UrlToSignature)(resourceSig) : void 0;
27
30
  return {
28
- id: (0, _milaboratories_pl_client.bigintToResourceId)(BigInt(resourceId)),
31
+ id: (0, _milaboratories_pl_client.createSignedResourceId)(BigInt(resourceId), sig),
29
32
  type: {
30
33
  name: resourceType,
31
34
  version: resourceVersion
@@ -1 +1 @@
1
- {"version":3,"file":"logs_handle.cjs","names":[],"sources":["../../../src/drivers/helpers/logs_handle.ts"],"sourcesContent":["/** Handle of logs. This handle should be passed\n * to the driver for retrieving logs. */\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport { bigintToResourceId } from \"@milaboratories/pl-client\";\n\nexport function newLogHandle(live: boolean, rInfo: ResourceInfo): sdk.AnyLogHandle {\n if (live) {\n return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}` as sdk.LiveLogHandle;\n }\n\n return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}` as sdk.ReadyLogHandle;\n}\n\n/** Handle of the live logs of a program.\n * The resource that represents a log can be deleted,\n * in this case the handle should be refreshed. */\n\nexport const liveHandleRegex =\n /^log\\+live:\\/\\/log\\/(?<resourceType>.*)\\/(?<resourceVersion>.*)\\/(?<resourceId>.*)$/;\n\nexport function isLiveLogHandle(handle: string): handle is sdk.LiveLogHandle {\n return liveHandleRegex.test(handle);\n}\n\n/** Handle of the ready logs of a program. */\n\nexport const readyHandleRegex =\n /^log\\+ready:\\/\\/log\\/(?<resourceType>.*)\\/(?<resourceVersion>.*)\\/(?<resourceId>.*)$/;\n\nexport function isReadyLogHandle(handle: string): handle is sdk.ReadyLogHandle {\n return readyHandleRegex.test(handle);\n}\n\nexport function getResourceInfoFromLogHandle(handle: sdk.AnyLogHandle): ResourceInfo {\n let parsed: RegExpMatchArray | null;\n\n if (isLiveLogHandle(handle)) {\n parsed = handle.match(liveHandleRegex);\n } else if (isReadyLogHandle(handle)) {\n parsed = handle.match(readyHandleRegex);\n } else throw new Error(`Log handle is malformed: ${handle}`);\n if (parsed == null) throw new Error(`Log handle wasn't parsed: ${handle}`);\n\n const { resourceType, resourceVersion, resourceId } = parsed.groups!;\n\n return {\n id: bigintToResourceId(BigInt(resourceId)),\n type: { name: resourceType, version: resourceVersion },\n };\n}\n"],"mappings":";;;AAOA,SAAgB,aAAa,MAAe,OAAuC;AACjF,KAAI,KACF,QAAO,kBAAkB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,OAAO,MAAM,GAAG;AAGpF,QAAO,mBAAmB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,OAAO,MAAM,GAAG;;;;;AAOrF,MAAa,kBACX;AAEF,SAAgB,gBAAgB,QAA6C;AAC3E,QAAO,gBAAgB,KAAK,OAAO;;;AAKrC,MAAa,mBACX;AAEF,SAAgB,iBAAiB,QAA8C;AAC7E,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,6BAA6B,QAAwC;CACnF,IAAI;AAEJ,KAAI,gBAAgB,OAAO,CACzB,UAAS,OAAO,MAAM,gBAAgB;UAC7B,iBAAiB,OAAO,CACjC,UAAS,OAAO,MAAM,iBAAiB;KAClC,OAAM,IAAI,MAAM,4BAA4B,SAAS;AAC5D,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,6BAA6B,SAAS;CAE1E,MAAM,EAAE,cAAc,iBAAiB,eAAe,OAAO;AAE7D,QAAO;EACL,KAAA,GAAA,0BAAA,oBAAuB,OAAO,WAAW,CAAC;EAC1C,MAAM;GAAE,MAAM;GAAc,SAAS;GAAiB;EACvD"}
1
+ {"version":3,"file":"logs_handle.cjs","names":[],"sources":["../../../src/drivers/helpers/logs_handle.ts"],"sourcesContent":["/** Handle of logs. This handle should be passed\n * to the driver for retrieving logs. */\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport {\n createSignedResourceId,\n parseSignedResourceId,\n signatureToBase64Url,\n base64UrlToSignature,\n} from \"@milaboratories/pl-client\";\n\nexport function newLogHandle(live: boolean, rInfo: ResourceInfo): sdk.AnyLogHandle {\n const { globalId, signature } = parseSignedResourceId(rInfo.id);\n const sigSegment = signatureToBase64Url(signature);\n if (live) {\n return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}` as sdk.LiveLogHandle;\n }\n\n return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}` as sdk.ReadyLogHandle;\n}\n\n/** Handle of the live logs of a program.\n * The resource that represents a log can be deleted,\n * in this case the handle should be refreshed. */\n\nexport const liveHandleRegex =\n /^log\\+live:\\/\\/log\\/(?<resourceType>.+)\\/(?<resourceVersion>[^/]+)\\/(?<resourceId>\\d+)\\/(?<resourceSig>[A-Za-z0-9_\\-=]*)$/;\n\nexport function isLiveLogHandle(handle: string): handle is sdk.LiveLogHandle {\n return liveHandleRegex.test(handle);\n}\n\n/** Handle of the ready logs of a program. */\n\nexport const readyHandleRegex =\n /^log\\+ready:\\/\\/log\\/(?<resourceType>.+)\\/(?<resourceVersion>.+)\\/(?<resourceId>\\d+)\\/(?<resourceSig>[A-Za-z0-9_\\-=]*)$/;\n\nexport function isReadyLogHandle(handle: string): handle is sdk.ReadyLogHandle {\n return readyHandleRegex.test(handle);\n}\n\nexport function getResourceInfoFromLogHandle(handle: sdk.AnyLogHandle): ResourceInfo {\n let parsed: RegExpMatchArray | null;\n\n if (isLiveLogHandle(handle)) {\n parsed = handle.match(liveHandleRegex);\n } else if (isReadyLogHandle(handle)) {\n parsed = handle.match(readyHandleRegex);\n } else throw new Error(`Log handle is malformed: ${handle}`);\n if (parsed == null) throw new Error(`Log handle wasn't parsed: ${handle}`);\n\n const { resourceType, resourceVersion, resourceId, resourceSig } = parsed.groups!;\n\n const sig = resourceSig ? base64UrlToSignature(resourceSig) : undefined;\n\n return {\n id: createSignedResourceId(BigInt(resourceId), sig),\n type: { name: resourceType, version: resourceVersion },\n };\n}\n"],"mappings":";;;AAYA,SAAgB,aAAa,MAAe,OAAuC;CACjF,MAAM,EAAE,UAAU,eAAA,GAAA,0BAAA,uBAAoC,MAAM,GAAG;CAC/D,MAAM,cAAA,GAAA,0BAAA,sBAAkC,UAAU;AAClD,KAAI,KACF,QAAO,kBAAkB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,SAAS,GAAG;AAGhF,QAAO,mBAAmB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,SAAS,GAAG;;;;;AAOjF,MAAa,kBACX;AAEF,SAAgB,gBAAgB,QAA6C;AAC3E,QAAO,gBAAgB,KAAK,OAAO;;;AAKrC,MAAa,mBACX;AAEF,SAAgB,iBAAiB,QAA8C;AAC7E,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,6BAA6B,QAAwC;CACnF,IAAI;AAEJ,KAAI,gBAAgB,OAAO,CACzB,UAAS,OAAO,MAAM,gBAAgB;UAC7B,iBAAiB,OAAO,CACjC,UAAS,OAAO,MAAM,iBAAiB;KAClC,OAAM,IAAI,MAAM,4BAA4B,SAAS;AAC5D,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,6BAA6B,SAAS;CAE1E,MAAM,EAAE,cAAc,iBAAiB,YAAY,gBAAgB,OAAO;CAE1E,MAAM,MAAM,eAAA,GAAA,0BAAA,sBAAmC,YAAY,GAAG,KAAA;AAE9D,QAAO;EACL,KAAA,GAAA,0BAAA,wBAA2B,OAAO,WAAW,EAAE,IAAI;EACnD,MAAM;GAAE,MAAM;GAAc,SAAS;GAAiB;EACvD"}
@@ -1,18 +1,20 @@
1
- import { bigintToResourceId } from "@milaboratories/pl-client";
1
+ import { base64UrlToSignature, createSignedResourceId, parseSignedResourceId, signatureToBase64Url } from "@milaboratories/pl-client";
2
2
  //#region src/drivers/helpers/logs_handle.ts
3
3
  function newLogHandle(live, rInfo) {
4
- if (live) return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}`;
5
- return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}`;
4
+ const { globalId, signature } = parseSignedResourceId(rInfo.id);
5
+ const sigSegment = signatureToBase64Url(signature);
6
+ if (live) return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}`;
7
+ return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}`;
6
8
  }
7
9
  /** Handle of the live logs of a program.
8
10
  * The resource that represents a log can be deleted,
9
11
  * in this case the handle should be refreshed. */
10
- const liveHandleRegex = /^log\+live:\/\/log\/(?<resourceType>.*)\/(?<resourceVersion>.*)\/(?<resourceId>.*)$/;
12
+ const liveHandleRegex = /^log\+live:\/\/log\/(?<resourceType>.+)\/(?<resourceVersion>[^/]+)\/(?<resourceId>\d+)\/(?<resourceSig>[A-Za-z0-9_\-=]*)$/;
11
13
  function isLiveLogHandle(handle) {
12
14
  return liveHandleRegex.test(handle);
13
15
  }
14
16
  /** Handle of the ready logs of a program. */
15
- const readyHandleRegex = /^log\+ready:\/\/log\/(?<resourceType>.*)\/(?<resourceVersion>.*)\/(?<resourceId>.*)$/;
17
+ const readyHandleRegex = /^log\+ready:\/\/log\/(?<resourceType>.+)\/(?<resourceVersion>.+)\/(?<resourceId>\d+)\/(?<resourceSig>[A-Za-z0-9_\-=]*)$/;
16
18
  function isReadyLogHandle(handle) {
17
19
  return readyHandleRegex.test(handle);
18
20
  }
@@ -22,9 +24,10 @@ function getResourceInfoFromLogHandle(handle) {
22
24
  else if (isReadyLogHandle(handle)) parsed = handle.match(readyHandleRegex);
23
25
  else throw new Error(`Log handle is malformed: ${handle}`);
24
26
  if (parsed == null) throw new Error(`Log handle wasn't parsed: ${handle}`);
25
- const { resourceType, resourceVersion, resourceId } = parsed.groups;
27
+ const { resourceType, resourceVersion, resourceId, resourceSig } = parsed.groups;
28
+ const sig = resourceSig ? base64UrlToSignature(resourceSig) : void 0;
26
29
  return {
27
- id: bigintToResourceId(BigInt(resourceId)),
30
+ id: createSignedResourceId(BigInt(resourceId), sig),
28
31
  type: {
29
32
  name: resourceType,
30
33
  version: resourceVersion
@@ -1 +1 @@
1
- {"version":3,"file":"logs_handle.js","names":[],"sources":["../../../src/drivers/helpers/logs_handle.ts"],"sourcesContent":["/** Handle of logs. This handle should be passed\n * to the driver for retrieving logs. */\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport { bigintToResourceId } from \"@milaboratories/pl-client\";\n\nexport function newLogHandle(live: boolean, rInfo: ResourceInfo): sdk.AnyLogHandle {\n if (live) {\n return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}` as sdk.LiveLogHandle;\n }\n\n return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${BigInt(rInfo.id)}` as sdk.ReadyLogHandle;\n}\n\n/** Handle of the live logs of a program.\n * The resource that represents a log can be deleted,\n * in this case the handle should be refreshed. */\n\nexport const liveHandleRegex =\n /^log\\+live:\\/\\/log\\/(?<resourceType>.*)\\/(?<resourceVersion>.*)\\/(?<resourceId>.*)$/;\n\nexport function isLiveLogHandle(handle: string): handle is sdk.LiveLogHandle {\n return liveHandleRegex.test(handle);\n}\n\n/** Handle of the ready logs of a program. */\n\nexport const readyHandleRegex =\n /^log\\+ready:\\/\\/log\\/(?<resourceType>.*)\\/(?<resourceVersion>.*)\\/(?<resourceId>.*)$/;\n\nexport function isReadyLogHandle(handle: string): handle is sdk.ReadyLogHandle {\n return readyHandleRegex.test(handle);\n}\n\nexport function getResourceInfoFromLogHandle(handle: sdk.AnyLogHandle): ResourceInfo {\n let parsed: RegExpMatchArray | null;\n\n if (isLiveLogHandle(handle)) {\n parsed = handle.match(liveHandleRegex);\n } else if (isReadyLogHandle(handle)) {\n parsed = handle.match(readyHandleRegex);\n } else throw new Error(`Log handle is malformed: ${handle}`);\n if (parsed == null) throw new Error(`Log handle wasn't parsed: ${handle}`);\n\n const { resourceType, resourceVersion, resourceId } = parsed.groups!;\n\n return {\n id: bigintToResourceId(BigInt(resourceId)),\n type: { name: resourceType, version: resourceVersion },\n };\n}\n"],"mappings":";;AAOA,SAAgB,aAAa,MAAe,OAAuC;AACjF,KAAI,KACF,QAAO,kBAAkB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,OAAO,MAAM,GAAG;AAGpF,QAAO,mBAAmB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,OAAO,MAAM,GAAG;;;;;AAOrF,MAAa,kBACX;AAEF,SAAgB,gBAAgB,QAA6C;AAC3E,QAAO,gBAAgB,KAAK,OAAO;;;AAKrC,MAAa,mBACX;AAEF,SAAgB,iBAAiB,QAA8C;AAC7E,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,6BAA6B,QAAwC;CACnF,IAAI;AAEJ,KAAI,gBAAgB,OAAO,CACzB,UAAS,OAAO,MAAM,gBAAgB;UAC7B,iBAAiB,OAAO,CACjC,UAAS,OAAO,MAAM,iBAAiB;KAClC,OAAM,IAAI,MAAM,4BAA4B,SAAS;AAC5D,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,6BAA6B,SAAS;CAE1E,MAAM,EAAE,cAAc,iBAAiB,eAAe,OAAO;AAE7D,QAAO;EACL,IAAI,mBAAmB,OAAO,WAAW,CAAC;EAC1C,MAAM;GAAE,MAAM;GAAc,SAAS;GAAiB;EACvD"}
1
+ {"version":3,"file":"logs_handle.js","names":[],"sources":["../../../src/drivers/helpers/logs_handle.ts"],"sourcesContent":["/** Handle of logs. This handle should be passed\n * to the driver for retrieving logs. */\n\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport {\n createSignedResourceId,\n parseSignedResourceId,\n signatureToBase64Url,\n base64UrlToSignature,\n} from \"@milaboratories/pl-client\";\n\nexport function newLogHandle(live: boolean, rInfo: ResourceInfo): sdk.AnyLogHandle {\n const { globalId, signature } = parseSignedResourceId(rInfo.id);\n const sigSegment = signatureToBase64Url(signature);\n if (live) {\n return `log+live://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}` as sdk.LiveLogHandle;\n }\n\n return `log+ready://log/${rInfo.type.name}/${rInfo.type.version}/${globalId}/${sigSegment}` as sdk.ReadyLogHandle;\n}\n\n/** Handle of the live logs of a program.\n * The resource that represents a log can be deleted,\n * in this case the handle should be refreshed. */\n\nexport const liveHandleRegex =\n /^log\\+live:\\/\\/log\\/(?<resourceType>.+)\\/(?<resourceVersion>[^/]+)\\/(?<resourceId>\\d+)\\/(?<resourceSig>[A-Za-z0-9_\\-=]*)$/;\n\nexport function isLiveLogHandle(handle: string): handle is sdk.LiveLogHandle {\n return liveHandleRegex.test(handle);\n}\n\n/** Handle of the ready logs of a program. */\n\nexport const readyHandleRegex =\n /^log\\+ready:\\/\\/log\\/(?<resourceType>.+)\\/(?<resourceVersion>.+)\\/(?<resourceId>\\d+)\\/(?<resourceSig>[A-Za-z0-9_\\-=]*)$/;\n\nexport function isReadyLogHandle(handle: string): handle is sdk.ReadyLogHandle {\n return readyHandleRegex.test(handle);\n}\n\nexport function getResourceInfoFromLogHandle(handle: sdk.AnyLogHandle): ResourceInfo {\n let parsed: RegExpMatchArray | null;\n\n if (isLiveLogHandle(handle)) {\n parsed = handle.match(liveHandleRegex);\n } else if (isReadyLogHandle(handle)) {\n parsed = handle.match(readyHandleRegex);\n } else throw new Error(`Log handle is malformed: ${handle}`);\n if (parsed == null) throw new Error(`Log handle wasn't parsed: ${handle}`);\n\n const { resourceType, resourceVersion, resourceId, resourceSig } = parsed.groups!;\n\n const sig = resourceSig ? base64UrlToSignature(resourceSig) : undefined;\n\n return {\n id: createSignedResourceId(BigInt(resourceId), sig),\n type: { name: resourceType, version: resourceVersion },\n };\n}\n"],"mappings":";;AAYA,SAAgB,aAAa,MAAe,OAAuC;CACjF,MAAM,EAAE,UAAU,cAAc,sBAAsB,MAAM,GAAG;CAC/D,MAAM,aAAa,qBAAqB,UAAU;AAClD,KAAI,KACF,QAAO,kBAAkB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,SAAS,GAAG;AAGhF,QAAO,mBAAmB,MAAM,KAAK,KAAK,GAAG,MAAM,KAAK,QAAQ,GAAG,SAAS,GAAG;;;;;AAOjF,MAAa,kBACX;AAEF,SAAgB,gBAAgB,QAA6C;AAC3E,QAAO,gBAAgB,KAAK,OAAO;;;AAKrC,MAAa,mBACX;AAEF,SAAgB,iBAAiB,QAA8C;AAC7E,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,6BAA6B,QAAwC;CACnF,IAAI;AAEJ,KAAI,gBAAgB,OAAO,CACzB,UAAS,OAAO,MAAM,gBAAgB;UAC7B,iBAAiB,OAAO,CACjC,UAAS,OAAO,MAAM,iBAAiB;KAClC,OAAM,IAAI,MAAM,4BAA4B,SAAS;AAC5D,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,6BAA6B,SAAS;CAE1E,MAAM,EAAE,cAAc,iBAAiB,YAAY,gBAAgB,OAAO;CAE1E,MAAM,MAAM,cAAc,qBAAqB,YAAY,GAAG,KAAA;AAE9D,QAAO;EACL,IAAI,uBAAuB,OAAO,WAAW,EAAE,IAAI;EACnD,MAAM;GAAE,MAAM;GAAc,SAAS;GAAiB;EACvD"}
@@ -1,8 +1,8 @@
1
1
  const require_types = require("../types.cjs");
2
2
  //#region src/drivers/helpers/ls_remote_import_handle.ts
3
- function createIndexImportHandle(storageName, path) {
3
+ function createIndexImportHandle(storageId, path) {
4
4
  return `index://index/${encodeURIComponent(JSON.stringify({
5
- storageId: storageName,
5
+ storageId,
6
6
  path
7
7
  }))}`;
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ls_remote_import_handle.cjs","names":["ImportFileHandleUploadData","ImportFileHandleIndexData"],"sources":["../../../src/drivers/helpers/ls_remote_import_handle.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { ImportFileHandleIndexData, ImportFileHandleUploadData } from \"../types\";\n\nexport function createIndexImportHandle(\n storageName: string,\n path: string,\n): sdk.ImportFileHandleIndex {\n const data: ImportFileHandleIndexData = {\n storageId: storageName,\n path: path,\n };\n\n return `index://index/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function createUploadImportHandle(\n localPath: string,\n signer: Signer,\n sizeBytes: bigint,\n modificationTimeSeconds: bigint,\n): sdk.ImportFileHandleUpload {\n const data: ImportFileHandleUploadData = {\n localPath,\n pathSignature: signer.sign(localPath),\n sizeBytes: String(sizeBytes),\n modificationTime: String(modificationTimeSeconds),\n };\n\n return `upload://upload/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function parseUploadHandle(handle: sdk.ImportFileHandleUpload): ImportFileHandleUploadData {\n const url = new URL(handle);\n return ImportFileHandleUploadData.parse(\n JSON.parse(decodeURIComponent(url.pathname.substring(1))),\n );\n}\n\nexport function parseIndexHandle(handle: sdk.ImportFileHandleIndex): ImportFileHandleIndexData {\n const url = new URL(handle);\n return ImportFileHandleIndexData.parse(JSON.parse(decodeURIComponent(url.pathname.substring(1))));\n}\n"],"mappings":";;AAIA,SAAgB,wBACd,aACA,MAC2B;AAM3B,QAAO,iBAAiB,mBAAmB,KAAK,UALR;EACtC,WAAW;EACL;EACP,CAE8D,CAAC;;AAGlE,SAAgB,yBACd,WACA,QACA,WACA,yBAC4B;CAC5B,MAAM,OAAmC;EACvC;EACA,eAAe,OAAO,KAAK,UAAU;EACrC,WAAW,OAAO,UAAU;EAC5B,kBAAkB,OAAO,wBAAwB;EAClD;AAED,QAAO,mBAAmB,mBAAmB,KAAK,UAAU,KAAK,CAAC;;AAGpE,SAAgB,kBAAkB,QAAgE;CAChG,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAOA,cAAAA,2BAA2B,MAChC,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAC1D;;AAGH,SAAgB,iBAAiB,QAA8D;CAC7F,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAOC,cAAAA,0BAA0B,MAAM,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"ls_remote_import_handle.cjs","names":["ImportFileHandleUploadData","ImportFileHandleIndexData"],"sources":["../../../src/drivers/helpers/ls_remote_import_handle.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { ImportFileHandleIndexData, ImportFileHandleUploadData } from \"../types\";\n\nexport function createIndexImportHandle(\n storageId: string,\n path: string,\n): sdk.ImportFileHandleIndex {\n const data: ImportFileHandleIndexData = {\n storageId: storageId,\n path: path,\n };\n\n return `index://index/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function createUploadImportHandle(\n localPath: string,\n signer: Signer,\n sizeBytes: bigint,\n modificationTimeSeconds: bigint,\n): sdk.ImportFileHandleUpload {\n const data: ImportFileHandleUploadData = {\n localPath,\n pathSignature: signer.sign(localPath),\n sizeBytes: String(sizeBytes),\n modificationTime: String(modificationTimeSeconds),\n };\n\n return `upload://upload/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function parseUploadHandle(handle: sdk.ImportFileHandleUpload): ImportFileHandleUploadData {\n const url = new URL(handle);\n return ImportFileHandleUploadData.parse(\n JSON.parse(decodeURIComponent(url.pathname.substring(1))),\n );\n}\n\nexport function parseIndexHandle(handle: sdk.ImportFileHandleIndex): ImportFileHandleIndexData {\n const url = new URL(handle);\n return ImportFileHandleIndexData.parse(JSON.parse(decodeURIComponent(url.pathname.substring(1))));\n}\n"],"mappings":";;AAIA,SAAgB,wBACd,WACA,MAC2B;AAM3B,QAAO,iBAAiB,mBAAmB,KAAK,UALR;EAC3B;EACL;EACP,CAE8D,CAAC;;AAGlE,SAAgB,yBACd,WACA,QACA,WACA,yBAC4B;CAC5B,MAAM,OAAmC;EACvC;EACA,eAAe,OAAO,KAAK,UAAU;EACrC,WAAW,OAAO,UAAU;EAC5B,kBAAkB,OAAO,wBAAwB;EAClD;AAED,QAAO,mBAAmB,mBAAmB,KAAK,UAAU,KAAK,CAAC;;AAGpE,SAAgB,kBAAkB,QAAgE;CAChG,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAOA,cAAAA,2BAA2B,MAChC,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAC1D;;AAGH,SAAgB,iBAAiB,QAA8D;CAC7F,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAOC,cAAAA,0BAA0B,MAAM,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { ImportFileHandleIndexData, ImportFileHandleUploadData } from "../types.js";
2
2
  //#region src/drivers/helpers/ls_remote_import_handle.ts
3
- function createIndexImportHandle(storageName, path) {
3
+ function createIndexImportHandle(storageId, path) {
4
4
  return `index://index/${encodeURIComponent(JSON.stringify({
5
- storageId: storageName,
5
+ storageId,
6
6
  path
7
7
  }))}`;
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ls_remote_import_handle.js","names":[],"sources":["../../../src/drivers/helpers/ls_remote_import_handle.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { ImportFileHandleIndexData, ImportFileHandleUploadData } from \"../types\";\n\nexport function createIndexImportHandle(\n storageName: string,\n path: string,\n): sdk.ImportFileHandleIndex {\n const data: ImportFileHandleIndexData = {\n storageId: storageName,\n path: path,\n };\n\n return `index://index/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function createUploadImportHandle(\n localPath: string,\n signer: Signer,\n sizeBytes: bigint,\n modificationTimeSeconds: bigint,\n): sdk.ImportFileHandleUpload {\n const data: ImportFileHandleUploadData = {\n localPath,\n pathSignature: signer.sign(localPath),\n sizeBytes: String(sizeBytes),\n modificationTime: String(modificationTimeSeconds),\n };\n\n return `upload://upload/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function parseUploadHandle(handle: sdk.ImportFileHandleUpload): ImportFileHandleUploadData {\n const url = new URL(handle);\n return ImportFileHandleUploadData.parse(\n JSON.parse(decodeURIComponent(url.pathname.substring(1))),\n );\n}\n\nexport function parseIndexHandle(handle: sdk.ImportFileHandleIndex): ImportFileHandleIndexData {\n const url = new URL(handle);\n return ImportFileHandleIndexData.parse(JSON.parse(decodeURIComponent(url.pathname.substring(1))));\n}\n"],"mappings":";;AAIA,SAAgB,wBACd,aACA,MAC2B;AAM3B,QAAO,iBAAiB,mBAAmB,KAAK,UALR;EACtC,WAAW;EACL;EACP,CAE8D,CAAC;;AAGlE,SAAgB,yBACd,WACA,QACA,WACA,yBAC4B;CAC5B,MAAM,OAAmC;EACvC;EACA,eAAe,OAAO,KAAK,UAAU;EACrC,WAAW,OAAO,UAAU;EAC5B,kBAAkB,OAAO,wBAAwB;EAClD;AAED,QAAO,mBAAmB,mBAAmB,KAAK,UAAU,KAAK,CAAC;;AAGpE,SAAgB,kBAAkB,QAAgE;CAChG,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAO,2BAA2B,MAChC,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAC1D;;AAGH,SAAgB,iBAAiB,QAA8D;CAC7F,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAO,0BAA0B,MAAM,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"ls_remote_import_handle.js","names":[],"sources":["../../../src/drivers/helpers/ls_remote_import_handle.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { ImportFileHandleIndexData, ImportFileHandleUploadData } from \"../types\";\n\nexport function createIndexImportHandle(\n storageId: string,\n path: string,\n): sdk.ImportFileHandleIndex {\n const data: ImportFileHandleIndexData = {\n storageId: storageId,\n path: path,\n };\n\n return `index://index/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function createUploadImportHandle(\n localPath: string,\n signer: Signer,\n sizeBytes: bigint,\n modificationTimeSeconds: bigint,\n): sdk.ImportFileHandleUpload {\n const data: ImportFileHandleUploadData = {\n localPath,\n pathSignature: signer.sign(localPath),\n sizeBytes: String(sizeBytes),\n modificationTime: String(modificationTimeSeconds),\n };\n\n return `upload://upload/${encodeURIComponent(JSON.stringify(data))}`;\n}\n\nexport function parseUploadHandle(handle: sdk.ImportFileHandleUpload): ImportFileHandleUploadData {\n const url = new URL(handle);\n return ImportFileHandleUploadData.parse(\n JSON.parse(decodeURIComponent(url.pathname.substring(1))),\n );\n}\n\nexport function parseIndexHandle(handle: sdk.ImportFileHandleIndex): ImportFileHandleIndexData {\n const url = new URL(handle);\n return ImportFileHandleIndexData.parse(JSON.parse(decodeURIComponent(url.pathname.substring(1))));\n}\n"],"mappings":";;AAIA,SAAgB,wBACd,WACA,MAC2B;AAM3B,QAAO,iBAAiB,mBAAmB,KAAK,UALR;EAC3B;EACL;EACP,CAE8D,CAAC;;AAGlE,SAAgB,yBACd,WACA,QACA,WACA,yBAC4B;CAC5B,MAAM,OAAmC;EACvC;EACA,eAAe,OAAO,KAAK,UAAU;EACrC,WAAW,OAAO,UAAU;EAC5B,kBAAkB,OAAO,wBAAwB;EAClD;AAED,QAAO,mBAAmB,mBAAmB,KAAK,UAAU,KAAK,CAAC;;AAGpE,SAAgB,kBAAkB,QAAgE;CAChG,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAO,2BAA2B,MAChC,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAC1D;;AAGH,SAAgB,iBAAiB,QAA8D;CAC7F,MAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAO,0BAA0B,MAAM,KAAK,MAAM,mBAAmB,IAAI,SAAS,UAAU,EAAE,CAAC,CAAC,CAAC"}
@@ -22,33 +22,27 @@ function parseLocalStorageHandle(handle) {
22
22
  if (parsed == null) throw new Error(`Local list handle wasn't parsed: ${handle}`);
23
23
  const { name, path } = parsed.groups;
24
24
  return {
25
+ isRemote: false,
25
26
  rootPath: decodeURIComponent(path),
26
- name,
27
- isRemote: false
27
+ name
28
28
  };
29
29
  }
30
- const remoteHandleRegex = /^remote:\/\/(?<name>.*)\/(?<resourceId>.*)$/;
30
+ const remoteHandleRegex = /^remote:\/\/(?<storageId>.*)\/(?<resourceType>.*)\/(?<resourceId>.*)$/;
31
31
  function isRemoteStorageHandle(handle) {
32
32
  return remoteHandleRegex.test(handle);
33
33
  }
34
- function createRemoteStorageHandle(name, rId) {
35
- return `remote://${name}/${BigInt(rId)}`;
34
+ function createRemoteStorageHandle(info) {
35
+ return `remote://${info.storageId}/${encodeURIComponent((0, _milaboratories_pl_client.resourceTypeToString)(info.resourceType))}/${encodeURIComponent(info.resourceId)}`;
36
36
  }
37
37
  function parseRemoteStorageHandle(handle) {
38
38
  const parsed = handle.match(remoteHandleRegex);
39
39
  if (parsed == null) throw new Error(`Remote list handle wasn't parsed: ${handle}`);
40
- const { name, resourceId } = parsed.groups;
40
+ const { storageId, resourceType: encodedRType, resourceId: encodedRId } = parsed.groups;
41
41
  return {
42
- id: (0, _milaboratories_pl_client.bigintToResourceId)(BigInt(resourceId)),
43
- type: storageType(name),
44
- name,
45
- isRemote: true
46
- };
47
- }
48
- function storageType(name) {
49
- return {
50
- name: `LS/${name}`,
51
- version: "1"
42
+ isRemote: true,
43
+ storageId,
44
+ resourceType: (0, _milaboratories_pl_client.parseResourceType)(decodeURIComponent(encodedRType)),
45
+ resourceId: decodeURIComponent(encodedRId)
52
46
  };
53
47
  }
54
48
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"ls_storage_entry.cjs","names":[],"sources":["../../../src/drivers/helpers/ls_storage_entry.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { ResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport { bigintToResourceId } from \"@milaboratories/pl-client\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\n\nexport type StorageHandleData = RemoteStorageHandleData | LocalStorageHandleData;\n\n/**\n * Gets a storage handle and gives an underlying data from it.\n */\nexport function parseStorageHandle(handle: sdk.StorageHandle): StorageHandleData {\n if (isRemoteStorageHandle(handle)) {\n return parseRemoteStorageHandle(handle);\n } else if (isLocalStorageHandle(handle)) {\n return parseLocalStorageHandle(handle);\n }\n\n assertNever(handle);\n}\n\n//\n// Local storage:\n//\n\nexport type LocalStorageHandleData = {\n isRemote: false;\n name: string;\n rootPath: string;\n};\n\nconst localHandleRegex = /^local:\\/\\/(?<name>.*)\\/(?<path>.*)$/;\n\nexport function isLocalStorageHandle(handle: sdk.StorageHandle): handle is sdk.StorageHandleLocal {\n return localHandleRegex.test(handle);\n}\n\nexport function createLocalStorageHandle(name: string, path: string): sdk.StorageHandleLocal {\n return `local://${name}/${encodeURIComponent(path)}`;\n}\n\nfunction parseLocalStorageHandle(handle: string): LocalStorageHandleData {\n const parsed = handle.match(localHandleRegex);\n if (parsed == null) throw new Error(`Local list handle wasn't parsed: ${handle}`);\n\n const { name, path } = parsed.groups!;\n\n return {\n rootPath: decodeURIComponent(path),\n name,\n isRemote: false,\n };\n}\n\n//\n// Remote storage:\n//\n\nexport type RemoteStorageHandleData = {\n isRemote: true;\n name: string;\n id: ResourceId;\n type: ResourceType;\n};\n\nconst remoteHandleRegex = /^remote:\\/\\/(?<name>.*)\\/(?<resourceId>.*)$/;\n\nexport function isRemoteStorageHandle(\n handle: sdk.StorageHandle,\n): handle is sdk.StorageHandleRemote {\n return remoteHandleRegex.test(handle);\n}\n\nexport function createRemoteStorageHandle(name: string, rId: ResourceId): sdk.StorageHandleRemote {\n return `remote://${name}/${BigInt(rId)}`;\n}\n\nfunction parseRemoteStorageHandle(handle: string): RemoteStorageHandleData {\n const parsed = handle.match(remoteHandleRegex);\n if (parsed == null) throw new Error(`Remote list handle wasn't parsed: ${handle}`);\n const { name, resourceId } = parsed.groups!;\n\n return {\n id: bigintToResourceId(BigInt(resourceId)),\n type: storageType(name),\n name,\n isRemote: true,\n };\n}\n\nfunction storageType(name: string): ResourceType {\n return { name: `LS/${name}`, version: \"1\" };\n}\n"],"mappings":";;;;;;;AAUA,SAAgB,mBAAmB,QAA8C;AAC/E,KAAI,sBAAsB,OAAO,CAC/B,QAAO,yBAAyB,OAAO;UAC9B,qBAAqB,OAAO,CACrC,QAAO,wBAAwB,OAAO;AAGxC,EAAA,GAAA,2BAAA,aAAY,OAAO;;AAarB,MAAM,mBAAmB;AAEzB,SAAgB,qBAAqB,QAA6D;AAChG,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,yBAAyB,MAAc,MAAsC;AAC3F,QAAO,WAAW,KAAK,GAAG,mBAAmB,KAAK;;AAGpD,SAAS,wBAAwB,QAAwC;CACvE,MAAM,SAAS,OAAO,MAAM,iBAAiB;AAC7C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,oCAAoC,SAAS;CAEjF,MAAM,EAAE,MAAM,SAAS,OAAO;AAE9B,QAAO;EACL,UAAU,mBAAmB,KAAK;EAClC;EACA,UAAU;EACX;;AAcH,MAAM,oBAAoB;AAE1B,SAAgB,sBACd,QACmC;AACnC,QAAO,kBAAkB,KAAK,OAAO;;AAGvC,SAAgB,0BAA0B,MAAc,KAA0C;AAChG,QAAO,YAAY,KAAK,GAAG,OAAO,IAAI;;AAGxC,SAAS,yBAAyB,QAAyC;CACzE,MAAM,SAAS,OAAO,MAAM,kBAAkB;AAC9C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,qCAAqC,SAAS;CAClF,MAAM,EAAE,MAAM,eAAe,OAAO;AAEpC,QAAO;EACL,KAAA,GAAA,0BAAA,oBAAuB,OAAO,WAAW,CAAC;EAC1C,MAAM,YAAY,KAAK;EACvB;EACA,UAAU;EACX;;AAGH,SAAS,YAAY,MAA4B;AAC/C,QAAO;EAAE,MAAM,MAAM;EAAQ,SAAS;EAAK"}
1
+ {"version":3,"file":"ls_storage_entry.cjs","names":[],"sources":["../../../src/drivers/helpers/ls_storage_entry.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { ResourceType, SignedResourceId, StorageInfo } from \"@milaboratories/pl-client\";\nimport { resourceTypeToString, parseResourceType } from \"@milaboratories/pl-client\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\n\nexport type StorageHandleData = RemoteStorageHandleData | LocalStorageHandleData;\n\n/**\n * Gets a storage handle and gives an underlying data from it.\n */\nexport function parseStorageHandle(handle: sdk.StorageHandle): StorageHandleData {\n if (isRemoteStorageHandle(handle)) {\n return parseRemoteStorageHandle(handle);\n } else if (isLocalStorageHandle(handle)) {\n return parseLocalStorageHandle(handle);\n }\n\n assertNever(handle);\n}\n\n//\n// Local storage:\n//\n\nexport type LocalStorageHandleData = {\n isRemote: false;\n name: string;\n rootPath: string;\n};\n\nconst localHandleRegex = /^local:\\/\\/(?<name>.*)\\/(?<path>.*)$/;\n\nexport function isLocalStorageHandle(handle: sdk.StorageHandle): handle is sdk.StorageHandleLocal {\n return localHandleRegex.test(handle);\n}\n\nexport function createLocalStorageHandle(name: string, path: string): sdk.StorageHandleLocal {\n return `local://${name}/${encodeURIComponent(path)}`;\n}\n\nfunction parseLocalStorageHandle(handle: string): LocalStorageHandleData {\n const parsed = handle.match(localHandleRegex);\n if (parsed == null) throw new Error(`Local list handle wasn't parsed: ${handle}`);\n\n const { name, path } = parsed.groups!;\n\n return {\n isRemote: false,\n rootPath: decodeURIComponent(path),\n name,\n };\n}\n\n//\n// Remote storage:\n//\n\nexport type RemoteStorageHandleData = {\n isRemote: true;\n storageId: string;\n resourceType: ResourceType;\n resourceId: SignedResourceId;\n};\n\nconst remoteHandleRegex = /^remote:\\/\\/(?<storageId>.*)\\/(?<resourceType>.*)\\/(?<resourceId>.*)$/;\n\nexport function isRemoteStorageHandle(\n handle: sdk.StorageHandle,\n): handle is sdk.StorageHandleRemote {\n return remoteHandleRegex.test(handle);\n}\n\nexport function createRemoteStorageHandle(info: StorageInfo): sdk.StorageHandleRemote {\n return `remote://${info.storageId}/${encodeURIComponent(resourceTypeToString(info.resourceType))}/${encodeURIComponent(info.resourceId)}`;\n}\n\nfunction parseRemoteStorageHandle(handle: string): RemoteStorageHandleData {\n const parsed = handle.match(remoteHandleRegex);\n if (parsed == null) throw new Error(`Remote list handle wasn't parsed: ${handle}`);\n const { storageId, resourceType: encodedRType, resourceId: encodedRId } = parsed.groups!;\n\n const resourceType = parseResourceType(decodeURIComponent(encodedRType));\n const resourceId = decodeURIComponent(encodedRId) as SignedResourceId; // lint-allow-cast\n return {\n isRemote: true,\n storageId,\n resourceType: resourceType,\n resourceId: resourceId,\n };\n}\n"],"mappings":";;;;;;;AAUA,SAAgB,mBAAmB,QAA8C;AAC/E,KAAI,sBAAsB,OAAO,CAC/B,QAAO,yBAAyB,OAAO;UAC9B,qBAAqB,OAAO,CACrC,QAAO,wBAAwB,OAAO;AAGxC,EAAA,GAAA,2BAAA,aAAY,OAAO;;AAarB,MAAM,mBAAmB;AAEzB,SAAgB,qBAAqB,QAA6D;AAChG,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,yBAAyB,MAAc,MAAsC;AAC3F,QAAO,WAAW,KAAK,GAAG,mBAAmB,KAAK;;AAGpD,SAAS,wBAAwB,QAAwC;CACvE,MAAM,SAAS,OAAO,MAAM,iBAAiB;AAC7C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,oCAAoC,SAAS;CAEjF,MAAM,EAAE,MAAM,SAAS,OAAO;AAE9B,QAAO;EACL,UAAU;EACV,UAAU,mBAAmB,KAAK;EAClC;EACD;;AAcH,MAAM,oBAAoB;AAE1B,SAAgB,sBACd,QACmC;AACnC,QAAO,kBAAkB,KAAK,OAAO;;AAGvC,SAAgB,0BAA0B,MAA4C;AACpF,QAAO,YAAY,KAAK,UAAU,GAAG,oBAAA,GAAA,0BAAA,sBAAwC,KAAK,aAAa,CAAC,CAAC,GAAG,mBAAmB,KAAK,WAAW;;AAGzI,SAAS,yBAAyB,QAAyC;CACzE,MAAM,SAAS,OAAO,MAAM,kBAAkB;AAC9C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,qCAAqC,SAAS;CAClF,MAAM,EAAE,WAAW,cAAc,cAAc,YAAY,eAAe,OAAO;AAIjF,QAAO;EACL,UAAU;EACV;EACA,eAAA,GAAA,0BAAA,mBALqC,mBAAmB,aAAa,CAAC;EAMtE,YALiB,mBAAmB,WAAW;EAMhD"}
@@ -1,4 +1,4 @@
1
- import { bigintToResourceId } from "@milaboratories/pl-client";
1
+ import { parseResourceType, resourceTypeToString } from "@milaboratories/pl-client";
2
2
  import { assertNever } from "@milaboratories/ts-helpers";
3
3
  //#region src/drivers/helpers/ls_storage_entry.ts
4
4
  /**
@@ -21,33 +21,27 @@ function parseLocalStorageHandle(handle) {
21
21
  if (parsed == null) throw new Error(`Local list handle wasn't parsed: ${handle}`);
22
22
  const { name, path } = parsed.groups;
23
23
  return {
24
+ isRemote: false,
24
25
  rootPath: decodeURIComponent(path),
25
- name,
26
- isRemote: false
26
+ name
27
27
  };
28
28
  }
29
- const remoteHandleRegex = /^remote:\/\/(?<name>.*)\/(?<resourceId>.*)$/;
29
+ const remoteHandleRegex = /^remote:\/\/(?<storageId>.*)\/(?<resourceType>.*)\/(?<resourceId>.*)$/;
30
30
  function isRemoteStorageHandle(handle) {
31
31
  return remoteHandleRegex.test(handle);
32
32
  }
33
- function createRemoteStorageHandle(name, rId) {
34
- return `remote://${name}/${BigInt(rId)}`;
33
+ function createRemoteStorageHandle(info) {
34
+ return `remote://${info.storageId}/${encodeURIComponent(resourceTypeToString(info.resourceType))}/${encodeURIComponent(info.resourceId)}`;
35
35
  }
36
36
  function parseRemoteStorageHandle(handle) {
37
37
  const parsed = handle.match(remoteHandleRegex);
38
38
  if (parsed == null) throw new Error(`Remote list handle wasn't parsed: ${handle}`);
39
- const { name, resourceId } = parsed.groups;
39
+ const { storageId, resourceType: encodedRType, resourceId: encodedRId } = parsed.groups;
40
40
  return {
41
- id: bigintToResourceId(BigInt(resourceId)),
42
- type: storageType(name),
43
- name,
44
- isRemote: true
45
- };
46
- }
47
- function storageType(name) {
48
- return {
49
- name: `LS/${name}`,
50
- version: "1"
41
+ isRemote: true,
42
+ storageId,
43
+ resourceType: parseResourceType(decodeURIComponent(encodedRType)),
44
+ resourceId: decodeURIComponent(encodedRId)
51
45
  };
52
46
  }
53
47
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"ls_storage_entry.js","names":[],"sources":["../../../src/drivers/helpers/ls_storage_entry.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { ResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport { bigintToResourceId } from \"@milaboratories/pl-client\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\n\nexport type StorageHandleData = RemoteStorageHandleData | LocalStorageHandleData;\n\n/**\n * Gets a storage handle and gives an underlying data from it.\n */\nexport function parseStorageHandle(handle: sdk.StorageHandle): StorageHandleData {\n if (isRemoteStorageHandle(handle)) {\n return parseRemoteStorageHandle(handle);\n } else if (isLocalStorageHandle(handle)) {\n return parseLocalStorageHandle(handle);\n }\n\n assertNever(handle);\n}\n\n//\n// Local storage:\n//\n\nexport type LocalStorageHandleData = {\n isRemote: false;\n name: string;\n rootPath: string;\n};\n\nconst localHandleRegex = /^local:\\/\\/(?<name>.*)\\/(?<path>.*)$/;\n\nexport function isLocalStorageHandle(handle: sdk.StorageHandle): handle is sdk.StorageHandleLocal {\n return localHandleRegex.test(handle);\n}\n\nexport function createLocalStorageHandle(name: string, path: string): sdk.StorageHandleLocal {\n return `local://${name}/${encodeURIComponent(path)}`;\n}\n\nfunction parseLocalStorageHandle(handle: string): LocalStorageHandleData {\n const parsed = handle.match(localHandleRegex);\n if (parsed == null) throw new Error(`Local list handle wasn't parsed: ${handle}`);\n\n const { name, path } = parsed.groups!;\n\n return {\n rootPath: decodeURIComponent(path),\n name,\n isRemote: false,\n };\n}\n\n//\n// Remote storage:\n//\n\nexport type RemoteStorageHandleData = {\n isRemote: true;\n name: string;\n id: ResourceId;\n type: ResourceType;\n};\n\nconst remoteHandleRegex = /^remote:\\/\\/(?<name>.*)\\/(?<resourceId>.*)$/;\n\nexport function isRemoteStorageHandle(\n handle: sdk.StorageHandle,\n): handle is sdk.StorageHandleRemote {\n return remoteHandleRegex.test(handle);\n}\n\nexport function createRemoteStorageHandle(name: string, rId: ResourceId): sdk.StorageHandleRemote {\n return `remote://${name}/${BigInt(rId)}`;\n}\n\nfunction parseRemoteStorageHandle(handle: string): RemoteStorageHandleData {\n const parsed = handle.match(remoteHandleRegex);\n if (parsed == null) throw new Error(`Remote list handle wasn't parsed: ${handle}`);\n const { name, resourceId } = parsed.groups!;\n\n return {\n id: bigintToResourceId(BigInt(resourceId)),\n type: storageType(name),\n name,\n isRemote: true,\n };\n}\n\nfunction storageType(name: string): ResourceType {\n return { name: `LS/${name}`, version: \"1\" };\n}\n"],"mappings":";;;;;;AAUA,SAAgB,mBAAmB,QAA8C;AAC/E,KAAI,sBAAsB,OAAO,CAC/B,QAAO,yBAAyB,OAAO;UAC9B,qBAAqB,OAAO,CACrC,QAAO,wBAAwB,OAAO;AAGxC,aAAY,OAAO;;AAarB,MAAM,mBAAmB;AAEzB,SAAgB,qBAAqB,QAA6D;AAChG,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,yBAAyB,MAAc,MAAsC;AAC3F,QAAO,WAAW,KAAK,GAAG,mBAAmB,KAAK;;AAGpD,SAAS,wBAAwB,QAAwC;CACvE,MAAM,SAAS,OAAO,MAAM,iBAAiB;AAC7C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,oCAAoC,SAAS;CAEjF,MAAM,EAAE,MAAM,SAAS,OAAO;AAE9B,QAAO;EACL,UAAU,mBAAmB,KAAK;EAClC;EACA,UAAU;EACX;;AAcH,MAAM,oBAAoB;AAE1B,SAAgB,sBACd,QACmC;AACnC,QAAO,kBAAkB,KAAK,OAAO;;AAGvC,SAAgB,0BAA0B,MAAc,KAA0C;AAChG,QAAO,YAAY,KAAK,GAAG,OAAO,IAAI;;AAGxC,SAAS,yBAAyB,QAAyC;CACzE,MAAM,SAAS,OAAO,MAAM,kBAAkB;AAC9C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,qCAAqC,SAAS;CAClF,MAAM,EAAE,MAAM,eAAe,OAAO;AAEpC,QAAO;EACL,IAAI,mBAAmB,OAAO,WAAW,CAAC;EAC1C,MAAM,YAAY,KAAK;EACvB;EACA,UAAU;EACX;;AAGH,SAAS,YAAY,MAA4B;AAC/C,QAAO;EAAE,MAAM,MAAM;EAAQ,SAAS;EAAK"}
1
+ {"version":3,"file":"ls_storage_entry.js","names":[],"sources":["../../../src/drivers/helpers/ls_storage_entry.ts"],"sourcesContent":["import type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { ResourceType, SignedResourceId, StorageInfo } from \"@milaboratories/pl-client\";\nimport { resourceTypeToString, parseResourceType } from \"@milaboratories/pl-client\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\n\nexport type StorageHandleData = RemoteStorageHandleData | LocalStorageHandleData;\n\n/**\n * Gets a storage handle and gives an underlying data from it.\n */\nexport function parseStorageHandle(handle: sdk.StorageHandle): StorageHandleData {\n if (isRemoteStorageHandle(handle)) {\n return parseRemoteStorageHandle(handle);\n } else if (isLocalStorageHandle(handle)) {\n return parseLocalStorageHandle(handle);\n }\n\n assertNever(handle);\n}\n\n//\n// Local storage:\n//\n\nexport type LocalStorageHandleData = {\n isRemote: false;\n name: string;\n rootPath: string;\n};\n\nconst localHandleRegex = /^local:\\/\\/(?<name>.*)\\/(?<path>.*)$/;\n\nexport function isLocalStorageHandle(handle: sdk.StorageHandle): handle is sdk.StorageHandleLocal {\n return localHandleRegex.test(handle);\n}\n\nexport function createLocalStorageHandle(name: string, path: string): sdk.StorageHandleLocal {\n return `local://${name}/${encodeURIComponent(path)}`;\n}\n\nfunction parseLocalStorageHandle(handle: string): LocalStorageHandleData {\n const parsed = handle.match(localHandleRegex);\n if (parsed == null) throw new Error(`Local list handle wasn't parsed: ${handle}`);\n\n const { name, path } = parsed.groups!;\n\n return {\n isRemote: false,\n rootPath: decodeURIComponent(path),\n name,\n };\n}\n\n//\n// Remote storage:\n//\n\nexport type RemoteStorageHandleData = {\n isRemote: true;\n storageId: string;\n resourceType: ResourceType;\n resourceId: SignedResourceId;\n};\n\nconst remoteHandleRegex = /^remote:\\/\\/(?<storageId>.*)\\/(?<resourceType>.*)\\/(?<resourceId>.*)$/;\n\nexport function isRemoteStorageHandle(\n handle: sdk.StorageHandle,\n): handle is sdk.StorageHandleRemote {\n return remoteHandleRegex.test(handle);\n}\n\nexport function createRemoteStorageHandle(info: StorageInfo): sdk.StorageHandleRemote {\n return `remote://${info.storageId}/${encodeURIComponent(resourceTypeToString(info.resourceType))}/${encodeURIComponent(info.resourceId)}`;\n}\n\nfunction parseRemoteStorageHandle(handle: string): RemoteStorageHandleData {\n const parsed = handle.match(remoteHandleRegex);\n if (parsed == null) throw new Error(`Remote list handle wasn't parsed: ${handle}`);\n const { storageId, resourceType: encodedRType, resourceId: encodedRId } = parsed.groups!;\n\n const resourceType = parseResourceType(decodeURIComponent(encodedRType));\n const resourceId = decodeURIComponent(encodedRId) as SignedResourceId; // lint-allow-cast\n return {\n isRemote: true,\n storageId,\n resourceType: resourceType,\n resourceId: resourceId,\n };\n}\n"],"mappings":";;;;;;AAUA,SAAgB,mBAAmB,QAA8C;AAC/E,KAAI,sBAAsB,OAAO,CAC/B,QAAO,yBAAyB,OAAO;UAC9B,qBAAqB,OAAO,CACrC,QAAO,wBAAwB,OAAO;AAGxC,aAAY,OAAO;;AAarB,MAAM,mBAAmB;AAEzB,SAAgB,qBAAqB,QAA6D;AAChG,QAAO,iBAAiB,KAAK,OAAO;;AAGtC,SAAgB,yBAAyB,MAAc,MAAsC;AAC3F,QAAO,WAAW,KAAK,GAAG,mBAAmB,KAAK;;AAGpD,SAAS,wBAAwB,QAAwC;CACvE,MAAM,SAAS,OAAO,MAAM,iBAAiB;AAC7C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,oCAAoC,SAAS;CAEjF,MAAM,EAAE,MAAM,SAAS,OAAO;AAE9B,QAAO;EACL,UAAU;EACV,UAAU,mBAAmB,KAAK;EAClC;EACD;;AAcH,MAAM,oBAAoB;AAE1B,SAAgB,sBACd,QACmC;AACnC,QAAO,kBAAkB,KAAK,OAAO;;AAGvC,SAAgB,0BAA0B,MAA4C;AACpF,QAAO,YAAY,KAAK,UAAU,GAAG,mBAAmB,qBAAqB,KAAK,aAAa,CAAC,CAAC,GAAG,mBAAmB,KAAK,WAAW;;AAGzI,SAAS,yBAAyB,QAAyC;CACzE,MAAM,SAAS,OAAO,MAAM,kBAAkB;AAC9C,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,qCAAqC,SAAS;CAClF,MAAM,EAAE,WAAW,cAAc,cAAc,YAAY,eAAe,OAAO;AAIjF,QAAO;EACL,UAAU;EACV;EACA,cALmB,kBAAkB,mBAAmB,aAAa,CAAC;EAMtE,YALiB,mBAAmB,WAAW;EAMhD"}
@@ -1 +1 @@
1
- {"version":3,"file":"logs_stream.cjs","names":["PollingComputableHooks","Computable","newLogHandle","getResourceInfoFromLogHandle","isLiveLogHandle","scheduler","ChangeSource","CallersCounter","WrongResourceTypeError"],"sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type { ComputableCtx, Watcher } from \"@milaboratories/computable\";\nimport { ChangeSource, Computable, PollingComputableHooks } from \"@milaboratories/computable\";\nimport type { ResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport {\n isNotFoundError,\n resourceIdToString,\n stringifyWithResourceId,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { asyncPool, CallersCounter } from \"@milaboratories/ts-helpers\";\nimport type { ClientLogs } from \"../clients/logs\";\nimport { randomUUID } from \"node:crypto\";\nimport type { PlTreeEntry, ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { treeEntryToResourceInfo } from \"@milaboratories/pl-tree\";\nimport { scheduler } from \"node:timers/promises\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { PollingOps } from \"./helpers/polling_ops\";\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from \"./helpers/logs_handle\";\nimport { WrongResourceTypeError } from \"./helpers/helpers\";\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx,\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n \"The logs are from stream, so we consider them unstable. Final values will be got from blobs.\",\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getLastLogs\", rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx,\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n \"The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.\",\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getProgressLog\", rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType(\"getLogHandle\", rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (isNotFoundError(e)) {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: ResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: ResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** Stops polling loop and waits for it to finish */\n public async terminate(): Promise<void> {\n this.stopUpdating();\n if (this.currentLoop !== undefined) {\n await this.currentLoop;\n }\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.terminate();\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs)\n this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n if (isNotFoundError(e)) {\n // No resource\n this.logs = \"\";\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith(\"StreamWorkdir\")) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, ` +\n `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"logs_stream.cjs","names":["PollingComputableHooks","Computable","newLogHandle","getResourceInfoFromLogHandle","isLiveLogHandle","scheduler","ChangeSource","CallersCounter","WrongResourceTypeError"],"sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type { ComputableCtx, Watcher } from \"@milaboratories/computable\";\nimport { ChangeSource, Computable, PollingComputableHooks } from \"@milaboratories/computable\";\nimport type { SignedResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport {\n isNotFoundError,\n resourceIdToString,\n stringifyWithResourceId,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { asyncPool, CallersCounter } from \"@milaboratories/ts-helpers\";\nimport type { ClientLogs } from \"../clients/logs\";\nimport { randomUUID } from \"node:crypto\";\nimport type { PlTreeEntry, ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { treeEntryToResourceInfo } from \"@milaboratories/pl-tree\";\nimport { scheduler } from \"node:timers/promises\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { PollingOps } from \"./helpers/polling_ops\";\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from \"./helpers/logs_handle\";\nimport { WrongResourceTypeError } from \"./helpers/helpers\";\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<SignedResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<SignedResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx,\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n \"The logs are from stream, so we consider them unstable. Final values will be got from blobs.\",\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getLastLogs\", rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx,\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n \"The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.\",\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getProgressLog\", rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType(\"getLogHandle\", rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (isNotFoundError(e)) {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: SignedResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: SignedResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** Stops polling loop and waits for it to finish */\n public async terminate(): Promise<void> {\n this.stopUpdating();\n if (this.currentLoop !== undefined) {\n await this.currentLoop;\n }\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.terminate();\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs)\n this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n if (isNotFoundError(e)) {\n // No resource\n this.logs = \"\";\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith(\"StreamWorkdir\")) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, ` +\n `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logs_stream.js","names":[],"sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type { ComputableCtx, Watcher } from \"@milaboratories/computable\";\nimport { ChangeSource, Computable, PollingComputableHooks } from \"@milaboratories/computable\";\nimport type { ResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport {\n isNotFoundError,\n resourceIdToString,\n stringifyWithResourceId,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { asyncPool, CallersCounter } from \"@milaboratories/ts-helpers\";\nimport type { ClientLogs } from \"../clients/logs\";\nimport { randomUUID } from \"node:crypto\";\nimport type { PlTreeEntry, ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { treeEntryToResourceInfo } from \"@milaboratories/pl-tree\";\nimport { scheduler } from \"node:timers/promises\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { PollingOps } from \"./helpers/polling_ops\";\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from \"./helpers/logs_handle\";\nimport { WrongResourceTypeError } from \"./helpers/helpers\";\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx,\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n \"The logs are from stream, so we consider them unstable. Final values will be got from blobs.\",\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getLastLogs\", rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx,\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n \"The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.\",\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getProgressLog\", rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType(\"getLogHandle\", rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (isNotFoundError(e)) {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: ResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: ResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** Stops polling loop and waits for it to finish */\n public async terminate(): Promise<void> {\n this.stopUpdating();\n if (this.currentLoop !== undefined) {\n await this.currentLoop;\n }\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.terminate();\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs)\n this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n if (isNotFoundError(e)) {\n // No resource\n this.logs = \"\";\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith(\"StreamWorkdir\")) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, ` +\n `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"logs_stream.js","names":[],"sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type { ComputableCtx, Watcher } from \"@milaboratories/computable\";\nimport { ChangeSource, Computable, PollingComputableHooks } from \"@milaboratories/computable\";\nimport type { SignedResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport {\n isNotFoundError,\n resourceIdToString,\n stringifyWithResourceId,\n} from \"@milaboratories/pl-client\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { asyncPool, CallersCounter } from \"@milaboratories/ts-helpers\";\nimport type { ClientLogs } from \"../clients/logs\";\nimport { randomUUID } from \"node:crypto\";\nimport type { PlTreeEntry, ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { treeEntryToResourceInfo } from \"@milaboratories/pl-tree\";\nimport { scheduler } from \"node:timers/promises\";\nimport type { StreamingAPI_Response } from \"../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol\";\nimport type * as sdk from \"@milaboratories/pl-model-common\";\nimport type { PollingOps } from \"./helpers/polling_ops\";\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from \"./helpers/logs_handle\";\nimport { WrongResourceTypeError } from \"./helpers/helpers\";\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<SignedResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<SignedResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx,\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n \"The logs are from stream, so we consider them unstable. Final values will be got from blobs.\",\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getLastLogs\", rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx,\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n \"The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.\",\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType(\"getProgressLog\", rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType(\"getLogHandle\", rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (isNotFoundError(e)) {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: SignedResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: SignedResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** Stops polling loop and waits for it to finish */\n public async terminate(): Promise<void> {\n this.stopUpdating();\n if (this.currentLoop !== undefined) {\n await this.currentLoop;\n }\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.terminate();\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs)\n this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n if (isNotFoundError(e)) {\n // No resource\n this.logs = \"\";\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith(\"StreamWorkdir\")) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, ` +\n `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"mappings":"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"}
@@ -4,7 +4,6 @@ const require_constructors = require("../clients/constructors.cjs");
4
4
  const require_ls_remote_import_handle = require("./helpers/ls_remote_import_handle.cjs");
5
5
  const require_ls_storage_entry = require("./helpers/ls_storage_entry.cjs");
6
6
  const require_virtual_storages = require("./virtual_storages.cjs");
7
- let _milaboratories_pl_client = require("@milaboratories/pl-client");
8
7
  let node_fs_promises = require("node:fs/promises");
9
8
  node_fs_promises = require_runtime.__toESM(node_fs_promises);
10
9
  let node_path = require("node:path");
@@ -12,10 +11,10 @@ node_path = require_runtime.__toESM(node_path);
12
11
  let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
13
12
  //#region src/drivers/ls.ts
14
13
  var LsDriver = class LsDriver {
15
- constructor(logger, lsClient, storageIdToResourceId, signer, virtualStoragesMap, localProjectionsMap, openFileDialogCallback) {
14
+ constructor(logger, lsClient, userResources, signer, virtualStoragesMap, localProjectionsMap, openFileDialogCallback) {
16
15
  this.logger = logger;
17
16
  this.lsClient = lsClient;
18
- this.storageIdToResourceId = storageIdToResourceId;
17
+ this.userResources = userResources;
19
18
  this.signer = signer;
20
19
  this.virtualStoragesMap = virtualStoragesMap;
21
20
  this.localProjectionsMap = localProjectionsMap;
@@ -81,26 +80,30 @@ var LsDriver = class LsDriver {
81
80
  }
82
81
  async getStorageList() {
83
82
  const virtualStorages = [...this.virtualStoragesMap.values()].map((s) => ({
83
+ id: s.id,
84
84
  name: s.name,
85
- handle: require_ls_storage_entry.createLocalStorageHandle(s.name, s.root),
85
+ handle: require_ls_storage_entry.createLocalStorageHandle(s.id, s.root),
86
86
  initialFullPath: s.initialPath
87
87
  }));
88
- const noRoot = Object.entries(this.storageIdToResourceId).map(([storageId, resourceId]) => ({
89
- name: storageId,
90
- handle: require_ls_storage_entry.createRemoteStorageHandle(storageId, resourceId),
91
- initialFullPath: "",
92
- isInitialPathHome: false
93
- })).filter((it) => it.name !== "root");
88
+ const noRoot = [...(await this.userResources.getDataLibraries()).values()].map((info) => ({
89
+ id: info.storageId,
90
+ name: info.storageName,
91
+ handle: require_ls_storage_entry.createRemoteStorageHandle(info),
92
+ initialFullPath: ""
93
+ })).filter((it) => it.id !== "root");
94
94
  return [...virtualStorages, ...noRoot];
95
95
  }
96
96
  async listFiles(storageHandle, fullPath) {
97
97
  const storageData = require_ls_storage_entry.parseStorageHandle(storageHandle);
98
- if (storageData.isRemote) return { entries: (await this.lsClient.list(storageData, fullPath)).items.map((e) => ({
99
- type: e.isDir ? "dir" : "file",
100
- name: e.name,
101
- fullPath: e.fullName,
102
- handle: require_ls_remote_import_handle.createIndexImportHandle(storageData.name, e.fullName)
103
- })) };
98
+ if (storageData.isRemote) {
99
+ const rInfo = await this.resolveRemoteStorageResourceInfo(storageData);
100
+ return { entries: (await this.lsClient.list(rInfo, fullPath)).items.map((e) => ({
101
+ type: e.isDir ? "dir" : "file",
102
+ name: e.name,
103
+ fullPath: e.fullName,
104
+ handle: require_ls_remote_import_handle.createIndexImportHandle(storageData.storageId, e.fullName)
105
+ })) };
106
+ }
104
107
  if (node_path.sep === "/" && fullPath === "") fullPath = "/";
105
108
  if (storageData.rootPath === "") require_validate.validateAbsolute(fullPath);
106
109
  const lsRoot = node_path.isAbsolute(fullPath) ? fullPath : node_path.join(storageData.rootPath, fullPath);
@@ -120,14 +123,22 @@ var LsDriver = class LsDriver {
120
123
  async listRemoteFilesWithAdditionalInfo(storageHandle, fullPath) {
121
124
  const storageData = require_ls_storage_entry.parseStorageHandle(storageHandle);
122
125
  if (!storageData.isRemote) throw new Error(`Storage ${storageData.name} is not remote`);
123
- return { entries: (await this.lsClient.list(storageData, fullPath)).items.map((e) => ({
126
+ const rInfo = await this.resolveRemoteStorageResourceInfo(storageData);
127
+ return { entries: (await this.lsClient.list(rInfo, fullPath)).items.map((e) => ({
124
128
  type: e.isDir ? "dir" : "file",
125
129
  name: e.name,
126
130
  fullPath: e.fullName,
127
- handle: require_ls_remote_import_handle.createIndexImportHandle(storageData.name, e.fullName),
131
+ handle: require_ls_remote_import_handle.createIndexImportHandle(storageData.storageId, e.fullName),
128
132
  size: Number(e.size)
129
133
  })) };
130
134
  }
135
+ /** Looks up ResourceType for a remote storage from the data libraries index. */
136
+ async resolveRemoteStorageResourceInfo(storageData) {
137
+ return {
138
+ id: storageData.resourceId,
139
+ type: storageData.resourceType
140
+ };
141
+ }
131
142
  async fileToImportHandle(_file) {
132
143
  throw new Error("Not implemented. This method must be implemented and intercepted in desktop preload script.");
133
144
  }
@@ -136,21 +147,12 @@ var LsDriver = class LsDriver {
136
147
  if (!virtualStorages) virtualStorages = await require_virtual_storages.DefaultVirtualLocalStorages();
137
148
  for (const vp of virtualStorages) require_validate.validateAbsolute(vp.root);
138
149
  for (const lp of localProjections) if (lp.localPath !== "") require_validate.validateAbsolute(lp.localPath);
139
- const virtualStoragesMap = new Map(virtualStorages.map((s) => [s.name, s]));
150
+ const virtualStoragesMap = new Map(virtualStorages.map((s) => [s.id, s]));
140
151
  const localProjectionsMap = new Map(localProjections.map((s) => [s.storageId, s]));
141
152
  if (new Set([...virtualStoragesMap.keys(), ...localProjectionsMap.keys()]).size !== virtualStoragesMap.size + localProjectionsMap.size) throw new Error("Intersection between local projection storage ids and virtual storages names detected.");
142
- return new LsDriver(logger, lsClient, await doGetAvailableStorageIds(client), signer, virtualStoragesMap, localProjectionsMap, openFileDialogCallback);
153
+ return new LsDriver(logger, lsClient, client.userResources, signer, virtualStoragesMap, localProjectionsMap, openFileDialogCallback);
143
154
  }
144
155
  };
145
- async function doGetAvailableStorageIds(client) {
146
- return client.withReadTx("GetAvailableStorageIds", async (tx) => {
147
- const lsProviderId = await tx.getResourceByName("LSProvider");
148
- return providerToStorageIds(await tx.getResourceData(lsProviderId, true));
149
- });
150
- }
151
- function providerToStorageIds(provider) {
152
- return Object.fromEntries(provider.fields.filter((f) => f.type == "Dynamic" && (0, _milaboratories_pl_client.isNotNullResourceId)(f.value)).map((f) => [f.name.substring(8), f.value]));
153
- }
154
156
  //#endregion
155
157
  exports.LsDriver = LsDriver;
156
158