kintone-migrator 0.24.0 → 0.24.1

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/index.mjs CHANGED
@@ -76,13 +76,15 @@ const FieldPermissionErrorCode = {
76
76
  //#region src/core/domain/formSchema/errorCode.ts
77
77
  const FormSchemaErrorCode = {
78
78
  FsEmptyFieldCode: "FS_EMPTY_FIELD_CODE",
79
+ FsInvalidFieldCode: "FS_INVALID_FIELD_CODE",
79
80
  FsEmptySchemaText: "FS_EMPTY_SCHEMA_TEXT",
80
81
  FsInvalidSchemaFormat: "FS_INVALID_SCHEMA_FORMAT",
81
82
  FsInvalidSchemaStructure: "FS_INVALID_SCHEMA_STRUCTURE",
82
83
  FsDuplicateFieldCode: "FS_DUPLICATE_FIELD_CODE",
83
84
  FsInvalidFieldType: "FS_INVALID_FIELD_TYPE",
84
85
  FsInvalidLayoutStructure: "FS_INVALID_LAYOUT_STRUCTURE",
85
- FsInvalidDecorationElement: "FS_INVALID_DECORATION_ELEMENT"
86
+ FsInvalidDecorationElement: "FS_INVALID_DECORATION_ELEMENT",
87
+ FsEmptyFields: "FS_EMPTY_FIELDS"
86
88
  };
87
89
 
88
90
  //#endregion
@@ -135,6 +137,7 @@ const ProjectConfigErrorCode = {
135
137
  PcEmptyApps: "PC_EMPTY_APPS",
136
138
  PcEmptyAppId: "PC_EMPTY_APP_ID",
137
139
  PcEmptyAppName: "PC_EMPTY_APP_NAME",
140
+ PcInvalidAppName: "PC_INVALID_APP_NAME",
138
141
  PcInvalidConfigStructure: "PC_INVALID_CONFIG_STRUCTURE",
139
142
  PcInvalidAuthConfig: "PC_INVALID_AUTH_CONFIG"
140
143
  };
@@ -329,7 +332,7 @@ function isSystemError(error) {
329
332
  * Excludes built-in types (Date, RegExp, Map, Set) that are technically
330
333
  * objects but should not be treated as string-keyed records.
331
334
  */
332
- function isRecord$1(value) {
335
+ function isRecord(value) {
333
336
  return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof Map) && !(value instanceof Set);
334
337
  }
335
338
 
@@ -343,22 +346,22 @@ function isRecord$1(value) {
343
346
  * Narrows `unknown` to `{ code: string }`.
344
347
  */
345
348
  function hasCode(value) {
346
- return isRecord$1(value) && typeof value.code === "string";
349
+ return isRecord(value) && typeof value.code === "string";
347
350
  }
348
351
  /**
349
352
  * Narrows `unknown` to `{ value: Record<string, { value: unknown }> }`.
350
353
  * Used when processing kintone subtable rows.
351
354
  */
352
355
  function isKintoneSubtableRow(value) {
353
- if (!isRecord$1(value)) return false;
354
- if (!isRecord$1(value.value)) return false;
355
- return Object.values(value.value).every((cell) => isRecord$1(cell) && "value" in cell);
356
+ if (!isRecord(value)) return false;
357
+ if (!isRecord(value.value)) return false;
358
+ return Object.values(value.value).every((cell) => isRecord(cell) && "value" in cell);
356
359
  }
357
360
  /**
358
361
  * Narrows `unknown` to `{ type?: string }`.
359
362
  */
360
363
  function hasOptionalType(value) {
361
- if (!isRecord$1(value)) return false;
364
+ if (!isRecord(value)) return false;
362
365
  return value.type === void 0 || typeof value.type === "string";
363
366
  }
364
367
 
@@ -374,7 +377,7 @@ const VALID_ENTITY_TYPES$10 = new Set([
374
377
  //#endregion
375
378
  //#region src/core/domain/action/services/configParser.ts
376
379
  function parseDestApp(raw, actionName) {
377
- if (!isRecord$1(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" destApp must be an object`);
380
+ if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" destApp must be an object`);
378
381
  const obj = raw;
379
382
  const result = {};
380
383
  if (obj.app !== void 0 && obj.app !== null) result.app = String(obj.app);
@@ -382,7 +385,7 @@ function parseDestApp(raw, actionName) {
382
385
  return result;
383
386
  }
384
387
  function parseMapping(raw, index, actionName) {
385
- if (!isRecord$1(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" mapping at index ${index} must be an object`);
388
+ if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" mapping at index ${index} must be an object`);
386
389
  const obj = raw;
387
390
  if (typeof obj.srcType !== "string" || !VALID_SRC_TYPES.has(obj.srcType)) throw new BusinessRuleError(ActionErrorCode.AcInvalidSrcType, `Action "${actionName}" mapping at index ${index} has invalid srcType: ${String(obj.srcType)}. Must be FIELD or RECORD_URL`);
388
391
  if (typeof obj.destField !== "string" || obj.destField.length === 0) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" mapping at index ${index} must have a non-empty "destField" property`);
@@ -393,7 +396,7 @@ function parseMapping(raw, index, actionName) {
393
396
  };
394
397
  }
395
398
  function parseEntity$4(raw, index, actionName) {
396
- if (!isRecord$1(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" entity at index ${index} must be an object`);
399
+ if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" entity at index ${index} must be an object`);
397
400
  const obj = raw;
398
401
  if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$10.has(obj.type)) throw new BusinessRuleError(ActionErrorCode.AcInvalidEntityType, `Action "${actionName}" entity at index ${index} has invalid type: ${String(obj.type)}. Must be USER, GROUP, or ORGANIZATION`);
399
402
  if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" entity at index ${index} must have a non-empty "code" property`);
@@ -403,11 +406,11 @@ function parseEntity$4(raw, index, actionName) {
403
406
  };
404
407
  }
405
408
  function parseActionConfig(raw, actionName) {
406
- if (!isRecord$1(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must be an object`);
409
+ if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must be an object`);
407
410
  const obj = raw;
408
411
  if (actionName.length === 0) throw new BusinessRuleError(ActionErrorCode.AcEmptyActionName, "Action name (key) must not be empty");
409
412
  if (typeof obj.index !== "number") throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have a numeric "index" property`);
410
- if (!isRecord$1(obj.destApp)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have a "destApp" object`);
413
+ if (!isRecord(obj.destApp)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have a "destApp" object`);
411
414
  const destApp = parseDestApp(obj.destApp, actionName);
412
415
  if (!Array.isArray(obj.mappings)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have a "mappings" array`);
413
416
  const mappings = obj.mappings.map((item, i) => parseMapping(item, i, actionName));
@@ -431,9 +434,9 @@ const ActionConfigParser = { parse: (rawText) => {
431
434
  } catch (error) {
432
435
  throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
433
436
  }
434
- if (!isRecord$1(parsed)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must be a YAML object");
437
+ if (!isRecord(parsed)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must be a YAML object");
435
438
  const obj = parsed;
436
- if (!isRecord$1(obj.actions)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must have an \"actions\" object");
439
+ if (!isRecord(obj.actions)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must have an \"actions\" object");
437
440
  const rawActions = obj.actions;
438
441
  const actions = {};
439
442
  for (const [key, value] of Object.entries(rawActions)) actions[key] = parseActionConfig(value, key);
@@ -791,10 +794,40 @@ var KintoneFileUploader = class {
791
794
  }
792
795
  };
793
796
 
797
+ //#endregion
798
+ //#region src/lib/charValidation.ts
799
+ /** Returns true if the string contains any control characters (0x00–0x1f or 0x7f). */
800
+ function hasControlChars(s) {
801
+ for (let i = 0; i < s.length; i++) {
802
+ const ch = s.charCodeAt(i);
803
+ if (ch <= 31 || ch === 127) return true;
804
+ }
805
+ return false;
806
+ }
807
+ /** Replaces control characters (0x00–0x1f, 0x7f) with escaped `\\xNN` representation for safe display. */
808
+ function sanitizeForDisplay(s) {
809
+ let result = "";
810
+ for (let i = 0; i < s.length; i++) {
811
+ const ch = s.charCodeAt(i);
812
+ if (ch <= 31 || ch === 127) result += `\\x${ch.toString(16).padStart(2, "0")}`;
813
+ else result += s[i];
814
+ }
815
+ return result;
816
+ }
817
+
794
818
  //#endregion
795
819
  //#region src/core/domain/formSchema/valueObject.ts
820
+ function hasInvalidFieldCodeChars(code) {
821
+ if (hasControlChars(code)) return true;
822
+ for (let i = 0; i < code.length; i++) {
823
+ const c = code[i];
824
+ if (c === "/" || c === "\\") return true;
825
+ }
826
+ return false;
827
+ }
796
828
  const FieldCode = { create: (code) => {
797
829
  if (code.length === 0) throw new BusinessRuleError(FormSchemaErrorCode.FsEmptyFieldCode, "Field code cannot be empty");
830
+ if (hasInvalidFieldCodeChars(code)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidFieldCode, `Field code "${sanitizeForDisplay(code)}" contains invalid characters`);
798
831
  return code;
799
832
  } };
800
833
 
@@ -1648,16 +1681,31 @@ async function executeMultiApp(plan, executor) {
1648
1681
 
1649
1682
  //#endregion
1650
1683
  //#region src/core/domain/projectConfig/valueObject.ts
1684
+ const INVALID_APP_NAME_CHARS = new Set([
1685
+ "/",
1686
+ "\\",
1687
+ ":",
1688
+ "*",
1689
+ "?",
1690
+ "\"",
1691
+ "<",
1692
+ ">",
1693
+ "|"
1694
+ ]);
1695
+ function hasInvalidAppNameChars(name) {
1696
+ if (hasControlChars(name)) return true;
1697
+ for (let i = 0; i < name.length; i++) if (INVALID_APP_NAME_CHARS.has(name[i])) return true;
1698
+ return false;
1699
+ }
1651
1700
  const AppName = { create: (name) => {
1652
1701
  if (name.length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcEmptyAppName, "App name cannot be empty");
1702
+ if (hasInvalidAppNameChars(name)) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAppName, `App name "${sanitizeForDisplay(name)}" contains invalid characters (path separators or control characters are not allowed)`);
1703
+ if (name === "." || name === "..") throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAppName, `App name "${name}" is not allowed (reserved path component)`);
1653
1704
  return name;
1654
1705
  } };
1655
1706
 
1656
1707
  //#endregion
1657
1708
  //#region src/core/domain/projectConfig/services/configParser.ts
1658
- function isRecord(value) {
1659
- return typeof value === "object" && value !== null && !Array.isArray(value);
1660
- }
1661
1709
  function asOptionalString(value) {
1662
1710
  return typeof value === "string" ? value : void 0;
1663
1711
  }
@@ -1731,19 +1779,21 @@ function parseAuth(raw) {
1731
1779
  if (!raw) return void 0;
1732
1780
  const apiToken = asOptionalString(raw.apiToken);
1733
1781
  if (apiToken !== void 0) {
1734
- if (apiToken.trim().length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAuthConfig, "apiToken must not be empty");
1782
+ const trimmed = apiToken.trim();
1783
+ if (trimmed.length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAuthConfig, "apiToken must not be empty");
1735
1784
  return {
1736
1785
  type: "apiToken",
1737
- apiToken
1786
+ apiToken: trimmed
1738
1787
  };
1739
1788
  }
1740
1789
  const username = asOptionalString(raw.username);
1741
1790
  const password = asOptionalString(raw.password);
1742
1791
  if (username !== void 0 && password !== void 0) {
1743
- if (username.trim().length === 0 || password.trim().length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAuthConfig, "username and password must not be empty");
1792
+ const trimmedUsername = username.trim();
1793
+ if (trimmedUsername.length === 0 || password.length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAuthConfig, "username and password must not be empty");
1744
1794
  return {
1745
1795
  type: "password",
1746
- username,
1796
+ username: trimmedUsername,
1747
1797
  password
1748
1798
  };
1749
1799
  }
@@ -1804,7 +1854,8 @@ function resolveExecutionOrder(apps) {
1804
1854
  queue.push(...nextBatch);
1805
1855
  }
1806
1856
  if (orderedNames.length !== apps.size) {
1807
- const cycleNodes = [...apps.keys()].filter((name) => !orderedNames.includes(name));
1857
+ const orderedSet = new Set(orderedNames);
1858
+ const cycleNodes = [...apps.keys()].filter((name) => !orderedSet.has(name));
1808
1859
  throw new BusinessRuleError(ProjectConfigErrorCode.PcCircularDependency, `Circular dependency detected among: ${cycleNodes.join(", ")}`);
1809
1860
  }
1810
1861
  return { orderedApps: orderedNames.flatMap((name) => {
@@ -2505,7 +2556,7 @@ function deepEqualInner(a, b, seen) {
2505
2556
  if (objB instanceof Map) return false;
2506
2557
  if (objA instanceof Set) return isSetEqual(objA, objB, seen);
2507
2558
  if (objB instanceof Set) return false;
2508
- if (isRecord$1(objA) && isRecord$1(objB)) return isRecordEqual(objA, objB, seen);
2559
+ if (isRecord(objA) && isRecord(objB)) return isRecordEqual(objA, objB, seen);
2509
2560
  return false;
2510
2561
  }
2511
2562
  /**
@@ -2528,7 +2579,7 @@ function deepEqualInner(a, b, seen) {
2528
2579
  * (e.g. `a.self = a` vs `b.self = b`) return `false`. This is a conservative
2529
2580
  * approach that prevents infinite recursion but may produce false negatives.
2530
2581
  */
2531
- function deepEqual$1(a, b) {
2582
+ function deepEqual(a, b) {
2532
2583
  return deepEqualInner(a, b, /* @__PURE__ */ new WeakSet());
2533
2584
  }
2534
2585
 
@@ -2566,11 +2617,11 @@ function compareActions$1(local, remote) {
2566
2617
  const diffs = [];
2567
2618
  if (local.index !== remote.index) diffs.push(`index: ${remote.index} -> ${local.index}`);
2568
2619
  if (local.name !== remote.name) diffs.push(`name: "${remote.name}" -> "${local.name}"`);
2569
- if (!deepEqual$1(local.destApp, remote.destApp)) diffs.push("destApp changed");
2620
+ if (!deepEqual(local.destApp, remote.destApp)) diffs.push("destApp changed");
2570
2621
  if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
2571
- if (!deepEqual$1(local.mappings, remote.mappings)) if (local.mappings.length !== remote.mappings.length) diffs.push(`mappings: ${remote.mappings.length} -> ${local.mappings.length}`);
2622
+ if (!deepEqual(local.mappings, remote.mappings)) if (local.mappings.length !== remote.mappings.length) diffs.push(`mappings: ${remote.mappings.length} -> ${local.mappings.length}`);
2572
2623
  else diffs.push("mappings changed");
2573
- if (!deepEqual$1(local.entities, remote.entities)) diffs.push("entities changed");
2624
+ if (!deepEqual(local.entities, remote.entities)) diffs.push("entities changed");
2574
2625
  return diffs;
2575
2626
  }
2576
2627
  const ActionDiffDetector = { detect: (local, remote) => {
@@ -2703,7 +2754,7 @@ const AdminNotesConfigParser = { parse: (rawText) => {
2703
2754
  } catch (error) {
2704
2755
  throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
2705
2756
  }
2706
- if (!isRecord$1(parsed)) throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must be a YAML object");
2757
+ if (!isRecord(parsed)) throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must be a YAML object");
2707
2758
  const obj = parsed;
2708
2759
  if (typeof obj.content !== "string") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have a \"content\" string property");
2709
2760
  if (typeof obj.includeInTemplateAndDuplicates !== "boolean") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have an \"includeInTemplateAndDuplicates\" boolean property");
@@ -3004,7 +3055,7 @@ const VALID_ENTITY_TYPES$9 = new Set([
3004
3055
  "CREATOR"
3005
3056
  ]);
3006
3057
  function parseEntity$3(raw, index) {
3007
- if (!isRecord$1(raw)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, `Entity at index ${index} must be an object`);
3058
+ if (!isRecord(raw)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, `Entity at index ${index} must be an object`);
3008
3059
  const obj = raw;
3009
3060
  if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$9.has(obj.type)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidEntityType, `Entity at index ${index} has invalid type: ${String(obj.type)}. Must be USER, GROUP, ORGANIZATION, or CREATOR`);
3010
3061
  const type = obj.type;
@@ -3024,7 +3075,7 @@ function parseBooleanField$1(obj, field, index) {
3024
3075
  return value;
3025
3076
  }
3026
3077
  function parseAppRight(raw, index) {
3027
- if (!isRecord$1(raw)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, `App right at index ${index} must be an object`);
3078
+ if (!isRecord(raw)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, `App right at index ${index} must be an object`);
3028
3079
  const obj = raw;
3029
3080
  return {
3030
3081
  entity: parseEntity$3(obj.entity, index),
@@ -3046,7 +3097,7 @@ const AppPermissionConfigParser = { parse: (rawText) => {
3046
3097
  } catch (error) {
3047
3098
  throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
3048
3099
  }
3049
- if (!isRecord$1(parsed)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must be a YAML object");
3100
+ if (!isRecord(parsed)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must be a YAML object");
3050
3101
  const obj = parsed;
3051
3102
  if (!Array.isArray(obj.rights)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must have a \"rights\" array");
3052
3103
  const rights = obj.rights.map((item, i) => parseAppRight(item, i));
@@ -3465,7 +3516,7 @@ const VALID_SCOPES = new Set([
3465
3516
  ]);
3466
3517
  const VALID_RESOURCE_TYPES = new Set(["FILE", "URL"]);
3467
3518
  function parseResource(raw, index) {
3468
- if (!isRecord$1(raw)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, `Resource at index ${index} must be an object`);
3519
+ if (!isRecord(raw)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, `Resource at index ${index} must be an object`);
3469
3520
  const obj = raw;
3470
3521
  const type = obj.type;
3471
3522
  if (typeof type !== "string" || !VALID_RESOURCE_TYPES.has(type)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidResourceType, `Resource at index ${index} has invalid type: ${String(type)}. Must be FILE or URL`);
@@ -3487,7 +3538,7 @@ function parseResourceList(raw) {
3487
3538
  return raw.map((item, index) => parseResource(item, index));
3488
3539
  }
3489
3540
  function parsePlatform(raw) {
3490
- if (!isRecord$1(raw)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, "Platform configuration must be an object");
3541
+ if (!isRecord(raw)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, "Platform configuration must be an object");
3491
3542
  const obj = raw;
3492
3543
  return {
3493
3544
  js: obj.js === void 0 || obj.js === null ? [] : parseResourceList(obj.js),
@@ -3502,7 +3553,7 @@ const ConfigParser = { parse: (rawText) => {
3502
3553
  } catch (error) {
3503
3554
  throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
3504
3555
  }
3505
- if (!isRecord$1(parsed)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, "Config must be a YAML object");
3556
+ if (!isRecord(parsed)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, "Config must be a YAML object");
3506
3557
  const obj = parsed;
3507
3558
  let scope;
3508
3559
  if (obj.scope !== void 0 && obj.scope !== null) {
@@ -4135,7 +4186,7 @@ const VALID_ENTITY_TYPES$6 = new Set([
4135
4186
  "FIELD_ENTITY"
4136
4187
  ]);
4137
4188
  function parseEntity$2(raw, index) {
4138
- if (!isRecord$1(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Entity at index ${index} must be an object`);
4189
+ if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Entity at index ${index} must be an object`);
4139
4190
  const obj = raw;
4140
4191
  if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$6.has(obj.type)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidEntityType, `Entity at index ${index} has invalid type: ${String(obj.type)}. Must be USER, GROUP, ORGANIZATION, or FIELD_ENTITY`);
4141
4192
  if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(FieldPermissionErrorCode.FpEmptyEntityCode, `Entity at index ${index} must have a non-empty "code" property`);
@@ -4145,7 +4196,7 @@ function parseEntity$2(raw, index) {
4145
4196
  };
4146
4197
  }
4147
4198
  function parseFieldRightEntity(raw, index) {
4148
- if (!isRecord$1(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right entity at index ${index} must be an object`);
4199
+ if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right entity at index ${index} must be an object`);
4149
4200
  const obj = raw;
4150
4201
  if (typeof obj.accessibility !== "string" || !VALID_ACCESSIBILITIES.has(obj.accessibility)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidAccessibility, `Field right entity at index ${index} has invalid accessibility: ${String(obj.accessibility)}. Must be READ, WRITE, or NONE`);
4151
4202
  const entity = parseEntity$2(obj.entity, index);
@@ -4160,7 +4211,7 @@ function parseFieldRightEntity(raw, index) {
4160
4211
  return result;
4161
4212
  }
4162
4213
  function parseFieldRight(raw, index) {
4163
- if (!isRecord$1(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right at index ${index} must be an object`);
4214
+ if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right at index ${index} must be an object`);
4164
4215
  const obj = raw;
4165
4216
  if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(FieldPermissionErrorCode.FpEmptyFieldCode, `Field right at index ${index} must have a non-empty "code" property`);
4166
4217
  if (!Array.isArray(obj.entities)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right at index ${index} must have an "entities" array`);
@@ -4178,7 +4229,7 @@ const FieldPermissionConfigParser = { parse: (rawText) => {
4178
4229
  } catch (error) {
4179
4230
  throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
4180
4231
  }
4181
- if (!isRecord$1(parsed)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must be a YAML object");
4232
+ if (!isRecord(parsed)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must be a YAML object");
4182
4233
  const obj = parsed;
4183
4234
  if (!Array.isArray(obj.rights)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must have a \"rights\" array");
4184
4235
  const rights = obj.rights.map((item, i) => parseFieldRight(item, i));
@@ -4363,7 +4414,7 @@ var capture_default$9 = define({
4363
4414
  //#endregion
4364
4415
  //#region src/core/domain/fieldPermission/services/diffDetector.ts
4365
4416
  function areEntitiesEqual(a, b) {
4366
- return deepEqual$1(a.entities.map((e) => ({
4417
+ return deepEqual(a.entities.map((e) => ({
4367
4418
  accessibility: e.accessibility,
4368
4419
  type: e.entity.type,
4369
4420
  code: e.entity.code,
@@ -6186,11 +6237,7 @@ async function saveReport({ container, input }) {
6186
6237
  //#endregion
6187
6238
  //#region src/core/domain/seedData/services/seedSerializer.ts
6188
6239
  const SeedSerializer = { serialize: (seedData) => {
6189
- const records = seedData.records.map((record) => {
6190
- const plain = {};
6191
- for (const [key, value] of Object.entries(record)) plain[key] = value;
6192
- return plain;
6193
- });
6240
+ const records = seedData.records.map((record) => ({ ...record }));
6194
6241
  return stringify(seedData.key !== null ? {
6195
6242
  key: seedData.key,
6196
6243
  records
@@ -6620,7 +6667,7 @@ const VALID_ENTITY_TYPES$2 = new Set([
6620
6667
  "FIELD_ENTITY"
6621
6668
  ]);
6622
6669
  function parseEntity$1(raw, context) {
6623
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `${context}: entity must be an object`);
6670
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `${context}: entity must be an object`);
6624
6671
  const obj = raw;
6625
6672
  if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$2.has(obj.type)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidEntityType, `${context}: entity has invalid type: ${String(obj.type)}. Must be USER, GROUP, ORGANIZATION, or FIELD_ENTITY`);
6626
6673
  if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(NotificationErrorCode.NtEmptyEntityCode, `${context}: entity must have a non-empty "code" property`);
@@ -6630,7 +6677,7 @@ function parseEntity$1(raw, context) {
6630
6677
  };
6631
6678
  }
6632
6679
  function parseGeneralNotification(raw, index) {
6633
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `General notification at index ${index} must be an object`);
6680
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `General notification at index ${index} must be an object`);
6634
6681
  const obj = raw;
6635
6682
  const result = {
6636
6683
  entity: parseEntity$1(obj.entity, `General notification at index ${index}`),
@@ -6647,7 +6694,7 @@ function parseGeneralNotification(raw, index) {
6647
6694
  return result;
6648
6695
  }
6649
6696
  function parseGeneralConfig(raw) {
6650
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"general\" must be an object");
6697
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"general\" must be an object");
6651
6698
  const obj = raw;
6652
6699
  if (!Array.isArray(obj.notifications)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"general\" must have a \"notifications\" array");
6653
6700
  const notifications = obj.notifications.map((item, i) => parseGeneralNotification(item, i));
@@ -6657,7 +6704,7 @@ function parseGeneralConfig(raw) {
6657
6704
  };
6658
6705
  }
6659
6706
  function parsePerRecordTarget(raw, index) {
6660
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Per-record target at index ${index} must be an object`);
6707
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Per-record target at index ${index} must be an object`);
6661
6708
  const obj = raw;
6662
6709
  const result = { entity: parseEntity$1(obj.entity, `Per-record target at index ${index}`) };
6663
6710
  if (obj.includeSubs !== void 0 && obj.includeSubs !== null) return {
@@ -6667,7 +6714,7 @@ function parsePerRecordTarget(raw, index) {
6667
6714
  return result;
6668
6715
  }
6669
6716
  function parsePerRecordNotification(raw, index) {
6670
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Per-record notification at index ${index} must be an object`);
6717
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Per-record notification at index ${index} must be an object`);
6671
6718
  const obj = raw;
6672
6719
  if (!Array.isArray(obj.targets)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Per-record notification at index ${index} must have a "targets" array`);
6673
6720
  const targets = obj.targets.map((item, i) => parsePerRecordTarget(item, i));
@@ -6683,7 +6730,7 @@ function parsePerRecordConfig(raw) {
6683
6730
  return raw.map((item, i) => parsePerRecordNotification(item, i));
6684
6731
  }
6685
6732
  function parseReminderTarget(raw, index) {
6686
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder target at index ${index} must be an object`);
6733
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder target at index ${index} must be an object`);
6687
6734
  const obj = raw;
6688
6735
  const result = { entity: parseEntity$1(obj.entity, `Reminder target at index ${index}`) };
6689
6736
  if (obj.includeSubs !== void 0 && obj.includeSubs !== null) return {
@@ -6693,7 +6740,7 @@ function parseReminderTarget(raw, index) {
6693
6740
  return result;
6694
6741
  }
6695
6742
  function parseReminderNotification(raw, index) {
6696
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} must be an object`);
6743
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} must be an object`);
6697
6744
  const obj = raw;
6698
6745
  if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} must have a non-empty "code" property`);
6699
6746
  if (!Array.isArray(obj.targets)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} must have a "targets" array`);
@@ -6720,7 +6767,7 @@ function parseReminderNotification(raw, index) {
6720
6767
  return result;
6721
6768
  }
6722
6769
  function parseReminderConfig(raw) {
6723
- if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"reminder\" must be an object");
6770
+ if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"reminder\" must be an object");
6724
6771
  const obj = raw;
6725
6772
  if (!Array.isArray(obj.notifications)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"reminder\" must have a \"notifications\" array");
6726
6773
  const notifications = obj.notifications.map((item, i) => parseReminderNotification(item, i));
@@ -6737,7 +6784,7 @@ const NotificationConfigParser = { parse: (rawText) => {
6737
6784
  } catch (error) {
6738
6785
  throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
6739
6786
  }
6740
- if (!isRecord$1(parsed)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "Config must be a YAML object");
6787
+ if (!isRecord(parsed)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "Config must be a YAML object");
6741
6788
  const obj = parsed;
6742
6789
  const config = {};
6743
6790
  if (obj.general !== void 0) config.general = parseGeneralConfig(obj.general);
@@ -6979,7 +7026,7 @@ function perRecordLabel(notif) {
6979
7026
  function describePerRecordChanges(local, remote) {
6980
7027
  const diffs = [];
6981
7028
  if (local.title !== remote.title) diffs.push("title changed");
6982
- if (!deepEqual$1(local.targets, remote.targets)) diffs.push("targets changed");
7029
+ if (!deepEqual(local.targets, remote.targets)) diffs.push("targets changed");
6983
7030
  return diffs.length > 0 ? diffs.join(", ") : "changed";
6984
7031
  }
6985
7032
  function describeReminderChanges(local, remote) {
@@ -6989,7 +7036,7 @@ function describeReminderChanges(local, remote) {
6989
7036
  if ((local.hoursLater ?? 0) !== (remote.hoursLater ?? 0)) diffs.push("hoursLater changed");
6990
7037
  if ((local.time ?? "") !== (remote.time ?? "")) diffs.push("time changed");
6991
7038
  if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
6992
- if (!deepEqual$1(local.targets, remote.targets)) diffs.push("targets changed");
7039
+ if (!deepEqual(local.targets, remote.targets)) diffs.push("targets changed");
6993
7040
  return diffs.length > 0 ? diffs.join(", ") : "changed";
6994
7041
  }
6995
7042
  function comparePerRecordSection(local, remote) {
@@ -7014,7 +7061,7 @@ function comparePerRecordSection(local, remote) {
7014
7061
  name: perRecordLabel(remoteNotif),
7015
7062
  details: "removed"
7016
7063
  });
7017
- else if (localNotif && remoteNotif && !deepEqual$1(localNotif, remoteNotif)) {
7064
+ else if (localNotif && remoteNotif && !deepEqual(localNotif, remoteNotif)) {
7018
7065
  const diffs = describePerRecordChanges(localNotif, remoteNotif);
7019
7066
  entries.push({
7020
7067
  type: "modified",
@@ -7045,7 +7092,7 @@ function compareReminderSection(local, remote) {
7045
7092
  name: code,
7046
7093
  details: `"${localNotif.title}"`
7047
7094
  });
7048
- else if (!deepEqual$1(localNotif, remoteNotif)) entries.push({
7095
+ else if (!deepEqual(localNotif, remoteNotif)) entries.push({
7049
7096
  type: "modified",
7050
7097
  section: "reminder",
7051
7098
  name: code,
@@ -7156,7 +7203,7 @@ var notification_default = define({
7156
7203
  //#endregion
7157
7204
  //#region src/core/domain/plugin/services/configParser.ts
7158
7205
  function parsePluginEntry(raw, index) {
7159
- if (!isRecord$1(raw)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, `Plugin at index ${index} must be an object`);
7206
+ if (!isRecord(raw)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, `Plugin at index ${index} must be an object`);
7160
7207
  const obj = raw;
7161
7208
  if (typeof obj.id !== "string" || obj.id.length === 0) throw new BusinessRuleError(PluginErrorCode.PlEmptyPluginId, `Plugin at index ${index} must have a non-empty "id" property`);
7162
7209
  return {
@@ -7173,7 +7220,7 @@ const PluginConfigParser = { parse: (rawText) => {
7173
7220
  } catch (error) {
7174
7221
  throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
7175
7222
  }
7176
- if (!isRecord$1(parsed)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, "Config must be a YAML object");
7223
+ if (!isRecord(parsed)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, "Config must be a YAML object");
7177
7224
  const obj = parsed;
7178
7225
  if (!Array.isArray(obj.plugins)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, "Config must have a \"plugins\" array");
7179
7226
  return { plugins: obj.plugins.map((item, i) => parsePluginEntry(item, i)) };
@@ -7399,7 +7446,7 @@ const VALID_ENTITY_TYPES$1 = new Set([
7399
7446
  ]);
7400
7447
  const VALID_ACTION_TYPES = new Set(["PRIMARY", "SECONDARY"]);
7401
7448
  function parseProcessEntity(raw, index) {
7402
- if (!isRecord$1(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Entity at index ${index} must be an object`);
7449
+ if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Entity at index ${index} must be an object`);
7403
7450
  const obj = raw;
7404
7451
  if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$1.has(obj.type)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidEntityType, `Entity at index ${index} has invalid type: ${String(obj.type)}. Must be USER, GROUP, ORGANIZATION, FIELD_ENTITY, CREATOR, or CUSTOM_FIELD`);
7405
7452
  const result = { type: obj.type };
@@ -7414,7 +7461,7 @@ function parseProcessEntity(raw, index) {
7414
7461
  return withCode;
7415
7462
  }
7416
7463
  function parseAssignee(raw, stateName) {
7417
- if (!isRecord$1(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must be an object`);
7464
+ if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must be an object`);
7418
7465
  const obj = raw;
7419
7466
  if (typeof obj.type !== "string" || !VALID_ASSIGNEE_TYPES.has(obj.type)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidAssigneeType, `Assignee for state "${stateName}" has invalid type: ${String(obj.type)}. Must be ONE, ALL, or ANY`);
7420
7467
  if (!Array.isArray(obj.entities)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must have an "entities" array`);
@@ -7425,7 +7472,7 @@ function parseAssignee(raw, stateName) {
7425
7472
  };
7426
7473
  }
7427
7474
  function parseState(raw, stateName) {
7428
- if (!isRecord$1(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must be an object`);
7475
+ if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must be an object`);
7429
7476
  const obj = raw;
7430
7477
  if (typeof obj.index !== "number") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must have a numeric "index" property`);
7431
7478
  if (obj.assignee === void 0 || obj.assignee === null) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must have an "assignee" property`);
@@ -7436,13 +7483,13 @@ function parseState(raw, stateName) {
7436
7483
  };
7437
7484
  }
7438
7485
  function parseExecutableUser(raw, actionIndex) {
7439
- if (!isRecord$1(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${actionIndex}: executableUser must be an object`);
7486
+ if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${actionIndex}: executableUser must be an object`);
7440
7487
  const obj = raw;
7441
7488
  if (!Array.isArray(obj.entities)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${actionIndex}: executableUser must have an "entities" array`);
7442
7489
  return { entities: obj.entities.map((item, i) => parseProcessEntity(item, i)) };
7443
7490
  }
7444
7491
  function parseAction(raw, index) {
7445
- if (!isRecord$1(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must be an object`);
7492
+ if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must be an object`);
7446
7493
  const obj = raw;
7447
7494
  if (typeof obj.name !== "string") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must have a "name" string property`);
7448
7495
  if (typeof obj.from !== "string") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must have a "from" string property`);
@@ -7470,11 +7517,11 @@ const ProcessManagementConfigParser = { parse: (rawText) => {
7470
7517
  } catch (error) {
7471
7518
  throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
7472
7519
  }
7473
- if (!isRecord$1(parsed)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config must be a YAML object");
7520
+ if (!isRecord(parsed)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config must be a YAML object");
7474
7521
  const obj = parsed;
7475
7522
  const enable = obj.enable !== void 0 && obj.enable !== null ? Boolean(obj.enable) : false;
7476
- if (obj.states !== void 0 && obj.states !== null && !isRecord$1(obj.states)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config \"states\" must be an object (map of state name to state definition)");
7477
- const rawStates = isRecord$1(obj.states) ? obj.states : {};
7523
+ if (obj.states !== void 0 && obj.states !== null && !isRecord(obj.states)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config \"states\" must be an object (map of state name to state definition)");
7524
+ const rawStates = isRecord(obj.states) ? obj.states : {};
7478
7525
  const states = {};
7479
7526
  for (const [name, value] of Object.entries(rawStates)) states[name] = parseState(value, name);
7480
7527
  if (!Array.isArray(obj.actions) && obj.actions !== void 0) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config \"actions\" must be an array");
@@ -7775,7 +7822,7 @@ function parseBooleanField(value, fieldName, context) {
7775
7822
  throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidPermissionValue, `${context} has invalid "${fieldName}" value: ${String(value)}. Must be a boolean`);
7776
7823
  }
7777
7824
  function parseEntity(raw, index) {
7778
- if (!isRecord$1(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Entity at index ${index} must be an object`);
7825
+ if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Entity at index ${index} must be an object`);
7779
7826
  const obj = raw;
7780
7827
  if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES.has(obj.type)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidEntityType, `Entity at index ${index} has invalid type: ${String(obj.type)}. Must be USER, GROUP, ORGANIZATION, or FIELD_ENTITY`);
7781
7828
  if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(RecordPermissionErrorCode.RpEmptyEntityCode, `Entity at index ${index} must have a non-empty "code" property`);
@@ -7785,7 +7832,7 @@ function parseEntity(raw, index) {
7785
7832
  };
7786
7833
  }
7787
7834
  function parseRecordRightEntity(raw, index) {
7788
- if (!isRecord$1(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right entity at index ${index} must be an object`);
7835
+ if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right entity at index ${index} must be an object`);
7789
7836
  const obj = raw;
7790
7837
  const entity = parseEntity(obj.entity, index);
7791
7838
  const context = `Record right entity at index ${index}`;
@@ -7798,7 +7845,7 @@ function parseRecordRightEntity(raw, index) {
7798
7845
  };
7799
7846
  }
7800
7847
  function parseRecordRight(raw, index) {
7801
- if (!isRecord$1(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right at index ${index} must be an object`);
7848
+ if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right at index ${index} must be an object`);
7802
7849
  const obj = raw;
7803
7850
  if (!Array.isArray(obj.entities)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right at index ${index} must have an "entities" array`);
7804
7851
  const entities = obj.entities.map((item, i) => parseRecordRightEntity(item, i));
@@ -7815,7 +7862,7 @@ const RecordPermissionConfigParser = { parse: (rawText) => {
7815
7862
  } catch (error) {
7816
7863
  throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
7817
7864
  }
7818
- if (!isRecord$1(parsed)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, "Config must be a YAML object");
7865
+ if (!isRecord(parsed)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, "Config must be a YAML object");
7819
7866
  const obj = parsed;
7820
7867
  if (!Array.isArray(obj.rights)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, "Config must have a \"rights\" array");
7821
7868
  return { rights: obj.rights.map((item, i) => parseRecordRight(item, i)) };
@@ -7954,7 +8001,7 @@ var capture_default$5 = define({
7954
8001
  //#endregion
7955
8002
  //#region src/core/domain/recordPermission/services/diffDetector.ts
7956
8003
  function areRightsEqual(a, b) {
7957
- return deepEqual$1(a.entities.map((e) => ({
8004
+ return deepEqual(a.entities.map((e) => ({
7958
8005
  type: e.entity.type,
7959
8006
  code: e.entity.code,
7960
8007
  viewable: e.viewable,
@@ -8126,7 +8173,7 @@ const VALID_PERIODIC_EVERY = new Set([
8126
8173
  "HOUR"
8127
8174
  ]);
8128
8175
  function parseGroup(raw, index) {
8129
- if (!isRecord$1(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Group at index ${index} must be an object`);
8176
+ if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Group at index ${index} must be an object`);
8130
8177
  const obj = raw;
8131
8178
  if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Group at index ${index} must have a non-empty "code" property`);
8132
8179
  const result = { code: obj.code };
@@ -8140,7 +8187,7 @@ function parseGroup(raw, index) {
8140
8187
  return result;
8141
8188
  }
8142
8189
  function parseAggregation(raw, index) {
8143
- if (!isRecord$1(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Aggregation at index ${index} must be an object`);
8190
+ if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Aggregation at index ${index} must be an object`);
8144
8191
  const obj = raw;
8145
8192
  if (typeof obj.type !== "string" || !VALID_AGGREGATION_TYPES.has(obj.type)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Aggregation at index ${index} has invalid type: ${String(obj.type)}. Must be COUNT, SUM, AVERAGE, MAX, or MIN`);
8146
8193
  const result = { type: obj.type };
@@ -8154,7 +8201,7 @@ function parseAggregation(raw, index) {
8154
8201
  return result;
8155
8202
  }
8156
8203
  function parseSort(raw, index) {
8157
- if (!isRecord$1(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Sort at index ${index} must be an object`);
8204
+ if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Sort at index ${index} must be an object`);
8158
8205
  const obj = raw;
8159
8206
  if (typeof obj.by !== "string" || !VALID_SORT_BY.has(obj.by)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Sort at index ${index} has invalid by: ${String(obj.by)}. Must be TOTAL, GROUP1, GROUP2, or GROUP3`);
8160
8207
  if (typeof obj.order !== "string" || !VALID_SORT_ORDER.has(obj.order)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Sort at index ${index} has invalid order: ${String(obj.order)}. Must be ASC or DESC`);
@@ -8164,7 +8211,7 @@ function parseSort(raw, index) {
8164
8211
  };
8165
8212
  }
8166
8213
  function parsePeriodicReportPeriod(raw) {
8167
- if (!isRecord$1(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport.period must be an object");
8214
+ if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport.period must be an object");
8168
8215
  const obj = raw;
8169
8216
  if (typeof obj.every !== "string" || !VALID_PERIODIC_EVERY.has(obj.every)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has invalid every: ${String(obj.every)}. Must be YEAR, QUARTER, MONTH, WEEK, DAY, or HOUR`);
8170
8217
  const every = obj.every;
@@ -8211,7 +8258,7 @@ function parsePeriodicReportPeriod(raw) {
8211
8258
  };
8212
8259
  }
8213
8260
  function parsePeriodicReport(raw) {
8214
- if (!isRecord$1(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport must be an object");
8261
+ if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport must be an object");
8215
8262
  const obj = raw;
8216
8263
  if (typeof obj.active !== "boolean") throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport.active must be a boolean");
8217
8264
  const period = parsePeriodicReportPeriod(obj.period);
@@ -8221,7 +8268,7 @@ function parsePeriodicReport(raw) {
8221
8268
  };
8222
8269
  }
8223
8270
  function parseReportConfig(raw, reportName) {
8224
- if (!isRecord$1(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Report "${reportName}" must be an object`);
8271
+ if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Report "${reportName}" must be an object`);
8225
8272
  const obj = raw;
8226
8273
  if (typeof obj.chartType !== "string" || !VALID_CHART_TYPES.has(obj.chartType)) throw new BusinessRuleError(ReportErrorCode.RtInvalidChartType, `Report "${reportName}" has invalid chartType: ${String(obj.chartType)}. Must be BAR, COLUMN, PIE, LINE, PIVOT_TABLE, TABLE, AREA, SPLINE, or SPLINE_AREA`);
8227
8274
  let chartMode;
@@ -8260,9 +8307,9 @@ const ReportConfigParser = { parse: (rawText) => {
8260
8307
  } catch (error) {
8261
8308
  throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
8262
8309
  }
8263
- if (!isRecord$1(parsed)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must be a YAML object");
8310
+ if (!isRecord(parsed)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must be a YAML object");
8264
8311
  const obj = parsed;
8265
- if (!isRecord$1(obj.reports)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must have a \"reports\" object");
8312
+ if (!isRecord(obj.reports)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must have a \"reports\" object");
8266
8313
  const rawReports = obj.reports;
8267
8314
  const reports = {};
8268
8315
  for (const [name, value] of Object.entries(rawReports)) reports[name] = parseReportConfig(value, name);
@@ -8408,10 +8455,10 @@ function compareReports(local, remote) {
8408
8455
  if ((local.chartMode ?? "") !== (remote.chartMode ?? "")) diffs.push(`chartMode: ${remote.chartMode ?? "(unset)"} -> ${local.chartMode ?? "(unset)"}`);
8409
8456
  if (local.index !== remote.index) diffs.push(`index: ${remote.index} -> ${local.index}`);
8410
8457
  if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
8411
- if (!deepEqual$1(local.groups, remote.groups)) diffs.push("groups changed");
8412
- if (!deepEqual$1(local.aggregations, remote.aggregations)) diffs.push("aggregations changed");
8413
- if (!deepEqual$1(local.sorts, remote.sorts)) diffs.push("sorts changed");
8414
- if (!deepEqual$1(local.periodicReport ?? null, remote.periodicReport ?? null)) diffs.push("periodicReport changed");
8458
+ if (!deepEqual(local.groups, remote.groups)) diffs.push("groups changed");
8459
+ if (!deepEqual(local.aggregations, remote.aggregations)) diffs.push("aggregations changed");
8460
+ if (!deepEqual(local.sorts, remote.sorts)) diffs.push("sorts changed");
8461
+ if (!deepEqual(local.periodicReport ?? null, remote.periodicReport ?? null)) diffs.push("periodicReport changed");
8415
8462
  return diffs;
8416
8463
  }
8417
8464
  const ReportDiffDetector = { detect: (local, remote) => {
@@ -8539,26 +8586,26 @@ function isMapEqual(a, b) {
8539
8586
  }
8540
8587
  function isPropertiesEqual(a, b) {
8541
8588
  if (a.type === "SUBTABLE" && b.type === "SUBTABLE") return isMapEqual(a.properties.fields, b.properties.fields);
8542
- if (a.type === "REFERENCE_TABLE" && b.type === "REFERENCE_TABLE") return deepEqual$1(a.properties.referenceTable, b.properties.referenceTable);
8543
- return deepEqual$1(a.properties, b.properties);
8589
+ if (a.type === "REFERENCE_TABLE" && b.type === "REFERENCE_TABLE") return deepEqual(a.properties.referenceTable, b.properties.referenceTable);
8590
+ return deepEqual(a.properties, b.properties);
8544
8591
  }
8545
8592
  function isFieldEqual(a, b) {
8546
8593
  if (a.type !== b.type) return false;
8547
8594
  if (a.label !== b.label) return false;
8548
8595
  if (a.code !== b.code) return false;
8549
- if (Boolean(a.noLabel) !== Boolean(b.noLabel)) return false;
8596
+ if ((a.noLabel ?? false) !== (b.noLabel ?? false)) return false;
8550
8597
  return isPropertiesEqual(a, b);
8551
8598
  }
8552
8599
  function describeChanges$1(before, after) {
8553
8600
  const changes = [];
8554
8601
  if (before.type !== after.type) changes.push(`type: ${before.type} -> ${after.type}`);
8555
8602
  if (before.label !== after.label) changes.push(`label: ${before.label} -> ${after.label}`);
8556
- if (Boolean(before.noLabel) !== Boolean(after.noLabel)) changes.push(`noLabel: ${before.noLabel ?? false} -> ${after.noLabel ?? false}`);
8603
+ if ((before.noLabel ?? false) !== (after.noLabel ?? false)) changes.push(`noLabel: ${before.noLabel ?? false} -> ${after.noLabel ?? false}`);
8557
8604
  if (!isPropertiesEqual(before, after)) changes.push("properties changed");
8558
8605
  return changes.length > 0 ? changes.join(", ") : "no visible changes";
8559
8606
  }
8560
8607
  function isLayoutEqual(a, b) {
8561
- return deepEqual$1(a, b);
8608
+ return deepEqual(a, b);
8562
8609
  }
8563
8610
  const DiffDetector = {
8564
8611
  detectLayoutChanges: (schemaLayout, currentLayout) => {
@@ -8595,6 +8642,16 @@ const DiffDetector = {
8595
8642
  }
8596
8643
  };
8597
8644
 
8645
+ //#endregion
8646
+ //#region src/core/domain/formSchema/entity.ts
8647
+ const Schema = { create: (fields, layout) => {
8648
+ if (fields.size === 0) throw new BusinessRuleError(FormSchemaErrorCode.FsEmptyFields, "Schema must have at least one field");
8649
+ return {
8650
+ fields,
8651
+ layout
8652
+ };
8653
+ } };
8654
+
8598
8655
  //#endregion
8599
8656
  //#region src/core/domain/formSchema/services/schemaParser.ts
8600
8657
  const VALID_UNIT_POSITIONS = new Set(["BEFORE", "AFTER"]);
@@ -8614,7 +8671,7 @@ const VALID_LINK_PROTOCOLS = new Set([
8614
8671
  "MAIL"
8615
8672
  ]);
8616
8673
  function validateEnumProperty(fieldCode, propName, value, validValues) {
8617
- if (value !== void 0 && !validValues.has(value)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Invalid ${propName} "${String(value)}" for field "${fieldCode}". Expected one of: ${[...validValues].join(", ")}`);
8674
+ if (value !== void 0 && (typeof value !== "string" || !validValues.has(value))) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Invalid ${propName} "${String(value)}" for field "${fieldCode}". Expected one of: ${[...validValues].join(", ")}`);
8618
8675
  }
8619
8676
  function validateFieldProperties(code, fieldType, properties) {
8620
8677
  switch (fieldType) {
@@ -8683,17 +8740,38 @@ const LAYOUT_ATTRIBUTES = new Set(["size"]);
8683
8740
  const DECORATION_ATTRIBUTES = new Set(["elementId"]);
8684
8741
  const GROUP_ATTRIBUTES = new Set(["openGroup", "layout"]);
8685
8742
  const SUBTABLE_ATTRIBUTES = new Set(["fields"]);
8743
+ /**
8744
+ * Parses a raw size object into an ElementSize.
8745
+ * Returns undefined when no size properties are present, treating an empty
8746
+ * object the same as absent — layout elements without explicit sizing should
8747
+ * not carry a redundant empty size object.
8748
+ */
8686
8749
  function parseSize(raw) {
8687
- if (!isRecord$1(raw)) return void 0;
8750
+ if (!isRecord(raw)) return void 0;
8688
8751
  const obj = raw;
8752
+ if (obj.width === void 0 && obj.height === void 0 && obj.innerHeight === void 0) return;
8689
8753
  return {
8690
8754
  ...obj.width !== void 0 ? { width: String(obj.width) } : {},
8691
8755
  ...obj.height !== void 0 ? { height: String(obj.height) } : {},
8692
8756
  ...obj.innerHeight !== void 0 ? { innerHeight: String(obj.innerHeight) } : {}
8693
8757
  };
8694
8758
  }
8695
- function normalizePropertyValue(value) {
8759
+ const BOOLEAN_PROPERTIES = new Set([
8760
+ "required",
8761
+ "unique",
8762
+ "digit",
8763
+ "hideExpression",
8764
+ "defaultNowValue",
8765
+ "openGroup"
8766
+ ]);
8767
+ function normalizePropertyValue(key, value) {
8768
+ if (typeof value === "boolean") return value;
8696
8769
  if (typeof value === "number") return String(value);
8770
+ if (BOOLEAN_PROPERTIES.has(key) && typeof value === "string") {
8771
+ if (value === "true") return true;
8772
+ if (value === "false") return false;
8773
+ throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Invalid boolean string "${value}" for property "${key}". Expected "true" or "false"`);
8774
+ }
8697
8775
  return value;
8698
8776
  }
8699
8777
  function extractProperties(raw) {
@@ -8704,7 +8782,7 @@ function extractProperties(raw) {
8704
8782
  if (DECORATION_ATTRIBUTES.has(key)) continue;
8705
8783
  if (GROUP_ATTRIBUTES.has(key)) continue;
8706
8784
  if (SUBTABLE_ATTRIBUTES.has(key)) continue;
8707
- properties[key] = normalizePropertyValue(value);
8785
+ properties[key] = normalizePropertyValue(key, value);
8708
8786
  }
8709
8787
  return properties;
8710
8788
  }
@@ -8822,10 +8900,10 @@ function parseFieldDefinitionFromFlat(raw) {
8822
8900
  };
8823
8901
  }
8824
8902
  if (fieldType === "REFERENCE_TABLE") {
8825
- if (!isRecord$1(raw.referenceTable)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have a "referenceTable" property`);
8903
+ if (!isRecord(raw.referenceTable)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have a "referenceTable" property`);
8826
8904
  const refTable = raw.referenceTable;
8827
- if (!isRecord$1(refTable.relatedApp)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.relatedApp"`);
8828
- if (!isRecord$1(refTable.condition)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.condition"`);
8905
+ if (!isRecord(refTable.relatedApp)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.relatedApp"`);
8906
+ if (!isRecord(refTable.condition)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.condition"`);
8829
8907
  if (!Array.isArray(refTable.displayFields)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.displayFields" array`);
8830
8908
  const condition = refTable.condition;
8831
8909
  const displayFields = refTable.displayFields.map((f) => FieldCode.create(f));
@@ -8900,6 +8978,7 @@ function parseLayoutElement(raw) {
8900
8978
  }
8901
8979
  function parseLayoutRow(raw) {
8902
8980
  if (raw.type !== "ROW") throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidLayoutStructure, `Expected layout row type "ROW", got "${String(raw.type)}"`);
8981
+ if (raw.fields !== void 0 && !Array.isArray(raw.fields)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidLayoutStructure, `ROW "fields" must be an array, got ${typeof raw.fields}`);
8903
8982
  return {
8904
8983
  type: "ROW",
8905
8984
  fields: (Array.isArray(raw.fields) ? raw.fields : []).map(parseLayoutElement)
@@ -8939,7 +9018,7 @@ function parseLayoutItem(raw) {
8939
9018
  const label = String(raw.label ?? "");
8940
9019
  const noLabel = typeof raw.noLabel === "boolean" ? raw.noLabel : void 0;
8941
9020
  const openGroup = typeof raw.openGroup === "boolean" ? raw.openGroup : void 0;
8942
- const rawLayout = Array.isArray(raw.layout) ? raw.layout.filter(isRecord$1) : [];
9021
+ const rawLayout = Array.isArray(raw.layout) ? raw.layout.filter(isRecord) : [];
8943
9022
  let groupFields = /* @__PURE__ */ new Map();
8944
9023
  const layout = [];
8945
9024
  for (const r of rawLayout) {
@@ -9024,22 +9103,21 @@ const SchemaParser = { parse: (rawText) => {
9024
9103
  } catch {
9025
9104
  throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaFormat, "Schema text is not valid YAML/JSON");
9026
9105
  }
9027
- if (!isRecord$1(parsed)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, "Schema must be an object");
9106
+ if (!isRecord(parsed)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, "Schema must be an object");
9028
9107
  const obj = parsed;
9029
9108
  if ("fields" in obj && !("layout" in obj)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, "\"fields\" key detected. Schema format has changed. Please use \"capture\" to generate a new format schema.");
9030
9109
  if (!("layout" in obj) || !Array.isArray(obj.layout)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidLayoutStructure, "Schema must have a \"layout\" array");
9031
- const rawLayout = obj.layout.filter(isRecord$1);
9110
+ const rawLayout = obj.layout;
9032
9111
  let fieldMap = /* @__PURE__ */ new Map();
9033
9112
  const layout = [];
9034
- for (const rawItem of rawLayout) {
9113
+ for (let i = 0; i < rawLayout.length; i++) {
9114
+ const rawItem = rawLayout[i];
9115
+ if (!isRecord(rawItem)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidLayoutStructure, `Layout item at index ${i} must be an object`);
9035
9116
  const result = parseLayoutItem(rawItem);
9036
9117
  layout.push(result.item);
9037
9118
  fieldMap = mergeFieldMaps(fieldMap, result.fields);
9038
9119
  }
9039
- return {
9040
- fields: fieldMap,
9041
- layout
9042
- };
9120
+ return Schema.create(fieldMap, layout);
9043
9121
  } };
9044
9122
 
9045
9123
  //#endregion
@@ -9863,17 +9941,17 @@ function normalizeValue(value) {
9863
9941
  if (typeof first === "string") return value;
9864
9942
  if (typeof first === "number") return value.map(String);
9865
9943
  if (typeof first === "object" && first !== null && "code" in first && Object.keys(first).length === 1) return value;
9866
- return value.filter(isRecord$1).map((row) => {
9944
+ return value.filter(isRecord).map((row) => {
9867
9945
  const normalized = {};
9868
9946
  for (const [k, v] of Object.entries(row)) if (Array.isArray(v)) normalized[k] = v.map(String);
9869
9947
  else normalized[k] = v === null || v === void 0 ? "" : String(v);
9870
9948
  return normalized;
9871
9949
  });
9872
9950
  }
9873
- return String(value);
9951
+ throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Unsupported value type: ${typeof value}`);
9874
9952
  }
9875
9953
  function parseRecord(raw, index) {
9876
- if (!isRecord$1(raw)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Record at index ${index} must be an object`);
9954
+ if (!isRecord(raw)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Record at index ${index} must be an object`);
9877
9955
  const record = {};
9878
9956
  for (const [key, value] of Object.entries(raw)) record[key] = normalizeValue(value);
9879
9957
  return record;
@@ -9886,7 +9964,7 @@ const SeedParser = { parse: (rawText) => {
9886
9964
  } catch {
9887
9965
  throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedYaml, "Seed text is not valid YAML");
9888
9966
  }
9889
- if (!isRecord$1(parsed)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, "Seed data must be an object");
9967
+ if (!isRecord(parsed)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, "Seed data must be an object");
9890
9968
  const obj = parsed;
9891
9969
  const key = "key" in obj && typeof obj.key === "string" ? UpsertKey.create(obj.key) : null;
9892
9970
  if (!("records" in obj) || !Array.isArray(obj.records)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, "Seed data must have a \"records\" array");
@@ -9895,8 +9973,9 @@ const SeedParser = { parse: (rawText) => {
9895
9973
  for (let i = 0; i < obj.records.length; i++) {
9896
9974
  const record = parseRecord(obj.records[i], i);
9897
9975
  if (key !== null) {
9898
- if (!(key in record)) throw new BusinessRuleError(SeedDataErrorCode.SdMissingKeyField, `Record at index ${i} is missing key field "${key}"`);
9899
- const keyValue = record[key];
9976
+ const keyField = key;
9977
+ if (!(keyField in record)) throw new BusinessRuleError(SeedDataErrorCode.SdMissingKeyField, `Record at index ${i} is missing key field "${key}"`);
9978
+ const keyValue = record[keyField];
9900
9979
  if (typeof keyValue !== "string") throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Key field "${key}" value at index ${i} must be a string`);
9901
9980
  if (seenKeys.has(keyValue)) throw new BusinessRuleError(SeedDataErrorCode.SdDuplicateKeyValue, `Duplicate key value "${keyValue}" at index ${i}`);
9902
9981
  seenKeys.add(keyValue);
@@ -9911,30 +9990,6 @@ const SeedParser = { parse: (rawText) => {
9911
9990
 
9912
9991
  //#endregion
9913
9992
  //#region src/core/domain/seedData/services/upsertPlanner.ts
9914
- function deepEqual(a, b) {
9915
- if (typeof a === "string" && typeof b === "string") return a === b;
9916
- if (Array.isArray(a) && Array.isArray(b)) {
9917
- if (a.length !== b.length) return false;
9918
- for (let i = 0; i < a.length; i++) {
9919
- const itemA = a[i];
9920
- const itemB = b[i];
9921
- if (typeof itemA === "string" && typeof itemB === "string") {
9922
- if (itemA !== itemB) return false;
9923
- continue;
9924
- }
9925
- if (isRecord$1(itemA) && isRecord$1(itemB)) {
9926
- const keysA = Object.keys(itemA);
9927
- const keysB = Object.keys(itemB);
9928
- if (keysA.length !== keysB.length) return false;
9929
- for (const key of keysA) if (String(itemA[key] ?? "") !== String(itemB[key] ?? "")) return false;
9930
- continue;
9931
- }
9932
- if (String(itemA) !== String(itemB)) return false;
9933
- }
9934
- return true;
9935
- }
9936
- return String(a) === String(b);
9937
- }
9938
9993
  function recordsEqual(seed, existing, keyField) {
9939
9994
  const seedKeys = Object.keys(seed).filter((k) => k !== keyField);
9940
9995
  for (const key of seedKeys) {
@@ -10210,7 +10265,7 @@ const VALID_ROUNDING_MODES = new Set([
10210
10265
  "DOWN"
10211
10266
  ]);
10212
10267
  function parseIcon(raw) {
10213
- if (!isRecord$1(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must be an object with \"type\" and \"key\" properties");
10268
+ if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must be an object with \"type\" and \"key\" properties");
10214
10269
  const obj = raw;
10215
10270
  if (typeof obj.type !== "string" || !VALID_ICON_TYPES.has(obj.type)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidIconType, `icon.type must be PRESET or FILE, got: ${String(obj.type)}`);
10216
10271
  if (typeof obj.key !== "string" || obj.key.length === 0) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must have a non-empty \"key\" property");
@@ -10220,7 +10275,7 @@ function parseIcon(raw) {
10220
10275
  };
10221
10276
  }
10222
10277
  function parseTitleField(raw) {
10223
- if (!isRecord$1(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "titleField must be an object with \"selectionMode\" property");
10278
+ if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "titleField must be an object with \"selectionMode\" property");
10224
10279
  const obj = raw;
10225
10280
  if (typeof obj.selectionMode !== "string" || !VALID_SELECTION_MODES.has(obj.selectionMode)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, `titleField.selectionMode must be AUTO or MANUAL, got: ${String(obj.selectionMode)}`);
10226
10281
  const result = { selectionMode: obj.selectionMode };
@@ -10234,7 +10289,7 @@ function parseTitleField(raw) {
10234
10289
  return result;
10235
10290
  }
10236
10291
  function parseNumberPrecision(raw) {
10237
- if (!isRecord$1(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision must be an object");
10292
+ if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision must be an object");
10238
10293
  const obj = raw;
10239
10294
  if (typeof obj.digits !== "number") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision.digits must be a number");
10240
10295
  if (typeof obj.decimalPlaces !== "number") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision.decimalPlaces must be a number");
@@ -10253,7 +10308,7 @@ const GeneralSettingsConfigParser = { parse: (rawText) => {
10253
10308
  } catch (error) {
10254
10309
  throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
10255
10310
  }
10256
- if (!isRecord$1(parsed)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "Config must be a YAML object");
10311
+ if (!isRecord(parsed)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "Config must be a YAML object");
10257
10312
  const obj = parsed;
10258
10313
  let name;
10259
10314
  if (obj.name !== void 0 && obj.name !== null) {
@@ -10473,7 +10528,7 @@ function compareConfigs(local, remote) {
10473
10528
  });
10474
10529
  }
10475
10530
  function compareDeepEqual(field, l, r) {
10476
- if (!deepEqual$1(l, r)) entries.push({
10531
+ if (!deepEqual(l, r)) entries.push({
10477
10532
  type: "modified",
10478
10533
  field,
10479
10534
  details: `${field} changed`
@@ -10539,7 +10594,7 @@ var settings_default = define({
10539
10594
  //#endregion
10540
10595
  //#region src/core/domain/view/services/configParser.ts
10541
10596
  function parseViewConfig(name, raw) {
10542
- if (!isRecord$1(raw)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, `View "${name}" must be an object`);
10597
+ if (!isRecord(raw)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, `View "${name}" must be an object`);
10543
10598
  const obj = raw;
10544
10599
  if (typeof obj.type !== "string" || !VALID_VIEW_TYPES.has(obj.type)) throw new BusinessRuleError(ViewErrorCode.VwInvalidViewType, `View "${name}" has invalid type: ${String(obj.type)}. Must be LIST, CALENDAR, or CUSTOM`);
10545
10600
  return {
@@ -10569,9 +10624,9 @@ const ViewConfigParser = { parse: (rawText) => {
10569
10624
  } catch (error) {
10570
10625
  throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
10571
10626
  }
10572
- if (!isRecord$1(parsed)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must be a YAML object");
10627
+ if (!isRecord(parsed)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must be a YAML object");
10573
10628
  const obj = parsed;
10574
- if (!isRecord$1(obj.views)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must have a \"views\" object");
10629
+ if (!isRecord(obj.views)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must have a \"views\" object");
10575
10630
  const viewsObj = obj.views;
10576
10631
  const views = {};
10577
10632
  for (const [name, value] of Object.entries(viewsObj)) {
@@ -10733,7 +10788,7 @@ function describeChanges(local, remote) {
10733
10788
  if ((local.html ?? "") !== (remote.html ?? "")) changes.push("html changed");
10734
10789
  if ((local.pager ?? false) !== (remote.pager ?? false)) changes.push(`pager: ${String(remote.pager ?? false)} -> ${String(local.pager ?? false)}`);
10735
10790
  if ((local.device ?? "") !== (remote.device ?? "")) changes.push("device changed");
10736
- if (!deepEqual$1(local.fields ?? [], remote.fields ?? [])) changes.push("fields changed");
10791
+ if (!deepEqual(local.fields ?? [], remote.fields ?? [])) changes.push("fields changed");
10737
10792
  return changes;
10738
10793
  }
10739
10794
  const ViewDiffDetector = { detect: (localViews, remoteViews) => {