@platforma-sdk/model 1.61.1 → 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.
Files changed (88) 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/components/PlMultiSequenceAlignment.cjs +1 -1
  23. package/dist/components/PlMultiSequenceAlignment.cjs.map +1 -1
  24. package/dist/components/PlMultiSequenceAlignment.js +2 -2
  25. package/dist/components/PlMultiSequenceAlignment.js.map +1 -1
  26. package/dist/components/PlSelectionModel.cjs.map +1 -1
  27. package/dist/components/PlSelectionModel.d.ts +1 -1
  28. package/dist/components/PlSelectionModel.js.map +1 -1
  29. package/dist/index.cjs +7 -0
  30. package/dist/index.d.ts +6 -2
  31. package/dist/index.js +4 -1
  32. package/dist/package.cjs +1 -1
  33. package/dist/package.js +1 -1
  34. package/dist/pframe_utils/index.cjs +2 -5
  35. package/dist/pframe_utils/index.cjs.map +1 -1
  36. package/dist/pframe_utils/index.js +2 -5
  37. package/dist/pframe_utils/index.js.map +1 -1
  38. package/dist/platforma.d.ts +8 -4
  39. package/dist/plugin_handle.cjs.map +1 -1
  40. package/dist/plugin_handle.d.ts +13 -7
  41. package/dist/plugin_handle.js.map +1 -1
  42. package/dist/plugin_model.cjs +37 -11
  43. package/dist/plugin_model.cjs.map +1 -1
  44. package/dist/plugin_model.d.ts +80 -39
  45. package/dist/plugin_model.js +37 -11
  46. package/dist/plugin_model.js.map +1 -1
  47. package/dist/render/api.cjs +13 -24
  48. package/dist/render/api.cjs.map +1 -1
  49. package/dist/render/api.d.ts +11 -14
  50. package/dist/render/api.js +13 -24
  51. package/dist/render/api.js.map +1 -1
  52. package/dist/render/internal.cjs.map +1 -1
  53. package/dist/render/internal.d.ts +3 -14
  54. package/dist/render/internal.js.map +1 -1
  55. package/dist/services/block_services.cjs +18 -0
  56. package/dist/services/block_services.cjs.map +1 -0
  57. package/dist/services/block_services.d.ts +18 -0
  58. package/dist/services/block_services.js +16 -0
  59. package/dist/services/block_services.js.map +1 -0
  60. package/dist/services/index.cjs +2 -0
  61. package/dist/services/index.d.ts +3 -0
  62. package/dist/services/index.js +2 -0
  63. package/dist/services/service_bridge.cjs +35 -0
  64. package/dist/services/service_bridge.cjs.map +1 -0
  65. package/dist/services/service_bridge.d.ts +18 -0
  66. package/dist/services/service_bridge.js +33 -0
  67. package/dist/services/service_bridge.js.map +1 -0
  68. package/dist/services/service_resolve.d.ts +13 -0
  69. package/package.json +9 -9
  70. package/src/block_model.ts +47 -14
  71. package/src/columns/column_collection_builder.test.ts +23 -2
  72. package/src/columns/column_collection_builder.ts +38 -30
  73. package/src/columns/ctx_column_sources.ts +2 -2
  74. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +159 -153
  75. package/src/components/PlDataTable/createPlDataTable/index.ts +5 -4
  76. package/src/components/PlMultiSequenceAlignment.ts +1 -2
  77. package/src/components/PlSelectionModel.ts +1 -1
  78. package/src/index.ts +1 -0
  79. package/src/pframe_utils/index.ts +2 -6
  80. package/src/platforma.ts +14 -2
  81. package/src/plugin_handle.ts +24 -6
  82. package/src/plugin_model.ts +252 -84
  83. package/src/render/api.ts +50 -51
  84. package/src/render/internal.ts +3 -38
  85. package/src/services/block_services.ts +17 -0
  86. package/src/services/index.ts +3 -0
  87. package/src/services/service_bridge.ts +71 -0
  88. package/src/services/service_resolve.ts +71 -0
@@ -1 +1 @@
1
- {"version":3,"file":"plugin_handle.js","names":[],"sources":["../src/plugin_handle.ts"],"sourcesContent":["/**\n * PluginHandle — Opaque branded handle and output key utilities for plugin instances.\n *\n * Extracted into its own module to break circular dependencies:\n * both block_storage.ts and plugin_model.ts can import from here\n * without depending on each other.\n *\n * @module plugin_handle\n */\n\nimport type { Branded } from \"@milaboratories/helpers\";\n\n/**\n * Phantom-only base type for constraining PluginHandle's type parameter.\n *\n * PluginFactory has create() → PluginInstance with function properties, making it invariant\n * under strictFunctionTypes. PluginFactoryLike exposes only the covariant `__types` phantom,\n * avoiding the contravariance chain. Handles only need `__types` for type extraction.\n *\n * PluginFactory extends PluginFactoryLike, so every concrete factory satisfies this constraint.\n */\nexport interface PluginFactoryLike<\n Data extends Record<string, unknown> = Record<string, unknown>,\n Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,\n Outputs extends Record<string, unknown> = Record<string, unknown>,\n> {\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n };\n}\n\n/** Extract the Data type from a PluginFactoryLike phantom. */\nexport type InferFactoryData<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<infer D, any, any> ? D : Record<string, unknown>\n>;\n\n/** Extract the Params type from a PluginFactoryLike phantom. */\nexport type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, infer P, any> ? P : undefined\n>;\n\n/** Extract the Outputs type from a PluginFactoryLike phantom. */\nexport type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, any, infer O> ? O : Record<string, unknown>\n>;\n\n/**\n * Derive a typed PluginHandle from a PluginFactory type.\n * Normalizes the brand to only data/params/outputs (strips config) so handles\n * from InferPluginHandles match handles from InferPluginHandle.\n */\nexport type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<infer Data, infer Params, infer Outputs>\n ? PluginHandle<PluginFactoryLike<Data, Params, Outputs>>\n : PluginHandle\n>;\n\n/**\n * Opaque handle for a plugin instance. Runtime value is the plugin instance ID string.\n * Branded with factory phantom `F` for type-safe data/outputs extraction.\n * Constrained with PluginFactoryLike (not PluginFactory) to avoid variance issues.\n */\nexport type PluginHandle<F extends PluginFactoryLike = PluginFactoryLike> = Branded<string, F>;\n\nconst PLUGIN_OUTPUT_PREFIX = \"plugin-output#\";\n\n/** Construct the output key for a plugin output in the block outputs map. */\nexport function pluginOutputKey<F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n outputKey: string,\n): string {\n return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;\n}\n\n/** Check whether an output key belongs to a plugin (vs block-level output). */\nexport function isPluginOutputKey(key: string): boolean {\n return key.startsWith(PLUGIN_OUTPUT_PREFIX);\n}\n\n/** Get the prefix used for all outputs of a specific plugin instance. */\nexport function pluginOutputPrefix<F extends PluginFactoryLike>(handle: PluginHandle<F>): string {\n return pluginOutputKey(handle, \"\");\n}\n"],"mappings":";AAkEA,MAAM,uBAAuB;;AAG7B,SAAgB,gBACd,QACA,WACQ;AACR,QAAO,GAAG,uBAAuB,OAAO,GAAG;;;AAI7C,SAAgB,kBAAkB,KAAsB;AACtD,QAAO,IAAI,WAAW,qBAAqB;;;AAI7C,SAAgB,mBAAgD,QAAiC;AAC/F,QAAO,gBAAgB,QAAQ,GAAG"}
1
+ {"version":3,"file":"plugin_handle.js","names":[],"sources":["../src/plugin_handle.ts"],"sourcesContent":["/**\n * PluginHandle — Opaque branded handle and output key utilities for plugin instances.\n *\n * Extracted into its own module to break circular dependencies:\n * both block_storage.ts and plugin_model.ts can import from here\n * without depending on each other.\n *\n * @module plugin_handle\n */\n\nimport type { Branded } from \"@milaboratories/helpers\";\n\n/**\n * Phantom-only base type for constraining PluginHandle's type parameter.\n *\n * PluginFactory has create() → PluginInstance with function properties, making it invariant\n * under strictFunctionTypes. PluginFactoryLike exposes only the covariant `__types` phantom,\n * avoiding the contravariance chain. Handles only need `__types` for type extraction.\n *\n * PluginFactory extends PluginFactoryLike, so every concrete factory satisfies this constraint.\n */\nexport interface PluginFactoryLike<\n Data extends Record<string, unknown> = Record<string, unknown>,\n Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,\n Outputs extends Record<string, unknown> = Record<string, unknown>,\n ModelServices = unknown,\n UiServices = unknown,\n> {\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n };\n}\n\n/** Extract the Data type from a PluginFactoryLike phantom. */\nexport type InferFactoryData<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<infer D, any, any, any, any> ? D : Record<string, unknown>\n>;\n\n/** Extract the Params type from a PluginFactoryLike phantom. */\nexport type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, infer P, any, any, any> ? P : undefined\n>;\n\n/** Extract the Outputs type from a PluginFactoryLike phantom. */\nexport type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, any, infer O, any, any> ? O : Record<string, unknown>\n>;\n\n/** Extract the pre-resolved model services type from a PluginFactoryLike phantom. */\nexport type InferFactoryModelServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, infer ModelServices, any> ? ModelServices : {};\n\n/** Extract the pre-resolved UI services type from a PluginFactoryLike phantom. */\nexport type InferFactoryUiServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, any, infer UiServices> ? UiServices : {};\n\n/**\n * Derive a typed PluginHandle from a PluginFactory type.\n * Normalizes the brand to data/params/outputs/services (strips config) so handles\n * from InferPluginHandles match handles from InferPluginHandle.\n */\nexport type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<\n infer Data,\n infer Params,\n infer Outputs,\n infer ModelServices,\n infer UiServices\n >\n ? PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>>\n : PluginHandle\n>;\n\n/**\n * Opaque handle for a plugin instance. Runtime value is the plugin instance ID string.\n * Branded with factory phantom `F` for type-safe data/outputs extraction.\n * Constrained with PluginFactoryLike (not PluginFactory) to avoid variance issues.\n */\nexport type PluginHandle<F extends PluginFactoryLike = PluginFactoryLike> = Branded<string, F>;\n\nconst PLUGIN_OUTPUT_PREFIX = \"plugin-output#\";\n\n/** Construct the output key for a plugin output in the block outputs map. */\nexport function pluginOutputKey<F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n outputKey: string,\n): string {\n return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;\n}\n\n/** Check whether an output key belongs to a plugin (vs block-level output). */\nexport function isPluginOutputKey(key: string): boolean {\n return key.startsWith(PLUGIN_OUTPUT_PREFIX);\n}\n\n/** Get the prefix used for all outputs of a specific plugin instance. */\nexport function pluginOutputPrefix<F extends PluginFactoryLike>(handle: PluginHandle<F>): string {\n return pluginOutputKey(handle, \"\");\n}\n"],"mappings":";AAoFA,MAAM,uBAAuB;;AAG7B,SAAgB,gBACd,QACA,WACQ;AACR,QAAO,GAAG,uBAAuB,OAAO,GAAG;;;AAI7C,SAAgB,kBAAkB,KAAsB;AACtD,QAAO,IAAI,WAAW,qBAAqB;;;AAI7C,SAAgB,mBAAgD,QAAiC;AAC/F,QAAO,gBAAgB,QAAQ,GAAG"}
@@ -180,23 +180,22 @@ function buildPluginDataModel(state, configInitFn) {
180
180
  var PluginInstance = class PluginInstance {
181
181
  id;
182
182
  transferVersion;
183
- /** @internal Phantom for type inference of Data/Params/Outputs; never set at runtime. */
183
+ /** @internal Phantom for type inference; never set at runtime. */
184
184
  __instanceTypes;
185
- factory;
186
- config;
187
- constructor(id, factory, transferVersion, config) {
185
+ /** Bound closure that creates the PluginModel. Config is captured at factory.create() time. */
186
+ createPluginModel;
187
+ constructor(id, createPluginModel, transferVersion) {
188
188
  this.id = id;
189
- this.factory = factory;
189
+ this.createPluginModel = createPluginModel;
190
190
  this.transferVersion = transferVersion;
191
- this.config = config;
192
191
  }
193
- /** @internal */
192
+ /** @internal Accepts concrete Config — binds it into a closure, avoiding Config variance issues. */
194
193
  static [FROM_BUILDER](id, factory, transferVersion, config) {
195
- return new PluginInstance(id, factory, transferVersion, config);
194
+ return new PluginInstance(id, () => factory[CREATE_PLUGIN_MODEL](config), transferVersion);
196
195
  }
197
196
  /** @internal Create a PluginModel from this instance. Used by BlockModelV3.plugin(). */
198
197
  [CREATE_PLUGIN_MODEL]() {
199
- return this.factory[CREATE_PLUGIN_MODEL](this.config);
198
+ return this.createPluginModel();
200
199
  }
201
200
  };
202
201
  /**
@@ -235,14 +234,14 @@ var PluginModel = class PluginModel {
235
234
  static define(options) {
236
235
  if (options.data instanceof PluginDataModel) {
237
236
  const pdm = options.data;
238
- return PluginModelBuilder[FROM_BUILDER]({
237
+ return PluginModelInitialBuilder.create({
239
238
  name: options.name,
240
239
  dataFn: () => pdm.dataModel,
241
240
  getDefaultDataFn: (config) => pdm.getDefaultData(config),
242
241
  featureFlags: options.featureFlags
243
242
  });
244
243
  }
245
- return PluginModelBuilder[FROM_BUILDER]({
244
+ return PluginModelInitialBuilder.create({
246
245
  name: options.name,
247
246
  dataFn: options.data,
248
247
  featureFlags: options.featureFlags
@@ -408,6 +407,33 @@ var PluginModelBuilder = class PluginModelBuilder {
408
407
  });
409
408
  }
410
409
  };
410
+ /**
411
+ * Initial builder returned by PluginModel.define(). Extends PluginModelBuilder with .params().
412
+ * Once .params() or .output() is called, transitions to PluginModelBuilder (no second .params()).
413
+ */
414
+ var PluginModelInitialBuilder = class PluginModelInitialBuilder extends PluginModelBuilder {
415
+ /** @internal */
416
+ static create(options) {
417
+ return new PluginModelInitialBuilder(options);
418
+ }
419
+ /**
420
+ * Sets the Params type for this plugin — the shape of data derived from the block's
421
+ * render context and passed into plugin output functions via `ctx.params`.
422
+ * Must be called before .output(). Available only on the initial builder.
423
+ *
424
+ * @example
425
+ * .params<{ title: string }>()
426
+ * .output('displayText', (ctx) => ctx.params.title)
427
+ */
428
+ params() {
429
+ return PluginModelBuilder[FROM_BUILDER]({
430
+ name: this.name,
431
+ dataFn: this.dataFn,
432
+ getDefaultDataFn: this.getDefaultDataFn,
433
+ featureFlags: this.featureFlags
434
+ });
435
+ }
436
+ };
411
437
 
412
438
  //#endregion
413
439
  exports.CREATE_PLUGIN_MODEL = CREATE_PLUGIN_MODEL;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin_model.cjs","names":["DATA_MODEL_LEGACY_VERSION","DataModelBuilder"],"sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags, OutputWithStatus } from \"@milaboratories/pl-model-common\";\nimport {\n type DataModel,\n DataModelBuilder,\n type DataRecoverFn,\n type DataVersioned,\n type TransferTarget,\n} from \"./block_migrations\";\nimport { type PluginName, DATA_MODEL_LEGACY_VERSION } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Symbol for internal plugin model creation — not accessible to external consumers */\nexport const CREATE_PLUGIN_MODEL = Symbol(\"createPluginModel\");\n\n/** Sentinel for PluginInstance without transferAt — no transfer possible. */\nconst NO_TRANSFER_VERSION = \"\";\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Plugin data model with typed migration chain and config-aware initialization.\n *\n * @typeParam Data - Current (latest) plugin data type\n * @typeParam Versions - Map of version keys to their data types (accumulated by the chain)\n * @typeParam Config - Config type passed to init function (undefined if none)\n */\nexport class PluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown> = {},\n Config = undefined,\n> {\n readonly dataModel: DataModel<Data>;\n private readonly configInitFn: (config?: Config) => Data;\n\n /** @internal Phantom field to anchor the Versions type parameter. */\n declare readonly __versions?: Versions;\n\n private constructor(dataModel: DataModel<Data>, configInitFn: (config?: Config) => Data) {\n this.dataModel = dataModel;\n this.configInitFn = configInitFn;\n }\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>, Config>(\n dataModel: DataModel<Data>,\n configInitFn: (config?: Config) => Data,\n ): PluginDataModel<Data, Versions, Config> {\n return new PluginDataModel<Data, Versions, Config>(dataModel, configInitFn);\n }\n\n /** Create fresh data with optional config. */\n getDefaultData(config?: Config): DataVersioned<Data> {\n const data = this.configInitFn(config);\n return { version: this.dataModel.version, data };\n }\n}\n\n/** Internal state for plugin data model chain. */\ntype PluginChainState = {\n initialVersion: string;\n migrations: Array<{ toVersion: string; fn: (data: unknown) => unknown }>;\n recoverFn?: (version: string, data: unknown) => unknown;\n recoverAtIndex?: number;\n};\n\n/** Version → persisted data shape for each migration step (third generic of `PluginModel.define` when `data` is a `PluginDataModel`). */\nexport type PluginDataModelVersions<\n M extends PluginDataModel<PluginData, Record<string, unknown>, unknown>,\n> = M extends PluginDataModel<PluginData, infer Versions, unknown> ? Versions : never;\n\n/**\n * Builder for creating PluginDataModel with type-safe migrations.\n * Mirrors DataModelBuilder — same .from(), .migrate(), .recover(), .init() chain.\n *\n * @example\n * const pluginData = new PluginDataModelBuilder()\n * .from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n */\nexport class PluginDataModelBuilder {\n from<Data extends PluginData, const V extends string>(\n version: V,\n ): PluginDataModelInitialChain<Data, Record<V, Data>> {\n return PluginDataModelInitialChain[FROM_BUILDER]<Data, Record<V, Data>>({\n initialVersion: version,\n migrations: [],\n });\n }\n}\n\n/**\n * Chain returned by .migrate(). Supports .migrate(), .recover(), .init().\n * No .upgradeLegacy() — that is only available on the initial chain.\n */\nexport class PluginDataModelChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n protected constructor(protected readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelChain<Data, Versions> {\n return new PluginDataModelChain(state);\n }\n\n /**\n * Add a migration step transforming data from the current version to the next.\n */\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelChain<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelChain[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n * Can only be called once — the returned chain has no recover() method.\n */\n recover(fn: DataRecoverFn<Data>): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n recoverFn: fn as (version: string, data: unknown) => unknown,\n recoverAtIndex: this.state.migrations.length,\n });\n }\n\n /** Finalize the PluginDataModel. */\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Initial chain returned by new PluginDataModelBuilder().from().\n * Extends PluginDataModelChain with .upgradeLegacy() — available only before\n * any .migrate() calls, matching the block's DataModelInitialChain pattern.\n */\nexport class PluginDataModelInitialChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> extends PluginDataModelChain<Data, Versions> {\n /** @internal */\n static override [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelInitialChain<Data, Versions> {\n return new PluginDataModelInitialChain(state);\n }\n\n /**\n * Handle data from a previous plugin type occupying this slot.\n * Prepends a migration from DATA_MODEL_LEGACY_VERSION to the initial version.\n * When a plugin type changes, the old data arrives with DATA_MODEL_LEGACY_VERSION —\n * this function transforms it into the initial version, then the normal chain runs.\n *\n * Must be called right after .from() — not available after .migrate().\n * Mutually exclusive with recover().\n *\n * @param fn - Transform from old plugin's raw data to this plugin's initial data type\n */\n upgradeLegacy(fn: (data: unknown) => Data): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n migrations: [\n { toVersion: this.state.initialVersion, fn: fn as (data: unknown) => unknown },\n ...this.state.migrations,\n ],\n initialVersion: DATA_MODEL_LEGACY_VERSION,\n });\n }\n}\n\n/**\n * Chain after .recover() — supports .migrate(), .init(). No second recover().\n */\nexport class PluginDataModelWithRecover<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n private constructor(private readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelWithRecover<Data, Versions> {\n return new PluginDataModelWithRecover(state);\n }\n\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelWithRecover<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Builds a PluginDataModel by replaying the stored chain state through DataModelBuilder.\n * @internal\n */\nfunction buildPluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n Config,\n>(\n state: PluginChainState,\n configInitFn: (config?: Config) => Data,\n): PluginDataModel<Data, Versions, Config> {\n // Build inner DataModel by replaying migrations through DataModelBuilder chain.\n // Uses `any` internally — type safety is maintained by the public chain types.\n let chain: any = new DataModelBuilder().from(state.initialVersion);\n\n for (let i = 0; i < state.migrations.length; i++) {\n if (state.recoverFn !== undefined && state.recoverAtIndex === i) {\n chain = chain.recover(state.recoverFn);\n }\n chain = chain.migrate(state.migrations[i].toVersion, state.migrations[i].fn);\n }\n\n // If recover was placed at or after the last migration\n if (state.recoverFn !== undefined && state.recoverAtIndex === state.migrations.length) {\n chain = chain.recover(state.recoverFn);\n }\n\n const dataModel: DataModel<Data> = chain.init(() => configInitFn());\n\n return PluginDataModel[FROM_BUILDER]<Data, Versions, Config>(dataModel, configInitFn);\n}\n\n/**\n * A named plugin instance created by `factory.create({ pluginId, ... })`.\n * Passed to both `.transfer()` (on migration chain) and `.plugin()` (on BlockModelV3).\n * Implements TransferTarget so the migration chain can accept it.\n *\n * @typeParam Id - Plugin instance ID literal type\n * @typeParam Data - Plugin data type\n * @typeParam Params - Plugin params type\n * @typeParam Outputs - Plugin outputs type\n * @typeParam TransferData - Type of data entering the plugin via transfer (never if no transfer)\n */\nexport class PluginInstance<\n Id extends string = string,\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n TransferData = never,\n> implements TransferTarget<Id, TransferData> {\n readonly id: Id;\n readonly transferVersion: string;\n /** @internal Phantom for type inference of Data/Params/Outputs; never set at runtime. */\n readonly __instanceTypes?: { data: Data; params: Params; outputs: Outputs };\n private readonly factory: PluginModelFactory<Data, Params, Outputs, any, any>;\n private readonly config: any;\n\n private constructor(\n id: Id,\n factory: PluginModelFactory<Data, Params, Outputs, any, any>,\n transferVersion: string,\n config?: any,\n ) {\n this.id = id;\n this.factory = factory;\n this.transferVersion = transferVersion;\n this.config = config;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Id extends string,\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n TransferData,\n >(\n id: Id,\n factory: PluginModelFactory<Data, Params, Outputs, any, any>,\n transferVersion: string,\n config?: any,\n ): PluginInstance<Id, Data, Params, Outputs, TransferData> {\n return new PluginInstance(id, factory, transferVersion, config);\n }\n\n /** @internal Create a PluginModel from this instance. Used by BlockModelV3.plugin(). */\n [CREATE_PLUGIN_MODEL](): PluginModel<Data, Params, Outputs> {\n return this.factory[CREATE_PLUGIN_MODEL](this.config);\n }\n}\n\n/**\n * Configured plugin instance returned by PluginModelFactory[CREATE_PLUGIN_MODEL]().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n /** Per-output flags (e.g. withStatus) */\n readonly outputFlags: Record<string, { withStatus: boolean }>;\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n /** Create fresh default data. Config (if any) is captured at creation time. */\n readonly getDefaultData: () => DataVersioned<Data>;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.outputFlags = options.outputFlags;\n this.featureFlags = options.featureFlags;\n this.getDefaultData = options.getDefaultData;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n }): PluginModel<Data, Params, Outputs> {\n return new PluginModel<Data, Params, Outputs>(options);\n }\n\n /**\n * Creates a new PluginModelBuilder with a PluginDataModel (supports transfer / config).\n *\n * @example\n * const pluginData = new PluginDataModelBuilder().from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: pluginData,\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Versions extends Record<string, unknown> = {},\n Config extends PluginConfig = undefined,\n >(options: {\n name: PluginName;\n data: PluginDataModel<Data, Versions, Config>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, {}, Config, Versions>;\n /**\n * Creates a new PluginModelBuilder with a data model factory function (backward compatible).\n *\n * @example\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Config extends PluginConfig = undefined,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, {}, Config, {}>;\n static define(options: {\n name: PluginName;\n data: PluginDataModel<any, any, any> | ((config?: any) => DataModel<any>);\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder {\n if (options.data instanceof PluginDataModel) {\n const pdm = options.data;\n return PluginModelBuilder[FROM_BUILDER]({\n name: options.name,\n dataFn: () => pdm.dataModel,\n getDefaultDataFn: (config: any) => pdm.getDefaultData(config),\n featureFlags: options.featureFlags,\n });\n }\n return PluginModelBuilder[FROM_BUILDER]({\n name: options.name,\n dataFn: options.data,\n featureFlags: options.featureFlags,\n });\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n> extends PluginFactoryLike<Data, Params, Outputs> {\n /** Create a named plugin instance, optionally with transfer at a specific version. */\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<Id, Data, Params, Outputs, Versions[V]>;\n\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n config: Config;\n versions: Versions;\n };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n> implements PluginFactory<Data, Params, Outputs, Config, Versions> {\n private readonly name: PluginName;\n private readonly dataFn: (config?: Config) => DataModel<Data>;\n private readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly outputFlags: Record<string, { withStatus: boolean }>;\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs = options.outputs;\n this.outputFlags = options.outputFlags;\n this.featureFlags = options.featureFlags;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n Versions extends Record<string, unknown>,\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelFactory<Data, Params, Outputs, Config, Versions> {\n return new PluginModelFactory(options);\n }\n\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<Id, Data, Params, Outputs, Versions[V]> {\n const transferVersion = options.transferAt ?? NO_TRANSFER_VERSION;\n return PluginInstance[FROM_BUILDER]<Id, Data, Params, Outputs, Versions[V]>(\n options.pluginId as Id,\n this as any,\n transferVersion,\n options.config,\n );\n }\n\n /** @internal Create a PluginModel from config. Config is captured in getDefaultData closure. */\n [CREATE_PLUGIN_MODEL](config?: Config): PluginModel<Data, Params, Outputs> {\n const dataModel = this.dataFn(config);\n const getDefaultDataFn = this.getDefaultDataFn;\n return PluginModel[FROM_BUILDER]<Data, Params, Outputs>({\n name: this.name,\n dataModel,\n outputs: this.outputs,\n outputFlags: this.outputFlags,\n featureFlags: this.featureFlags,\n getDefaultData: getDefaultDataFn\n ? () => getDefaultDataFn(config)\n : () => dataModel.getDefaultData(),\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n * @typeParam Versions - Version map from PluginDataModel (empty for function-based data)\n *\n * @example\n * const dataTable = PluginModel.define({\n * name: 'dataTable' as PluginName,\n * data: pluginDataModel,\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n> {\n private readonly name: PluginName;\n private readonly dataFn: (config?: Config) => DataModel<Data>;\n private readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly outputFlags: Record<string, { withStatus: boolean }>;\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n outputFlags?: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs =\n options.outputs ??\n ({} as {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n });\n this.outputFlags = options.outputFlags ?? {};\n this.featureFlags = options.featureFlags;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n Versions extends Record<string, unknown> = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n outputFlags?: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, Outputs, Config, Versions> {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('isReady', (ctx) => ctx.params.columns !== undefined)\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,\n ): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config, Versions> {\n return new PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config, Versions>({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: T })]: (\n ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,\n ) => (Outputs & { [P in Key]: T })[K];\n },\n outputFlags: { ...this.outputFlags, [key]: { withStatus: false } },\n });\n }\n\n /**\n * Adds an output wrapped with status information to the plugin.\n *\n * The UI receives the full {@link OutputWithStatus} object instead of an unwrapped value,\n * allowing it to distinguish between pending, success, and error states.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new status-wrapped output added\n *\n * @example\n * .outputWithStatus('table', (ctx) => {\n * const pCols = ctx.params.pFrame?.getPColumns();\n * if (pCols === undefined) return undefined;\n * return createPlDataTableV2(ctx, pCols, ctx.data.tableState);\n * })\n */\n outputWithStatus<const Key extends string, T>(\n key: Key,\n fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,\n ): PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n Config,\n Versions\n > {\n return new PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n Config,\n Versions\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: OutputWithStatus<T> })]: (\n ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,\n ) => (Outputs & { [P in Key]: OutputWithStatus<T> })[K];\n },\n outputFlags: { ...this.outputFlags, [key]: { withStatus: true } },\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a PluginFactory.\n *\n * @returns Plugin factory that creates named plugin instances via .create()\n *\n * @example\n * const myPlugin = PluginModel.define({ ... })\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Create a named instance:\n * const table = myPlugin.create({ pluginId: 'mainTable', config: { ... } });\n */\n build(): PluginFactory<Data, Params, Outputs, Config, Versions> {\n return PluginModelFactory[FROM_BUILDER]<Data, Params, Outputs, Config, Versions>({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n outputs: this.outputs,\n outputFlags: this.outputFlags,\n featureFlags: this.featureFlags,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin_model.cjs","names":["DATA_MODEL_LEGACY_VERSION","DataModelBuilder"],"sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags, OutputWithStatus } from \"@milaboratories/pl-model-common\";\nimport type { ResolveModelServices, ResolveUiServices } from \"./services/service_resolve\";\nimport {\n type DataModel,\n DataModelBuilder,\n type DataRecoverFn,\n type DataVersioned,\n type TransferTarget,\n} from \"./block_migrations\";\nimport { type PluginName, DATA_MODEL_LEGACY_VERSION } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Output function signature for plugin render context. */\ntype PluginOutputFn<\n Data extends PluginData,\n Params extends PluginParams,\n ModelServices,\n UiServices,\n T,\n> = (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n) => T;\n\n/** Mapped output functions for a plugin's outputs. */\ntype PluginOutputFns<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n ModelServices,\n UiServices,\n> = {\n [K in keyof Outputs]: PluginOutputFn<Data, Params, ModelServices, UiServices, Outputs[K]>;\n};\n\n/** Symbol for internal plugin model creation — not accessible to external consumers */\nexport const CREATE_PLUGIN_MODEL = Symbol(\"createPluginModel\");\n\n/** Sentinel for PluginInstance without transferAt — no transfer possible. */\nconst NO_TRANSFER_VERSION = \"\";\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Plugin data model with typed migration chain and config-aware initialization.\n *\n * @typeParam Data - Current (latest) plugin data type\n * @typeParam Versions - Map of version keys to their data types (accumulated by the chain)\n * @typeParam Config - Config type passed to init function (undefined if none)\n */\nexport class PluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown> = {},\n Config = undefined,\n> {\n readonly dataModel: DataModel<Data>;\n private readonly configInitFn: (config?: Config) => Data;\n\n /** @internal Phantom field to anchor the Versions type parameter. */\n declare readonly __versions?: Versions;\n\n private constructor(dataModel: DataModel<Data>, configInitFn: (config?: Config) => Data) {\n this.dataModel = dataModel;\n this.configInitFn = configInitFn;\n }\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>, Config>(\n dataModel: DataModel<Data>,\n configInitFn: (config?: Config) => Data,\n ): PluginDataModel<Data, Versions, Config> {\n return new PluginDataModel<Data, Versions, Config>(dataModel, configInitFn);\n }\n\n /** Create fresh data with optional config. */\n getDefaultData(config?: Config): DataVersioned<Data> {\n const data = this.configInitFn(config);\n return { version: this.dataModel.version, data };\n }\n}\n\n/** Internal state for plugin data model chain. */\ntype PluginChainState = {\n initialVersion: string;\n migrations: Array<{ toVersion: string; fn: (data: unknown) => unknown }>;\n recoverFn?: (version: string, data: unknown) => unknown;\n recoverAtIndex?: number;\n};\n\n/** Version → persisted data shape for each migration step (third generic of `PluginModel.define` when `data` is a `PluginDataModel`). */\nexport type PluginDataModelVersions<\n M extends PluginDataModel<PluginData, Record<string, unknown>, unknown>,\n> = M extends PluginDataModel<PluginData, infer Versions, unknown> ? Versions : never;\n\n/**\n * Builder for creating PluginDataModel with type-safe migrations.\n * Mirrors DataModelBuilder — same .from(), .migrate(), .recover(), .init() chain.\n *\n * @example\n * const pluginData = new PluginDataModelBuilder()\n * .from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n */\nexport class PluginDataModelBuilder {\n from<Data extends PluginData, const V extends string>(\n version: V,\n ): PluginDataModelInitialChain<Data, Record<V, Data>> {\n return PluginDataModelInitialChain[FROM_BUILDER]<Data, Record<V, Data>>({\n initialVersion: version,\n migrations: [],\n });\n }\n}\n\n/**\n * Chain returned by .migrate(). Supports .migrate(), .recover(), .init().\n * No .upgradeLegacy() — that is only available on the initial chain.\n */\nexport class PluginDataModelChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n protected constructor(protected readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelChain<Data, Versions> {\n return new PluginDataModelChain(state);\n }\n\n /**\n * Add a migration step transforming data from the current version to the next.\n */\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelChain<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelChain[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n * Can only be called once — the returned chain has no recover() method.\n */\n recover(fn: DataRecoverFn<Data>): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n recoverFn: fn as (version: string, data: unknown) => unknown,\n recoverAtIndex: this.state.migrations.length,\n });\n }\n\n /** Finalize the PluginDataModel. */\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Initial chain returned by new PluginDataModelBuilder().from().\n * Extends PluginDataModelChain with .upgradeLegacy() — available only before\n * any .migrate() calls, matching the block's DataModelInitialChain pattern.\n */\nexport class PluginDataModelInitialChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> extends PluginDataModelChain<Data, Versions> {\n /** @internal */\n static override [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelInitialChain<Data, Versions> {\n return new PluginDataModelInitialChain(state);\n }\n\n /**\n * Handle data from a previous plugin type occupying this slot.\n * Prepends a migration from DATA_MODEL_LEGACY_VERSION to the initial version.\n * When a plugin type changes, the old data arrives with DATA_MODEL_LEGACY_VERSION —\n * this function transforms it into the initial version, then the normal chain runs.\n *\n * Must be called right after .from() — not available after .migrate().\n * Mutually exclusive with recover().\n *\n * @param fn - Transform from old plugin's raw data to this plugin's initial data type\n */\n upgradeLegacy(fn: (data: unknown) => Data): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n migrations: [\n { toVersion: this.state.initialVersion, fn: fn as (data: unknown) => unknown },\n ...this.state.migrations,\n ],\n initialVersion: DATA_MODEL_LEGACY_VERSION,\n });\n }\n}\n\n/**\n * Chain after .recover() — supports .migrate(), .init(). No second recover().\n */\nexport class PluginDataModelWithRecover<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n private constructor(private readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelWithRecover<Data, Versions> {\n return new PluginDataModelWithRecover(state);\n }\n\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelWithRecover<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Builds a PluginDataModel by replaying the stored chain state through DataModelBuilder.\n * @internal\n */\nfunction buildPluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n Config,\n>(\n state: PluginChainState,\n configInitFn: (config?: Config) => Data,\n): PluginDataModel<Data, Versions, Config> {\n // Build inner DataModel by replaying migrations through DataModelBuilder chain.\n // Uses `any` internally — type safety is maintained by the public chain types.\n let chain: any = new DataModelBuilder().from(state.initialVersion);\n\n for (let i = 0; i < state.migrations.length; i++) {\n if (state.recoverFn !== undefined && state.recoverAtIndex === i) {\n chain = chain.recover(state.recoverFn);\n }\n chain = chain.migrate(state.migrations[i].toVersion, state.migrations[i].fn);\n }\n\n // If recover was placed at or after the last migration\n if (state.recoverFn !== undefined && state.recoverAtIndex === state.migrations.length) {\n chain = chain.recover(state.recoverFn);\n }\n\n const dataModel: DataModel<Data> = chain.init(() => configInitFn());\n\n return PluginDataModel[FROM_BUILDER]<Data, Versions, Config>(dataModel, configInitFn);\n}\n\n/**\n * A named plugin instance created by `factory.create({ pluginId, ... })`.\n * Passed to both `.transfer()` (on migration chain) and `.plugin()` (on BlockModelV3).\n * Implements TransferTarget so the migration chain can accept it.\n *\n * @typeParam Id - Plugin instance ID literal type\n * @typeParam Data - Plugin data type\n * @typeParam Params - Plugin params type\n * @typeParam Outputs - Plugin outputs type\n * @typeParam TransferData - Type of data entering the plugin via transfer (never if no transfer)\n */\nexport class PluginInstance<\n Id extends string = string,\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n TransferData = never,\n ModelServices = unknown,\n UiServices = unknown,\n> implements TransferTarget<Id, TransferData> {\n readonly id: Id;\n readonly transferVersion: string;\n /** @internal Phantom for type inference; never set at runtime. */\n readonly __instanceTypes?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n };\n /** Bound closure that creates the PluginModel. Config is captured at factory.create() time. */\n private readonly createPluginModel: () => PluginModel<\n Data,\n Params,\n Outputs,\n ModelServices,\n UiServices\n >;\n\n private constructor(\n id: Id,\n createPluginModel: () => PluginModel<Data, Params, Outputs, ModelServices, UiServices>,\n transferVersion: string,\n ) {\n this.id = id;\n this.createPluginModel = createPluginModel;\n this.transferVersion = transferVersion;\n }\n\n /** @internal Accepts concrete Config — binds it into a closure, avoiding Config variance issues. */\n static [FROM_BUILDER]<\n Id extends string,\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n TransferData,\n Config extends PluginConfig = PluginConfig,\n ModelServices = unknown,\n UiServices = unknown,\n >(\n id: Id,\n factory: PluginModelFactory<\n Data,\n Params,\n Outputs,\n Config,\n Record<string, unknown>,\n ModelServices,\n UiServices\n >,\n transferVersion: string,\n config?: Config,\n ): PluginInstance<Id, Data, Params, Outputs, TransferData, ModelServices, UiServices> {\n return new PluginInstance(id, () => factory[CREATE_PLUGIN_MODEL](config), transferVersion);\n }\n\n /** @internal Create a PluginModel from this instance. Used by BlockModelV3.plugin(). */\n [CREATE_PLUGIN_MODEL](): PluginModel<Data, Params, Outputs, ModelServices, UiServices> {\n return this.createPluginModel();\n }\n}\n\n/**\n * Configured plugin instance returned by PluginModelFactory[CREATE_PLUGIN_MODEL]().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n ModelServices = {},\n UiServices = {},\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n /** Per-output flags (e.g. withStatus) */\n readonly outputFlags: Record<string, { withStatus: boolean }>;\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n /** Create fresh default data. Config (if any) is captured at creation time. */\n readonly getDefaultData: () => DataVersioned<Data>;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.outputFlags = options.outputFlags;\n this.featureFlags = options.featureFlags;\n this.getDefaultData = options.getDefaultData;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n }): PluginModel<Data, Params, Outputs, ModelServices, UiServices> {\n return new PluginModel<Data, Params, Outputs, ModelServices, UiServices>(options);\n }\n\n /**\n * Creates a new PluginModelBuilder with a PluginDataModel (supports transfer / config).\n *\n * @example\n * const pluginData = new PluginDataModelBuilder().from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: pluginData,\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Versions extends Record<string, unknown> = {},\n Config extends PluginConfig = undefined,\n Flags extends BlockCodeKnownFeatureFlags = {},\n >(options: {\n name: PluginName;\n data: PluginDataModel<Data, Versions, Config>;\n featureFlags?: Flags;\n }): PluginModelInitialBuilder<\n Data,\n Params,\n Config,\n Versions,\n ResolveModelServices<Flags>,\n ResolveUiServices<Flags>\n >;\n /**\n * Creates a new PluginModelBuilder with a data model factory function (backward compatible).\n *\n * @example\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Config extends PluginConfig = undefined,\n Flags extends BlockCodeKnownFeatureFlags = {},\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: Flags;\n }): PluginModelInitialBuilder<\n Data,\n Params,\n Config,\n {},\n ResolveModelServices<Flags>,\n ResolveUiServices<Flags>\n >;\n static define(options: {\n name: PluginName;\n data: PluginDataModel<any, any, any> | ((config?: any) => DataModel<any>);\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelInitialBuilder {\n if (options.data instanceof PluginDataModel) {\n const pdm = options.data;\n return PluginModelInitialBuilder.create({\n name: options.name,\n dataFn: () => pdm.dataModel,\n getDefaultDataFn: (config: any) => pdm.getDefaultData(config),\n featureFlags: options.featureFlags,\n });\n }\n return PluginModelInitialBuilder.create({\n name: options.name,\n dataFn: options.data,\n featureFlags: options.featureFlags,\n });\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> extends PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices> {\n /** Create a named plugin instance, optionally with transfer at a specific version. */\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<Id, Data, Params, Outputs, Versions[V], ModelServices, UiServices>;\n\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n config: Config;\n versions: Versions;\n };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> implements PluginFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n private readonly name: PluginName;\n private readonly dataFn: (config?: Config) => DataModel<Data>;\n private readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n private readonly outputFlags: Record<string, { withStatus: boolean }>;\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs = options.outputs;\n this.outputFlags = options.outputFlags;\n this.featureFlags = options.featureFlags;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n Versions extends Record<string, unknown>,\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n return new PluginModelFactory(options);\n }\n\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<Id, Data, Params, Outputs, Versions[V], ModelServices, UiServices> {\n const transferVersion = options.transferAt ?? NO_TRANSFER_VERSION;\n return PluginInstance[FROM_BUILDER]<\n Id,\n Data,\n Params,\n Outputs,\n Versions[V],\n Config,\n ModelServices,\n UiServices\n >(options.pluginId as Id, this, transferVersion, options.config);\n }\n\n /** @internal Create a PluginModel from config. Config is captured in getDefaultData closure. */\n [CREATE_PLUGIN_MODEL](\n config?: Config,\n ): PluginModel<Data, Params, Outputs, ModelServices, UiServices> {\n const dataModel = this.dataFn(config);\n const getDefaultDataFn = this.getDefaultDataFn;\n return PluginModel[FROM_BUILDER]<Data, Params, Outputs, ModelServices, UiServices>({\n name: this.name,\n dataModel,\n outputs: this.outputs,\n outputFlags: this.outputFlags,\n featureFlags: this.featureFlags,\n getDefaultData: getDefaultDataFn\n ? () => getDefaultDataFn(config)\n : () => dataModel.getDefaultData(),\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n * @typeParam Versions - Version map from PluginDataModel (empty for function-based data)\n *\n * @example\n * const dataTable = PluginModel.define({\n * name: 'dataTable' as PluginName,\n * data: pluginDataModel,\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> {\n protected readonly name: PluginName;\n protected readonly dataFn: (config?: Config) => DataModel<Data>;\n protected readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n private readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n private readonly outputFlags: Record<string, { withStatus: boolean }>;\n protected readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n protected constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags?: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs =\n options.outputs ?? ({} as PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>);\n this.outputFlags = options.outputFlags ?? {};\n this.featureFlags = options.featureFlags;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags?: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('isReady', (ctx) => ctx.params.columns !== undefined)\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => T,\n ): PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: T },\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: T },\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: T })]: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => (Outputs & { [P in Key]: T })[K];\n },\n outputFlags: { ...this.outputFlags, [key]: { withStatus: false } },\n });\n }\n\n /**\n * Adds an output wrapped with status information to the plugin.\n *\n * The UI receives the full {@link OutputWithStatus} object instead of an unwrapped value,\n * allowing it to distinguish between pending, success, and error states.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new status-wrapped output added\n *\n * @example\n * .outputWithStatus('table', (ctx) => {\n * const pCols = ctx.params.pFrame?.getPColumns();\n * if (pCols === undefined) return undefined;\n * return createPlDataTableV2(ctx, pCols, ctx.data.tableState);\n * })\n */\n outputWithStatus<const Key extends string, T>(\n key: Key,\n fn: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => T,\n ): PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: OutputWithStatus<T> })]: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => (Outputs & { [P in Key]: OutputWithStatus<T> })[K];\n },\n outputFlags: { ...this.outputFlags, [key]: { withStatus: true } },\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a PluginFactory.\n *\n * @returns Plugin factory that creates named plugin instances via .create()\n *\n * @example\n * const myPlugin = PluginModel.define({ ... })\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Create a named instance:\n * const table = myPlugin.create({ pluginId: 'mainTable', config: { ... } });\n */\n build(): PluginFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n return PluginModelFactory[FROM_BUILDER]<\n Data,\n Params,\n Outputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n outputs: this.outputs,\n outputFlags: this.outputFlags,\n featureFlags: this.featureFlags,\n });\n }\n}\n\n/**\n * Initial builder returned by PluginModel.define(). Extends PluginModelBuilder with .params().\n * Once .params() or .output() is called, transitions to PluginModelBuilder (no second .params()).\n */\nclass PluginModelInitialBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> extends PluginModelBuilder<Data, Params, {}, Config, Versions, ModelServices, UiServices> {\n /** @internal */\n static create<\n Data extends PluginData,\n Config extends PluginConfig,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelInitialBuilder<Data, undefined, Config, Versions, ModelServices, UiServices> {\n return new PluginModelInitialBuilder(options);\n }\n\n /**\n * Sets the Params type for this plugin — the shape of data derived from the block's\n * render context and passed into plugin output functions via `ctx.params`.\n * Must be called before .output(). Available only on the initial builder.\n *\n * @example\n * .params<{ title: string }>()\n * .output('displayText', (ctx) => ctx.params.title)\n */\n params<P extends PluginParams>(): PluginModelBuilder<\n Data,\n P,\n {},\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return PluginModelBuilder[FROM_BUILDER]<\n Data,\n P,\n {},\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n });\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { PluginFactoryLike } from "./plugin_handle.js";
2
2
  import { DataModel, DataRecoverFn, DataVersioned, TransferTarget } from "./block_migrations.js";
3
3
  import { PluginName } from "./block_storage.js";
4
+ import { ResolveModelServices, ResolveUiServices } from "./services/service_resolve.js";
4
5
  import { PluginRenderCtx } from "./render/api.js";
5
6
  import "./render/index.js";
6
7
  import { BlockCodeKnownFeatureFlags, OutputWithStatus } from "@milaboratories/pl-model-common";
@@ -8,6 +9,10 @@ import { BlockCodeKnownFeatureFlags, OutputWithStatus } from "@milaboratories/pl
8
9
  //#region src/plugin_model.d.ts
9
10
  /** Symbol for internal builder creation method */
10
11
  declare const FROM_BUILDER: unique symbol;
12
+ /** Output function signature for plugin render context. */
13
+ type PluginOutputFn<Data extends PluginData, Params extends PluginParams, ModelServices, UiServices, T> = (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>>) => T;
14
+ /** Mapped output functions for a plugin's outputs. */
15
+ type PluginOutputFns<Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, ModelServices, UiServices> = { [K in keyof Outputs]: PluginOutputFn<Data, Params, ModelServices, UiServices, Outputs[K]> };
11
16
  /** Symbol for internal plugin model creation — not accessible to external consumers */
12
17
  declare const CREATE_PLUGIN_MODEL: unique symbol;
13
18
  type PluginData = Record<string, unknown>;
@@ -124,34 +129,36 @@ declare class PluginDataModelWithRecover<Data extends PluginData, Versions exten
124
129
  * @typeParam Outputs - Plugin outputs type
125
130
  * @typeParam TransferData - Type of data entering the plugin via transfer (never if no transfer)
126
131
  */
127
- declare class PluginInstance<Id extends string = string, Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, TransferData = never> implements TransferTarget<Id, TransferData> {
132
+ declare class PluginInstance<Id extends string = string, Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, TransferData = never, ModelServices = unknown, UiServices = unknown> implements TransferTarget<Id, TransferData> {
128
133
  readonly id: Id;
129
134
  readonly transferVersion: string;
130
- /** @internal Phantom for type inference of Data/Params/Outputs; never set at runtime. */
135
+ /** @internal Phantom for type inference; never set at runtime. */
131
136
  readonly __instanceTypes?: {
132
137
  data: Data;
133
138
  params: Params;
134
139
  outputs: Outputs;
140
+ modelServices: ModelServices;
141
+ uiServices: UiServices;
135
142
  };
136
- private readonly factory;
137
- private readonly config;
143
+ /** Bound closure that creates the PluginModel. Config is captured at factory.create() time. */
144
+ private readonly createPluginModel;
138
145
  private constructor();
139
- /** @internal */
140
- static [FROM_BUILDER]<Id extends string, Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, TransferData>(id: Id, factory: PluginModelFactory<Data, Params, Outputs, any, any>, transferVersion: string, config?: any): PluginInstance<Id, Data, Params, Outputs, TransferData>;
146
+ /** @internal Accepts concrete Config — binds it into a closure, avoiding Config variance issues. */
147
+ static [FROM_BUILDER]<Id extends string, Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, TransferData, Config extends PluginConfig = PluginConfig, ModelServices = unknown, UiServices = unknown>(id: Id, factory: PluginModelFactory<Data, Params, Outputs, Config, Record<string, unknown>, ModelServices, UiServices>, transferVersion: string, config?: Config): PluginInstance<Id, Data, Params, Outputs, TransferData, ModelServices, UiServices>;
141
148
  /** @internal Create a PluginModel from this instance. Used by BlockModelV3.plugin(). */
142
- [CREATE_PLUGIN_MODEL](): PluginModel<Data, Params, Outputs>;
149
+ [CREATE_PLUGIN_MODEL](): PluginModel<Data, Params, Outputs, ModelServices, UiServices>;
143
150
  }
144
151
  /**
145
152
  * Configured plugin instance returned by PluginModelFactory[CREATE_PLUGIN_MODEL]().
146
153
  * Contains the plugin's name, data model, and output definitions.
147
154
  */
148
- declare class PluginModel<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs> {
155
+ declare class PluginModel<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, ModelServices = {}, UiServices = {}> {
149
156
  /** Globally unique plugin name */
150
157
  readonly name: PluginName;
151
158
  /** Data model instance for this plugin */
152
159
  readonly dataModel: DataModel<Data>;
153
160
  /** Output definitions - functions that compute outputs from plugin context */
154
- readonly outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K] };
161
+ readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;
155
162
  /** Per-output flags (e.g. withStatus) */
156
163
  readonly outputFlags: Record<string, {
157
164
  withStatus: boolean;
@@ -166,16 +173,16 @@ declare class PluginModel<Data extends PluginData = PluginData, Params extends P
166
173
  * Uses Symbol key to prevent external access.
167
174
  * @internal
168
175
  */
169
- static [FROM_BUILDER]<Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs>(options: {
176
+ static [FROM_BUILDER]<Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, ModelServices = {}, UiServices = {}>(options: {
170
177
  name: PluginName;
171
178
  dataModel: DataModel<Data>;
172
- outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K] };
179
+ outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;
173
180
  outputFlags: Record<string, {
174
181
  withStatus: boolean;
175
182
  }>;
176
183
  featureFlags?: BlockCodeKnownFeatureFlags;
177
184
  getDefaultData: () => DataVersioned<Data>;
178
- }): PluginModel<Data, Params, Outputs>;
185
+ }): PluginModel<Data, Params, Outputs, ModelServices, UiServices>;
179
186
  /**
180
187
  * Creates a new PluginModelBuilder with a PluginDataModel (supports transfer / config).
181
188
  *
@@ -192,11 +199,11 @@ declare class PluginModel<Data extends PluginData = PluginData, Params extends P
192
199
  * data: pluginData,
193
200
  * }).build();
194
201
  */
195
- static define<Data extends PluginData, Params extends PluginParams = undefined, Versions extends Record<string, unknown> = {}, Config extends PluginConfig = undefined>(options: {
202
+ static define<Data extends PluginData, Params extends PluginParams = undefined, Versions extends Record<string, unknown> = {}, Config extends PluginConfig = undefined, Flags extends BlockCodeKnownFeatureFlags = {}>(options: {
196
203
  name: PluginName;
197
204
  data: PluginDataModel<Data, Versions, Config>;
198
- featureFlags?: BlockCodeKnownFeatureFlags;
199
- }): PluginModelBuilder<Data, Params, {}, Config, Versions>;
205
+ featureFlags?: Flags;
206
+ }): PluginModelInitialBuilder<Data, Params, Config, Versions, ResolveModelServices<Flags>, ResolveUiServices<Flags>>;
200
207
  /**
201
208
  * Creates a new PluginModelBuilder with a data model factory function (backward compatible).
202
209
  *
@@ -206,20 +213,20 @@ declare class PluginModel<Data extends PluginData = PluginData, Params extends P
206
213
  * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),
207
214
  * }).build();
208
215
  */
209
- static define<Data extends PluginData, Params extends PluginParams = undefined, Config extends PluginConfig = undefined>(options: {
216
+ static define<Data extends PluginData, Params extends PluginParams = undefined, Config extends PluginConfig = undefined, Flags extends BlockCodeKnownFeatureFlags = {}>(options: {
210
217
  name: PluginName;
211
218
  data: (config?: Config) => DataModel<Data>;
212
- featureFlags?: BlockCodeKnownFeatureFlags;
213
- }): PluginModelBuilder<Data, Params, {}, Config, {}>;
219
+ featureFlags?: Flags;
220
+ }): PluginModelInitialBuilder<Data, Params, Config, {}, ResolveModelServices<Flags>, ResolveUiServices<Flags>>;
214
221
  }
215
222
  /** Plugin factory returned by PluginModelBuilder.build(). */
216
- interface PluginFactory<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, Config extends PluginConfig = undefined, Versions extends Record<string, unknown> = {}> extends PluginFactoryLike<Data, Params, Outputs> {
223
+ interface PluginFactory<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, Config extends PluginConfig = undefined, Versions extends Record<string, unknown> = {}, ModelServices = {}, UiServices = {}> extends PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices> {
217
224
  /** Create a named plugin instance, optionally with transfer at a specific version. */
218
225
  create<const Id extends string, const V extends string & keyof Versions = never>(options: {
219
226
  pluginId: Id;
220
227
  transferAt?: V;
221
228
  config?: Config;
222
- }): PluginInstance<Id, Data, Params, Outputs, Versions[V]>;
229
+ }): PluginInstance<Id, Data, Params, Outputs, Versions[V], ModelServices, UiServices>;
223
230
  /**
224
231
  * @internal Phantom field for structural type extraction.
225
232
  * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.
@@ -228,36 +235,38 @@ interface PluginFactory<Data extends PluginData = PluginData, Params extends Plu
228
235
  data: Data;
229
236
  params: Params;
230
237
  outputs: Outputs;
238
+ modelServices: ModelServices;
239
+ uiServices: UiServices;
231
240
  config: Config;
232
241
  versions: Versions;
233
242
  };
234
243
  }
235
- declare class PluginModelFactory<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, Config extends PluginConfig = undefined, Versions extends Record<string, unknown> = {}> implements PluginFactory<Data, Params, Outputs, Config, Versions> {
244
+ declare class PluginModelFactory<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, Config extends PluginConfig = undefined, Versions extends Record<string, unknown> = {}, ModelServices = {}, UiServices = {}> implements PluginFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {
236
245
  private readonly name;
237
246
  private readonly dataFn;
238
247
  private readonly getDefaultDataFn?;
239
- readonly outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K] };
248
+ readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;
240
249
  private readonly outputFlags;
241
250
  private readonly featureFlags?;
242
251
  private constructor();
243
252
  /** @internal */
244
- static [FROM_BUILDER]<Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, Config extends PluginConfig, Versions extends Record<string, unknown>>(options: {
253
+ static [FROM_BUILDER]<Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, Config extends PluginConfig, Versions extends Record<string, unknown>, ModelServices = {}, UiServices = {}>(options: {
245
254
  name: PluginName;
246
255
  dataFn: (config?: Config) => DataModel<Data>;
247
256
  getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;
248
- outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K] };
257
+ outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;
249
258
  outputFlags: Record<string, {
250
259
  withStatus: boolean;
251
260
  }>;
252
261
  featureFlags?: BlockCodeKnownFeatureFlags;
253
- }): PluginModelFactory<Data, Params, Outputs, Config, Versions>;
262
+ }): PluginModelFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices>;
254
263
  create<const Id extends string, const V extends string & keyof Versions = never>(options: {
255
264
  pluginId: Id;
256
265
  transferAt?: V;
257
266
  config?: Config;
258
- }): PluginInstance<Id, Data, Params, Outputs, Versions[V]>;
267
+ }): PluginInstance<Id, Data, Params, Outputs, Versions[V], ModelServices, UiServices>;
259
268
  /** @internal Create a PluginModel from config. Config is captured in getDefaultData closure. */
260
- [CREATE_PLUGIN_MODEL](config?: Config): PluginModel<Data, Params, Outputs>;
269
+ [CREATE_PLUGIN_MODEL](config?: Config): PluginModel<Data, Params, Outputs, ModelServices, UiServices>;
261
270
  }
262
271
  /**
263
272
  * Builder for creating PluginType with type-safe output definitions.
@@ -278,25 +287,34 @@ declare class PluginModelFactory<Data extends PluginData = PluginData, Params ex
278
287
  * .output('model', (ctx) => createTableModel(ctx))
279
288
  * .build();
280
289
  */
281
- declare class PluginModelBuilder<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, Config extends PluginConfig = undefined, Versions extends Record<string, unknown> = {}> {
282
- private readonly name;
283
- private readonly dataFn;
284
- private readonly getDefaultDataFn?;
290
+ declare class PluginModelBuilder<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Outputs extends PluginOutputs = PluginOutputs, Config extends PluginConfig = undefined, Versions extends Record<string, unknown> = {}, ModelServices = {}, UiServices = {}> {
291
+ protected readonly name: PluginName;
292
+ protected readonly dataFn: (config?: Config) => DataModel<Data>;
293
+ protected readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;
285
294
  private readonly outputs;
286
295
  private readonly outputFlags;
287
- private readonly featureFlags?;
288
- private constructor();
296
+ protected readonly featureFlags?: BlockCodeKnownFeatureFlags;
297
+ protected constructor(options: {
298
+ name: PluginName;
299
+ dataFn: (config?: Config) => DataModel<Data>;
300
+ getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;
301
+ outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;
302
+ outputFlags?: Record<string, {
303
+ withStatus: boolean;
304
+ }>;
305
+ featureFlags?: BlockCodeKnownFeatureFlags;
306
+ });
289
307
  /** @internal */
290
- static [FROM_BUILDER]<Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, Config extends PluginConfig, Versions extends Record<string, unknown> = {}>(options: {
308
+ static [FROM_BUILDER]<Data extends PluginData, Params extends PluginParams, Outputs extends PluginOutputs, Config extends PluginConfig, Versions extends Record<string, unknown> = {}, ModelServices = {}, UiServices = {}>(options: {
291
309
  name: PluginName;
292
310
  dataFn: (config?: Config) => DataModel<Data>;
293
311
  getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;
294
- outputs?: { [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K] };
312
+ outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;
295
313
  outputFlags?: Record<string, {
296
314
  withStatus: boolean;
297
315
  }>;
298
316
  featureFlags?: BlockCodeKnownFeatureFlags;
299
- }): PluginModelBuilder<Data, Params, Outputs, Config, Versions>;
317
+ }): PluginModelBuilder<Data, Params, Outputs, Config, Versions, ModelServices, UiServices>;
300
318
  /**
301
319
  * Adds an output to the plugin.
302
320
  *
@@ -308,7 +326,7 @@ declare class PluginModelBuilder<Data extends PluginData = PluginData, Params ex
308
326
  * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))
309
327
  * .output('isReady', (ctx) => ctx.params.columns !== undefined)
310
328
  */
311
- output<const Key extends string, T>(key: Key, fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config, Versions>;
329
+ output<const Key extends string, T>(key: Key, fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>>) => T): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config, Versions, ModelServices, UiServices>;
312
330
  /**
313
331
  * Adds an output wrapped with status information to the plugin.
314
332
  *
@@ -326,7 +344,7 @@ declare class PluginModelBuilder<Data extends PluginData = PluginData, Params ex
326
344
  * return createPlDataTableV2(ctx, pCols, ctx.data.tableState);
327
345
  * })
328
346
  */
329
- outputWithStatus<const Key extends string, T>(key: Key, fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: OutputWithStatus<T> }, Config, Versions>;
347
+ outputWithStatus<const Key extends string, T>(key: Key, fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>>) => T): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: OutputWithStatus<T> }, Config, Versions, ModelServices, UiServices>;
330
348
  /**
331
349
  * Finalizes the plugin definition and returns a PluginFactory.
332
350
  *
@@ -340,7 +358,30 @@ declare class PluginModelBuilder<Data extends PluginData = PluginData, Params ex
340
358
  * // Create a named instance:
341
359
  * const table = myPlugin.create({ pluginId: 'mainTable', config: { ... } });
342
360
  */
343
- build(): PluginFactory<Data, Params, Outputs, Config, Versions>;
361
+ build(): PluginFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices>;
362
+ }
363
+ /**
364
+ * Initial builder returned by PluginModel.define(). Extends PluginModelBuilder with .params().
365
+ * Once .params() or .output() is called, transitions to PluginModelBuilder (no second .params()).
366
+ */
367
+ declare class PluginModelInitialBuilder<Data extends PluginData = PluginData, Params extends PluginParams = undefined, Config extends PluginConfig = undefined, Versions extends Record<string, unknown> = {}, ModelServices = {}, UiServices = {}> extends PluginModelBuilder<Data, Params, {}, Config, Versions, ModelServices, UiServices> {
368
+ /** @internal */
369
+ static create<Data extends PluginData, Config extends PluginConfig, Versions extends Record<string, unknown> = {}, ModelServices = {}, UiServices = {}>(options: {
370
+ name: PluginName;
371
+ dataFn: (config?: Config) => DataModel<Data>;
372
+ getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;
373
+ featureFlags?: BlockCodeKnownFeatureFlags;
374
+ }): PluginModelInitialBuilder<Data, undefined, Config, Versions, ModelServices, UiServices>;
375
+ /**
376
+ * Sets the Params type for this plugin — the shape of data derived from the block's
377
+ * render context and passed into plugin output functions via `ctx.params`.
378
+ * Must be called before .output(). Available only on the initial builder.
379
+ *
380
+ * @example
381
+ * .params<{ title: string }>()
382
+ * .output('displayText', (ctx) => ctx.params.title)
383
+ */
384
+ params<P extends PluginParams>(): PluginModelBuilder<Data, P, {}, Config, Versions, ModelServices, UiServices>;
344
385
  }
345
386
  //#endregion
346
387
  export { PluginConfig, PluginData, PluginDataModel, PluginDataModelBuilder, PluginDataModelVersions, PluginFactory, PluginInstance, PluginModel, PluginOutputs, PluginParams };
@@ -180,23 +180,22 @@ function buildPluginDataModel(state, configInitFn) {
180
180
  var PluginInstance = class PluginInstance {
181
181
  id;
182
182
  transferVersion;
183
- /** @internal Phantom for type inference of Data/Params/Outputs; never set at runtime. */
183
+ /** @internal Phantom for type inference; never set at runtime. */
184
184
  __instanceTypes;
185
- factory;
186
- config;
187
- constructor(id, factory, transferVersion, config) {
185
+ /** Bound closure that creates the PluginModel. Config is captured at factory.create() time. */
186
+ createPluginModel;
187
+ constructor(id, createPluginModel, transferVersion) {
188
188
  this.id = id;
189
- this.factory = factory;
189
+ this.createPluginModel = createPluginModel;
190
190
  this.transferVersion = transferVersion;
191
- this.config = config;
192
191
  }
193
- /** @internal */
192
+ /** @internal Accepts concrete Config — binds it into a closure, avoiding Config variance issues. */
194
193
  static [FROM_BUILDER](id, factory, transferVersion, config) {
195
- return new PluginInstance(id, factory, transferVersion, config);
194
+ return new PluginInstance(id, () => factory[CREATE_PLUGIN_MODEL](config), transferVersion);
196
195
  }
197
196
  /** @internal Create a PluginModel from this instance. Used by BlockModelV3.plugin(). */
198
197
  [CREATE_PLUGIN_MODEL]() {
199
- return this.factory[CREATE_PLUGIN_MODEL](this.config);
198
+ return this.createPluginModel();
200
199
  }
201
200
  };
202
201
  /**
@@ -235,14 +234,14 @@ var PluginModel = class PluginModel {
235
234
  static define(options) {
236
235
  if (options.data instanceof PluginDataModel) {
237
236
  const pdm = options.data;
238
- return PluginModelBuilder[FROM_BUILDER]({
237
+ return PluginModelInitialBuilder.create({
239
238
  name: options.name,
240
239
  dataFn: () => pdm.dataModel,
241
240
  getDefaultDataFn: (config) => pdm.getDefaultData(config),
242
241
  featureFlags: options.featureFlags
243
242
  });
244
243
  }
245
- return PluginModelBuilder[FROM_BUILDER]({
244
+ return PluginModelInitialBuilder.create({
246
245
  name: options.name,
247
246
  dataFn: options.data,
248
247
  featureFlags: options.featureFlags
@@ -408,6 +407,33 @@ var PluginModelBuilder = class PluginModelBuilder {
408
407
  });
409
408
  }
410
409
  };
410
+ /**
411
+ * Initial builder returned by PluginModel.define(). Extends PluginModelBuilder with .params().
412
+ * Once .params() or .output() is called, transitions to PluginModelBuilder (no second .params()).
413
+ */
414
+ var PluginModelInitialBuilder = class PluginModelInitialBuilder extends PluginModelBuilder {
415
+ /** @internal */
416
+ static create(options) {
417
+ return new PluginModelInitialBuilder(options);
418
+ }
419
+ /**
420
+ * Sets the Params type for this plugin — the shape of data derived from the block's
421
+ * render context and passed into plugin output functions via `ctx.params`.
422
+ * Must be called before .output(). Available only on the initial builder.
423
+ *
424
+ * @example
425
+ * .params<{ title: string }>()
426
+ * .output('displayText', (ctx) => ctx.params.title)
427
+ */
428
+ params() {
429
+ return PluginModelBuilder[FROM_BUILDER]({
430
+ name: this.name,
431
+ dataFn: this.dataFn,
432
+ getDefaultDataFn: this.getDefaultDataFn,
433
+ featureFlags: this.featureFlags
434
+ });
435
+ }
436
+ };
411
437
 
412
438
  //#endregion
413
439
  export { CREATE_PLUGIN_MODEL, PluginDataModel, PluginDataModelBuilder, PluginInstance, PluginModel };