@milaboratories/pl-middle-layer 1.64.37 → 1.64.39

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 (247) hide show
  1. package/dist/_virtual/{_@oxc-project_runtime@0.123.0/helpers → _@oxc-project_runtime@0.137.0/helpers/esm}/usingCtx.cjs +2 -2
  2. package/dist/_virtual/{_@oxc-project_runtime@0.123.0/helpers → _@oxc-project_runtime@0.137.0/helpers/esm}/usingCtx.js +2 -2
  3. package/dist/block_registry/index.cjs +11 -3
  4. package/dist/block_registry/index.d.ts +3 -2
  5. package/dist/block_registry/index.js +4 -3
  6. package/dist/block_registry/registry-v2-provider.cjs +1 -1
  7. package/dist/block_registry/registry-v2-provider.cjs.map +1 -1
  8. package/dist/block_registry/registry-v2-provider.d.ts.map +1 -1
  9. package/dist/block_registry/registry-v2-provider.js +1 -0
  10. package/dist/block_registry/registry-v2-provider.js.map +1 -1
  11. package/dist/block_registry/registry.cjs +20 -3
  12. package/dist/block_registry/registry.cjs.map +1 -1
  13. package/dist/block_registry/registry.d.ts +7 -1
  14. package/dist/block_registry/registry.d.ts.map +1 -1
  15. package/dist/block_registry/registry.js +17 -1
  16. package/dist/block_registry/registry.js.map +1 -1
  17. package/dist/block_registry/watcher.cjs +21 -2
  18. package/dist/block_registry/watcher.cjs.map +1 -1
  19. package/dist/block_registry/watcher.d.ts +1 -1
  20. package/dist/block_registry/watcher.d.ts.map +1 -1
  21. package/dist/block_registry/watcher.js +21 -3
  22. package/dist/block_registry/watcher.js.map +1 -1
  23. package/dist/block_registry/well_known_registries.cjs.map +1 -1
  24. package/dist/block_registry/well_known_registries.d.ts.map +1 -1
  25. package/dist/block_registry/well_known_registries.js.map +1 -1
  26. package/dist/cfg_render/executor.cjs +2 -2
  27. package/dist/cfg_render/executor.cjs.map +1 -1
  28. package/dist/cfg_render/executor.js.map +1 -1
  29. package/dist/cfg_render/renderer.cjs +0 -1
  30. package/dist/cfg_render/renderer.cjs.map +1 -1
  31. package/dist/cfg_render/renderer.js.map +1 -1
  32. package/dist/cfg_render/traverse.cjs +0 -1
  33. package/dist/cfg_render/traverse.cjs.map +1 -1
  34. package/dist/cfg_render/traverse.js.map +1 -1
  35. package/dist/cfg_render/util.cjs.map +1 -1
  36. package/dist/cfg_render/util.js.map +1 -1
  37. package/dist/debug/index.cjs +1 -0
  38. package/dist/debug/index.cjs.map +1 -1
  39. package/dist/debug/index.js +1 -1
  40. package/dist/debug/index.js.map +1 -1
  41. package/dist/dev_env/index.cjs +9 -1
  42. package/dist/dev_env/index.cjs.map +1 -1
  43. package/dist/dev_env/index.js +1 -1
  44. package/dist/dev_env/index.js.map +1 -1
  45. package/dist/dev_env/util.cjs +1 -1
  46. package/dist/dev_env/util.cjs.map +1 -1
  47. package/dist/dev_env/util.js.map +1 -1
  48. package/dist/index.cjs +2 -0
  49. package/dist/index.d.ts +3 -3
  50. package/dist/index.js +3 -3
  51. package/dist/js_render/computable_context.cjs +8 -5
  52. package/dist/js_render/computable_context.cjs.map +1 -1
  53. package/dist/js_render/computable_context.js +5 -1
  54. package/dist/js_render/computable_context.js.map +1 -1
  55. package/dist/js_render/context.cjs +4 -1
  56. package/dist/js_render/context.cjs.map +1 -1
  57. package/dist/js_render/context.js +4 -1
  58. package/dist/js_render/context.js.map +1 -1
  59. package/dist/js_render/index.cjs +0 -1
  60. package/dist/js_render/index.cjs.map +1 -1
  61. package/dist/js_render/index.js.map +1 -1
  62. package/dist/js_render/service_injectors.cjs +2 -3
  63. package/dist/js_render/service_injectors.cjs.map +1 -1
  64. package/dist/js_render/service_injectors.js +1 -1
  65. package/dist/js_render/service_injectors.js.map +1 -1
  66. package/dist/middle_layer/active_cfg.cjs +0 -1
  67. package/dist/middle_layer/active_cfg.cjs.map +1 -1
  68. package/dist/middle_layer/active_cfg.js.map +1 -1
  69. package/dist/middle_layer/block.cjs +0 -1
  70. package/dist/middle_layer/block.cjs.map +1 -1
  71. package/dist/middle_layer/block.js.map +1 -1
  72. package/dist/middle_layer/block_ctx.cjs +0 -1
  73. package/dist/middle_layer/block_ctx.cjs.map +1 -1
  74. package/dist/middle_layer/block_ctx.js.map +1 -1
  75. package/dist/middle_layer/block_ctx_unsafe.cjs.map +1 -1
  76. package/dist/middle_layer/block_ctx_unsafe.js.map +1 -1
  77. package/dist/middle_layer/driver_kit.cjs +0 -1
  78. package/dist/middle_layer/driver_kit.cjs.map +1 -1
  79. package/dist/middle_layer/driver_kit.js.map +1 -1
  80. package/dist/middle_layer/frontend_path.cjs +5 -1
  81. package/dist/middle_layer/frontend_path.cjs.map +1 -1
  82. package/dist/middle_layer/frontend_path.js +6 -1
  83. package/dist/middle_layer/frontend_path.js.map +1 -1
  84. package/dist/middle_layer/index.cjs +13 -5
  85. package/dist/middle_layer/index.d.ts +2 -1
  86. package/dist/middle_layer/index.js +6 -5
  87. package/dist/middle_layer/middle_layer.cjs +7 -1
  88. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  89. package/dist/middle_layer/middle_layer.d.ts.map +1 -1
  90. package/dist/middle_layer/middle_layer.js +7 -0
  91. package/dist/middle_layer/middle_layer.js.map +1 -1
  92. package/dist/middle_layer/navigation_states.cjs +0 -1
  93. package/dist/middle_layer/navigation_states.cjs.map +1 -1
  94. package/dist/middle_layer/navigation_states.js.map +1 -1
  95. package/dist/middle_layer/ops.cjs +1 -1
  96. package/dist/middle_layer/ops.cjs.map +1 -1
  97. package/dist/middle_layer/ops.d.ts.map +1 -1
  98. package/dist/middle_layer/ops.js.map +1 -1
  99. package/dist/middle_layer/project.cjs +9 -2
  100. package/dist/middle_layer/project.cjs.map +1 -1
  101. package/dist/middle_layer/project.d.ts.map +1 -1
  102. package/dist/middle_layer/project.js +5 -1
  103. package/dist/middle_layer/project.js.map +1 -1
  104. package/dist/middle_layer/project_list.cjs +2 -1
  105. package/dist/middle_layer/project_list.cjs.map +1 -1
  106. package/dist/middle_layer/project_list.js +1 -1
  107. package/dist/middle_layer/project_list.js.map +1 -1
  108. package/dist/middle_layer/project_overview.cjs +0 -1
  109. package/dist/middle_layer/project_overview.cjs.map +1 -1
  110. package/dist/middle_layer/project_overview.js.map +1 -1
  111. package/dist/middle_layer/project_overview_light.cjs +0 -1
  112. package/dist/middle_layer/project_overview_light.cjs.map +1 -1
  113. package/dist/middle_layer/project_overview_light.js.map +1 -1
  114. package/dist/middle_layer/render.cjs +0 -1
  115. package/dist/middle_layer/render.cjs.map +1 -1
  116. package/dist/middle_layer/render.js.map +1 -1
  117. package/dist/middle_layer/types.d.ts.map +1 -1
  118. package/dist/middle_layer/util.cjs +0 -1
  119. package/dist/middle_layer/util.cjs.map +1 -1
  120. package/dist/middle_layer/util.js.map +1 -1
  121. package/dist/model/args.cjs +1 -1
  122. package/dist/model/args.cjs.map +1 -1
  123. package/dist/model/args.js +1 -1
  124. package/dist/model/args.js.map +1 -1
  125. package/dist/model/block_pack_spec.cjs +5 -0
  126. package/dist/model/block_pack_spec.cjs.map +1 -1
  127. package/dist/model/block_pack_spec.d.ts +19 -2
  128. package/dist/model/block_pack_spec.d.ts.map +1 -1
  129. package/dist/model/block_pack_spec.js +5 -1
  130. package/dist/model/block_pack_spec.js.map +1 -1
  131. package/dist/model/frontend.d.ts.map +1 -1
  132. package/dist/model/index.d.ts +2 -1
  133. package/dist/model/project_helper.cjs +2 -1
  134. package/dist/model/project_helper.cjs.map +1 -1
  135. package/dist/model/project_helper.d.ts +1 -1
  136. package/dist/model/project_helper.d.ts.map +1 -1
  137. package/dist/model/project_helper.js +2 -0
  138. package/dist/model/project_helper.js.map +1 -1
  139. package/dist/model/project_model.cjs +2 -1
  140. package/dist/model/project_model.cjs.map +1 -1
  141. package/dist/model/project_model.d.ts.map +1 -1
  142. package/dist/model/project_model.js +2 -2
  143. package/dist/model/project_model.js.map +1 -1
  144. package/dist/model/project_model_util.cjs +4 -3
  145. package/dist/model/project_model_util.cjs.map +1 -1
  146. package/dist/model/project_model_util.js +4 -4
  147. package/dist/model/project_model_util.js.map +1 -1
  148. package/dist/model/template_spec.d.ts.map +1 -1
  149. package/dist/mutator/block-pack/block_pack.cjs +41 -4
  150. package/dist/mutator/block-pack/block_pack.cjs.map +1 -1
  151. package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
  152. package/dist/mutator/block-pack/block_pack.js +40 -4
  153. package/dist/mutator/block-pack/block_pack.js.map +1 -1
  154. package/dist/mutator/block-pack/frontend.cjs +5 -1
  155. package/dist/mutator/block-pack/frontend.cjs.map +1 -1
  156. package/dist/mutator/block-pack/frontend.js +6 -1
  157. package/dist/mutator/block-pack/frontend.js.map +1 -1
  158. package/dist/mutator/block-pack/required_capabilities.cjs +0 -1
  159. package/dist/mutator/block-pack/required_capabilities.cjs.map +1 -1
  160. package/dist/mutator/block-pack/required_capabilities.js.map +1 -1
  161. package/dist/mutator/context_export.cjs +0 -1
  162. package/dist/mutator/context_export.cjs.map +1 -1
  163. package/dist/mutator/context_export.js.map +1 -1
  164. package/dist/mutator/migration.cjs +0 -1
  165. package/dist/mutator/migration.cjs.map +1 -1
  166. package/dist/mutator/migration.js.map +1 -1
  167. package/dist/mutator/project.cjs +22 -4
  168. package/dist/mutator/project.cjs.map +1 -1
  169. package/dist/mutator/project.js +21 -4
  170. package/dist/mutator/project.js.map +1 -1
  171. package/dist/mutator/template/direct_template_loader.cjs +0 -1
  172. package/dist/mutator/template/direct_template_loader.cjs.map +1 -1
  173. package/dist/mutator/template/direct_template_loader.js.map +1 -1
  174. package/dist/mutator/template/direct_template_loader_v3.cjs +0 -1
  175. package/dist/mutator/template/direct_template_loader_v3.cjs.map +1 -1
  176. package/dist/mutator/template/direct_template_loader_v3.js.map +1 -1
  177. package/dist/mutator/template/render_block.cjs +4 -1
  178. package/dist/mutator/template/render_block.cjs.map +1 -1
  179. package/dist/mutator/template/render_block.js +1 -1
  180. package/dist/mutator/template/render_block.js.map +1 -1
  181. package/dist/mutator/template/render_template.cjs +0 -1
  182. package/dist/mutator/template/render_template.cjs.map +1 -1
  183. package/dist/mutator/template/render_template.d.ts.map +1 -1
  184. package/dist/mutator/template/render_template.js.map +1 -1
  185. package/dist/mutator/template/template_cache.cjs +6 -3
  186. package/dist/mutator/template/template_cache.cjs.map +1 -1
  187. package/dist/mutator/template/template_cache.d.ts +1 -2
  188. package/dist/mutator/template/template_cache.d.ts.map +1 -1
  189. package/dist/mutator/template/template_cache.js +6 -2
  190. package/dist/mutator/template/template_cache.js.map +1 -1
  191. package/dist/mutator/template/template_loading.cjs +1 -1
  192. package/dist/mutator/template/template_loading.cjs.map +1 -1
  193. package/dist/mutator/template/template_loading.d.ts.map +1 -1
  194. package/dist/mutator/template/template_loading.js.map +1 -1
  195. package/dist/network_check/network_check.cjs +0 -1
  196. package/dist/network_check/network_check.cjs.map +1 -1
  197. package/dist/network_check/network_check.d.ts.map +1 -1
  198. package/dist/network_check/network_check.js.map +1 -1
  199. package/dist/network_check/pings.cjs +3 -1
  200. package/dist/network_check/pings.cjs.map +1 -1
  201. package/dist/network_check/pings.js +1 -1
  202. package/dist/network_check/pings.js.map +1 -1
  203. package/dist/network_check/template.cjs +10 -3
  204. package/dist/network_check/template.cjs.map +1 -1
  205. package/dist/network_check/template.js +1 -1
  206. package/dist/network_check/template.js.map +1 -1
  207. package/dist/pool/data.cjs +12 -1
  208. package/dist/pool/data.cjs.map +1 -1
  209. package/dist/pool/data.d.ts.map +1 -1
  210. package/dist/pool/data.js +3 -1
  211. package/dist/pool/data.js.map +1 -1
  212. package/dist/pool/driver.cjs +8 -1
  213. package/dist/pool/driver.cjs.map +1 -1
  214. package/dist/pool/driver.d.ts.map +1 -1
  215. package/dist/pool/driver.js +7 -0
  216. package/dist/pool/driver.js.map +1 -1
  217. package/dist/pool/index.cjs +5 -2
  218. package/dist/pool/index.d.ts +2 -1
  219. package/dist/pool/index.js +3 -2
  220. package/dist/pool/p_object_collection.cjs +1 -1
  221. package/dist/pool/p_object_collection.cjs.map +1 -1
  222. package/dist/pool/p_object_collection.js.map +1 -1
  223. package/dist/pool/result_pool.cjs +2 -1
  224. package/dist/pool/result_pool.cjs.map +1 -1
  225. package/dist/pool/result_pool.js +2 -0
  226. package/dist/pool/result_pool.js.map +1 -1
  227. package/dist/service_factories.cjs +0 -1
  228. package/dist/service_factories.cjs.map +1 -1
  229. package/dist/service_factories.js.map +1 -1
  230. package/dist/worker/WorkerManager.cjs +3 -2
  231. package/dist/worker/WorkerManager.cjs.map +1 -1
  232. package/dist/worker/WorkerManager.js +2 -1
  233. package/dist/worker/WorkerManager.js.map +1 -1
  234. package/dist/worker/worker.cjs +0 -1
  235. package/dist/worker/worker.cjs.map +1 -1
  236. package/dist/worker/worker.js.map +1 -1
  237. package/dist/worker/workerApi.cjs +0 -1
  238. package/dist/worker/workerApi.cjs.map +1 -1
  239. package/dist/worker/workerApi.js.map +1 -1
  240. package/package.json +15 -15
  241. package/src/block_registry/registry.ts +19 -0
  242. package/src/block_registry/watcher.ts +25 -2
  243. package/src/middle_layer/frontend_path.ts +22 -2
  244. package/src/model/block_pack_spec.ts +24 -1
  245. package/src/mutator/block-pack/block_pack.ts +61 -2
  246. package/src/mutator/block-pack/frontend.ts +20 -2
  247. package/src/mutator/template/template_cache.ts +10 -2
@@ -1 +1 @@
1
- {"version":3,"file":"pings.js","names":[],"sources":["../../src/network_check/pings.ts"],"sourcesContent":["import type { ValueOrError } from \"@milaboratories/ts-helpers\";\nimport { setTimeout } from \"node:timers/promises\";\nimport { request } from \"undici\";\nimport type { Dispatcher } from \"undici\";\nimport type { CheckNetworkOpts } from \"./network_check\";\nimport { UnauthenticatedPlClient, type PlClientConfig } from \"@milaboratories/pl-client\";\n\n/** A report about one concrete ping to the service. */\nexport interface NetworkReport<T> {\n elapsedMs: number;\n response: ValueOrError<T>;\n}\n\nexport type HttpNetworkReport = NetworkReport<{\n statusCode: number;\n beginningOfBody: string;\n}>;\n\nexport async function backendPings(\n ops: CheckNetworkOpts,\n plConfig: PlClientConfig,\n): Promise<NetworkReport<string>[]> {\n return await recordPings(\n ops.pingCheckDurationMs,\n ops.maxPingsPerSecond,\n async () => {\n const uaClient = await UnauthenticatedPlClient.build(plConfig);\n const response = await uaClient.ping();\n return JSON.stringify(response).slice(0, ops.bodyLimit) + \"...\";\n },\n ops.signal,\n );\n}\n\nexport async function blockRegistryOverviewPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () =>\n await requestUrl(new URL(ops.blockOverviewPath, ops.blockRegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function blockGARegistryOverviewPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () =>\n await requestUrl(new URL(ops.blockOverviewPath, ops.blockGARegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function blockRegistryUiPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () => await requestUrl(new URL(ops.blockUiPath, ops.blockRegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function blockGARegistryUiPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () => await requestUrl(new URL(ops.blockUiPath, ops.blockGARegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function autoUpdateCdnPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.autoUpdateCdnDurationMs,\n ops.maxAutoUpdateCdnChecksPerSecond,\n async () => await requestUrl(ops.autoUpdateCdnUrl, ops, httpClient),\n ops.signal,\n );\n}\n\n/** Executes a body several times per second up to the given duration,\n * and returns results and elapsed time for every result. */\nexport async function recordPings<T>(\n pingCheckDurationMs: number,\n maxPingsPerSecond: number,\n body: () => Promise<T>,\n signal?: AbortSignal,\n): Promise<NetworkReport<T>[]> {\n const startPings = Date.now();\n const reports: NetworkReport<T>[] = [];\n\n while (elapsed(startPings) < pingCheckDurationMs && !signal?.aborted) {\n const startPing = Date.now();\n let response: ValueOrError<T>;\n try {\n response = { ok: true, value: await body() };\n } catch (e) {\n response = { ok: false, error: e };\n }\n const elapsedPing = elapsed(startPing);\n\n reports.push({\n elapsedMs: elapsedPing,\n response,\n });\n\n const sleepBetweenPings = 1000 / maxPingsPerSecond - elapsedPing;\n\n if (sleepBetweenPings > 0) {\n try {\n await setTimeout(sleepBetweenPings, undefined, signal ? { signal } : undefined);\n } catch (e: unknown) {\n if (e instanceof Error && e.name === \"AbortError\") break;\n throw e;\n }\n }\n }\n\n return reports;\n}\n\nexport async function requestUrl(url: string | URL, ops: CheckNetworkOpts, httpClient: Dispatcher) {\n const { body: rawBody, statusCode } = await request(url, {\n dispatcher: httpClient,\n headersTimeout: ops.httpTimeoutMs,\n bodyTimeout: ops.httpTimeoutMs,\n });\n const body = await rawBody.text();\n\n return {\n statusCode: statusCode,\n beginningOfBody: body.slice(0, ops.bodyLimit) + \"...\",\n };\n}\n\nexport function elapsed(startMs: number): number {\n return Date.now() - startMs;\n}\n\nexport function reportToString<T>(report: NetworkReport<T>[]): {\n ok: boolean;\n details: string;\n} {\n const successes = report.filter((r) => r.response.ok);\n const errorsLen = report.length - successes.length;\n const { mean, median } = elapsedStat(report);\n\n const details = `\n total: ${report.length};\n successes: ${successes.length};\n errors: ${errorsLen};\n mean in ms: ${mean};\n median in ms: ${median};\n `;\n\n return {\n ok: errorsLen === 0,\n details,\n };\n}\n\nfunction elapsedStat(reports: { elapsedMs: number }[]) {\n if (reports.length === 0) return { mean: 0, median: undefined };\n const checks = reports.map((p) => p.elapsedMs).sort();\n const mean = checks.reduce((sum, p) => sum + p) / checks.length;\n\n let median = undefined;\n if (checks.length > 0) {\n const mid = Math.floor(checks.length / 2);\n median = checks.length % 2 ? checks[mid] : (checks[mid - 1] + checks[mid]) / 2;\n }\n\n return { mean, median };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pings.js","names":[],"sources":["../../src/network_check/pings.ts"],"sourcesContent":["import type { ValueOrError } from \"@milaboratories/ts-helpers\";\nimport { setTimeout } from \"node:timers/promises\";\nimport { request } from \"undici\";\nimport type { Dispatcher } from \"undici\";\nimport type { CheckNetworkOpts } from \"./network_check\";\nimport { UnauthenticatedPlClient, type PlClientConfig } from \"@milaboratories/pl-client\";\n\n/** A report about one concrete ping to the service. */\nexport interface NetworkReport<T> {\n elapsedMs: number;\n response: ValueOrError<T>;\n}\n\nexport type HttpNetworkReport = NetworkReport<{\n statusCode: number;\n beginningOfBody: string;\n}>;\n\nexport async function backendPings(\n ops: CheckNetworkOpts,\n plConfig: PlClientConfig,\n): Promise<NetworkReport<string>[]> {\n return await recordPings(\n ops.pingCheckDurationMs,\n ops.maxPingsPerSecond,\n async () => {\n const uaClient = await UnauthenticatedPlClient.build(plConfig);\n const response = await uaClient.ping();\n return JSON.stringify(response).slice(0, ops.bodyLimit) + \"...\";\n },\n ops.signal,\n );\n}\n\nexport async function blockRegistryOverviewPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () =>\n await requestUrl(new URL(ops.blockOverviewPath, ops.blockRegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function blockGARegistryOverviewPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () =>\n await requestUrl(new URL(ops.blockOverviewPath, ops.blockGARegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function blockRegistryUiPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () => await requestUrl(new URL(ops.blockUiPath, ops.blockRegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function blockGARegistryUiPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.blockRegistryDurationMs,\n ops.maxRegistryChecksPerSecond,\n async () => await requestUrl(new URL(ops.blockUiPath, ops.blockGARegistryUrl), ops, httpClient),\n ops.signal,\n );\n}\n\nexport async function autoUpdateCdnPings(\n ops: CheckNetworkOpts,\n httpClient: Dispatcher,\n): Promise<HttpNetworkReport[]> {\n return await recordPings(\n ops.autoUpdateCdnDurationMs,\n ops.maxAutoUpdateCdnChecksPerSecond,\n async () => await requestUrl(ops.autoUpdateCdnUrl, ops, httpClient),\n ops.signal,\n );\n}\n\n/** Executes a body several times per second up to the given duration,\n * and returns results and elapsed time for every result. */\nexport async function recordPings<T>(\n pingCheckDurationMs: number,\n maxPingsPerSecond: number,\n body: () => Promise<T>,\n signal?: AbortSignal,\n): Promise<NetworkReport<T>[]> {\n const startPings = Date.now();\n const reports: NetworkReport<T>[] = [];\n\n while (elapsed(startPings) < pingCheckDurationMs && !signal?.aborted) {\n const startPing = Date.now();\n let response: ValueOrError<T>;\n try {\n response = { ok: true, value: await body() };\n } catch (e) {\n response = { ok: false, error: e };\n }\n const elapsedPing = elapsed(startPing);\n\n reports.push({\n elapsedMs: elapsedPing,\n response,\n });\n\n const sleepBetweenPings = 1000 / maxPingsPerSecond - elapsedPing;\n\n if (sleepBetweenPings > 0) {\n try {\n await setTimeout(sleepBetweenPings, undefined, signal ? { signal } : undefined);\n } catch (e: unknown) {\n if (e instanceof Error && e.name === \"AbortError\") break;\n throw e;\n }\n }\n }\n\n return reports;\n}\n\nexport async function requestUrl(url: string | URL, ops: CheckNetworkOpts, httpClient: Dispatcher) {\n const { body: rawBody, statusCode } = await request(url, {\n dispatcher: httpClient,\n headersTimeout: ops.httpTimeoutMs,\n bodyTimeout: ops.httpTimeoutMs,\n });\n const body = await rawBody.text();\n\n return {\n statusCode: statusCode,\n beginningOfBody: body.slice(0, ops.bodyLimit) + \"...\",\n };\n}\n\nexport function elapsed(startMs: number): number {\n return Date.now() - startMs;\n}\n\nexport function reportToString<T>(report: NetworkReport<T>[]): {\n ok: boolean;\n details: string;\n} {\n const successes = report.filter((r) => r.response.ok);\n const errorsLen = report.length - successes.length;\n const { mean, median } = elapsedStat(report);\n\n const details = `\n total: ${report.length};\n successes: ${successes.length};\n errors: ${errorsLen};\n mean in ms: ${mean};\n median in ms: ${median};\n `;\n\n return {\n ok: errorsLen === 0,\n details,\n };\n}\n\nfunction elapsedStat(reports: { elapsedMs: number }[]) {\n if (reports.length === 0) return { mean: 0, median: undefined };\n const checks = reports.map((p) => p.elapsedMs).sort();\n const mean = checks.reduce((sum, p) => sum + p) / checks.length;\n\n let median = undefined;\n if (checks.length > 0) {\n const mid = Math.floor(checks.length / 2);\n median = checks.length % 2 ? checks[mid] : (checks[mid - 1] + checks[mid]) / 2;\n }\n\n return { mean, median };\n}\n"],"mappings":"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"}
@@ -2,17 +2,17 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
2
  const require_render_template = require("../mutator/template/render_template.cjs");
3
3
  const require_template_loading = require("../mutator/template/template_loading.cjs");
4
4
  let node_path = require("node:path");
5
- node_path = require_runtime.__toESM(node_path);
5
+ node_path = require_runtime.__toESM(node_path, 1);
6
6
  let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
7
7
  let node_fs_promises = require("node:fs/promises");
8
- node_fs_promises = require_runtime.__toESM(node_fs_promises);
8
+ node_fs_promises = require_runtime.__toESM(node_fs_promises, 1);
9
9
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
10
10
  let node_crypto = require("node:crypto");
11
11
  let _platforma_sdk_workflow_tengo = require("@platforma-sdk/workflow-tengo");
12
12
  let _milaboratories_pl_drivers = require("@milaboratories/pl-drivers");
13
13
  let node_stream_consumers = require("node:stream/consumers");
14
14
  let node_os = require("node:os");
15
- node_os = require_runtime.__toESM(node_os);
15
+ node_os = require_runtime.__toESM(node_os, 1);
16
16
  //#region src/network_check/template.ts
17
17
  /** Uploads `hello-world` template and checks the output is correct. */
18
18
  async function uploadTemplate(logger, pl, name) {
@@ -301,11 +301,18 @@ async function deleteFields(client, fieldIds) {
301
301
  });
302
302
  }
303
303
  //#endregion
304
+ exports.chooseFile = chooseFile;
304
305
  exports.createBigTempFile = createBigTempFile;
305
306
  exports.createTempFile = createTempFile;
306
307
  exports.downloadFile = downloadFile;
307
308
  exports.downloadFromEveryStorage = downloadFromEveryStorage;
309
+ exports.listFilesSequence = listFilesSequence;
308
310
  exports.pythonSoftware = pythonSoftware;
311
+ exports.runDownloadFile = runDownloadFile;
312
+ exports.runPythonSoftware = runPythonSoftware;
313
+ exports.runSoftware = runSoftware;
314
+ exports.runUploadFile = runUploadFile;
315
+ exports.runUploadTemplate = runUploadTemplate;
309
316
  exports.softwareCheck = softwareCheck;
310
317
  exports.uploadFile = uploadFile;
311
318
  exports.uploadTemplate = uploadTemplate;
@@ -1 +1 @@
1
- {"version":3,"file":"template.cjs","names":["SdkTemplates","Pl","ImportFileHandleUploadData","path","os","fs","createRenderTemplate","loadTemplate","prepareTemplateSpec","ContinuePolling"],"sources":["../../src/network_check/template.ts"],"sourcesContent":["import type { FieldId, FieldRef, PlClient, ResourceData } from \"@milaboratories/pl-client\";\nimport {\n type PlTransaction,\n ContinuePolling,\n field,\n isNotNullSignedResourceId,\n isNullSignedResourceId,\n Pl,\n poll,\n toGlobalFieldId,\n} from \"@milaboratories/pl-client\";\nimport { createRenderTemplate } from \"../mutator/template/render_template\";\nimport { Templates as SdkTemplates } from \"@platforma-sdk/workflow-tengo\";\nimport type { TemplateSpecAny } from \"../model/template_spec\";\nimport { loadTemplate, prepareTemplateSpec } from \"../mutator/template/template_loading\";\nimport type { ClientDownload, LsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n ImportFileHandleUploadData,\n isSignMatch,\n isUpload,\n uploadBlob,\n type ClientUpload,\n type LsEntryWithFileStats,\n} from \"@milaboratories/pl-drivers\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { notEmpty, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { text } from \"node:stream/consumers\";\nimport path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { randomBytes } from \"node:crypto\";\nimport type { StorageEntry } from \"@milaboratories/pl-model-common\";\n\nexport interface TemplateReport {\n status: \"ok\" | \"warn\" | \"failed\";\n message: string;\n}\n\n/** Uploads `hello-world` template and checks the output is correct. */\nexport async function uploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<TemplateReport> {\n try {\n const gotGreeting = await runUploadTemplate(logger, pl, name);\n if (gotGreeting !== `Hello, ${name}`) {\n return {\n status: \"failed\",\n message: `Template uploading failed: expected: ${name}, got: ${gotGreeting}`,\n };\n }\n\n return { status: \"ok\", message: `Template uploading succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Template uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<string> {\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_template\"],\n true,\n (tx) => ({\n name: tx.createValue(Pl.JsonObject, JSON.stringify(name)),\n }),\n [\"greeting\"],\n );\n\n try {\n return JSON.parse(notEmpty((await getFieldValue(pl, outputs.greeting)).data?.toString()));\n } finally {\n if (outputs != undefined) {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n}\n\n/** Uploads a file to the backend and checks the output is a Blob resource. */\nexport async function uploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<TemplateReport> {\n try {\n const gotBlob = await runUploadFile(logger, signer, lsDriver, uploadClient, pl, filePath);\n\n if (gotBlob.type.name !== \"Blob\") {\n return { status: \"failed\", message: `File uploading failed: ${gotBlob.type.name}` };\n }\n\n return { status: \"ok\", message: `File uploading succeeded: ${gotBlob.type.name}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<ResourceInfo> {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_blob\"],\n true,\n (tx) => ({\n file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)),\n }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, result.progress);\n\n if (isUpload(progress)) {\n const uploadData = ImportFileHandleUploadData.parse(\n JSON.parse(notEmpty(progress.data?.toString())),\n );\n const isUploadSignMatch = isSignMatch(signer, uploadData.localPath, uploadData.pathSignature);\n\n if (isUploadSignMatch) {\n await uploadBlob(logger, uploadClient, progress, uploadData, () => false, {\n nPartsWithThisUploadSpeed: 10,\n nPartsToIncreaseUpload: 10,\n currentSpeed: 10,\n maxSpeed: 10,\n });\n }\n }\n\n return await getFieldValue(pl, result.file);\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Uploads a file to the backend and then tries to download it back. */\nexport async function downloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n fileContent: string,\n): Promise<TemplateReport> {\n try {\n const gotFileContent = await runDownloadFile(\n logger,\n pl,\n lsDriver,\n uploadClient,\n downloadClient,\n filePath,\n );\n\n if (gotFileContent !== fileContent) {\n return {\n status: \"failed\",\n message: `File downloading failed: expected: ${fileContent}, got: ${gotFileContent}`,\n };\n }\n return { status: \"ok\", message: `File downloading succeeded: ${gotFileContent}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File downloading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runDownloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n) {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.download_blob\"],\n true,\n (tx) => ({ file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)) }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, outputs.progress);\n\n await uploadBlob(\n logger,\n uploadClient,\n progress,\n ImportFileHandleUploadData.parse(JSON.parse(notEmpty(progress.data?.toString()))),\n () => false,\n {\n nPartsWithThisUploadSpeed: 1,\n nPartsToIncreaseUpload: 1,\n currentSpeed: 1,\n maxSpeed: 1,\n },\n );\n\n const fileInfo = await getFieldValue(pl, outputs.file);\n\n return await downloadClient.withBlobContent(\n fileInfo,\n {},\n {},\n async (content) => await text(content),\n );\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n}\n\n/** Runs Go's hello-world binary. */\nexport async function softwareCheck(pl: PlClient): Promise<TemplateReport> {\n try {\n const gotGreeting = await runSoftware(pl);\n\n if (gotGreeting !== \"Hello from go binary\\n\") {\n return { status: \"failed\", message: `Software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runSoftware(pl: PlClient): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world\"],\n true,\n (_: PlTransaction) => ({}),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Runs Python hello-world. */\nexport async function pythonSoftware(pl: PlClient, name: string): Promise<TemplateReport> {\n try {\n const gotGreeting = await runPythonSoftware(pl, name);\n\n if (gotGreeting !== `Hello, ${name}!\\n`) {\n return { status: \"failed\", message: `Python software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Python software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Python software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runPythonSoftware(pl: PlClient, name: string): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world_py\"],\n true,\n (tx) => ({ name: tx.createValue(Pl.JsonObject, JSON.stringify(name)) }),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Tries to download a file from every storage. */\nexport async function downloadFromEveryStorage(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n ops: {\n minLsRequests: number;\n bytesLimit: number;\n minFileSize: number;\n maxFileSize: number;\n nFilesToCheck: number;\n },\n): Promise<Record<string, TemplateReport>> {\n try {\n const storages = await lsDriver.getStorageList();\n const results: Record<string, TemplateReport> = {};\n\n for (const storage of storages) {\n const result = await chooseFile(\n lsDriver,\n storage,\n ops.nFilesToCheck,\n ops.minFileSize,\n ops.maxFileSize,\n ops.minLsRequests,\n );\n if (result.file === undefined) {\n results[storage.id] = {\n status: \"warn\",\n message:\n `No file between ${ops.minFileSize} and ${ops.maxFileSize} bytes ` +\n `found in storage ${storage.name}, checked ${result.nCheckedFiles} files, ` +\n `did ${result.nLsRequests} ls requests`,\n };\n continue;\n }\n\n logger.info(`Downloading file ${JSON.stringify(result)} from storage ${storage.name}`);\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.create_workdir_from_storage\"],\n true,\n (tx) => ({\n file: tx.createValue(\n Pl.JsonObject,\n JSON.stringify((result.file as { handle: string }).handle),\n ),\n }),\n [\"workdirTypeName\"],\n );\n\n try {\n const workdirTypeName = JSON.parse(\n Buffer.from((await getFieldValue(pl, outputs.workdirTypeName)).data!).toString(),\n ) as string;\n\n if (workdirTypeName?.startsWith(\"WorkingDirectory\")) {\n results[storage.id] = {\n status: \"ok\",\n message:\n `Workdir creation succeeded, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n } else {\n results[storage.id] = {\n status: \"failed\",\n message:\n `Workdir creation failed: ${workdirTypeName}, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n }\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n\n return results;\n } catch (e: unknown) {\n return {\n unknown: {\n status: \"failed\",\n message: `Download from every storage failed: error occurred: ${e}`,\n },\n };\n }\n}\n\n/** Chooses a random file from the storage in a size range.\n * If we couldn't find a normal-sized file, we'll return a small file to check at least something.\n */\nexport async function chooseFile(\n lsDriver: LsDriver,\n storage: StorageEntry,\n limit: number,\n minSize: number,\n maxSize: number,\n minLsRequests: number,\n): Promise<{\n file: LsEntryWithFileStats | undefined;\n nLsRequests: number;\n nCheckedFiles: number;\n}> {\n const files = listFilesSequence(lsDriver, storage, \"\", 0);\n\n // return small file in case we don't have many normal-sized files.\n // While we'll download only a small range of bytes from the file,\n // we don't want to return a big file in case the underlying S3 doesn't support range requests.\n let smallFile: LsEntryWithFileStats | undefined;\n let nCheckedFiles = 0;\n let maxNLsRequests = 0;\n\n for await (const { file, nLsRequests } of files) {\n maxNLsRequests = Math.max(maxNLsRequests, nLsRequests);\n\n if (nCheckedFiles >= limit && maxNLsRequests > minLsRequests) {\n // we reached a limit on both the number of files and the number of ls requests.\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n }\n nCheckedFiles++;\n if (minSize <= file.size && file.size <= maxSize) {\n return { file, nLsRequests: maxNLsRequests, nCheckedFiles };\n } else if (file.size < minSize) {\n smallFile = file;\n }\n }\n\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n}\n\n/** Deep-first search for files in the storage. */\nexport async function* listFilesSequence(\n lsDriver: LsDriver,\n storage: StorageEntry,\n parent: string,\n nLsRequests: number,\n): AsyncGenerator<{ file: LsEntryWithFileStats; nLsRequests: number }, void, unknown> {\n nLsRequests++;\n const files = await lsDriver.listRemoteFilesWithFileStats(storage.handle, parent);\n\n for (const file of files.entries) {\n if (file.type === \"file\" && file.fullPath.startsWith(parent)) {\n yield {\n file,\n nLsRequests,\n };\n } else if (file.type === \"dir\") {\n for await (const nestedFile of listFilesSequence(\n lsDriver,\n storage,\n file.fullPath,\n nLsRequests,\n )) {\n nLsRequests = Math.max(nestedFile.nLsRequests, nLsRequests);\n yield nestedFile;\n }\n }\n }\n}\n\n/** Creates a big temporary file with random content. */\nexport async function createBigTempFile(): Promise<{ filePath: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-big-temp-${Date.now()}.bin`);\n const fileSize = 20 * 1024 * 1024; // 20 MiB\n\n const fileContent = randomBytes(fileSize);\n\n await fs.appendFile(filePath, fileContent);\n\n return { filePath };\n}\n\n/** Creates a temporarly file we could use for uploading and downloading. */\nexport async function createTempFile(): Promise<{ filePath: string; fileContent: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-temp-${Date.now()}.txt`);\n\n const fileContent = \"Hello, world! \" + new Date().toISOString();\n await fs.writeFile(filePath, fileContent);\n\n return { filePath, fileContent };\n}\n\n/** Creates a template and RenderTemplate resources, gets all resources from outputs.\n * Throws a error if any of the outputs failed.\n */\nasync function runTemplate(\n client: PlClient,\n tpl: TemplateSpecAny,\n ephemeral: boolean,\n inputs: (tx: PlTransaction) => Pl.PlRecord,\n outputs: string[],\n): Promise<Record<string, FieldId>> {\n return await client.withWriteTx(\"TemplateRender\", async (tx) => {\n const preparedTemplate = await prepareTemplateSpec(tpl);\n const tplResource = loadTemplate(tx, preparedTemplate);\n\n const outputFields: Record<string, FieldRef> = createRenderTemplate(\n tx,\n tplResource,\n ephemeral,\n inputs(tx),\n outputs,\n );\n\n const outputsIds: Record<string, FieldId> = {};\n\n for (const output of outputs) {\n const fieldRef = field(client.clientRoot, output) as FieldId;\n tx.createField(fieldRef, \"Dynamic\", outputFields[output]);\n outputsIds[output] = await toGlobalFieldId(fieldRef);\n }\n\n await tx.commit();\n\n return outputsIds;\n });\n}\n\n/** Gets a resource from field's value or throws a error. */\nasync function getFieldValue(client: PlClient, fieldId: FieldId): Promise<ResourceData> {\n // We could also do polling with pl-tree, but it seemed like an overkill,\n // that's why we have a simple polling here.\n\n return await poll(client, async (tx) => {\n const field = await tx.tx.getField(fieldId);\n if (isNotNullSignedResourceId(field.error)) {\n const err = await tx.tx.getResourceData(field.error, true);\n throw new Error(`getFieldValue of \"${fieldId.fieldName}\" field failed: ${err.data}`);\n }\n\n if (isNullSignedResourceId(field.value)) {\n throw new ContinuePolling();\n }\n\n return await tx.tx.getResourceData(field.value, true);\n });\n}\n\nasync function deleteFields(client: PlClient, fieldIds: FieldId[]) {\n await client.withWriteTx(\"DeleteFields\", async (tx) => {\n for (const fieldId of fieldIds) {\n tx.resetField(fieldId);\n }\n await tx.commit();\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"template.cjs","names":["SdkTemplates","Pl","ImportFileHandleUploadData","path","os","fs","createRenderTemplate","loadTemplate","prepareTemplateSpec","ContinuePolling"],"sources":["../../src/network_check/template.ts"],"sourcesContent":["import type { FieldId, FieldRef, PlClient, ResourceData } from \"@milaboratories/pl-client\";\nimport {\n type PlTransaction,\n ContinuePolling,\n field,\n isNotNullSignedResourceId,\n isNullSignedResourceId,\n Pl,\n poll,\n toGlobalFieldId,\n} from \"@milaboratories/pl-client\";\nimport { createRenderTemplate } from \"../mutator/template/render_template\";\nimport { Templates as SdkTemplates } from \"@platforma-sdk/workflow-tengo\";\nimport type { TemplateSpecAny } from \"../model/template_spec\";\nimport { loadTemplate, prepareTemplateSpec } from \"../mutator/template/template_loading\";\nimport type { ClientDownload, LsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n ImportFileHandleUploadData,\n isSignMatch,\n isUpload,\n uploadBlob,\n type ClientUpload,\n type LsEntryWithFileStats,\n} from \"@milaboratories/pl-drivers\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { notEmpty, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { text } from \"node:stream/consumers\";\nimport path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { randomBytes } from \"node:crypto\";\nimport type { StorageEntry } from \"@milaboratories/pl-model-common\";\n\nexport interface TemplateReport {\n status: \"ok\" | \"warn\" | \"failed\";\n message: string;\n}\n\n/** Uploads `hello-world` template and checks the output is correct. */\nexport async function uploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<TemplateReport> {\n try {\n const gotGreeting = await runUploadTemplate(logger, pl, name);\n if (gotGreeting !== `Hello, ${name}`) {\n return {\n status: \"failed\",\n message: `Template uploading failed: expected: ${name}, got: ${gotGreeting}`,\n };\n }\n\n return { status: \"ok\", message: `Template uploading succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Template uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<string> {\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_template\"],\n true,\n (tx) => ({\n name: tx.createValue(Pl.JsonObject, JSON.stringify(name)),\n }),\n [\"greeting\"],\n );\n\n try {\n return JSON.parse(notEmpty((await getFieldValue(pl, outputs.greeting)).data?.toString()));\n } finally {\n if (outputs != undefined) {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n}\n\n/** Uploads a file to the backend and checks the output is a Blob resource. */\nexport async function uploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<TemplateReport> {\n try {\n const gotBlob = await runUploadFile(logger, signer, lsDriver, uploadClient, pl, filePath);\n\n if (gotBlob.type.name !== \"Blob\") {\n return { status: \"failed\", message: `File uploading failed: ${gotBlob.type.name}` };\n }\n\n return { status: \"ok\", message: `File uploading succeeded: ${gotBlob.type.name}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<ResourceInfo> {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_blob\"],\n true,\n (tx) => ({\n file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)),\n }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, result.progress);\n\n if (isUpload(progress)) {\n const uploadData = ImportFileHandleUploadData.parse(\n JSON.parse(notEmpty(progress.data?.toString())),\n );\n const isUploadSignMatch = isSignMatch(signer, uploadData.localPath, uploadData.pathSignature);\n\n if (isUploadSignMatch) {\n await uploadBlob(logger, uploadClient, progress, uploadData, () => false, {\n nPartsWithThisUploadSpeed: 10,\n nPartsToIncreaseUpload: 10,\n currentSpeed: 10,\n maxSpeed: 10,\n });\n }\n }\n\n return await getFieldValue(pl, result.file);\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Uploads a file to the backend and then tries to download it back. */\nexport async function downloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n fileContent: string,\n): Promise<TemplateReport> {\n try {\n const gotFileContent = await runDownloadFile(\n logger,\n pl,\n lsDriver,\n uploadClient,\n downloadClient,\n filePath,\n );\n\n if (gotFileContent !== fileContent) {\n return {\n status: \"failed\",\n message: `File downloading failed: expected: ${fileContent}, got: ${gotFileContent}`,\n };\n }\n return { status: \"ok\", message: `File downloading succeeded: ${gotFileContent}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File downloading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runDownloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n) {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.download_blob\"],\n true,\n (tx) => ({ file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)) }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, outputs.progress);\n\n await uploadBlob(\n logger,\n uploadClient,\n progress,\n ImportFileHandleUploadData.parse(JSON.parse(notEmpty(progress.data?.toString()))),\n () => false,\n {\n nPartsWithThisUploadSpeed: 1,\n nPartsToIncreaseUpload: 1,\n currentSpeed: 1,\n maxSpeed: 1,\n },\n );\n\n const fileInfo = await getFieldValue(pl, outputs.file);\n\n return await downloadClient.withBlobContent(\n fileInfo,\n {},\n {},\n async (content) => await text(content),\n );\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n}\n\n/** Runs Go's hello-world binary. */\nexport async function softwareCheck(pl: PlClient): Promise<TemplateReport> {\n try {\n const gotGreeting = await runSoftware(pl);\n\n if (gotGreeting !== \"Hello from go binary\\n\") {\n return { status: \"failed\", message: `Software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runSoftware(pl: PlClient): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world\"],\n true,\n (_: PlTransaction) => ({}),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Runs Python hello-world. */\nexport async function pythonSoftware(pl: PlClient, name: string): Promise<TemplateReport> {\n try {\n const gotGreeting = await runPythonSoftware(pl, name);\n\n if (gotGreeting !== `Hello, ${name}!\\n`) {\n return { status: \"failed\", message: `Python software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Python software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Python software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runPythonSoftware(pl: PlClient, name: string): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world_py\"],\n true,\n (tx) => ({ name: tx.createValue(Pl.JsonObject, JSON.stringify(name)) }),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Tries to download a file from every storage. */\nexport async function downloadFromEveryStorage(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n ops: {\n minLsRequests: number;\n bytesLimit: number;\n minFileSize: number;\n maxFileSize: number;\n nFilesToCheck: number;\n },\n): Promise<Record<string, TemplateReport>> {\n try {\n const storages = await lsDriver.getStorageList();\n const results: Record<string, TemplateReport> = {};\n\n for (const storage of storages) {\n const result = await chooseFile(\n lsDriver,\n storage,\n ops.nFilesToCheck,\n ops.minFileSize,\n ops.maxFileSize,\n ops.minLsRequests,\n );\n if (result.file === undefined) {\n results[storage.id] = {\n status: \"warn\",\n message:\n `No file between ${ops.minFileSize} and ${ops.maxFileSize} bytes ` +\n `found in storage ${storage.name}, checked ${result.nCheckedFiles} files, ` +\n `did ${result.nLsRequests} ls requests`,\n };\n continue;\n }\n\n logger.info(`Downloading file ${JSON.stringify(result)} from storage ${storage.name}`);\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.create_workdir_from_storage\"],\n true,\n (tx) => ({\n file: tx.createValue(\n Pl.JsonObject,\n JSON.stringify((result.file as { handle: string }).handle),\n ),\n }),\n [\"workdirTypeName\"],\n );\n\n try {\n const workdirTypeName = JSON.parse(\n Buffer.from((await getFieldValue(pl, outputs.workdirTypeName)).data!).toString(),\n ) as string;\n\n if (workdirTypeName?.startsWith(\"WorkingDirectory\")) {\n results[storage.id] = {\n status: \"ok\",\n message:\n `Workdir creation succeeded, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n } else {\n results[storage.id] = {\n status: \"failed\",\n message:\n `Workdir creation failed: ${workdirTypeName}, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n }\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n\n return results;\n } catch (e: unknown) {\n return {\n unknown: {\n status: \"failed\",\n message: `Download from every storage failed: error occurred: ${e}`,\n },\n };\n }\n}\n\n/** Chooses a random file from the storage in a size range.\n * If we couldn't find a normal-sized file, we'll return a small file to check at least something.\n */\nexport async function chooseFile(\n lsDriver: LsDriver,\n storage: StorageEntry,\n limit: number,\n minSize: number,\n maxSize: number,\n minLsRequests: number,\n): Promise<{\n file: LsEntryWithFileStats | undefined;\n nLsRequests: number;\n nCheckedFiles: number;\n}> {\n const files = listFilesSequence(lsDriver, storage, \"\", 0);\n\n // return small file in case we don't have many normal-sized files.\n // While we'll download only a small range of bytes from the file,\n // we don't want to return a big file in case the underlying S3 doesn't support range requests.\n let smallFile: LsEntryWithFileStats | undefined;\n let nCheckedFiles = 0;\n let maxNLsRequests = 0;\n\n for await (const { file, nLsRequests } of files) {\n maxNLsRequests = Math.max(maxNLsRequests, nLsRequests);\n\n if (nCheckedFiles >= limit && maxNLsRequests > minLsRequests) {\n // we reached a limit on both the number of files and the number of ls requests.\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n }\n nCheckedFiles++;\n if (minSize <= file.size && file.size <= maxSize) {\n return { file, nLsRequests: maxNLsRequests, nCheckedFiles };\n } else if (file.size < minSize) {\n smallFile = file;\n }\n }\n\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n}\n\n/** Deep-first search for files in the storage. */\nexport async function* listFilesSequence(\n lsDriver: LsDriver,\n storage: StorageEntry,\n parent: string,\n nLsRequests: number,\n): AsyncGenerator<{ file: LsEntryWithFileStats; nLsRequests: number }, void, unknown> {\n nLsRequests++;\n const files = await lsDriver.listRemoteFilesWithFileStats(storage.handle, parent);\n\n for (const file of files.entries) {\n if (file.type === \"file\" && file.fullPath.startsWith(parent)) {\n yield {\n file,\n nLsRequests,\n };\n } else if (file.type === \"dir\") {\n for await (const nestedFile of listFilesSequence(\n lsDriver,\n storage,\n file.fullPath,\n nLsRequests,\n )) {\n nLsRequests = Math.max(nestedFile.nLsRequests, nLsRequests);\n yield nestedFile;\n }\n }\n }\n}\n\n/** Creates a big temporary file with random content. */\nexport async function createBigTempFile(): Promise<{ filePath: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-big-temp-${Date.now()}.bin`);\n const fileSize = 20 * 1024 * 1024; // 20 MiB\n\n const fileContent = randomBytes(fileSize);\n\n await fs.appendFile(filePath, fileContent);\n\n return { filePath };\n}\n\n/** Creates a temporarly file we could use for uploading and downloading. */\nexport async function createTempFile(): Promise<{ filePath: string; fileContent: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-temp-${Date.now()}.txt`);\n\n const fileContent = \"Hello, world! \" + new Date().toISOString();\n await fs.writeFile(filePath, fileContent);\n\n return { filePath, fileContent };\n}\n\n/** Creates a template and RenderTemplate resources, gets all resources from outputs.\n * Throws a error if any of the outputs failed.\n */\nasync function runTemplate(\n client: PlClient,\n tpl: TemplateSpecAny,\n ephemeral: boolean,\n inputs: (tx: PlTransaction) => Pl.PlRecord,\n outputs: string[],\n): Promise<Record<string, FieldId>> {\n return await client.withWriteTx(\"TemplateRender\", async (tx) => {\n const preparedTemplate = await prepareTemplateSpec(tpl);\n const tplResource = loadTemplate(tx, preparedTemplate);\n\n const outputFields: Record<string, FieldRef> = createRenderTemplate(\n tx,\n tplResource,\n ephemeral,\n inputs(tx),\n outputs,\n );\n\n const outputsIds: Record<string, FieldId> = {};\n\n for (const output of outputs) {\n const fieldRef = field(client.clientRoot, output) as FieldId;\n tx.createField(fieldRef, \"Dynamic\", outputFields[output]);\n outputsIds[output] = await toGlobalFieldId(fieldRef);\n }\n\n await tx.commit();\n\n return outputsIds;\n });\n}\n\n/** Gets a resource from field's value or throws a error. */\nasync function getFieldValue(client: PlClient, fieldId: FieldId): Promise<ResourceData> {\n // We could also do polling with pl-tree, but it seemed like an overkill,\n // that's why we have a simple polling here.\n\n return await poll(client, async (tx) => {\n const field = await tx.tx.getField(fieldId);\n if (isNotNullSignedResourceId(field.error)) {\n const err = await tx.tx.getResourceData(field.error, true);\n throw new Error(`getFieldValue of \"${fieldId.fieldName}\" field failed: ${err.data}`);\n }\n\n if (isNullSignedResourceId(field.value)) {\n throw new ContinuePolling();\n }\n\n return await tx.tx.getResourceData(field.value, true);\n });\n}\n\nasync function deleteFields(client: PlClient, fieldIds: FieldId[]) {\n await client.withWriteTx(\"DeleteFields\", async (tx) => {\n for (const fieldId of fieldIds) {\n tx.resetField(fieldId);\n }\n await tx.commit();\n });\n}\n"],"mappings":"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"}
@@ -297,6 +297,6 @@ async function deleteFields(client, fieldIds) {
297
297
  });
298
298
  }
299
299
  //#endregion
300
- export { createBigTempFile, createTempFile, downloadFile, downloadFromEveryStorage, pythonSoftware, softwareCheck, uploadFile, uploadTemplate };
300
+ export { chooseFile, createBigTempFile, createTempFile, downloadFile, downloadFromEveryStorage, listFilesSequence, pythonSoftware, runDownloadFile, runPythonSoftware, runSoftware, runUploadFile, runUploadTemplate, softwareCheck, uploadFile, uploadTemplate };
301
301
 
302
302
  //# sourceMappingURL=template.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","names":["SdkTemplates"],"sources":["../../src/network_check/template.ts"],"sourcesContent":["import type { FieldId, FieldRef, PlClient, ResourceData } from \"@milaboratories/pl-client\";\nimport {\n type PlTransaction,\n ContinuePolling,\n field,\n isNotNullSignedResourceId,\n isNullSignedResourceId,\n Pl,\n poll,\n toGlobalFieldId,\n} from \"@milaboratories/pl-client\";\nimport { createRenderTemplate } from \"../mutator/template/render_template\";\nimport { Templates as SdkTemplates } from \"@platforma-sdk/workflow-tengo\";\nimport type { TemplateSpecAny } from \"../model/template_spec\";\nimport { loadTemplate, prepareTemplateSpec } from \"../mutator/template/template_loading\";\nimport type { ClientDownload, LsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n ImportFileHandleUploadData,\n isSignMatch,\n isUpload,\n uploadBlob,\n type ClientUpload,\n type LsEntryWithFileStats,\n} from \"@milaboratories/pl-drivers\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { notEmpty, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { text } from \"node:stream/consumers\";\nimport path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { randomBytes } from \"node:crypto\";\nimport type { StorageEntry } from \"@milaboratories/pl-model-common\";\n\nexport interface TemplateReport {\n status: \"ok\" | \"warn\" | \"failed\";\n message: string;\n}\n\n/** Uploads `hello-world` template and checks the output is correct. */\nexport async function uploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<TemplateReport> {\n try {\n const gotGreeting = await runUploadTemplate(logger, pl, name);\n if (gotGreeting !== `Hello, ${name}`) {\n return {\n status: \"failed\",\n message: `Template uploading failed: expected: ${name}, got: ${gotGreeting}`,\n };\n }\n\n return { status: \"ok\", message: `Template uploading succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Template uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<string> {\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_template\"],\n true,\n (tx) => ({\n name: tx.createValue(Pl.JsonObject, JSON.stringify(name)),\n }),\n [\"greeting\"],\n );\n\n try {\n return JSON.parse(notEmpty((await getFieldValue(pl, outputs.greeting)).data?.toString()));\n } finally {\n if (outputs != undefined) {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n}\n\n/** Uploads a file to the backend and checks the output is a Blob resource. */\nexport async function uploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<TemplateReport> {\n try {\n const gotBlob = await runUploadFile(logger, signer, lsDriver, uploadClient, pl, filePath);\n\n if (gotBlob.type.name !== \"Blob\") {\n return { status: \"failed\", message: `File uploading failed: ${gotBlob.type.name}` };\n }\n\n return { status: \"ok\", message: `File uploading succeeded: ${gotBlob.type.name}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<ResourceInfo> {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_blob\"],\n true,\n (tx) => ({\n file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)),\n }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, result.progress);\n\n if (isUpload(progress)) {\n const uploadData = ImportFileHandleUploadData.parse(\n JSON.parse(notEmpty(progress.data?.toString())),\n );\n const isUploadSignMatch = isSignMatch(signer, uploadData.localPath, uploadData.pathSignature);\n\n if (isUploadSignMatch) {\n await uploadBlob(logger, uploadClient, progress, uploadData, () => false, {\n nPartsWithThisUploadSpeed: 10,\n nPartsToIncreaseUpload: 10,\n currentSpeed: 10,\n maxSpeed: 10,\n });\n }\n }\n\n return await getFieldValue(pl, result.file);\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Uploads a file to the backend and then tries to download it back. */\nexport async function downloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n fileContent: string,\n): Promise<TemplateReport> {\n try {\n const gotFileContent = await runDownloadFile(\n logger,\n pl,\n lsDriver,\n uploadClient,\n downloadClient,\n filePath,\n );\n\n if (gotFileContent !== fileContent) {\n return {\n status: \"failed\",\n message: `File downloading failed: expected: ${fileContent}, got: ${gotFileContent}`,\n };\n }\n return { status: \"ok\", message: `File downloading succeeded: ${gotFileContent}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File downloading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runDownloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n) {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.download_blob\"],\n true,\n (tx) => ({ file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)) }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, outputs.progress);\n\n await uploadBlob(\n logger,\n uploadClient,\n progress,\n ImportFileHandleUploadData.parse(JSON.parse(notEmpty(progress.data?.toString()))),\n () => false,\n {\n nPartsWithThisUploadSpeed: 1,\n nPartsToIncreaseUpload: 1,\n currentSpeed: 1,\n maxSpeed: 1,\n },\n );\n\n const fileInfo = await getFieldValue(pl, outputs.file);\n\n return await downloadClient.withBlobContent(\n fileInfo,\n {},\n {},\n async (content) => await text(content),\n );\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n}\n\n/** Runs Go's hello-world binary. */\nexport async function softwareCheck(pl: PlClient): Promise<TemplateReport> {\n try {\n const gotGreeting = await runSoftware(pl);\n\n if (gotGreeting !== \"Hello from go binary\\n\") {\n return { status: \"failed\", message: `Software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runSoftware(pl: PlClient): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world\"],\n true,\n (_: PlTransaction) => ({}),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Runs Python hello-world. */\nexport async function pythonSoftware(pl: PlClient, name: string): Promise<TemplateReport> {\n try {\n const gotGreeting = await runPythonSoftware(pl, name);\n\n if (gotGreeting !== `Hello, ${name}!\\n`) {\n return { status: \"failed\", message: `Python software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Python software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Python software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runPythonSoftware(pl: PlClient, name: string): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world_py\"],\n true,\n (tx) => ({ name: tx.createValue(Pl.JsonObject, JSON.stringify(name)) }),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Tries to download a file from every storage. */\nexport async function downloadFromEveryStorage(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n ops: {\n minLsRequests: number;\n bytesLimit: number;\n minFileSize: number;\n maxFileSize: number;\n nFilesToCheck: number;\n },\n): Promise<Record<string, TemplateReport>> {\n try {\n const storages = await lsDriver.getStorageList();\n const results: Record<string, TemplateReport> = {};\n\n for (const storage of storages) {\n const result = await chooseFile(\n lsDriver,\n storage,\n ops.nFilesToCheck,\n ops.minFileSize,\n ops.maxFileSize,\n ops.minLsRequests,\n );\n if (result.file === undefined) {\n results[storage.id] = {\n status: \"warn\",\n message:\n `No file between ${ops.minFileSize} and ${ops.maxFileSize} bytes ` +\n `found in storage ${storage.name}, checked ${result.nCheckedFiles} files, ` +\n `did ${result.nLsRequests} ls requests`,\n };\n continue;\n }\n\n logger.info(`Downloading file ${JSON.stringify(result)} from storage ${storage.name}`);\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.create_workdir_from_storage\"],\n true,\n (tx) => ({\n file: tx.createValue(\n Pl.JsonObject,\n JSON.stringify((result.file as { handle: string }).handle),\n ),\n }),\n [\"workdirTypeName\"],\n );\n\n try {\n const workdirTypeName = JSON.parse(\n Buffer.from((await getFieldValue(pl, outputs.workdirTypeName)).data!).toString(),\n ) as string;\n\n if (workdirTypeName?.startsWith(\"WorkingDirectory\")) {\n results[storage.id] = {\n status: \"ok\",\n message:\n `Workdir creation succeeded, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n } else {\n results[storage.id] = {\n status: \"failed\",\n message:\n `Workdir creation failed: ${workdirTypeName}, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n }\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n\n return results;\n } catch (e: unknown) {\n return {\n unknown: {\n status: \"failed\",\n message: `Download from every storage failed: error occurred: ${e}`,\n },\n };\n }\n}\n\n/** Chooses a random file from the storage in a size range.\n * If we couldn't find a normal-sized file, we'll return a small file to check at least something.\n */\nexport async function chooseFile(\n lsDriver: LsDriver,\n storage: StorageEntry,\n limit: number,\n minSize: number,\n maxSize: number,\n minLsRequests: number,\n): Promise<{\n file: LsEntryWithFileStats | undefined;\n nLsRequests: number;\n nCheckedFiles: number;\n}> {\n const files = listFilesSequence(lsDriver, storage, \"\", 0);\n\n // return small file in case we don't have many normal-sized files.\n // While we'll download only a small range of bytes from the file,\n // we don't want to return a big file in case the underlying S3 doesn't support range requests.\n let smallFile: LsEntryWithFileStats | undefined;\n let nCheckedFiles = 0;\n let maxNLsRequests = 0;\n\n for await (const { file, nLsRequests } of files) {\n maxNLsRequests = Math.max(maxNLsRequests, nLsRequests);\n\n if (nCheckedFiles >= limit && maxNLsRequests > minLsRequests) {\n // we reached a limit on both the number of files and the number of ls requests.\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n }\n nCheckedFiles++;\n if (minSize <= file.size && file.size <= maxSize) {\n return { file, nLsRequests: maxNLsRequests, nCheckedFiles };\n } else if (file.size < minSize) {\n smallFile = file;\n }\n }\n\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n}\n\n/** Deep-first search for files in the storage. */\nexport async function* listFilesSequence(\n lsDriver: LsDriver,\n storage: StorageEntry,\n parent: string,\n nLsRequests: number,\n): AsyncGenerator<{ file: LsEntryWithFileStats; nLsRequests: number }, void, unknown> {\n nLsRequests++;\n const files = await lsDriver.listRemoteFilesWithFileStats(storage.handle, parent);\n\n for (const file of files.entries) {\n if (file.type === \"file\" && file.fullPath.startsWith(parent)) {\n yield {\n file,\n nLsRequests,\n };\n } else if (file.type === \"dir\") {\n for await (const nestedFile of listFilesSequence(\n lsDriver,\n storage,\n file.fullPath,\n nLsRequests,\n )) {\n nLsRequests = Math.max(nestedFile.nLsRequests, nLsRequests);\n yield nestedFile;\n }\n }\n }\n}\n\n/** Creates a big temporary file with random content. */\nexport async function createBigTempFile(): Promise<{ filePath: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-big-temp-${Date.now()}.bin`);\n const fileSize = 20 * 1024 * 1024; // 20 MiB\n\n const fileContent = randomBytes(fileSize);\n\n await fs.appendFile(filePath, fileContent);\n\n return { filePath };\n}\n\n/** Creates a temporarly file we could use for uploading and downloading. */\nexport async function createTempFile(): Promise<{ filePath: string; fileContent: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-temp-${Date.now()}.txt`);\n\n const fileContent = \"Hello, world! \" + new Date().toISOString();\n await fs.writeFile(filePath, fileContent);\n\n return { filePath, fileContent };\n}\n\n/** Creates a template and RenderTemplate resources, gets all resources from outputs.\n * Throws a error if any of the outputs failed.\n */\nasync function runTemplate(\n client: PlClient,\n tpl: TemplateSpecAny,\n ephemeral: boolean,\n inputs: (tx: PlTransaction) => Pl.PlRecord,\n outputs: string[],\n): Promise<Record<string, FieldId>> {\n return await client.withWriteTx(\"TemplateRender\", async (tx) => {\n const preparedTemplate = await prepareTemplateSpec(tpl);\n const tplResource = loadTemplate(tx, preparedTemplate);\n\n const outputFields: Record<string, FieldRef> = createRenderTemplate(\n tx,\n tplResource,\n ephemeral,\n inputs(tx),\n outputs,\n );\n\n const outputsIds: Record<string, FieldId> = {};\n\n for (const output of outputs) {\n const fieldRef = field(client.clientRoot, output) as FieldId;\n tx.createField(fieldRef, \"Dynamic\", outputFields[output]);\n outputsIds[output] = await toGlobalFieldId(fieldRef);\n }\n\n await tx.commit();\n\n return outputsIds;\n });\n}\n\n/** Gets a resource from field's value or throws a error. */\nasync function getFieldValue(client: PlClient, fieldId: FieldId): Promise<ResourceData> {\n // We could also do polling with pl-tree, but it seemed like an overkill,\n // that's why we have a simple polling here.\n\n return await poll(client, async (tx) => {\n const field = await tx.tx.getField(fieldId);\n if (isNotNullSignedResourceId(field.error)) {\n const err = await tx.tx.getResourceData(field.error, true);\n throw new Error(`getFieldValue of \"${fieldId.fieldName}\" field failed: ${err.data}`);\n }\n\n if (isNullSignedResourceId(field.value)) {\n throw new ContinuePolling();\n }\n\n return await tx.tx.getResourceData(field.value, true);\n });\n}\n\nasync function deleteFields(client: PlClient, fieldIds: FieldId[]) {\n await client.withWriteTx(\"DeleteFields\", async (tx) => {\n for (const fieldId of fieldIds) {\n tx.resetField(fieldId);\n }\n await tx.commit();\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"template.js","names":["SdkTemplates"],"sources":["../../src/network_check/template.ts"],"sourcesContent":["import type { FieldId, FieldRef, PlClient, ResourceData } from \"@milaboratories/pl-client\";\nimport {\n type PlTransaction,\n ContinuePolling,\n field,\n isNotNullSignedResourceId,\n isNullSignedResourceId,\n Pl,\n poll,\n toGlobalFieldId,\n} from \"@milaboratories/pl-client\";\nimport { createRenderTemplate } from \"../mutator/template/render_template\";\nimport { Templates as SdkTemplates } from \"@platforma-sdk/workflow-tengo\";\nimport type { TemplateSpecAny } from \"../model/template_spec\";\nimport { loadTemplate, prepareTemplateSpec } from \"../mutator/template/template_loading\";\nimport type { ClientDownload, LsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n ImportFileHandleUploadData,\n isSignMatch,\n isUpload,\n uploadBlob,\n type ClientUpload,\n type LsEntryWithFileStats,\n} from \"@milaboratories/pl-drivers\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { notEmpty, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { ResourceInfo } from \"@milaboratories/pl-tree\";\nimport { text } from \"node:stream/consumers\";\nimport path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { randomBytes } from \"node:crypto\";\nimport type { StorageEntry } from \"@milaboratories/pl-model-common\";\n\nexport interface TemplateReport {\n status: \"ok\" | \"warn\" | \"failed\";\n message: string;\n}\n\n/** Uploads `hello-world` template and checks the output is correct. */\nexport async function uploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<TemplateReport> {\n try {\n const gotGreeting = await runUploadTemplate(logger, pl, name);\n if (gotGreeting !== `Hello, ${name}`) {\n return {\n status: \"failed\",\n message: `Template uploading failed: expected: ${name}, got: ${gotGreeting}`,\n };\n }\n\n return { status: \"ok\", message: `Template uploading succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Template uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadTemplate(\n logger: MiLogger,\n pl: PlClient,\n name: string,\n): Promise<string> {\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_template\"],\n true,\n (tx) => ({\n name: tx.createValue(Pl.JsonObject, JSON.stringify(name)),\n }),\n [\"greeting\"],\n );\n\n try {\n return JSON.parse(notEmpty((await getFieldValue(pl, outputs.greeting)).data?.toString()));\n } finally {\n if (outputs != undefined) {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n}\n\n/** Uploads a file to the backend and checks the output is a Blob resource. */\nexport async function uploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<TemplateReport> {\n try {\n const gotBlob = await runUploadFile(logger, signer, lsDriver, uploadClient, pl, filePath);\n\n if (gotBlob.type.name !== \"Blob\") {\n return { status: \"failed\", message: `File uploading failed: ${gotBlob.type.name}` };\n }\n\n return { status: \"ok\", message: `File uploading succeeded: ${gotBlob.type.name}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File uploading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runUploadFile(\n logger: MiLogger,\n signer: Signer,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n pl: PlClient,\n filePath: string,\n): Promise<ResourceInfo> {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.upload_blob\"],\n true,\n (tx) => ({\n file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)),\n }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, result.progress);\n\n if (isUpload(progress)) {\n const uploadData = ImportFileHandleUploadData.parse(\n JSON.parse(notEmpty(progress.data?.toString())),\n );\n const isUploadSignMatch = isSignMatch(signer, uploadData.localPath, uploadData.pathSignature);\n\n if (isUploadSignMatch) {\n await uploadBlob(logger, uploadClient, progress, uploadData, () => false, {\n nPartsWithThisUploadSpeed: 10,\n nPartsToIncreaseUpload: 10,\n currentSpeed: 10,\n maxSpeed: 10,\n });\n }\n }\n\n return await getFieldValue(pl, result.file);\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Uploads a file to the backend and then tries to download it back. */\nexport async function downloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n fileContent: string,\n): Promise<TemplateReport> {\n try {\n const gotFileContent = await runDownloadFile(\n logger,\n pl,\n lsDriver,\n uploadClient,\n downloadClient,\n filePath,\n );\n\n if (gotFileContent !== fileContent) {\n return {\n status: \"failed\",\n message: `File downloading failed: expected: ${fileContent}, got: ${gotFileContent}`,\n };\n }\n return { status: \"ok\", message: `File downloading succeeded: ${gotFileContent}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `File downloading failed: error occurred: ${e}` };\n }\n}\n\nexport async function runDownloadFile(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n uploadClient: ClientUpload,\n downloadClient: ClientDownload,\n filePath: string,\n) {\n const handle = await lsDriver.getLocalFileHandle(filePath);\n\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.download_blob\"],\n true,\n (tx) => ({ file: tx.createValue(Pl.JsonObject, JSON.stringify(handle)) }),\n [\"progress\", \"file\"],\n );\n\n try {\n const progress = await getFieldValue(pl, outputs.progress);\n\n await uploadBlob(\n logger,\n uploadClient,\n progress,\n ImportFileHandleUploadData.parse(JSON.parse(notEmpty(progress.data?.toString()))),\n () => false,\n {\n nPartsWithThisUploadSpeed: 1,\n nPartsToIncreaseUpload: 1,\n currentSpeed: 1,\n maxSpeed: 1,\n },\n );\n\n const fileInfo = await getFieldValue(pl, outputs.file);\n\n return await downloadClient.withBlobContent(\n fileInfo,\n {},\n {},\n async (content) => await text(content),\n );\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n}\n\n/** Runs Go's hello-world binary. */\nexport async function softwareCheck(pl: PlClient): Promise<TemplateReport> {\n try {\n const gotGreeting = await runSoftware(pl);\n\n if (gotGreeting !== \"Hello from go binary\\n\") {\n return { status: \"failed\", message: `Software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runSoftware(pl: PlClient): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world\"],\n true,\n (_: PlTransaction) => ({}),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Runs Python hello-world. */\nexport async function pythonSoftware(pl: PlClient, name: string): Promise<TemplateReport> {\n try {\n const gotGreeting = await runPythonSoftware(pl, name);\n\n if (gotGreeting !== `Hello, ${name}!\\n`) {\n return { status: \"failed\", message: `Python software check failed: got: ${gotGreeting}` };\n }\n return { status: \"ok\", message: `Python software check succeeded: ${gotGreeting}` };\n } catch (e: unknown) {\n return { status: \"failed\", message: `Python software check failed: error occurred: ${e}` };\n }\n}\n\nexport async function runPythonSoftware(pl: PlClient, name: string): Promise<string> {\n const result = await runTemplate(\n pl,\n SdkTemplates[\"check_network.run_hello_world_py\"],\n true,\n (tx) => ({ name: tx.createValue(Pl.JsonObject, JSON.stringify(name)) }),\n [\"greeting\"],\n );\n\n try {\n return notEmpty((await getFieldValue(pl, result.greeting)).data?.toString());\n } finally {\n await deleteFields(pl, Object.values(result));\n }\n}\n\n/** Tries to download a file from every storage. */\nexport async function downloadFromEveryStorage(\n logger: MiLogger,\n pl: PlClient,\n lsDriver: LsDriver,\n ops: {\n minLsRequests: number;\n bytesLimit: number;\n minFileSize: number;\n maxFileSize: number;\n nFilesToCheck: number;\n },\n): Promise<Record<string, TemplateReport>> {\n try {\n const storages = await lsDriver.getStorageList();\n const results: Record<string, TemplateReport> = {};\n\n for (const storage of storages) {\n const result = await chooseFile(\n lsDriver,\n storage,\n ops.nFilesToCheck,\n ops.minFileSize,\n ops.maxFileSize,\n ops.minLsRequests,\n );\n if (result.file === undefined) {\n results[storage.id] = {\n status: \"warn\",\n message:\n `No file between ${ops.minFileSize} and ${ops.maxFileSize} bytes ` +\n `found in storage ${storage.name}, checked ${result.nCheckedFiles} files, ` +\n `did ${result.nLsRequests} ls requests`,\n };\n continue;\n }\n\n logger.info(`Downloading file ${JSON.stringify(result)} from storage ${storage.name}`);\n const outputs = await runTemplate(\n pl,\n SdkTemplates[\"check_network.create_workdir_from_storage\"],\n true,\n (tx) => ({\n file: tx.createValue(\n Pl.JsonObject,\n JSON.stringify((result.file as { handle: string }).handle),\n ),\n }),\n [\"workdirTypeName\"],\n );\n\n try {\n const workdirTypeName = JSON.parse(\n Buffer.from((await getFieldValue(pl, outputs.workdirTypeName)).data!).toString(),\n ) as string;\n\n if (workdirTypeName?.startsWith(\"WorkingDirectory\")) {\n results[storage.id] = {\n status: \"ok\",\n message:\n `Workdir creation succeeded, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n } else {\n results[storage.id] = {\n status: \"failed\",\n message:\n `Workdir creation failed: ${workdirTypeName}, size of file: ${result.file?.size}, ` +\n `checked ${result.nCheckedFiles} files, did ${result.nLsRequests} ls requests`,\n };\n }\n } finally {\n await deleteFields(pl, Object.values(outputs));\n }\n }\n\n return results;\n } catch (e: unknown) {\n return {\n unknown: {\n status: \"failed\",\n message: `Download from every storage failed: error occurred: ${e}`,\n },\n };\n }\n}\n\n/** Chooses a random file from the storage in a size range.\n * If we couldn't find a normal-sized file, we'll return a small file to check at least something.\n */\nexport async function chooseFile(\n lsDriver: LsDriver,\n storage: StorageEntry,\n limit: number,\n minSize: number,\n maxSize: number,\n minLsRequests: number,\n): Promise<{\n file: LsEntryWithFileStats | undefined;\n nLsRequests: number;\n nCheckedFiles: number;\n}> {\n const files = listFilesSequence(lsDriver, storage, \"\", 0);\n\n // return small file in case we don't have many normal-sized files.\n // While we'll download only a small range of bytes from the file,\n // we don't want to return a big file in case the underlying S3 doesn't support range requests.\n let smallFile: LsEntryWithFileStats | undefined;\n let nCheckedFiles = 0;\n let maxNLsRequests = 0;\n\n for await (const { file, nLsRequests } of files) {\n maxNLsRequests = Math.max(maxNLsRequests, nLsRequests);\n\n if (nCheckedFiles >= limit && maxNLsRequests > minLsRequests) {\n // we reached a limit on both the number of files and the number of ls requests.\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n }\n nCheckedFiles++;\n if (minSize <= file.size && file.size <= maxSize) {\n return { file, nLsRequests: maxNLsRequests, nCheckedFiles };\n } else if (file.size < minSize) {\n smallFile = file;\n }\n }\n\n return { file: smallFile, nLsRequests: maxNLsRequests, nCheckedFiles };\n}\n\n/** Deep-first search for files in the storage. */\nexport async function* listFilesSequence(\n lsDriver: LsDriver,\n storage: StorageEntry,\n parent: string,\n nLsRequests: number,\n): AsyncGenerator<{ file: LsEntryWithFileStats; nLsRequests: number }, void, unknown> {\n nLsRequests++;\n const files = await lsDriver.listRemoteFilesWithFileStats(storage.handle, parent);\n\n for (const file of files.entries) {\n if (file.type === \"file\" && file.fullPath.startsWith(parent)) {\n yield {\n file,\n nLsRequests,\n };\n } else if (file.type === \"dir\") {\n for await (const nestedFile of listFilesSequence(\n lsDriver,\n storage,\n file.fullPath,\n nLsRequests,\n )) {\n nLsRequests = Math.max(nestedFile.nLsRequests, nLsRequests);\n yield nestedFile;\n }\n }\n }\n}\n\n/** Creates a big temporary file with random content. */\nexport async function createBigTempFile(): Promise<{ filePath: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-big-temp-${Date.now()}.bin`);\n const fileSize = 20 * 1024 * 1024; // 20 MiB\n\n const fileContent = randomBytes(fileSize);\n\n await fs.appendFile(filePath, fileContent);\n\n return { filePath };\n}\n\n/** Creates a temporarly file we could use for uploading and downloading. */\nexport async function createTempFile(): Promise<{ filePath: string; fileContent: string }> {\n const filePath = path.join(os.tmpdir(), `check-network-temp-${Date.now()}.txt`);\n\n const fileContent = \"Hello, world! \" + new Date().toISOString();\n await fs.writeFile(filePath, fileContent);\n\n return { filePath, fileContent };\n}\n\n/** Creates a template and RenderTemplate resources, gets all resources from outputs.\n * Throws a error if any of the outputs failed.\n */\nasync function runTemplate(\n client: PlClient,\n tpl: TemplateSpecAny,\n ephemeral: boolean,\n inputs: (tx: PlTransaction) => Pl.PlRecord,\n outputs: string[],\n): Promise<Record<string, FieldId>> {\n return await client.withWriteTx(\"TemplateRender\", async (tx) => {\n const preparedTemplate = await prepareTemplateSpec(tpl);\n const tplResource = loadTemplate(tx, preparedTemplate);\n\n const outputFields: Record<string, FieldRef> = createRenderTemplate(\n tx,\n tplResource,\n ephemeral,\n inputs(tx),\n outputs,\n );\n\n const outputsIds: Record<string, FieldId> = {};\n\n for (const output of outputs) {\n const fieldRef = field(client.clientRoot, output) as FieldId;\n tx.createField(fieldRef, \"Dynamic\", outputFields[output]);\n outputsIds[output] = await toGlobalFieldId(fieldRef);\n }\n\n await tx.commit();\n\n return outputsIds;\n });\n}\n\n/** Gets a resource from field's value or throws a error. */\nasync function getFieldValue(client: PlClient, fieldId: FieldId): Promise<ResourceData> {\n // We could also do polling with pl-tree, but it seemed like an overkill,\n // that's why we have a simple polling here.\n\n return await poll(client, async (tx) => {\n const field = await tx.tx.getField(fieldId);\n if (isNotNullSignedResourceId(field.error)) {\n const err = await tx.tx.getResourceData(field.error, true);\n throw new Error(`getFieldValue of \"${fieldId.fieldName}\" field failed: ${err.data}`);\n }\n\n if (isNullSignedResourceId(field.value)) {\n throw new ContinuePolling();\n }\n\n return await tx.tx.getResourceData(field.value, true);\n });\n}\n\nasync function deleteFields(client: PlClient, fieldIds: FieldId[]) {\n await client.withWriteTx(\"DeleteFields\", async (tx) => {\n for (const fieldId of fieldIds) {\n tx.resetField(fieldId);\n }\n await tx.commit();\n });\n}\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ let _milaboratories_pl_client = require("@milaboratories/pl-client");
4
4
  let _milaboratories_pl_tree = require("@milaboratories/pl-tree");
5
5
  let node_crypto = require("node:crypto");
6
6
  let canonicalize = require("canonicalize");
7
- canonicalize = require_runtime.__toESM(canonicalize);
7
+ canonicalize = require_runtime.__toESM(canonicalize, 1);
8
8
  let _milaboratories_pl_drivers = require("@milaboratories/pl-drivers");
9
9
  //#region src/pool/data.ts
10
10
  /**
@@ -21,6 +21,8 @@ let _milaboratories_pl_drivers = require("@milaboratories/pl-drivers");
21
21
  * download driver with the snapshot directly — independent of any specific tree.
22
22
  */
23
23
  var BlobResourceRef = class {
24
+ resourceInfo;
25
+ onDemandSnapshot;
24
26
  constructor(resourceInfo, onDemandSnapshot) {
25
27
  this.resourceInfo = resourceInfo;
26
28
  this.onDemandSnapshot = onDemandSnapshot;
@@ -245,6 +247,15 @@ function deriveLocalPObjectId(resolvePath, outputName) {
245
247
  });
246
248
  }
247
249
  //#endregion
250
+ exports.BlobResourceRef = BlobResourceRef;
251
+ exports.PColumnDataBinaryPartitioned = PColumnDataBinaryPartitioned;
252
+ exports.PColumnDataBinarySuperPartitioned = PColumnDataBinarySuperPartitioned;
253
+ exports.PColumnDataJson = PColumnDataJson;
254
+ exports.PColumnDataJsonPartitioned = PColumnDataJsonPartitioned;
255
+ exports.PColumnDataJsonSuperPartitioned = PColumnDataJsonSuperPartitioned;
256
+ exports.PColumnDataParquetPartitioned = PColumnDataParquetPartitioned;
257
+ exports.PColumnDataParquetSuperPartitioned = PColumnDataParquetSuperPartitioned;
258
+ exports.ParquetChunkResourceType = ParquetChunkResourceType;
248
259
  exports.deriveGlobalPObjectId = deriveGlobalPObjectId;
249
260
  exports.deriveLegacyPObjectId = deriveLegacyPObjectId;
250
261
  exports.deriveLocalPObjectId = deriveLocalPObjectId;
@@ -1 +1 @@
1
- {"version":3,"file":"data.cjs","names":["OnDemandBlobResourceSnapshot","PFrameDriverError"],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport { makeResourceSnapshot, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n anyResourceIdToBigint,\n isNullSignedResourceId,\n resourceIdToString,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n type SignedResourceId,\n type ResourceType,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { OnDemandBlobResourceSnapshot } from \"@milaboratories/pl-drivers\";\n\n/**\n * Tree-independent reference to a blob resource used by the PFrame data flow.\n *\n * The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;\n * resolution then went back through the originating tree, so when that tree dropped\n * the resource (e.g., a project recalculated with new settings), shared pool entries\n * — held alive by other projects — would start failing with \"resource not found in\n * the tree\" even though the underlying blob was still valid backend-side.\n *\n * BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed\n * to resolve. The pools then key by rid (`resourceInfo.id`) and call into the\n * download driver with the snapshot directly — independent of any specific tree.\n */\nexport class BlobResourceRef {\n constructor(\n public readonly resourceInfo: { readonly id: SignedResourceId; readonly type: ResourceType },\n /** Present only for on-demand (remote) blobs; needed for size and signed handle. */\n public readonly onDemandSnapshot: OnDemandBlobResourceSnapshot | undefined,\n ) {}\n\n toJSON(): string {\n return resourceIdToString(this.resourceInfo.id);\n }\n}\n\nexport function makeLocalBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(accessor.resourceInfo, undefined);\n}\n\nfunction makeRemoteBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(\n accessor.resourceInfo,\n makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot),\n );\n}\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): undefined | PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) return undefined;\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [\n field,\n makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true })),\n ]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, BlobResourceRef> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = makeLocalBlobRef(\n superPart.traverse({ field: key, errorIfFieldNotSet: true }),\n );\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<BlobResourceRef> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = makeRemoteBlobRef(\n resource.traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true }),\n );\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n const rid = !isNullSignedResourceId(data.originalId) ? data.originalId : data.id;\n hash.update(String(anyResourceIdToBigint(rid)));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"data.cjs","names":["OnDemandBlobResourceSnapshot","PFrameDriverError"],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport { makeResourceSnapshot, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n anyResourceIdToBigint,\n isNullSignedResourceId,\n resourceIdToString,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n type SignedResourceId,\n type ResourceType,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { OnDemandBlobResourceSnapshot } from \"@milaboratories/pl-drivers\";\n\n/**\n * Tree-independent reference to a blob resource used by the PFrame data flow.\n *\n * The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;\n * resolution then went back through the originating tree, so when that tree dropped\n * the resource (e.g., a project recalculated with new settings), shared pool entries\n * — held alive by other projects — would start failing with \"resource not found in\n * the tree\" even though the underlying blob was still valid backend-side.\n *\n * BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed\n * to resolve. The pools then key by rid (`resourceInfo.id`) and call into the\n * download driver with the snapshot directly — independent of any specific tree.\n */\nexport class BlobResourceRef {\n constructor(\n public readonly resourceInfo: { readonly id: SignedResourceId; readonly type: ResourceType },\n /** Present only for on-demand (remote) blobs; needed for size and signed handle. */\n public readonly onDemandSnapshot: OnDemandBlobResourceSnapshot | undefined,\n ) {}\n\n toJSON(): string {\n return resourceIdToString(this.resourceInfo.id);\n }\n}\n\nexport function makeLocalBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(accessor.resourceInfo, undefined);\n}\n\nfunction makeRemoteBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(\n accessor.resourceInfo,\n makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot),\n );\n}\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): undefined | PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) return undefined;\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [\n field,\n makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true })),\n ]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, BlobResourceRef> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = makeLocalBlobRef(\n superPart.traverse({ field: key, errorIfFieldNotSet: true }),\n );\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<BlobResourceRef> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = makeRemoteBlobRef(\n resource.traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true }),\n );\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n const rid = !isNullSignedResourceId(data.originalId) ? data.originalId : data.id;\n hash.update(String(anyResourceIdToBigint(rid)));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,kBAAb,MAA6B;CAET;CAEA;CAHlB,YACE,cAEA,kBACA;EAHgB,KAAA,eAAA;EAEA,KAAA,mBAAA;CACf;CAEH,SAAiB;EACf,QAAA,GAAA,0BAAA,mBAAA,CAA0B,KAAK,aAAa,EAAE;CAChD;AACF;AAEA,SAAgB,iBAAiB,UAA+C;CAC9E,OAAO,IAAI,gBAAgB,SAAS,cAAc,KAAA,CAAS;AAC7D;AAEA,SAAS,kBAAkB,UAA+C;CACxE,OAAO,IAAI,gBACT,SAAS,eAAA,GAAA,wBAAA,qBAAA,CACY,UAAUA,2BAAAA,4BAA4B,CAC7D;AACF;AAEA,MAAa,8BAAA,GAAA,0BAAA,aAAA,CAA0C,+BAA+B,GAAG;AACzF,MAAa,mCAAA,GAAA,0BAAA,aAAA,CACX,2CACA,GACF;AACA,MAAa,gCAAA,GAAA,0BAAA,aAAA,CAA4C,iCAAiC,GAAG;AAC7F,MAAa,qCAAA,GAAA,0BAAA,aAAA,CACX,6CACA,GACF;AACA,MAAa,iCAAA,GAAA,0BAAA,aAAA,CAA6C,kCAAkC,GAAG;AAC/F,MAAa,sCAAA,GAAA,0BAAA,aAAA,CACX,8CACA,GACF;AACA,MAAa,mBAAA,GAAA,0BAAA,aAAA,CAA+B,oBAAoB,GAAG;AAEnE,MAAa,4BAAA,GAAA,0BAAA,aAAA,CAAwC,gBAAgB,GAAG;AAgBxE,MAAM,oCAAoC;AAC1C,MAAM,qCAAqC;AAE3C,SAAgB,sBACd,MACsD;CACtD,IAAI,CAAC,KAAK,kBAAkB,GAAG,OAAO,KAAA;CAEtC,MAAM,eAAe,KAAK,cAAc;CACxC,IAAI,iBAAiB,KAAA,GACnB,MAAM,IAAIC,qBAAAA,kBAAkB,kDAAkD;CAEhF,KAAA,GAAA,0BAAA,mBAAA,CAAuB,KAAK,cAAc,eAAe,GAAG;EAC1D,MAAM,cAAc;EAEpB,OAAO;GACL,MAAM;GACN,WAAW,YAAY;GACvB,MAAM,YAAY;EACpB;CACF,OAAO,KAAA,GAAA,0BAAA,mBAAA,CAAuB,KAAK,cAAc,0BAA0B,GAAG;EAC5E,MAAM,OAAO;EAEb,MAAM,QAAQ,OAAO,YACnB,KACG,gBAAgB,CAAC,CACjB,KAAK,UAAU,CACd,OACA,iBAAiB,KAAK,SAAS;GAAE;GAAO,oBAAoB;EAAK,CAAC,CAAC,CACrE,CAAC,CACL;EAEA,OAAO;GACL,MAAM;GACN,oBAAoB,KAAK;GACzB;EACF;CACF,OAAO,KAAA,GAAA,0BAAA,mBAAA,CAAuB,KAAK,cAAc,+BAA+B,GAAG;EACjF,MAAM,OAAO;EAEb,MAAM,QAAyC,CAAC;EAChD,KAAK,MAAM,YAAY,KAAK,gBAAgB,GAAG;GAC7C,MAAM,YAAY,KAAK,SAAS;IAAE,OAAO;IAAU,oBAAoB;GAAK,CAAC;GAC7E,MAAM,OAAO,UAAU,gBAAgB;GACvC,IAAI,SAAS,KAAA,GACX,MAAM,IAAIA,qBAAAA,kBAAkB,mCAAmC,UAAU;GAE3E,KAAK,MAAM,OAAO,MAAM;IACtB,MAAM,UAAU,KAAK,UAAU,CAC7B,GAAI,KAAK,MAAM,QAAQ,GACvB,GAAI,KAAK,MAAM,GAAG,CACpB,CAAC;IACD,MAAM,WAAW,iBACf,UAAU,SAAS;KAAE,OAAO;KAAK,oBAAoB;IAAK,CAAC,CAC7D;GACF;EACF;EAEA,OAAO;GACL,MAAM;GACN,oBAAoB,KAAK,0BAA0B,KAAK;GACxD;EACF;CACF,OAAO,KAAA,GAAA,0BAAA,mBAAA,CAAuB,KAAK,cAAc,4BAA4B,GAAG;EAC9E,MAAM,OAAO;EAEb,MAAM,QAAyE,CAAC;EAGhF,KAAK,MAAM,SAAS,KAAK,gBAAgB,GACvC,IAAI,MAAM,SAAS,iCAAiC,GAAG;GACrD,MAAM,UAAU,MAAM,MAAM,GAAG,EAAyC;GACxE,IAAI,OAAO,MAAM;GACjB,IAAI,SAAS,KAAA,GAAW;IACtB,OAAO,CAAC;IACR,MAAM,WAAW;GACnB;GACA,KAAK,QAAQ,iBAAiB,KAAK,SAAS;IAAE;IAAO,oBAAoB;GAAK,CAAC,CAAC;EAClF,OAAO,IAAI,MAAM,SAAS,kCAAkC,GAAG;GAC7D,MAAM,UAAU,MAAM,MAAM,GAAG,EAA0C;GACzE,IAAI,OAAO,MAAM;GACjB,IAAI,SAAS,KAAA,GAAW;IACtB,OAAO,CAAC;IACR,MAAM,WAAW;GACnB;GACA,KAAK,SAAS,iBAAiB,KAAK,SAAS;IAAE;IAAO,oBAAoB;GAAK,CAAC,CAAC;EACnF,OAAO,MAAM,IAAIA,qBAAAA,kBAAkB,iCAAiC,OAAO;EAI7E,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,KAAK,GAAG;GAC/C,IAAI,KAAK,UAAU,KAAA,GAAW,MAAM,IAAIA,qBAAAA,kBAAkB,qBAAqB,KAAK;GACpF,IAAI,KAAK,WAAW,KAAA,GAAW,MAAM,IAAIA,qBAAAA,kBAAkB,sBAAsB,KAAK;EACxF;EAEA,OAAO;GACL,MAAM;GACN,oBAAoB,KAAK;GAClB;EACT;CACF,OAAO,KAAA,GAAA,0BAAA,mBAAA,CAAuB,KAAK,cAAc,iCAAiC,GAAG;EACnF,MAAM,OAAO;EAEb,MAAM,QAAyE,CAAC;EAChF,KAAK,MAAM,YAAY,KAAK,gBAAgB,GAAG;GAC7C,MAAM,YAAY,KAAK,SAAS;IAAE,OAAO;IAAU,oBAAoB;GAAK,CAAC;GAC7E,MAAM,OAAO,UAAU,gBAAgB;GACvC,IAAI,SAAS,KAAA,GACX,MAAM,IAAIA,qBAAAA,kBAAkB,mCAAmC,UAAU;GAE3E,KAAK,MAAM,SAAS,MAClB,IAAI,MAAM,SAAS,iCAAiC,GAAG;IACrD,MAAM,MAAM,MAAM,MAAM,GAAG,EAAyC;IAEpE,MAAM,UAAU,KAAK,UAAU,CAC7B,GAAI,KAAK,MAAM,QAAQ,GACvB,GAAI,KAAK,MAAM,GAAG,CACpB,CAAC;IACD,IAAI,OAAO,MAAM;IACjB,IAAI,SAAS,KAAA,GAAW;KACtB,OAAO,CAAC;KACR,MAAM,WAAW;IACnB;IACA,MAAM,QAAQ,CAAC,QAAQ,iBACrB,UAAU,SAAS;KAAE;KAAO,oBAAoB;IAAK,CAAC,CACxD;GACF,OAAO,IAAI,MAAM,SAAS,kCAAkC,GAAG;IAC7D,MAAM,MAAM,MAAM,MAAM,GAAG,EAA0C;IAErE,MAAM,UAAU,KAAK,UAAU,CAC7B,GAAI,KAAK,MAAM,QAAQ,GACvB,GAAI,KAAK,MAAM,GAAG,CACpB,CAAC;IACD,IAAI,OAAO,MAAM;IACjB,IAAI,SAAS,KAAA,GAAW;KACtB,OAAO,CAAC;KACR,MAAM,WAAW;IACnB;IACA,MAAM,QAAQ,CAAC,SAAS,iBACtB,UAAU,SAAS;KAAE;KAAO,oBAAoB;IAAK,CAAC,CACxD;GACF,OAAO,MAAM,IAAIA,qBAAAA,kBAAkB,iCAAiC,OAAO;EAE/E;EAEA,OAAO;GACL,MAAM;GACN,oBAAoB,KAAK,0BAA0B,KAAK;GACjD;EACT;CACF,OAAO,KAAA,GAAA,0BAAA,mBAAA,CAAuB,KAAK,cAAc,6BAA6B,GAAG;EAC/E,MAAM,OAAO;EAEb,MAAM,QAAuD,CAAC;EAC9D,KAAK,MAAM,OAAO,KAAK,gBAAgB,GAOrC,MAAM,OAAO,6BANI,KAAK,SAAS;GAC7B,OAAO;GACP,iBAAiB;GACjB,oBAAoB;EACtB,CAEiD,CAAC;EAGpD,OAAO;GACL,MAAM;GACN,oBAAoB,KAAK;GACzB;EACF;CACF,OAAO,KAAA,GAAA,0BAAA,mBAAA,CAAuB,KAAK,cAAc,kCAAkC,GAAG;EACpF,MAAM,OAAO;EAEb,MAAM,QAAuD,CAAC;EAC9D,KAAK,MAAM,YAAY,KAAK,gBAAgB,GAAG;GAE7C,MAAM,OADY,KAAK,SAAS;IAAE,OAAO;IAAU,oBAAoB;GAAK,CACvD,CAAC,CAAC,gBAAgB;GACvC,IAAI,SAAS,KAAA,GACX,MAAM,IAAIA,qBAAAA,kBAAkB,mCAAmC,UAAU;GAE3E,KAAK,MAAM,OAAO,MAAM;IACtB,MAAM,WAAW,KAAK,SAAS;KAAE,OAAO;KAAK,oBAAoB;IAAK,CAAC;IAEvE,MAAM,UAAU,KAAK,UAAU,CAC7B,GAAI,KAAK,MAAM,QAAQ,GACvB,GAAI,KAAK,MAAM,GAAG,CACpB,CAAC;IACD,MAAM,WAAW,6BAA6B,QAAQ;GACxD;EACF;EAEA,OAAO;GACL,MAAM;GACN,oBAAoB,KAAK,0BAA0B,KAAK;GACxD;EACF;CACF;CAEA,MAAM,IAAIA,qBAAAA,kBACR,+BAAA,GAAA,0BAAA,qBAAA,CAAmD,KAAK,YAAY,GACtE;AACF;AAEA,SAAgB,6BACd,UAC+B;CAC/B,IAAI,EAAA,GAAA,0BAAA,mBAAA,CAAoB,SAAS,cAAc,wBAAwB,GACrE,MAAM,IAAIA,qBAAAA,kBACR,2BAAA,GAAA,0BAAA,qBAAA,CAA+C,SAAS,YAAY,EAAE,eAAA,GAAA,0BAAA,qBAAA,CAClC,wBAAwB,GAC9D;CAGF,MAAM,OAAO,kBACX,SAAS,SAAS;EAAE,OAAO;EAAQ,iBAAiB;EAAW,oBAAoB;CAAK,CAAC,CAC3F;CACA,MAAM,WAAW,SAAS,cAAc;CACxC,MAAM,UAAU,SACb,SAAS;EAAE,OAAO;EAAW,iBAAiB;EAAW,oBAAoB;CAAK,CAAC,CAAC,CACpF,cAAc;CAEjB,OAAO;EACL,MAAM;EACN,GAAG;EACH,GAAG;CACL;AACF;AAEA,SAAgB,sBAAsB,MAAmB,MAAqC;CAC5F,MAAM,QAAA,GAAA,YAAA,WAAA,CAAkB,QAAQ;CAChC,KAAK,QAAA,GAAA,aAAA,QAAA,CAAoB,IAAI,CAAE;CAC/B,MAAM,MAAM,EAAA,GAAA,0BAAA,uBAAA,CAAwB,KAAK,UAAU,IAAI,KAAK,aAAa,KAAK;CAC9E,KAAK,OAAO,QAAA,GAAA,0BAAA,sBAAA,CAA6B,GAAG,CAAC,CAAC;CAC9C,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,KAAK;AACrC;AAEA,SAAgB,sBAAsB,SAAiB,YAA+B;CACpF,QAAA,GAAA,aAAA,QAAA,CAAoB;EAAE,SAAS;EAAM;EAAS,MAAM;CAAW,CAAiB;AAClF;AAEA,SAAgB,qBAAqB,aAAuB,YAA+B;CACzF,QAAA,GAAA,aAAA,QAAA,CAAoB;EAAE;EAAa,MAAM;CAAW,CAAC;AACvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","names":[],"sources":["../../src/pool/data.ts"],"mappings":";;;;;;;iBA4UgB,qBAAA,CAAsB,OAAA,UAAiB,UAAA,WAAqB,SAAA;AAAA,iBAI5D,oBAAA,CAAqB,WAAA,YAAuB,UAAA,WAAqB,SAAA"}
1
+ {"version":3,"file":"data.d.ts","names":[],"sources":["../../src/pool/data.ts"],"mappings":";;;;;;;iBA4UgB,qBAAA,CAAsB,OAAA,UAAiB,UAAA,WAAqB,SAAS;AAAA,iBAIrE,oBAAA,CAAqB,WAAA,YAAuB,UAAA,WAAqB,SAAS"}
package/dist/pool/data.js CHANGED
@@ -19,6 +19,8 @@ import { OnDemandBlobResourceSnapshot } from "@milaboratories/pl-drivers";
19
19
  * download driver with the snapshot directly — independent of any specific tree.
20
20
  */
21
21
  var BlobResourceRef = class {
22
+ resourceInfo;
23
+ onDemandSnapshot;
22
24
  constructor(resourceInfo, onDemandSnapshot) {
23
25
  this.resourceInfo = resourceInfo;
24
26
  this.onDemandSnapshot = onDemandSnapshot;
@@ -243,6 +245,6 @@ function deriveLocalPObjectId(resolvePath, outputName) {
243
245
  });
244
246
  }
245
247
  //#endregion
246
- export { deriveGlobalPObjectId, deriveLegacyPObjectId, deriveLocalPObjectId, makeLocalBlobRef, parseDataInfoResource, traverseParquetChunkResource };
248
+ export { BlobResourceRef, PColumnDataBinaryPartitioned, PColumnDataBinarySuperPartitioned, PColumnDataJson, PColumnDataJsonPartitioned, PColumnDataJsonSuperPartitioned, PColumnDataParquetPartitioned, PColumnDataParquetSuperPartitioned, ParquetChunkResourceType, deriveGlobalPObjectId, deriveLegacyPObjectId, deriveLocalPObjectId, makeLocalBlobRef, parseDataInfoResource, traverseParquetChunkResource };
247
249
 
248
250
  //# sourceMappingURL=data.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","names":[],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport { makeResourceSnapshot, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n anyResourceIdToBigint,\n isNullSignedResourceId,\n resourceIdToString,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n type SignedResourceId,\n type ResourceType,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { OnDemandBlobResourceSnapshot } from \"@milaboratories/pl-drivers\";\n\n/**\n * Tree-independent reference to a blob resource used by the PFrame data flow.\n *\n * The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;\n * resolution then went back through the originating tree, so when that tree dropped\n * the resource (e.g., a project recalculated with new settings), shared pool entries\n * — held alive by other projects — would start failing with \"resource not found in\n * the tree\" even though the underlying blob was still valid backend-side.\n *\n * BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed\n * to resolve. The pools then key by rid (`resourceInfo.id`) and call into the\n * download driver with the snapshot directly — independent of any specific tree.\n */\nexport class BlobResourceRef {\n constructor(\n public readonly resourceInfo: { readonly id: SignedResourceId; readonly type: ResourceType },\n /** Present only for on-demand (remote) blobs; needed for size and signed handle. */\n public readonly onDemandSnapshot: OnDemandBlobResourceSnapshot | undefined,\n ) {}\n\n toJSON(): string {\n return resourceIdToString(this.resourceInfo.id);\n }\n}\n\nexport function makeLocalBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(accessor.resourceInfo, undefined);\n}\n\nfunction makeRemoteBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(\n accessor.resourceInfo,\n makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot),\n );\n}\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): undefined | PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) return undefined;\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [\n field,\n makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true })),\n ]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, BlobResourceRef> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = makeLocalBlobRef(\n superPart.traverse({ field: key, errorIfFieldNotSet: true }),\n );\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<BlobResourceRef> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = makeRemoteBlobRef(\n resource.traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true }),\n );\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n const rid = !isNullSignedResourceId(data.originalId) ? data.originalId : data.id;\n hash.update(String(anyResourceIdToBigint(rid)));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"data.js","names":[],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport { makeResourceSnapshot, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n anyResourceIdToBigint,\n isNullSignedResourceId,\n resourceIdToString,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n type SignedResourceId,\n type ResourceType,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { OnDemandBlobResourceSnapshot } from \"@milaboratories/pl-drivers\";\n\n/**\n * Tree-independent reference to a blob resource used by the PFrame data flow.\n *\n * The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;\n * resolution then went back through the originating tree, so when that tree dropped\n * the resource (e.g., a project recalculated with new settings), shared pool entries\n * — held alive by other projects — would start failing with \"resource not found in\n * the tree\" even though the underlying blob was still valid backend-side.\n *\n * BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed\n * to resolve. The pools then key by rid (`resourceInfo.id`) and call into the\n * download driver with the snapshot directly — independent of any specific tree.\n */\nexport class BlobResourceRef {\n constructor(\n public readonly resourceInfo: { readonly id: SignedResourceId; readonly type: ResourceType },\n /** Present only for on-demand (remote) blobs; needed for size and signed handle. */\n public readonly onDemandSnapshot: OnDemandBlobResourceSnapshot | undefined,\n ) {}\n\n toJSON(): string {\n return resourceIdToString(this.resourceInfo.id);\n }\n}\n\nexport function makeLocalBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(accessor.resourceInfo, undefined);\n}\n\nfunction makeRemoteBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(\n accessor.resourceInfo,\n makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot),\n );\n}\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): undefined | PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) return undefined;\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [\n field,\n makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true })),\n ]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, BlobResourceRef> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = makeLocalBlobRef(\n superPart.traverse({ field: key, errorIfFieldNotSet: true }),\n );\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<BlobResourceRef> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = makeRemoteBlobRef(\n resource.traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true }),\n );\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n const rid = !isNullSignedResourceId(data.originalId) ? data.originalId : data.id;\n hash.update(String(anyResourceIdToBigint(rid)));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":"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"}