@routevn/creator-model 1.3.5 → 1.3.7

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/model.js +328 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routevn/creator-model",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/model.js CHANGED
@@ -2020,7 +2020,16 @@ const validateAnimationItems = ({ items, path, errorFactory }) => {
2020
2020
  allowedKeys:
2021
2021
  item.type === "folder"
2022
2022
  ? ["id", "type", "name", "description"]
2023
- : ["id", "type", "name", "description", "tagIds", "animation"],
2023
+ : [
2024
+ "id",
2025
+ "type",
2026
+ "name",
2027
+ "description",
2028
+ "tagIds",
2029
+ "thumbnailFileId",
2030
+ "preview",
2031
+ "animation",
2032
+ ],
2024
2033
  path: itemPath,
2025
2034
  errorFactory,
2026
2035
  });
@@ -2058,6 +2067,27 @@ const validateAnimationItems = ({ items, path, errorFactory }) => {
2058
2067
  }
2059
2068
 
2060
2069
  if (item.type === "animation") {
2070
+ if (
2071
+ item.thumbnailFileId !== undefined &&
2072
+ !isNonEmptyString(item.thumbnailFileId)
2073
+ ) {
2074
+ return invalidFromErrorFactory(
2075
+ errorFactory,
2076
+ `${itemPath}.thumbnailFileId must be a non-empty string when provided`,
2077
+ );
2078
+ }
2079
+
2080
+ {
2081
+ const result = validatePreviewObject({
2082
+ value: item.preview,
2083
+ path: `${itemPath}.preview`,
2084
+ errorFactory,
2085
+ });
2086
+ if (result?.valid === false) {
2087
+ return result;
2088
+ }
2089
+ }
2090
+
2061
2091
  {
2062
2092
  const result = validateOptionalUniqueIdArray({
2063
2093
  value: item.tagIds,
@@ -2534,6 +2564,85 @@ const validateVariableTypedValue = ({
2534
2564
  }
2535
2565
  };
2536
2566
 
2567
+ const normalizeVariableEnumValues = (values = []) => {
2568
+ const normalizedValues = Array.isArray(values) ? values : [];
2569
+ const seen = new Set();
2570
+ const result = [];
2571
+
2572
+ for (const value of normalizedValues) {
2573
+ const stringValue = String(value ?? "").trim();
2574
+ if (!stringValue || seen.has(stringValue)) {
2575
+ continue;
2576
+ }
2577
+
2578
+ seen.add(stringValue);
2579
+ result.push(stringValue);
2580
+ }
2581
+
2582
+ return result;
2583
+ };
2584
+
2585
+ const validateVariableEnumValues = ({ value, path, errorFactory }) => {
2586
+ if (value === undefined) {
2587
+ return VALID_RESULT;
2588
+ }
2589
+
2590
+ if (!Array.isArray(value)) {
2591
+ return invalidFromErrorFactory(
2592
+ errorFactory,
2593
+ `${path} must be an array when provided`,
2594
+ );
2595
+ }
2596
+
2597
+ for (const [index, enumValue] of value.entries()) {
2598
+ if (!isString(enumValue)) {
2599
+ return invalidFromErrorFactory(
2600
+ errorFactory,
2601
+ `${path}[${index}] must be a string`,
2602
+ );
2603
+ }
2604
+ }
2605
+
2606
+ return VALID_RESULT;
2607
+ };
2608
+
2609
+ const validateVariableEnumMetadata = ({
2610
+ data,
2611
+ variableType,
2612
+ path,
2613
+ errorFactory,
2614
+ }) => {
2615
+ if (data.isEnum !== undefined && typeof data.isEnum !== "boolean") {
2616
+ return invalidFromErrorFactory(
2617
+ errorFactory,
2618
+ `${path}.isEnum must be a boolean when provided`,
2619
+ );
2620
+ }
2621
+
2622
+ {
2623
+ const result = validateVariableEnumValues({
2624
+ value: data.enumValues,
2625
+ path: `${path}.enumValues`,
2626
+ errorFactory,
2627
+ });
2628
+ if (result?.valid === false) {
2629
+ return result;
2630
+ }
2631
+ }
2632
+
2633
+ if (
2634
+ variableType !== "string" &&
2635
+ (data.isEnum !== undefined || data.enumValues !== undefined)
2636
+ ) {
2637
+ return invalidFromErrorFactory(
2638
+ errorFactory,
2639
+ `${path}.isEnum and ${path}.enumValues are only supported for string variables`,
2640
+ );
2641
+ }
2642
+
2643
+ return VALID_RESULT;
2644
+ };
2645
+
2537
2646
  const validateVariableItems = ({ items, path, errorFactory }) => {
2538
2647
  for (const [itemId, item] of Object.entries(items)) {
2539
2648
  const itemPath = `${path}.${itemId}`;
@@ -2564,6 +2673,8 @@ const validateVariableItems = ({ items, path, errorFactory }) => {
2564
2673
  "scope",
2565
2674
  "default",
2566
2675
  "value",
2676
+ "isEnum",
2677
+ "enumValues",
2567
2678
  ],
2568
2679
  path: itemPath,
2569
2680
  errorFactory,
@@ -2614,6 +2725,18 @@ const validateVariableItems = ({ items, path, errorFactory }) => {
2614
2725
  }
2615
2726
  }
2616
2727
 
2728
+ {
2729
+ const result = validateVariableEnumMetadata({
2730
+ data: item,
2731
+ variableType,
2732
+ path: itemPath,
2733
+ errorFactory,
2734
+ });
2735
+ if (result?.valid === false) {
2736
+ return result;
2737
+ }
2738
+ }
2739
+
2617
2740
  if (!VARIABLE_SCOPE_KEYS.includes(item.scope)) {
2618
2741
  return invalidFromErrorFactory(
2619
2742
  errorFactory,
@@ -4269,6 +4392,44 @@ const applyCharacterUpdate = ({ currentItem, data }) => {
4269
4392
  return nextItem;
4270
4393
  };
4271
4394
 
4395
+ const applyVariableEnumMetadata = ({ item, data }) => {
4396
+ if (!isPlainObject(item)) {
4397
+ return item;
4398
+ }
4399
+
4400
+ const enumEnabled =
4401
+ item.type === "string" &&
4402
+ data.isEnum !== false &&
4403
+ (data.isEnum === true ||
4404
+ data.enumValues !== undefined ||
4405
+ (data.isEnum === undefined && item.isEnum === true));
4406
+
4407
+ if (!enumEnabled) {
4408
+ delete item.isEnum;
4409
+ delete item.enumValues;
4410
+ return item;
4411
+ }
4412
+
4413
+ item.isEnum = true;
4414
+ item.enumValues = normalizeVariableEnumValues(
4415
+ data.enumValues ?? item.enumValues,
4416
+ );
4417
+
4418
+ return item;
4419
+ };
4420
+
4421
+ const applyVariableUpdate = ({ currentItem, data }) => {
4422
+ const nextItem = applyTagIdsUpdate({
4423
+ currentItem,
4424
+ data,
4425
+ });
4426
+
4427
+ return applyVariableEnumMetadata({
4428
+ item: nextItem,
4429
+ data,
4430
+ });
4431
+ };
4432
+
4272
4433
  const stripDeletedTagIdsFromItem = ({ item, deletedTagIds }) => {
4273
4434
  if (!Array.isArray(item?.tagIds) || item.tagIds.length === 0) {
4274
4435
  return;
@@ -6100,6 +6261,19 @@ export const assertInvariants = ({ state }) => {
6100
6261
  }
6101
6262
  }
6102
6263
 
6264
+ if (animation.thumbnailFileId !== undefined) {
6265
+ const fileResult = validateFileReference({
6266
+ state,
6267
+ fileId: animation.thumbnailFileId,
6268
+ path: "animation.thumbnailFileId",
6269
+ details: { animationId, thumbnailFileId: animation.thumbnailFileId },
6270
+ errorFactory: createInvariantValidationError,
6271
+ });
6272
+ if (!fileResult.valid) {
6273
+ return fileResult;
6274
+ }
6275
+ }
6276
+
6103
6277
  const result = validateAnimationMaskImageReferences({
6104
6278
  state,
6105
6279
  animation: animation.animation,
@@ -8602,7 +8776,15 @@ const validateAnimationCreateData = ({ data, errorFactory }) => {
8602
8776
  allowedKeys:
8603
8777
  data.type === "folder"
8604
8778
  ? ["type", "name", "description"]
8605
- : ["type", "name", "description", "tagIds", "animation"],
8779
+ : [
8780
+ "type",
8781
+ "name",
8782
+ "description",
8783
+ "tagIds",
8784
+ "thumbnailFileId",
8785
+ "preview",
8786
+ "animation",
8787
+ ],
8606
8788
  path: "payload.data",
8607
8789
  errorFactory,
8608
8790
  });
@@ -8626,6 +8808,27 @@ const validateAnimationCreateData = ({ data, errorFactory }) => {
8626
8808
  }
8627
8809
 
8628
8810
  if (data.type === "animation") {
8811
+ if (
8812
+ data.thumbnailFileId !== undefined &&
8813
+ !isNonEmptyString(data.thumbnailFileId)
8814
+ ) {
8815
+ return invalidFromErrorFactory(
8816
+ errorFactory,
8817
+ "payload.data.thumbnailFileId must be a non-empty string when provided",
8818
+ );
8819
+ }
8820
+
8821
+ {
8822
+ const result = validatePreviewObject({
8823
+ value: data.preview,
8824
+ path: "payload.data.preview",
8825
+ errorFactory,
8826
+ });
8827
+ if (result?.valid === false) {
8828
+ return result;
8829
+ }
8830
+ }
8831
+
8629
8832
  {
8630
8833
  const result = validateOptionalUniqueIdArray({
8631
8834
  value: data.tagIds,
@@ -8654,7 +8857,14 @@ const validateAnimationUpdateData = ({ data, errorFactory }) => {
8654
8857
  {
8655
8858
  const result = validateAllowedKeys({
8656
8859
  value: data,
8657
- allowedKeys: ["name", "description", "tagIds", "animation"],
8860
+ allowedKeys: [
8861
+ "name",
8862
+ "description",
8863
+ "tagIds",
8864
+ "thumbnailFileId",
8865
+ "preview",
8866
+ "animation",
8867
+ ],
8658
8868
  path: "payload.data",
8659
8869
  errorFactory,
8660
8870
  });
@@ -8684,6 +8894,27 @@ const validateAnimationUpdateData = ({ data, errorFactory }) => {
8684
8894
  );
8685
8895
  }
8686
8896
 
8897
+ if (
8898
+ data.thumbnailFileId !== undefined &&
8899
+ !isNonEmptyString(data.thumbnailFileId)
8900
+ ) {
8901
+ return invalidFromErrorFactory(
8902
+ errorFactory,
8903
+ "payload.data.thumbnailFileId must be a non-empty string when provided",
8904
+ );
8905
+ }
8906
+
8907
+ {
8908
+ const result = validatePreviewObject({
8909
+ value: data.preview,
8910
+ path: "payload.data.preview",
8911
+ errorFactory,
8912
+ });
8913
+ if (result?.valid === false) {
8914
+ return result;
8915
+ }
8916
+ }
8917
+
8687
8918
  {
8688
8919
  const result = validateOptionalUniqueIdArray({
8689
8920
  value: data.tagIds,
@@ -9124,6 +9355,8 @@ const validateVariableCreateData = ({ data, errorFactory }) => {
9124
9355
  "scope",
9125
9356
  "default",
9126
9357
  "value",
9358
+ "isEnum",
9359
+ "enumValues",
9127
9360
  ],
9128
9361
  path: "payload.data",
9129
9362
  errorFactory,
@@ -9160,6 +9393,18 @@ const validateVariableCreateData = ({ data, errorFactory }) => {
9160
9393
  }
9161
9394
  }
9162
9395
 
9396
+ {
9397
+ const result = validateVariableEnumMetadata({
9398
+ data,
9399
+ variableType: data.type,
9400
+ path: "payload.data",
9401
+ errorFactory,
9402
+ });
9403
+ if (result?.valid === false) {
9404
+ return result;
9405
+ }
9406
+ }
9407
+
9163
9408
  if (!VARIABLE_SCOPE_KEYS.includes(data.scope)) {
9164
9409
  return invalidFromErrorFactory(
9165
9410
  errorFactory,
@@ -9203,6 +9448,8 @@ const validateVariableUpdateData = ({ data, errorFactory }) => {
9203
9448
  "scope",
9204
9449
  "default",
9205
9450
  "value",
9451
+ "isEnum",
9452
+ "enumValues",
9206
9453
  ],
9207
9454
  path: "payload.data",
9208
9455
  errorFactory,
@@ -9233,6 +9480,24 @@ const validateVariableUpdateData = ({ data, errorFactory }) => {
9233
9480
  );
9234
9481
  }
9235
9482
 
9483
+ if (data.isEnum !== undefined && typeof data.isEnum !== "boolean") {
9484
+ return invalidFromErrorFactory(
9485
+ errorFactory,
9486
+ "payload.data.isEnum must be a boolean when provided",
9487
+ );
9488
+ }
9489
+
9490
+ {
9491
+ const result = validateVariableEnumValues({
9492
+ value: data.enumValues,
9493
+ path: "payload.data.enumValues",
9494
+ errorFactory,
9495
+ });
9496
+ if (result?.valid === false) {
9497
+ return result;
9498
+ }
9499
+ }
9500
+
9236
9501
  if (data.scope !== undefined && !VARIABLE_SCOPE_KEYS.includes(data.scope)) {
9237
9502
  return invalidFromErrorFactory(
9238
9503
  errorFactory,
@@ -11329,6 +11594,22 @@ const findReferencedFileUsage = ({ state, fileId }) => {
11329
11594
  }
11330
11595
  }
11331
11596
 
11597
+ for (const [animationId, animation] of Object.entries(
11598
+ state.animations.items,
11599
+ )) {
11600
+ if (animation.type !== "animation") {
11601
+ continue;
11602
+ }
11603
+
11604
+ if (animation.thumbnailFileId === fileId) {
11605
+ return {
11606
+ kind: "animation",
11607
+ field: "thumbnailFileId",
11608
+ ownerId: animationId,
11609
+ };
11610
+ }
11611
+ }
11612
+
11332
11613
  for (const [characterId, character] of Object.entries(
11333
11614
  state.characters.items,
11334
11615
  )) {
@@ -14288,6 +14569,16 @@ const COMMAND_DEFINITIONS = [
14288
14569
  return result;
14289
14570
  }
14290
14571
 
14572
+ const fileResult = validateReferencedFilesInData({
14573
+ state,
14574
+ data: payload.data,
14575
+ fields: ["thumbnailFileId"],
14576
+ details: { animationId: payload.animationId },
14577
+ });
14578
+ if (!fileResult.valid) {
14579
+ return fileResult;
14580
+ }
14581
+
14291
14582
  return validateTagIdsAgainstScope({
14292
14583
  state,
14293
14584
  tagIds: payload.data.tagIds,
@@ -14315,6 +14606,12 @@ const COMMAND_DEFINITIONS = [
14315
14606
  target: nextAnimation,
14316
14607
  tagIds: payload.data.tagIds,
14317
14608
  });
14609
+ if (payload.data.thumbnailFileId !== undefined) {
14610
+ nextAnimation.thumbnailFileId = payload.data.thumbnailFileId;
14611
+ }
14612
+ if (payload.data.preview !== undefined) {
14613
+ nextAnimation.preview = structuredClone(payload.data.preview);
14614
+ }
14318
14615
  nextAnimation.animation = structuredClone(payload.data.animation);
14319
14616
  }
14320
14617
 
@@ -14397,6 +14694,16 @@ const COMMAND_DEFINITIONS = [
14397
14694
  }
14398
14695
  }
14399
14696
 
14697
+ const fileResult = validateReferencedFilesInData({
14698
+ state,
14699
+ data: payload.data,
14700
+ fields: ["thumbnailFileId"],
14701
+ details: { animationId: payload.animationId },
14702
+ });
14703
+ if (!fileResult.valid) {
14704
+ return fileResult;
14705
+ }
14706
+
14400
14707
  return validateTagIdsAgainstScope({
14401
14708
  state,
14402
14709
  tagIds: payload.data.tagIds,
@@ -15665,13 +15972,16 @@ const COMMAND_DEFINITIONS = [
15665
15972
  delete data.tagIds;
15666
15973
  }
15667
15974
 
15668
- return {
15669
- id: payload.variableId,
15670
- ...data,
15671
- };
15975
+ return applyVariableEnumMetadata({
15976
+ item: {
15977
+ id: payload.variableId,
15978
+ ...data,
15979
+ },
15980
+ data,
15981
+ });
15672
15982
  },
15673
15983
  updateItem: ({ currentItem, payload }) =>
15674
- applyTagIdsUpdate({
15984
+ applyVariableUpdate({
15675
15985
  currentItem,
15676
15986
  data: payload.data,
15677
15987
  }),
@@ -15702,6 +16012,16 @@ const COMMAND_DEFINITIONS = [
15702
16012
  );
15703
16013
  }
15704
16014
 
16015
+ if (
16016
+ currentItem.type !== "string" &&
16017
+ (payload.data.isEnum !== undefined ||
16018
+ payload.data.enumValues !== undefined)
16019
+ ) {
16020
+ return invalidPrecondition(
16021
+ "variable enum fields can only update string variables",
16022
+ );
16023
+ }
16024
+
15705
16025
  if (currentItem.type !== "folder") {
15706
16026
  {
15707
16027
  const result = validateTagIdsAgainstScope({