@milaboratories/pl-middle-layer 1.50.1 → 1.52.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/cfg_render/executor.cjs +2 -2
- package/dist/cfg_render/executor.js +1 -1
- package/dist/debug/index.cjs +4 -1
- package/dist/debug/index.cjs.map +1 -1
- package/dist/debug/index.js +4 -1
- package/dist/debug/index.js.map +1 -1
- package/dist/index.cjs +14 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/js_render/computable_context.cjs +36 -4
- package/dist/js_render/computable_context.cjs.map +1 -1
- package/dist/js_render/computable_context.js +36 -4
- package/dist/js_render/computable_context.js.map +1 -1
- package/dist/js_render/context.cjs +36 -3
- package/dist/js_render/context.cjs.map +1 -1
- package/dist/js_render/context.js +36 -3
- package/dist/js_render/context.js.map +1 -1
- package/dist/js_render/index.cjs +5 -1
- package/dist/js_render/index.cjs.map +1 -1
- package/dist/js_render/index.js +5 -1
- package/dist/js_render/index.js.map +1 -1
- package/dist/js_render/spec_driver.cjs +43 -0
- package/dist/js_render/spec_driver.cjs.map +1 -0
- package/dist/js_render/spec_driver.js +42 -0
- package/dist/js_render/spec_driver.js.map +1 -0
- package/dist/middle_layer/project.cjs +8 -5
- package/dist/middle_layer/project.cjs.map +1 -1
- package/dist/middle_layer/project.js +8 -5
- package/dist/middle_layer/project.js.map +1 -1
- package/dist/middle_layer/project_overview.cjs +28 -22
- package/dist/middle_layer/project_overview.cjs.map +1 -1
- package/dist/middle_layer/project_overview.js +28 -22
- package/dist/middle_layer/project_overview.js.map +1 -1
- package/dist/model/block_pack_spec.cjs.map +1 -1
- package/dist/model/block_pack_spec.d.ts +2 -2
- package/dist/model/block_pack_spec.js.map +1 -1
- package/dist/model/project_helper.cjs.map +1 -1
- package/dist/model/project_helper.d.ts +2 -1
- package/dist/model/project_helper.js.map +1 -1
- package/dist/model/template_spec.d.ts +7 -2
- package/dist/mutator/block-pack/block_pack.cjs +20 -1
- package/dist/mutator/block-pack/block_pack.cjs.map +1 -1
- package/dist/mutator/block-pack/block_pack.d.ts +4 -0
- package/dist/mutator/block-pack/block_pack.js +19 -1
- package/dist/mutator/block-pack/block_pack.js.map +1 -1
- package/dist/mutator/template/template_cache.cjs +515 -0
- package/dist/mutator/template/template_cache.cjs.map +1 -0
- package/dist/mutator/template/template_cache.d.ts +78 -0
- package/dist/mutator/template/template_cache.js +502 -0
- package/dist/mutator/template/template_cache.js.map +1 -0
- package/dist/mutator/template/template_loading.cjs +3 -1
- package/dist/mutator/template/template_loading.cjs.map +1 -1
- package/dist/mutator/template/template_loading.js +3 -1
- package/dist/mutator/template/template_loading.js.map +1 -1
- package/package.json +18 -17
- package/src/debug/index.ts +6 -0
- package/src/index.ts +1 -0
- package/src/js_render/computable_context.ts +69 -4
- package/src/js_render/context.ts +58 -5
- package/src/js_render/index.ts +8 -1
- package/src/js_render/spec_driver.ts +55 -0
- package/src/middle_layer/project.ts +12 -8
- package/src/middle_layer/project_overview.ts +6 -0
- package/src/model/block_pack_spec.ts +2 -2
- package/src/model/project_helper.ts +2 -7
- package/src/model/template_spec.ts +11 -1
- package/src/mutator/block-pack/block_pack.ts +35 -1
- package/src/mutator/template/template_cache.test.ts +373 -0
- package/src/mutator/template/template_cache.ts +763 -0
- package/src/mutator/template/template_loading.ts +3 -0
|
@@ -30,7 +30,8 @@ async function prepareTemplateSpec(tpl) {
|
|
|
30
30
|
content: await node_fs.default.promises.readFile(tpl.path)
|
|
31
31
|
};
|
|
32
32
|
case "from-registry":
|
|
33
|
-
case "explicit":
|
|
33
|
+
case "explicit":
|
|
34
|
+
case "cached": return tpl;
|
|
34
35
|
case "prepared": return tpl;
|
|
35
36
|
default: return (0, _milaboratories_ts_helpers.assertNever)(tpl);
|
|
36
37
|
}
|
|
@@ -49,6 +50,7 @@ function loadTemplate(tx, spec) {
|
|
|
49
50
|
case "from-registry": return loadTemplateFromRegistry(tx, spec);
|
|
50
51
|
case "explicit": return require_direct_template_loader.loadTemplateFromExplicitDirect(tx, spec);
|
|
51
52
|
case "prepared": return require_direct_template_loader.loadTemplateFromPrepared(tx, spec);
|
|
53
|
+
case "cached": return spec.resourceId;
|
|
52
54
|
default: return (0, _milaboratories_ts_helpers.assertNever)(spec);
|
|
53
55
|
}
|
|
54
56
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template_loading.cjs","names":["fs","Pl","loadTemplateFromExplicitDirect","loadTemplateFromPrepared"],"sources":["../../../src/mutator/template/template_loading.ts"],"sourcesContent":["import type { AnyRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field, Pl } from \"@milaboratories/pl-client\";\nimport fs from \"node:fs\";\nimport type {\n TemplateFromRegistry,\n TemplateSpecAny,\n TemplateSpecPrepared,\n} from \"../../model/template_spec\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport { loadTemplateFromExplicitDirect, loadTemplateFromPrepared } from \"./direct_template_loader\";\n\n//\n// Resource schema\n//\n\nexport const TengoTemplateGet: ResourceType = { name: \"TengoTemplateGet\", version: \"1\" };\nexport const TengoTemplateGetRegistry = \"registry\";\nexport const TengoTemplateGetTemplateURI = \"templateURI\";\nexport const TengoTemplateGetTemplate = \"template\";\n\nexport const TengoTemplatePack: ResourceType = { name: \"TengoTemplatePack\", version: \"1\" };\nexport const TengoTemplatePackConvert: ResourceType = {\n name: \"TengoTemplatePackConvert\",\n version: \"1\",\n};\nexport const TengoTemplatePackConvertTemplatePack = \"templatePack\";\nexport const TengoTemplatePackConvertTemplate = \"template\";\n\nexport async function prepareTemplateSpec(tpl: TemplateSpecAny): Promise<TemplateSpecPrepared> {\n switch (tpl.type) {\n case \"from-file\":\n return {\n type: \"explicit\",\n content: await fs.promises.readFile(tpl.path),\n };\n case \"from-registry\":\n case \"explicit\":\n return tpl;\n case \"prepared\":\n return tpl;\n default:\n return assertNever(tpl);\n }\n}\n\nfunction loadTemplateFromRegistry(tx: PlTransaction, spec: TemplateFromRegistry): AnyRef {\n const getTemplate = tx.createStruct(TengoTemplateGet);\n const registry = field(getTemplate, TengoTemplateGetRegistry);\n const uri = field(getTemplate, TengoTemplateGetTemplateURI);\n const templateFromRegistry = field(getTemplate, TengoTemplateGetTemplate);\n\n // Note: it has a resource schema, so platforma creates fields by itself.\n\n tx.setField(registry, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.registry))));\n tx.setField(uri, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.path))));\n\n return templateFromRegistry;\n}\n\nexport function loadTemplate(tx: PlTransaction, spec: TemplateSpecPrepared): AnyRef {\n switch (spec.type) {\n case \"from-registry\":\n return loadTemplateFromRegistry(tx, spec);\n case \"explicit\":\n return loadTemplateFromExplicitDirect(tx, spec);\n case \"prepared\":\n return loadTemplateFromPrepared(tx, spec);\n default:\n return assertNever(spec);\n }\n}\n"],"mappings":";;;;;;;;AAeA,MAAa,mBAAiC;CAAE,MAAM;CAAoB,SAAS;CAAK;AACxF,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;AAC3C,MAAa,2BAA2B;AAExC,MAAa,oBAAkC;CAAE,MAAM;CAAqB,SAAS;CAAK;AAC1F,MAAa,2BAAyC;CACpD,MAAM;CACN,SAAS;CACV;AACD,MAAa,uCAAuC;AACpD,MAAa,mCAAmC;AAEhD,eAAsB,oBAAoB,KAAqD;AAC7F,SAAQ,IAAI,MAAZ;EACE,KAAK,YACH,QAAO;GACL,MAAM;GACN,SAAS,MAAMA,gBAAG,SAAS,SAAS,IAAI,KAAK;GAC9C;EACH,KAAK;EACL,KAAK,
|
|
1
|
+
{"version":3,"file":"template_loading.cjs","names":["fs","Pl","loadTemplateFromExplicitDirect","loadTemplateFromPrepared"],"sources":["../../../src/mutator/template/template_loading.ts"],"sourcesContent":["import type { AnyRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field, Pl } from \"@milaboratories/pl-client\";\nimport fs from \"node:fs\";\nimport type {\n TemplateFromRegistry,\n TemplateSpecAny,\n TemplateSpecPrepared,\n} from \"../../model/template_spec\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport { loadTemplateFromExplicitDirect, loadTemplateFromPrepared } from \"./direct_template_loader\";\n\n//\n// Resource schema\n//\n\nexport const TengoTemplateGet: ResourceType = { name: \"TengoTemplateGet\", version: \"1\" };\nexport const TengoTemplateGetRegistry = \"registry\";\nexport const TengoTemplateGetTemplateURI = \"templateURI\";\nexport const TengoTemplateGetTemplate = \"template\";\n\nexport const TengoTemplatePack: ResourceType = { name: \"TengoTemplatePack\", version: \"1\" };\nexport const TengoTemplatePackConvert: ResourceType = {\n name: \"TengoTemplatePackConvert\",\n version: \"1\",\n};\nexport const TengoTemplatePackConvertTemplatePack = \"templatePack\";\nexport const TengoTemplatePackConvertTemplate = \"template\";\n\nexport async function prepareTemplateSpec(tpl: TemplateSpecAny): Promise<TemplateSpecPrepared> {\n switch (tpl.type) {\n case \"from-file\":\n return {\n type: \"explicit\",\n content: await fs.promises.readFile(tpl.path),\n };\n case \"from-registry\":\n case \"explicit\":\n case \"cached\":\n return tpl;\n case \"prepared\":\n return tpl;\n default:\n return assertNever(tpl);\n }\n}\n\nfunction loadTemplateFromRegistry(tx: PlTransaction, spec: TemplateFromRegistry): AnyRef {\n const getTemplate = tx.createStruct(TengoTemplateGet);\n const registry = field(getTemplate, TengoTemplateGetRegistry);\n const uri = field(getTemplate, TengoTemplateGetTemplateURI);\n const templateFromRegistry = field(getTemplate, TengoTemplateGetTemplate);\n\n // Note: it has a resource schema, so platforma creates fields by itself.\n\n tx.setField(registry, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.registry))));\n tx.setField(uri, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.path))));\n\n return templateFromRegistry;\n}\n\nexport function loadTemplate(tx: PlTransaction, spec: TemplateSpecPrepared): AnyRef {\n switch (spec.type) {\n case \"from-registry\":\n return loadTemplateFromRegistry(tx, spec);\n case \"explicit\":\n return loadTemplateFromExplicitDirect(tx, spec);\n case \"prepared\":\n return loadTemplateFromPrepared(tx, spec);\n case \"cached\":\n return spec.resourceId;\n default:\n return assertNever(spec);\n }\n}\n"],"mappings":";;;;;;;;AAeA,MAAa,mBAAiC;CAAE,MAAM;CAAoB,SAAS;CAAK;AACxF,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;AAC3C,MAAa,2BAA2B;AAExC,MAAa,oBAAkC;CAAE,MAAM;CAAqB,SAAS;CAAK;AAC1F,MAAa,2BAAyC;CACpD,MAAM;CACN,SAAS;CACV;AACD,MAAa,uCAAuC;AACpD,MAAa,mCAAmC;AAEhD,eAAsB,oBAAoB,KAAqD;AAC7F,SAAQ,IAAI,MAAZ;EACE,KAAK,YACH,QAAO;GACL,MAAM;GACN,SAAS,MAAMA,gBAAG,SAAS,SAAS,IAAI,KAAK;GAC9C;EACH,KAAK;EACL,KAAK;EACL,KAAK,SACH,QAAO;EACT,KAAK,WACH,QAAO;EACT,QACE,oDAAmB,IAAI;;;AAI7B,SAAS,yBAAyB,IAAmB,MAAoC;CACvF,MAAM,cAAc,GAAG,aAAa,iBAAiB;CACrD,MAAM,gDAAiB,aAAa,yBAAyB;CAC7D,MAAM,2CAAY,aAAa,4BAA4B;CAC3D,MAAM,4DAA6B,aAAa,yBAAyB;AAIzE,IAAG,SAAS,UAAU,GAAG,YAAYC,6BAAG,YAAY,OAAO,KAAK,KAAK,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC;AAChG,IAAG,SAAS,KAAK,GAAG,YAAYA,6BAAG,YAAY,OAAO,KAAK,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC;AAEvF,QAAO;;AAGT,SAAgB,aAAa,IAAmB,MAAoC;AAClF,SAAQ,KAAK,MAAb;EACE,KAAK,gBACH,QAAO,yBAAyB,IAAI,KAAK;EAC3C,KAAK,WACH,QAAOC,8DAA+B,IAAI,KAAK;EACjD,KAAK,WACH,QAAOC,wDAAyB,IAAI,KAAK;EAC3C,KAAK,SACH,QAAO,KAAK;EACd,QACE,oDAAmB,KAAK"}
|
|
@@ -28,7 +28,8 @@ async function prepareTemplateSpec(tpl) {
|
|
|
28
28
|
content: await fs.promises.readFile(tpl.path)
|
|
29
29
|
};
|
|
30
30
|
case "from-registry":
|
|
31
|
-
case "explicit":
|
|
31
|
+
case "explicit":
|
|
32
|
+
case "cached": return tpl;
|
|
32
33
|
case "prepared": return tpl;
|
|
33
34
|
default: return assertNever(tpl);
|
|
34
35
|
}
|
|
@@ -47,6 +48,7 @@ function loadTemplate(tx, spec) {
|
|
|
47
48
|
case "from-registry": return loadTemplateFromRegistry(tx, spec);
|
|
48
49
|
case "explicit": return loadTemplateFromExplicitDirect(tx, spec);
|
|
49
50
|
case "prepared": return loadTemplateFromPrepared(tx, spec);
|
|
51
|
+
case "cached": return spec.resourceId;
|
|
50
52
|
default: return assertNever(spec);
|
|
51
53
|
}
|
|
52
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template_loading.js","names":[],"sources":["../../../src/mutator/template/template_loading.ts"],"sourcesContent":["import type { AnyRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field, Pl } from \"@milaboratories/pl-client\";\nimport fs from \"node:fs\";\nimport type {\n TemplateFromRegistry,\n TemplateSpecAny,\n TemplateSpecPrepared,\n} from \"../../model/template_spec\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport { loadTemplateFromExplicitDirect, loadTemplateFromPrepared } from \"./direct_template_loader\";\n\n//\n// Resource schema\n//\n\nexport const TengoTemplateGet: ResourceType = { name: \"TengoTemplateGet\", version: \"1\" };\nexport const TengoTemplateGetRegistry = \"registry\";\nexport const TengoTemplateGetTemplateURI = \"templateURI\";\nexport const TengoTemplateGetTemplate = \"template\";\n\nexport const TengoTemplatePack: ResourceType = { name: \"TengoTemplatePack\", version: \"1\" };\nexport const TengoTemplatePackConvert: ResourceType = {\n name: \"TengoTemplatePackConvert\",\n version: \"1\",\n};\nexport const TengoTemplatePackConvertTemplatePack = \"templatePack\";\nexport const TengoTemplatePackConvertTemplate = \"template\";\n\nexport async function prepareTemplateSpec(tpl: TemplateSpecAny): Promise<TemplateSpecPrepared> {\n switch (tpl.type) {\n case \"from-file\":\n return {\n type: \"explicit\",\n content: await fs.promises.readFile(tpl.path),\n };\n case \"from-registry\":\n case \"explicit\":\n return tpl;\n case \"prepared\":\n return tpl;\n default:\n return assertNever(tpl);\n }\n}\n\nfunction loadTemplateFromRegistry(tx: PlTransaction, spec: TemplateFromRegistry): AnyRef {\n const getTemplate = tx.createStruct(TengoTemplateGet);\n const registry = field(getTemplate, TengoTemplateGetRegistry);\n const uri = field(getTemplate, TengoTemplateGetTemplateURI);\n const templateFromRegistry = field(getTemplate, TengoTemplateGetTemplate);\n\n // Note: it has a resource schema, so platforma creates fields by itself.\n\n tx.setField(registry, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.registry))));\n tx.setField(uri, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.path))));\n\n return templateFromRegistry;\n}\n\nexport function loadTemplate(tx: PlTransaction, spec: TemplateSpecPrepared): AnyRef {\n switch (spec.type) {\n case \"from-registry\":\n return loadTemplateFromRegistry(tx, spec);\n case \"explicit\":\n return loadTemplateFromExplicitDirect(tx, spec);\n case \"prepared\":\n return loadTemplateFromPrepared(tx, spec);\n default:\n return assertNever(spec);\n }\n}\n"],"mappings":";;;;;;AAeA,MAAa,mBAAiC;CAAE,MAAM;CAAoB,SAAS;CAAK;AACxF,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;AAC3C,MAAa,2BAA2B;AAExC,MAAa,oBAAkC;CAAE,MAAM;CAAqB,SAAS;CAAK;AAC1F,MAAa,2BAAyC;CACpD,MAAM;CACN,SAAS;CACV;AACD,MAAa,uCAAuC;AACpD,MAAa,mCAAmC;AAEhD,eAAsB,oBAAoB,KAAqD;AAC7F,SAAQ,IAAI,MAAZ;EACE,KAAK,YACH,QAAO;GACL,MAAM;GACN,SAAS,MAAM,GAAG,SAAS,SAAS,IAAI,KAAK;GAC9C;EACH,KAAK;EACL,KAAK,
|
|
1
|
+
{"version":3,"file":"template_loading.js","names":[],"sources":["../../../src/mutator/template/template_loading.ts"],"sourcesContent":["import type { AnyRef, PlTransaction, ResourceType } from \"@milaboratories/pl-client\";\nimport { field, Pl } from \"@milaboratories/pl-client\";\nimport fs from \"node:fs\";\nimport type {\n TemplateFromRegistry,\n TemplateSpecAny,\n TemplateSpecPrepared,\n} from \"../../model/template_spec\";\nimport { assertNever } from \"@milaboratories/ts-helpers\";\nimport { loadTemplateFromExplicitDirect, loadTemplateFromPrepared } from \"./direct_template_loader\";\n\n//\n// Resource schema\n//\n\nexport const TengoTemplateGet: ResourceType = { name: \"TengoTemplateGet\", version: \"1\" };\nexport const TengoTemplateGetRegistry = \"registry\";\nexport const TengoTemplateGetTemplateURI = \"templateURI\";\nexport const TengoTemplateGetTemplate = \"template\";\n\nexport const TengoTemplatePack: ResourceType = { name: \"TengoTemplatePack\", version: \"1\" };\nexport const TengoTemplatePackConvert: ResourceType = {\n name: \"TengoTemplatePackConvert\",\n version: \"1\",\n};\nexport const TengoTemplatePackConvertTemplatePack = \"templatePack\";\nexport const TengoTemplatePackConvertTemplate = \"template\";\n\nexport async function prepareTemplateSpec(tpl: TemplateSpecAny): Promise<TemplateSpecPrepared> {\n switch (tpl.type) {\n case \"from-file\":\n return {\n type: \"explicit\",\n content: await fs.promises.readFile(tpl.path),\n };\n case \"from-registry\":\n case \"explicit\":\n case \"cached\":\n return tpl;\n case \"prepared\":\n return tpl;\n default:\n return assertNever(tpl);\n }\n}\n\nfunction loadTemplateFromRegistry(tx: PlTransaction, spec: TemplateFromRegistry): AnyRef {\n const getTemplate = tx.createStruct(TengoTemplateGet);\n const registry = field(getTemplate, TengoTemplateGetRegistry);\n const uri = field(getTemplate, TengoTemplateGetTemplateURI);\n const templateFromRegistry = field(getTemplate, TengoTemplateGetTemplate);\n\n // Note: it has a resource schema, so platforma creates fields by itself.\n\n tx.setField(registry, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.registry))));\n tx.setField(uri, tx.createValue(Pl.JsonString, Buffer.from(JSON.stringify(spec.path))));\n\n return templateFromRegistry;\n}\n\nexport function loadTemplate(tx: PlTransaction, spec: TemplateSpecPrepared): AnyRef {\n switch (spec.type) {\n case \"from-registry\":\n return loadTemplateFromRegistry(tx, spec);\n case \"explicit\":\n return loadTemplateFromExplicitDirect(tx, spec);\n case \"prepared\":\n return loadTemplateFromPrepared(tx, spec);\n case \"cached\":\n return spec.resourceId;\n default:\n return assertNever(spec);\n }\n}\n"],"mappings":";;;;;;AAeA,MAAa,mBAAiC;CAAE,MAAM;CAAoB,SAAS;CAAK;AACxF,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;AAC3C,MAAa,2BAA2B;AAExC,MAAa,oBAAkC;CAAE,MAAM;CAAqB,SAAS;CAAK;AAC1F,MAAa,2BAAyC;CACpD,MAAM;CACN,SAAS;CACV;AACD,MAAa,uCAAuC;AACpD,MAAa,mCAAmC;AAEhD,eAAsB,oBAAoB,KAAqD;AAC7F,SAAQ,IAAI,MAAZ;EACE,KAAK,YACH,QAAO;GACL,MAAM;GACN,SAAS,MAAM,GAAG,SAAS,SAAS,IAAI,KAAK;GAC9C;EACH,KAAK;EACL,KAAK;EACL,KAAK,SACH,QAAO;EACT,KAAK,WACH,QAAO;EACT,QACE,QAAO,YAAY,IAAI;;;AAI7B,SAAS,yBAAyB,IAAmB,MAAoC;CACvF,MAAM,cAAc,GAAG,aAAa,iBAAiB;CACrD,MAAM,WAAW,MAAM,aAAa,yBAAyB;CAC7D,MAAM,MAAM,MAAM,aAAa,4BAA4B;CAC3D,MAAM,uBAAuB,MAAM,aAAa,yBAAyB;AAIzE,IAAG,SAAS,UAAU,GAAG,YAAY,GAAG,YAAY,OAAO,KAAK,KAAK,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC;AAChG,IAAG,SAAS,KAAK,GAAG,YAAY,GAAG,YAAY,OAAO,KAAK,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC;AAEvF,QAAO;;AAGT,SAAgB,aAAa,IAAmB,MAAoC;AAClF,SAAQ,KAAK,MAAb;EACE,KAAK,gBACH,QAAO,yBAAyB,IAAI,KAAK;EAC3C,KAAK,WACH,QAAO,+BAA+B,IAAI,KAAK;EACjD,KAAK,WACH,QAAO,yBAAyB,IAAI,KAAK;EAC3C,KAAK,SACH,QAAO,KAAK;EACd,QACE,QAAO,YAAY,KAAK"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-middle-layer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.52.0",
|
|
4
4
|
"description": "Pl Middle Layer",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@milaboratories/pframes-rs-node": "1.1.14",
|
|
23
|
+
"@milaboratories/pframes-rs-wasm": "1.1.14",
|
|
23
24
|
"canonicalize": "~2.1.0",
|
|
24
25
|
"denque": "^2.1.0",
|
|
25
26
|
"es-toolkit": "^1.39.10",
|
|
@@ -29,22 +30,22 @@
|
|
|
29
30
|
"utility-types": "^3.11.0",
|
|
30
31
|
"yaml": "^2.8.0",
|
|
31
32
|
"zod": "~3.23.8",
|
|
32
|
-
"@milaboratories/pf-driver": "1.0
|
|
33
|
-
"@milaboratories/pl-
|
|
34
|
-
"@milaboratories/pl-
|
|
35
|
-
"@milaboratories/computable": "2.
|
|
36
|
-
"@milaboratories/pl-errors": "1.
|
|
33
|
+
"@milaboratories/pf-driver": "1.1.0",
|
|
34
|
+
"@milaboratories/pl-client": "2.18.0",
|
|
35
|
+
"@milaboratories/pl-deployments": "2.16.0",
|
|
36
|
+
"@milaboratories/computable": "2.9.0",
|
|
37
|
+
"@milaboratories/pl-errors": "1.2.0",
|
|
38
|
+
"@milaboratories/pl-drivers": "1.12.1",
|
|
37
39
|
"@milaboratories/pl-http": "1.2.4",
|
|
38
|
-
"@milaboratories/pl-model-
|
|
39
|
-
"@milaboratories/pl-
|
|
40
|
-
"@milaboratories/pl-
|
|
41
|
-
"@milaboratories/pl-model-
|
|
42
|
-
"@milaboratories/resolve-helper": "1.1.3",
|
|
43
|
-
"@milaboratories/pl-tree": "1.8.52",
|
|
40
|
+
"@milaboratories/pl-model-backend": "1.2.0",
|
|
41
|
+
"@milaboratories/pl-model-common": "1.27.0",
|
|
42
|
+
"@milaboratories/pl-tree": "1.9.1",
|
|
43
|
+
"@milaboratories/pl-model-middle-layer": "1.14.0",
|
|
44
44
|
"@milaboratories/ts-helpers": "1.7.3",
|
|
45
|
-
"@
|
|
46
|
-
"@platforma-sdk/
|
|
47
|
-
"@platforma-sdk/
|
|
45
|
+
"@milaboratories/resolve-helper": "1.1.3",
|
|
46
|
+
"@platforma-sdk/block-tools": "2.7.0",
|
|
47
|
+
"@platforma-sdk/model": "1.60.0",
|
|
48
|
+
"@platforma-sdk/workflow-tengo": "5.11.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@types/node": "~24.5.2",
|
|
@@ -54,8 +55,8 @@
|
|
|
54
55
|
"typescript": "~5.9.3",
|
|
55
56
|
"vitest": "^4.0.18",
|
|
56
57
|
"@milaboratories/build-configs": "1.5.2",
|
|
57
|
-
"@milaboratories/ts-
|
|
58
|
-
"@milaboratories/ts-
|
|
58
|
+
"@milaboratories/ts-configs": "1.2.2",
|
|
59
|
+
"@milaboratories/ts-builder": "1.3.0"
|
|
59
60
|
},
|
|
60
61
|
"engines": {
|
|
61
62
|
"node": ">=22.19.0"
|
package/src/debug/index.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export type MlDebugFlags = {
|
|
2
2
|
logTreeStats?: "cumulative" | "per-request";
|
|
3
3
|
logProjectMutationStat: boolean;
|
|
4
|
+
logTemplateCacheStat: boolean;
|
|
4
5
|
dumpInitialTreeState: boolean;
|
|
5
6
|
logOutputStatus?: "any" | "unstable-only";
|
|
6
7
|
logOutputRecalculations?: boolean;
|
|
8
|
+
logProjectOverviewStat: boolean;
|
|
9
|
+
logJsExecStat: boolean;
|
|
7
10
|
};
|
|
8
11
|
|
|
9
12
|
let flags: MlDebugFlags | undefined = undefined;
|
|
@@ -12,7 +15,10 @@ export function getDebugFlags() {
|
|
|
12
15
|
flags = {
|
|
13
16
|
dumpInitialTreeState: process.env.MI_DUMP_INITIAL_TREE_STATE !== undefined,
|
|
14
17
|
logProjectMutationStat: process.env.MI_LOG_PROJECT_MUTATION_STAT !== undefined,
|
|
18
|
+
logTemplateCacheStat: process.env.MI_LOG_TEMPLATE_CACHE_STAT !== undefined,
|
|
15
19
|
logOutputRecalculations: process.env.MI_LOG_OUTPUT_RECALCULATIONS !== undefined,
|
|
20
|
+
logProjectOverviewStat: process.env.MI_LOG_PROJECT_OVERVIEW_STAT !== undefined,
|
|
21
|
+
logJsExecStat: process.env.MI_LOG_JS_EXEC_STAT !== undefined,
|
|
16
22
|
};
|
|
17
23
|
if (process.env.MI_LOG_OUTPUT_STATUS)
|
|
18
24
|
flags.logOutputStatus =
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export type { InternalLsDriver } from "@milaboratories/pl-drivers";
|
|
|
19
19
|
|
|
20
20
|
// for tests etc..
|
|
21
21
|
export * from "./mutator/template/template_loading";
|
|
22
|
+
export * from "./mutator/template/template_cache";
|
|
22
23
|
export * from "./mutator/template/render_template";
|
|
23
24
|
export * from "./model/template_spec";
|
|
24
25
|
|
|
@@ -44,6 +44,13 @@ import type { ResultPool } from "../pool/result_pool";
|
|
|
44
44
|
import type { JsExecutionContext } from "./context";
|
|
45
45
|
import type { VmFunctionImplementation } from "quickjs-emscripten";
|
|
46
46
|
import { Scope, type QuickJSHandle } from "quickjs-emscripten";
|
|
47
|
+
import type {
|
|
48
|
+
DiscoverColumnsRequest,
|
|
49
|
+
DiscoverColumnsResponse,
|
|
50
|
+
PColumnSpec,
|
|
51
|
+
SpecFrameHandle,
|
|
52
|
+
} from "@milaboratories/pl-model-common";
|
|
53
|
+
import { SpecDriver } from "./spec_driver";
|
|
47
54
|
|
|
48
55
|
function bytesToBase64(data: Uint8Array | undefined): string | undefined {
|
|
49
56
|
return data !== undefined ? Buffer.from(data).toString("base64") : undefined;
|
|
@@ -57,8 +64,17 @@ export class ComputableContextHelper implements JsRenderInternal.GlobalCfgRender
|
|
|
57
64
|
|
|
58
65
|
private computableCtx: ComputableCtx | undefined;
|
|
59
66
|
private readonly accessors = new Map<string, PlTreeNodeAccessor | undefined>();
|
|
67
|
+
private readonly specDriver = new SpecDriver();
|
|
60
68
|
|
|
61
|
-
private
|
|
69
|
+
private _meta: Map<string, Block> | undefined;
|
|
70
|
+
private get meta(): Map<string, Block> {
|
|
71
|
+
if (this._meta === undefined) {
|
|
72
|
+
if (this.computableCtx === undefined)
|
|
73
|
+
throw new Error("blockMeta can't be resolved in this context");
|
|
74
|
+
this._meta = this.blockCtx.blockMeta(this.computableCtx);
|
|
75
|
+
}
|
|
76
|
+
return this._meta;
|
|
77
|
+
}
|
|
62
78
|
|
|
63
79
|
constructor(
|
|
64
80
|
private readonly parent: JsExecutionContext,
|
|
@@ -68,7 +84,6 @@ export class ComputableContextHelper implements JsRenderInternal.GlobalCfgRender
|
|
|
68
84
|
computableCtx: ComputableCtx,
|
|
69
85
|
) {
|
|
70
86
|
this.computableCtx = computableCtx;
|
|
71
|
-
this.meta = blockCtx.blockMeta(computableCtx);
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
public resetComputableCtx() {
|
|
@@ -426,6 +441,27 @@ export class ComputableContextHelper implements JsRenderInternal.GlobalCfgRender
|
|
|
426
441
|
return key;
|
|
427
442
|
}
|
|
428
443
|
|
|
444
|
+
//
|
|
445
|
+
// Spec Frames
|
|
446
|
+
//
|
|
447
|
+
|
|
448
|
+
public createSpecFrame(specs: Record<string, PColumnSpec>): SpecFrameHandle {
|
|
449
|
+
const handle = this.specDriver.createSpecFrame(specs);
|
|
450
|
+
this.computableCtx?.addOnDestroy(() => this.specDriver.disposeSpecFrame(handle));
|
|
451
|
+
return handle;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
public specFrameDiscoverColumns(
|
|
455
|
+
handle: SpecFrameHandle,
|
|
456
|
+
request: DiscoverColumnsRequest,
|
|
457
|
+
): DiscoverColumnsResponse {
|
|
458
|
+
return this.specDriver.specFrameDiscoverColumns(handle as SpecFrameHandle, request);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
public specFrameDispose(handle: SpecFrameHandle): void {
|
|
462
|
+
this.specDriver.disposeSpecFrame(handle as SpecFrameHandle);
|
|
463
|
+
}
|
|
464
|
+
|
|
429
465
|
/**
|
|
430
466
|
* Transforms input data for PFrame/PTable creation
|
|
431
467
|
* - Converts string handles to accessors
|
|
@@ -504,11 +540,15 @@ export class ComputableContextHelper implements JsRenderInternal.GlobalCfgRender
|
|
|
504
540
|
// QuickJS strips all fields from errors apart from 'name' and 'message'.
|
|
505
541
|
// That's why here we need to store them, and rethrow them when we exit
|
|
506
542
|
// from QuickJS code.
|
|
543
|
+
const t0 = performance.now();
|
|
507
544
|
try {
|
|
508
545
|
return (fn as any)(...args);
|
|
509
546
|
} catch (e: unknown) {
|
|
510
547
|
const newErr = parent.errorRepo.setAndRecreateForQuickJS(e);
|
|
511
548
|
throw vm.newError(newErr);
|
|
549
|
+
} finally {
|
|
550
|
+
parent.stats.ctxMethodCalls++;
|
|
551
|
+
parent.stats.ctxMethodMs += performance.now() - t0;
|
|
512
552
|
}
|
|
513
553
|
};
|
|
514
554
|
|
|
@@ -648,11 +688,11 @@ export class ComputableContextHelper implements JsRenderInternal.GlobalCfgRender
|
|
|
648
688
|
});
|
|
649
689
|
|
|
650
690
|
exportCtxFunction("listOutputFields", (handle) => {
|
|
651
|
-
return parent.exportObjectViaJson(this.
|
|
691
|
+
return parent.exportObjectViaJson(this.listOutputFields(vm.getString(handle)), undefined);
|
|
652
692
|
});
|
|
653
693
|
|
|
654
694
|
exportCtxFunction("listDynamicFields", (handle) => {
|
|
655
|
-
return parent.exportObjectViaJson(this.
|
|
695
|
+
return parent.exportObjectViaJson(this.listDynamicFields(vm.getString(handle)), undefined);
|
|
656
696
|
});
|
|
657
697
|
|
|
658
698
|
exportCtxFunction("getKeyValueBase64", (handle, key) => {
|
|
@@ -858,6 +898,31 @@ export class ComputableContextHelper implements JsRenderInternal.GlobalCfgRender
|
|
|
858
898
|
);
|
|
859
899
|
});
|
|
860
900
|
|
|
901
|
+
//
|
|
902
|
+
// Spec Frames
|
|
903
|
+
//
|
|
904
|
+
|
|
905
|
+
exportCtxFunction("createSpecFrame", (specs) => {
|
|
906
|
+
return parent.exportSingleValue(
|
|
907
|
+
this.createSpecFrame(parent.importObjectViaJson(specs) as Record<string, PColumnSpec>),
|
|
908
|
+
undefined,
|
|
909
|
+
);
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
exportCtxFunction("specFrameDiscoverColumns", (handle, request) => {
|
|
913
|
+
return parent.exportObjectViaJson(
|
|
914
|
+
this.specFrameDiscoverColumns(
|
|
915
|
+
vm.getString(handle) as SpecFrameHandle,
|
|
916
|
+
parent.importObjectViaJson(request) as DiscoverColumnsRequest,
|
|
917
|
+
),
|
|
918
|
+
undefined,
|
|
919
|
+
);
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
exportCtxFunction("specFrameDispose", (handle) => {
|
|
923
|
+
this.specFrameDispose(vm.getString(handle) as SpecFrameHandle);
|
|
924
|
+
});
|
|
925
|
+
|
|
861
926
|
//
|
|
862
927
|
// Computable
|
|
863
928
|
//
|
package/src/js_render/context.ts
CHANGED
|
@@ -39,6 +39,26 @@ export type ComputableEnv = {
|
|
|
39
39
|
computableCtx: ComputableCtx;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
/** Execution stats accumulated during the lifetime of a JsExecutionContext. */
|
|
43
|
+
export type JsExecStats = {
|
|
44
|
+
bundleEvalMs: number;
|
|
45
|
+
bundleBytes: number;
|
|
46
|
+
|
|
47
|
+
callbackMs: number;
|
|
48
|
+
callbackCount: number;
|
|
49
|
+
|
|
50
|
+
serInMs: number;
|
|
51
|
+
serInBytes: number;
|
|
52
|
+
serInCalls: number;
|
|
53
|
+
|
|
54
|
+
serOutMs: number;
|
|
55
|
+
serOutBytes: number;
|
|
56
|
+
serOutCalls: number;
|
|
57
|
+
|
|
58
|
+
ctxMethodCalls: number;
|
|
59
|
+
ctxMethodMs: number;
|
|
60
|
+
};
|
|
61
|
+
|
|
42
62
|
export class JsExecutionContext {
|
|
43
63
|
private readonly callbackRegistry: QuickJSHandle;
|
|
44
64
|
private readonly fnJSONStringify: QuickJSHandle;
|
|
@@ -48,6 +68,21 @@ export class JsExecutionContext {
|
|
|
48
68
|
|
|
49
69
|
public readonly computableHelper: ComputableContextHelper | undefined;
|
|
50
70
|
|
|
71
|
+
public readonly stats: JsExecStats = {
|
|
72
|
+
bundleEvalMs: 0,
|
|
73
|
+
bundleBytes: 0,
|
|
74
|
+
callbackMs: 0,
|
|
75
|
+
callbackCount: 0,
|
|
76
|
+
serInMs: 0,
|
|
77
|
+
serInBytes: 0,
|
|
78
|
+
serInCalls: 0,
|
|
79
|
+
serOutMs: 0,
|
|
80
|
+
serOutBytes: 0,
|
|
81
|
+
serOutCalls: 0,
|
|
82
|
+
ctxMethodCalls: 0,
|
|
83
|
+
ctxMethodMs: 0,
|
|
84
|
+
};
|
|
85
|
+
|
|
51
86
|
/**
|
|
52
87
|
* Creates a new JS execution context.
|
|
53
88
|
*
|
|
@@ -111,6 +146,7 @@ export class JsExecutionContext {
|
|
|
111
146
|
// }
|
|
112
147
|
|
|
113
148
|
public evaluateBundle(code: string) {
|
|
149
|
+
const t0 = performance.now();
|
|
114
150
|
try {
|
|
115
151
|
this.deadlineSetter({
|
|
116
152
|
currentExecutionTarget: "evaluateBundle",
|
|
@@ -122,10 +158,13 @@ export class JsExecutionContext {
|
|
|
122
158
|
throw err;
|
|
123
159
|
} finally {
|
|
124
160
|
this.deadlineSetter(undefined);
|
|
161
|
+
this.stats.bundleEvalMs += performance.now() - t0;
|
|
162
|
+
this.stats.bundleBytes += code.length;
|
|
125
163
|
}
|
|
126
164
|
}
|
|
127
165
|
|
|
128
166
|
public runCallback(cbName: string, ...args: unknown[]): QuickJSHandle {
|
|
167
|
+
const t0 = performance.now();
|
|
129
168
|
try {
|
|
130
169
|
this.deadlineSetter({ currentExecutionTarget: cbName, deadline: Date.now() + 10000 });
|
|
131
170
|
return Scope.withScope((localScope) => {
|
|
@@ -150,6 +189,8 @@ export class JsExecutionContext {
|
|
|
150
189
|
throw original;
|
|
151
190
|
} finally {
|
|
152
191
|
this.deadlineSetter(undefined);
|
|
192
|
+
this.stats.callbackMs += performance.now() - t0;
|
|
193
|
+
this.stats.callbackCount++;
|
|
153
194
|
}
|
|
154
195
|
}
|
|
155
196
|
|
|
@@ -210,11 +251,16 @@ export class JsExecutionContext {
|
|
|
210
251
|
}
|
|
211
252
|
|
|
212
253
|
public exportObjectViaJson(obj: unknown, scope: Scope | undefined): QuickJSHandle {
|
|
254
|
+
const t0 = performance.now();
|
|
255
|
+
const json = JSON.stringify(obj);
|
|
256
|
+
this.stats.serInBytes += json.length;
|
|
257
|
+
this.stats.serInCalls++;
|
|
213
258
|
const result = this.vm
|
|
214
|
-
.newString(
|
|
215
|
-
.consume((
|
|
216
|
-
this.vm.unwrapResult(this.vm.callFunction(this.fnJSONParse, this.vm.undefined,
|
|
259
|
+
.newString(json)
|
|
260
|
+
.consume((jsonHandle) =>
|
|
261
|
+
this.vm.unwrapResult(this.vm.callFunction(this.fnJSONParse, this.vm.undefined, jsonHandle)),
|
|
217
262
|
);
|
|
263
|
+
this.stats.serInMs += performance.now() - t0;
|
|
218
264
|
return scope !== undefined ? scope.manage(result) : result;
|
|
219
265
|
}
|
|
220
266
|
|
|
@@ -233,13 +279,20 @@ export class JsExecutionContext {
|
|
|
233
279
|
}
|
|
234
280
|
|
|
235
281
|
public importObjectViaJson(handle: QuickJSHandle): unknown {
|
|
282
|
+
const t0 = performance.now();
|
|
236
283
|
const text = this.vm
|
|
237
284
|
.unwrapResult(this.vm.callFunction(this.fnJSONStringify, this.vm.undefined, handle))
|
|
238
285
|
.consume((strHandle) => this.vm.getString(strHandle));
|
|
239
|
-
|
|
286
|
+
this.stats.serOutBytes += text.length;
|
|
287
|
+
this.stats.serOutCalls++;
|
|
288
|
+
if (text === "undefined") {
|
|
240
289
|
// special case with futures
|
|
290
|
+
this.stats.serOutMs += performance.now() - t0;
|
|
241
291
|
return undefined;
|
|
242
|
-
|
|
292
|
+
}
|
|
293
|
+
const result = JSON.parse(text);
|
|
294
|
+
this.stats.serOutMs += performance.now() - t0;
|
|
295
|
+
return result;
|
|
243
296
|
}
|
|
244
297
|
|
|
245
298
|
private injectCtx() {
|
package/src/js_render/index.ts
CHANGED
|
@@ -135,6 +135,8 @@ export function computableFromRF(
|
|
|
135
135
|
|
|
136
136
|
if (Object.keys(toBeResolved).length === 0) {
|
|
137
137
|
const importedResult = rCtx.importObjectUniversal(result);
|
|
138
|
+
if (getDebugFlags().logJsExecStat)
|
|
139
|
+
console.log(`[jsExec] ${key}: ${JSON.stringify(rCtx.stats)}`);
|
|
138
140
|
logOutputStatus(
|
|
139
141
|
fh.handle,
|
|
140
142
|
importedResult,
|
|
@@ -161,6 +163,8 @@ export function computableFromRF(
|
|
|
161
163
|
|
|
162
164
|
// logging
|
|
163
165
|
recalculationCounter++;
|
|
166
|
+
if (getDebugFlags().logJsExecStat)
|
|
167
|
+
console.log(`[jsExec] ${key} #${recalculationCounter}: ${JSON.stringify(rCtx.stats)}`);
|
|
164
168
|
logOutputStatus(fh.handle, renderedResult, stable, recalculationCounter, unstableMarker);
|
|
165
169
|
|
|
166
170
|
return renderedResult;
|
|
@@ -208,7 +212,10 @@ export function executeSingleLambda(
|
|
|
208
212
|
rCtx.evaluateBundle(code.content);
|
|
209
213
|
|
|
210
214
|
// Running the lambda with arguments (e.g., state for args(), args for enrichmentTargets())
|
|
211
|
-
|
|
215
|
+
const importedResult = rCtx.importObjectUniversal(rCtx.runCallback(fh.handle, ...args));
|
|
216
|
+
if (getDebugFlags().logJsExecStat)
|
|
217
|
+
console.log(`[jsExec] ${fh.handle}: ${JSON.stringify(rCtx.stats)}`);
|
|
218
|
+
return importedResult;
|
|
212
219
|
} finally {
|
|
213
220
|
scope.dispose();
|
|
214
221
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createPFrame } from "@milaboratories/pframes-rs-wasm";
|
|
2
|
+
import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
3
|
+
import type {
|
|
4
|
+
PColumnSpec,
|
|
5
|
+
PSpecDriver,
|
|
6
|
+
SpecFrameHandle,
|
|
7
|
+
DiscoverColumnsRequest,
|
|
8
|
+
DiscoverColumnsResponse,
|
|
9
|
+
} from "@milaboratories/pl-model-common";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Manages spec-only PFrame instances (WASM) with handle-based lifecycle.
|
|
14
|
+
*
|
|
15
|
+
* All operations are synchronous — WASM computes results immediately.
|
|
16
|
+
*/
|
|
17
|
+
export class SpecDriver implements PSpecDriver {
|
|
18
|
+
private readonly frames = new Map<string, PFrameInternal.PFrameWasm>();
|
|
19
|
+
|
|
20
|
+
createSpecFrame(specs: Record<string, PColumnSpec>): SpecFrameHandle {
|
|
21
|
+
const frame = createPFrame(specs);
|
|
22
|
+
const handle = randomUUID() as SpecFrameHandle;
|
|
23
|
+
this.frames.set(handle, frame);
|
|
24
|
+
return handle;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
specFrameDiscoverColumns(
|
|
28
|
+
handle: SpecFrameHandle,
|
|
29
|
+
request: DiscoverColumnsRequest,
|
|
30
|
+
): DiscoverColumnsResponse {
|
|
31
|
+
return this.getFrame(handle).discoverColumns(request);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
disposeSpecFrame(handle: SpecFrameHandle): void {
|
|
35
|
+
const frame = this.frames.get(handle);
|
|
36
|
+
if (frame) {
|
|
37
|
+
frame[Symbol.dispose]();
|
|
38
|
+
this.frames.delete(handle);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Dispose all managed spec frames. */
|
|
43
|
+
disposeAll(): void {
|
|
44
|
+
for (const frame of this.frames.values()) {
|
|
45
|
+
frame[Symbol.dispose]();
|
|
46
|
+
}
|
|
47
|
+
this.frames.clear();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private getFrame(handle: string): PFrameInternal.PFrameWasm {
|
|
51
|
+
const frame = this.frames.get(handle);
|
|
52
|
+
if (frame === undefined) throw new Error(`No such spec frame: ${handle}`);
|
|
53
|
+
return frame;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -47,6 +47,7 @@ import canonicalize from "canonicalize";
|
|
|
47
47
|
import type { ProjectOverviewLight } from "./project_overview_light";
|
|
48
48
|
import { projectOverviewLight } from "./project_overview_light";
|
|
49
49
|
import { applyProjectMigrations } from "../mutator/migration";
|
|
50
|
+
import { cacheBlockPackTemplate } from "../mutator/template/template_cache";
|
|
50
51
|
|
|
51
52
|
type BlockStateComputables = {
|
|
52
53
|
readonly fullState: Computable<BlockStateInternalV3>;
|
|
@@ -210,18 +211,20 @@ export class Project {
|
|
|
210
211
|
blockId: string = randomUUID(),
|
|
211
212
|
): Promise<string> {
|
|
212
213
|
const preparedBp = await this.env.bpPreparer.prepare(blockPackSpec);
|
|
213
|
-
const
|
|
214
|
-
const blockCfg = extractConfig(blockCfgContainer); // full content of this var should never be persisted
|
|
214
|
+
const blockCfg = extractConfig(preparedBp.config);
|
|
215
215
|
|
|
216
216
|
this.env.runtimeCapabilities.throwIfIncompatible(blockCfg.featureFlags);
|
|
217
217
|
|
|
218
|
+
// Pre-materialize template via cache (separate transaction(s))
|
|
219
|
+
const cachedBp = await cacheBlockPackTemplate(this.env.pl, preparedBp);
|
|
220
|
+
|
|
218
221
|
// Build NewBlockSpec based on model API version
|
|
219
222
|
const newBlockSpec =
|
|
220
223
|
blockCfg.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION
|
|
221
|
-
? { storageMode: "fromModel" as const, blockPack:
|
|
224
|
+
? { storageMode: "fromModel" as const, blockPack: cachedBp }
|
|
222
225
|
: {
|
|
223
226
|
storageMode: "legacy" as const,
|
|
224
|
-
blockPack:
|
|
227
|
+
blockPack: cachedBp,
|
|
225
228
|
legacyState: canonicalize({
|
|
226
229
|
args: blockCfg.initialArgs,
|
|
227
230
|
uiState: blockCfg.initialUiState,
|
|
@@ -301,12 +304,13 @@ export class Project {
|
|
|
301
304
|
author?: AuthorMarker,
|
|
302
305
|
): Promise<void> {
|
|
303
306
|
const preparedBp = await this.env.bpPreparer.prepare(blockPackSpec);
|
|
304
|
-
const blockCfg = extractConfig(
|
|
305
|
-
await this.env.bpPreparer.getBlockConfigContainer(blockPackSpec),
|
|
306
|
-
);
|
|
307
|
+
const blockCfg = extractConfig(preparedBp.config);
|
|
307
308
|
|
|
308
309
|
this.env.runtimeCapabilities.throwIfIncompatible(blockCfg.featureFlags);
|
|
309
310
|
|
|
311
|
+
// Pre-materialize template via cache (separate transaction(s))
|
|
312
|
+
const cachedBp = await cacheBlockPackTemplate(this.env.pl, preparedBp);
|
|
313
|
+
|
|
310
314
|
// resetState signals to mutator to reset storage
|
|
311
315
|
// For v2+ blocks: mutator gets initial storage directly via getInitialStorageInVM
|
|
312
316
|
// For v1 blocks: we pass the legacy state format
|
|
@@ -323,7 +327,7 @@ export class Project {
|
|
|
323
327
|
this.env.pl,
|
|
324
328
|
this.rid,
|
|
325
329
|
author,
|
|
326
|
-
(mut) => mut.migrateBlockPack(blockId,
|
|
330
|
+
(mut) => mut.migrateBlockPack(blockId, cachedBp, resetState),
|
|
327
331
|
{ name: "updateBlockPack", lockId: this.projectLockId },
|
|
328
332
|
);
|
|
329
333
|
await this.projectTree.refreshState();
|
|
@@ -30,6 +30,7 @@ import type { NavigationStates } from "./navigation_states";
|
|
|
30
30
|
import { getBlockPackInfo } from "./util";
|
|
31
31
|
import { resourceIdToString, type ResourceId } from "@milaboratories/pl-client";
|
|
32
32
|
import { omitBy, isEqual } from "es-toolkit";
|
|
33
|
+
import { getDebugFlags } from "../debug";
|
|
33
34
|
|
|
34
35
|
type BlockInfo = {
|
|
35
36
|
argsRid?: ResourceId;
|
|
@@ -346,6 +347,11 @@ export function projectOverview(
|
|
|
346
347
|
}),
|
|
347
348
|
};
|
|
348
349
|
},
|
|
350
|
+
onRecalculation: getDebugFlags().logProjectOverviewStat
|
|
351
|
+
? (stats) => {
|
|
352
|
+
console.log(`[projectOverview] ${JSON.stringify(stats)}`);
|
|
353
|
+
}
|
|
354
|
+
: undefined,
|
|
349
355
|
},
|
|
350
356
|
).withStableType();
|
|
351
357
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExplicitTemplate, PreparedTemplate } from "./template_spec";
|
|
1
|
+
import type { CachedTemplate, ExplicitTemplate, PreparedTemplate } from "./template_spec";
|
|
2
2
|
import type { ResourceType } from "@milaboratories/pl-client";
|
|
3
3
|
import type { BlockConfigContainer } from "@platforma-sdk/model";
|
|
4
4
|
import type { BlockPackSpec } from "@milaboratories/pl-model-middle-layer";
|
|
@@ -48,7 +48,7 @@ export interface BlockPackExplicit {
|
|
|
48
48
|
/** Block-pack spec that can be materialized in pl. */
|
|
49
49
|
export type BlockPackSpecPrepared = {
|
|
50
50
|
type: "prepared";
|
|
51
|
-
template: PreparedTemplate;
|
|
51
|
+
template: PreparedTemplate | CachedTemplate;
|
|
52
52
|
config: BlockConfigContainer;
|
|
53
53
|
frontend: FrontendSpec;
|
|
54
54
|
source: BlockPackSpec;
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ResultOrError,
|
|
3
|
-
BlockConfig,
|
|
4
|
-
BlockStorage,
|
|
5
|
-
PlRef,
|
|
6
|
-
StorageDebugView,
|
|
7
|
-
} from "@platforma-sdk/model";
|
|
1
|
+
import type { ResultOrError, BlockConfig, BlockStorage, PlRef } from "@platforma-sdk/model";
|
|
8
2
|
import type { StringifiedJson } from "@milaboratories/pl-model-common";
|
|
9
3
|
import {
|
|
10
4
|
extractCodeWithInfo,
|
|
@@ -17,6 +11,7 @@ import type { QuickJSWASMModule } from "quickjs-emscripten";
|
|
|
17
11
|
import { executeSingleLambda } from "../js_render";
|
|
18
12
|
import type { ResourceId } from "@milaboratories/pl-client";
|
|
19
13
|
import { ConsoleLoggerAdapter, type MiLogger } from "@milaboratories/ts-helpers";
|
|
14
|
+
import type { StorageDebugView } from "@milaboratories/pl-model-middle-layer";
|
|
20
15
|
|
|
21
16
|
type EnrichmentTargetsRequest = {
|
|
22
17
|
blockConfig: () => BlockConfig;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ResourceId } from "@milaboratories/pl-client";
|
|
1
2
|
import type { CompiledTemplateV3, TemplateData } from "@milaboratories/pl-model-backend";
|
|
2
3
|
|
|
3
4
|
export interface TemplateFromRegistry {
|
|
@@ -16,10 +17,19 @@ export interface PreparedTemplate {
|
|
|
16
17
|
data: TemplateData | CompiledTemplateV3;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
export interface CachedTemplate {
|
|
21
|
+
readonly type: "cached";
|
|
22
|
+
readonly resourceId: ResourceId;
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
export interface TemplateFromFile {
|
|
20
26
|
readonly type: "from-file";
|
|
21
27
|
path: string;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
export type TemplateSpecPrepared =
|
|
30
|
+
export type TemplateSpecPrepared =
|
|
31
|
+
| TemplateFromRegistry
|
|
32
|
+
| ExplicitTemplate
|
|
33
|
+
| PreparedTemplate
|
|
34
|
+
| CachedTemplate;
|
|
25
35
|
export type TemplateSpecAny = TemplateSpecPrepared | TemplateFromFile;
|