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 +198 -143
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
354
|
-
if (!isRecord
|
|
355
|
-
return Object.values(value.value).every((cell) => isRecord
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
437
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must be a YAML object");
|
|
435
438
|
const obj = parsed;
|
|
436
|
-
if (!isRecord
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7477
|
-
const rawStates = isRecord
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
8310
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must be a YAML object");
|
|
8264
8311
|
const obj = parsed;
|
|
8265
|
-
if (!isRecord
|
|
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
|
|
8412
|
-
if (!deepEqual
|
|
8413
|
-
if (!deepEqual
|
|
8414
|
-
if (!deepEqual
|
|
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
|
|
8543
|
-
return deepEqual
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
8828
|
-
if (!isRecord
|
|
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
|
|
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
|
|
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
|
|
9110
|
+
const rawLayout = obj.layout;
|
|
9032
9111
|
let fieldMap = /* @__PURE__ */ new Map();
|
|
9033
9112
|
const layout = [];
|
|
9034
|
-
for (
|
|
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
|
|
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
|
-
|
|
9951
|
+
throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Unsupported value type: ${typeof value}`);
|
|
9874
9952
|
}
|
|
9875
9953
|
function parseRecord(raw, index) {
|
|
9876
|
-
if (!isRecord
|
|
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
|
|
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
|
-
|
|
9899
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
10627
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must be a YAML object");
|
|
10573
10628
|
const obj = parsed;
|
|
10574
|
-
if (!isRecord
|
|
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
|
|
10791
|
+
if (!deepEqual(local.fields ?? [], remote.fields ?? [])) changes.push("fields changed");
|
|
10737
10792
|
return changes;
|
|
10738
10793
|
}
|
|
10739
10794
|
const ViewDiffDetector = { detect: (localViews, remoteViews) => {
|