@milaboratories/pl-middle-layer 1.61.12 → 1.63.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/js_render/service_injectors.cjs +2 -1
- package/dist/js_render/service_injectors.cjs.map +1 -1
- package/dist/js_render/service_injectors.js +2 -1
- package/dist/js_render/service_injectors.js.map +1 -1
- package/dist/mutator/template/direct_template_loader_v3.cjs +17 -0
- package/dist/mutator/template/direct_template_loader_v3.cjs.map +1 -1
- package/dist/mutator/template/direct_template_loader_v3.js +18 -1
- package/dist/mutator/template/direct_template_loader_v3.js.map +1 -1
- package/package.json +19 -19
- package/src/js_render/service_injectors.ts +11 -0
- package/src/mutator/template/direct_template_loader_v3.ts +35 -0
|
@@ -34,7 +34,8 @@ function getServiceInjectors() {
|
|
|
34
34
|
expandAxes: (spec) => vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec))),
|
|
35
35
|
collapseAxes: (ids) => vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids))),
|
|
36
36
|
findAxis: (spec, selector) => vm.exportSingleValue(driver.findAxis(vm.importObjectViaJson(spec), vm.importObjectViaJson(selector))),
|
|
37
|
-
findTableColumn: (tableSpec, selector) => vm.exportSingleValue(driver.findTableColumn(vm.importObjectViaJson(tableSpec), vm.importObjectViaJson(selector)))
|
|
37
|
+
findTableColumn: (tableSpec, selector) => vm.exportSingleValue(driver.findTableColumn(vm.importObjectViaJson(tableSpec), vm.importObjectViaJson(selector))),
|
|
38
|
+
rewriteLegacyFilters: (request) => vm.exportObjectViaJson(driver.rewriteLegacyFilters(vm.importObjectViaJson(request)))
|
|
38
39
|
};
|
|
39
40
|
},
|
|
40
41
|
Dialog: () => ({}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service_injectors.cjs","names":["Services","ServiceNotRegisteredError","PoolEntryGuard"],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type { InferServiceModel, ServiceBrand } from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PTableColumnId,\n PTableColumnSpec,\n SingleAxisSelector,\n BuildQueryInput,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n listColumns: (handle: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.listColumns(vm.vm.getString(handle) as SpecFrameHandle)),\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n buildQuery: (input: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.buildQuery(vm.importObjectViaJson(input) as BuildQueryInput),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n };\n },\n\n // Dialog has no model-side surface — workflow scripts cannot open save dialogs.\n // Declared as an empty injector to satisfy the exhaustive ServiceInjectorMap.\n Dialog: () => ({}) as Record<never, VmMethod>,\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n };\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"service_injectors.cjs","names":["Services","ServiceNotRegisteredError","PoolEntryGuard"],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type { InferServiceModel, ServiceBrand } from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PTableColumnId,\n PTableColumnSpec,\n PTableRecordFilter,\n SingleAxisSelector,\n BuildQueryInput,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n listColumns: (handle: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.listColumns(vm.vm.getString(handle) as SpecFrameHandle)),\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n buildQuery: (input: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.buildQuery(vm.importObjectViaJson(input) as BuildQueryInput),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n\n rewriteLegacyFilters: (request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.rewriteLegacyFilters(\n vm.importObjectViaJson(request) as {\n tableSpec: PTableColumnSpec[];\n filters: PTableRecordFilter[];\n },\n ),\n ),\n };\n },\n\n // Dialog has no model-side surface — workflow scripts cannot open save dialogs.\n // Declared as an empty injector to satisfy the exhaustive ServiceInjectorMap.\n Dialog: () => ({}) as Record<never, VmMethod>,\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n };\n}\n"],"mappings":";;;;AAkDA,SAAgB,sBAA0C;AACxD,QAAO;EACL,aAAa,EAAE,MAAM,SAAiC;GACpD,MAAM,SAAS,KAAK,gBAAgB,IAAIA,gCAAAA,SAAS,WAAW;AAC5D,OAAI,CAAC,OACH,OAAM,IAAIC,gCAAAA,0BACR,YAAYD,gCAAAA,SAAS,WAAW,uEACjC;AAEH,UAAO;IACL,kBAAkB,UAAyB;;;MACzC,MAAM,QAAA,YAAA,EAAQ,IAAIE,gCAAAA,eAChB,OAAO,gBAAgB,GAAG,oBAAoB,MAAM,CAAgC,CACrF,CAAA;AACD,WAAK,aAAa,MAAM,MAAM,MAAM;MACpC,MAAM,QAAQ,MAAM,MAAM;MAE1B,MAAM,MAAM,GAAG,GAAG,WAAW;AAC7B,SAAG,GAAG,UAAU,MAAM,IAAI,CAAC,SAAS,MAAM,GAAG,GAAG,QAAQ,KAAK,OAAO,EAAE,CAAC;AACvE,SAAG,GACA,YAAY,eAAe;AAC1B,aAAM,OAAO;QACb,CACD,SAAS,OAAO,GAAG,GAAG,QAAQ,KAAK,SAAS,GAAG,CAAC;AACnD,aAAO;;;;;;;IAGT,cAAc,WACZ,GAAG,oBAAoB,OAAO,YAAY,GAAG,GAAG,UAAU,OAAO,CAAoB,CAAC;IAExF,kBAAkB,QAAuB,YACvC,GAAG,oBACD,OAAO,gBACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,aAAa,UACX,GAAG,oBACD,OAAO,WAAW,GAAG,oBAAoB,MAAM,CAAoB,CACpE;IAEH,eAAe,QAAuB,YACpC,GAAG,oBACD,OAAO,aACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,gBAAgB,QAAuB,YACrC,GAAG,oBACD,OAAO,cACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,aAAa,SACX,GAAG,oBAAoB,OAAO,WAAW,GAAG,oBAAoB,KAAK,CAAa,CAAC;IAErF,eAAe,QACb,GAAG,oBAAoB,OAAO,aAAa,GAAG,oBAAoB,IAAI,CAAW,CAAC;IAEpF,WAAW,MAAqB,aAC9B,GAAG,kBACD,OAAO,SACL,GAAG,oBAAoB,KAAK,EAC5B,GAAG,oBAAoB,SAAS,CACjC,CACF;IAEH,kBAAkB,WAA0B,aAC1C,GAAG,kBACD,OAAO,gBACL,GAAG,oBAAoB,UAAU,EACjC,GAAG,oBAAoB,SAAS,CACjC,CACF;IAEH,uBAAuB,YACrB,GAAG,oBACD,OAAO,qBACL,GAAG,oBAAoB,QAAQ,CAIhC,CACF;IACJ;;EAKH,eAAe,EAAE;EAEjB,SAAS,EAAE,MAAM,UAAkC;GACjD,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,iBAAiB,QACf,GAAG,kBACD,KAAK,eACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GACJ;EACF"}
|
|
@@ -33,7 +33,8 @@ function getServiceInjectors() {
|
|
|
33
33
|
expandAxes: (spec) => vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec))),
|
|
34
34
|
collapseAxes: (ids) => vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids))),
|
|
35
35
|
findAxis: (spec, selector) => vm.exportSingleValue(driver.findAxis(vm.importObjectViaJson(spec), vm.importObjectViaJson(selector))),
|
|
36
|
-
findTableColumn: (tableSpec, selector) => vm.exportSingleValue(driver.findTableColumn(vm.importObjectViaJson(tableSpec), vm.importObjectViaJson(selector)))
|
|
36
|
+
findTableColumn: (tableSpec, selector) => vm.exportSingleValue(driver.findTableColumn(vm.importObjectViaJson(tableSpec), vm.importObjectViaJson(selector))),
|
|
37
|
+
rewriteLegacyFilters: (request) => vm.exportObjectViaJson(driver.rewriteLegacyFilters(vm.importObjectViaJson(request)))
|
|
37
38
|
};
|
|
38
39
|
},
|
|
39
40
|
Dialog: () => ({}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service_injectors.js","names":[],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type { InferServiceModel, ServiceBrand } from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PTableColumnId,\n PTableColumnSpec,\n SingleAxisSelector,\n BuildQueryInput,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n listColumns: (handle: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.listColumns(vm.vm.getString(handle) as SpecFrameHandle)),\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n buildQuery: (input: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.buildQuery(vm.importObjectViaJson(input) as BuildQueryInput),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n };\n },\n\n // Dialog has no model-side surface — workflow scripts cannot open save dialogs.\n // Declared as an empty injector to satisfy the exhaustive ServiceInjectorMap.\n Dialog: () => ({}) as Record<never, VmMethod>,\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n };\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"service_injectors.js","names":[],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type { InferServiceModel, ServiceBrand } from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PTableColumnId,\n PTableColumnSpec,\n PTableRecordFilter,\n SingleAxisSelector,\n BuildQueryInput,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n listColumns: (handle: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.listColumns(vm.vm.getString(handle) as SpecFrameHandle)),\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n buildQuery: (input: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.buildQuery(vm.importObjectViaJson(input) as BuildQueryInput),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n\n rewriteLegacyFilters: (request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.rewriteLegacyFilters(\n vm.importObjectViaJson(request) as {\n tableSpec: PTableColumnSpec[];\n filters: PTableRecordFilter[];\n },\n ),\n ),\n };\n },\n\n // Dialog has no model-side surface — workflow scripts cannot open save dialogs.\n // Declared as an empty injector to satisfy the exhaustive ServiceInjectorMap.\n Dialog: () => ({}) as Record<never, VmMethod>,\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n };\n}\n"],"mappings":";;;AAkDA,SAAgB,sBAA0C;AACxD,QAAO;EACL,aAAa,EAAE,MAAM,SAAiC;GACpD,MAAM,SAAS,KAAK,gBAAgB,IAAI,SAAS,WAAW;AAC5D,OAAI,CAAC,OACH,OAAM,IAAI,0BACR,YAAY,SAAS,WAAW,uEACjC;AAEH,UAAO;IACL,kBAAkB,UAAyB;;;MACzC,MAAM,QAAA,YAAA,EAAQ,IAAI,eAChB,OAAO,gBAAgB,GAAG,oBAAoB,MAAM,CAAgC,CACrF,CAAA;AACD,WAAK,aAAa,MAAM,MAAM,MAAM;MACpC,MAAM,QAAQ,MAAM,MAAM;MAE1B,MAAM,MAAM,GAAG,GAAG,WAAW;AAC7B,SAAG,GAAG,UAAU,MAAM,IAAI,CAAC,SAAS,MAAM,GAAG,GAAG,QAAQ,KAAK,OAAO,EAAE,CAAC;AACvE,SAAG,GACA,YAAY,eAAe;AAC1B,aAAM,OAAO;QACb,CACD,SAAS,OAAO,GAAG,GAAG,QAAQ,KAAK,SAAS,GAAG,CAAC;AACnD,aAAO;;;;;;;IAGT,cAAc,WACZ,GAAG,oBAAoB,OAAO,YAAY,GAAG,GAAG,UAAU,OAAO,CAAoB,CAAC;IAExF,kBAAkB,QAAuB,YACvC,GAAG,oBACD,OAAO,gBACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,aAAa,UACX,GAAG,oBACD,OAAO,WAAW,GAAG,oBAAoB,MAAM,CAAoB,CACpE;IAEH,eAAe,QAAuB,YACpC,GAAG,oBACD,OAAO,aACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,gBAAgB,QAAuB,YACrC,GAAG,oBACD,OAAO,cACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,aAAa,SACX,GAAG,oBAAoB,OAAO,WAAW,GAAG,oBAAoB,KAAK,CAAa,CAAC;IAErF,eAAe,QACb,GAAG,oBAAoB,OAAO,aAAa,GAAG,oBAAoB,IAAI,CAAW,CAAC;IAEpF,WAAW,MAAqB,aAC9B,GAAG,kBACD,OAAO,SACL,GAAG,oBAAoB,KAAK,EAC5B,GAAG,oBAAoB,SAAS,CACjC,CACF;IAEH,kBAAkB,WAA0B,aAC1C,GAAG,kBACD,OAAO,gBACL,GAAG,oBAAoB,UAAU,EACjC,GAAG,oBAAoB,SAAS,CACjC,CACF;IAEH,uBAAuB,YACrB,GAAG,oBACD,OAAO,qBACL,GAAG,oBAAoB,QAAQ,CAIhC,CACF;IACJ;;EAKH,eAAe,EAAE;EAEjB,SAAS,EAAE,MAAM,UAAkC;GACjD,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,iBAAiB,QACf,GAAG,kBACD,KAAK,eACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GACJ;EACF"}
|
|
@@ -36,6 +36,14 @@ const LibRenderer = {
|
|
|
36
36
|
return tx.createValue(_milaboratories_pl_model_backend.PlTemplateLibV1.type, JSON.stringify(_milaboratories_pl_model_backend.PlTemplateLibV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash)).data));
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
|
+
const WasmRenderer = {
|
|
40
|
+
updateCacheKey(resource, hash, sources) {
|
|
41
|
+
hash.update(_milaboratories_pl_model_backend.PlWasmV1.type.name).update(_milaboratories_pl_model_backend.PlWasmV1.type.version).update(resource.name).update(resource.version).update(getSourceCode(resource.name, sources, resource.sourceHash));
|
|
42
|
+
},
|
|
43
|
+
render(resource, tx, _creator, sources) {
|
|
44
|
+
return tx.createValue(_milaboratories_pl_model_backend.PlWasmV1.type, JSON.stringify(_milaboratories_pl_model_backend.PlWasmV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash)).data));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
39
47
|
const SoftwareInfoRenderer = {
|
|
40
48
|
updateCacheKey(resource, hash, sources) {
|
|
41
49
|
hash.update(_milaboratories_pl_model_backend.PlTemplateSoftwareV1.type.name).update(_milaboratories_pl_model_backend.PlTemplateSoftwareV1.type.version).update(resource.name).update(resource.version).update(getSourceCode(resource.name, sources, resource.sourceHash));
|
|
@@ -71,6 +79,10 @@ const TemplateRenderer = {
|
|
|
71
79
|
hash.update("tpl:" + tplId);
|
|
72
80
|
this.updateCacheKey(tpl, hash, sources);
|
|
73
81
|
}
|
|
82
|
+
for (const [wasmId, wasm] of srt(Object.entries(resource.wasm ?? {}))) {
|
|
83
|
+
hash.update("wasm:" + wasmId);
|
|
84
|
+
WasmRenderer.updateCacheKey(wasm, hash, sources);
|
|
85
|
+
}
|
|
74
86
|
},
|
|
75
87
|
render(resource, tx, _creator, sources) {
|
|
76
88
|
const tplRef = tx.createStruct(_milaboratories_pl_model_backend.PlTemplateV1.type, JSON.stringify(_milaboratories_pl_model_backend.PlTemplateV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash)).data));
|
|
@@ -94,6 +106,11 @@ const TemplateRenderer = {
|
|
|
94
106
|
tx.createField(fld, "Input");
|
|
95
107
|
tx.setField(fld, _creator(depTpl, TemplateRenderer, sources));
|
|
96
108
|
}
|
|
109
|
+
for (const [wasmId, wasm] of Object.entries(resource.wasm ?? {})) {
|
|
110
|
+
const fld = _milaboratories_pl_model_backend.PlTemplateV1.wasmField(tplRef, wasmId);
|
|
111
|
+
tx.createField(fld, "Input");
|
|
112
|
+
tx.setField(fld, _creator(wasm, WasmRenderer, sources));
|
|
113
|
+
}
|
|
97
114
|
tx.lock(tplRef);
|
|
98
115
|
if (!resource.hashOverride) return tplRef;
|
|
99
116
|
const overrideRef = tx.createStruct(_milaboratories_pl_model_backend.PlTemplateOverrideV1.type, JSON.stringify(_milaboratories_pl_model_backend.PlTemplateOverrideV1.fromV3Data(resource)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"direct_template_loader_v3.cjs","names":["PlTemplateLibV1","PlTemplateSoftwareV1","PlTemplateV1","PlTemplateOverrideV1"],"sources":["../../../src/mutator/template/direct_template_loader_v3.ts"],"sourcesContent":["import type { AnyRef, AnyResourceRef, PlTransaction } from \"@milaboratories/pl-client\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\nimport type {\n CompiledTemplateV3,\n TemplateDataV3,\n TemplateLibDataV3,\n TemplateSoftwareDataV3,\n} from \"@milaboratories/pl-model-backend\";\nimport {\n PlTemplateLibV1,\n PlTemplateSoftwareV1,\n PlTemplateV1,\n PlTemplateOverrideV1,\n} from \"@milaboratories/pl-model-backend\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\n\n/**\n * Renders the tree of templates by caching all resource ids\n * by their cache keys.\n * It's different from v2 version because we provide\n * the hash map of the code of all sources everywhere.\n * It does a double-dispatch on the node type (template, library etc),\n * and creates resources.\n *\n * IMO, it'd be clearer to rewrite it with Visitor pattern, and separate\n * tree traversing and operations on it, but I don't have time to do it now.\n */\nexport function createTemplateV3Tree(tx: PlTransaction, tplData: CompiledTemplateV3): AnyRef {\n const resourceCache = new Map<string, AnyResourceRef>();\n\n const createResourceCached = <T>(\n resource: T,\n renderer: Renderer<T>,\n hashToSource: Record<string, string>,\n ): AnyResourceRef => {\n const key: Hash = createHash(\"sha256\");\n renderer.updateCacheKey(resource, key, hashToSource);\n\n const rKey = key.digest(\"hex\");\n\n if (!resourceCache.has(rKey)) {\n const rId = renderer.render(resource, tx, createResourceCached, hashToSource);\n resourceCache.set(rKey, rId);\n }\n\n return resourceCache.get(rKey)!;\n };\n\n return createResourceCached(tplData.template, TemplateRenderer, tplData.hashToSource);\n}\n\ntype Renderer<T> = {\n /** Updates the cache key by adding all info of the artifact. */\n updateCacheKey: CacheKey<T>;\n /** Create resources for all dependencies recursively and then for this artifact. */\n render: (\n resource: T,\n tx: PlTransaction,\n creator: Creator,\n sources: Record<string, string>,\n ) => AnyResourceRef;\n};\ntype CacheKey<T> = (resource: T, key: Hash, sources: Record<string, string>) => void;\ntype Creator = <T>(\n resource: T,\n renderer: Renderer<T>,\n sources: Record<string, string>,\n) => AnyResourceRef;\n\nconst LibRenderer: Renderer<TemplateLibDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateLibV1.type.name)\n .update(PlTemplateLibV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n return tx.createValue(\n PlTemplateLibV1.type,\n JSON.stringify(\n PlTemplateLibV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n },\n};\n\nconst SoftwareInfoRenderer: Renderer<TemplateSoftwareDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateSoftwareV1.type.name)\n .update(PlTemplateSoftwareV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n const sw = PlTemplateSoftwareV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n );\n const ref = tx.createStruct(PlTemplateSoftwareV1.type, sw.data);\n tx.setKValue(ref, PlTemplateSoftwareV1.metaNameKey, JSON.stringify(sw.name));\n tx.lock(ref);\n return ref;\n },\n};\n\nconst TemplateRenderer: Renderer<TemplateDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateV1.type.name)\n .update(PlTemplateV1.type.version)\n .update(resource.hashOverride ?? \"no-override\")\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n\n const srt = <T>(entries: [string, T][]): [string, T][] => {\n entries.sort((a, b) => (a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1));\n return entries;\n };\n\n for (const [libId, lib] of srt(Object.entries(resource.libs ?? {}))) {\n hash.update(\"lib:\" + libId);\n LibRenderer.updateCacheKey(lib, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.software ?? {}))) {\n hash.update(\"soft:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.assets ?? {}))) {\n hash.update(\"asset:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [tplId, tpl] of srt(Object.entries(resource.templates ?? {}))) {\n hash.update(\"tpl:\" + tplId);\n this.updateCacheKey(tpl, hash, sources);\n }\n },\n render(resource, tx, _creator, sources) {\n const tplRef = tx.createStruct(\n PlTemplateV1.type,\n JSON.stringify(\n PlTemplateV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n // Render libraries\n for (const [libId, lib] of Object.entries(resource.libs ?? {})) {\n const fld = PlTemplateV1.libField(tplRef, libId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(lib, LibRenderer, sources));\n }\n\n // Render software and assets\n for (const [swId, sw] of Object.entries(resource.software ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n for (const [swId, sw] of Object.entries(resource.assets ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n\n // Render dependency templates\n for (const [depTplId, depTpl] of Object.entries(resource.templates ?? {})) {\n const fld = PlTemplateV1.tplField(tplRef, depTplId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(depTpl, TemplateRenderer, sources));\n }\n\n tx.lock(tplRef);\n\n if (!resource.hashOverride) return tplRef;\n\n // Override template hash with proxy resource, when hash override is configured for template\n const overrideRef = tx.createStruct(\n PlTemplateOverrideV1.type,\n JSON.stringify(PlTemplateOverrideV1.fromV3Data(resource)),\n );\n const fld = PlTemplateOverrideV1.tplField(overrideRef);\n tx.createField(fld, \"Service\");\n tx.setField(fld, tplRef);\n tx.lock(overrideRef);\n return overrideRef;\n },\n};\n\n/**\n * Gets a source code of the artifact by its source hash.\n * the source hash was calculated and stored by tengo compiler\n * and is different from the hash we're using for caching here.\n */\nfunction getSourceCode(name: string, sources: Record<string, string>, sourceHash: string): string {\n return notEmpty(\n sources[sourceHash],\n `trying to get \"${name}\" source: sources map doesn't contain source hash ${sourceHash}`,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"direct_template_loader_v3.cjs","names":["PlTemplateLibV1","PlWasmV1","PlTemplateSoftwareV1","PlTemplateV1","PlTemplateOverrideV1"],"sources":["../../../src/mutator/template/direct_template_loader_v3.ts"],"sourcesContent":["import type { AnyRef, AnyResourceRef, PlTransaction } from \"@milaboratories/pl-client\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\nimport type {\n CompiledTemplateV3,\n TemplateDataV3,\n TemplateLibDataV3,\n TemplateSoftwareDataV3,\n TemplateWasmDataV3,\n} from \"@milaboratories/pl-model-backend\";\nimport {\n PlTemplateLibV1,\n PlTemplateSoftwareV1,\n PlTemplateV1,\n PlTemplateOverrideV1,\n PlWasmV1,\n} from \"@milaboratories/pl-model-backend\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\n\n/**\n * Renders the tree of templates by caching all resource ids\n * by their cache keys.\n * It's different from v2 version because we provide\n * the hash map of the code of all sources everywhere.\n * It does a double-dispatch on the node type (template, library etc),\n * and creates resources.\n *\n * IMO, it'd be clearer to rewrite it with Visitor pattern, and separate\n * tree traversing and operations on it, but I don't have time to do it now.\n */\nexport function createTemplateV3Tree(tx: PlTransaction, tplData: CompiledTemplateV3): AnyRef {\n const resourceCache = new Map<string, AnyResourceRef>();\n\n const createResourceCached = <T>(\n resource: T,\n renderer: Renderer<T>,\n hashToSource: Record<string, string>,\n ): AnyResourceRef => {\n const key: Hash = createHash(\"sha256\");\n renderer.updateCacheKey(resource, key, hashToSource);\n\n const rKey = key.digest(\"hex\");\n\n if (!resourceCache.has(rKey)) {\n const rId = renderer.render(resource, tx, createResourceCached, hashToSource);\n resourceCache.set(rKey, rId);\n }\n\n return resourceCache.get(rKey)!;\n };\n\n return createResourceCached(tplData.template, TemplateRenderer, tplData.hashToSource);\n}\n\ntype Renderer<T> = {\n /** Updates the cache key by adding all info of the artifact. */\n updateCacheKey: CacheKey<T>;\n /** Create resources for all dependencies recursively and then for this artifact. */\n render: (\n resource: T,\n tx: PlTransaction,\n creator: Creator,\n sources: Record<string, string>,\n ) => AnyResourceRef;\n};\ntype CacheKey<T> = (resource: T, key: Hash, sources: Record<string, string>) => void;\ntype Creator = <T>(\n resource: T,\n renderer: Renderer<T>,\n sources: Record<string, string>,\n) => AnyResourceRef;\n\nconst LibRenderer: Renderer<TemplateLibDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateLibV1.type.name)\n .update(PlTemplateLibV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n return tx.createValue(\n PlTemplateLibV1.type,\n JSON.stringify(\n PlTemplateLibV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n },\n};\n\nconst WasmRenderer: Renderer<TemplateWasmDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlWasmV1.type.name)\n .update(PlWasmV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n return tx.createValue(\n PlWasmV1.type,\n JSON.stringify(\n PlWasmV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash))\n .data,\n ),\n );\n },\n};\n\nconst SoftwareInfoRenderer: Renderer<TemplateSoftwareDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateSoftwareV1.type.name)\n .update(PlTemplateSoftwareV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n const sw = PlTemplateSoftwareV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n );\n const ref = tx.createStruct(PlTemplateSoftwareV1.type, sw.data);\n tx.setKValue(ref, PlTemplateSoftwareV1.metaNameKey, JSON.stringify(sw.name));\n tx.lock(ref);\n return ref;\n },\n};\n\nconst TemplateRenderer: Renderer<TemplateDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateV1.type.name)\n .update(PlTemplateV1.type.version)\n .update(resource.hashOverride ?? \"no-override\")\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n\n const srt = <T>(entries: [string, T][]): [string, T][] => {\n entries.sort((a, b) => (a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1));\n return entries;\n };\n\n for (const [libId, lib] of srt(Object.entries(resource.libs ?? {}))) {\n hash.update(\"lib:\" + libId);\n LibRenderer.updateCacheKey(lib, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.software ?? {}))) {\n hash.update(\"soft:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.assets ?? {}))) {\n hash.update(\"asset:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [tplId, tpl] of srt(Object.entries(resource.templates ?? {}))) {\n hash.update(\"tpl:\" + tplId);\n this.updateCacheKey(tpl, hash, sources);\n }\n for (const [wasmId, wasm] of srt(Object.entries(resource.wasm ?? {}))) {\n hash.update(\"wasm:\" + wasmId);\n WasmRenderer.updateCacheKey(wasm, hash, sources);\n }\n },\n render(resource, tx, _creator, sources) {\n const tplRef = tx.createStruct(\n PlTemplateV1.type,\n JSON.stringify(\n PlTemplateV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n // Render libraries\n for (const [libId, lib] of Object.entries(resource.libs ?? {})) {\n const fld = PlTemplateV1.libField(tplRef, libId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(lib, LibRenderer, sources));\n }\n\n // Render software and assets\n for (const [swId, sw] of Object.entries(resource.software ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n for (const [swId, sw] of Object.entries(resource.assets ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n\n // Render dependency templates\n for (const [depTplId, depTpl] of Object.entries(resource.templates ?? {})) {\n const fld = PlTemplateV1.tplField(tplRef, depTplId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(depTpl, TemplateRenderer, sources));\n }\n\n // Render wasm dependencies. The field name (alias) feeds straight into\n // the backend's TengoTemplateV1.wasm map and becomes the lookup key in\n // RuntimeV1.deps.Wasm consumed by plapi.loadWasm.\n for (const [wasmId, wasm] of Object.entries(resource.wasm ?? {})) {\n const fld = PlTemplateV1.wasmField(tplRef, wasmId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(wasm, WasmRenderer, sources));\n }\n\n tx.lock(tplRef);\n\n if (!resource.hashOverride) return tplRef;\n\n // Override template hash with proxy resource, when hash override is configured for template\n const overrideRef = tx.createStruct(\n PlTemplateOverrideV1.type,\n JSON.stringify(PlTemplateOverrideV1.fromV3Data(resource)),\n );\n const fld = PlTemplateOverrideV1.tplField(overrideRef);\n tx.createField(fld, \"Service\");\n tx.setField(fld, tplRef);\n tx.lock(overrideRef);\n return overrideRef;\n },\n};\n\n/**\n * Gets a source code of the artifact by its source hash.\n * the source hash was calculated and stored by tengo compiler\n * and is different from the hash we're using for caching here.\n */\nfunction getSourceCode(name: string, sources: Record<string, string>, sourceHash: string): string {\n return notEmpty(\n sources[sourceHash],\n `trying to get \"${name}\" source: sources map doesn't contain source hash ${sourceHash}`,\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { notEmpty } from "@milaboratories/ts-helpers";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { PlTemplateLibV1, PlTemplateOverrideV1, PlTemplateSoftwareV1, PlTemplateV1 } from "@milaboratories/pl-model-backend";
|
|
3
|
+
import { PlTemplateLibV1, PlTemplateOverrideV1, PlTemplateSoftwareV1, PlTemplateV1, PlWasmV1 } from "@milaboratories/pl-model-backend";
|
|
4
4
|
//#region src/mutator/template/direct_template_loader_v3.ts
|
|
5
5
|
/**
|
|
6
6
|
* Renders the tree of templates by caching all resource ids
|
|
@@ -35,6 +35,14 @@ const LibRenderer = {
|
|
|
35
35
|
return tx.createValue(PlTemplateLibV1.type, JSON.stringify(PlTemplateLibV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash)).data));
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
const WasmRenderer = {
|
|
39
|
+
updateCacheKey(resource, hash, sources) {
|
|
40
|
+
hash.update(PlWasmV1.type.name).update(PlWasmV1.type.version).update(resource.name).update(resource.version).update(getSourceCode(resource.name, sources, resource.sourceHash));
|
|
41
|
+
},
|
|
42
|
+
render(resource, tx, _creator, sources) {
|
|
43
|
+
return tx.createValue(PlWasmV1.type, JSON.stringify(PlWasmV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash)).data));
|
|
44
|
+
}
|
|
45
|
+
};
|
|
38
46
|
const SoftwareInfoRenderer = {
|
|
39
47
|
updateCacheKey(resource, hash, sources) {
|
|
40
48
|
hash.update(PlTemplateSoftwareV1.type.name).update(PlTemplateSoftwareV1.type.version).update(resource.name).update(resource.version).update(getSourceCode(resource.name, sources, resource.sourceHash));
|
|
@@ -70,6 +78,10 @@ const TemplateRenderer = {
|
|
|
70
78
|
hash.update("tpl:" + tplId);
|
|
71
79
|
this.updateCacheKey(tpl, hash, sources);
|
|
72
80
|
}
|
|
81
|
+
for (const [wasmId, wasm] of srt(Object.entries(resource.wasm ?? {}))) {
|
|
82
|
+
hash.update("wasm:" + wasmId);
|
|
83
|
+
WasmRenderer.updateCacheKey(wasm, hash, sources);
|
|
84
|
+
}
|
|
73
85
|
},
|
|
74
86
|
render(resource, tx, _creator, sources) {
|
|
75
87
|
const tplRef = tx.createStruct(PlTemplateV1.type, JSON.stringify(PlTemplateV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash)).data));
|
|
@@ -93,6 +105,11 @@ const TemplateRenderer = {
|
|
|
93
105
|
tx.createField(fld, "Input");
|
|
94
106
|
tx.setField(fld, _creator(depTpl, TemplateRenderer, sources));
|
|
95
107
|
}
|
|
108
|
+
for (const [wasmId, wasm] of Object.entries(resource.wasm ?? {})) {
|
|
109
|
+
const fld = PlTemplateV1.wasmField(tplRef, wasmId);
|
|
110
|
+
tx.createField(fld, "Input");
|
|
111
|
+
tx.setField(fld, _creator(wasm, WasmRenderer, sources));
|
|
112
|
+
}
|
|
96
113
|
tx.lock(tplRef);
|
|
97
114
|
if (!resource.hashOverride) return tplRef;
|
|
98
115
|
const overrideRef = tx.createStruct(PlTemplateOverrideV1.type, JSON.stringify(PlTemplateOverrideV1.fromV3Data(resource)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"direct_template_loader_v3.js","names":[],"sources":["../../../src/mutator/template/direct_template_loader_v3.ts"],"sourcesContent":["import type { AnyRef, AnyResourceRef, PlTransaction } from \"@milaboratories/pl-client\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\nimport type {\n CompiledTemplateV3,\n TemplateDataV3,\n TemplateLibDataV3,\n TemplateSoftwareDataV3,\n} from \"@milaboratories/pl-model-backend\";\nimport {\n PlTemplateLibV1,\n PlTemplateSoftwareV1,\n PlTemplateV1,\n PlTemplateOverrideV1,\n} from \"@milaboratories/pl-model-backend\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\n\n/**\n * Renders the tree of templates by caching all resource ids\n * by their cache keys.\n * It's different from v2 version because we provide\n * the hash map of the code of all sources everywhere.\n * It does a double-dispatch on the node type (template, library etc),\n * and creates resources.\n *\n * IMO, it'd be clearer to rewrite it with Visitor pattern, and separate\n * tree traversing and operations on it, but I don't have time to do it now.\n */\nexport function createTemplateV3Tree(tx: PlTransaction, tplData: CompiledTemplateV3): AnyRef {\n const resourceCache = new Map<string, AnyResourceRef>();\n\n const createResourceCached = <T>(\n resource: T,\n renderer: Renderer<T>,\n hashToSource: Record<string, string>,\n ): AnyResourceRef => {\n const key: Hash = createHash(\"sha256\");\n renderer.updateCacheKey(resource, key, hashToSource);\n\n const rKey = key.digest(\"hex\");\n\n if (!resourceCache.has(rKey)) {\n const rId = renderer.render(resource, tx, createResourceCached, hashToSource);\n resourceCache.set(rKey, rId);\n }\n\n return resourceCache.get(rKey)!;\n };\n\n return createResourceCached(tplData.template, TemplateRenderer, tplData.hashToSource);\n}\n\ntype Renderer<T> = {\n /** Updates the cache key by adding all info of the artifact. */\n updateCacheKey: CacheKey<T>;\n /** Create resources for all dependencies recursively and then for this artifact. */\n render: (\n resource: T,\n tx: PlTransaction,\n creator: Creator,\n sources: Record<string, string>,\n ) => AnyResourceRef;\n};\ntype CacheKey<T> = (resource: T, key: Hash, sources: Record<string, string>) => void;\ntype Creator = <T>(\n resource: T,\n renderer: Renderer<T>,\n sources: Record<string, string>,\n) => AnyResourceRef;\n\nconst LibRenderer: Renderer<TemplateLibDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateLibV1.type.name)\n .update(PlTemplateLibV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n return tx.createValue(\n PlTemplateLibV1.type,\n JSON.stringify(\n PlTemplateLibV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n },\n};\n\nconst SoftwareInfoRenderer: Renderer<TemplateSoftwareDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateSoftwareV1.type.name)\n .update(PlTemplateSoftwareV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n const sw = PlTemplateSoftwareV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n );\n const ref = tx.createStruct(PlTemplateSoftwareV1.type, sw.data);\n tx.setKValue(ref, PlTemplateSoftwareV1.metaNameKey, JSON.stringify(sw.name));\n tx.lock(ref);\n return ref;\n },\n};\n\nconst TemplateRenderer: Renderer<TemplateDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateV1.type.name)\n .update(PlTemplateV1.type.version)\n .update(resource.hashOverride ?? \"no-override\")\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n\n const srt = <T>(entries: [string, T][]): [string, T][] => {\n entries.sort((a, b) => (a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1));\n return entries;\n };\n\n for (const [libId, lib] of srt(Object.entries(resource.libs ?? {}))) {\n hash.update(\"lib:\" + libId);\n LibRenderer.updateCacheKey(lib, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.software ?? {}))) {\n hash.update(\"soft:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.assets ?? {}))) {\n hash.update(\"asset:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [tplId, tpl] of srt(Object.entries(resource.templates ?? {}))) {\n hash.update(\"tpl:\" + tplId);\n this.updateCacheKey(tpl, hash, sources);\n }\n },\n render(resource, tx, _creator, sources) {\n const tplRef = tx.createStruct(\n PlTemplateV1.type,\n JSON.stringify(\n PlTemplateV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n // Render libraries\n for (const [libId, lib] of Object.entries(resource.libs ?? {})) {\n const fld = PlTemplateV1.libField(tplRef, libId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(lib, LibRenderer, sources));\n }\n\n // Render software and assets\n for (const [swId, sw] of Object.entries(resource.software ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n for (const [swId, sw] of Object.entries(resource.assets ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n\n // Render dependency templates\n for (const [depTplId, depTpl] of Object.entries(resource.templates ?? {})) {\n const fld = PlTemplateV1.tplField(tplRef, depTplId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(depTpl, TemplateRenderer, sources));\n }\n\n tx.lock(tplRef);\n\n if (!resource.hashOverride) return tplRef;\n\n // Override template hash with proxy resource, when hash override is configured for template\n const overrideRef = tx.createStruct(\n PlTemplateOverrideV1.type,\n JSON.stringify(PlTemplateOverrideV1.fromV3Data(resource)),\n );\n const fld = PlTemplateOverrideV1.tplField(overrideRef);\n tx.createField(fld, \"Service\");\n tx.setField(fld, tplRef);\n tx.lock(overrideRef);\n return overrideRef;\n },\n};\n\n/**\n * Gets a source code of the artifact by its source hash.\n * the source hash was calculated and stored by tengo compiler\n * and is different from the hash we're using for caching here.\n */\nfunction getSourceCode(name: string, sources: Record<string, string>, sourceHash: string): string {\n return notEmpty(\n sources[sourceHash],\n `trying to get \"${name}\" source: sources map doesn't contain source hash ${sourceHash}`,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"direct_template_loader_v3.js","names":[],"sources":["../../../src/mutator/template/direct_template_loader_v3.ts"],"sourcesContent":["import type { AnyRef, AnyResourceRef, PlTransaction } from \"@milaboratories/pl-client\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\nimport type {\n CompiledTemplateV3,\n TemplateDataV3,\n TemplateLibDataV3,\n TemplateSoftwareDataV3,\n TemplateWasmDataV3,\n} from \"@milaboratories/pl-model-backend\";\nimport {\n PlTemplateLibV1,\n PlTemplateSoftwareV1,\n PlTemplateV1,\n PlTemplateOverrideV1,\n PlWasmV1,\n} from \"@milaboratories/pl-model-backend\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\n\n/**\n * Renders the tree of templates by caching all resource ids\n * by their cache keys.\n * It's different from v2 version because we provide\n * the hash map of the code of all sources everywhere.\n * It does a double-dispatch on the node type (template, library etc),\n * and creates resources.\n *\n * IMO, it'd be clearer to rewrite it with Visitor pattern, and separate\n * tree traversing and operations on it, but I don't have time to do it now.\n */\nexport function createTemplateV3Tree(tx: PlTransaction, tplData: CompiledTemplateV3): AnyRef {\n const resourceCache = new Map<string, AnyResourceRef>();\n\n const createResourceCached = <T>(\n resource: T,\n renderer: Renderer<T>,\n hashToSource: Record<string, string>,\n ): AnyResourceRef => {\n const key: Hash = createHash(\"sha256\");\n renderer.updateCacheKey(resource, key, hashToSource);\n\n const rKey = key.digest(\"hex\");\n\n if (!resourceCache.has(rKey)) {\n const rId = renderer.render(resource, tx, createResourceCached, hashToSource);\n resourceCache.set(rKey, rId);\n }\n\n return resourceCache.get(rKey)!;\n };\n\n return createResourceCached(tplData.template, TemplateRenderer, tplData.hashToSource);\n}\n\ntype Renderer<T> = {\n /** Updates the cache key by adding all info of the artifact. */\n updateCacheKey: CacheKey<T>;\n /** Create resources for all dependencies recursively and then for this artifact. */\n render: (\n resource: T,\n tx: PlTransaction,\n creator: Creator,\n sources: Record<string, string>,\n ) => AnyResourceRef;\n};\ntype CacheKey<T> = (resource: T, key: Hash, sources: Record<string, string>) => void;\ntype Creator = <T>(\n resource: T,\n renderer: Renderer<T>,\n sources: Record<string, string>,\n) => AnyResourceRef;\n\nconst LibRenderer: Renderer<TemplateLibDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateLibV1.type.name)\n .update(PlTemplateLibV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n return tx.createValue(\n PlTemplateLibV1.type,\n JSON.stringify(\n PlTemplateLibV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n },\n};\n\nconst WasmRenderer: Renderer<TemplateWasmDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlWasmV1.type.name)\n .update(PlWasmV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n return tx.createValue(\n PlWasmV1.type,\n JSON.stringify(\n PlWasmV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash))\n .data,\n ),\n );\n },\n};\n\nconst SoftwareInfoRenderer: Renderer<TemplateSoftwareDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateSoftwareV1.type.name)\n .update(PlTemplateSoftwareV1.type.version)\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n },\n render(resource, tx, _creator, sources) {\n const sw = PlTemplateSoftwareV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n );\n const ref = tx.createStruct(PlTemplateSoftwareV1.type, sw.data);\n tx.setKValue(ref, PlTemplateSoftwareV1.metaNameKey, JSON.stringify(sw.name));\n tx.lock(ref);\n return ref;\n },\n};\n\nconst TemplateRenderer: Renderer<TemplateDataV3> = {\n updateCacheKey(resource, hash, sources) {\n hash\n .update(PlTemplateV1.type.name)\n .update(PlTemplateV1.type.version)\n .update(resource.hashOverride ?? \"no-override\")\n .update(resource.name)\n .update(resource.version)\n .update(getSourceCode(resource.name, sources, resource.sourceHash));\n\n const srt = <T>(entries: [string, T][]): [string, T][] => {\n entries.sort((a, b) => (a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1));\n return entries;\n };\n\n for (const [libId, lib] of srt(Object.entries(resource.libs ?? {}))) {\n hash.update(\"lib:\" + libId);\n LibRenderer.updateCacheKey(lib, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.software ?? {}))) {\n hash.update(\"soft:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [swId, sw] of srt(Object.entries(resource.assets ?? {}))) {\n hash.update(\"asset:\" + swId);\n SoftwareInfoRenderer.updateCacheKey(sw, hash, sources);\n }\n for (const [tplId, tpl] of srt(Object.entries(resource.templates ?? {}))) {\n hash.update(\"tpl:\" + tplId);\n this.updateCacheKey(tpl, hash, sources);\n }\n for (const [wasmId, wasm] of srt(Object.entries(resource.wasm ?? {}))) {\n hash.update(\"wasm:\" + wasmId);\n WasmRenderer.updateCacheKey(wasm, hash, sources);\n }\n },\n render(resource, tx, _creator, sources) {\n const tplRef = tx.createStruct(\n PlTemplateV1.type,\n JSON.stringify(\n PlTemplateV1.fromV3Data(\n resource,\n getSourceCode(resource.name, sources, resource.sourceHash),\n ).data,\n ),\n );\n // Render libraries\n for (const [libId, lib] of Object.entries(resource.libs ?? {})) {\n const fld = PlTemplateV1.libField(tplRef, libId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(lib, LibRenderer, sources));\n }\n\n // Render software and assets\n for (const [swId, sw] of Object.entries(resource.software ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n for (const [swId, sw] of Object.entries(resource.assets ?? {})) {\n const fld = PlTemplateV1.swField(tplRef, swId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(sw, SoftwareInfoRenderer, sources));\n }\n\n // Render dependency templates\n for (const [depTplId, depTpl] of Object.entries(resource.templates ?? {})) {\n const fld = PlTemplateV1.tplField(tplRef, depTplId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(depTpl, TemplateRenderer, sources));\n }\n\n // Render wasm dependencies. The field name (alias) feeds straight into\n // the backend's TengoTemplateV1.wasm map and becomes the lookup key in\n // RuntimeV1.deps.Wasm consumed by plapi.loadWasm.\n for (const [wasmId, wasm] of Object.entries(resource.wasm ?? {})) {\n const fld = PlTemplateV1.wasmField(tplRef, wasmId);\n tx.createField(fld, \"Input\");\n tx.setField(fld, _creator(wasm, WasmRenderer, sources));\n }\n\n tx.lock(tplRef);\n\n if (!resource.hashOverride) return tplRef;\n\n // Override template hash with proxy resource, when hash override is configured for template\n const overrideRef = tx.createStruct(\n PlTemplateOverrideV1.type,\n JSON.stringify(PlTemplateOverrideV1.fromV3Data(resource)),\n );\n const fld = PlTemplateOverrideV1.tplField(overrideRef);\n tx.createField(fld, \"Service\");\n tx.setField(fld, tplRef);\n tx.lock(overrideRef);\n return overrideRef;\n },\n};\n\n/**\n * Gets a source code of the artifact by its source hash.\n * the source hash was calculated and stored by tengo compiler\n * and is different from the hash we're using for caching here.\n */\nfunction getSourceCode(name: string, sources: Record<string, string>, sourceHash: string): string {\n return notEmpty(\n sources[sourceHash],\n `trying to get \"${name}\" source: sources map doesn't contain source hash ${sourceHash}`,\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-middle-layer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.63.0",
|
|
4
4
|
"description": "Pl Middle Layer",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@milaboratories/pframes-rs-node": "1.1.
|
|
23
|
-
"@milaboratories/pframes-rs-wasm": "1.1.
|
|
22
|
+
"@milaboratories/pframes-rs-node": "1.1.38",
|
|
23
|
+
"@milaboratories/pframes-rs-wasm": "1.1.38",
|
|
24
24
|
"canonicalize": "~2.1.0",
|
|
25
25
|
"denque": "^2.1.0",
|
|
26
26
|
"es-toolkit": "^1.39.10",
|
|
@@ -30,24 +30,24 @@
|
|
|
30
30
|
"utility-types": "^3.11.0",
|
|
31
31
|
"yaml": "^2.8.0",
|
|
32
32
|
"zod": "~3.25.76",
|
|
33
|
-
"@milaboratories/
|
|
33
|
+
"@milaboratories/pf-driver": "1.5.0",
|
|
34
34
|
"@milaboratories/computable": "2.9.4",
|
|
35
|
-
"@milaboratories/
|
|
36
|
-
"@milaboratories/pf-spec-driver": "1.
|
|
37
|
-
"@milaboratories/
|
|
38
|
-
"@milaboratories/pl-
|
|
35
|
+
"@milaboratories/pl-client": "3.10.1",
|
|
36
|
+
"@milaboratories/pf-spec-driver": "1.4.0",
|
|
37
|
+
"@milaboratories/helpers": "1.14.2",
|
|
38
|
+
"@milaboratories/pl-errors": "1.4.16",
|
|
39
39
|
"@milaboratories/pl-http": "1.2.4",
|
|
40
|
-
"@milaboratories/pl-
|
|
41
|
-
"@milaboratories/pl-model-backend": "1.
|
|
42
|
-
"@milaboratories/pl-
|
|
43
|
-
"@milaboratories/pl-model-common": "1.
|
|
44
|
-
"@milaboratories/pl-tree": "1.12.4",
|
|
45
|
-
"@milaboratories/resolve-helper": "1.1.3",
|
|
46
|
-
"@milaboratories/pl-model-middle-layer": "1.24.0",
|
|
47
|
-
"@platforma-sdk/block-tools": "2.9.4",
|
|
40
|
+
"@milaboratories/pl-deployments": "3.0.2",
|
|
41
|
+
"@milaboratories/pl-model-backend": "1.4.1",
|
|
42
|
+
"@milaboratories/pl-drivers": "1.14.16",
|
|
43
|
+
"@milaboratories/pl-model-common": "1.43.0",
|
|
48
44
|
"@milaboratories/ts-helpers": "1.8.2",
|
|
49
|
-
"@
|
|
50
|
-
"@
|
|
45
|
+
"@milaboratories/pl-tree": "1.12.6",
|
|
46
|
+
"@milaboratories/resolve-helper": "1.1.3",
|
|
47
|
+
"@milaboratories/pl-model-middle-layer": "1.26.0",
|
|
48
|
+
"@platforma-sdk/block-tools": "2.10.1",
|
|
49
|
+
"@platforma-sdk/model": "1.77.18",
|
|
50
|
+
"@platforma-sdk/workflow-tengo": "6.1.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "~24.5.2",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"semver": "^7.7.2",
|
|
57
57
|
"typescript": "~5.9.3",
|
|
58
58
|
"vitest": "^4.1.3",
|
|
59
|
-
"@milaboratories/ts-configs": "1.2.3",
|
|
60
59
|
"@milaboratories/build-configs": "2.0.0",
|
|
60
|
+
"@milaboratories/ts-configs": "1.2.3",
|
|
61
61
|
"@milaboratories/ts-builder": "1.5.0"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
PColumnValues,
|
|
11
11
|
PTableColumnId,
|
|
12
12
|
PTableColumnSpec,
|
|
13
|
+
PTableRecordFilter,
|
|
13
14
|
SingleAxisSelector,
|
|
14
15
|
BuildQueryInput,
|
|
15
16
|
DeleteColumnRequest,
|
|
@@ -127,6 +128,16 @@ export function getServiceInjectors(): ServiceInjectorMap {
|
|
|
127
128
|
vm.importObjectViaJson(selector) as PTableColumnId,
|
|
128
129
|
),
|
|
129
130
|
),
|
|
131
|
+
|
|
132
|
+
rewriteLegacyFilters: (request: QuickJSHandle) =>
|
|
133
|
+
vm.exportObjectViaJson(
|
|
134
|
+
driver.rewriteLegacyFilters(
|
|
135
|
+
vm.importObjectViaJson(request) as {
|
|
136
|
+
tableSpec: PTableColumnSpec[];
|
|
137
|
+
filters: PTableRecordFilter[];
|
|
138
|
+
},
|
|
139
|
+
),
|
|
140
|
+
),
|
|
130
141
|
};
|
|
131
142
|
},
|
|
132
143
|
|
|
@@ -6,12 +6,14 @@ import type {
|
|
|
6
6
|
TemplateDataV3,
|
|
7
7
|
TemplateLibDataV3,
|
|
8
8
|
TemplateSoftwareDataV3,
|
|
9
|
+
TemplateWasmDataV3,
|
|
9
10
|
} from "@milaboratories/pl-model-backend";
|
|
10
11
|
import {
|
|
11
12
|
PlTemplateLibV1,
|
|
12
13
|
PlTemplateSoftwareV1,
|
|
13
14
|
PlTemplateV1,
|
|
14
15
|
PlTemplateOverrideV1,
|
|
16
|
+
PlWasmV1,
|
|
15
17
|
} from "@milaboratories/pl-model-backend";
|
|
16
18
|
import { notEmpty } from "@milaboratories/ts-helpers";
|
|
17
19
|
|
|
@@ -90,6 +92,26 @@ const LibRenderer: Renderer<TemplateLibDataV3> = {
|
|
|
90
92
|
},
|
|
91
93
|
};
|
|
92
94
|
|
|
95
|
+
const WasmRenderer: Renderer<TemplateWasmDataV3> = {
|
|
96
|
+
updateCacheKey(resource, hash, sources) {
|
|
97
|
+
hash
|
|
98
|
+
.update(PlWasmV1.type.name)
|
|
99
|
+
.update(PlWasmV1.type.version)
|
|
100
|
+
.update(resource.name)
|
|
101
|
+
.update(resource.version)
|
|
102
|
+
.update(getSourceCode(resource.name, sources, resource.sourceHash));
|
|
103
|
+
},
|
|
104
|
+
render(resource, tx, _creator, sources) {
|
|
105
|
+
return tx.createValue(
|
|
106
|
+
PlWasmV1.type,
|
|
107
|
+
JSON.stringify(
|
|
108
|
+
PlWasmV1.fromV3Data(resource, getSourceCode(resource.name, sources, resource.sourceHash))
|
|
109
|
+
.data,
|
|
110
|
+
),
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
93
115
|
const SoftwareInfoRenderer: Renderer<TemplateSoftwareDataV3> = {
|
|
94
116
|
updateCacheKey(resource, hash, sources) {
|
|
95
117
|
hash
|
|
@@ -142,6 +164,10 @@ const TemplateRenderer: Renderer<TemplateDataV3> = {
|
|
|
142
164
|
hash.update("tpl:" + tplId);
|
|
143
165
|
this.updateCacheKey(tpl, hash, sources);
|
|
144
166
|
}
|
|
167
|
+
for (const [wasmId, wasm] of srt(Object.entries(resource.wasm ?? {}))) {
|
|
168
|
+
hash.update("wasm:" + wasmId);
|
|
169
|
+
WasmRenderer.updateCacheKey(wasm, hash, sources);
|
|
170
|
+
}
|
|
145
171
|
},
|
|
146
172
|
render(resource, tx, _creator, sources) {
|
|
147
173
|
const tplRef = tx.createStruct(
|
|
@@ -179,6 +205,15 @@ const TemplateRenderer: Renderer<TemplateDataV3> = {
|
|
|
179
205
|
tx.setField(fld, _creator(depTpl, TemplateRenderer, sources));
|
|
180
206
|
}
|
|
181
207
|
|
|
208
|
+
// Render wasm dependencies. The field name (alias) feeds straight into
|
|
209
|
+
// the backend's TengoTemplateV1.wasm map and becomes the lookup key in
|
|
210
|
+
// RuntimeV1.deps.Wasm consumed by plapi.loadWasm.
|
|
211
|
+
for (const [wasmId, wasm] of Object.entries(resource.wasm ?? {})) {
|
|
212
|
+
const fld = PlTemplateV1.wasmField(tplRef, wasmId);
|
|
213
|
+
tx.createField(fld, "Input");
|
|
214
|
+
tx.setField(fld, _creator(wasm, WasmRenderer, sources));
|
|
215
|
+
}
|
|
216
|
+
|
|
182
217
|
tx.lock(tplRef);
|
|
183
218
|
|
|
184
219
|
if (!resource.hashOverride) return tplRef;
|