@routevn/creator-model 1.2.7 → 1.2.9

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/README.md CHANGED
@@ -42,6 +42,11 @@ processCommand({
42
42
  state,
43
43
  command: { type, payload },
44
44
  });
45
+
46
+ replayCommands({
47
+ state,
48
+ commands: [{ type, payload }],
49
+ });
45
50
  ```
46
51
 
47
52
  `SCHEMA_VERSION` is the exported schema version constant for persisted command
@@ -76,6 +81,12 @@ or:
76
81
  { valid: true, state: nextState }
77
82
  ```
78
83
 
84
+ `replayCommands()` returns the same result shape while applying a trusted
85
+ command tape against a single working state clone. It is intended for batch
86
+ history reconstruction paths such as offline repository boot/import replay,
87
+ where validating the full state before and after every individual command is
88
+ needlessly expensive.
89
+
79
90
  Design rules:
80
91
 
81
92
  - no classes
@@ -86,6 +97,7 @@ Design rules:
86
97
  - patch releases must not change persisted schema compatibility
87
98
  - `bun run test:compat` is the required compatibility gate for model changes
88
99
  - `processCommand()` is the authoritative state transition
100
+ - `replayCommands()` is the fast batch replay path for trusted command tapes
89
101
  - model state should contain project-owned runtime data only
90
102
  - app-owned metadata like project id, name, and description should stay out of
91
103
  this package
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routevn/creator-model",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export {
2
+ replayCommands,
2
3
  SCHEMA_VERSION,
3
4
  processCommand,
4
5
  validateAgainstState,
package/src/model.js CHANGED
@@ -779,8 +779,6 @@ const validateImageItems = ({ items, path, errorFactory }) => {
779
779
  "description",
780
780
  "thumbnailFileId",
781
781
  "fileId",
782
- "fileType",
783
- "fileSize",
784
782
  "width",
785
783
  "height",
786
784
  ],
@@ -838,20 +836,6 @@ const validateImageItems = ({ items, path, errorFactory }) => {
838
836
  );
839
837
  }
840
838
 
841
- if (item.fileType !== undefined && !isString(item.fileType)) {
842
- return invalidFromErrorFactory(
843
- errorFactory,
844
- `${itemPath}.fileType must be a string when provided`,
845
- );
846
- }
847
-
848
- if (item.fileSize !== undefined && !isFiniteNumber(item.fileSize)) {
849
- return invalidFromErrorFactory(
850
- errorFactory,
851
- `${itemPath}.fileSize must be a finite number`,
852
- );
853
- }
854
-
855
839
  if (item.width !== undefined && !isFiniteNumber(item.width)) {
856
840
  return invalidFromErrorFactory(
857
841
  errorFactory,
@@ -962,8 +946,6 @@ const validateSpritesheetItems = ({ items, path, errorFactory }) => {
962
946
  "description",
963
947
  "thumbnailFileId",
964
948
  "fileId",
965
- "fileType",
966
- "fileSize",
967
949
  "sheetWidth",
968
950
  "sheetHeight",
969
951
  "frameCount",
@@ -1026,15 +1008,7 @@ const validateSpritesheetItems = ({ items, path, errorFactory }) => {
1026
1008
  );
1027
1009
  }
1028
1010
 
1029
- if (item.fileType !== undefined && !isString(item.fileType)) {
1030
- return invalidFromErrorFactory(
1031
- errorFactory,
1032
- `${itemPath}.fileType must be a string when provided`,
1033
- );
1034
- }
1035
-
1036
1011
  for (const key of [
1037
- "fileSize",
1038
1012
  "sheetWidth",
1039
1013
  "sheetHeight",
1040
1014
  "frameCount",
@@ -1093,8 +1067,6 @@ const validateSoundItems = ({ items, path, errorFactory }) => {
1093
1067
  "name",
1094
1068
  "description",
1095
1069
  "fileId",
1096
- "fileType",
1097
- "fileSize",
1098
1070
  "waveformDataFileId",
1099
1071
  "duration",
1100
1072
  ],
@@ -1142,20 +1114,6 @@ const validateSoundItems = ({ items, path, errorFactory }) => {
1142
1114
  );
1143
1115
  }
1144
1116
 
1145
- if (item.fileType !== undefined && !isString(item.fileType)) {
1146
- return invalidFromErrorFactory(
1147
- errorFactory,
1148
- `${itemPath}.fileType must be a string when provided`,
1149
- );
1150
- }
1151
-
1152
- if (item.fileSize !== undefined && !isFiniteNumber(item.fileSize)) {
1153
- return invalidFromErrorFactory(
1154
- errorFactory,
1155
- `${itemPath}.fileSize must be a finite number`,
1156
- );
1157
- }
1158
-
1159
1117
  if (
1160
1118
  item.waveformDataFileId !== undefined &&
1161
1119
  item.waveformDataFileId !== null &&
@@ -1201,8 +1159,6 @@ const validateVideoItems = ({ items, path, errorFactory }) => {
1201
1159
  "description",
1202
1160
  "fileId",
1203
1161
  "thumbnailFileId",
1204
- "fileType",
1205
- "fileSize",
1206
1162
  "duration",
1207
1163
  "width",
1208
1164
  "height",
@@ -1258,20 +1214,6 @@ const validateVideoItems = ({ items, path, errorFactory }) => {
1258
1214
  );
1259
1215
  }
1260
1216
 
1261
- if (item.fileType !== undefined && !isString(item.fileType)) {
1262
- return invalidFromErrorFactory(
1263
- errorFactory,
1264
- `${itemPath}.fileType must be a string when provided`,
1265
- );
1266
- }
1267
-
1268
- if (item.fileSize !== undefined && !isFiniteNumber(item.fileSize)) {
1269
- return invalidFromErrorFactory(
1270
- errorFactory,
1271
- `${itemPath}.fileSize must be a finite number`,
1272
- );
1273
- }
1274
-
1275
1217
  if (item.duration !== undefined && !isFiniteNumber(item.duration)) {
1276
1218
  return invalidFromErrorFactory(
1277
1219
  errorFactory,
@@ -1998,8 +1940,6 @@ const validateFontItems = ({ items, path, errorFactory }) => {
1998
1940
  "description",
1999
1941
  "fileId",
2000
1942
  "fontFamily",
2001
- "fileType",
2002
- "fileSize",
2003
1943
  ],
2004
1944
  path: itemPath,
2005
1945
  errorFactory,
@@ -2052,19 +1992,6 @@ const validateFontItems = ({ items, path, errorFactory }) => {
2052
1992
  );
2053
1993
  }
2054
1994
 
2055
- if (item.fileType !== undefined && !isString(item.fileType)) {
2056
- return invalidFromErrorFactory(
2057
- errorFactory,
2058
- `${itemPath}.fileType must be a string when provided`,
2059
- );
2060
- }
2061
-
2062
- if (item.fileSize !== undefined && !isFiniteNumber(item.fileSize)) {
2063
- return invalidFromErrorFactory(
2064
- errorFactory,
2065
- `${itemPath}.fileSize must be a finite number`,
2066
- );
2067
- }
2068
1995
  }
2069
1996
  }
2070
1997
  };
@@ -2687,8 +2614,6 @@ const validateCharacterSpriteItems = ({ items, path, errorFactory }) => {
2687
2614
  "description",
2688
2615
  "thumbnailFileId",
2689
2616
  "fileId",
2690
- "fileType",
2691
- "fileSize",
2692
2617
  "width",
2693
2618
  "height",
2694
2619
  ],
@@ -2746,20 +2671,6 @@ const validateCharacterSpriteItems = ({ items, path, errorFactory }) => {
2746
2671
  );
2747
2672
  }
2748
2673
 
2749
- if (item.fileType !== undefined && !isString(item.fileType)) {
2750
- return invalidFromErrorFactory(
2751
- errorFactory,
2752
- `${itemPath}.fileType must be a string when provided`,
2753
- );
2754
- }
2755
-
2756
- if (item.fileSize !== undefined && !isFiniteNumber(item.fileSize)) {
2757
- return invalidFromErrorFactory(
2758
- errorFactory,
2759
- `${itemPath}.fileSize must be a finite number when provided`,
2760
- );
2761
- }
2762
-
2763
2674
  if (item.width !== undefined && !isFiniteNumber(item.width)) {
2764
2675
  return invalidFromErrorFactory(
2765
2676
  errorFactory,
@@ -3540,8 +3451,6 @@ const validateCharacterItems = ({ items, path, errorFactory }) => {
3540
3451
  "description",
3541
3452
  "shortcut",
3542
3453
  "fileId",
3543
- "fileType",
3544
- "fileSize",
3545
3454
  "sprites",
3546
3455
  ],
3547
3456
  path: itemPath,
@@ -3595,20 +3504,6 @@ const validateCharacterItems = ({ items, path, errorFactory }) => {
3595
3504
  );
3596
3505
  }
3597
3506
 
3598
- if (item.fileType !== undefined && !isString(item.fileType)) {
3599
- return invalidFromErrorFactory(
3600
- errorFactory,
3601
- `${itemPath}.fileType must be a string when provided`,
3602
- );
3603
- }
3604
-
3605
- if (item.fileSize !== undefined && !isFiniteNumber(item.fileSize)) {
3606
- return invalidFromErrorFactory(
3607
- errorFactory,
3608
- `${itemPath}.fileSize must be a finite number when provided`,
3609
- );
3610
- }
3611
-
3612
3507
  {
3613
3508
  const result = validateNestedCollection({
3614
3509
  collection: item.sprites,
@@ -5966,8 +5861,6 @@ const validateImageCreateData = ({ data, errorFactory }) => {
5966
5861
  "description",
5967
5862
  "thumbnailFileId",
5968
5863
  "fileId",
5969
- "fileType",
5970
- "fileSize",
5971
5864
  "width",
5972
5865
  "height",
5973
5866
  ],
@@ -6011,20 +5904,6 @@ const validateImageCreateData = ({ data, errorFactory }) => {
6011
5904
  );
6012
5905
  }
6013
5906
 
6014
- if (data.fileType !== undefined && !isString(data.fileType)) {
6015
- return invalidFromErrorFactory(
6016
- errorFactory,
6017
- "payload.data.fileType must be a string when provided",
6018
- );
6019
- }
6020
-
6021
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6022
- return invalidFromErrorFactory(
6023
- errorFactory,
6024
- "payload.data.fileSize must be a finite number",
6025
- );
6026
- }
6027
-
6028
5907
  if (data.width !== undefined && !isFiniteNumber(data.width)) {
6029
5908
  return invalidFromErrorFactory(
6030
5909
  errorFactory,
@@ -6050,8 +5929,6 @@ const validateImageUpdateData = ({ data, errorFactory }) => {
6050
5929
  "description",
6051
5930
  "thumbnailFileId",
6052
5931
  "fileId",
6053
- "fileType",
6054
- "fileSize",
6055
5932
  "width",
6056
5933
  "height",
6057
5934
  ],
@@ -6101,20 +5978,6 @@ const validateImageUpdateData = ({ data, errorFactory }) => {
6101
5978
  );
6102
5979
  }
6103
5980
 
6104
- if (data.fileType !== undefined && !isString(data.fileType)) {
6105
- return invalidFromErrorFactory(
6106
- errorFactory,
6107
- "payload.data.fileType must be a string when provided",
6108
- );
6109
- }
6110
-
6111
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6112
- return invalidFromErrorFactory(
6113
- errorFactory,
6114
- "payload.data.fileSize must be a finite number",
6115
- );
6116
- }
6117
-
6118
5981
  if (data.width !== undefined && !isFiniteNumber(data.width)) {
6119
5982
  return invalidFromErrorFactory(
6120
5983
  errorFactory,
@@ -6157,8 +6020,6 @@ const validateSpritesheetCreateData = ({ data, errorFactory }) => {
6157
6020
  "description",
6158
6021
  "thumbnailFileId",
6159
6022
  "fileId",
6160
- "fileType",
6161
- "fileSize",
6162
6023
  "sheetWidth",
6163
6024
  "sheetHeight",
6164
6025
  "frameCount",
@@ -6207,15 +6068,7 @@ const validateSpritesheetCreateData = ({ data, errorFactory }) => {
6207
6068
  );
6208
6069
  }
6209
6070
 
6210
- if (data.fileType !== undefined && !isString(data.fileType)) {
6211
- return invalidFromErrorFactory(
6212
- errorFactory,
6213
- "payload.data.fileType must be a string when provided",
6214
- );
6215
- }
6216
-
6217
6071
  for (const key of [
6218
- "fileSize",
6219
6072
  "sheetWidth",
6220
6073
  "sheetHeight",
6221
6074
  "frameCount",
@@ -6259,8 +6112,6 @@ const validateSpritesheetUpdateData = ({ data, errorFactory }) => {
6259
6112
  "description",
6260
6113
  "thumbnailFileId",
6261
6114
  "fileId",
6262
- "fileType",
6263
- "fileSize",
6264
6115
  "sheetWidth",
6265
6116
  "sheetHeight",
6266
6117
  "frameCount",
@@ -6315,15 +6166,7 @@ const validateSpritesheetUpdateData = ({ data, errorFactory }) => {
6315
6166
  );
6316
6167
  }
6317
6168
 
6318
- if (data.fileType !== undefined && !isString(data.fileType)) {
6319
- return invalidFromErrorFactory(
6320
- errorFactory,
6321
- "payload.data.fileType must be a string when provided",
6322
- );
6323
- }
6324
-
6325
6169
  for (const key of [
6326
- "fileSize",
6327
6170
  "sheetWidth",
6328
6171
  "sheetHeight",
6329
6172
  "frameCount",
@@ -6383,8 +6226,6 @@ const validateSoundCreateData = ({ data, errorFactory }) => {
6383
6226
  "name",
6384
6227
  "description",
6385
6228
  "fileId",
6386
- "fileType",
6387
- "fileSize",
6388
6229
  "waveformDataFileId",
6389
6230
  "duration",
6390
6231
  ],
@@ -6418,20 +6259,6 @@ const validateSoundCreateData = ({ data, errorFactory }) => {
6418
6259
  );
6419
6260
  }
6420
6261
 
6421
- if (data.fileType !== undefined && !isString(data.fileType)) {
6422
- return invalidFromErrorFactory(
6423
- errorFactory,
6424
- "payload.data.fileType must be a string when provided",
6425
- );
6426
- }
6427
-
6428
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6429
- return invalidFromErrorFactory(
6430
- errorFactory,
6431
- "payload.data.fileSize must be a finite number",
6432
- );
6433
- }
6434
-
6435
6262
  if (
6436
6263
  data.waveformDataFileId !== undefined &&
6437
6264
  data.waveformDataFileId !== null &&
@@ -6460,8 +6287,6 @@ const validateSoundUpdateData = ({ data, errorFactory }) => {
6460
6287
  "name",
6461
6288
  "description",
6462
6289
  "fileId",
6463
- "fileType",
6464
- "fileSize",
6465
6290
  "waveformDataFileId",
6466
6291
  "duration",
6467
6292
  ],
@@ -6501,20 +6326,6 @@ const validateSoundUpdateData = ({ data, errorFactory }) => {
6501
6326
  );
6502
6327
  }
6503
6328
 
6504
- if (data.fileType !== undefined && !isString(data.fileType)) {
6505
- return invalidFromErrorFactory(
6506
- errorFactory,
6507
- "payload.data.fileType must be a string when provided",
6508
- );
6509
- }
6510
-
6511
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6512
- return invalidFromErrorFactory(
6513
- errorFactory,
6514
- "payload.data.fileSize must be a finite number",
6515
- );
6516
- }
6517
-
6518
6329
  if (
6519
6330
  data.waveformDataFileId !== undefined &&
6520
6331
  data.waveformDataFileId !== null &&
@@ -6561,8 +6372,6 @@ const validateVideoCreateData = ({ data, errorFactory }) => {
6561
6372
  "description",
6562
6373
  "fileId",
6563
6374
  "thumbnailFileId",
6564
- "fileType",
6565
- "fileSize",
6566
6375
  "duration",
6567
6376
  "width",
6568
6377
  "height",
@@ -6604,20 +6413,6 @@ const validateVideoCreateData = ({ data, errorFactory }) => {
6604
6413
  );
6605
6414
  }
6606
6415
 
6607
- if (data.fileType !== undefined && !isString(data.fileType)) {
6608
- return invalidFromErrorFactory(
6609
- errorFactory,
6610
- "payload.data.fileType must be a string when provided",
6611
- );
6612
- }
6613
-
6614
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6615
- return invalidFromErrorFactory(
6616
- errorFactory,
6617
- "payload.data.fileSize must be a finite number",
6618
- );
6619
- }
6620
-
6621
6416
  if (data.duration !== undefined && !isFiniteNumber(data.duration)) {
6622
6417
  return invalidFromErrorFactory(
6623
6418
  errorFactory,
@@ -6650,8 +6445,6 @@ const validateVideoUpdateData = ({ data, errorFactory }) => {
6650
6445
  "description",
6651
6446
  "fileId",
6652
6447
  "thumbnailFileId",
6653
- "fileType",
6654
- "fileSize",
6655
6448
  "duration",
6656
6449
  "width",
6657
6450
  "height",
@@ -6702,20 +6495,6 @@ const validateVideoUpdateData = ({ data, errorFactory }) => {
6702
6495
  );
6703
6496
  }
6704
6497
 
6705
- if (data.fileType !== undefined && !isString(data.fileType)) {
6706
- return invalidFromErrorFactory(
6707
- errorFactory,
6708
- "payload.data.fileType must be a string when provided",
6709
- );
6710
- }
6711
-
6712
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6713
- return invalidFromErrorFactory(
6714
- errorFactory,
6715
- "payload.data.fileSize must be a finite number",
6716
- );
6717
- }
6718
-
6719
6498
  if (data.duration !== undefined && !isFiniteNumber(data.duration)) {
6720
6499
  return invalidFromErrorFactory(
6721
6500
  errorFactory,
@@ -6765,8 +6544,6 @@ const validateFontCreateData = ({ data, errorFactory }) => {
6765
6544
  "description",
6766
6545
  "fileId",
6767
6546
  "fontFamily",
6768
- "fileType",
6769
- "fileSize",
6770
6547
  ],
6771
6548
  path: "payload.data",
6772
6549
  errorFactory,
@@ -6805,19 +6582,6 @@ const validateFontCreateData = ({ data, errorFactory }) => {
6805
6582
  );
6806
6583
  }
6807
6584
 
6808
- if (data.fileType !== undefined && !isString(data.fileType)) {
6809
- return invalidFromErrorFactory(
6810
- errorFactory,
6811
- "payload.data.fileType must be a string when provided",
6812
- );
6813
- }
6814
-
6815
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6816
- return invalidFromErrorFactory(
6817
- errorFactory,
6818
- "payload.data.fileSize must be a finite number",
6819
- );
6820
- }
6821
6585
  }
6822
6586
  };
6823
6587
 
@@ -6830,8 +6594,6 @@ const validateFontUpdateData = ({ data, errorFactory }) => {
6830
6594
  "description",
6831
6595
  "fileId",
6832
6596
  "fontFamily",
6833
- "fileType",
6834
- "fileSize",
6835
6597
  ],
6836
6598
  path: "payload.data",
6837
6599
  errorFactory,
@@ -6876,19 +6638,6 @@ const validateFontUpdateData = ({ data, errorFactory }) => {
6876
6638
  );
6877
6639
  }
6878
6640
 
6879
- if (data.fileType !== undefined && !isString(data.fileType)) {
6880
- return invalidFromErrorFactory(
6881
- errorFactory,
6882
- "payload.data.fileType must be a string when provided",
6883
- );
6884
- }
6885
-
6886
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
6887
- return invalidFromErrorFactory(
6888
- errorFactory,
6889
- "payload.data.fileSize must be a finite number",
6890
- );
6891
- }
6892
6641
  };
6893
6642
 
6894
6643
  const validateFileCreateData = ({ data, errorFactory }) => {
@@ -7844,8 +7593,6 @@ const validateCharacterSpriteCreateData = ({ data, errorFactory }) => {
7844
7593
  "description",
7845
7594
  "fileId",
7846
7595
  "thumbnailFileId",
7847
- "fileType",
7848
- "fileSize",
7849
7596
  "width",
7850
7597
  "height",
7851
7598
  ],
@@ -7889,20 +7636,6 @@ const validateCharacterSpriteCreateData = ({ data, errorFactory }) => {
7889
7636
  );
7890
7637
  }
7891
7638
 
7892
- if (data.fileType !== undefined && !isString(data.fileType)) {
7893
- return invalidFromErrorFactory(
7894
- errorFactory,
7895
- "payload.data.fileType must be a string when provided",
7896
- );
7897
- }
7898
-
7899
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
7900
- return invalidFromErrorFactory(
7901
- errorFactory,
7902
- "payload.data.fileSize must be a finite number when provided",
7903
- );
7904
- }
7905
-
7906
7639
  if (data.width !== undefined && !isFiniteNumber(data.width)) {
7907
7640
  return invalidFromErrorFactory(
7908
7641
  errorFactory,
@@ -7928,8 +7661,6 @@ const validateCharacterSpriteUpdateData = ({ data, errorFactory }) => {
7928
7661
  "description",
7929
7662
  "fileId",
7930
7663
  "thumbnailFileId",
7931
- "fileType",
7932
- "fileSize",
7933
7664
  "width",
7934
7665
  "height",
7935
7666
  ],
@@ -7979,20 +7710,6 @@ const validateCharacterSpriteUpdateData = ({ data, errorFactory }) => {
7979
7710
  );
7980
7711
  }
7981
7712
 
7982
- if (data.fileType !== undefined && !isString(data.fileType)) {
7983
- return invalidFromErrorFactory(
7984
- errorFactory,
7985
- "payload.data.fileType must be a string when provided",
7986
- );
7987
- }
7988
-
7989
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
7990
- return invalidFromErrorFactory(
7991
- errorFactory,
7992
- "payload.data.fileSize must be a finite number when provided",
7993
- );
7994
- }
7995
-
7996
7713
  if (data.width !== undefined && !isFiniteNumber(data.width)) {
7997
7714
  return invalidFromErrorFactory(
7998
7715
  errorFactory,
@@ -8035,8 +7752,6 @@ const validateCharacterCreateData = ({ data, errorFactory }) => {
8035
7752
  "description",
8036
7753
  "shortcut",
8037
7754
  "fileId",
8038
- "fileType",
8039
- "fileSize",
8040
7755
  "sprites",
8041
7756
  ],
8042
7757
  path: "payload.data",
@@ -8076,20 +7791,6 @@ const validateCharacterCreateData = ({ data, errorFactory }) => {
8076
7791
  );
8077
7792
  }
8078
7793
 
8079
- if (data.fileType !== undefined && !isString(data.fileType)) {
8080
- return invalidFromErrorFactory(
8081
- errorFactory,
8082
- "payload.data.fileType must be a string when provided",
8083
- );
8084
- }
8085
-
8086
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
8087
- return invalidFromErrorFactory(
8088
- errorFactory,
8089
- "payload.data.fileSize must be a finite number when provided",
8090
- );
8091
- }
8092
-
8093
7794
  if (data.sprites !== undefined) {
8094
7795
  {
8095
7796
  const result = validateNestedCollection({
@@ -8117,8 +7818,6 @@ const validateCharacterUpdateData = ({ data, errorFactory }) => {
8117
7818
  "description",
8118
7819
  "shortcut",
8119
7820
  "fileId",
8120
- "fileType",
8121
- "fileSize",
8122
7821
  ],
8123
7822
  path: "payload.data",
8124
7823
  errorFactory,
@@ -8163,19 +7862,6 @@ const validateCharacterUpdateData = ({ data, errorFactory }) => {
8163
7862
  );
8164
7863
  }
8165
7864
 
8166
- if (data.fileType !== undefined && !isString(data.fileType)) {
8167
- return invalidFromErrorFactory(
8168
- errorFactory,
8169
- "payload.data.fileType must be a string when provided",
8170
- );
8171
- }
8172
-
8173
- if (data.fileSize !== undefined && !isFiniteNumber(data.fileSize)) {
8174
- return invalidFromErrorFactory(
8175
- errorFactory,
8176
- "payload.data.fileSize must be a finite number when provided",
8177
- );
8178
- }
8179
7865
  };
8180
7866
 
8181
7867
  const validateLayoutCreateData = ({ data, errorFactory }) => {
@@ -9684,16 +9370,6 @@ const COMMAND_DEFINITIONS = [
9684
9370
  thumbnailFileId: payload.data.thumbnailFileId,
9685
9371
  }
9686
9372
  : {}),
9687
- ...(payload.data.fileType !== undefined
9688
- ? {
9689
- fileType: payload.data.fileType,
9690
- }
9691
- : {}),
9692
- ...(payload.data.fileSize !== undefined
9693
- ? {
9694
- fileSize: payload.data.fileSize,
9695
- }
9696
- : {}),
9697
9373
  ...(payload.data.sheetWidth !== undefined
9698
9374
  ? {
9699
9375
  sheetWidth: payload.data.sheetWidth,
@@ -11117,12 +10793,6 @@ const COMMAND_DEFINITIONS = [
11117
10793
  if (payload.data.thumbnailFileId !== undefined) {
11118
10794
  nextImage.thumbnailFileId = payload.data.thumbnailFileId;
11119
10795
  }
11120
- if (payload.data.fileType !== undefined) {
11121
- nextImage.fileType = payload.data.fileType;
11122
- }
11123
- if (payload.data.fileSize !== undefined) {
11124
- nextImage.fileSize = payload.data.fileSize;
11125
- }
11126
10796
  if (payload.data.width !== undefined) {
11127
10797
  nextImage.width = payload.data.width;
11128
10798
  }
@@ -11189,8 +10859,6 @@ const COMMAND_DEFINITIONS = [
11189
10859
  currentImage.type === "folder" &&
11190
10860
  (payload.data.fileId !== undefined ||
11191
10861
  payload.data.thumbnailFileId !== undefined ||
11192
- payload.data.fileType !== undefined ||
11193
- payload.data.fileSize !== undefined ||
11194
10862
  payload.data.width !== undefined ||
11195
10863
  payload.data.height !== undefined)
11196
10864
  ) {
@@ -11539,12 +11207,6 @@ const COMMAND_DEFINITIONS = [
11539
11207
 
11540
11208
  if (payload.data.type === "sound") {
11541
11209
  nextSound.fileId = payload.data.fileId;
11542
- if (payload.data.fileType !== undefined) {
11543
- nextSound.fileType = payload.data.fileType;
11544
- }
11545
- if (payload.data.fileSize !== undefined) {
11546
- nextSound.fileSize = payload.data.fileSize;
11547
- }
11548
11210
  if (payload.data.waveformDataFileId !== undefined) {
11549
11211
  nextSound.waveformDataFileId = payload.data.waveformDataFileId;
11550
11212
  }
@@ -11610,8 +11272,6 @@ const COMMAND_DEFINITIONS = [
11610
11272
  if (
11611
11273
  currentSound.type === "folder" &&
11612
11274
  (payload.data.fileId !== undefined ||
11613
- payload.data.fileType !== undefined ||
11614
- payload.data.fileSize !== undefined ||
11615
11275
  payload.data.waveformDataFileId !== undefined ||
11616
11276
  payload.data.duration !== undefined)
11617
11277
  ) {
@@ -11961,12 +11621,6 @@ const COMMAND_DEFINITIONS = [
11961
11621
  if (payload.data.type === "video") {
11962
11622
  nextVideo.fileId = payload.data.fileId;
11963
11623
  nextVideo.thumbnailFileId = payload.data.thumbnailFileId;
11964
- if (payload.data.fileType !== undefined) {
11965
- nextVideo.fileType = payload.data.fileType;
11966
- }
11967
- if (payload.data.fileSize !== undefined) {
11968
- nextVideo.fileSize = payload.data.fileSize;
11969
- }
11970
11624
  if (payload.data.duration !== undefined) {
11971
11625
  nextVideo.duration = payload.data.duration;
11972
11626
  }
@@ -12036,8 +11690,6 @@ const COMMAND_DEFINITIONS = [
12036
11690
  currentVideo.type === "folder" &&
12037
11691
  (payload.data.fileId !== undefined ||
12038
11692
  payload.data.thumbnailFileId !== undefined ||
12039
- payload.data.fileType !== undefined ||
12040
- payload.data.fileSize !== undefined ||
12041
11693
  payload.data.duration !== undefined ||
12042
11694
  payload.data.width !== undefined ||
12043
11695
  payload.data.height !== undefined)
@@ -12791,12 +12443,6 @@ const COMMAND_DEFINITIONS = [
12791
12443
  if (payload.data.type === "font") {
12792
12444
  nextFont.fileId = payload.data.fileId;
12793
12445
  nextFont.fontFamily = payload.data.fontFamily;
12794
- if (payload.data.fileType !== undefined) {
12795
- nextFont.fileType = payload.data.fileType;
12796
- }
12797
- if (payload.data.fileSize !== undefined) {
12798
- nextFont.fileSize = payload.data.fileSize;
12799
- }
12800
12446
  }
12801
12447
 
12802
12448
  state.fonts.items[payload.fontId] = nextFont;
@@ -12856,9 +12502,7 @@ const COMMAND_DEFINITIONS = [
12856
12502
  if (
12857
12503
  currentFont.type === "folder" &&
12858
12504
  (payload.data.fileId !== undefined ||
12859
- payload.data.fontFamily !== undefined ||
12860
- payload.data.fileType !== undefined ||
12861
- payload.data.fileSize !== undefined)
12505
+ payload.data.fontFamily !== undefined)
12862
12506
  ) {
12863
12507
  return invalidPrecondition(
12864
12508
  "folder font items cannot update font fields",
@@ -13707,14 +13351,6 @@ const COMMAND_DEFINITIONS = [
13707
13351
  item.fileId = payload.data.fileId;
13708
13352
  }
13709
13353
 
13710
- if (payload.data.fileType !== undefined) {
13711
- item.fileType = payload.data.fileType;
13712
- }
13713
-
13714
- if (payload.data.fileSize !== undefined) {
13715
- item.fileSize = payload.data.fileSize;
13716
- }
13717
-
13718
13354
  item.sprites =
13719
13355
  payload.data.sprites === undefined
13720
13356
  ? { items: {}, tree: [] }
@@ -15478,50 +15114,118 @@ export const validatePayload = ({ type, payload }) => {
15478
15114
  });
15479
15115
  };
15480
15116
 
15117
+ const normalizeCurrentStateValidationResult = (stateResult) => {
15118
+ if (stateResult.valid) {
15119
+ return stateResult;
15120
+ }
15121
+
15122
+ if (stateResult.error.kind === "invariant") {
15123
+ return invalidInvariant(
15124
+ stateResult.error.message,
15125
+ toDomainErrorDetails(stateResult.error),
15126
+ );
15127
+ }
15128
+
15129
+ return invalidState(
15130
+ stateResult.error.message,
15131
+ toDomainErrorDetails(stateResult.error),
15132
+ );
15133
+ };
15134
+
15135
+ const validateCommandDefinitionAgainstState = ({ state, command }) => {
15136
+ if (!isPlainObject(command)) {
15137
+ return invalidPrecondition("command must be an object");
15138
+ }
15139
+
15140
+ const payloadResult = validatePayload(command);
15141
+ if (!payloadResult.valid) {
15142
+ return invalidPayload(
15143
+ payloadResult.error.message,
15144
+ toDomainErrorDetails(payloadResult.error),
15145
+ );
15146
+ }
15147
+
15148
+ const definition = getCommandDefinition({ type: command.type });
15149
+ if (!definition) {
15150
+ return invalidPrecondition(`unknown command type '${command.type}'`);
15151
+ }
15152
+
15153
+ const validationResult = captureValidation(() =>
15154
+ definition.validateAgainstState({
15155
+ state,
15156
+ payload: command.payload,
15157
+ }),
15158
+ );
15159
+ const normalizedValidationResult = normalizeStateResult(validationResult);
15160
+ if (!normalizedValidationResult.valid) {
15161
+ return normalizedValidationResult;
15162
+ }
15163
+
15164
+ return {
15165
+ valid: true,
15166
+ definition,
15167
+ };
15168
+ };
15169
+
15170
+ const applyCommandDefinition = ({ state, definition, payload }) => {
15171
+ const nextState = definition.reduce({
15172
+ state,
15173
+ payload,
15174
+ });
15175
+ if (nextState?.valid === false) {
15176
+ return nextState;
15177
+ }
15178
+
15179
+ return {
15180
+ valid: true,
15181
+ state: nextState === undefined ? state : nextState,
15182
+ };
15183
+ };
15184
+
15185
+ const appendReplayCommandContext = (result, { commandIndex, command } = {}) => {
15186
+ if (result?.valid !== false || !result.error) {
15187
+ return result;
15188
+ }
15189
+
15190
+ const details = isPlainObject(result.error.details)
15191
+ ? structuredClone(result.error.details)
15192
+ : {};
15193
+
15194
+ if (Number.isInteger(commandIndex) && commandIndex >= 0) {
15195
+ details.commandIndex = commandIndex;
15196
+ }
15197
+
15198
+ if (isNonEmptyString(command?.type)) {
15199
+ details.commandType = command.type;
15200
+ }
15201
+
15202
+ return {
15203
+ valid: false,
15204
+ error: {
15205
+ ...result.error,
15206
+ details,
15207
+ },
15208
+ };
15209
+ };
15210
+
15481
15211
  export const validateAgainstState = ({ state, command }) => {
15482
15212
  return captureValidation(() => {
15483
15213
  const normalizedState = normalizeStateCollections(state);
15484
15214
 
15485
- if (!isPlainObject(command)) {
15486
- return invalidPrecondition("command must be an object");
15487
- }
15488
-
15489
- const payloadResult = validatePayload(command);
15490
- if (!payloadResult.valid) {
15491
- return invalidPayload(
15492
- payloadResult.error.message,
15493
- toDomainErrorDetails(payloadResult.error),
15494
- );
15495
- }
15496
-
15497
15215
  const stateResult = validateState({ state: normalizedState });
15498
15216
  if (!stateResult.valid) {
15499
- if (stateResult.error.kind === "invariant") {
15500
- return invalidInvariant(
15501
- stateResult.error.message,
15502
- toDomainErrorDetails(stateResult.error),
15503
- );
15504
- }
15505
-
15506
- return invalidState(
15507
- stateResult.error.message,
15508
- toDomainErrorDetails(stateResult.error),
15509
- );
15217
+ return normalizeCurrentStateValidationResult(stateResult);
15510
15218
  }
15511
15219
 
15512
- const definition = getCommandDefinition({ type: command.type });
15513
- if (!definition) {
15514
- return invalidPrecondition(`unknown command type '${command.type}'`);
15220
+ const validationResult = validateCommandDefinitionAgainstState({
15221
+ state: normalizedState,
15222
+ command,
15223
+ });
15224
+ if (!validationResult.valid) {
15225
+ return validationResult;
15515
15226
  }
15516
15227
 
15517
- const validationResult = captureValidation(() =>
15518
- definition.validateAgainstState({
15519
- state: normalizedState,
15520
- payload: command.payload,
15521
- }),
15522
- );
15523
-
15524
- return normalizeStateResult(validationResult);
15228
+ return VALID_RESULT;
15525
15229
  });
15526
15230
  };
15527
15231
 
@@ -15534,49 +15238,97 @@ export const processCommand = ({ state, command }) => {
15534
15238
  command.type.startsWith("spritesheet.") ||
15535
15239
  command.type.startsWith("particle."));
15536
15240
 
15537
- if (!isPlainObject(command)) {
15538
- return invalidPrecondition("command must be an object");
15241
+ const stateResult = validateState({ state: normalizedState });
15242
+ if (!stateResult.valid) {
15243
+ return normalizeCurrentStateValidationResult(stateResult);
15539
15244
  }
15540
15245
 
15541
- const preconditionResult = validateAgainstState({
15246
+ const validationResult = validateCommandDefinitionAgainstState({
15542
15247
  state: normalizedState,
15543
15248
  command,
15544
15249
  });
15545
- if (!preconditionResult.valid) {
15546
- return preconditionResult;
15547
- }
15548
-
15549
- const definition = getCommandDefinition({ type: command.type });
15550
- if (!definition) {
15551
- return invalidPrecondition(`unknown command type '${command.type}'`);
15250
+ if (!validationResult.valid) {
15251
+ return validationResult;
15552
15252
  }
15553
15253
 
15554
- const nextState = definition.reduce({
15254
+ const applyResult = applyCommandDefinition({
15555
15255
  state: structuredClone(
15556
15256
  shouldMaterializeNormalizedState ? normalizedState : state,
15557
15257
  ),
15258
+ definition: validationResult.definition,
15558
15259
  payload: command.payload,
15559
15260
  });
15560
- if (nextState?.valid === false) {
15561
- return nextState;
15261
+ if (!applyResult.valid) {
15262
+ return applyResult;
15562
15263
  }
15563
15264
 
15564
- const finalState =
15565
- nextState === undefined
15566
- ? shouldMaterializeNormalizedState
15567
- ? normalizedState
15568
- : state
15569
- : nextState;
15265
+ const stateResultAfterCommand = validateState({
15266
+ state: applyResult.state,
15267
+ });
15268
+ if (!stateResultAfterCommand.valid) {
15269
+ return stateResultAfterCommand;
15270
+ }
15271
+
15272
+ return {
15273
+ valid: true,
15274
+ state: applyResult.state,
15275
+ };
15276
+ });
15277
+ };
15278
+
15279
+ export const replayCommands = ({ state, commands }) => {
15280
+ return captureValidation(() => {
15281
+ if (!Array.isArray(commands)) {
15282
+ return invalidPrecondition("commands must be an array");
15283
+ }
15284
+
15285
+ const normalizedState = normalizeStateCollections(state);
15570
15286
  const stateResult = validateState({
15571
- state: finalState,
15287
+ state: normalizedState,
15572
15288
  });
15573
15289
  if (!stateResult.valid) {
15574
- return stateResult;
15290
+ return normalizeCurrentStateValidationResult(stateResult);
15291
+ }
15292
+
15293
+ let workingState = structuredClone(normalizedState);
15294
+ for (let index = 0; index < commands.length; index += 1) {
15295
+ const command = commands[index];
15296
+ const validationResult = validateCommandDefinitionAgainstState({
15297
+ state: workingState,
15298
+ command,
15299
+ });
15300
+ if (!validationResult.valid) {
15301
+ return appendReplayCommandContext(validationResult, {
15302
+ commandIndex: index,
15303
+ command,
15304
+ });
15305
+ }
15306
+
15307
+ const applyResult = applyCommandDefinition({
15308
+ state: workingState,
15309
+ definition: validationResult.definition,
15310
+ payload: command.payload,
15311
+ });
15312
+ if (!applyResult.valid) {
15313
+ return appendReplayCommandContext(applyResult, {
15314
+ commandIndex: index,
15315
+ command,
15316
+ });
15317
+ }
15318
+
15319
+ workingState = applyResult.state;
15320
+ }
15321
+
15322
+ const finalStateResult = validateState({
15323
+ state: workingState,
15324
+ });
15325
+ if (!finalStateResult.valid) {
15326
+ return finalStateResult;
15575
15327
  }
15576
15328
 
15577
15329
  return {
15578
15330
  valid: true,
15579
- state: finalState,
15331
+ state: workingState,
15580
15332
  };
15581
15333
  });
15582
15334
  };