@platforma-sdk/model 1.81.0 → 1.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/block_migrations.cjs +92 -8
- package/dist/block_migrations.cjs.map +1 -1
- package/dist/block_migrations.d.ts +121 -32
- package/dist/block_migrations.d.ts.map +1 -1
- package/dist/block_migrations.js +92 -8
- package/dist/block_migrations.js.map +1 -1
- package/dist/block_model.cjs +69 -15
- package/dist/block_model.cjs.map +1 -1
- package/dist/block_model.d.ts +58 -22
- package/dist/block_model.d.ts.map +1 -1
- package/dist/block_model.js +71 -17
- package/dist/block_model.js.map +1 -1
- package/dist/block_storage_callbacks.cjs +194 -13
- package/dist/block_storage_callbacks.cjs.map +1 -1
- package/dist/block_storage_callbacks.js +192 -15
- package/dist/block_storage_callbacks.js.map +1 -1
- package/dist/block_storage_facade.cjs +4 -1
- package/dist/block_storage_facade.cjs.map +1 -1
- package/dist/block_storage_facade.d.ts +102 -0
- package/dist/block_storage_facade.d.ts.map +1 -1
- package/dist/block_storage_facade.js +4 -1
- package/dist/block_storage_facade.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.cjs +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.js +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.js +1 -1
- package/package.json +9 -8
- package/src/block_migrations.ts +205 -55
- package/src/block_model.ts +190 -59
- package/src/block_storage_callbacks.ts +294 -15
- package/src/block_storage_facade.ts +95 -0
- package/src/components/PlDataTable/createPlDataTable/utils.test.ts +31 -0
- package/src/components/PlDataTable/createPlDataTable/utils.ts +4 -1
- package/src/kind_reference.test.ts +134 -0
- package/src/template_init.test.ts +413 -0
- package/src/template_params.test.ts +135 -0
package/src/block_migrations.ts
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
|
+
import type { BlockKindReference } from "@milaboratories/pl-model-common";
|
|
2
|
+
import { formatKindRef } from "@milaboratories/pl-model-common";
|
|
3
|
+
import type { CompiledBlockKind } from "@platforma-sdk/block-kind";
|
|
1
4
|
import { DATA_MODEL_LEGACY_VERSION } from "./block_storage";
|
|
2
5
|
|
|
3
6
|
export type DataVersionKey = string;
|
|
4
7
|
export type DataMigrateFn<From, To> = (prev: Readonly<From>) => To;
|
|
5
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Initial-data factory. Object-arg so future inputs (services, resolved refs)
|
|
10
|
+
* can extend it without a signature break. `Params` carries the block's
|
|
11
|
+
* kind-declared params type; `never` means the block reads no params yet.
|
|
12
|
+
*/
|
|
13
|
+
export type DataCreateFn<T, Params = never> = (args: { params?: Params }) => T;
|
|
6
14
|
export type DataRecoverFn<T> = (version: DataVersionKey, data: unknown) => T;
|
|
7
15
|
|
|
16
|
+
/**
|
|
17
|
+
* The compiled block-kind object a block declares — exactly the output of
|
|
18
|
+
* `defineBlockKind` from `@platforma-sdk/block-kind`, consumed type-only.
|
|
19
|
+
*
|
|
20
|
+
* The kind object carries no reference field: the `{name}@{version}` reference
|
|
21
|
+
* is derived from it internally (via `formatKindRef`) at the point the builder
|
|
22
|
+
* and `BlockModelV3.create` need it. Aliased here so `DataModelBuilder` /
|
|
23
|
+
* `create` signatures directly accept `defineBlockKind`'s output.
|
|
24
|
+
*/
|
|
25
|
+
export type BlockKind<Params = never> = CompiledBlockKind<Params>;
|
|
26
|
+
|
|
8
27
|
/**
|
|
9
28
|
* Minimal interface that .transfer() accepts. PluginInstance implements this.
|
|
10
29
|
* Defined here to avoid circular dependency with plugin_model.ts.
|
|
@@ -89,23 +108,42 @@ const FROM_BUILDER = Symbol("fromBuilder");
|
|
|
89
108
|
/** Legacy V1 model state shape: { args, uiState } */
|
|
90
109
|
export type LegacyV1State<Args, UiState> = { args: Args; uiState: UiState };
|
|
91
110
|
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
111
|
+
/**
|
|
112
|
+
* The kind a chain belongs to, threaded unchanged from the builder into `DataModel`.
|
|
113
|
+
*
|
|
114
|
+
* Named because every constructor in this file carries exactly this pair, and they travel
|
|
115
|
+
* together by construction: a reference with no parser could not check the params it names,
|
|
116
|
+
* and a parser with no reference would have nothing to check them against.
|
|
117
|
+
*/
|
|
118
|
+
type KindWiring = {
|
|
119
|
+
/** Reference to the block kind this data model belongs to, if declared. */
|
|
120
|
+
kindRef?: BlockKindReference;
|
|
121
|
+
/** The kind's runtime params check, threaded with {@link KindWiring.kindRef}. */
|
|
122
|
+
parseInitializationParams?: (value: unknown) => unknown;
|
|
102
123
|
};
|
|
103
124
|
|
|
104
125
|
type RecoverState = {
|
|
105
126
|
recoverFn?: (version: DataVersionKey, data: unknown) => unknown;
|
|
127
|
+
/** Index of the first step to run after recovery. Equals the number of steps
|
|
128
|
+
* present at the time recover() was called. */
|
|
106
129
|
recoverFromIndex?: number;
|
|
107
130
|
};
|
|
108
131
|
|
|
132
|
+
/** Internal state passed from builder to DataModel */
|
|
133
|
+
type BuilderState<S> = KindWiring &
|
|
134
|
+
RecoverState & {
|
|
135
|
+
versionChain: DataVersionKey[];
|
|
136
|
+
steps: MigrationStep[];
|
|
137
|
+
transferSteps: TransferStep[];
|
|
138
|
+
/**
|
|
139
|
+
* The params type is erased to `unknown` here: the builder checks the block's
|
|
140
|
+
* factory against its kind's params, but a caller that supplies params carries them as
|
|
141
|
+
* data it did not type — parsed file content, today — and cannot state the type. The
|
|
142
|
+
* kind's own parser is what recovers it.
|
|
143
|
+
*/
|
|
144
|
+
initialDataFn: DataCreateFn<S, unknown>;
|
|
145
|
+
};
|
|
146
|
+
|
|
109
147
|
/**
|
|
110
148
|
* Abstract base for both migration chain types.
|
|
111
149
|
* Holds shared state, buildStep() helper, and init().
|
|
@@ -115,19 +153,31 @@ type RecoverState = {
|
|
|
115
153
|
*
|
|
116
154
|
* @internal
|
|
117
155
|
*/
|
|
118
|
-
abstract class MigrationChainBase<
|
|
156
|
+
abstract class MigrationChainBase<
|
|
157
|
+
Current,
|
|
158
|
+
Transfers extends Record<string, unknown> = {},
|
|
159
|
+
Params = never,
|
|
160
|
+
> {
|
|
119
161
|
protected readonly versionChain: DataVersionKey[];
|
|
120
162
|
protected readonly migrationSteps: MigrationStep[];
|
|
121
163
|
protected readonly transferSteps: TransferStep[];
|
|
122
|
-
|
|
123
|
-
protected
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
164
|
+
/** Kind reference seeded by the builder, threaded through the chain into init(). */
|
|
165
|
+
protected readonly kindRef?: BlockKindReference;
|
|
166
|
+
/** The kind's runtime params check, carried for `init()` to hand to the DataModel. */
|
|
167
|
+
protected readonly parseInitializationParams?: (value: unknown) => unknown;
|
|
168
|
+
|
|
169
|
+
protected constructor(
|
|
170
|
+
state: KindWiring & {
|
|
171
|
+
versionChain: DataVersionKey[];
|
|
172
|
+
steps: MigrationStep[];
|
|
173
|
+
transferSteps?: TransferStep[];
|
|
174
|
+
},
|
|
175
|
+
) {
|
|
128
176
|
this.versionChain = state.versionChain;
|
|
129
177
|
this.migrationSteps = state.steps;
|
|
130
178
|
this.transferSteps = state.transferSteps ?? [];
|
|
179
|
+
this.kindRef = state.kindRef;
|
|
180
|
+
this.parseInitializationParams = state.parseInitializationParams;
|
|
131
181
|
}
|
|
132
182
|
|
|
133
183
|
/** Appends a migration step and returns the new versionChain and steps arrays. */
|
|
@@ -178,12 +228,14 @@ abstract class MigrationChainBase<Current, Transfers extends Record<string, unkn
|
|
|
178
228
|
* @param initialData - Factory function returning the initial state
|
|
179
229
|
* @returns Finalized DataModel instance
|
|
180
230
|
*/
|
|
181
|
-
init(initialData: DataCreateFn<Current>): DataModel<Current, Transfers> {
|
|
182
|
-
return DataModel[FROM_BUILDER]<Current, Transfers>({
|
|
231
|
+
init(initialData: DataCreateFn<Current, Params>): DataModel<Current, Params, Transfers> {
|
|
232
|
+
return DataModel[FROM_BUILDER]<Current, Params, Transfers>({
|
|
183
233
|
versionChain: this.versionChain,
|
|
184
234
|
steps: this.migrationSteps,
|
|
185
235
|
transferSteps: this.transferSteps,
|
|
186
|
-
initialDataFn: initialData,
|
|
236
|
+
initialDataFn: initialData as DataCreateFn<Current, unknown>,
|
|
237
|
+
kindRef: this.kindRef,
|
|
238
|
+
parseInitializationParams: this.parseInitializationParams,
|
|
187
239
|
...this.recoverState(),
|
|
188
240
|
});
|
|
189
241
|
}
|
|
@@ -201,18 +253,20 @@ abstract class MigrationChainBase<Current, Transfers extends Record<string, unkn
|
|
|
201
253
|
class DataModelMigrationChainWithRecover<
|
|
202
254
|
Current,
|
|
203
255
|
Transfers extends Record<string, unknown> = {},
|
|
204
|
-
|
|
256
|
+
Params = never,
|
|
257
|
+
> extends MigrationChainBase<Current, Transfers, Params> {
|
|
205
258
|
private readonly recoverFn?: (version: DataVersionKey, data: unknown) => unknown;
|
|
206
259
|
private readonly recoverFromIndex?: number;
|
|
207
260
|
|
|
208
261
|
/** @internal */
|
|
209
|
-
constructor(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
262
|
+
constructor(
|
|
263
|
+
state: KindWiring &
|
|
264
|
+
RecoverState & {
|
|
265
|
+
versionChain: DataVersionKey[];
|
|
266
|
+
steps: MigrationStep[];
|
|
267
|
+
transferSteps?: TransferStep[];
|
|
268
|
+
},
|
|
269
|
+
) {
|
|
216
270
|
super(state);
|
|
217
271
|
this.recoverFn = state.recoverFn;
|
|
218
272
|
this.recoverFromIndex = state.recoverFromIndex;
|
|
@@ -232,12 +286,14 @@ class DataModelMigrationChainWithRecover<
|
|
|
232
286
|
migrate<Next>(
|
|
233
287
|
nextVersion: string,
|
|
234
288
|
fn: DataMigrateFn<Current, Next>,
|
|
235
|
-
): DataModelMigrationChainWithRecover<Next, Transfers> {
|
|
289
|
+
): DataModelMigrationChainWithRecover<Next, Transfers, Params> {
|
|
236
290
|
const { versionChain, steps } = this.buildStep(nextVersion, fn);
|
|
237
|
-
return new DataModelMigrationChainWithRecover<Next, Transfers>({
|
|
291
|
+
return new DataModelMigrationChainWithRecover<Next, Transfers, Params>({
|
|
238
292
|
versionChain,
|
|
239
293
|
steps,
|
|
240
294
|
transferSteps: this.transferSteps,
|
|
295
|
+
kindRef: this.kindRef,
|
|
296
|
+
parseInitializationParams: this.parseInitializationParams,
|
|
241
297
|
recoverFn: this.recoverFn,
|
|
242
298
|
recoverFromIndex: this.recoverFromIndex,
|
|
243
299
|
});
|
|
@@ -251,12 +307,14 @@ class DataModelMigrationChainWithRecover<
|
|
|
251
307
|
transfer<Id extends string, L>(
|
|
252
308
|
target: TransferTarget<Id & (Id extends keyof Transfers ? never : string), L>,
|
|
253
309
|
extract: (data: Current) => L,
|
|
254
|
-
): DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L
|
|
310
|
+
): DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L>, Params> {
|
|
255
311
|
const { transferSteps } = this.buildTransfer(target, extract);
|
|
256
|
-
return new DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L
|
|
312
|
+
return new DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L>, Params>({
|
|
257
313
|
versionChain: this.versionChain,
|
|
258
314
|
steps: this.migrationSteps,
|
|
259
315
|
transferSteps,
|
|
316
|
+
kindRef: this.kindRef,
|
|
317
|
+
parseInitializationParams: this.parseInitializationParams,
|
|
260
318
|
recoverFn: this.recoverFn,
|
|
261
319
|
recoverFromIndex: this.recoverFromIndex,
|
|
262
320
|
});
|
|
@@ -276,18 +334,21 @@ class DataModelMigrationChainWithRecover<
|
|
|
276
334
|
class DataModelMigrationChain<
|
|
277
335
|
Current,
|
|
278
336
|
Transfers extends Record<string, unknown> = {},
|
|
279
|
-
|
|
337
|
+
Params = never,
|
|
338
|
+
> extends MigrationChainBase<Current, Transfers, Params> {
|
|
280
339
|
/** @internal */
|
|
281
340
|
constructor({
|
|
282
341
|
versionChain,
|
|
283
342
|
steps = [],
|
|
284
343
|
transferSteps = [],
|
|
285
|
-
|
|
344
|
+
kindRef,
|
|
345
|
+
parseInitializationParams,
|
|
346
|
+
}: KindWiring & {
|
|
286
347
|
versionChain: DataVersionKey[];
|
|
287
348
|
steps?: MigrationStep[];
|
|
288
349
|
transferSteps?: TransferStep[];
|
|
289
350
|
}) {
|
|
290
|
-
super({ versionChain, steps, transferSteps });
|
|
351
|
+
super({ versionChain, steps, transferSteps, kindRef, parseInitializationParams });
|
|
291
352
|
}
|
|
292
353
|
|
|
293
354
|
/**
|
|
@@ -304,12 +365,14 @@ class DataModelMigrationChain<
|
|
|
304
365
|
migrate<Next>(
|
|
305
366
|
nextVersion: string,
|
|
306
367
|
fn: DataMigrateFn<Current, Next>,
|
|
307
|
-
): DataModelMigrationChain<Next, Transfers> {
|
|
368
|
+
): DataModelMigrationChain<Next, Transfers, Params> {
|
|
308
369
|
const { versionChain, steps } = this.buildStep(nextVersion, fn);
|
|
309
|
-
return new DataModelMigrationChain<Next, Transfers>({
|
|
370
|
+
return new DataModelMigrationChain<Next, Transfers, Params>({
|
|
310
371
|
versionChain,
|
|
311
372
|
steps,
|
|
312
373
|
transferSteps: this.transferSteps,
|
|
374
|
+
kindRef: this.kindRef,
|
|
375
|
+
parseInitializationParams: this.parseInitializationParams,
|
|
313
376
|
});
|
|
314
377
|
}
|
|
315
378
|
|
|
@@ -329,12 +392,14 @@ class DataModelMigrationChain<
|
|
|
329
392
|
transfer<Id extends string, L>(
|
|
330
393
|
target: TransferTarget<Id & (Id extends keyof Transfers ? never : string), L>,
|
|
331
394
|
extract: (data: Current) => L,
|
|
332
|
-
): DataModelMigrationChain<Current, Transfers & Record<Id, L
|
|
395
|
+
): DataModelMigrationChain<Current, Transfers & Record<Id, L>, Params> {
|
|
333
396
|
const { transferSteps } = this.buildTransfer(target, extract);
|
|
334
|
-
return new DataModelMigrationChain<Current, Transfers & Record<Id, L
|
|
397
|
+
return new DataModelMigrationChain<Current, Transfers & Record<Id, L>, Params>({
|
|
335
398
|
versionChain: this.versionChain,
|
|
336
399
|
steps: this.migrationSteps,
|
|
337
400
|
transferSteps,
|
|
401
|
+
kindRef: this.kindRef,
|
|
402
|
+
parseInitializationParams: this.parseInitializationParams,
|
|
338
403
|
});
|
|
339
404
|
}
|
|
340
405
|
|
|
@@ -361,11 +426,15 @@ class DataModelMigrationChain<
|
|
|
361
426
|
* .migrate<V3>("v3", (v2) => ({ ...v2, description: "" }))
|
|
362
427
|
* .init(() => ({ count: 0, label: "", description: "" }));
|
|
363
428
|
*/
|
|
364
|
-
recover(
|
|
365
|
-
|
|
429
|
+
recover(
|
|
430
|
+
fn: DataRecoverFn<Current>,
|
|
431
|
+
): DataModelMigrationChainWithRecover<Current, Transfers, Params> {
|
|
432
|
+
return new DataModelMigrationChainWithRecover<Current, Transfers, Params>({
|
|
366
433
|
versionChain: this.versionChain,
|
|
367
434
|
steps: this.migrationSteps,
|
|
368
435
|
transferSteps: this.transferSteps,
|
|
436
|
+
kindRef: this.kindRef,
|
|
437
|
+
parseInitializationParams: this.parseInitializationParams,
|
|
369
438
|
recoverFn: fn as (version: DataVersionKey, data: unknown) => unknown,
|
|
370
439
|
recoverFromIndex: this.migrationSteps.length,
|
|
371
440
|
});
|
|
@@ -384,7 +453,8 @@ class DataModelMigrationChain<
|
|
|
384
453
|
class DataModelInitialChain<
|
|
385
454
|
Current,
|
|
386
455
|
Transfers extends Record<string, unknown> = {},
|
|
387
|
-
|
|
456
|
+
Params = never,
|
|
457
|
+
> extends DataModelMigrationChain<Current, Transfers, Params> {
|
|
388
458
|
/**
|
|
389
459
|
* Handle legacy V1 model state ({ args, uiState }) when upgrading a block from
|
|
390
460
|
* BlockModel V1 to BlockModelV3.
|
|
@@ -421,7 +491,7 @@ class DataModelInitialChain<
|
|
|
421
491
|
*/
|
|
422
492
|
upgradeLegacy<Args, UiState = unknown>(
|
|
423
493
|
fn: (legacy: LegacyV1State<Args, UiState>) => Current,
|
|
424
|
-
): DataModelMigrationChainWithRecover<Current, Transfers> {
|
|
494
|
+
): DataModelMigrationChainWithRecover<Current, Transfers, Params> {
|
|
425
495
|
const wrappedFn = (data: unknown): unknown => {
|
|
426
496
|
if (data !== null && typeof data === "object" && "args" in data) {
|
|
427
497
|
return fn(data as LegacyV1State<Args, UiState>);
|
|
@@ -437,9 +507,11 @@ class DataModelInitialChain<
|
|
|
437
507
|
toVersion: initialVersion,
|
|
438
508
|
migrate: wrappedFn,
|
|
439
509
|
};
|
|
440
|
-
return new DataModelMigrationChainWithRecover<Current, Transfers>({
|
|
510
|
+
return new DataModelMigrationChainWithRecover<Current, Transfers, Params>({
|
|
441
511
|
versionChain: [DATA_MODEL_LEGACY_VERSION, ...this.versionChain],
|
|
442
512
|
steps: [step, ...this.migrationSteps],
|
|
513
|
+
kindRef: this.kindRef,
|
|
514
|
+
parseInitializationParams: this.parseInitializationParams,
|
|
443
515
|
// Shift transfer indices to account for the prepended legacy step
|
|
444
516
|
transferSteps: this.transferSteps.map((t) => ({
|
|
445
517
|
...t,
|
|
@@ -495,7 +567,29 @@ class DataModelInitialChain<
|
|
|
495
567
|
* }))
|
|
496
568
|
* .init(() => ({ inputFile: '', selectedTab: 'main' }));
|
|
497
569
|
*/
|
|
498
|
-
export class DataModelBuilder {
|
|
570
|
+
export class DataModelBuilder<Params = never> {
|
|
571
|
+
readonly #kindRef?: BlockKindReference;
|
|
572
|
+
readonly #parseInitializationParams?: (value: unknown) => Params;
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* @param opts.kind - The block kind this data model implements. Its reference
|
|
576
|
+
* is captured and baked into the config so the manifest can advertise which
|
|
577
|
+
* kind the block satisfies, and its `Params` type flows into `.init()`.
|
|
578
|
+
* Optional during the transition window while existing V3 blocks are
|
|
579
|
+
* migrated to kind-carrying builders; a kind-less builder simply carries no
|
|
580
|
+
* reference and the reconciler can't project it yet. Object form mirrors
|
|
581
|
+
* `BlockModelV3.create({ dataModel, kind })`.
|
|
582
|
+
*/
|
|
583
|
+
constructor(opts?: { kind?: BlockKind<Params> }) {
|
|
584
|
+
// Derive the on-wire `{name}@{version}` reference from the compiled kind;
|
|
585
|
+
// the kind object itself has no reference field.
|
|
586
|
+
this.#kindRef = opts?.kind ? formatKindRef(opts.kind) : undefined;
|
|
587
|
+
// Carried alongside the reference, and for the same reason: the kind object is
|
|
588
|
+
// not kept, but two things off it are needed later — how to name the kind, and
|
|
589
|
+
// how to check params claimed to be of it.
|
|
590
|
+
this.#parseInitializationParams = opts?.kind?.parseInitializationParams;
|
|
591
|
+
}
|
|
592
|
+
|
|
499
593
|
/**
|
|
500
594
|
* Start the migration chain with the given initial data type and version key.
|
|
501
595
|
*
|
|
@@ -503,8 +597,14 @@ export class DataModelBuilder {
|
|
|
503
597
|
* @param initialVersion - Version key string (e.g. "v1")
|
|
504
598
|
* @returns Migration chain builder
|
|
505
599
|
*/
|
|
506
|
-
from<T>(initialVersion: string): DataModelInitialChain<T> {
|
|
507
|
-
return new DataModelInitialChain<T>({
|
|
600
|
+
from<T>(initialVersion: string): DataModelInitialChain<T, {}, Params> {
|
|
601
|
+
return new DataModelInitialChain<T, {}, Params>({
|
|
602
|
+
versionChain: [initialVersion],
|
|
603
|
+
kindRef: this.#kindRef,
|
|
604
|
+
parseInitializationParams: this.#parseInitializationParams as
|
|
605
|
+
| ((value: unknown) => unknown)
|
|
606
|
+
| undefined,
|
|
607
|
+
});
|
|
508
608
|
}
|
|
509
609
|
}
|
|
510
610
|
|
|
@@ -527,9 +627,12 @@ export class DataModelBuilder {
|
|
|
527
627
|
* .migrate<V3>("v3", (v2) => ({ ...v2, description: "" }))
|
|
528
628
|
* .init(() => ({ count: 0, label: "", description: "" }));
|
|
529
629
|
*/
|
|
530
|
-
export class DataModel<State, Transfers extends Record<string, unknown> = {}> {
|
|
630
|
+
export class DataModel<State, Params = never, Transfers extends Record<string, unknown> = {}> {
|
|
531
631
|
/** @internal Phantom field to anchor the Transfers type parameter. */
|
|
532
632
|
declare readonly __transfers?: Transfers;
|
|
633
|
+
/** @internal Phantom field to anchor the Params type parameter (drives the
|
|
634
|
+
* compile-time kind cross-check in `BlockModelV3.create`). */
|
|
635
|
+
declare readonly __params?: Params;
|
|
533
636
|
|
|
534
637
|
/** Latest version key — O(1) access for the common "already current" check. */
|
|
535
638
|
private readonly latestVersion: DataVersionKey;
|
|
@@ -537,15 +640,21 @@ export class DataModel<State, Transfers extends Record<string, unknown> = {}> {
|
|
|
537
640
|
private readonly stepsByFromVersion: ReadonlyMap<DataVersionKey, number>;
|
|
538
641
|
private readonly steps: MigrationStep[];
|
|
539
642
|
private readonly transferSteps: TransferStep[];
|
|
540
|
-
private readonly initialDataFn:
|
|
643
|
+
private readonly initialDataFn: DataCreateFn<State, unknown>;
|
|
541
644
|
private readonly recoverFn: (version: DataVersionKey, data: unknown) => unknown;
|
|
542
645
|
private readonly recoverFromIndex: number;
|
|
646
|
+
/** Reference to the block kind this data model was built for, if any. */
|
|
647
|
+
private readonly _kindRef?: BlockKindReference;
|
|
648
|
+
/** The kind's runtime params check, if it declares one. */
|
|
649
|
+
private readonly _parseInitializationParams?: (value: unknown) => unknown;
|
|
543
650
|
|
|
544
651
|
private constructor({
|
|
545
652
|
versionChain,
|
|
546
653
|
steps,
|
|
547
654
|
transferSteps = [],
|
|
548
655
|
initialDataFn,
|
|
656
|
+
kindRef,
|
|
657
|
+
parseInitializationParams,
|
|
549
658
|
recoverFn = defaultRecover,
|
|
550
659
|
recoverFromIndex,
|
|
551
660
|
}: BuilderState<State>) {
|
|
@@ -557,6 +666,8 @@ export class DataModel<State, Transfers extends Record<string, unknown> = {}> {
|
|
|
557
666
|
this.steps = steps;
|
|
558
667
|
this.transferSteps = transferSteps;
|
|
559
668
|
this.initialDataFn = initialDataFn;
|
|
669
|
+
this._kindRef = kindRef;
|
|
670
|
+
this._parseInitializationParams = parseInitializationParams;
|
|
560
671
|
this.recoverFn = recoverFn;
|
|
561
672
|
this.recoverFromIndex = recoverFromIndex ?? steps.length;
|
|
562
673
|
}
|
|
@@ -566,10 +677,31 @@ export class DataModel<State, Transfers extends Record<string, unknown> = {}> {
|
|
|
566
677
|
* Uses Symbol key to prevent external access.
|
|
567
678
|
* @internal
|
|
568
679
|
*/
|
|
569
|
-
static [FROM_BUILDER]<S, T extends Record<string, unknown> = {}>(
|
|
680
|
+
static [FROM_BUILDER]<S, P = never, T extends Record<string, unknown> = {}>(
|
|
570
681
|
state: BuilderState<S>,
|
|
571
|
-
): DataModel<S, T> {
|
|
572
|
-
return new DataModel<S, T>(state);
|
|
682
|
+
): DataModel<S, P, T> {
|
|
683
|
+
return new DataModel<S, P, T>(state);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Reference to the block kind this data model was built for, or `undefined`
|
|
688
|
+
* for a kind-less builder. Used by `BlockModelV3.create` to cross-check that
|
|
689
|
+
* the kind handed to the builder matches the kind handed to `create`.
|
|
690
|
+
* @internal
|
|
691
|
+
*/
|
|
692
|
+
get kindRef(): BlockKindReference | undefined {
|
|
693
|
+
return this._kindRef;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* The kind's runtime params check, or `undefined` if the kind declares none (or
|
|
698
|
+
* there is no kind). Read by `BlockModelV3.done()` to register the check, and
|
|
699
|
+
* carried here rather than only on the model because `init` — the one place params
|
|
700
|
+
* are consumed — lives on this side.
|
|
701
|
+
* @internal
|
|
702
|
+
*/
|
|
703
|
+
get templateParamsParser(): ((value: unknown) => unknown) | undefined {
|
|
704
|
+
return this._parseInitializationParams;
|
|
573
705
|
}
|
|
574
706
|
|
|
575
707
|
/**
|
|
@@ -583,7 +715,7 @@ export class DataModel<State, Transfers extends Record<string, unknown> = {}> {
|
|
|
583
715
|
* Get a fresh copy of the initial data.
|
|
584
716
|
*/
|
|
585
717
|
initialData(): State {
|
|
586
|
-
return this.initialDataFn();
|
|
718
|
+
return this.initialDataFn({});
|
|
587
719
|
}
|
|
588
720
|
|
|
589
721
|
/**
|
|
@@ -591,7 +723,25 @@ export class DataModel<State, Transfers extends Record<string, unknown> = {}> {
|
|
|
591
723
|
* Used when creating new blocks or resetting to defaults.
|
|
592
724
|
*/
|
|
593
725
|
getDefaultData(): DataVersioned<State> {
|
|
594
|
-
return makeVersionedData(this.latestVersion, this.initialDataFn());
|
|
726
|
+
return makeVersionedData(this.latestVersion, this.initialDataFn({}));
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Get initial data built from params, wrapped with current version.
|
|
731
|
+
*
|
|
732
|
+
* The counterpart of {@link getDefaultData} for a block created from a template
|
|
733
|
+
* entry: the factory receives the entry's params instead of nothing. A factory
|
|
734
|
+
* that ignores its argument produces the same result as `getDefaultData`, which
|
|
735
|
+
* is why the two are separate methods rather than one optional argument — the
|
|
736
|
+
* caller decides which contract it is asking for, and a block that cannot honour
|
|
737
|
+
* params must not silently look like one that can.
|
|
738
|
+
*
|
|
739
|
+
* References inside `params` are already resolved to the target project's
|
|
740
|
+
* concrete ids by the time they get here; the factory never sees a
|
|
741
|
+
* template-local one.
|
|
742
|
+
*/
|
|
743
|
+
getDataFromParams(params: unknown): DataVersioned<State> {
|
|
744
|
+
return makeVersionedData(this.latestVersion, this.initialDataFn({ params }));
|
|
595
745
|
}
|
|
596
746
|
|
|
597
747
|
private recoverFrom(data: unknown, version: DataVersionKey): DataVersioned<State> {
|