@platforma-sdk/model 1.57.0 → 1.58.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 (94) hide show
  1. package/dist/block_model.cjs +17 -13
  2. package/dist/block_model.cjs.map +1 -1
  3. package/dist/block_model.d.ts +4 -4
  4. package/dist/block_model.d.ts.map +1 -1
  5. package/dist/block_model.js +17 -13
  6. package/dist/block_model.js.map +1 -1
  7. package/dist/block_model_legacy.cjs +1 -0
  8. package/dist/block_model_legacy.cjs.map +1 -1
  9. package/dist/block_model_legacy.d.ts.map +1 -1
  10. package/dist/block_model_legacy.js +1 -0
  11. package/dist/block_model_legacy.js.map +1 -1
  12. package/dist/block_storage.cjs +18 -14
  13. package/dist/block_storage.cjs.map +1 -1
  14. package/dist/block_storage.d.ts +14 -10
  15. package/dist/block_storage.d.ts.map +1 -1
  16. package/dist/block_storage.js +18 -14
  17. package/dist/block_storage.js.map +1 -1
  18. package/dist/block_storage_callbacks.cjs +3 -3
  19. package/dist/block_storage_callbacks.cjs.map +1 -1
  20. package/dist/block_storage_callbacks.d.ts +4 -3
  21. package/dist/block_storage_callbacks.d.ts.map +1 -1
  22. package/dist/block_storage_callbacks.js +3 -3
  23. package/dist/block_storage_callbacks.js.map +1 -1
  24. package/dist/components/PFrameForGraphs.cjs +0 -117
  25. package/dist/components/PFrameForGraphs.cjs.map +1 -1
  26. package/dist/components/PFrameForGraphs.d.ts +3 -5
  27. package/dist/components/PFrameForGraphs.d.ts.map +1 -1
  28. package/dist/components/PFrameForGraphs.js +2 -117
  29. package/dist/components/PFrameForGraphs.js.map +1 -1
  30. package/dist/components/PlDataTable/index.d.ts +1 -1
  31. package/dist/components/PlDataTable/index.d.ts.map +1 -1
  32. package/dist/components/PlDataTable/table.cjs +16 -1
  33. package/dist/components/PlDataTable/table.cjs.map +1 -1
  34. package/dist/components/PlDataTable/table.d.ts.map +1 -1
  35. package/dist/components/PlDataTable/table.js +16 -2
  36. package/dist/components/PlDataTable/table.js.map +1 -1
  37. package/dist/index.cjs +8 -2
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.ts +2 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +4 -2
  42. package/dist/index.js.map +1 -1
  43. package/dist/package.json.cjs +1 -1
  44. package/dist/package.json.js +1 -1
  45. package/dist/pframe_utils/axes.cjs +131 -0
  46. package/dist/pframe_utils/axes.cjs.map +1 -0
  47. package/dist/pframe_utils/axes.d.ts +15 -0
  48. package/dist/pframe_utils/axes.d.ts.map +1 -0
  49. package/dist/pframe_utils/axes.js +128 -0
  50. package/dist/pframe_utils/axes.js.map +1 -0
  51. package/dist/pframe_utils/columns.cjs +4 -7
  52. package/dist/pframe_utils/columns.cjs.map +1 -1
  53. package/dist/pframe_utils/columns.js +1 -4
  54. package/dist/pframe_utils/columns.js.map +1 -1
  55. package/dist/pframe_utils/index.cjs +0 -2
  56. package/dist/pframe_utils/index.cjs.map +1 -1
  57. package/dist/pframe_utils/index.js +0 -2
  58. package/dist/pframe_utils/index.js.map +1 -1
  59. package/dist/platforma.d.ts +12 -2
  60. package/dist/platforma.d.ts.map +1 -1
  61. package/dist/plugin_handle.cjs +29 -0
  62. package/dist/plugin_handle.cjs.map +1 -0
  63. package/dist/plugin_handle.d.ts +51 -0
  64. package/dist/plugin_handle.d.ts.map +1 -0
  65. package/dist/plugin_handle.js +25 -0
  66. package/dist/plugin_handle.js.map +1 -0
  67. package/dist/plugin_model.cjs +27 -27
  68. package/dist/plugin_model.cjs.map +1 -1
  69. package/dist/plugin_model.d.ts +41 -33
  70. package/dist/plugin_model.d.ts.map +1 -1
  71. package/dist/plugin_model.js +27 -27
  72. package/dist/plugin_model.js.map +1 -1
  73. package/dist/render/api.cjs +9 -5
  74. package/dist/render/api.cjs.map +1 -1
  75. package/dist/render/api.d.ts +11 -5
  76. package/dist/render/api.d.ts.map +1 -1
  77. package/dist/render/api.js +9 -5
  78. package/dist/render/api.js.map +1 -1
  79. package/package.json +5 -5
  80. package/src/block_model.ts +33 -19
  81. package/src/block_model_legacy.ts +1 -0
  82. package/src/block_storage.test.ts +3 -2
  83. package/src/block_storage.ts +30 -22
  84. package/src/block_storage_callbacks.ts +8 -7
  85. package/src/components/PFrameForGraphs.ts +4 -167
  86. package/src/components/PlDataTable/index.ts +6 -1
  87. package/src/components/PlDataTable/table.ts +3 -4
  88. package/src/index.ts +2 -1
  89. package/src/pframe_utils/axes.ts +175 -0
  90. package/src/pframe_utils/columns.ts +2 -2
  91. package/src/platforma.ts +17 -2
  92. package/src/plugin_handle.ts +85 -0
  93. package/src/plugin_model.ts +118 -56
  94. package/src/render/api.ts +21 -11
@@ -0,0 +1,85 @@
1
+ /**
2
+ * PluginHandle — Opaque branded handle and output key utilities for plugin instances.
3
+ *
4
+ * Extracted into its own module to break circular dependencies:
5
+ * both block_storage.ts and plugin_model.ts can import from here
6
+ * without depending on each other.
7
+ *
8
+ * @module plugin_handle
9
+ */
10
+
11
+ import type { Branded } from "@milaboratories/helpers";
12
+
13
+ /**
14
+ * Phantom-only base type for constraining PluginHandle's type parameter.
15
+ *
16
+ * PluginFactory has create() → PluginModel with function properties, making it invariant
17
+ * under strictFunctionTypes. PluginFactoryLike exposes only the covariant `__types` phantom,
18
+ * avoiding the contravariance chain. Handles only need `__types` for type extraction.
19
+ *
20
+ * PluginFactory extends PluginFactoryLike, so every concrete factory satisfies this constraint.
21
+ */
22
+ export interface PluginFactoryLike<
23
+ Data extends Record<string, unknown> = Record<string, unknown>,
24
+ Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,
25
+ Outputs extends Record<string, unknown> = Record<string, unknown>,
26
+ > {
27
+ readonly __types?: {
28
+ data: Data;
29
+ params: Params;
30
+ outputs: Outputs;
31
+ };
32
+ }
33
+
34
+ /** Extract the Data type from a PluginFactoryLike phantom. */
35
+ export type InferFactoryData<F extends PluginFactoryLike> = NonNullable<
36
+ F extends PluginFactoryLike<infer D, any, any> ? D : Record<string, unknown>
37
+ >;
38
+
39
+ /** Extract the Params type from a PluginFactoryLike phantom. */
40
+ export type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<
41
+ F extends PluginFactoryLike<any, infer P, any> ? P : undefined
42
+ >;
43
+
44
+ /** Extract the Outputs type from a PluginFactoryLike phantom. */
45
+ export type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<
46
+ F extends PluginFactoryLike<any, any, infer O> ? O : Record<string, unknown>
47
+ >;
48
+
49
+ /**
50
+ * Derive a typed PluginHandle from a PluginFactory type.
51
+ * Normalizes the brand to only data/params/outputs (strips config) so handles
52
+ * from InferPluginHandles match handles from InferPluginHandle.
53
+ */
54
+ export type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<
55
+ F extends PluginFactoryLike<infer Data, infer Params, infer Outputs>
56
+ ? PluginHandle<PluginFactoryLike<Data, Params, Outputs>>
57
+ : PluginHandle
58
+ >;
59
+
60
+ /**
61
+ * Opaque handle for a plugin instance. Runtime value is the plugin instance ID string.
62
+ * Branded with factory phantom `F` for type-safe data/outputs extraction.
63
+ * Constrained with PluginFactoryLike (not PluginFactory) to avoid variance issues.
64
+ */
65
+ export type PluginHandle<F extends PluginFactoryLike = PluginFactoryLike> = Branded<string, F>;
66
+
67
+ const PLUGIN_OUTPUT_PREFIX = "plugin-output#";
68
+
69
+ /** Construct the output key for a plugin output in the block outputs map. */
70
+ export function pluginOutputKey<F extends PluginFactoryLike>(
71
+ handle: PluginHandle<F>,
72
+ outputKey: string,
73
+ ): string {
74
+ return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;
75
+ }
76
+
77
+ /** Check whether an output key belongs to a plugin (vs block-level output). */
78
+ export function isPluginOutputKey(key: string): boolean {
79
+ return key.startsWith(PLUGIN_OUTPUT_PREFIX);
80
+ }
81
+
82
+ /** Get the prefix used for all outputs of a specific plugin instance. */
83
+ export function pluginOutputPrefix<F extends PluginFactoryLike>(handle: PluginHandle<F>): string {
84
+ return pluginOutputKey(handle, "");
85
+ }
@@ -7,37 +7,52 @@
7
7
  * @module plugin_model
8
8
  */
9
9
 
10
+ import type { BlockCodeKnownFeatureFlags } from "@milaboratories/pl-model-common";
10
11
  import type { DataModel } from "./block_migrations";
11
12
  import type { PluginName } from "./block_storage";
13
+ import type { PluginFactoryLike } from "./plugin_handle";
12
14
  import type { PluginRenderCtx } from "./render";
13
15
 
14
16
  /** Symbol for internal builder creation method */
15
17
  const FROM_BUILDER = Symbol("fromBuilder");
16
18
 
17
- // =============================================================================
18
- // Plugin Type
19
- // =============================================================================
19
+ export type PluginData = Record<string, unknown>;
20
+ export type PluginParams = undefined | Record<string, unknown>;
21
+ export type PluginOutputs = Record<string, unknown>;
22
+ export type PluginConfig = undefined | Record<string, unknown>;
20
23
 
21
24
  /**
22
25
  * Configured plugin instance returned by PluginModelFactory.create().
23
26
  * Contains the plugin's name, data model, and output definitions.
24
27
  */
25
- export class PluginModel<Data = unknown, Params = undefined, Outputs = {}> {
28
+ export class PluginModel<
29
+ Data extends PluginData = PluginData,
30
+ Params extends PluginParams = undefined,
31
+ Outputs extends PluginOutputs = PluginOutputs,
32
+ > {
26
33
  /** Globally unique plugin name */
27
34
  readonly name: PluginName;
28
35
  /** Data model instance for this plugin */
29
36
  readonly dataModel: DataModel<Data>;
30
37
  /** Output definitions - functions that compute outputs from plugin context */
31
- readonly outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
38
+ readonly outputs: {
39
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
40
+ };
41
+ /** Feature flags declared by this plugin */
42
+ readonly featureFlags?: BlockCodeKnownFeatureFlags;
32
43
 
33
- private constructor(input: {
44
+ private constructor(options: {
34
45
  name: PluginName;
35
46
  dataModel: DataModel<Data>;
36
- outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
47
+ outputs: {
48
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
49
+ };
50
+ featureFlags?: BlockCodeKnownFeatureFlags;
37
51
  }) {
38
- this.name = input.name;
39
- this.dataModel = input.dataModel;
40
- this.outputs = input.outputs;
52
+ this.name = options.name;
53
+ this.dataModel = options.dataModel;
54
+ this.outputs = options.outputs;
55
+ this.featureFlags = options.featureFlags;
41
56
  }
42
57
 
43
58
  /**
@@ -45,12 +60,19 @@ export class PluginModel<Data = unknown, Params = undefined, Outputs = {}> {
45
60
  * Uses Symbol key to prevent external access.
46
61
  * @internal
47
62
  */
48
- static [FROM_BUILDER]<D, P, O>(input: {
63
+ static [FROM_BUILDER]<
64
+ Data extends PluginData,
65
+ Params extends PluginParams,
66
+ Outputs extends PluginOutputs,
67
+ >(options: {
49
68
  name: PluginName;
50
- dataModel: DataModel<D>;
51
- outputs: { [K in keyof O]: (ctx: PluginRenderCtx<D, P>) => O[K] };
52
- }): PluginModel<D, P, O> {
53
- return new this<D, P, O>(input);
69
+ dataModel: DataModel<Data>;
70
+ outputs: {
71
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
72
+ };
73
+ featureFlags?: BlockCodeKnownFeatureFlags;
74
+ }): PluginModel<Data, Params, Outputs> {
75
+ return new PluginModel<Data, Params, Outputs>(options);
54
76
  }
55
77
 
56
78
  /**
@@ -63,40 +85,66 @@ export class PluginModel<Data = unknown, Params = undefined, Outputs = {}> {
63
85
  * @example
64
86
  * const dataModelChain = new DataModelBuilder().from<MyData>(DATA_MODEL_DEFAULT_VERSION);
65
87
  *
66
- * const myPlugin = PluginModel.define<MyData, MyParams, MyConfig>({
88
+ * const myPlugin = PluginModel.define({
67
89
  * name: 'myPlugin' as PluginName,
68
90
  * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),
69
91
  * })
70
92
  * .output('computed', (ctx) => ctx.data.value * ctx.params.multiplier)
71
93
  * .build();
72
94
  */
73
- static define<Data, Params = undefined, Config = undefined>(options: {
95
+ static define<
96
+ Data extends PluginData,
97
+ Params extends PluginParams,
98
+ Config extends PluginConfig,
99
+ >(options: {
74
100
  name: PluginName;
75
101
  data: (config?: Config) => DataModel<Data>;
76
- }): PluginModelBuilder<Data, Params, Config> {
77
- return PluginModelBuilder[FROM_BUILDER]<Data, Params, Config>(options);
102
+ featureFlags?: BlockCodeKnownFeatureFlags;
103
+ }): PluginModelBuilder<Data, Params, {}, Config> {
104
+ return PluginModelBuilder[FROM_BUILDER](options);
78
105
  }
79
106
  }
80
107
 
81
- /**
82
- * Plugin factory returned by PluginModelBuilder.build().
83
- * Call create() with config to get a configured PluginModel instance.
84
- */
85
- class PluginModelFactory<Data, Params, Config, Outputs> {
108
+ /** Plugin factory returned by PluginModelBuilder.build(). */
109
+ export interface PluginFactory<
110
+ Data extends PluginData = PluginData,
111
+ Params extends PluginParams = undefined,
112
+ Outputs extends PluginOutputs = PluginOutputs,
113
+ Config extends PluginConfig = undefined,
114
+ > extends PluginFactoryLike {
115
+ create(config?: Config): PluginModel<Data, Params, Outputs>;
116
+ /**
117
+ * @internal Phantom field for structural type extraction.
118
+ * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.
119
+ */
120
+ readonly __types?: { data: Data; params: Params; outputs: Outputs; config: Config };
121
+ }
122
+
123
+ class PluginModelFactory<
124
+ Data extends PluginData = PluginData,
125
+ Params extends PluginParams = undefined,
126
+ Outputs extends PluginOutputs = PluginOutputs,
127
+ Config extends PluginConfig = undefined,
128
+ > implements PluginFactory<Data, Params, Outputs, Config> {
86
129
  private readonly name: PluginName;
87
130
  private readonly data: (config?: Config) => DataModel<Data>;
88
131
  private readonly outputs: {
89
- [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K];
132
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
90
133
  };
134
+ private readonly featureFlags?: BlockCodeKnownFeatureFlags;
91
135
 
92
- constructor(input: {
136
+ constructor(options: {
93
137
  name: PluginName;
94
138
  data: (config?: Config) => DataModel<Data>;
95
- outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
139
+ outputs: {
140
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
141
+ };
142
+ featureFlags?: BlockCodeKnownFeatureFlags;
96
143
  }) {
97
- this.name = input.name;
98
- this.data = input.data;
99
- this.outputs = input.outputs;
144
+ this.name = options.name;
145
+ this.data = options.data;
146
+ this.outputs = options.outputs;
147
+ this.featureFlags = options.featureFlags;
100
148
  }
101
149
 
102
150
  /** Create a configured PluginModel instance */
@@ -105,14 +153,11 @@ class PluginModelFactory<Data, Params, Config, Outputs> {
105
153
  name: this.name,
106
154
  dataModel: this.data(config),
107
155
  outputs: this.outputs,
156
+ featureFlags: this.featureFlags,
108
157
  });
109
158
  }
110
159
  }
111
160
 
112
- // =============================================================================
113
- // Plugin Model Builder
114
- // =============================================================================
115
-
116
161
  /**
117
162
  * Builder for creating PluginType with type-safe output definitions.
118
163
  *
@@ -136,27 +181,34 @@ class PluginModelFactory<Data, Params, Config, Outputs> {
136
181
  * .build();
137
182
  */
138
183
  class PluginModelBuilder<
139
- Data,
140
- Params = undefined,
141
- Config = undefined,
142
- Outputs extends Record<string, unknown> = {},
184
+ Data extends PluginData = PluginData,
185
+ Params extends PluginParams = undefined,
186
+ Outputs extends PluginOutputs = PluginOutputs,
187
+ Config extends PluginConfig = undefined,
143
188
  > {
144
189
  private readonly name: PluginName;
145
190
  private readonly data: (config?: Config) => DataModel<Data>;
146
191
  private readonly outputs: {
147
- [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K];
192
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
148
193
  };
194
+ private readonly featureFlags?: BlockCodeKnownFeatureFlags;
149
195
 
150
- private constructor(input: {
196
+ private constructor(options: {
151
197
  name: PluginName;
152
198
  data: (config?: Config) => DataModel<Data>;
153
- outputs?: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
199
+ outputs?: {
200
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
201
+ };
202
+ featureFlags?: BlockCodeKnownFeatureFlags;
154
203
  }) {
155
- this.name = input.name;
156
- this.data = input.data;
204
+ this.name = options.name;
205
+ this.data = options.data;
157
206
  this.outputs =
158
- input.outputs ??
159
- ({} as { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] });
207
+ options.outputs ??
208
+ ({} as {
209
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
210
+ });
211
+ this.featureFlags = options.featureFlags;
160
212
  }
161
213
 
162
214
  /**
@@ -164,12 +216,20 @@ class PluginModelBuilder<
164
216
  * Uses Symbol key to prevent external access.
165
217
  * @internal
166
218
  */
167
- static [FROM_BUILDER]<D, P, C, O extends Record<string, unknown> = {}>(input: {
219
+ static [FROM_BUILDER]<
220
+ Data extends PluginData,
221
+ Params extends PluginParams,
222
+ Outputs extends PluginOutputs,
223
+ Config extends PluginConfig,
224
+ >(options: {
168
225
  name: PluginName;
169
- data: (config?: C) => DataModel<D>;
170
- outputs?: { [K in keyof O]: (ctx: PluginRenderCtx<D, P>) => O[K] };
171
- }): PluginModelBuilder<D, P, C, O> {
172
- return new this<D, P, C, O>(input);
226
+ data: (config?: Config) => DataModel<Data>;
227
+ outputs?: {
228
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
229
+ };
230
+ featureFlags?: BlockCodeKnownFeatureFlags;
231
+ }): PluginModelBuilder<Data, Params, Outputs, Config> {
232
+ return new PluginModelBuilder(options);
173
233
  }
174
234
 
175
235
  /**
@@ -185,17 +245,18 @@ class PluginModelBuilder<
185
245
  */
186
246
  output<const Key extends string, T>(
187
247
  key: Key,
188
- fn: (ctx: PluginRenderCtx<Data, Params>) => T,
189
- ): PluginModelBuilder<Data, Params, Config, Outputs & { [K in Key]: T }> {
190
- return new PluginModelBuilder<Data, Params, Config, Outputs & { [K in Key]: T }>({
248
+ fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,
249
+ ): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config> {
250
+ return new PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config>({
191
251
  name: this.name,
192
252
  data: this.data,
253
+ featureFlags: this.featureFlags,
193
254
  outputs: {
194
255
  ...this.outputs,
195
256
  [key]: fn,
196
257
  } as {
197
258
  [K in keyof (Outputs & { [P in Key]: T })]: (
198
- ctx: PluginRenderCtx<Data, Params>,
259
+ ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,
199
260
  ) => (Outputs & { [P in Key]: T })[K];
200
261
  },
201
262
  });
@@ -214,11 +275,12 @@ class PluginModelBuilder<
214
275
  * // Later, call create() with config to get a configured instance:
215
276
  * const configured = myPlugin.create({ defaultValue: 'test' });
216
277
  */
217
- build(): PluginModelFactory<Data, Params, Config, Outputs> {
218
- return new PluginModelFactory<Data, Params, Config, Outputs>({
278
+ build(): PluginFactory<Data, Params, Outputs, Config> {
279
+ return new PluginModelFactory<Data, Params, Outputs, Config>({
219
280
  name: this.name,
220
281
  data: this.data,
221
282
  outputs: this.outputs,
283
+ featureFlags: this.featureFlags,
222
284
  });
223
285
  }
224
286
  }
package/src/render/api.ts CHANGED
@@ -50,6 +50,12 @@ import canonicalize from "canonicalize";
50
50
  import type { Optional } from "utility-types";
51
51
  import { getCfgRenderCtx } from "../internal";
52
52
  import { getPluginData } from "../block_storage";
53
+ import type {
54
+ PluginHandle,
55
+ PluginFactoryLike,
56
+ InferFactoryData,
57
+ InferFactoryParams,
58
+ } from "../plugin_handle";
53
59
  import { TreeNodeAccessor, ifDef } from "./accessor";
54
60
  import type { FutureRef } from "./future";
55
61
  import type { AccessorHandle, GlobalCfgRenderCtx } from "./internal";
@@ -756,40 +762,44 @@ export class RenderCtxLegacy<Args = unknown, UiState = unknown> extends RenderCt
756
762
  /**
757
763
  * Render context for plugin output functions.
758
764
  * Reads plugin data from blockStorage and derives params from pre-wrapped input callbacks.
765
+ *
766
+ * Parameterized on the factory-like phantom F so that getPluginData returns
767
+ * InferFactoryData<F> directly — no casts needed for the data getter.
768
+ *
769
+ * @typeParam F - PluginFactoryLike phantom carrying data/params/outputs types
759
770
  */
760
- export class PluginRenderCtx<Data = unknown, Params = unknown> {
771
+ export class PluginRenderCtx<F extends PluginFactoryLike = PluginFactoryLike> {
761
772
  private readonly ctx: GlobalCfgRenderCtx;
762
- private readonly pluginId: string;
773
+ private readonly handle: PluginHandle<F>;
763
774
  private readonly wrappedInputs: Record<string, () => unknown>;
764
775
 
765
- constructor(pluginId: string, wrappedInputs: Record<string, () => unknown>) {
776
+ constructor(handle: PluginHandle<F>, wrappedInputs: Record<string, () => unknown>) {
766
777
  this.ctx = getCfgRenderCtx();
767
- this.pluginId = pluginId;
778
+ this.handle = handle;
768
779
  this.wrappedInputs = wrappedInputs;
769
780
  }
770
781
 
771
- private dataCache?: { v: Data };
782
+ private dataCache?: { v: InferFactoryData<F> };
772
783
 
773
784
  /** Plugin's persistent data from blockStorage.__plugins.{pluginId}.__data */
774
- public get data(): Data {
785
+ public get data(): InferFactoryData<F> {
775
786
  if (this.dataCache === undefined) {
776
787
  const raw = this.ctx.blockStorage();
777
- const pluginData = getPluginData<Data>(parseJson(raw), this.pluginId);
778
- this.dataCache = { v: pluginData };
788
+ this.dataCache = { v: getPluginData(parseJson(raw), this.handle) };
779
789
  }
780
790
  return this.dataCache.v;
781
791
  }
782
792
 
783
- private paramsCache?: { v: Params };
793
+ private paramsCache?: { v: InferFactoryParams<F> };
784
794
 
785
795
  /** Params derived from block context via pre-wrapped input callbacks */
786
- public get params(): Params {
796
+ public get params(): InferFactoryParams<F> {
787
797
  if (this.paramsCache === undefined) {
788
798
  const result: Record<string, unknown> = {};
789
799
  for (const [key, fn] of Object.entries(this.wrappedInputs)) {
790
800
  result[key] = fn();
791
801
  }
792
- this.paramsCache = { v: result as Params };
802
+ this.paramsCache = { v: result as InferFactoryParams<F> };
793
803
  }
794
804
  return this.paramsCache.v;
795
805
  }