@milaboratories/pl-middle-layer 1.60.4 → 1.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/block_registry/registry.cjs +7 -1
- package/dist/block_registry/registry.cjs.map +1 -1
- package/dist/block_registry/registry.d.ts.map +1 -1
- package/dist/block_registry/registry.js +7 -1
- package/dist/block_registry/registry.js.map +1 -1
- package/dist/middle_layer/middle_layer.cjs +9 -0
- package/dist/middle_layer/middle_layer.cjs.map +1 -1
- package/dist/middle_layer/middle_layer.d.ts +7 -0
- package/dist/middle_layer/middle_layer.d.ts.map +1 -1
- package/dist/middle_layer/middle_layer.js +9 -0
- package/dist/middle_layer/middle_layer.js.map +1 -1
- package/dist/middle_layer/project.cjs +17 -0
- package/dist/middle_layer/project.cjs.map +1 -1
- package/dist/middle_layer/project.d.ts.map +1 -1
- package/dist/middle_layer/project.js +17 -0
- package/dist/middle_layer/project.js.map +1 -1
- package/dist/model/block_pack_spec.cjs.map +1 -1
- package/dist/model/block_pack_spec.d.ts +6 -0
- package/dist/model/block_pack_spec.d.ts.map +1 -1
- package/dist/model/block_pack_spec.js.map +1 -1
- package/dist/mutator/block-pack/block_pack.cjs +5 -3
- package/dist/mutator/block-pack/block_pack.cjs.map +1 -1
- package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
- package/dist/mutator/block-pack/block_pack.js +5 -3
- package/dist/mutator/block-pack/block_pack.js.map +1 -1
- package/dist/mutator/block-pack/required_capabilities.cjs +44 -0
- package/dist/mutator/block-pack/required_capabilities.cjs.map +1 -0
- package/dist/mutator/block-pack/required_capabilities.js +42 -0
- package/dist/mutator/block-pack/required_capabilities.js.map +1 -0
- package/dist/mutator/project.cjs +1 -1
- package/dist/mutator/project.js +1 -1
- package/dist/pool/data.cjs +1 -1
- package/dist/pool/data.cjs.map +1 -1
- package/dist/pool/data.js +1 -1
- package/dist/pool/data.js.map +1 -1
- package/dist/pool/driver.cjs +2 -1
- package/dist/pool/driver.cjs.map +1 -1
- package/dist/pool/driver.js +2 -1
- package/dist/pool/driver.js.map +1 -1
- package/package.json +12 -12
- package/src/block_registry/registry.ts +21 -1
- package/src/middle_layer/middle_layer.ts +10 -0
- package/src/middle_layer/project.ts +27 -0
- package/src/model/block_pack_spec.ts +6 -0
- package/src/mutator/block-pack/block_pack.ts +7 -2
- package/src/mutator/block-pack/required_capabilities.ts +44 -0
- package/src/pool/data.ts +2 -2
- package/src/pool/driver.ts +9 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_pack_spec.js","names":[],"sources":["../../src/model/block_pack_spec.ts"],"sourcesContent":["import type { CachedTemplate, ExplicitTemplate, PreparedTemplate } from \"./template_spec\";\nimport type { ResourceType } from \"@milaboratories/pl-client\";\nimport type { BlockConfigContainer } from \"@platforma-sdk/model\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\n\nexport type FrontendSpec = FrontendFromUrl | FrontendFromFolder;\n\nexport interface FrontendFromUrlData {\n url: string;\n}\n\nexport const FrontendFromUrlResourceType: ResourceType = { name: \"Frontend/FromUrl\", version: \"1\" };\n\n/** Directs user of the block pack to download the contents from the URL\n * outside the pl infrastructure. */\nexport interface FrontendFromUrl extends FrontendFromUrlData {\n type: \"url\";\n}\n\nexport interface FrontendFromFolderData {\n path: string;\n /** HMAC signature of the path using local secret encoded as hex. */\n signature: string;\n}\n\nexport const FrontendFromFolderResourceType: ResourceType = {\n name: \"Frontend/FromFolder\",\n version: \"1\",\n};\n\n/** Directs user of the block pack to load frontend from specific local\n * folder. Signature allows to confirm that this is the same client who\n * added the resource. */\nexport interface FrontendFromFolder extends FrontendFromFolderData {\n type: \"local\";\n}\n\n/** Direct instructions to create block-pack from client. Currently, this\n * is the only block-pack spec that can be directly materialized. */\nexport interface BlockPackExplicit {\n type: \"explicit\";\n template: ExplicitTemplate;\n config: BlockConfigContainer;\n frontend: FrontendSpec;\n source: BlockPackSpec;\n}\n\n/** Block-pack spec that can be materialized in pl. */\nexport type BlockPackSpecPrepared = {\n type: \"prepared\";\n template: PreparedTemplate | CachedTemplate;\n config: BlockConfigContainer;\n frontend: FrontendSpec;\n source: BlockPackSpec;\n};\n\n/** All block-pack specs. */\nexport type BlockPackSpecAny = BlockPackSpecPrepared | BlockPackExplicit | BlockPackSpec;\n"],"mappings":";AAWA,MAAa,8BAA4C;CAAE,MAAM;CAAoB,SAAS;CAAK;AAcnG,MAAa,iCAA+C;CAC1D,MAAM;CACN,SAAS;CACV"}
|
|
1
|
+
{"version":3,"file":"block_pack_spec.js","names":[],"sources":["../../src/model/block_pack_spec.ts"],"sourcesContent":["import type { CachedTemplate, ExplicitTemplate, PreparedTemplate } from \"./template_spec\";\nimport type { ResourceType } from \"@milaboratories/pl-client\";\nimport type { BlockConfigContainer } from \"@platforma-sdk/model\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\n\nexport type FrontendSpec = FrontendFromUrl | FrontendFromFolder;\n\nexport interface FrontendFromUrlData {\n url: string;\n}\n\nexport const FrontendFromUrlResourceType: ResourceType = { name: \"Frontend/FromUrl\", version: \"1\" };\n\n/** Directs user of the block pack to download the contents from the URL\n * outside the pl infrastructure. */\nexport interface FrontendFromUrl extends FrontendFromUrlData {\n type: \"url\";\n}\n\nexport interface FrontendFromFolderData {\n path: string;\n /** HMAC signature of the path using local secret encoded as hex. */\n signature: string;\n}\n\nexport const FrontendFromFolderResourceType: ResourceType = {\n name: \"Frontend/FromFolder\",\n version: \"1\",\n};\n\n/** Directs user of the block pack to load frontend from specific local\n * folder. Signature allows to confirm that this is the same client who\n * added the resource. */\nexport interface FrontendFromFolder extends FrontendFromFolderData {\n type: \"local\";\n}\n\n/** Direct instructions to create block-pack from client. Currently, this\n * is the only block-pack spec that can be directly materialized. */\nexport interface BlockPackExplicit {\n type: \"explicit\";\n template: ExplicitTemplate;\n config: BlockConfigContainer;\n frontend: FrontendSpec;\n source: BlockPackSpec;\n}\n\n/** Block-pack spec that can be materialized in pl. */\nexport type BlockPackSpecPrepared = {\n type: \"prepared\";\n template: PreparedTemplate | CachedTemplate;\n config: BlockConfigContainer;\n frontend: FrontendSpec;\n source: BlockPackSpec;\n /** Backend-side runtime capabilities the block requires at install time.\n * Derived from the parsed workflow template by\n * `requiredCapabilitiesFromTemplate` during `BlockPackPreparer.prepare`.\n * `Project.addBlock` matches this list against `pl.serverInfo.capabilities`\n * and refuses to install when anything is missing. */\n requiredCapabilities?: string[];\n};\n\n/** All block-pack specs. */\nexport type BlockPackSpecAny = BlockPackSpecPrepared | BlockPackExplicit | BlockPackSpec;\n"],"mappings":";AAWA,MAAa,8BAA4C;CAAE,MAAM;CAAoB,SAAS;CAAK;AAcnG,MAAa,iCAA+C;CAC1D,MAAM;CACN,SAAS;CACV"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
const require_index = require("../../dev_env/index.cjs");
|
|
3
|
+
const require_required_capabilities = require("./required_capabilities.cjs");
|
|
3
4
|
const require_registry = require("../../block_registry/registry.cjs");
|
|
4
5
|
require("../../block_registry/index.cjs");
|
|
5
6
|
const require_template_loading = require("../template/template_loading.cjs");
|
|
@@ -101,14 +102,15 @@ var BlockPackPreparer = class {
|
|
|
101
102
|
if (cached) return cached;
|
|
102
103
|
}
|
|
103
104
|
const explicit = await this.prepareWithoutUnpacking(spec);
|
|
104
|
-
const
|
|
105
|
+
const parsed = await _usingCtx$1.a(new require_WorkerManager.WorkerManager()).process("parseTemplate", explicit.template.content);
|
|
105
106
|
const result = {
|
|
106
107
|
...explicit,
|
|
107
108
|
type: "prepared",
|
|
108
109
|
template: {
|
|
109
110
|
type: "prepared",
|
|
110
|
-
data:
|
|
111
|
-
}
|
|
111
|
+
data: parsed
|
|
112
|
+
},
|
|
113
|
+
requiredCapabilities: require_required_capabilities.requiredCapabilitiesFromTemplate(parsed)
|
|
112
114
|
};
|
|
113
115
|
if (key) this.preparedCache.set(key, result);
|
|
114
116
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_pack.cjs","names":["z","Code","LRUCache","resolveDevPacket","fs","RegistryV1","WorkerManager","getDevV2PacketMtime","loadTemplate","createFrontend"],"sources":["../../../src/mutator/block-pack/block_pack.ts"],"sourcesContent":["import type { AnyResourceRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field } from \"@milaboratories/pl-client\";\nimport { loadTemplate } from \"../template/template_loading\";\nimport type { BlockPackExplicit, BlockPackSpecAny, BlockPackSpecPrepared } from \"../../model\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport type { Branded } from \"@milaboratories/pl-model-common\";\nimport fs from \"node:fs\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport { createFrontend } from \"./frontend\";\nimport type { BlockConfigContainer } from \"@platforma-sdk/model\";\nimport { Code } from \"@platforma-sdk/model\";\nimport { loadPackDescription, RegistryV1 } from \"@platforma-sdk/block-tools\";\nimport type { BlockPackInfo } from \"../../model/block_pack\";\nimport { resolveDevPacket } from \"../../dev_env\";\nimport { getDevV2PacketMtime } from \"../../block_registry\";\nimport type { V2RegistryProvider } from \"../../block_registry/registry-v2-provider\";\nimport { LRUCache } from \"lru-cache\";\nimport canonicalize from \"canonicalize\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\nimport { WorkerManager } from \"../../worker/WorkerManager\";\nimport { z } from \"zod\";\n\ntype PreparedCacheKey = Branded<string, \"PreparedCacheKey\">;\n\nexport const BlockPackCustomType: ResourceType = { name: \"BlockPackCustom\", version: \"1\" };\nexport const BlockPackTemplateField = \"template\";\nexport const BlockPackFrontendField = \"frontend\";\n\n/** Ensure trailing slash */\nfunction tSlash(str: string): string {\n if (str.endsWith(\"/\")) return str;\n else return `${str}/`;\n}\n\nfunction parseStringConfig(configContent: string): BlockConfigContainer {\n const res = z.record(z.string(), z.unknown()).safeParse(JSON.parse(configContent));\n\n if (!res.success) {\n throw new Error(\"Invalid config content\");\n }\n\n if (!Code.safeParse(res.data.code).success) {\n throw new Error(\"parseStringConfig:No code bundle\");\n }\n\n return res.data as BlockConfigContainer;\n}\n\nfunction parseBufferConfig(buffer: ArrayBuffer): BlockConfigContainer {\n return parseStringConfig(Buffer.from(buffer).toString(\"utf8\"));\n}\n\nexport class BlockPackPreparer {\n constructor(\n private readonly v2RegistryProvider: V2RegistryProvider,\n private readonly signer: Signer,\n private readonly http?: Dispatcher,\n ) {}\n\n private readonly remoteContentCache = new LRUCache<string, ArrayBuffer>({\n max: 500,\n maxSize: 128 * 1024 * 1024,\n fetchMethod: async (key) => {\n const httpOptions = this.http !== undefined ? { dispatcher: this.http } : {};\n return await (await request(key, httpOptions)).body.arrayBuffer();\n },\n sizeCalculation: (value) => value.byteLength,\n });\n\n /** Cache of prepared block packs for registry specs (immutable by version). */\n private readonly preparedCache = new LRUCache<PreparedCacheKey, BlockPackSpecPrepared>({\n max: 50,\n });\n\n public async getBlockConfigContainer(spec: BlockPackSpecAny): Promise<BlockConfigContainer> {\n switch (spec.type) {\n case \"explicit\":\n return spec.config;\n\n case \"prepared\":\n return spec.config;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n const configContent = await fs.promises.readFile(devPaths.config, { encoding: \"utf-8\" });\n return JSON.parse(configContent);\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const configContent = await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n });\n return parseStringConfig(configContent);\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n return JSON.parse(Buffer.from(configResponse).toString(\"utf8\"));\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const configResponse = await this.remoteContentCache.forceFetch(components.model.url);\n return parseBufferConfig(configResponse);\n }\n\n default:\n return assertNever(spec);\n }\n }\n\n /** Returns a stable cache key for registry specs (immutable by version). Dev specs return undefined. */\n private specKey(spec: BlockPackSpecAny): PreparedCacheKey | undefined {\n switch (spec.type) {\n case \"from-registry-v1\":\n return `v1:${spec.registryUrl}:${spec.id.organization}:${spec.id.name}:${spec.id.version}` as PreparedCacheKey;\n case \"from-registry-v2\":\n return `v2:${spec.registryUrl}:${canonicalize(spec.id)}` as PreparedCacheKey;\n default:\n return undefined; // dev, explicit, prepared — not cacheable\n }\n }\n\n public async prepare(spec: BlockPackSpecAny): Promise<BlockPackSpecPrepared> {\n if (spec.type === \"prepared\") {\n return spec;\n }\n\n // Check prepare cache for registry specs\n const key = this.specKey(spec);\n if (key) {\n const cached = this.preparedCache.get(key);\n if (cached) return cached;\n }\n\n const explicit = await this.prepareWithoutUnpacking(spec);\n\n await using workerManager = new WorkerManager();\n\n const result: BlockPackSpecPrepared = {\n ...explicit,\n type: \"prepared\",\n template: {\n type: \"prepared\",\n data: await workerManager.process(\"parseTemplate\", explicit.template.content),\n },\n };\n\n if (key) {\n this.preparedCache.set(key, result);\n }\n\n return result;\n }\n\n private async prepareWithoutUnpacking(\n spec: BlockPackExplicit | BlockPackSpec,\n ): Promise<BlockPackExplicit> {\n switch (spec.type) {\n case \"explicit\":\n return spec;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n\n // template\n const templateContent = await fs.promises.readFile(devPaths.workflow);\n\n // config\n const config = JSON.parse(await fs.promises.readFile(devPaths.config, \"utf-8\"));\n\n // frontend\n const frontendPath = devPaths.ui;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source: spec,\n };\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const config = parseStringConfig(\n await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n }),\n );\n const workflowContent = await fs.promises.readFile(\n description.components.workflow.main.file,\n );\n const frontendPath = description.components.ui.folder;\n const source = { ...spec };\n if (spec.mtime === undefined)\n // if absent, calculating the mtime here, so the block will correctly show whether it can be updated\n source.mtime = await getDevV2PacketMtime(description);\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: workflowContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source,\n };\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const templateUrl = `${urlPrefix}/template.plj.gz`;\n // template\n const templateResponse = await this.remoteContentCache.forceFetch(templateUrl);\n const templateContent = new Uint8Array(templateResponse);\n\n // config\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n const config = JSON.parse(\n Buffer.from(configResponse).toString(\"utf8\"),\n ) as BlockConfigContainer;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"url\",\n url: `${urlPrefix}/frontend.tgz`,\n },\n source: spec,\n };\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const getModel = async () =>\n parseBufferConfig(await this.remoteContentCache.forceFetch(components.model.url));\n const getWorkflow = async () =>\n await this.remoteContentCache.forceFetch(components.workflow.main.url);\n\n const [model, workflow] = await Promise.all([getModel(), getWorkflow()]);\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: Buffer.from(workflow),\n },\n config: model,\n frontend: {\n type: \"url\",\n url: components.ui.url,\n },\n source: spec,\n };\n }\n\n default:\n return assertNever(spec);\n }\n }\n}\n\nfunction createCustomBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n const blockPackInfo: BlockPackInfo = { config: spec.config, source: spec.source };\n const bp = tx.createStruct(BlockPackCustomType, JSON.stringify(blockPackInfo));\n tx.createField(field(bp, BlockPackTemplateField), \"Input\", loadTemplate(tx, spec.template));\n tx.createField(field(bp, BlockPackFrontendField), \"Input\", createFrontend(tx, spec.frontend));\n tx.lock(bp);\n\n return bp;\n}\n\nexport function createBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n switch (spec.type) {\n case \"prepared\":\n return createCustomBlockPack(tx, spec);\n default:\n return assertNever(spec.type);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"block_pack.cjs","names":["z","Code","LRUCache","resolveDevPacket","fs","RegistryV1","WorkerManager","requiredCapabilitiesFromTemplate","getDevV2PacketMtime","loadTemplate","createFrontend"],"sources":["../../../src/mutator/block-pack/block_pack.ts"],"sourcesContent":["import type { AnyResourceRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field } from \"@milaboratories/pl-client\";\nimport { loadTemplate } from \"../template/template_loading\";\nimport type { BlockPackExplicit, BlockPackSpecAny, BlockPackSpecPrepared } from \"../../model\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport type { Branded } from \"@milaboratories/pl-model-common\";\nimport fs from \"node:fs\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport { createFrontend } from \"./frontend\";\nimport { requiredCapabilitiesFromTemplate } from \"./required_capabilities\";\nimport type { BlockConfigContainer } from \"@platforma-sdk/model\";\nimport { Code } from \"@platforma-sdk/model\";\nimport { loadPackDescription, RegistryV1 } from \"@platforma-sdk/block-tools\";\nimport type { BlockPackInfo } from \"../../model/block_pack\";\nimport { resolveDevPacket } from \"../../dev_env\";\nimport { getDevV2PacketMtime } from \"../../block_registry\";\nimport type { V2RegistryProvider } from \"../../block_registry/registry-v2-provider\";\nimport { LRUCache } from \"lru-cache\";\nimport canonicalize from \"canonicalize\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\nimport { WorkerManager } from \"../../worker/WorkerManager\";\nimport { z } from \"zod\";\n\ntype PreparedCacheKey = Branded<string, \"PreparedCacheKey\">;\n\nexport const BlockPackCustomType: ResourceType = { name: \"BlockPackCustom\", version: \"1\" };\nexport const BlockPackTemplateField = \"template\";\nexport const BlockPackFrontendField = \"frontend\";\n\n/** Ensure trailing slash */\nfunction tSlash(str: string): string {\n if (str.endsWith(\"/\")) return str;\n else return `${str}/`;\n}\n\nfunction parseStringConfig(configContent: string): BlockConfigContainer {\n const res = z.record(z.string(), z.unknown()).safeParse(JSON.parse(configContent));\n\n if (!res.success) {\n throw new Error(\"Invalid config content\");\n }\n\n if (!Code.safeParse(res.data.code).success) {\n throw new Error(\"parseStringConfig:No code bundle\");\n }\n\n return res.data as BlockConfigContainer;\n}\n\nfunction parseBufferConfig(buffer: ArrayBuffer): BlockConfigContainer {\n return parseStringConfig(Buffer.from(buffer).toString(\"utf8\"));\n}\n\nexport class BlockPackPreparer {\n constructor(\n private readonly v2RegistryProvider: V2RegistryProvider,\n private readonly signer: Signer,\n private readonly http?: Dispatcher,\n ) {}\n\n private readonly remoteContentCache = new LRUCache<string, ArrayBuffer>({\n max: 500,\n maxSize: 128 * 1024 * 1024,\n fetchMethod: async (key) => {\n const httpOptions = this.http !== undefined ? { dispatcher: this.http } : {};\n return await (await request(key, httpOptions)).body.arrayBuffer();\n },\n sizeCalculation: (value) => value.byteLength,\n });\n\n /** Cache of prepared block packs for registry specs (immutable by version). */\n private readonly preparedCache = new LRUCache<PreparedCacheKey, BlockPackSpecPrepared>({\n max: 50,\n });\n\n public async getBlockConfigContainer(spec: BlockPackSpecAny): Promise<BlockConfigContainer> {\n switch (spec.type) {\n case \"explicit\":\n return spec.config;\n\n case \"prepared\":\n return spec.config;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n const configContent = await fs.promises.readFile(devPaths.config, { encoding: \"utf-8\" });\n return JSON.parse(configContent);\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const configContent = await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n });\n return parseStringConfig(configContent);\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n return JSON.parse(Buffer.from(configResponse).toString(\"utf8\"));\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const configResponse = await this.remoteContentCache.forceFetch(components.model.url);\n return parseBufferConfig(configResponse);\n }\n\n default:\n return assertNever(spec);\n }\n }\n\n /** Returns a stable cache key for registry specs (immutable by version). Dev specs return undefined. */\n private specKey(spec: BlockPackSpecAny): PreparedCacheKey | undefined {\n switch (spec.type) {\n case \"from-registry-v1\":\n return `v1:${spec.registryUrl}:${spec.id.organization}:${spec.id.name}:${spec.id.version}` as PreparedCacheKey;\n case \"from-registry-v2\":\n return `v2:${spec.registryUrl}:${canonicalize(spec.id)}` as PreparedCacheKey;\n default:\n return undefined; // dev, explicit, prepared — not cacheable\n }\n }\n\n public async prepare(spec: BlockPackSpecAny): Promise<BlockPackSpecPrepared> {\n if (spec.type === \"prepared\") {\n return spec;\n }\n\n // Check prepare cache for registry specs\n const key = this.specKey(spec);\n if (key) {\n const cached = this.preparedCache.get(key);\n if (cached) return cached;\n }\n\n const explicit = await this.prepareWithoutUnpacking(spec);\n\n await using workerManager = new WorkerManager();\n\n const parsed = await workerManager.process(\"parseTemplate\", explicit.template.content);\n\n const result: BlockPackSpecPrepared = {\n ...explicit,\n type: \"prepared\",\n template: {\n type: \"prepared\",\n data: parsed,\n },\n requiredCapabilities: requiredCapabilitiesFromTemplate(parsed),\n };\n\n if (key) {\n this.preparedCache.set(key, result);\n }\n\n return result;\n }\n\n private async prepareWithoutUnpacking(\n spec: BlockPackExplicit | BlockPackSpec,\n ): Promise<BlockPackExplicit> {\n switch (spec.type) {\n case \"explicit\":\n return spec;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n\n // template\n const templateContent = await fs.promises.readFile(devPaths.workflow);\n\n // config\n const config = JSON.parse(await fs.promises.readFile(devPaths.config, \"utf-8\"));\n\n // frontend\n const frontendPath = devPaths.ui;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source: spec,\n };\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const config = parseStringConfig(\n await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n }),\n );\n const workflowContent = await fs.promises.readFile(\n description.components.workflow.main.file,\n );\n const frontendPath = description.components.ui.folder;\n const source = { ...spec };\n if (spec.mtime === undefined)\n // if absent, calculating the mtime here, so the block will correctly show whether it can be updated\n source.mtime = await getDevV2PacketMtime(description);\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: workflowContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source,\n };\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const templateUrl = `${urlPrefix}/template.plj.gz`;\n // template\n const templateResponse = await this.remoteContentCache.forceFetch(templateUrl);\n const templateContent = new Uint8Array(templateResponse);\n\n // config\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n const config = JSON.parse(\n Buffer.from(configResponse).toString(\"utf8\"),\n ) as BlockConfigContainer;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"url\",\n url: `${urlPrefix}/frontend.tgz`,\n },\n source: spec,\n };\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const getModel = async () =>\n parseBufferConfig(await this.remoteContentCache.forceFetch(components.model.url));\n const getWorkflow = async () =>\n await this.remoteContentCache.forceFetch(components.workflow.main.url);\n\n const [model, workflow] = await Promise.all([getModel(), getWorkflow()]);\n const workflowContent = Buffer.from(workflow);\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: workflowContent,\n },\n config: model,\n frontend: {\n type: \"url\",\n url: components.ui.url,\n },\n source: spec,\n };\n }\n\n default:\n return assertNever(spec);\n }\n }\n}\n\nfunction createCustomBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n const blockPackInfo: BlockPackInfo = { config: spec.config, source: spec.source };\n const bp = tx.createStruct(BlockPackCustomType, JSON.stringify(blockPackInfo));\n tx.createField(field(bp, BlockPackTemplateField), \"Input\", loadTemplate(tx, spec.template));\n tx.createField(field(bp, BlockPackFrontendField), \"Input\", createFrontend(tx, spec.frontend));\n tx.lock(bp);\n\n return bp;\n}\n\nexport function createBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n switch (spec.type) {\n case \"prepared\":\n return createCustomBlockPack(tx, spec);\n default:\n return assertNever(spec.type);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,sBAAoC;CAAE,MAAM;CAAmB,SAAS;CAAK;AAC1F,MAAa,yBAAyB;AACtC,MAAa,yBAAyB;;AAGtC,SAAS,OAAO,KAAqB;AACnC,KAAI,IAAI,SAAS,IAAI,CAAE,QAAO;KACzB,QAAO,GAAG,IAAI;;AAGrB,SAAS,kBAAkB,eAA6C;CACtE,MAAM,MAAMA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,QAAQ,EAAEA,IAAAA,EAAE,SAAS,CAAC,CAAC,UAAU,KAAK,MAAM,cAAc,CAAC;AAElF,KAAI,CAAC,IAAI,QACP,OAAM,IAAI,MAAM,yBAAyB;AAG3C,KAAI,CAACC,qBAAAA,KAAK,UAAU,IAAI,KAAK,KAAK,CAAC,QACjC,OAAM,IAAI,MAAM,mCAAmC;AAGrD,QAAO,IAAI;;AAGb,SAAS,kBAAkB,QAA2C;AACpE,QAAO,kBAAkB,OAAO,KAAK,OAAO,CAAC,SAAS,OAAO,CAAC;;AAGhE,IAAa,oBAAb,MAA+B;CAC7B,YACE,oBACA,QACA,MACA;AAHiB,OAAA,qBAAA;AACA,OAAA,SAAA;AACA,OAAA,OAAA;;CAGnB,qBAAsC,IAAIC,UAAAA,SAA8B;EACtE,KAAK;EACL,SAAS,MAAM,OAAO;EACtB,aAAa,OAAO,QAAQ;AAE1B,UAAO,OAAO,OAAA,GAAA,OAAA,SAAc,KADR,KAAK,SAAS,KAAA,IAAY,EAAE,YAAY,KAAK,MAAM,GAAG,EAAE,CAC/B,EAAE,KAAK,aAAa;;EAEnE,kBAAkB,UAAU,MAAM;EACnC,CAAC;;CAGF,gBAAiC,IAAIA,UAAAA,SAAkD,EACrF,KAAK,IACN,CAAC;CAEF,MAAa,wBAAwB,MAAuD;AAC1F,UAAQ,KAAK,MAAb;GACE,KAAK,WACH,QAAO,KAAK;GAEd,KAAK,WACH,QAAO,KAAK;GAEd,KAAK,UAAU;IACb,MAAM,WAAW,MAAMC,cAAAA,iBAAiB,KAAK,QAAQ,MAAM;IAC3D,MAAM,gBAAgB,MAAMC,QAAAA,QAAG,SAAS,SAAS,SAAS,QAAQ,EAAE,UAAU,SAAS,CAAC;AACxF,WAAO,KAAK,MAAM,cAAc;;GAGlC,KAAK,UAAU;IACb,MAAM,cAAc,OAAA,GAAA,2BAAA,qBAA0B,KAAK,OAAO;AAI1D,WAAO,kBAHe,MAAMA,QAAAA,QAAG,SAAS,SAAS,YAAY,WAAW,MAAM,MAAM,EAClF,UAAU,SACX,CAAC,CACqC;;GAGzC,KAAK,oBAAoB;IACvB,MAAM,YAAY,GAAG,OAAO,KAAK,YAAY,GAAGC,2BAAAA,WAAW,qBAAqB;KAAE,cAAc,KAAK,GAAG;KAAc,SAAS,KAAK,GAAG;KAAM,SAAS,KAAK,GAAG;KAAS,CAAC;IAExK,MAAM,iBAAiB,MAAM,KAAK,mBAAmB,WAAW,GAAG,UAAU,cAAc;AAC3F,WAAO,KAAK,MAAM,OAAO,KAAK,eAAe,CAAC,SAAS,OAAO,CAAC;;GAGjE,KAAK,oBAAoB;IAEvB,MAAM,aAAa,MADF,KAAK,mBAAmB,YAAY,KAAK,YAAY,CACpC,cAAc,KAAK,GAAG;AAExD,WAAO,kBADgB,MAAM,KAAK,mBAAmB,WAAW,WAAW,MAAM,IAAI,CAC7C;;GAG1C,QACE,SAAA,GAAA,2BAAA,aAAmB,KAAK;;;;CAK9B,QAAgB,MAAsD;AACpE,UAAQ,KAAK,MAAb;GACE,KAAK,mBACH,QAAO,MAAM,KAAK,YAAY,GAAG,KAAK,GAAG,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG;GACnF,KAAK,mBACH,QAAO,MAAM,KAAK,YAAY,IAAA,GAAA,aAAA,SAAgB,KAAK,GAAG;GACxD,QACE;;;CAIN,MAAa,QAAQ,MAAwD;;;AAC3E,OAAI,KAAK,SAAS,WAChB,QAAO;GAIT,MAAM,MAAM,KAAK,QAAQ,KAAK;AAC9B,OAAI,KAAK;IACP,MAAM,SAAS,KAAK,cAAc,IAAI,IAAI;AAC1C,QAAI,OAAQ,QAAO;;GAGrB,MAAM,WAAW,MAAM,KAAK,wBAAwB,KAAK;GAIzD,MAAM,SAAS,MAAA,YAAA,EAFa,IAAIC,sBAAAA,eAAe,CAAA,CAEZ,QAAQ,iBAAiB,SAAS,SAAS,QAAQ;GAEtF,MAAM,SAAgC;IACpC,GAAG;IACH,MAAM;IACN,UAAU;KACR,MAAM;KACN,MAAM;KACP;IACD,sBAAsBC,8BAAAA,iCAAiC,OAAO;IAC/D;AAED,OAAI,IACF,MAAK,cAAc,IAAI,KAAK,OAAO;AAGrC,UAAO;;;;;;;CAGT,MAAc,wBACZ,MAC4B;AAC5B,UAAQ,KAAK,MAAb;GACE,KAAK,WACH,QAAO;GAET,KAAK,UAAU;IACb,MAAM,WAAW,MAAMJ,cAAAA,iBAAiB,KAAK,QAAQ,MAAM;IAG3D,MAAM,kBAAkB,MAAMC,QAAAA,QAAG,SAAS,SAAS,SAAS,SAAS;IAGrE,MAAM,SAAS,KAAK,MAAM,MAAMA,QAAAA,QAAG,SAAS,SAAS,SAAS,QAAQ,QAAQ,CAAC;IAG/E,MAAM,eAAe,SAAS;AAE9B,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SAAS;MACV;KACD;KACA,UAAU;MACR,MAAM;MACN,MAAM;MACN,WAAW,KAAK,OAAO,KAAK,aAAa;MAC1C;KACD,QAAQ;KACT;;GAGH,KAAK,UAAU;IACb,MAAM,cAAc,OAAA,GAAA,2BAAA,qBAA0B,KAAK,OAAO;IAC1D,MAAM,SAAS,kBACb,MAAMA,QAAAA,QAAG,SAAS,SAAS,YAAY,WAAW,MAAM,MAAM,EAC5D,UAAU,SACX,CAAC,CACH;IACD,MAAM,kBAAkB,MAAMA,QAAAA,QAAG,SAAS,SACxC,YAAY,WAAW,SAAS,KAAK,KACtC;IACD,MAAM,eAAe,YAAY,WAAW,GAAG;IAC/C,MAAM,SAAS,EAAE,GAAG,MAAM;AAC1B,QAAI,KAAK,UAAU,KAAA,EAEjB,QAAO,QAAQ,MAAMI,iBAAAA,oBAAoB,YAAY;AACvD,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SAAS;MACV;KACD;KACA,UAAU;MACR,MAAM;MACN,MAAM;MACN,WAAW,KAAK,OAAO,KAAK,aAAa;MAC1C;KACD;KACD;;GAGH,KAAK,oBAAoB;IACvB,MAAM,YAAY,GAAG,OAAO,KAAK,YAAY,GAAGH,2BAAAA,WAAW,qBAAqB;KAAE,cAAc,KAAK,GAAG;KAAc,SAAS,KAAK,GAAG;KAAM,SAAS,KAAK,GAAG;KAAS,CAAC;IAExK,MAAM,cAAc,GAAG,UAAU;IAEjC,MAAM,mBAAmB,MAAM,KAAK,mBAAmB,WAAW,YAAY;IAC9E,MAAM,kBAAkB,IAAI,WAAW,iBAAiB;IAGxD,MAAM,iBAAiB,MAAM,KAAK,mBAAmB,WAAW,GAAG,UAAU,cAAc;IAC3F,MAAM,SAAS,KAAK,MAClB,OAAO,KAAK,eAAe,CAAC,SAAS,OAAO,CAC7C;AAED,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SAAS;MACV;KACD;KACA,UAAU;MACR,MAAM;MACN,KAAK,GAAG,UAAU;MACnB;KACD,QAAQ;KACT;;GAGH,KAAK,oBAAoB;IAEvB,MAAM,aAAa,MADF,KAAK,mBAAmB,YAAY,KAAK,YAAY,CACpC,cAAc,KAAK,GAAG;IACxD,MAAM,WAAW,YACf,kBAAkB,MAAM,KAAK,mBAAmB,WAAW,WAAW,MAAM,IAAI,CAAC;IACnF,MAAM,cAAc,YAClB,MAAM,KAAK,mBAAmB,WAAW,WAAW,SAAS,KAAK,IAAI;IAExE,MAAM,CAAC,OAAO,YAAY,MAAM,QAAQ,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAGxE,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SANoB,OAAO,KAAK,SAAS;MAO1C;KACD,QAAQ;KACR,UAAU;MACR,MAAM;MACN,KAAK,WAAW,GAAG;MACpB;KACD,QAAQ;KACT;;GAGH,QACE,SAAA,GAAA,2BAAA,aAAmB,KAAK;;;;AAKhC,SAAS,sBAAsB,IAAmB,MAA6C;CAC7F,MAAM,gBAA+B;EAAE,QAAQ,KAAK;EAAQ,QAAQ,KAAK;EAAQ;CACjF,MAAM,KAAK,GAAG,aAAa,qBAAqB,KAAK,UAAU,cAAc,CAAC;AAC9E,IAAG,aAAA,GAAA,0BAAA,OAAkB,IAAI,uBAAuB,EAAE,SAASI,yBAAAA,aAAa,IAAI,KAAK,SAAS,CAAC;AAC3F,IAAG,aAAA,GAAA,0BAAA,OAAkB,IAAI,uBAAuB,EAAE,SAASC,iBAAAA,eAAe,IAAI,KAAK,SAAS,CAAC;AAC7F,IAAG,KAAK,GAAG;AAEX,QAAO;;AAGT,SAAgB,gBAAgB,IAAmB,MAA6C;AAC9F,SAAQ,KAAK,MAAb;EACE,KAAK,WACH,QAAO,sBAAsB,IAAI,KAAK;EACxC,QACE,SAAA,GAAA,2BAAA,aAAmB,KAAK,KAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_pack.d.ts","names":[],"sources":["../../../src/mutator/block-pack/block_pack.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"block_pack.d.ts","names":[],"sources":["../../../src/mutator/block-pack/block_pack.ts"],"mappings":";;;;;;;;cAuDa,iBAAA;EAAA,iBAEQ,kBAAA;EAAA,iBACA,MAAA;EAAA,iBACA,IAAA;cAFA,kBAAA,EAAoB,kBAAA,EACpB,MAAA,EAAQ,MAAA,EACR,IAAA,GAAO,UAAA;EAAA,iBAGT,kBAAA;EAe0B;EAAA,iBAJ1B,aAAA;EAIJ,uBAAA,CAAwB,IAAA,EAAM,gBAAA,GAAmB,OAAA,CAAQ,oBAAA;EAqD3C;EAAA,QAXnB,OAAA;EAWK,OAAA,CAAQ,IAAA,EAAM,gBAAA,GAAmB,OAAA,CAAQ,qBAAA;EAAA,QAmCxC,uBAAA;AAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveDevPacket } from "../../dev_env/index.js";
|
|
2
|
+
import { requiredCapabilitiesFromTemplate } from "./required_capabilities.js";
|
|
2
3
|
import { getDevV2PacketMtime } from "../../block_registry/registry.js";
|
|
3
4
|
import "../../block_registry/index.js";
|
|
4
5
|
import { loadTemplate } from "../template/template_loading.js";
|
|
@@ -98,14 +99,15 @@ var BlockPackPreparer = class {
|
|
|
98
99
|
if (cached) return cached;
|
|
99
100
|
}
|
|
100
101
|
const explicit = await this.prepareWithoutUnpacking(spec);
|
|
101
|
-
const
|
|
102
|
+
const parsed = await _usingCtx$1.a(new WorkerManager()).process("parseTemplate", explicit.template.content);
|
|
102
103
|
const result = {
|
|
103
104
|
...explicit,
|
|
104
105
|
type: "prepared",
|
|
105
106
|
template: {
|
|
106
107
|
type: "prepared",
|
|
107
|
-
data:
|
|
108
|
-
}
|
|
108
|
+
data: parsed
|
|
109
|
+
},
|
|
110
|
+
requiredCapabilities: requiredCapabilitiesFromTemplate(parsed)
|
|
109
111
|
};
|
|
110
112
|
if (key) this.preparedCache.set(key, result);
|
|
111
113
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_pack.js","names":[],"sources":["../../../src/mutator/block-pack/block_pack.ts"],"sourcesContent":["import type { AnyResourceRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field } from \"@milaboratories/pl-client\";\nimport { loadTemplate } from \"../template/template_loading\";\nimport type { BlockPackExplicit, BlockPackSpecAny, BlockPackSpecPrepared } from \"../../model\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport type { Branded } from \"@milaboratories/pl-model-common\";\nimport fs from \"node:fs\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport { createFrontend } from \"./frontend\";\nimport type { BlockConfigContainer } from \"@platforma-sdk/model\";\nimport { Code } from \"@platforma-sdk/model\";\nimport { loadPackDescription, RegistryV1 } from \"@platforma-sdk/block-tools\";\nimport type { BlockPackInfo } from \"../../model/block_pack\";\nimport { resolveDevPacket } from \"../../dev_env\";\nimport { getDevV2PacketMtime } from \"../../block_registry\";\nimport type { V2RegistryProvider } from \"../../block_registry/registry-v2-provider\";\nimport { LRUCache } from \"lru-cache\";\nimport canonicalize from \"canonicalize\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\nimport { WorkerManager } from \"../../worker/WorkerManager\";\nimport { z } from \"zod\";\n\ntype PreparedCacheKey = Branded<string, \"PreparedCacheKey\">;\n\nexport const BlockPackCustomType: ResourceType = { name: \"BlockPackCustom\", version: \"1\" };\nexport const BlockPackTemplateField = \"template\";\nexport const BlockPackFrontendField = \"frontend\";\n\n/** Ensure trailing slash */\nfunction tSlash(str: string): string {\n if (str.endsWith(\"/\")) return str;\n else return `${str}/`;\n}\n\nfunction parseStringConfig(configContent: string): BlockConfigContainer {\n const res = z.record(z.string(), z.unknown()).safeParse(JSON.parse(configContent));\n\n if (!res.success) {\n throw new Error(\"Invalid config content\");\n }\n\n if (!Code.safeParse(res.data.code).success) {\n throw new Error(\"parseStringConfig:No code bundle\");\n }\n\n return res.data as BlockConfigContainer;\n}\n\nfunction parseBufferConfig(buffer: ArrayBuffer): BlockConfigContainer {\n return parseStringConfig(Buffer.from(buffer).toString(\"utf8\"));\n}\n\nexport class BlockPackPreparer {\n constructor(\n private readonly v2RegistryProvider: V2RegistryProvider,\n private readonly signer: Signer,\n private readonly http?: Dispatcher,\n ) {}\n\n private readonly remoteContentCache = new LRUCache<string, ArrayBuffer>({\n max: 500,\n maxSize: 128 * 1024 * 1024,\n fetchMethod: async (key) => {\n const httpOptions = this.http !== undefined ? { dispatcher: this.http } : {};\n return await (await request(key, httpOptions)).body.arrayBuffer();\n },\n sizeCalculation: (value) => value.byteLength,\n });\n\n /** Cache of prepared block packs for registry specs (immutable by version). */\n private readonly preparedCache = new LRUCache<PreparedCacheKey, BlockPackSpecPrepared>({\n max: 50,\n });\n\n public async getBlockConfigContainer(spec: BlockPackSpecAny): Promise<BlockConfigContainer> {\n switch (spec.type) {\n case \"explicit\":\n return spec.config;\n\n case \"prepared\":\n return spec.config;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n const configContent = await fs.promises.readFile(devPaths.config, { encoding: \"utf-8\" });\n return JSON.parse(configContent);\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const configContent = await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n });\n return parseStringConfig(configContent);\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n return JSON.parse(Buffer.from(configResponse).toString(\"utf8\"));\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const configResponse = await this.remoteContentCache.forceFetch(components.model.url);\n return parseBufferConfig(configResponse);\n }\n\n default:\n return assertNever(spec);\n }\n }\n\n /** Returns a stable cache key for registry specs (immutable by version). Dev specs return undefined. */\n private specKey(spec: BlockPackSpecAny): PreparedCacheKey | undefined {\n switch (spec.type) {\n case \"from-registry-v1\":\n return `v1:${spec.registryUrl}:${spec.id.organization}:${spec.id.name}:${spec.id.version}` as PreparedCacheKey;\n case \"from-registry-v2\":\n return `v2:${spec.registryUrl}:${canonicalize(spec.id)}` as PreparedCacheKey;\n default:\n return undefined; // dev, explicit, prepared — not cacheable\n }\n }\n\n public async prepare(spec: BlockPackSpecAny): Promise<BlockPackSpecPrepared> {\n if (spec.type === \"prepared\") {\n return spec;\n }\n\n // Check prepare cache for registry specs\n const key = this.specKey(spec);\n if (key) {\n const cached = this.preparedCache.get(key);\n if (cached) return cached;\n }\n\n const explicit = await this.prepareWithoutUnpacking(spec);\n\n await using workerManager = new WorkerManager();\n\n const result: BlockPackSpecPrepared = {\n ...explicit,\n type: \"prepared\",\n template: {\n type: \"prepared\",\n data: await workerManager.process(\"parseTemplate\", explicit.template.content),\n },\n };\n\n if (key) {\n this.preparedCache.set(key, result);\n }\n\n return result;\n }\n\n private async prepareWithoutUnpacking(\n spec: BlockPackExplicit | BlockPackSpec,\n ): Promise<BlockPackExplicit> {\n switch (spec.type) {\n case \"explicit\":\n return spec;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n\n // template\n const templateContent = await fs.promises.readFile(devPaths.workflow);\n\n // config\n const config = JSON.parse(await fs.promises.readFile(devPaths.config, \"utf-8\"));\n\n // frontend\n const frontendPath = devPaths.ui;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source: spec,\n };\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const config = parseStringConfig(\n await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n }),\n );\n const workflowContent = await fs.promises.readFile(\n description.components.workflow.main.file,\n );\n const frontendPath = description.components.ui.folder;\n const source = { ...spec };\n if (spec.mtime === undefined)\n // if absent, calculating the mtime here, so the block will correctly show whether it can be updated\n source.mtime = await getDevV2PacketMtime(description);\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: workflowContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source,\n };\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const templateUrl = `${urlPrefix}/template.plj.gz`;\n // template\n const templateResponse = await this.remoteContentCache.forceFetch(templateUrl);\n const templateContent = new Uint8Array(templateResponse);\n\n // config\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n const config = JSON.parse(\n Buffer.from(configResponse).toString(\"utf8\"),\n ) as BlockConfigContainer;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"url\",\n url: `${urlPrefix}/frontend.tgz`,\n },\n source: spec,\n };\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const getModel = async () =>\n parseBufferConfig(await this.remoteContentCache.forceFetch(components.model.url));\n const getWorkflow = async () =>\n await this.remoteContentCache.forceFetch(components.workflow.main.url);\n\n const [model, workflow] = await Promise.all([getModel(), getWorkflow()]);\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: Buffer.from(workflow),\n },\n config: model,\n frontend: {\n type: \"url\",\n url: components.ui.url,\n },\n source: spec,\n };\n }\n\n default:\n return assertNever(spec);\n }\n }\n}\n\nfunction createCustomBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n const blockPackInfo: BlockPackInfo = { config: spec.config, source: spec.source };\n const bp = tx.createStruct(BlockPackCustomType, JSON.stringify(blockPackInfo));\n tx.createField(field(bp, BlockPackTemplateField), \"Input\", loadTemplate(tx, spec.template));\n tx.createField(field(bp, BlockPackFrontendField), \"Input\", createFrontend(tx, spec.frontend));\n tx.lock(bp);\n\n return bp;\n}\n\nexport function createBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n switch (spec.type) {\n case \"prepared\":\n return createCustomBlockPack(tx, spec);\n default:\n return assertNever(spec.type);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,MAAa,sBAAoC;CAAE,MAAM;CAAmB,SAAS;CAAK;AAC1F,MAAa,yBAAyB;AACtC,MAAa,yBAAyB;;AAGtC,SAAS,OAAO,KAAqB;AACnC,KAAI,IAAI,SAAS,IAAI,CAAE,QAAO;KACzB,QAAO,GAAG,IAAI;;AAGrB,SAAS,kBAAkB,eAA6C;CACtE,MAAM,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU,KAAK,MAAM,cAAc,CAAC;AAElF,KAAI,CAAC,IAAI,QACP,OAAM,IAAI,MAAM,yBAAyB;AAG3C,KAAI,CAAC,KAAK,UAAU,IAAI,KAAK,KAAK,CAAC,QACjC,OAAM,IAAI,MAAM,mCAAmC;AAGrD,QAAO,IAAI;;AAGb,SAAS,kBAAkB,QAA2C;AACpE,QAAO,kBAAkB,OAAO,KAAK,OAAO,CAAC,SAAS,OAAO,CAAC;;AAGhE,IAAa,oBAAb,MAA+B;CAC7B,YACE,oBACA,QACA,MACA;AAHiB,OAAA,qBAAA;AACA,OAAA,SAAA;AACA,OAAA,OAAA;;CAGnB,qBAAsC,IAAI,SAA8B;EACtE,KAAK;EACL,SAAS,MAAM,OAAO;EACtB,aAAa,OAAO,QAAQ;AAE1B,UAAO,OAAO,MAAM,QAAQ,KADR,KAAK,SAAS,KAAA,IAAY,EAAE,YAAY,KAAK,MAAM,GAAG,EAAE,CAC/B,EAAE,KAAK,aAAa;;EAEnE,kBAAkB,UAAU,MAAM;EACnC,CAAC;;CAGF,gBAAiC,IAAI,SAAkD,EACrF,KAAK,IACN,CAAC;CAEF,MAAa,wBAAwB,MAAuD;AAC1F,UAAQ,KAAK,MAAb;GACE,KAAK,WACH,QAAO,KAAK;GAEd,KAAK,WACH,QAAO,KAAK;GAEd,KAAK,UAAU;IACb,MAAM,WAAW,MAAM,iBAAiB,KAAK,QAAQ,MAAM;IAC3D,MAAM,gBAAgB,MAAM,GAAG,SAAS,SAAS,SAAS,QAAQ,EAAE,UAAU,SAAS,CAAC;AACxF,WAAO,KAAK,MAAM,cAAc;;GAGlC,KAAK,UAAU;IACb,MAAM,cAAc,MAAM,oBAAoB,KAAK,OAAO;AAI1D,WAAO,kBAHe,MAAM,GAAG,SAAS,SAAS,YAAY,WAAW,MAAM,MAAM,EAClF,UAAU,SACX,CAAC,CACqC;;GAGzC,KAAK,oBAAoB;IACvB,MAAM,YAAY,GAAG,OAAO,KAAK,YAAY,GAAG,WAAW,qBAAqB;KAAE,cAAc,KAAK,GAAG;KAAc,SAAS,KAAK,GAAG;KAAM,SAAS,KAAK,GAAG;KAAS,CAAC;IAExK,MAAM,iBAAiB,MAAM,KAAK,mBAAmB,WAAW,GAAG,UAAU,cAAc;AAC3F,WAAO,KAAK,MAAM,OAAO,KAAK,eAAe,CAAC,SAAS,OAAO,CAAC;;GAGjE,KAAK,oBAAoB;IAEvB,MAAM,aAAa,MADF,KAAK,mBAAmB,YAAY,KAAK,YAAY,CACpC,cAAc,KAAK,GAAG;AAExD,WAAO,kBADgB,MAAM,KAAK,mBAAmB,WAAW,WAAW,MAAM,IAAI,CAC7C;;GAG1C,QACE,QAAO,YAAY,KAAK;;;;CAK9B,QAAgB,MAAsD;AACpE,UAAQ,KAAK,MAAb;GACE,KAAK,mBACH,QAAO,MAAM,KAAK,YAAY,GAAG,KAAK,GAAG,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG;GACnF,KAAK,mBACH,QAAO,MAAM,KAAK,YAAY,GAAG,aAAa,KAAK,GAAG;GACxD,QACE;;;CAIN,MAAa,QAAQ,MAAwD;;;AAC3E,OAAI,KAAK,SAAS,WAChB,QAAO;GAIT,MAAM,MAAM,KAAK,QAAQ,KAAK;AAC9B,OAAI,KAAK;IACP,MAAM,SAAS,KAAK,cAAc,IAAI,IAAI;AAC1C,QAAI,OAAQ,QAAO;;GAGrB,MAAM,WAAW,MAAM,KAAK,wBAAwB,KAAK;GAEzD,MAAY,gBAAA,YAAA,EAAgB,IAAI,eAAe,CAAA;GAE/C,MAAM,SAAgC;IACpC,GAAG;IACH,MAAM;IACN,UAAU;KACR,MAAM;KACN,MAAM,MAAM,cAAc,QAAQ,iBAAiB,SAAS,SAAS,QAAQ;KAC9E;IACF;AAED,OAAI,IACF,MAAK,cAAc,IAAI,KAAK,OAAO;AAGrC,UAAO;;;;;;;CAGT,MAAc,wBACZ,MAC4B;AAC5B,UAAQ,KAAK,MAAb;GACE,KAAK,WACH,QAAO;GAET,KAAK,UAAU;IACb,MAAM,WAAW,MAAM,iBAAiB,KAAK,QAAQ,MAAM;IAG3D,MAAM,kBAAkB,MAAM,GAAG,SAAS,SAAS,SAAS,SAAS;IAGrE,MAAM,SAAS,KAAK,MAAM,MAAM,GAAG,SAAS,SAAS,SAAS,QAAQ,QAAQ,CAAC;IAG/E,MAAM,eAAe,SAAS;AAE9B,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SAAS;MACV;KACD;KACA,UAAU;MACR,MAAM;MACN,MAAM;MACN,WAAW,KAAK,OAAO,KAAK,aAAa;MAC1C;KACD,QAAQ;KACT;;GAGH,KAAK,UAAU;IACb,MAAM,cAAc,MAAM,oBAAoB,KAAK,OAAO;IAC1D,MAAM,SAAS,kBACb,MAAM,GAAG,SAAS,SAAS,YAAY,WAAW,MAAM,MAAM,EAC5D,UAAU,SACX,CAAC,CACH;IACD,MAAM,kBAAkB,MAAM,GAAG,SAAS,SACxC,YAAY,WAAW,SAAS,KAAK,KACtC;IACD,MAAM,eAAe,YAAY,WAAW,GAAG;IAC/C,MAAM,SAAS,EAAE,GAAG,MAAM;AAC1B,QAAI,KAAK,UAAU,KAAA,EAEjB,QAAO,QAAQ,MAAM,oBAAoB,YAAY;AACvD,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SAAS;MACV;KACD;KACA,UAAU;MACR,MAAM;MACN,MAAM;MACN,WAAW,KAAK,OAAO,KAAK,aAAa;MAC1C;KACD;KACD;;GAGH,KAAK,oBAAoB;IACvB,MAAM,YAAY,GAAG,OAAO,KAAK,YAAY,GAAG,WAAW,qBAAqB;KAAE,cAAc,KAAK,GAAG;KAAc,SAAS,KAAK,GAAG;KAAM,SAAS,KAAK,GAAG;KAAS,CAAC;IAExK,MAAM,cAAc,GAAG,UAAU;IAEjC,MAAM,mBAAmB,MAAM,KAAK,mBAAmB,WAAW,YAAY;IAC9E,MAAM,kBAAkB,IAAI,WAAW,iBAAiB;IAGxD,MAAM,iBAAiB,MAAM,KAAK,mBAAmB,WAAW,GAAG,UAAU,cAAc;IAC3F,MAAM,SAAS,KAAK,MAClB,OAAO,KAAK,eAAe,CAAC,SAAS,OAAO,CAC7C;AAED,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SAAS;MACV;KACD;KACA,UAAU;MACR,MAAM;MACN,KAAK,GAAG,UAAU;MACnB;KACD,QAAQ;KACT;;GAGH,KAAK,oBAAoB;IAEvB,MAAM,aAAa,MADF,KAAK,mBAAmB,YAAY,KAAK,YAAY,CACpC,cAAc,KAAK,GAAG;IACxD,MAAM,WAAW,YACf,kBAAkB,MAAM,KAAK,mBAAmB,WAAW,WAAW,MAAM,IAAI,CAAC;IACnF,MAAM,cAAc,YAClB,MAAM,KAAK,mBAAmB,WAAW,WAAW,SAAS,KAAK,IAAI;IAExE,MAAM,CAAC,OAAO,YAAY,MAAM,QAAQ,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAExE,WAAO;KACL,MAAM;KACN,UAAU;MACR,MAAM;MACN,SAAS,OAAO,KAAK,SAAS;MAC/B;KACD,QAAQ;KACR,UAAU;MACR,MAAM;MACN,KAAK,WAAW,GAAG;MACpB;KACD,QAAQ;KACT;;GAGH,QACE,QAAO,YAAY,KAAK;;;;AAKhC,SAAS,sBAAsB,IAAmB,MAA6C;CAC7F,MAAM,gBAA+B;EAAE,QAAQ,KAAK;EAAQ,QAAQ,KAAK;EAAQ;CACjF,MAAM,KAAK,GAAG,aAAa,qBAAqB,KAAK,UAAU,cAAc,CAAC;AAC9E,IAAG,YAAY,MAAM,IAAI,uBAAuB,EAAE,SAAS,aAAa,IAAI,KAAK,SAAS,CAAC;AAC3F,IAAG,YAAY,MAAM,IAAI,uBAAuB,EAAE,SAAS,eAAe,IAAI,KAAK,SAAS,CAAC;AAC7F,IAAG,KAAK,GAAG;AAEX,QAAO;;AAGT,SAAgB,gBAAgB,IAAmB,MAA6C;AAC9F,SAAQ,KAAK,MAAb;EACE,KAAK,WACH,QAAO,sBAAsB,IAAI,KAAK;EACxC,QACE,QAAO,YAAY,KAAK,KAAK"}
|
|
1
|
+
{"version":3,"file":"block_pack.js","names":[],"sources":["../../../src/mutator/block-pack/block_pack.ts"],"sourcesContent":["import type { AnyResourceRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field } from \"@milaboratories/pl-client\";\nimport { loadTemplate } from \"../template/template_loading\";\nimport type { BlockPackExplicit, BlockPackSpecAny, BlockPackSpecPrepared } from \"../../model\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport type { Branded } from \"@milaboratories/pl-model-common\";\nimport fs from \"node:fs\";\nimport type { Dispatcher } from \"undici\";\nimport { request } from \"undici\";\nimport { createFrontend } from \"./frontend\";\nimport { requiredCapabilitiesFromTemplate } from \"./required_capabilities\";\nimport type { BlockConfigContainer } from \"@platforma-sdk/model\";\nimport { Code } from \"@platforma-sdk/model\";\nimport { loadPackDescription, RegistryV1 } from \"@platforma-sdk/block-tools\";\nimport type { BlockPackInfo } from \"../../model/block_pack\";\nimport { resolveDevPacket } from \"../../dev_env\";\nimport { getDevV2PacketMtime } from \"../../block_registry\";\nimport type { V2RegistryProvider } from \"../../block_registry/registry-v2-provider\";\nimport { LRUCache } from \"lru-cache\";\nimport canonicalize from \"canonicalize\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\nimport { WorkerManager } from \"../../worker/WorkerManager\";\nimport { z } from \"zod\";\n\ntype PreparedCacheKey = Branded<string, \"PreparedCacheKey\">;\n\nexport const BlockPackCustomType: ResourceType = { name: \"BlockPackCustom\", version: \"1\" };\nexport const BlockPackTemplateField = \"template\";\nexport const BlockPackFrontendField = \"frontend\";\n\n/** Ensure trailing slash */\nfunction tSlash(str: string): string {\n if (str.endsWith(\"/\")) return str;\n else return `${str}/`;\n}\n\nfunction parseStringConfig(configContent: string): BlockConfigContainer {\n const res = z.record(z.string(), z.unknown()).safeParse(JSON.parse(configContent));\n\n if (!res.success) {\n throw new Error(\"Invalid config content\");\n }\n\n if (!Code.safeParse(res.data.code).success) {\n throw new Error(\"parseStringConfig:No code bundle\");\n }\n\n return res.data as BlockConfigContainer;\n}\n\nfunction parseBufferConfig(buffer: ArrayBuffer): BlockConfigContainer {\n return parseStringConfig(Buffer.from(buffer).toString(\"utf8\"));\n}\n\nexport class BlockPackPreparer {\n constructor(\n private readonly v2RegistryProvider: V2RegistryProvider,\n private readonly signer: Signer,\n private readonly http?: Dispatcher,\n ) {}\n\n private readonly remoteContentCache = new LRUCache<string, ArrayBuffer>({\n max: 500,\n maxSize: 128 * 1024 * 1024,\n fetchMethod: async (key) => {\n const httpOptions = this.http !== undefined ? { dispatcher: this.http } : {};\n return await (await request(key, httpOptions)).body.arrayBuffer();\n },\n sizeCalculation: (value) => value.byteLength,\n });\n\n /** Cache of prepared block packs for registry specs (immutable by version). */\n private readonly preparedCache = new LRUCache<PreparedCacheKey, BlockPackSpecPrepared>({\n max: 50,\n });\n\n public async getBlockConfigContainer(spec: BlockPackSpecAny): Promise<BlockConfigContainer> {\n switch (spec.type) {\n case \"explicit\":\n return spec.config;\n\n case \"prepared\":\n return spec.config;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n const configContent = await fs.promises.readFile(devPaths.config, { encoding: \"utf-8\" });\n return JSON.parse(configContent);\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const configContent = await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n });\n return parseStringConfig(configContent);\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n return JSON.parse(Buffer.from(configResponse).toString(\"utf8\"));\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const configResponse = await this.remoteContentCache.forceFetch(components.model.url);\n return parseBufferConfig(configResponse);\n }\n\n default:\n return assertNever(spec);\n }\n }\n\n /** Returns a stable cache key for registry specs (immutable by version). Dev specs return undefined. */\n private specKey(spec: BlockPackSpecAny): PreparedCacheKey | undefined {\n switch (spec.type) {\n case \"from-registry-v1\":\n return `v1:${spec.registryUrl}:${spec.id.organization}:${spec.id.name}:${spec.id.version}` as PreparedCacheKey;\n case \"from-registry-v2\":\n return `v2:${spec.registryUrl}:${canonicalize(spec.id)}` as PreparedCacheKey;\n default:\n return undefined; // dev, explicit, prepared — not cacheable\n }\n }\n\n public async prepare(spec: BlockPackSpecAny): Promise<BlockPackSpecPrepared> {\n if (spec.type === \"prepared\") {\n return spec;\n }\n\n // Check prepare cache for registry specs\n const key = this.specKey(spec);\n if (key) {\n const cached = this.preparedCache.get(key);\n if (cached) return cached;\n }\n\n const explicit = await this.prepareWithoutUnpacking(spec);\n\n await using workerManager = new WorkerManager();\n\n const parsed = await workerManager.process(\"parseTemplate\", explicit.template.content);\n\n const result: BlockPackSpecPrepared = {\n ...explicit,\n type: \"prepared\",\n template: {\n type: \"prepared\",\n data: parsed,\n },\n requiredCapabilities: requiredCapabilitiesFromTemplate(parsed),\n };\n\n if (key) {\n this.preparedCache.set(key, result);\n }\n\n return result;\n }\n\n private async prepareWithoutUnpacking(\n spec: BlockPackExplicit | BlockPackSpec,\n ): Promise<BlockPackExplicit> {\n switch (spec.type) {\n case \"explicit\":\n return spec;\n\n case \"dev-v1\": {\n const devPaths = await resolveDevPacket(spec.folder, false);\n\n // template\n const templateContent = await fs.promises.readFile(devPaths.workflow);\n\n // config\n const config = JSON.parse(await fs.promises.readFile(devPaths.config, \"utf-8\"));\n\n // frontend\n const frontendPath = devPaths.ui;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source: spec,\n };\n }\n\n case \"dev-v2\": {\n const description = await loadPackDescription(spec.folder);\n const config = parseStringConfig(\n await fs.promises.readFile(description.components.model.file, {\n encoding: \"utf-8\",\n }),\n );\n const workflowContent = await fs.promises.readFile(\n description.components.workflow.main.file,\n );\n const frontendPath = description.components.ui.folder;\n const source = { ...spec };\n if (spec.mtime === undefined)\n // if absent, calculating the mtime here, so the block will correctly show whether it can be updated\n source.mtime = await getDevV2PacketMtime(description);\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: workflowContent,\n },\n config,\n frontend: {\n type: \"local\",\n path: frontendPath,\n signature: this.signer.sign(frontendPath),\n },\n source,\n };\n }\n\n case \"from-registry-v1\": {\n const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix({ organization: spec.id.organization, package: spec.id.name, version: spec.id.version })}`;\n\n const templateUrl = `${urlPrefix}/template.plj.gz`;\n // template\n const templateResponse = await this.remoteContentCache.forceFetch(templateUrl);\n const templateContent = new Uint8Array(templateResponse);\n\n // config\n const configResponse = await this.remoteContentCache.forceFetch(`${urlPrefix}/config.json`);\n const config = JSON.parse(\n Buffer.from(configResponse).toString(\"utf8\"),\n ) as BlockConfigContainer;\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: templateContent,\n },\n config,\n frontend: {\n type: \"url\",\n url: `${urlPrefix}/frontend.tgz`,\n },\n source: spec,\n };\n }\n\n case \"from-registry-v2\": {\n const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);\n const components = await registry.getComponents(spec.id);\n const getModel = async () =>\n parseBufferConfig(await this.remoteContentCache.forceFetch(components.model.url));\n const getWorkflow = async () =>\n await this.remoteContentCache.forceFetch(components.workflow.main.url);\n\n const [model, workflow] = await Promise.all([getModel(), getWorkflow()]);\n const workflowContent = Buffer.from(workflow);\n\n return {\n type: \"explicit\",\n template: {\n type: \"explicit\",\n content: workflowContent,\n },\n config: model,\n frontend: {\n type: \"url\",\n url: components.ui.url,\n },\n source: spec,\n };\n }\n\n default:\n return assertNever(spec);\n }\n }\n}\n\nfunction createCustomBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n const blockPackInfo: BlockPackInfo = { config: spec.config, source: spec.source };\n const bp = tx.createStruct(BlockPackCustomType, JSON.stringify(blockPackInfo));\n tx.createField(field(bp, BlockPackTemplateField), \"Input\", loadTemplate(tx, spec.template));\n tx.createField(field(bp, BlockPackFrontendField), \"Input\", createFrontend(tx, spec.frontend));\n tx.lock(bp);\n\n return bp;\n}\n\nexport function createBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {\n switch (spec.type) {\n case \"prepared\":\n return createCustomBlockPack(tx, spec);\n default:\n return assertNever(spec.type);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require("../../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let node_zlib = require("node:zlib");
|
|
3
|
+
//#region src/mutator/block-pack/required_capabilities.ts
|
|
4
|
+
/**
|
|
5
|
+
* Reads the capability tokens a template declares it requires via
|
|
6
|
+
* `TemplateDataV3.requiredCapabilities` (populated by `tengo-builder` at
|
|
7
|
+
* compile time).
|
|
8
|
+
*
|
|
9
|
+
* Use this on the install path: `BlockPackPreparer.prepare` parses the
|
|
10
|
+
* workflow off-thread via the worker, and the parsed result feeds
|
|
11
|
+
* straight into this function — no second gunzip+JSON.parse on the main
|
|
12
|
+
* thread, no recursive walk to re-derive what the compiler already wrote
|
|
13
|
+
* down.
|
|
14
|
+
*
|
|
15
|
+
* Returns `undefined` for v2 templates (no compile-time capability
|
|
16
|
+
* field) and for v3 templates that declare no requirements; otherwise
|
|
17
|
+
* the array as the compiler wrote it.
|
|
18
|
+
*/
|
|
19
|
+
function requiredCapabilitiesFromTemplate(parsed) {
|
|
20
|
+
if (parsed.type !== "pl.tengo-template.v3") return void 0;
|
|
21
|
+
return parsed.template.requiredCapabilities;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Same lookup, starting from raw `main.plj.gz` bytes. Used only at
|
|
25
|
+
* catalog-listing time for local-dev blocks where the worker pipeline
|
|
26
|
+
* isn't in play (`block_registry/registry.ts`). Install paths go through
|
|
27
|
+
* `requiredCapabilitiesFromTemplate` instead to avoid parsing the
|
|
28
|
+
* workflow twice.
|
|
29
|
+
*/
|
|
30
|
+
function deriveRequiredCapabilities(workflowContent) {
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
const json = (0, node_zlib.gunzipSync)(workflowContent).toString("utf-8");
|
|
34
|
+
parsed = JSON.parse(json);
|
|
35
|
+
} catch {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
return requiredCapabilitiesFromTemplate(parsed);
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
exports.deriveRequiredCapabilities = deriveRequiredCapabilities;
|
|
42
|
+
exports.requiredCapabilitiesFromTemplate = requiredCapabilitiesFromTemplate;
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=required_capabilities.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required_capabilities.cjs","names":[],"sources":["../../../src/mutator/block-pack/required_capabilities.ts"],"sourcesContent":["import { gunzipSync } from \"node:zlib\";\nimport type { CompiledTemplateV3, TemplateData } from \"@milaboratories/pl-model-backend\";\n\n/**\n * Reads the capability tokens a template declares it requires via\n * `TemplateDataV3.requiredCapabilities` (populated by `tengo-builder` at\n * compile time).\n *\n * Use this on the install path: `BlockPackPreparer.prepare` parses the\n * workflow off-thread via the worker, and the parsed result feeds\n * straight into this function — no second gunzip+JSON.parse on the main\n * thread, no recursive walk to re-derive what the compiler already wrote\n * down.\n *\n * Returns `undefined` for v2 templates (no compile-time capability\n * field) and for v3 templates that declare no requirements; otherwise\n * the array as the compiler wrote it.\n */\nexport function requiredCapabilitiesFromTemplate(\n parsed: TemplateData | CompiledTemplateV3,\n): string[] | undefined {\n if (parsed.type !== \"pl.tengo-template.v3\") return undefined;\n return parsed.template.requiredCapabilities;\n}\n\n/**\n * Same lookup, starting from raw `main.plj.gz` bytes. Used only at\n * catalog-listing time for local-dev blocks where the worker pipeline\n * isn't in play (`block_registry/registry.ts`). Install paths go through\n * `requiredCapabilitiesFromTemplate` instead to avoid parsing the\n * workflow twice.\n */\nexport function deriveRequiredCapabilities(\n workflowContent: Uint8Array | Buffer,\n): string[] | undefined {\n let parsed: unknown;\n try {\n const json = gunzipSync(workflowContent).toString(\"utf-8\");\n parsed = JSON.parse(json);\n } catch {\n return undefined;\n }\n return requiredCapabilitiesFromTemplate(parsed as TemplateData | CompiledTemplateV3);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAgB,iCACd,QACsB;AACtB,KAAI,OAAO,SAAS,uBAAwB,QAAO,KAAA;AACnD,QAAO,OAAO,SAAS;;;;;;;;;AAUzB,SAAgB,2BACd,iBACsB;CACtB,IAAI;AACJ,KAAI;EACF,MAAM,QAAA,GAAA,UAAA,YAAkB,gBAAgB,CAAC,SAAS,QAAQ;AAC1D,WAAS,KAAK,MAAM,KAAK;SACnB;AACN;;AAEF,QAAO,iCAAiC,OAA4C"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { gunzipSync } from "node:zlib";
|
|
2
|
+
//#region src/mutator/block-pack/required_capabilities.ts
|
|
3
|
+
/**
|
|
4
|
+
* Reads the capability tokens a template declares it requires via
|
|
5
|
+
* `TemplateDataV3.requiredCapabilities` (populated by `tengo-builder` at
|
|
6
|
+
* compile time).
|
|
7
|
+
*
|
|
8
|
+
* Use this on the install path: `BlockPackPreparer.prepare` parses the
|
|
9
|
+
* workflow off-thread via the worker, and the parsed result feeds
|
|
10
|
+
* straight into this function — no second gunzip+JSON.parse on the main
|
|
11
|
+
* thread, no recursive walk to re-derive what the compiler already wrote
|
|
12
|
+
* down.
|
|
13
|
+
*
|
|
14
|
+
* Returns `undefined` for v2 templates (no compile-time capability
|
|
15
|
+
* field) and for v3 templates that declare no requirements; otherwise
|
|
16
|
+
* the array as the compiler wrote it.
|
|
17
|
+
*/
|
|
18
|
+
function requiredCapabilitiesFromTemplate(parsed) {
|
|
19
|
+
if (parsed.type !== "pl.tengo-template.v3") return void 0;
|
|
20
|
+
return parsed.template.requiredCapabilities;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Same lookup, starting from raw `main.plj.gz` bytes. Used only at
|
|
24
|
+
* catalog-listing time for local-dev blocks where the worker pipeline
|
|
25
|
+
* isn't in play (`block_registry/registry.ts`). Install paths go through
|
|
26
|
+
* `requiredCapabilitiesFromTemplate` instead to avoid parsing the
|
|
27
|
+
* workflow twice.
|
|
28
|
+
*/
|
|
29
|
+
function deriveRequiredCapabilities(workflowContent) {
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
const json = gunzipSync(workflowContent).toString("utf-8");
|
|
33
|
+
parsed = JSON.parse(json);
|
|
34
|
+
} catch {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
return requiredCapabilitiesFromTemplate(parsed);
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { deriveRequiredCapabilities, requiredCapabilitiesFromTemplate };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=required_capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required_capabilities.js","names":[],"sources":["../../../src/mutator/block-pack/required_capabilities.ts"],"sourcesContent":["import { gunzipSync } from \"node:zlib\";\nimport type { CompiledTemplateV3, TemplateData } from \"@milaboratories/pl-model-backend\";\n\n/**\n * Reads the capability tokens a template declares it requires via\n * `TemplateDataV3.requiredCapabilities` (populated by `tengo-builder` at\n * compile time).\n *\n * Use this on the install path: `BlockPackPreparer.prepare` parses the\n * workflow off-thread via the worker, and the parsed result feeds\n * straight into this function — no second gunzip+JSON.parse on the main\n * thread, no recursive walk to re-derive what the compiler already wrote\n * down.\n *\n * Returns `undefined` for v2 templates (no compile-time capability\n * field) and for v3 templates that declare no requirements; otherwise\n * the array as the compiler wrote it.\n */\nexport function requiredCapabilitiesFromTemplate(\n parsed: TemplateData | CompiledTemplateV3,\n): string[] | undefined {\n if (parsed.type !== \"pl.tengo-template.v3\") return undefined;\n return parsed.template.requiredCapabilities;\n}\n\n/**\n * Same lookup, starting from raw `main.plj.gz` bytes. Used only at\n * catalog-listing time for local-dev blocks where the worker pipeline\n * isn't in play (`block_registry/registry.ts`). Install paths go through\n * `requiredCapabilitiesFromTemplate` instead to avoid parsing the\n * workflow twice.\n */\nexport function deriveRequiredCapabilities(\n workflowContent: Uint8Array | Buffer,\n): string[] | undefined {\n let parsed: unknown;\n try {\n const json = gunzipSync(workflowContent).toString(\"utf-8\");\n parsed = JSON.parse(json);\n } catch {\n return undefined;\n }\n return requiredCapabilitiesFromTemplate(parsed as TemplateData | CompiledTemplateV3);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,SAAgB,iCACd,QACsB;AACtB,KAAI,OAAO,SAAS,uBAAwB,QAAO,KAAA;AACnD,QAAO,OAAO,SAAS;;;;;;;;;AAUzB,SAAgB,2BACd,iBACsB;CACtB,IAAI;AACJ,KAAI;EACF,MAAM,OAAO,WAAW,gBAAgB,CAAC,SAAS,QAAQ;AAC1D,WAAS,KAAK,MAAM,KAAK;SACnB;AACN;;AAEF,QAAO,iCAAiC,OAA4C"}
|
package/dist/mutator/project.cjs
CHANGED
|
@@ -9,11 +9,11 @@ const require_index = require("../debug/index.cjs");
|
|
|
9
9
|
let _platforma_sdk_model = require("@platforma-sdk/model");
|
|
10
10
|
let _milaboratories_pl_model_middle_layer = require("@milaboratories/pl-model-middle-layer");
|
|
11
11
|
let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
|
|
12
|
+
let node_zlib = require("node:zlib");
|
|
12
13
|
let _milaboratories_pl_client = require("@milaboratories/pl-client");
|
|
13
14
|
let _milaboratories_pl_errors = require("@milaboratories/pl-errors");
|
|
14
15
|
let denque = require("denque");
|
|
15
16
|
denque = require_runtime.__toESM(denque);
|
|
16
|
-
let node_zlib = require("node:zlib");
|
|
17
17
|
//#region src/mutator/project.ts
|
|
18
18
|
function cached(modIdCb, valueCb) {
|
|
19
19
|
let initialized = false;
|
package/dist/mutator/project.js
CHANGED
|
@@ -8,10 +8,10 @@ import { getDebugFlags } from "../debug/index.js";
|
|
|
8
8
|
import { BLOCK_STORAGE_FACADE_VERSION, UiError, extractConfig } from "@platforma-sdk/model";
|
|
9
9
|
import { InitialBlockSettings } from "@milaboratories/pl-model-middle-layer";
|
|
10
10
|
import { ConsoleLoggerAdapter, cachedDecode, cachedDeserialize, canonicalJsonBytes, notEmpty } from "@milaboratories/ts-helpers";
|
|
11
|
+
import { gzipSync } from "node:zlib";
|
|
11
12
|
import { Pl, PlClient, ensureSignedResourceIdNotNull, field, isNotNullSignedResourceId, isNullSignedResourceId, isResource, isResourceId, isResourceRef } from "@milaboratories/pl-client";
|
|
12
13
|
import { ModelAPIVersionMismatchError } from "@milaboratories/pl-errors";
|
|
13
14
|
import Denque from "denque";
|
|
14
|
-
import { gzipSync } from "node:zlib";
|
|
15
15
|
//#region src/mutator/project.ts
|
|
16
16
|
function cached(modIdCb, valueCb) {
|
|
17
17
|
let initialized = false;
|
package/dist/pool/data.cjs
CHANGED
|
@@ -46,7 +46,7 @@ const ParquetChunkResourceType = (0, _milaboratories_pl_client.resourceType)("Pa
|
|
|
46
46
|
const BinaryPartitionedIndexFieldSuffix = ".index";
|
|
47
47
|
const BinaryPartitionedValuesFieldSuffix = ".values";
|
|
48
48
|
function parseDataInfoResource(data) {
|
|
49
|
-
if (!data.getIsReadyOrError())
|
|
49
|
+
if (!data.getIsReadyOrError()) return void 0;
|
|
50
50
|
const resourceData = data.getDataAsJson();
|
|
51
51
|
if (resourceData === void 0) throw new _platforma_sdk_model.PFrameDriverError("unexpected data info structure, no resource data");
|
|
52
52
|
if ((0, _milaboratories_pl_client.resourceTypesEqual)(data.resourceType, PColumnDataJson)) {
|
package/dist/pool/data.cjs.map
CHANGED
|
@@ -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): PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) throw new PFrameDriverError(\"Data not ready.\");\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":"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"}
|
package/dist/pool/data.js
CHANGED
|
@@ -44,7 +44,7 @@ const ParquetChunkResourceType = resourceType("ParquetChunk", "1");
|
|
|
44
44
|
const BinaryPartitionedIndexFieldSuffix = ".index";
|
|
45
45
|
const BinaryPartitionedValuesFieldSuffix = ".values";
|
|
46
46
|
function parseDataInfoResource(data) {
|
|
47
|
-
if (!data.getIsReadyOrError())
|
|
47
|
+
if (!data.getIsReadyOrError()) return void 0;
|
|
48
48
|
const resourceData = data.getDataAsJson();
|
|
49
49
|
if (resourceData === void 0) throw new PFrameDriverError("unexpected data info structure, no resource data");
|
|
50
50
|
if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {
|
package/dist/pool/data.js.map
CHANGED
|
@@ -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): PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) throw new PFrameDriverError(\"Data not ready.\");\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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"}
|
package/dist/pool/driver.cjs
CHANGED
|
@@ -176,7 +176,8 @@ async function createPFrameDriver(params) {
|
|
|
176
176
|
const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);
|
|
177
177
|
const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, { port: params.options.parquetServerPort });
|
|
178
178
|
const resolveDataInfo = (spec, data) => {
|
|
179
|
-
|
|
179
|
+
if ((0, _milaboratories_pl_tree.isPlTreeNodeAccessor)(data)) return require_data.parseDataInfoResource(data) ?? (0, _milaboratories_pf_driver.makeJsonDataInfo)(spec, []);
|
|
180
|
+
return (0, _platforma_sdk_model.isDataInfo)(data) ? data.type === "ParquetPartitioned" ? (0, _platforma_sdk_model.mapDataInfo)(data, (a) => require_data.traverseParquetChunkResource(a)) : (0, _platforma_sdk_model.mapDataInfo)(data, (a) => require_data.makeLocalBlobRef(a)) : (0, _milaboratories_pf_driver.makeJsonDataInfo)(spec, data);
|
|
180
181
|
};
|
|
181
182
|
return new _milaboratories_pf_driver.AbstractPFrameDriver({
|
|
182
183
|
logger,
|