@platforma-sdk/model 1.61.1 → 1.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/block_model.cjs +17 -10
  2. package/dist/block_model.cjs.map +1 -1
  3. package/dist/block_model.d.ts +22 -5
  4. package/dist/block_model.js +16 -10
  5. package/dist/block_model.js.map +1 -1
  6. package/dist/columns/column_collection_builder.cjs +26 -14
  7. package/dist/columns/column_collection_builder.cjs.map +1 -1
  8. package/dist/columns/column_collection_builder.d.ts +9 -8
  9. package/dist/columns/column_collection_builder.js +26 -14
  10. package/dist/columns/column_collection_builder.js.map +1 -1
  11. package/dist/columns/ctx_column_sources.cjs.map +1 -1
  12. package/dist/columns/ctx_column_sources.d.ts +1 -1
  13. package/dist/columns/ctx_column_sources.js.map +1 -1
  14. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +93 -89
  15. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
  16. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +2 -2
  17. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +93 -89
  18. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
  19. package/dist/components/PlDataTable/createPlDataTable/index.cjs.map +1 -1
  20. package/dist/components/PlDataTable/createPlDataTable/index.d.ts +2 -1
  21. package/dist/components/PlDataTable/createPlDataTable/index.js.map +1 -1
  22. package/dist/index.cjs +7 -0
  23. package/dist/index.d.ts +6 -2
  24. package/dist/index.js +4 -1
  25. package/dist/package.cjs +1 -1
  26. package/dist/package.js +1 -1
  27. package/dist/platforma.d.ts +8 -4
  28. package/dist/plugin_handle.cjs.map +1 -1
  29. package/dist/plugin_handle.d.ts +13 -7
  30. package/dist/plugin_handle.js.map +1 -1
  31. package/dist/plugin_model.cjs +37 -11
  32. package/dist/plugin_model.cjs.map +1 -1
  33. package/dist/plugin_model.d.ts +80 -39
  34. package/dist/plugin_model.js +37 -11
  35. package/dist/plugin_model.js.map +1 -1
  36. package/dist/render/api.cjs +13 -24
  37. package/dist/render/api.cjs.map +1 -1
  38. package/dist/render/api.d.ts +11 -14
  39. package/dist/render/api.js +13 -24
  40. package/dist/render/api.js.map +1 -1
  41. package/dist/render/internal.cjs.map +1 -1
  42. package/dist/render/internal.d.ts +3 -14
  43. package/dist/render/internal.js.map +1 -1
  44. package/dist/services/block_services.cjs +18 -0
  45. package/dist/services/block_services.cjs.map +1 -0
  46. package/dist/services/block_services.d.ts +18 -0
  47. package/dist/services/block_services.js +16 -0
  48. package/dist/services/block_services.js.map +1 -0
  49. package/dist/services/index.cjs +2 -0
  50. package/dist/services/index.d.ts +3 -0
  51. package/dist/services/index.js +2 -0
  52. package/dist/services/service_bridge.cjs +35 -0
  53. package/dist/services/service_bridge.cjs.map +1 -0
  54. package/dist/services/service_bridge.d.ts +18 -0
  55. package/dist/services/service_bridge.js +33 -0
  56. package/dist/services/service_bridge.js.map +1 -0
  57. package/dist/services/service_resolve.d.ts +13 -0
  58. package/package.json +9 -9
  59. package/src/block_model.ts +47 -14
  60. package/src/columns/column_collection_builder.test.ts +23 -2
  61. package/src/columns/column_collection_builder.ts +38 -30
  62. package/src/columns/ctx_column_sources.ts +2 -2
  63. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +159 -153
  64. package/src/components/PlDataTable/createPlDataTable/index.ts +5 -4
  65. package/src/index.ts +1 -0
  66. package/src/platforma.ts +14 -2
  67. package/src/plugin_handle.ts +24 -6
  68. package/src/plugin_model.ts +252 -84
  69. package/src/render/api.ts +50 -51
  70. package/src/render/internal.ts +3 -38
  71. package/src/services/block_services.ts +17 -0
  72. package/src/services/index.ts +3 -0
  73. package/src/services/service_bridge.ts +71 -0
  74. package/src/services/service_resolve.ts +71 -0
@@ -1 +1 @@
1
- {"version":3,"file":"internal.js","names":[],"sources":["../../src/render/internal.ts"],"sourcesContent":["import type { Optional } from \"utility-types\";\nimport type {\n AxesId,\n AxesSpec,\n Branded,\n DiscoverColumnsRequest,\n DiscoverColumnsResponse,\n PTableColumnId,\n PTableColumnSpec,\n SingleAxisSelector,\n StringifiedJson,\n} from \"@milaboratories/pl-model-common\";\nimport type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from \"./traversal_ops\";\nimport type {\n ArchiveFormat,\n AnyFunction,\n Option,\n PColumn,\n PColumnValues,\n PFrameDef,\n PFrameHandle,\n PObject,\n PObjectSpec,\n PSpecPredicate,\n PTableDef,\n PTableDefV2,\n PTableHandle,\n ResultCollection,\n ValueOrError,\n DataInfo,\n RangeBytes,\n PColumnSpec,\n} from \"@milaboratories/pl-model-common\";\nimport type { TreeNodeAccessor } from \"./accessor\";\n\nexport const StagingAccessorName = \"staging\";\nexport const MainAccessorName = \"main\";\n\nexport type AccessorHandle = Branded<string, \"AccessorHandle\">;\nexport type FutureHandle = Branded<string, \"FutureHandle\">;\n\nexport type PColumnDataUniversal<TreeEntry = TreeNodeAccessor> =\n | TreeEntry\n | DataInfo<TreeEntry>\n | PColumnValues;\n\nexport interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = FutureHandle> {\n //\n // Root accessor creation\n //\n\n getAccessorHandleByName(name: string): AHandle | undefined;\n\n //\n // Basic resource accessor actions\n //\n\n resolveWithCommon(\n handle: AHandle,\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): AHandle | undefined;\n\n getResourceType(handle: AHandle): ResourceType;\n\n getInputsLocked(handle: AHandle): boolean;\n\n getOutputsLocked(handle: AHandle): boolean;\n\n getIsReadyOrError(handle: AHandle): boolean;\n\n getIsFinal(handle: AHandle): boolean;\n\n getError(handle: AHandle): AHandle | undefined;\n\n listInputFields(handle: AHandle): string[];\n\n listOutputFields(handle: AHandle): string[];\n\n listDynamicFields(handle: AHandle): string[];\n\n getKeyValueBase64(handle: AHandle, key: string): string | undefined;\n\n getKeyValueAsString(handle: AHandle, key: string): string | undefined;\n\n getDataBase64(handle: AHandle): string | undefined;\n\n getDataAsString(handle: AHandle): string | undefined;\n\n /** If not final returns undefined */\n parsePObjectCollection(\n handle: AHandle,\n errorOnUnknownField: boolean,\n prefix: string,\n ...resolvePath: string[]\n ): Record<string, PObject<AHandle>> | undefined;\n\n //\n // Blob\n //\n\n getBlobContentAsBase64(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getBlobContentAsString(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getDownloadedBlobContentHandle(handle: AHandle): FHandle; // LocalBlobHandleAndSize | undefined;\n\n getOnDemandBlobContentHandle(handle: AHandle): FHandle; // RemoteBlobHandleAndSize | undefined;\n\n //\n // Blobs to URLs\n //\n\n extractArchiveAndGetURL(handle: AHandle, format: ArchiveFormat): FHandle;\n\n //\n // Import progress\n //\n\n getImportProgress(handle: AHandle): FHandle; // ImportProgress;\n\n //\n // Logs\n //\n\n getLastLogs(handle: AHandle, nLines: number): FHandle; // string | undefined;\n\n getProgressLog(handle: AHandle, patternToSearch: string): FHandle; // string | undefined;\n\n getProgressLogWithInfo(handle: AHandle, patternToSearch: string): FHandle; // ProgressLogWithInfo | undefined;\n\n getLogHandle(handle: AHandle): FHandle; // AnyLogHandle | undefined;\n\n //\n // Blocks\n //\n\n /** @deprecated at some point will stop working and will return dummy values */\n getBlockLabel(blockId: string): string;\n\n //\n // Result Pool\n //\n\n getDataFromResultPool(): ResultCollection<PObject<AHandle>>;\n\n getDataWithErrorsFromResultPool(): ResultCollection<\n Optional<PObject<ValueOrError<AHandle, Error>>, \"id\">\n >;\n\n getSpecsFromResultPool(): ResultCollection<PObjectSpec>;\n\n getSpecFromResultPoolByRef(blockId: string, exportName: string): PObjectSpec | undefined;\n\n getDataFromResultPoolByRef(blockId: string, exportName: string): PObject<AHandle> | undefined;\n\n calculateOptions(predicate: PSpecPredicate): Option[];\n\n //\n // PFrame / PTable\n //\n\n createPFrame(def: PFrameDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PFrameHandle;\n\n createPTable(def: PTableDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PTableHandle;\n\n createPTableV2(\n def: PTableDefV2<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>,\n ): PTableHandle;\n\n //\n // Spec Frames (synchronous WASM-based PFrame for spec-level operations)\n //\n\n createSpecFrame(specs: Record<string, PColumnSpec>): string;\n\n specFrameDiscoverColumns(\n handle: string,\n request: DiscoverColumnsRequest,\n ): DiscoverColumnsResponse;\n\n disposeSpecFrame(handle: string): void;\n\n /** Expand index-based parentAxes in AxesSpec to resolved AxisId parents in AxesId. */\n expandAxes(spec: AxesSpec): AxesId;\n\n /** Collapse resolved AxisId parents back to index-based parentAxes in AxesSpec. */\n collapseAxes(ids: AxesId): AxesSpec;\n\n /** Find the index of an axis matching the given selector. Returns -1 if not found. */\n findAxis(spec: AxesSpec, selector: SingleAxisSelector): number;\n\n /** Find the flat index of a table column matching the given selector. Returns -1 if not found. */\n findTableColumn(tableSpec: PTableColumnSpec[], selector: PTableColumnId): number;\n\n //\n // Computable\n //\n\n getCurrentUnstableMarker(): string | undefined;\n\n //\n // Logging\n //\n\n logInfo(message: string): void;\n\n logWarn(message: string): void;\n\n logError(message: string): void;\n}\n\nexport const GlobalCfgRenderCtxFeatureFlags = {\n explicitColumnsSupport: true as const,\n inlineColumnsSupport: true as const,\n activeArgs: true as const,\n pTablePartitionFiltersSupport: true as const,\n pFrameInSetFilterSupport: true as const,\n};\n\nexport interface GlobalCfgRenderCtx extends GlobalCfgRenderCtxMethods {\n //\n // State: Args, UI State, Active Args\n //\n // Old runtime injects these values as strings, new runtime injects them as functions\n // that return strings, if block declares supportsLazyState flag.\n // If function not called in lazy state API, then resulting output will not depend on these values,\n // and thus will not be recalculated on corresponding state change.\n //\n\n readonly args: string | (() => string);\n /** @deprecated Use `data` instead. Optional for backward compatibility - falls back to `data` if not injected. */\n readonly uiState?: string | (() => string);\n readonly data: string | (() => string);\n readonly activeArgs: undefined | string | (() => string | undefined);\n\n readonly blockStorage: () => StringifiedJson;\n\n // Note: strings below are used because, anyway, using strings is the only way\n // to get data inside the QuickJS context, as it is implemented now. With this\n // approach deserialization can be lazily postponed until it is actually needed.\n readonly callbackRegistry: Record<string, AnyFunction>;\n readonly featureFlags?: typeof GlobalCfgRenderCtxFeatureFlags;\n}\n\nexport type FutureAwait = {\n __awaited_futures__: FutureHandle[];\n};\n\nexport function isFutureAwait(obj: unknown): obj is FutureAwait {\n return typeof obj === \"object\" && obj !== null && \"__awaited_futures__\" in obj;\n}\n\nfunction addAllFutureAwaits(set: Set<string>, visited: Set<unknown>, node: unknown) {\n if (visited.has(node)) return;\n visited.add(node);\n\n const type = typeof node;\n if (type === \"object\") {\n if (isFutureAwait(node)) node.__awaited_futures__.forEach((a) => set.add(a));\n else if (Array.isArray(node))\n for (const nested of node) addAllFutureAwaits(set, visited, nested);\n else\n for (const [, nested] of Object.entries(node as object))\n if (nested !== node) addAllFutureAwaits(set, visited, nested);\n }\n}\n\nexport function getAllFutureAwaits(obj: unknown): Set<string> {\n const set = new Set<string>();\n addAllFutureAwaits(set, new Set(), obj);\n return set;\n}\n"],"mappings":";;;;;;;;;;AAmCA,MAAa,sBAAsB;AACnC,MAAa,mBAAmB;AAgLhC,MAAa,iCAAiC;CAC5C,wBAAwB;CACxB,sBAAsB;CACtB,YAAY;CACZ,+BAA+B;CAC/B,0BAA0B;CAC3B;AA+BD,SAAgB,cAAc,KAAkC;AAC9D,QAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,yBAAyB;;AAG7E,SAAS,mBAAmB,KAAkB,SAAuB,MAAe;AAClF,KAAI,QAAQ,IAAI,KAAK,CAAE;AACvB,SAAQ,IAAI,KAAK;AAGjB,KADa,OAAO,SACP,UACX;MAAI,cAAc,KAAK,CAAE,MAAK,oBAAoB,SAAS,MAAM,IAAI,IAAI,EAAE,CAAC;WACnE,MAAM,QAAQ,KAAK,CAC1B,MAAK,MAAM,UAAU,KAAM,oBAAmB,KAAK,SAAS,OAAO;MAEnE,MAAK,MAAM,GAAG,WAAW,OAAO,QAAQ,KAAe,CACrD,KAAI,WAAW,KAAM,oBAAmB,KAAK,SAAS,OAAO;;;AAIrE,SAAgB,mBAAmB,KAA2B;CAC5D,MAAM,sBAAM,IAAI,KAAa;AAC7B,oBAAmB,qBAAK,IAAI,KAAK,EAAE,IAAI;AACvC,QAAO"}
1
+ {"version":3,"file":"internal.js","names":[],"sources":["../../src/render/internal.ts"],"sourcesContent":["import type { Optional } from \"utility-types\";\nimport type { Branded, StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from \"./traversal_ops\";\nimport type {\n ArchiveFormat,\n AnyFunction,\n Option,\n PColumn,\n PColumnValues,\n PFrameDef,\n PFrameHandle,\n PObject,\n PObjectSpec,\n PSpecPredicate,\n PTableDef,\n PTableDefV2,\n PTableHandle,\n ResultCollection,\n ValueOrError,\n DataInfo,\n RangeBytes,\n} from \"@milaboratories/pl-model-common\";\nimport type { TreeNodeAccessor } from \"./accessor\";\nimport type { ServiceDispatch } from \"@milaboratories/pl-model-common\";\n\nexport const StagingAccessorName = \"staging\";\nexport const MainAccessorName = \"main\";\n\nexport type AccessorHandle = Branded<string, \"AccessorHandle\">;\nexport type FutureHandle = Branded<string, \"FutureHandle\">;\n\nexport type PColumnDataUniversal<TreeEntry = TreeNodeAccessor> =\n | TreeEntry\n | DataInfo<TreeEntry>\n | PColumnValues;\n\nexport interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = FutureHandle> {\n //\n // Root accessor creation\n //\n\n getAccessorHandleByName(name: string): AHandle | undefined;\n\n //\n // Basic resource accessor actions\n //\n\n resolveWithCommon(\n handle: AHandle,\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): AHandle | undefined;\n\n getResourceType(handle: AHandle): ResourceType;\n\n getInputsLocked(handle: AHandle): boolean;\n\n getOutputsLocked(handle: AHandle): boolean;\n\n getIsReadyOrError(handle: AHandle): boolean;\n\n getIsFinal(handle: AHandle): boolean;\n\n getError(handle: AHandle): AHandle | undefined;\n\n listInputFields(handle: AHandle): string[];\n\n listOutputFields(handle: AHandle): string[];\n\n listDynamicFields(handle: AHandle): string[];\n\n getKeyValueBase64(handle: AHandle, key: string): string | undefined;\n\n getKeyValueAsString(handle: AHandle, key: string): string | undefined;\n\n getDataBase64(handle: AHandle): string | undefined;\n\n getDataAsString(handle: AHandle): string | undefined;\n\n /** If not final returns undefined */\n parsePObjectCollection(\n handle: AHandle,\n errorOnUnknownField: boolean,\n prefix: string,\n ...resolvePath: string[]\n ): Record<string, PObject<AHandle>> | undefined;\n\n //\n // Blob\n //\n\n getBlobContentAsBase64(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getBlobContentAsString(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getDownloadedBlobContentHandle(handle: AHandle): FHandle; // LocalBlobHandleAndSize | undefined;\n\n getOnDemandBlobContentHandle(handle: AHandle): FHandle; // RemoteBlobHandleAndSize | undefined;\n\n //\n // Blobs to URLs\n //\n\n extractArchiveAndGetURL(handle: AHandle, format: ArchiveFormat): FHandle;\n\n //\n // Import progress\n //\n\n getImportProgress(handle: AHandle): FHandle; // ImportProgress;\n\n //\n // Logs\n //\n\n getLastLogs(handle: AHandle, nLines: number): FHandle; // string | undefined;\n\n getProgressLog(handle: AHandle, patternToSearch: string): FHandle; // string | undefined;\n\n getProgressLogWithInfo(handle: AHandle, patternToSearch: string): FHandle; // ProgressLogWithInfo | undefined;\n\n getLogHandle(handle: AHandle): FHandle; // AnyLogHandle | undefined;\n\n //\n // Blocks\n //\n\n /** @deprecated at some point will stop working and will return dummy values */\n getBlockLabel(blockId: string): string;\n\n //\n // Result Pool\n //\n\n getDataFromResultPool(): ResultCollection<PObject<AHandle>>;\n\n getDataWithErrorsFromResultPool(): ResultCollection<\n Optional<PObject<ValueOrError<AHandle, Error>>, \"id\">\n >;\n\n getSpecsFromResultPool(): ResultCollection<PObjectSpec>;\n\n getSpecFromResultPoolByRef(blockId: string, exportName: string): PObjectSpec | undefined;\n\n getDataFromResultPoolByRef(blockId: string, exportName: string): PObject<AHandle> | undefined;\n\n calculateOptions(predicate: PSpecPredicate): Option[];\n\n //\n // PFrame / PTable\n //\n\n createPFrame(def: PFrameDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PFrameHandle;\n\n createPTable(def: PTableDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PTableHandle;\n\n createPTableV2(\n def: PTableDefV2<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>,\n ): PTableHandle;\n\n //\n // Computable\n //\n\n getCurrentUnstableMarker(): string | undefined;\n\n //\n // Logging\n //\n\n logInfo(message: string): void;\n\n logWarn(message: string): void;\n\n logError(message: string): void;\n}\n\nexport const GlobalCfgRenderCtxFeatureFlags = {\n explicitColumnsSupport: true as const,\n inlineColumnsSupport: true as const,\n activeArgs: true as const,\n pTablePartitionFiltersSupport: true as const,\n pFrameInSetFilterSupport: true as const,\n};\n\nexport interface GlobalCfgRenderCtx extends GlobalCfgRenderCtxMethods, ServiceDispatch {\n //\n // State: Args, UI State, Active Args\n //\n // Old runtime injects these values as strings, new runtime injects them as functions\n // that return strings, if block declares supportsLazyState flag.\n // If function not called in lazy state API, then resulting output will not depend on these values,\n // and thus will not be recalculated on corresponding state change.\n //\n\n readonly args: string | (() => string);\n /** @deprecated Use `data` instead. Optional for backward compatibility - falls back to `data` if not injected. */\n readonly uiState?: string | (() => string);\n readonly data: string | (() => string);\n readonly activeArgs: undefined | string | (() => string | undefined);\n\n readonly blockStorage: () => StringifiedJson;\n\n // Note: strings below are used because, anyway, using strings is the only way\n // to get data inside the QuickJS context, as it is implemented now. With this\n // approach deserialization can be lazily postponed until it is actually needed.\n readonly callbackRegistry: Record<string, AnyFunction>;\n readonly featureFlags?: typeof GlobalCfgRenderCtxFeatureFlags;\n}\n\nexport type FutureAwait = {\n __awaited_futures__: FutureHandle[];\n};\n\nexport function isFutureAwait(obj: unknown): obj is FutureAwait {\n return typeof obj === \"object\" && obj !== null && \"__awaited_futures__\" in obj;\n}\n\nfunction addAllFutureAwaits(set: Set<string>, visited: Set<unknown>, node: unknown) {\n if (visited.has(node)) return;\n visited.add(node);\n\n const type = typeof node;\n if (type === \"object\") {\n if (isFutureAwait(node)) node.__awaited_futures__.forEach((a) => set.add(a));\n else if (Array.isArray(node))\n for (const nested of node) addAllFutureAwaits(set, visited, nested);\n else\n for (const [, nested] of Object.entries(node as object))\n if (nested !== node) addAllFutureAwaits(set, visited, nested);\n }\n}\n\nexport function getAllFutureAwaits(obj: unknown): Set<string> {\n const set = new Set<string>();\n addAllFutureAwaits(set, new Set(), obj);\n return set;\n}\n"],"mappings":";;;;;;;;;;AAyBA,MAAa,sBAAsB;AACnC,MAAa,mBAAmB;AAuJhC,MAAa,iCAAiC;CAC5C,wBAAwB;CACxB,sBAAsB;CACtB,YAAY;CACZ,+BAA+B;CAC/B,0BAA0B;CAC3B;AA+BD,SAAgB,cAAc,KAAkC;AAC9D,QAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,yBAAyB;;AAG7E,SAAS,mBAAmB,KAAkB,SAAuB,MAAe;AAClF,KAAI,QAAQ,IAAI,KAAK,CAAE;AACvB,SAAQ,IAAI,KAAK;AAGjB,KADa,OAAO,SACP,UACX;MAAI,cAAc,KAAK,CAAE,MAAK,oBAAoB,SAAS,MAAM,IAAI,IAAI,EAAE,CAAC;WACnE,MAAM,QAAQ,KAAK,CAC1B,MAAK,MAAM,UAAU,KAAM,oBAAmB,KAAK,SAAS,OAAO;MAEnE,MAAK,MAAM,GAAG,WAAW,OAAO,QAAQ,KAAe,CACrD,KAAI,WAAW,KAAM,oBAAmB,KAAK,SAAS,OAAO;;;AAIrE,SAAgB,mBAAmB,KAA2B;CAC5D,MAAM,sBAAM,IAAI,KAAa;AAC7B,oBAAmB,qBAAK,IAAI,KAAK,EAAE,IAAI;AACvC,QAAO"}
@@ -0,0 +1,18 @@
1
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
2
+ let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
3
+
4
+ //#region src/services/block_services.ts
5
+ /**
6
+ * Services required by all V3 blocks by default.
7
+ * Edit this when a new service should be available to all blocks.
8
+ *
9
+ * Standalone module to avoid circular dependencies between block_model.ts
10
+ * and service type resolution.
11
+ */
12
+ const BLOCK_SERVICE_FLAGS = { requiresPFrameSpec: true };
13
+ const blockServiceNames = (0, _milaboratories_pl_model_common.resolveRequiredServices)(BLOCK_SERVICE_FLAGS);
14
+
15
+ //#endregion
16
+ exports.BLOCK_SERVICE_FLAGS = BLOCK_SERVICE_FLAGS;
17
+ exports.blockServiceNames = blockServiceNames;
18
+ //# sourceMappingURL=block_services.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block_services.cjs","names":[],"sources":["../../src/services/block_services.ts"],"sourcesContent":["import type { ServiceRequireFlags } from \"@milaboratories/pl-model-common\";\nimport { resolveRequiredServices } from \"@milaboratories/pl-model-common\";\n\n/**\n * Services required by all V3 blocks by default.\n * Edit this when a new service should be available to all blocks.\n *\n * Standalone module to avoid circular dependencies between block_model.ts\n * and service type resolution.\n */\nexport const BLOCK_SERVICE_FLAGS = {\n requiresPFrameSpec: true,\n} as const satisfies Partial<ServiceRequireFlags>;\n\nexport type BlockServiceFlags = typeof BLOCK_SERVICE_FLAGS;\n\nexport const blockServiceNames = resolveRequiredServices(BLOCK_SERVICE_FLAGS);\n"],"mappings":";;;;;;;;;;;AAUA,MAAa,sBAAsB,EACjC,oBAAoB,MACrB;AAID,MAAa,iFAA4C,oBAAoB"}
@@ -0,0 +1,18 @@
1
+ import * as _milaboratories_pl_model_common0 from "@milaboratories/pl-model-common";
2
+
3
+ //#region src/services/block_services.d.ts
4
+ /**
5
+ * Services required by all V3 blocks by default.
6
+ * Edit this when a new service should be available to all blocks.
7
+ *
8
+ * Standalone module to avoid circular dependencies between block_model.ts
9
+ * and service type resolution.
10
+ */
11
+ declare const BLOCK_SERVICE_FLAGS: {
12
+ readonly requiresPFrameSpec: true;
13
+ };
14
+ type BlockServiceFlags = typeof BLOCK_SERVICE_FLAGS;
15
+ declare const blockServiceNames: _milaboratories_pl_model_common0.ServiceName[];
16
+ //#endregion
17
+ export { BLOCK_SERVICE_FLAGS, BlockServiceFlags, blockServiceNames };
18
+ //# sourceMappingURL=block_services.d.ts.map
@@ -0,0 +1,16 @@
1
+ import { resolveRequiredServices } from "@milaboratories/pl-model-common";
2
+
3
+ //#region src/services/block_services.ts
4
+ /**
5
+ * Services required by all V3 blocks by default.
6
+ * Edit this when a new service should be available to all blocks.
7
+ *
8
+ * Standalone module to avoid circular dependencies between block_model.ts
9
+ * and service type resolution.
10
+ */
11
+ const BLOCK_SERVICE_FLAGS = { requiresPFrameSpec: true };
12
+ const blockServiceNames = resolveRequiredServices(BLOCK_SERVICE_FLAGS);
13
+
14
+ //#endregion
15
+ export { BLOCK_SERVICE_FLAGS, blockServiceNames };
16
+ //# sourceMappingURL=block_services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block_services.js","names":[],"sources":["../../src/services/block_services.ts"],"sourcesContent":["import type { ServiceRequireFlags } from \"@milaboratories/pl-model-common\";\nimport { resolveRequiredServices } from \"@milaboratories/pl-model-common\";\n\n/**\n * Services required by all V3 blocks by default.\n * Edit this when a new service should be available to all blocks.\n *\n * Standalone module to avoid circular dependencies between block_model.ts\n * and service type resolution.\n */\nexport const BLOCK_SERVICE_FLAGS = {\n requiresPFrameSpec: true,\n} as const satisfies Partial<ServiceRequireFlags>;\n\nexport type BlockServiceFlags = typeof BLOCK_SERVICE_FLAGS;\n\nexport const blockServiceNames = resolveRequiredServices(BLOCK_SERVICE_FLAGS);\n"],"mappings":";;;;;;;;;;AAUA,MAAa,sBAAsB,EACjC,oBAAoB,MACrB;AAID,MAAa,oBAAoB,wBAAwB,oBAAoB"}
@@ -0,0 +1,2 @@
1
+ const require_block_services = require('./block_services.cjs');
2
+ const require_service_bridge = require('./service_bridge.cjs');
@@ -0,0 +1,3 @@
1
+ import { BLOCK_SERVICE_FLAGS, BlockServiceFlags, blockServiceNames } from "./block_services.js";
2
+ import { BlockDefaultModelServices, BlockDefaultUiServices, ModelServices, ResolveModelServices, ResolveUiServices, UiServices } from "./service_resolve.js";
3
+ import { NodeServiceProxy, buildServices, createNodeServiceProxy } from "./service_bridge.js";
@@ -0,0 +1,2 @@
1
+ import { BLOCK_SERVICE_FLAGS, blockServiceNames } from "./block_services.js";
2
+ import { buildServices, createNodeServiceProxy } from "./service_bridge.js";
@@ -0,0 +1,35 @@
1
+
2
+ //#region src/services/service_bridge.ts
3
+ /**
4
+ * Builds a lazy services object from ServiceDispatch and UiServiceRegistry.
5
+ * Each service is instantiated on first access. Errors are cached to prevent
6
+ * repeated factory calls on failure.
7
+ */
8
+ function buildServices(dispatch, registry) {
9
+ return Object.create(null, Object.fromEntries(dispatch.getServiceNames().map((id) => {
10
+ let fetched = false;
11
+ let cached;
12
+ return [id, {
13
+ enumerable: true,
14
+ get() {
15
+ if (!fetched) {
16
+ fetched = true;
17
+ cached = registry.get(id);
18
+ }
19
+ return cached;
20
+ }
21
+ }];
22
+ })));
23
+ }
24
+ /**
25
+ * Builds a NodeServiceProxy from a ServiceDispatch.
26
+ * Each service method call is forwarded to dispatch.callServiceMethod.
27
+ */
28
+ function createNodeServiceProxy(dispatch) {
29
+ return ((serviceId) => Object.freeze(Object.fromEntries(dispatch.getServiceMethods(serviceId).map((method) => [method, async (...args) => dispatch.callServiceMethod(serviceId, method, ...args)]))));
30
+ }
31
+
32
+ //#endregion
33
+ exports.buildServices = buildServices;
34
+ exports.createNodeServiceProxy = createNodeServiceProxy;
35
+ //# sourceMappingURL=service_bridge.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service_bridge.cjs","names":[],"sources":["../../src/services/service_bridge.ts"],"sourcesContent":["/**\n * Runtime service bridge — builds lazy service objects from dispatch + registry.\n * Used by the UI layer to provide typed service access.\n */\n\nimport type {\n ServiceTypesLike,\n InferServiceUi,\n ServiceName,\n ServiceDispatch,\n UiServices as AllUiServices,\n} from \"@milaboratories/pl-model-common\";\nimport { UiServiceRegistry } from \"@milaboratories/pl-model-common\";\n\n// Makes a remote node service appear local.\n// Given a service ID, returns an object implementing the service's UI interface.\n// Provided by the desktop app (e.g. backed by Electron IPC).\nexport type NodeServiceProxy = <S extends ServiceTypesLike>(\n serviceId: ServiceName<S>,\n) => InferServiceUi<S>;\n\n/**\n * Builds a lazy services object from ServiceDispatch and UiServiceRegistry.\n * Each service is instantiated on first access. Errors are cached to prevent\n * repeated factory calls on failure.\n */\nexport function buildServices<S extends Partial<AllUiServices> = Partial<AllUiServices>>(\n dispatch: ServiceDispatch,\n registry: UiServiceRegistry,\n): S {\n return Object.create(\n null,\n Object.fromEntries(\n dispatch.getServiceNames().map((id) => {\n let fetched = false;\n let cached: unknown;\n return [\n id,\n {\n enumerable: true,\n get() {\n if (!fetched) {\n fetched = true;\n cached = registry.get(id);\n }\n return cached;\n },\n },\n ];\n }),\n ),\n );\n}\n\n/**\n * Builds a NodeServiceProxy from a ServiceDispatch.\n * Each service method call is forwarded to dispatch.callServiceMethod.\n */\nexport function createNodeServiceProxy(dispatch: ServiceDispatch): NodeServiceProxy {\n return ((serviceId: ServiceName) =>\n Object.freeze(\n Object.fromEntries(\n dispatch\n .getServiceMethods(serviceId)\n .map((method) => [\n method,\n async (...args: unknown[]) => dispatch.callServiceMethod(serviceId, method, ...args),\n ]),\n ),\n )) as NodeServiceProxy;\n}\n"],"mappings":";;;;;;;AA0BA,SAAgB,cACd,UACA,UACG;AACH,QAAO,OAAO,OACZ,MACA,OAAO,YACL,SAAS,iBAAiB,CAAC,KAAK,OAAO;EACrC,IAAI,UAAU;EACd,IAAI;AACJ,SAAO,CACL,IACA;GACE,YAAY;GACZ,MAAM;AACJ,QAAI,CAAC,SAAS;AACZ,eAAU;AACV,cAAS,SAAS,IAAI,GAAG;;AAE3B,WAAO;;GAEV,CACF;GACD,CACH,CACF;;;;;;AAOH,SAAgB,uBAAuB,UAA6C;AAClF,UAAS,cACP,OAAO,OACL,OAAO,YACL,SACG,kBAAkB,UAAU,CAC5B,KAAK,WAAW,CACf,QACA,OAAO,GAAG,SAAoB,SAAS,kBAAkB,WAAW,QAAQ,GAAG,KAAK,CACrF,CAAC,CACL,CACF"}
@@ -0,0 +1,18 @@
1
+ import { InferServiceUi, ServiceDispatch, ServiceName, ServiceTypesLike, UiServiceRegistry, UiServices } from "@milaboratories/pl-model-common";
2
+
3
+ //#region src/services/service_bridge.d.ts
4
+ type NodeServiceProxy = <S extends ServiceTypesLike>(serviceId: ServiceName<S>) => InferServiceUi<S>;
5
+ /**
6
+ * Builds a lazy services object from ServiceDispatch and UiServiceRegistry.
7
+ * Each service is instantiated on first access. Errors are cached to prevent
8
+ * repeated factory calls on failure.
9
+ */
10
+ declare function buildServices<S extends Partial<UiServices> = Partial<UiServices>>(dispatch: ServiceDispatch, registry: UiServiceRegistry): S;
11
+ /**
12
+ * Builds a NodeServiceProxy from a ServiceDispatch.
13
+ * Each service method call is forwarded to dispatch.callServiceMethod.
14
+ */
15
+ declare function createNodeServiceProxy(dispatch: ServiceDispatch): NodeServiceProxy;
16
+ //#endregion
17
+ export { NodeServiceProxy, buildServices, createNodeServiceProxy };
18
+ //# sourceMappingURL=service_bridge.d.ts.map
@@ -0,0 +1,33 @@
1
+ //#region src/services/service_bridge.ts
2
+ /**
3
+ * Builds a lazy services object from ServiceDispatch and UiServiceRegistry.
4
+ * Each service is instantiated on first access. Errors are cached to prevent
5
+ * repeated factory calls on failure.
6
+ */
7
+ function buildServices(dispatch, registry) {
8
+ return Object.create(null, Object.fromEntries(dispatch.getServiceNames().map((id) => {
9
+ let fetched = false;
10
+ let cached;
11
+ return [id, {
12
+ enumerable: true,
13
+ get() {
14
+ if (!fetched) {
15
+ fetched = true;
16
+ cached = registry.get(id);
17
+ }
18
+ return cached;
19
+ }
20
+ }];
21
+ })));
22
+ }
23
+ /**
24
+ * Builds a NodeServiceProxy from a ServiceDispatch.
25
+ * Each service method call is forwarded to dispatch.callServiceMethod.
26
+ */
27
+ function createNodeServiceProxy(dispatch) {
28
+ return ((serviceId) => Object.freeze(Object.fromEntries(dispatch.getServiceMethods(serviceId).map((method) => [method, async (...args) => dispatch.callServiceMethod(serviceId, method, ...args)]))));
29
+ }
30
+
31
+ //#endregion
32
+ export { buildServices, createNodeServiceProxy };
33
+ //# sourceMappingURL=service_bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service_bridge.js","names":[],"sources":["../../src/services/service_bridge.ts"],"sourcesContent":["/**\n * Runtime service bridge — builds lazy service objects from dispatch + registry.\n * Used by the UI layer to provide typed service access.\n */\n\nimport type {\n ServiceTypesLike,\n InferServiceUi,\n ServiceName,\n ServiceDispatch,\n UiServices as AllUiServices,\n} from \"@milaboratories/pl-model-common\";\nimport { UiServiceRegistry } from \"@milaboratories/pl-model-common\";\n\n// Makes a remote node service appear local.\n// Given a service ID, returns an object implementing the service's UI interface.\n// Provided by the desktop app (e.g. backed by Electron IPC).\nexport type NodeServiceProxy = <S extends ServiceTypesLike>(\n serviceId: ServiceName<S>,\n) => InferServiceUi<S>;\n\n/**\n * Builds a lazy services object from ServiceDispatch and UiServiceRegistry.\n * Each service is instantiated on first access. Errors are cached to prevent\n * repeated factory calls on failure.\n */\nexport function buildServices<S extends Partial<AllUiServices> = Partial<AllUiServices>>(\n dispatch: ServiceDispatch,\n registry: UiServiceRegistry,\n): S {\n return Object.create(\n null,\n Object.fromEntries(\n dispatch.getServiceNames().map((id) => {\n let fetched = false;\n let cached: unknown;\n return [\n id,\n {\n enumerable: true,\n get() {\n if (!fetched) {\n fetched = true;\n cached = registry.get(id);\n }\n return cached;\n },\n },\n ];\n }),\n ),\n );\n}\n\n/**\n * Builds a NodeServiceProxy from a ServiceDispatch.\n * Each service method call is forwarded to dispatch.callServiceMethod.\n */\nexport function createNodeServiceProxy(dispatch: ServiceDispatch): NodeServiceProxy {\n return ((serviceId: ServiceName) =>\n Object.freeze(\n Object.fromEntries(\n dispatch\n .getServiceMethods(serviceId)\n .map((method) => [\n method,\n async (...args: unknown[]) => dispatch.callServiceMethod(serviceId, method, ...args),\n ]),\n ),\n )) as NodeServiceProxy;\n}\n"],"mappings":";;;;;;AA0BA,SAAgB,cACd,UACA,UACG;AACH,QAAO,OAAO,OACZ,MACA,OAAO,YACL,SAAS,iBAAiB,CAAC,KAAK,OAAO;EACrC,IAAI,UAAU;EACd,IAAI;AACJ,SAAO,CACL,IACA;GACE,YAAY;GACZ,MAAM;AACJ,QAAI,CAAC,SAAS;AACZ,eAAU;AACV,cAAS,SAAS,IAAI,GAAG;;AAE3B,WAAO;;GAEV,CACF;GACD,CACH,CACF;;;;;;AAOH,SAAgB,uBAAuB,UAA6C;AAClF,UAAS,cACP,OAAO,OACL,OAAO,YACL,SACG,kBAAkB,UAAU,CAC5B,KAAK,WAAW,CACf,QACA,OAAO,GAAG,SAAoB,SAAS,kBAAkB,WAAW,QAAQ,GAAG,KAAK,CACrF,CAAC,CACL,CACF"}
@@ -0,0 +1,13 @@
1
+ import { BlockServiceFlags } from "./block_services.js";
2
+ import { ModelServices as ModelServices$1, ServiceNameLiterals, UiServices as UiServices$1 } from "@milaboratories/pl-model-common";
3
+
4
+ //#region src/services/service_resolve.d.ts
5
+ type FlagToName<Flag extends string> = Flag extends `requires${infer K}` ? K extends keyof ServiceNameLiterals ? ServiceNameLiterals[K] : never : never;
6
+ type RequiredServiceNames<Flags> = { [K in keyof Flags & `requires${string}`]: Flags[K] extends true ? FlagToName<K & string> : never }[keyof Flags & `requires${string}`];
7
+ type ResolveModelServices<Flags> = Pick<ModelServices$1, RequiredServiceNames<Flags> & keyof ModelServices$1>;
8
+ type ResolveUiServices<Flags> = Pick<UiServices$1, RequiredServiceNames<Flags> & keyof UiServices$1>;
9
+ type BlockDefaultModelServices = ResolveModelServices<BlockServiceFlags>;
10
+ type BlockDefaultUiServices = ResolveUiServices<BlockServiceFlags>;
11
+ //#endregion
12
+ export { BlockDefaultModelServices, BlockDefaultUiServices, type ModelServices$1 as ModelServices, ResolveModelServices, ResolveUiServices, type UiServices$1 as UiServices };
13
+ //# sourceMappingURL=service_resolve.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/model",
3
- "version": "1.61.1",
3
+ "version": "1.62.0",
4
4
  "description": "Platforma.bio SDK / Block Model",
5
5
  "files": [
6
6
  "./dist/**/*",
@@ -31,10 +31,10 @@
31
31
  "utility-types": "^3.11.0",
32
32
  "zod": "~3.23.8",
33
33
  "@milaboratories/helpers": "1.14.0",
34
- "@milaboratories/pl-model-common": "1.29.0",
35
- "@milaboratories/pl-model-middle-layer": "1.16.0",
36
- "@milaboratories/ptabler-expression-js": "1.2.2",
37
- "@milaboratories/pl-error-like": "1.12.9"
34
+ "@milaboratories/pl-model-common": "1.30.0",
35
+ "@milaboratories/pl-model-middle-layer": "1.16.1",
36
+ "@milaboratories/pl-error-like": "1.12.9",
37
+ "@milaboratories/ptabler-expression-js": "1.2.3"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@vitest/coverage-istanbul": "^4.0.18",
@@ -42,10 +42,10 @@
42
42
  "typescript": "~5.9.3",
43
43
  "vitest": "^4.0.18",
44
44
  "@milaboratories/build-configs": "1.5.2",
45
- "@milaboratories/pf-spec-driver": "1.1.0",
46
- "@milaboratories/pf-driver": "1.2.0",
47
- "@milaboratories/ts-configs": "1.2.2",
48
- "@milaboratories/ts-builder": "1.3.0"
45
+ "@milaboratories/pf-spec-driver": "1.2.0",
46
+ "@milaboratories/ts-builder": "1.3.0",
47
+ "@milaboratories/pf-driver": "1.3.0",
48
+ "@milaboratories/ts-configs": "1.2.2"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "ts-builder build --target node",
@@ -6,9 +6,12 @@ import type {
6
6
  BlockCodeKnownFeatureFlags,
7
7
  BlockConfigContainer,
8
8
  } from "@milaboratories/pl-model-common";
9
+ import { resolveRequiredServices } from "@milaboratories/pl-model-common";
9
10
  import { getPlatformaInstance, isInUI, createAndRegisterRenderLambda } from "./internal";
10
11
  import type { DataModel } from "./block_migrations";
11
12
  import type { PlatformaV3 } from "./platforma";
13
+ import type { BlockDefaultUiServices } from "./services/service_resolve";
14
+ import { blockServiceNames, BLOCK_SERVICE_FLAGS } from "./services/block_services";
12
15
  import type { InferRenderFunctionReturn, RenderFunction } from "./render";
13
16
  import { BlockRenderCtx, PluginRenderCtx } from "./render";
14
17
  import type { PluginData, PluginModel, PluginOutputs, PluginParams } from "./plugin_model";
@@ -87,8 +90,10 @@ export type PluginRecord<
87
90
  Data extends PluginData = PluginData,
88
91
  Params extends PluginParams = undefined,
89
92
  Outputs extends PluginOutputs = PluginOutputs,
93
+ ModelServices = unknown,
94
+ UiServices = unknown,
90
95
  > = {
91
- readonly model: PluginModel<Data, Params, Outputs>;
96
+ readonly model: PluginModel<Data, Params, Outputs, ModelServices, UiServices>;
92
97
  readonly inputs: ParamsInputErased;
93
98
  };
94
99
 
@@ -128,13 +133,17 @@ export class BlockModelV3<
128
133
  private readonly config: BlockModelV3Config<OutputsCfg, Data, Plugins, Transfers>,
129
134
  ) {}
130
135
 
131
- public static readonly INITIAL_BLOCK_FEATURE_FLAGS: BlockCodeKnownFeatureFlags = {
136
+ public static readonly FEATURE_FLAGS = {
132
137
  supportsLazyState: true,
133
138
  supportsPframeQueryRanking: true,
134
139
  requiresUIAPIVersion: 3,
135
140
  requiresModelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,
136
141
  requiresCreatePTable: 2,
137
- };
142
+ ...BLOCK_SERVICE_FLAGS,
143
+ } satisfies BlockCodeKnownFeatureFlags;
144
+
145
+ /** @deprecated Use FEATURE_FLAGS */
146
+ public static readonly INITIAL_BLOCK_FEATURE_FLAGS = BlockModelV3.FEATURE_FLAGS;
138
147
 
139
148
  /**
140
149
  * Creates a new BlockModelV3 builder with the specified data model.
@@ -164,7 +173,7 @@ export class BlockModelV3<
164
173
  subtitle: undefined,
165
174
  tags: undefined,
166
175
  enrichmentTargets: undefined,
167
- featureFlags: { ...BlockModelV3.INITIAL_BLOCK_FEATURE_FLAGS },
176
+ featureFlags: { ...BlockModelV3.FEATURE_FLAGS },
168
177
  argsFunction: undefined,
169
178
  prerunArgsFunction: undefined,
170
179
  plugins: {},
@@ -228,7 +237,7 @@ export class BlockModelV3<
228
237
  ...this.config.outputs,
229
238
  [key]: createAndRegisterRenderLambda({
230
239
  handle: `block-output#${key}`,
231
- lambda: () => cfgOrRf(new BlockRenderCtx<Args, Data>()),
240
+ lambda: () => cfgOrRf(new BlockRenderCtx<Args, Data>(blockServiceNames)),
232
241
  ...flags,
233
242
  }),
234
243
  },
@@ -324,7 +333,10 @@ export class BlockModelV3<
324
333
  ...this.config,
325
334
  // Replace the default sections callback with the user-provided one
326
335
  sections: createAndRegisterRenderLambda(
327
- { handle: "sections", lambda: () => rf(new BlockRenderCtx<Args, Data>()) },
336
+ {
337
+ handle: "sections",
338
+ lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),
339
+ },
328
340
  true,
329
341
  ),
330
342
  },
@@ -339,7 +351,7 @@ export class BlockModelV3<
339
351
  ...this.config,
340
352
  title: createAndRegisterRenderLambda({
341
353
  handle: "title",
342
- lambda: () => rf(new BlockRenderCtx<Args, Data>()),
354
+ lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),
343
355
  }),
344
356
  });
345
357
  }
@@ -351,7 +363,7 @@ export class BlockModelV3<
351
363
  ...this.config,
352
364
  subtitle: createAndRegisterRenderLambda({
353
365
  handle: "subtitle",
354
- lambda: () => rf(new BlockRenderCtx<Args, Data>()),
366
+ lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),
355
367
  }),
356
368
  });
357
369
  }
@@ -363,7 +375,7 @@ export class BlockModelV3<
363
375
  ...this.config,
364
376
  tags: createAndRegisterRenderLambda({
365
377
  handle: "tags",
366
- lambda: () => rf(new BlockRenderCtx<Args, Data>()),
378
+ lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),
367
379
  }),
368
380
  });
369
381
  }
@@ -418,6 +430,8 @@ export class BlockModelV3<
418
430
  PParams extends PluginParams,
419
431
  POutputs extends PluginOutputs,
420
432
  PTransferData,
433
+ PluginModelServices,
434
+ PluginUiServices,
421
435
  >(
422
436
  instance: PluginInstanceClass<
423
437
  PluginId &
@@ -432,7 +446,9 @@ export class BlockModelV3<
432
446
  PData,
433
447
  PParams,
434
448
  POutputs,
435
- PTransferData
449
+ PTransferData,
450
+ PluginModelServices,
451
+ PluginUiServices
436
452
  >,
437
453
  params?: ParamsInput<PParams, Args, Data>,
438
454
  ): BlockModelV3<
@@ -440,7 +456,15 @@ export class BlockModelV3<
440
456
  OutputsCfg,
441
457
  Data,
442
458
  Href,
443
- Plugins & { [K in PluginId]: PluginRecord<PData, PParams, POutputs> },
459
+ Plugins & {
460
+ [K in PluginId]: PluginRecord<
461
+ PData,
462
+ PParams,
463
+ POutputs,
464
+ PluginModelServices,
465
+ PluginUiServices
466
+ >;
467
+ },
444
468
  Omit<Transfers, PluginId>
445
469
  >;
446
470
  public plugin(
@@ -489,7 +513,14 @@ export class BlockModelV3<
489
513
  public done(
490
514
  ..._: keyof Transfers extends never ? [] : [never]
491
515
  ): PlatformaExtended<
492
- PlatformaV3<Data, Args, InferOutputsFromLambdas<OutputsCfg>, Href, Plugins>
516
+ PlatformaV3<
517
+ Data,
518
+ Args,
519
+ InferOutputsFromLambdas<OutputsCfg>,
520
+ Href,
521
+ Plugins,
522
+ BlockDefaultUiServices
523
+ >
493
524
  > {
494
525
  if (this.config.argsFunction === undefined) throw new Error("Args rendering function not set.");
495
526
 
@@ -505,6 +536,8 @@ export class BlockModelV3<
505
536
 
506
537
  const { dataModel, argsFunction, prerunArgsFunction } = this.config;
507
538
 
539
+ const mergedServiceNames = resolveRequiredServices(this.config.featureFlags);
540
+
508
541
  function getPlugin(handle: PluginHandle): PluginRecord {
509
542
  const plugin = plugins[handle];
510
543
  if (!plugin) throw new Error(`Plugin model not found for '${handle}'`);
@@ -544,7 +577,7 @@ export class BlockModelV3<
544
577
  // Wrap plugin param lambdas: close over BlockRenderCtx creation
545
578
  const wrappedInputs: Record<string, () => unknown> = {};
546
579
  for (const [paramKey, paramFn] of Object.entries(inputs)) {
547
- wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx());
580
+ wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx(mergedServiceNames));
548
581
  }
549
582
 
550
583
  // Register plugin outputs (in config pack, evaluated by middle layer)
@@ -554,7 +587,7 @@ export class BlockModelV3<
554
587
  const key = pluginOutputKey(handle, outputKey);
555
588
  pluginOutputs[key] = createAndRegisterRenderLambda({
556
589
  handle: key,
557
- lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs)),
590
+ lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs, mergedServiceNames)),
558
591
  withStatus: outputFlags[outputKey]?.withStatus,
559
592
  });
560
593
  }
@@ -20,8 +20,8 @@ function createSpecFrameCtx() {
20
20
  return driver;
21
21
  }
22
22
 
23
- afterEach(() => {
24
- for (const driver of drivers) driver.dispose();
23
+ afterEach(async () => {
24
+ for (const driver of drivers) await driver.dispose();
25
25
  drivers.length = 0;
26
26
  });
27
27
 
@@ -166,6 +166,27 @@ describe("ColumnCollection.findColumns", () => {
166
166
  expect(results).toHaveLength(1);
167
167
  expect(results[0].spec.name).toBe("col2");
168
168
  });
169
+
170
+ test("include filters by exact name among disjoint-axis columns", () => {
171
+ const vdjAxis = sampleAxis("pl7.app/vdj/clonotypeKey");
172
+ const itemAxis = sampleAxis("item");
173
+
174
+ const vdjColumns = Array.from({ length: 10 }, (_, i) =>
175
+ createSnapshot(`vdj${i}`, createSpec(`pl7.app/vdj/col${i}`, { axesSpec: [vdjAxis] })),
176
+ );
177
+ const mockScore = createSnapshot("mock", createSpec("mock_score", { axesSpec: [itemAxis] }));
178
+
179
+ const builder = new ColumnCollectionBuilder(createSpecFrameCtx());
180
+ builder.addSource([...vdjColumns, mockScore]);
181
+
182
+ const collection = builder.build()!;
183
+ const results = collection.findColumns({
184
+ include: [{ name: [{ type: "exact", value: "mock_score" }] }],
185
+ });
186
+
187
+ expect(results).toHaveLength(1);
188
+ expect(results[0].spec.name).toBe("mock_score");
189
+ });
169
190
  });
170
191
 
171
192
  describe("dedup by native ID", () => {