@platforma-sdk/model 1.54.13 → 1.56.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 (120) hide show
  1. package/dist/bconfig/normalization.cjs +8 -1
  2. package/dist/bconfig/normalization.cjs.map +1 -1
  3. package/dist/bconfig/normalization.d.ts.map +1 -1
  4. package/dist/bconfig/normalization.js +8 -1
  5. package/dist/bconfig/normalization.js.map +1 -1
  6. package/dist/block_api_v3.d.ts +2 -2
  7. package/dist/block_api_v3.d.ts.map +1 -1
  8. package/dist/block_migrations.cjs +246 -214
  9. package/dist/block_migrations.cjs.map +1 -1
  10. package/dist/block_migrations.d.ts +180 -158
  11. package/dist/block_migrations.d.ts.map +1 -1
  12. package/dist/block_migrations.js +247 -214
  13. package/dist/block_migrations.js.map +1 -1
  14. package/dist/block_model.cjs +85 -35
  15. package/dist/block_model.cjs.map +1 -1
  16. package/dist/block_model.d.ts +66 -38
  17. package/dist/block_model.d.ts.map +1 -1
  18. package/dist/block_model.js +86 -36
  19. package/dist/block_model.js.map +1 -1
  20. package/dist/{builder.cjs → block_model_legacy.cjs} +2 -2
  21. package/dist/block_model_legacy.cjs.map +1 -0
  22. package/dist/{builder.d.ts → block_model_legacy.d.ts} +1 -1
  23. package/dist/block_model_legacy.d.ts.map +1 -0
  24. package/dist/{builder.js → block_model_legacy.js} +2 -2
  25. package/dist/block_model_legacy.js.map +1 -0
  26. package/dist/block_state_patch.d.ts +11 -1
  27. package/dist/block_state_patch.d.ts.map +1 -1
  28. package/dist/block_storage.cjs +126 -109
  29. package/dist/block_storage.cjs.map +1 -1
  30. package/dist/block_storage.d.ts +109 -112
  31. package/dist/block_storage.d.ts.map +1 -1
  32. package/dist/block_storage.js +126 -101
  33. package/dist/block_storage.js.map +1 -1
  34. package/dist/block_storage_callbacks.cjs +227 -0
  35. package/dist/block_storage_callbacks.cjs.map +1 -0
  36. package/dist/block_storage_callbacks.d.ts +113 -0
  37. package/dist/block_storage_callbacks.d.ts.map +1 -0
  38. package/dist/block_storage_callbacks.js +218 -0
  39. package/dist/block_storage_callbacks.js.map +1 -0
  40. package/dist/block_storage_facade.cjs +104 -0
  41. package/dist/block_storage_facade.cjs.map +1 -0
  42. package/dist/block_storage_facade.d.ts +168 -0
  43. package/dist/block_storage_facade.d.ts.map +1 -0
  44. package/dist/block_storage_facade.js +99 -0
  45. package/dist/block_storage_facade.js.map +1 -0
  46. package/dist/index.cjs +13 -14
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.ts +8 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +6 -4
  51. package/dist/index.js.map +1 -1
  52. package/dist/package.json.cjs +1 -1
  53. package/dist/package.json.js +1 -1
  54. package/dist/platforma.d.ts +11 -4
  55. package/dist/platforma.d.ts.map +1 -1
  56. package/dist/plugin_model.cjs +171 -0
  57. package/dist/plugin_model.cjs.map +1 -0
  58. package/dist/plugin_model.d.ts +162 -0
  59. package/dist/plugin_model.d.ts.map +1 -0
  60. package/dist/plugin_model.js +169 -0
  61. package/dist/plugin_model.js.map +1 -0
  62. package/dist/render/api.cjs +20 -21
  63. package/dist/render/api.cjs.map +1 -1
  64. package/dist/render/api.d.ts +8 -8
  65. package/dist/render/api.d.ts.map +1 -1
  66. package/dist/render/api.js +20 -21
  67. package/dist/render/api.js.map +1 -1
  68. package/dist/render/internal.cjs.map +1 -1
  69. package/dist/render/internal.d.ts +2 -1
  70. package/dist/render/internal.d.ts.map +1 -1
  71. package/dist/render/internal.js.map +1 -1
  72. package/dist/version.cjs +4 -0
  73. package/dist/version.cjs.map +1 -1
  74. package/dist/version.d.ts +4 -0
  75. package/dist/version.d.ts.map +1 -1
  76. package/dist/version.js +4 -1
  77. package/dist/version.js.map +1 -1
  78. package/package.json +5 -5
  79. package/src/bconfig/normalization.ts +8 -1
  80. package/src/block_api_v3.ts +2 -2
  81. package/src/block_migrations.test.ts +141 -171
  82. package/src/block_migrations.ts +300 -285
  83. package/src/block_model.ts +205 -95
  84. package/src/{builder.ts → block_model_legacy.ts} +1 -1
  85. package/src/block_state_patch.ts +13 -1
  86. package/src/block_storage.test.ts +283 -95
  87. package/src/block_storage.ts +199 -188
  88. package/src/block_storage_callbacks.ts +326 -0
  89. package/src/block_storage_facade.ts +199 -0
  90. package/src/index.ts +7 -3
  91. package/src/platforma.ts +26 -7
  92. package/src/plugin_model.test.ts +168 -0
  93. package/src/plugin_model.ts +242 -0
  94. package/src/render/api.ts +26 -24
  95. package/src/render/internal.ts +3 -1
  96. package/src/typing.test.ts +1 -1
  97. package/src/version.ts +8 -0
  98. package/dist/block_storage_vm.cjs +0 -262
  99. package/dist/block_storage_vm.cjs.map +0 -1
  100. package/dist/block_storage_vm.d.ts +0 -59
  101. package/dist/block_storage_vm.d.ts.map +0 -1
  102. package/dist/block_storage_vm.js +0 -258
  103. package/dist/block_storage_vm.js.map +0 -1
  104. package/dist/branding.d.ts +0 -7
  105. package/dist/branding.d.ts.map +0 -1
  106. package/dist/builder.cjs.map +0 -1
  107. package/dist/builder.d.ts.map +0 -1
  108. package/dist/builder.js.map +0 -1
  109. package/dist/sdk_info.cjs +0 -10
  110. package/dist/sdk_info.cjs.map +0 -1
  111. package/dist/sdk_info.d.ts +0 -5
  112. package/dist/sdk_info.d.ts.map +0 -1
  113. package/dist/sdk_info.js +0 -8
  114. package/dist/sdk_info.js.map +0 -1
  115. package/dist/unionize.d.ts +0 -12
  116. package/dist/unionize.d.ts.map +0 -1
  117. package/src/block_storage_vm.ts +0 -346
  118. package/src/branding.ts +0 -4
  119. package/src/sdk_info.ts +0 -9
  120. package/src/unionize.ts +0 -12
@@ -0,0 +1,168 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { PluginModel } from "./plugin_model";
3
+ import type { PluginRenderCtx } from "./plugin_model";
4
+ import { DataModelBuilder } from "./block_migrations";
5
+ import { DATA_MODEL_DEFAULT_VERSION, type PluginName } from "./block_storage";
6
+ import type { ResultPool } from "./render";
7
+
8
+ // =============================================================================
9
+ // Test Fixtures
10
+ // =============================================================================
11
+
12
+ type Data = { count: number; label: string };
13
+
14
+ const dataModelChain = new DataModelBuilder().from<Data>(DATA_MODEL_DEFAULT_VERSION);
15
+
16
+ // Mock ResultPool for testing
17
+ const mockResultPool = {} as ResultPool;
18
+
19
+ // =============================================================================
20
+ // Tests
21
+ // =============================================================================
22
+
23
+ describe("PluginModel", () => {
24
+ it("creates PluginModel with required fields", () => {
25
+ const factory = PluginModel.define<Data>({
26
+ name: "testPlugin" as PluginName,
27
+ data: () => dataModelChain.init(() => ({ count: 0, label: "" })),
28
+ }).build();
29
+
30
+ const plugin = factory.create();
31
+ expect(plugin.name).toBe("testPlugin");
32
+ expect(plugin.outputs).toEqual({});
33
+ });
34
+
35
+ it("creates PluginModel when calling create() with config", () => {
36
+ type Config = { initialCount: number };
37
+
38
+ const factory = PluginModel.define<Data, undefined, Config>({
39
+ name: "factoryPlugin" as PluginName,
40
+ data: (cfg) => dataModelChain.init(() => ({ count: cfg.initialCount, label: "initialized" })),
41
+ }).build();
42
+
43
+ const plugin = factory.create({ initialCount: 100 });
44
+ expect(plugin.name).toBe("factoryPlugin");
45
+ expect(plugin.dataModel.initialData()).toEqual({ count: 100, label: "initialized" });
46
+ });
47
+
48
+ it("adds single output", () => {
49
+ const factory = PluginModel.define<Data, { multiplier: number }>({
50
+ name: "singleOutput" as PluginName,
51
+ data: () => dataModelChain.init(() => ({ count: 0, label: "" })),
52
+ })
53
+ .output("doubled", (ctx) => ctx.data.count * ctx.params.multiplier)
54
+ .build();
55
+
56
+ const plugin = factory.create();
57
+ expect(Object.keys(plugin.outputs)).toEqual(["doubled"]);
58
+ });
59
+
60
+ it("accumulates multiple outputs", () => {
61
+ const factory = PluginModel.define<Data, { prefix: string }>({
62
+ name: "multiOutput" as PluginName,
63
+ data: () => dataModelChain.init(() => ({ count: 0, label: "" })),
64
+ })
65
+ .output("formattedCount", (ctx) => `${ctx.params.prefix}${ctx.data.count}`)
66
+ .output("upperLabel", (ctx) => ctx.data.label.toUpperCase())
67
+ .output("isReady", (ctx) => ctx.data.count > 0)
68
+ .build();
69
+
70
+ const plugin = factory.create();
71
+ expect(Object.keys(plugin.outputs).sort()).toEqual(["formattedCount", "isReady", "upperLabel"]);
72
+ });
73
+
74
+ it("executes output functions with correct context", () => {
75
+ const factory = PluginModel.define<Data, { factor: number }>({
76
+ name: "contextTest" as PluginName,
77
+ data: () => dataModelChain.init(() => ({ count: 0, label: "" })),
78
+ })
79
+ .output("computed", (ctx) => ctx.data.count * ctx.params.factor)
80
+ .build();
81
+
82
+ const plugin = factory.create();
83
+
84
+ const ctx: PluginRenderCtx<Data, { factor: number }> = {
85
+ data: { count: 5, label: "" },
86
+ params: { factor: 3 },
87
+ resultPool: mockResultPool,
88
+ };
89
+
90
+ const result = plugin.outputs.computed(ctx);
91
+ expect(result).toBe(15);
92
+ });
93
+
94
+ it("allows outputs to access resultPool", () => {
95
+ const factory = PluginModel.define<Data>({
96
+ name: "resultPoolTest" as PluginName,
97
+ data: () => dataModelChain.init(() => ({ count: 0, label: "" })),
98
+ })
99
+ .output("hasResultPool", (ctx) => ctx.resultPool !== undefined)
100
+ .build();
101
+
102
+ const plugin = factory.create();
103
+
104
+ const ctx: PluginRenderCtx<Data> = {
105
+ data: { count: 0, label: "" },
106
+ params: undefined,
107
+ resultPool: mockResultPool,
108
+ };
109
+
110
+ expect(plugin.outputs.hasResultPool(ctx)).toBe(true);
111
+ });
112
+
113
+ it("returns valid PluginModel from factory.create()", () => {
114
+ const factory = PluginModel.define<Data, { items: string[] }, { option: boolean }>({
115
+ name: "completePlugin" as PluginName,
116
+ data: () => dataModelChain.init(() => ({ count: -1, label: "" })),
117
+ })
118
+ .output("currentItem", (ctx) => ctx.params.items[ctx.data.count])
119
+ .output("hasSelection", (ctx) => ctx.data.count >= 0)
120
+ .build();
121
+
122
+ const plugin = factory.create({ option: true });
123
+ expect(plugin.name).toBe("completePlugin");
124
+ expect(Object.keys(plugin.outputs).sort()).toEqual(["currentItem", "hasSelection"]);
125
+ });
126
+
127
+ it("allows creating plugin without outputs", () => {
128
+ const factory = PluginModel.define<Data>({
129
+ name: "noOutputs" as PluginName,
130
+ data: () => dataModelChain.init(() => ({ count: 0, label: "" })),
131
+ }).build();
132
+
133
+ const plugin = factory.create();
134
+ expect(plugin.outputs).toEqual({});
135
+ });
136
+
137
+ it("passes config to data model factory for initialization", () => {
138
+ type Config = { defaultCount: number; defaultLabel: string };
139
+
140
+ const factory = PluginModel.define<Data, undefined, Config>({
141
+ name: "configInitPlugin" as PluginName,
142
+ data: (cfg) =>
143
+ dataModelChain.init(() => ({ count: cfg.defaultCount, label: cfg.defaultLabel })),
144
+ }).build();
145
+
146
+ const plugin = factory.create({ defaultCount: 10, defaultLabel: "default" });
147
+ expect(plugin.dataModel.initialData()).toEqual({ count: 10, label: "default" });
148
+ });
149
+
150
+ it("does not modify original builder when chaining", () => {
151
+ const basePlugin = PluginModel.define<Data>({
152
+ name: "immutableTest" as PluginName,
153
+ data: () => dataModelChain.init(() => ({ count: 0, label: "" })),
154
+ });
155
+
156
+ const pluginWithOutput1 = basePlugin.output("first", (ctx) => ctx.data.count);
157
+ const pluginWithOutput2 = basePlugin.output("second", (ctx) => ctx.data.count * 2);
158
+
159
+ const factory1 = pluginWithOutput1.build();
160
+ const factory2 = pluginWithOutput2.build();
161
+
162
+ const plugin1 = factory1.create(undefined);
163
+ const plugin2 = factory2.create(undefined);
164
+
165
+ expect(Object.keys(plugin1.outputs)).toEqual(["first"]);
166
+ expect(Object.keys(plugin2.outputs)).toEqual(["second"]);
167
+ });
168
+ });
@@ -0,0 +1,242 @@
1
+ /**
2
+ * PluginModel - Builder for creating plugin types with data model and outputs.
3
+ *
4
+ * Plugins are UI components with their own model logic and persistent state.
5
+ * Block developers register plugin instances via BlockModelV3.plugin() method.
6
+ *
7
+ * @module plugin_model
8
+ */
9
+
10
+ import type { DataModel } from "./block_migrations";
11
+ import type { PluginName } from "./block_storage";
12
+ import type { ResultPool } from "./render";
13
+
14
+ /** Symbol for internal builder creation method */
15
+ const FROM_BUILDER = Symbol("fromBuilder");
16
+
17
+ // =============================================================================
18
+ // Plugin Render Context
19
+ // =============================================================================
20
+
21
+ /**
22
+ * Context passed to plugin output functions.
23
+ * Provides access to plugin's persistent data, params derived from block context,
24
+ * and the result pool for accessing workflow outputs.
25
+ */
26
+ export interface PluginRenderCtx<Data, Params = undefined> {
27
+ /** Plugin's persistent data */
28
+ readonly data: Data;
29
+ /** Params derived from block's RenderCtx */
30
+ readonly params: Params;
31
+ /** Result pool for accessing workflow outputs */
32
+ readonly resultPool: ResultPool;
33
+ }
34
+
35
+ // =============================================================================
36
+ // Plugin Type
37
+ // =============================================================================
38
+
39
+ /**
40
+ * Configured plugin instance returned by PluginModelFactory.create().
41
+ * Contains the plugin's name, data model, and output definitions.
42
+ */
43
+ export class PluginModel<Data = unknown, Params = undefined, Outputs = {}> {
44
+ /** Globally unique plugin name */
45
+ readonly name: PluginName;
46
+ /** Data model instance for this plugin */
47
+ readonly dataModel: DataModel<Data>;
48
+ /** Output definitions - functions that compute outputs from plugin context */
49
+ readonly outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
50
+
51
+ private constructor(input: {
52
+ name: PluginName;
53
+ dataModel: DataModel<Data>;
54
+ outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
55
+ }) {
56
+ this.name = input.name;
57
+ this.dataModel = input.dataModel;
58
+ this.outputs = input.outputs;
59
+ }
60
+
61
+ /**
62
+ * Internal method for creating PluginModel from factory.
63
+ * Uses Symbol key to prevent external access.
64
+ * @internal
65
+ */
66
+ static [FROM_BUILDER]<D, P, O>(input: {
67
+ name: PluginName;
68
+ dataModel: DataModel<D>;
69
+ outputs: { [K in keyof O]: (ctx: PluginRenderCtx<D, P>) => O[K] };
70
+ }): PluginModel<D, P, O> {
71
+ return new this<D, P, O>(input);
72
+ }
73
+
74
+ /**
75
+ * Creates a new PluginModelBuilder for building plugin definitions.
76
+ *
77
+ * @param options.name - Globally unique plugin name
78
+ * @param options.data - Factory function that creates the data model from config
79
+ * @returns PluginModelBuilder for chaining output definitions
80
+ *
81
+ * @example
82
+ * const dataModelChain = new DataModelBuilder().from<MyData>(DATA_MODEL_DEFAULT_VERSION);
83
+ *
84
+ * const myPlugin = PluginModel.define<MyData, MyParams, MyConfig>({
85
+ * name: 'myPlugin' as PluginName,
86
+ * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),
87
+ * })
88
+ * .output('computed', (ctx) => ctx.data.value * ctx.params.multiplier)
89
+ * .build();
90
+ */
91
+ static define<Data, Params = undefined, Config = undefined>(options: {
92
+ name: PluginName;
93
+ data: (config?: Config) => DataModel<Data>;
94
+ }): PluginModelBuilder<Data, Params, Config> {
95
+ return PluginModelBuilder[FROM_BUILDER]<Data, Params, Config>(options);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Plugin factory returned by PluginModelBuilder.build().
101
+ * Call create() with config to get a configured PluginModel instance.
102
+ */
103
+ class PluginModelFactory<Data, Params, Config, Outputs> {
104
+ private readonly name: PluginName;
105
+ private readonly data: (config?: Config) => DataModel<Data>;
106
+ private readonly outputs: {
107
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K];
108
+ };
109
+
110
+ constructor(input: {
111
+ name: PluginName;
112
+ data: (config?: Config) => DataModel<Data>;
113
+ outputs: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
114
+ }) {
115
+ this.name = input.name;
116
+ this.data = input.data;
117
+ this.outputs = input.outputs;
118
+ }
119
+
120
+ /** Create a configured PluginModel instance */
121
+ create(config?: Config): PluginModel<Data, Params, Outputs> {
122
+ return PluginModel[FROM_BUILDER]<Data, Params, Outputs>({
123
+ name: this.name,
124
+ dataModel: this.data(config),
125
+ outputs: this.outputs,
126
+ });
127
+ }
128
+ }
129
+
130
+ // =============================================================================
131
+ // Plugin Model Builder
132
+ // =============================================================================
133
+
134
+ /**
135
+ * Builder for creating PluginType with type-safe output definitions.
136
+ *
137
+ * Use `PluginModel.define()` to create a builder instance.
138
+ *
139
+ * @typeParam Data - Plugin's persistent data type
140
+ * @typeParam Params - Params derived from block's RenderCtx (optional)
141
+ * @typeParam Config - Static configuration passed to plugin factory (optional)
142
+ * @typeParam Outputs - Accumulated output types
143
+ *
144
+ * @example
145
+ * const dataModelChain = new DataModelBuilder().from<TableData>(DATA_MODEL_DEFAULT_VERSION);
146
+ *
147
+ * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({
148
+ * name: 'dataTable' as PluginName,
149
+ * data: (cfg) => {
150
+ * return dataModelChain.init(() => ({ state: createInitialState(cfg.ops) }));
151
+ * },
152
+ * })
153
+ * .output('model', (ctx) => createTableModel(ctx))
154
+ * .build();
155
+ */
156
+ class PluginModelBuilder<
157
+ Data,
158
+ Params = undefined,
159
+ Config = undefined,
160
+ Outputs extends Record<string, unknown> = {},
161
+ > {
162
+ private readonly name: PluginName;
163
+ private readonly data: (config?: Config) => DataModel<Data>;
164
+ private readonly outputs: {
165
+ [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K];
166
+ };
167
+
168
+ private constructor(input: {
169
+ name: PluginName;
170
+ data: (config?: Config) => DataModel<Data>;
171
+ outputs?: { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] };
172
+ }) {
173
+ this.name = input.name;
174
+ this.data = input.data;
175
+ this.outputs =
176
+ input.outputs ??
177
+ ({} as { [K in keyof Outputs]: (ctx: PluginRenderCtx<Data, Params>) => Outputs[K] });
178
+ }
179
+
180
+ /**
181
+ * Internal method for creating PluginModelBuilder.
182
+ * Uses Symbol key to prevent external access.
183
+ * @internal
184
+ */
185
+ static [FROM_BUILDER]<D, P, C, O extends Record<string, unknown> = {}>(input: {
186
+ name: PluginName;
187
+ data: (config?: C) => DataModel<D>;
188
+ outputs?: { [K in keyof O]: (ctx: PluginRenderCtx<D, P>) => O[K] };
189
+ }): PluginModelBuilder<D, P, C, O> {
190
+ return new this<D, P, C, O>(input);
191
+ }
192
+
193
+ /**
194
+ * Adds an output to the plugin.
195
+ *
196
+ * @param key - Output name
197
+ * @param fn - Function that computes the output value from plugin context
198
+ * @returns PluginModel with the new output added
199
+ *
200
+ * @example
201
+ * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))
202
+ * .output('isReady', (ctx) => ctx.params.columns !== undefined)
203
+ */
204
+ output<const Key extends string, T>(
205
+ key: Key,
206
+ fn: (ctx: PluginRenderCtx<Data, Params>) => T,
207
+ ): PluginModelBuilder<Data, Params, Config, Outputs & { [K in Key]: T }> {
208
+ return new PluginModelBuilder<Data, Params, Config, Outputs & { [K in Key]: T }>({
209
+ name: this.name,
210
+ data: this.data,
211
+ outputs: {
212
+ ...this.outputs,
213
+ [key]: fn,
214
+ } as {
215
+ [K in keyof (Outputs & { [P in Key]: T })]: (
216
+ ctx: PluginRenderCtx<Data, Params>,
217
+ ) => (Outputs & { [P in Key]: T })[K];
218
+ },
219
+ });
220
+ }
221
+
222
+ /**
223
+ * Finalizes the plugin definition and returns a ConfigurablePluginModel.
224
+ *
225
+ * @returns Callable plugin factory that accepts config and returns PluginModel
226
+ *
227
+ * @example
228
+ * const myPlugin = new PluginModelBuilder('myPlugin', () => dataModel)
229
+ * .output('value', (ctx) => ctx.data.value)
230
+ * .build();
231
+ *
232
+ * // Later, call create() with config to get a configured instance:
233
+ * const configured = myPlugin.create({ defaultValue: 'test' });
234
+ */
235
+ build(): PluginModelFactory<Data, Params, Config, Outputs> {
236
+ return new PluginModelFactory<Data, Params, Config, Outputs>({
237
+ name: this.name,
238
+ data: this.data,
239
+ outputs: this.outputs,
240
+ });
241
+ }
242
+ }
package/src/render/api.ts CHANGED
@@ -533,40 +533,40 @@ export class ResultPool implements ColumnProvider, AxisLabelProvider {
533
533
  }
534
534
 
535
535
  /** Main entry point to the API available within model lambdas (like outputs, sections, etc..) */
536
- export abstract class RenderCtxBase<Args, Data> {
536
+ export abstract class RenderCtxBase<Args = unknown, Data = unknown> {
537
537
  protected readonly ctx: GlobalCfgRenderCtx;
538
538
 
539
539
  constructor() {
540
540
  this.ctx = getCfgRenderCtx();
541
541
  }
542
542
 
543
- private _dataCache?: { v: Data };
543
+ private dataCache?: { v: Data };
544
544
 
545
545
  public get data(): Data {
546
- if (this._dataCache === undefined) {
546
+ if (this.dataCache === undefined) {
547
547
  const raw = this.ctx.data;
548
548
  const value = typeof raw === "function" ? raw() : raw;
549
- this._dataCache = { v: value ? JSON.parse(value) : ({} as Data) };
549
+ this.dataCache = { v: value ? JSON.parse(value) : ({} as Data) };
550
550
  }
551
- return this._dataCache.v;
551
+ return this.dataCache.v;
552
552
  }
553
553
 
554
554
  // lazy rendering because this feature is rarely used
555
- private _activeArgsCache?: { v?: Args };
555
+ private activeArgsCache?: { v?: Args };
556
556
 
557
557
  /**
558
558
  * Returns args snapshot the block was executed for (i.e. when "Run" button was pressed).
559
559
  * Returns undefined, if block was never executed or stopped mid-way execution, so that the result was cleared.
560
560
  * */
561
561
  public get activeArgs(): Args | undefined {
562
- if (this._activeArgsCache === undefined) {
562
+ if (this.activeArgsCache === undefined) {
563
563
  const raw = this.ctx.activeArgs;
564
564
  const value = typeof raw === "function" ? raw() : raw;
565
- this._activeArgsCache = {
565
+ this.activeArgsCache = {
566
566
  v: value ? JSON.parse(value) : undefined,
567
567
  };
568
568
  }
569
- return this._activeArgsCache.v;
569
+ return this.activeArgsCache.v;
570
570
  }
571
571
 
572
572
  // /** Can be used to determine features provided by the desktop instance. */
@@ -711,41 +711,43 @@ export abstract class RenderCtxBase<Args, Data> {
711
711
  }
712
712
 
713
713
  /** Main entry point to the API available within model lambdas (like outputs, sections, etc..) for v3+ blocks */
714
- export class RenderCtx<Args, Data> extends RenderCtxBase<Args, Data> {
715
- private _argsCache?: { v: Args | undefined };
714
+ export class RenderCtx<Args = unknown, Data = unknown> extends RenderCtxBase<Args, Data> {
715
+ private argsCache?: { v: Args | undefined };
716
716
  public get args(): Args | undefined {
717
- if (this._argsCache === undefined) {
717
+ if (this.argsCache === undefined) {
718
718
  const raw = this.ctx.args;
719
719
  const value = typeof raw === "function" ? raw() : raw;
720
- // args can be undefined when derivation fails (e.g., validation error in args())
721
- this._argsCache = { v: value === undefined ? undefined : JSON.parse(value) };
720
+ this.argsCache = { v: value === undefined ? undefined : JSON.parse(value) };
722
721
  }
723
- return this._argsCache.v;
722
+ return this.argsCache.v;
724
723
  }
725
724
  }
726
725
 
727
726
  /** Render context for legacy v1/v2 blocks - provides backward compatibility */
728
- export class RenderCtxLegacy<Args, UiState> extends RenderCtxBase<Args, UiState> {
729
- private _argsCache?: { v: Args };
727
+ export class RenderCtxLegacy<Args = unknown, UiState = unknown> extends RenderCtxBase<
728
+ Args,
729
+ UiState
730
+ > {
731
+ private argsCache?: { v: Args };
730
732
 
731
733
  public get args(): Args {
732
- if (this._argsCache === undefined) {
734
+ if (this.argsCache === undefined) {
733
735
  const raw = this.ctx.args;
734
736
  const value = typeof raw === "function" ? raw() : raw;
735
- this._argsCache = { v: JSON.parse(value) };
737
+ this.argsCache = { v: JSON.parse(value) };
736
738
  }
737
- return this._argsCache.v;
739
+ return this.argsCache.v;
738
740
  }
739
741
 
740
- private _uiStateCache?: { v: UiState };
742
+ private uiStateCache?: { v: UiState };
741
743
 
742
744
  public get uiState(): UiState {
743
- if (this._uiStateCache === undefined) {
745
+ if (this.uiStateCache === undefined) {
744
746
  const raw = this.ctx.uiState!;
745
747
  const value = typeof raw === "function" ? raw() : raw;
746
- this._uiStateCache = { v: value ? JSON.parse(value) : ({} as UiState) };
748
+ this.uiStateCache = { v: value ? JSON.parse(value) : ({} as UiState) };
747
749
  }
748
- return this._uiStateCache.v;
750
+ return this.uiStateCache.v;
749
751
  }
750
752
  }
751
753
 
@@ -1,5 +1,5 @@
1
1
  import type { Optional } from "utility-types";
2
- import type { Branded } from "../branding";
2
+ import type { Branded, StringifiedJson } from "@milaboratories/pl-model-common";
3
3
  import type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from "./traversal_ops";
4
4
  import type {
5
5
  ArchiveFormat,
@@ -198,6 +198,8 @@ export interface GlobalCfgRenderCtx extends GlobalCfgRenderCtxMethods {
198
198
  readonly data: string | (() => string);
199
199
  readonly activeArgs: undefined | string | (() => string | undefined);
200
200
 
201
+ readonly blockStorage: () => StringifiedJson;
202
+
201
203
  // Note: strings below are used because, anyway, using strings is the only way
202
204
  // to get data inside the QuickJS context, as it is implemented now. With this
203
205
  // approach deserialization can be lazily postponed until it is actually needed.
@@ -6,7 +6,7 @@ import {
6
6
  } from "@milaboratories/pl-model-common";
7
7
  import { expect, test } from "vitest";
8
8
  import { DeriveHref, StdCtx } from "./bconfig";
9
- import { BlockModel } from "./builder";
9
+ import { BlockModel } from "./block_model_legacy";
10
10
  import {
11
11
  Args,
12
12
  ConfigResult,
package/src/version.ts CHANGED
@@ -1,2 +1,10 @@
1
1
  import { version } from "../package.json";
2
2
  export const PlatformaSDKVersion = version;
3
+
4
+ export type SdkInfo = {
5
+ readonly sdkVersion: string;
6
+ };
7
+
8
+ export const CurrentSdkInfo: SdkInfo = {
9
+ sdkVersion: PlatformaSDKVersion,
10
+ };