kintone-migrator 0.24.0 → 0.24.2
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 +698 -639
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -25,7 +25,8 @@ const ActionErrorCode = {
|
|
|
25
25
|
AcInvalidConfigStructure: "AC_INVALID_CONFIG_STRUCTURE",
|
|
26
26
|
AcInvalidSrcType: "AC_INVALID_SRC_TYPE",
|
|
27
27
|
AcInvalidEntityType: "AC_INVALID_ENTITY_TYPE",
|
|
28
|
-
AcEmptyActionName: "AC_EMPTY_ACTION_NAME"
|
|
28
|
+
AcEmptyActionName: "AC_EMPTY_ACTION_NAME",
|
|
29
|
+
AcDuplicateIndex: "AC_DUPLICATE_INDEX"
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
//#endregion
|
|
@@ -76,13 +77,15 @@ const FieldPermissionErrorCode = {
|
|
|
76
77
|
//#region src/core/domain/formSchema/errorCode.ts
|
|
77
78
|
const FormSchemaErrorCode = {
|
|
78
79
|
FsEmptyFieldCode: "FS_EMPTY_FIELD_CODE",
|
|
80
|
+
FsInvalidFieldCode: "FS_INVALID_FIELD_CODE",
|
|
79
81
|
FsEmptySchemaText: "FS_EMPTY_SCHEMA_TEXT",
|
|
80
82
|
FsInvalidSchemaFormat: "FS_INVALID_SCHEMA_FORMAT",
|
|
81
83
|
FsInvalidSchemaStructure: "FS_INVALID_SCHEMA_STRUCTURE",
|
|
82
84
|
FsDuplicateFieldCode: "FS_DUPLICATE_FIELD_CODE",
|
|
83
85
|
FsInvalidFieldType: "FS_INVALID_FIELD_TYPE",
|
|
84
86
|
FsInvalidLayoutStructure: "FS_INVALID_LAYOUT_STRUCTURE",
|
|
85
|
-
FsInvalidDecorationElement: "FS_INVALID_DECORATION_ELEMENT"
|
|
87
|
+
FsInvalidDecorationElement: "FS_INVALID_DECORATION_ELEMENT",
|
|
88
|
+
FsEmptyFields: "FS_EMPTY_FIELDS"
|
|
86
89
|
};
|
|
87
90
|
|
|
88
91
|
//#endregion
|
|
@@ -104,7 +107,9 @@ const NotificationErrorCode = {
|
|
|
104
107
|
NtInvalidEntityType: "NT_INVALID_ENTITY_TYPE",
|
|
105
108
|
NtEmptyEntityCode: "NT_EMPTY_ENTITY_CODE",
|
|
106
109
|
NtMissingRequiredField: "NT_MISSING_REQUIRED_FIELD",
|
|
107
|
-
NtConflictingTimingFields: "NT_CONFLICTING_TIMING_FIELDS"
|
|
110
|
+
NtConflictingTimingFields: "NT_CONFLICTING_TIMING_FIELDS",
|
|
111
|
+
NtInvalidHoursLater: "NT_INVALID_HOURS_LATER",
|
|
112
|
+
NtInvalidDaysLater: "NT_INVALID_DAYS_LATER"
|
|
108
113
|
};
|
|
109
114
|
|
|
110
115
|
//#endregion
|
|
@@ -113,7 +118,8 @@ const PluginErrorCode = {
|
|
|
113
118
|
PlEmptyConfigText: "PL_EMPTY_CONFIG_TEXT",
|
|
114
119
|
PlInvalidConfigYaml: "PL_INVALID_CONFIG_YAML",
|
|
115
120
|
PlInvalidConfigStructure: "PL_INVALID_CONFIG_STRUCTURE",
|
|
116
|
-
PlEmptyPluginId: "PL_EMPTY_PLUGIN_ID"
|
|
121
|
+
PlEmptyPluginId: "PL_EMPTY_PLUGIN_ID",
|
|
122
|
+
PlDuplicatePluginId: "PL_DUPLICATE_PLUGIN_ID"
|
|
117
123
|
};
|
|
118
124
|
|
|
119
125
|
//#endregion
|
|
@@ -135,6 +141,7 @@ const ProjectConfigErrorCode = {
|
|
|
135
141
|
PcEmptyApps: "PC_EMPTY_APPS",
|
|
136
142
|
PcEmptyAppId: "PC_EMPTY_APP_ID",
|
|
137
143
|
PcEmptyAppName: "PC_EMPTY_APP_NAME",
|
|
144
|
+
PcInvalidAppName: "PC_INVALID_APP_NAME",
|
|
138
145
|
PcInvalidConfigStructure: "PC_INVALID_CONFIG_STRUCTURE",
|
|
139
146
|
PcInvalidAuthConfig: "PC_INVALID_AUTH_CONFIG"
|
|
140
147
|
};
|
|
@@ -181,7 +188,8 @@ const ViewErrorCode = {
|
|
|
181
188
|
VwInvalidConfigStructure: "VW_INVALID_CONFIG_STRUCTURE",
|
|
182
189
|
VwInvalidViewType: "VW_INVALID_VIEW_TYPE",
|
|
183
190
|
VwInvalidDeviceType: "VW_INVALID_DEVICE_TYPE",
|
|
184
|
-
VwEmptyViewName: "VW_EMPTY_VIEW_NAME"
|
|
191
|
+
VwEmptyViewName: "VW_EMPTY_VIEW_NAME",
|
|
192
|
+
VwInvalidIndex: "VW_INVALID_INDEX"
|
|
185
193
|
};
|
|
186
194
|
|
|
187
195
|
//#endregion
|
|
@@ -329,7 +337,7 @@ function isSystemError(error) {
|
|
|
329
337
|
* Excludes built-in types (Date, RegExp, Map, Set) that are technically
|
|
330
338
|
* objects but should not be treated as string-keyed records.
|
|
331
339
|
*/
|
|
332
|
-
function isRecord
|
|
340
|
+
function isRecord(value) {
|
|
333
341
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof Map) && !(value instanceof Set);
|
|
334
342
|
}
|
|
335
343
|
|
|
@@ -343,79 +351,100 @@ function isRecord$1(value) {
|
|
|
343
351
|
* Narrows `unknown` to `{ code: string }`.
|
|
344
352
|
*/
|
|
345
353
|
function hasCode(value) {
|
|
346
|
-
return isRecord
|
|
354
|
+
return isRecord(value) && typeof value.code === "string";
|
|
347
355
|
}
|
|
348
356
|
/**
|
|
349
357
|
* Narrows `unknown` to `{ value: Record<string, { value: unknown }> }`.
|
|
350
358
|
* Used when processing kintone subtable rows.
|
|
351
359
|
*/
|
|
352
360
|
function isKintoneSubtableRow(value) {
|
|
353
|
-
if (!isRecord
|
|
354
|
-
if (!isRecord
|
|
355
|
-
return Object.values(value.value).every((cell) => isRecord
|
|
361
|
+
if (!isRecord(value)) return false;
|
|
362
|
+
if (!isRecord(value.value)) return false;
|
|
363
|
+
return Object.values(value.value).every((cell) => isRecord(cell) && "value" in cell);
|
|
356
364
|
}
|
|
357
365
|
/**
|
|
358
366
|
* Narrows `unknown` to `{ type?: string }`.
|
|
359
367
|
*/
|
|
360
368
|
function hasOptionalType(value) {
|
|
361
|
-
if (!isRecord
|
|
369
|
+
if (!isRecord(value)) return false;
|
|
362
370
|
return value.type === void 0 || typeof value.type === "string";
|
|
363
371
|
}
|
|
364
372
|
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/core/domain/services/yamlConfigParser.ts
|
|
375
|
+
function parseYamlConfig(rawText, errorCodes, domainLabel) {
|
|
376
|
+
if (rawText.trim().length === 0) throw new BusinessRuleError(errorCodes.emptyConfigText, `${domainLabel} config text is empty`);
|
|
377
|
+
let parsed;
|
|
378
|
+
try {
|
|
379
|
+
parsed = parse(rawText);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
throw new BusinessRuleError(errorCodes.invalidConfigYaml, `Failed to parse ${domainLabel} YAML: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
382
|
+
}
|
|
383
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(errorCodes.invalidConfigStructure, `${domainLabel} config must be a YAML object`);
|
|
384
|
+
return parsed;
|
|
385
|
+
}
|
|
386
|
+
|
|
365
387
|
//#endregion
|
|
366
388
|
//#region src/core/domain/action/valueObject.ts
|
|
367
|
-
const
|
|
368
|
-
const
|
|
389
|
+
const SRC_TYPES = ["FIELD", "RECORD_URL"];
|
|
390
|
+
const VALID_SRC_TYPES = new Set(SRC_TYPES);
|
|
391
|
+
function isActionMappingSrcType(value) {
|
|
392
|
+
return VALID_SRC_TYPES.has(value);
|
|
393
|
+
}
|
|
394
|
+
const ENTITY_TYPES$1 = [
|
|
369
395
|
"USER",
|
|
370
396
|
"GROUP",
|
|
371
397
|
"ORGANIZATION"
|
|
372
|
-
]
|
|
398
|
+
];
|
|
399
|
+
const VALID_ENTITY_TYPES$9 = new Set(ENTITY_TYPES$1);
|
|
400
|
+
function isActionEntityType(value) {
|
|
401
|
+
return VALID_ENTITY_TYPES$9.has(value);
|
|
402
|
+
}
|
|
373
403
|
|
|
374
404
|
//#endregion
|
|
375
405
|
//#region src/core/domain/action/services/configParser.ts
|
|
376
406
|
function parseDestApp(raw, actionName) {
|
|
377
|
-
if (!isRecord
|
|
378
|
-
const obj = raw;
|
|
407
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" destApp must be an object`);
|
|
379
408
|
const result = {};
|
|
380
|
-
if (
|
|
381
|
-
if (
|
|
409
|
+
if (raw.app !== void 0 && raw.app !== null) result.app = String(raw.app);
|
|
410
|
+
if (raw.code !== void 0 && raw.code !== null) result.code = String(raw.code);
|
|
411
|
+
if (result.app === void 0 && result.code === void 0) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" destApp must have at least "app" or "code" property`);
|
|
382
412
|
return result;
|
|
383
413
|
}
|
|
384
414
|
function parseMapping(raw, index, actionName) {
|
|
385
|
-
if (!isRecord
|
|
386
|
-
|
|
387
|
-
if (typeof
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
...obj.srcField !== void 0 && obj.srcField !== null && typeof obj.srcField === "string" ? { srcField: obj.srcField } : {}
|
|
415
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" mapping at index ${index} must be an object`);
|
|
416
|
+
if (typeof raw.srcType !== "string" || !isActionMappingSrcType(raw.srcType)) throw new BusinessRuleError(ActionErrorCode.AcInvalidSrcType, `Action "${actionName}" mapping at index ${index} has invalid srcType: ${String(raw.srcType)}. Must be FIELD or RECORD_URL`);
|
|
417
|
+
if (typeof raw.destField !== "string" || raw.destField.length === 0) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" mapping at index ${index} must have a non-empty "destField" property`);
|
|
418
|
+
const result = {
|
|
419
|
+
srcType: raw.srcType,
|
|
420
|
+
destField: raw.destField,
|
|
421
|
+
...raw.srcField !== void 0 && raw.srcField !== null && typeof raw.srcField === "string" ? { srcField: raw.srcField } : {}
|
|
393
422
|
};
|
|
423
|
+
if (result.srcType === "FIELD" && result.srcField === void 0) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" mapping at index ${index} with srcType "FIELD" must have a "srcField" property`);
|
|
424
|
+
return result;
|
|
394
425
|
}
|
|
395
426
|
function parseEntity$4(raw, index, actionName) {
|
|
396
|
-
if (!isRecord
|
|
397
|
-
|
|
398
|
-
if (typeof
|
|
399
|
-
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`);
|
|
427
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" entity at index ${index} must be an object`);
|
|
428
|
+
if (typeof raw.type !== "string" || !isActionEntityType(raw.type)) throw new BusinessRuleError(ActionErrorCode.AcInvalidEntityType, `Action "${actionName}" entity at index ${index} has invalid type: ${String(raw.type)}. Must be USER, GROUP, or ORGANIZATION`);
|
|
429
|
+
if (typeof raw.code !== "string" || raw.code.length === 0) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" entity at index ${index} must have a non-empty "code" property`);
|
|
400
430
|
return {
|
|
401
|
-
type:
|
|
402
|
-
code:
|
|
431
|
+
type: raw.type,
|
|
432
|
+
code: raw.code
|
|
403
433
|
};
|
|
404
434
|
}
|
|
405
435
|
function parseActionConfig(raw, actionName) {
|
|
406
|
-
if (!isRecord$1(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must be an object`);
|
|
407
|
-
const obj = raw;
|
|
408
436
|
if (actionName.length === 0) throw new BusinessRuleError(ActionErrorCode.AcEmptyActionName, "Action name (key) must not be empty");
|
|
409
|
-
if (
|
|
410
|
-
if (!
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
437
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must be an object`);
|
|
438
|
+
if (typeof raw.index !== "number" || !Number.isInteger(raw.index) || raw.index < 0) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have a non-negative integer "index" property`);
|
|
439
|
+
if (!isRecord(raw.destApp)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have a "destApp" object`);
|
|
440
|
+
const destApp = parseDestApp(raw.destApp, actionName);
|
|
441
|
+
if (!Array.isArray(raw.mappings)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have a "mappings" array`);
|
|
442
|
+
const mappings = raw.mappings.map((item, i) => parseMapping(item, i, actionName));
|
|
443
|
+
if (!Array.isArray(raw.entities)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, `Action "${actionName}" must have an "entities" array`);
|
|
444
|
+
const entities = raw.entities.map((item, i) => parseEntity$4(item, i, actionName));
|
|
445
|
+
const filterCond = typeof raw.filterCond === "string" ? raw.filterCond : "";
|
|
446
|
+
return {
|
|
447
|
+
index: raw.index,
|
|
419
448
|
name: actionName,
|
|
420
449
|
destApp,
|
|
421
450
|
mappings,
|
|
@@ -424,19 +453,20 @@ function parseActionConfig(raw, actionName) {
|
|
|
424
453
|
};
|
|
425
454
|
}
|
|
426
455
|
const ActionConfigParser = { parse: (rawText) => {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
if (!isRecord$1(parsed)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must be a YAML object");
|
|
435
|
-
const obj = parsed;
|
|
436
|
-
if (!isRecord$1(obj.actions)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must have an \"actions\" object");
|
|
456
|
+
const obj = parseYamlConfig(rawText, {
|
|
457
|
+
emptyConfigText: ActionErrorCode.AcEmptyConfigText,
|
|
458
|
+
invalidConfigYaml: ActionErrorCode.AcInvalidConfigYaml,
|
|
459
|
+
invalidConfigStructure: ActionErrorCode.AcInvalidConfigStructure
|
|
460
|
+
}, "Action");
|
|
461
|
+
if (!isRecord(obj.actions)) throw new BusinessRuleError(ActionErrorCode.AcInvalidConfigStructure, "Config must have an \"actions\" object");
|
|
437
462
|
const rawActions = obj.actions;
|
|
438
463
|
const actions = {};
|
|
439
464
|
for (const [key, value] of Object.entries(rawActions)) actions[key] = parseActionConfig(value, key);
|
|
465
|
+
const seenIndices = /* @__PURE__ */ new Set();
|
|
466
|
+
for (const [key, action] of Object.entries(actions)) {
|
|
467
|
+
if (seenIndices.has(action.index)) throw new BusinessRuleError(ActionErrorCode.AcDuplicateIndex, `Duplicate action index ${action.index} found in action "${key}"`);
|
|
468
|
+
seenIndices.add(action.index);
|
|
469
|
+
}
|
|
440
470
|
return { actions };
|
|
441
471
|
} };
|
|
442
472
|
|
|
@@ -468,7 +498,7 @@ function fromKintoneDestApp(raw) {
|
|
|
468
498
|
return result;
|
|
469
499
|
}
|
|
470
500
|
function fromKintoneMapping(raw) {
|
|
471
|
-
if (!
|
|
501
|
+
if (!isActionMappingSrcType(raw.srcType)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected srcType value from kintone API: ${raw.srcType}`);
|
|
472
502
|
return {
|
|
473
503
|
srcType: raw.srcType,
|
|
474
504
|
destField: raw.destField,
|
|
@@ -476,15 +506,17 @@ function fromKintoneMapping(raw) {
|
|
|
476
506
|
};
|
|
477
507
|
}
|
|
478
508
|
function fromKintoneEntity$4(raw) {
|
|
479
|
-
if (!
|
|
509
|
+
if (!isActionEntityType(raw.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected entity type from kintone API: ${raw.type}`);
|
|
480
510
|
return {
|
|
481
511
|
type: raw.type,
|
|
482
512
|
code: raw.code
|
|
483
513
|
};
|
|
484
514
|
}
|
|
485
515
|
function fromKintoneAction$1(raw) {
|
|
516
|
+
const index = Number(raw.index);
|
|
517
|
+
if (!Number.isFinite(index)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric index from kintone API: ${raw.index}`);
|
|
486
518
|
return {
|
|
487
|
-
index
|
|
519
|
+
index,
|
|
488
520
|
name: raw.name,
|
|
489
521
|
destApp: fromKintoneDestApp(raw.destApp),
|
|
490
522
|
mappings: raw.mappings.map(fromKintoneMapping),
|
|
@@ -662,25 +694,42 @@ function createLocalFileActionStorage(filePath) {
|
|
|
662
694
|
}
|
|
663
695
|
|
|
664
696
|
//#endregion
|
|
665
|
-
//#region src/core/
|
|
666
|
-
const
|
|
697
|
+
//#region src/core/domain/customization/valueObject.ts
|
|
698
|
+
const SCOPES = [
|
|
667
699
|
"ALL",
|
|
668
700
|
"ADMIN",
|
|
669
701
|
"NONE"
|
|
670
|
-
]
|
|
702
|
+
];
|
|
703
|
+
const VALID_SCOPES = new Set(SCOPES);
|
|
704
|
+
function isCustomizationScope(value) {
|
|
705
|
+
return VALID_SCOPES.has(value);
|
|
706
|
+
}
|
|
707
|
+
const RESOURCE_TYPES = ["FILE", "URL"];
|
|
708
|
+
const VALID_RESOURCE_TYPES = new Set(RESOURCE_TYPES);
|
|
709
|
+
function isResourceType(value) {
|
|
710
|
+
return VALID_RESOURCE_TYPES.has(value);
|
|
711
|
+
}
|
|
712
|
+
const DEFAULT_CUSTOMIZATION_SCOPE = "ALL";
|
|
713
|
+
|
|
714
|
+
//#endregion
|
|
715
|
+
//#region src/core/adapters/kintone/customizationConfigurator.ts
|
|
671
716
|
function fromKintoneResource(raw) {
|
|
672
|
-
if (raw.type === "FILE"
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
717
|
+
if (raw.type === "FILE") {
|
|
718
|
+
if (!raw.file) throw new SystemError(SystemErrorCode.ExternalApiError, "FILE resource from kintone API is missing file metadata");
|
|
719
|
+
return {
|
|
720
|
+
type: "FILE",
|
|
721
|
+
file: {
|
|
722
|
+
fileKey: raw.file.fileKey,
|
|
723
|
+
name: raw.file.name,
|
|
724
|
+
contentType: raw.file.contentType,
|
|
725
|
+
size: raw.file.size
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
if (!raw.url) throw new SystemError(SystemErrorCode.ExternalApiError, "URL resource from kintone API is missing url property");
|
|
681
730
|
return {
|
|
682
731
|
type: "URL",
|
|
683
|
-
url: raw.url
|
|
732
|
+
url: raw.url
|
|
684
733
|
};
|
|
685
734
|
}
|
|
686
735
|
function fromKintoneResourceList(raw) {
|
|
@@ -711,7 +760,7 @@ var KintoneCustomizationConfigurator = class {
|
|
|
711
760
|
preview: true
|
|
712
761
|
});
|
|
713
762
|
const rawScope = String(response.scope);
|
|
714
|
-
if (!
|
|
763
|
+
if (!isCustomizationScope(rawScope)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected scope value from kintone API: ${rawScope}`);
|
|
715
764
|
return {
|
|
716
765
|
scope: rawScope,
|
|
717
766
|
desktop: {
|
|
@@ -791,10 +840,40 @@ var KintoneFileUploader = class {
|
|
|
791
840
|
}
|
|
792
841
|
};
|
|
793
842
|
|
|
843
|
+
//#endregion
|
|
844
|
+
//#region src/lib/charValidation.ts
|
|
845
|
+
/** Returns true if the string contains any control characters (0x00–0x1f or 0x7f). */
|
|
846
|
+
function hasControlChars(s) {
|
|
847
|
+
for (let i = 0; i < s.length; i++) {
|
|
848
|
+
const ch = s.charCodeAt(i);
|
|
849
|
+
if (ch <= 31 || ch === 127) return true;
|
|
850
|
+
}
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
/** Replaces control characters (0x00–0x1f, 0x7f) with escaped `\\xNN` representation for safe display. */
|
|
854
|
+
function sanitizeForDisplay(s) {
|
|
855
|
+
let result = "";
|
|
856
|
+
for (let i = 0; i < s.length; i++) {
|
|
857
|
+
const ch = s.charCodeAt(i);
|
|
858
|
+
if (ch <= 31 || ch === 127) result += `\\x${ch.toString(16).padStart(2, "0")}`;
|
|
859
|
+
else result += s[i];
|
|
860
|
+
}
|
|
861
|
+
return result;
|
|
862
|
+
}
|
|
863
|
+
|
|
794
864
|
//#endregion
|
|
795
865
|
//#region src/core/domain/formSchema/valueObject.ts
|
|
866
|
+
function hasInvalidFieldCodeChars(code) {
|
|
867
|
+
if (hasControlChars(code)) return true;
|
|
868
|
+
for (let i = 0; i < code.length; i++) {
|
|
869
|
+
const c = code[i];
|
|
870
|
+
if (c === "/" || c === "\\") return true;
|
|
871
|
+
}
|
|
872
|
+
return false;
|
|
873
|
+
}
|
|
796
874
|
const FieldCode = { create: (code) => {
|
|
797
875
|
if (code.length === 0) throw new BusinessRuleError(FormSchemaErrorCode.FsEmptyFieldCode, "Field code cannot be empty");
|
|
876
|
+
if (hasInvalidFieldCodeChars(code)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidFieldCode, `Field code "${sanitizeForDisplay(code)}" contains invalid characters`);
|
|
798
877
|
return code;
|
|
799
878
|
} };
|
|
800
879
|
|
|
@@ -1648,16 +1727,31 @@ async function executeMultiApp(plan, executor) {
|
|
|
1648
1727
|
|
|
1649
1728
|
//#endregion
|
|
1650
1729
|
//#region src/core/domain/projectConfig/valueObject.ts
|
|
1730
|
+
const INVALID_APP_NAME_CHARS = new Set([
|
|
1731
|
+
"/",
|
|
1732
|
+
"\\",
|
|
1733
|
+
":",
|
|
1734
|
+
"*",
|
|
1735
|
+
"?",
|
|
1736
|
+
"\"",
|
|
1737
|
+
"<",
|
|
1738
|
+
">",
|
|
1739
|
+
"|"
|
|
1740
|
+
]);
|
|
1741
|
+
function hasInvalidAppNameChars(name) {
|
|
1742
|
+
if (hasControlChars(name)) return true;
|
|
1743
|
+
for (let i = 0; i < name.length; i++) if (INVALID_APP_NAME_CHARS.has(name[i])) return true;
|
|
1744
|
+
return false;
|
|
1745
|
+
}
|
|
1651
1746
|
const AppName = { create: (name) => {
|
|
1652
1747
|
if (name.length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcEmptyAppName, "App name cannot be empty");
|
|
1748
|
+
if (hasInvalidAppNameChars(name)) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAppName, `App name "${sanitizeForDisplay(name)}" contains invalid characters (path separators or control characters are not allowed)`);
|
|
1749
|
+
if (name === "." || name === "..") throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAppName, `App name "${name}" is not allowed (reserved path component)`);
|
|
1653
1750
|
return name;
|
|
1654
1751
|
} };
|
|
1655
1752
|
|
|
1656
1753
|
//#endregion
|
|
1657
1754
|
//#region src/core/domain/projectConfig/services/configParser.ts
|
|
1658
|
-
function isRecord(value) {
|
|
1659
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1660
|
-
}
|
|
1661
1755
|
function asOptionalString(value) {
|
|
1662
1756
|
return typeof value === "string" ? value : void 0;
|
|
1663
1757
|
}
|
|
@@ -1731,25 +1825,27 @@ function parseAuth(raw) {
|
|
|
1731
1825
|
if (!raw) return void 0;
|
|
1732
1826
|
const apiToken = asOptionalString(raw.apiToken);
|
|
1733
1827
|
if (apiToken !== void 0) {
|
|
1734
|
-
|
|
1828
|
+
const trimmed = apiToken.trim();
|
|
1829
|
+
if (trimmed.length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAuthConfig, "apiToken must not be empty");
|
|
1735
1830
|
return {
|
|
1736
1831
|
type: "apiToken",
|
|
1737
|
-
apiToken
|
|
1832
|
+
apiToken: trimmed
|
|
1738
1833
|
};
|
|
1739
1834
|
}
|
|
1740
1835
|
const username = asOptionalString(raw.username);
|
|
1741
1836
|
const password = asOptionalString(raw.password);
|
|
1742
1837
|
if (username !== void 0 && password !== void 0) {
|
|
1743
|
-
|
|
1838
|
+
const trimmedUsername = username.trim();
|
|
1839
|
+
if (trimmedUsername.length === 0 || password.length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAuthConfig, "username and password must not be empty");
|
|
1744
1840
|
return {
|
|
1745
1841
|
type: "password",
|
|
1746
|
-
username,
|
|
1842
|
+
username: trimmedUsername,
|
|
1747
1843
|
password
|
|
1748
1844
|
};
|
|
1749
1845
|
}
|
|
1750
1846
|
throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAuthConfig, "Auth must have either apiToken or username/password");
|
|
1751
1847
|
}
|
|
1752
|
-
const ConfigParser
|
|
1848
|
+
const ConfigParser = { parse: parseProjectConfig };
|
|
1753
1849
|
|
|
1754
1850
|
//#endregion
|
|
1755
1851
|
//#region src/core/application/projectConfig/loadProjectConfig.ts
|
|
@@ -1765,7 +1861,7 @@ function loadProjectConfig(input) {
|
|
|
1765
1861
|
} catch (cause) {
|
|
1766
1862
|
throw new ValidationError(ValidationErrorCode.InvalidInput, "Invalid YAML syntax in config file", cause);
|
|
1767
1863
|
}
|
|
1768
|
-
return ConfigParser
|
|
1864
|
+
return ConfigParser.parse(raw);
|
|
1769
1865
|
}
|
|
1770
1866
|
|
|
1771
1867
|
//#endregion
|
|
@@ -1804,7 +1900,8 @@ function resolveExecutionOrder(apps) {
|
|
|
1804
1900
|
queue.push(...nextBatch);
|
|
1805
1901
|
}
|
|
1806
1902
|
if (orderedNames.length !== apps.size) {
|
|
1807
|
-
const
|
|
1903
|
+
const orderedSet = new Set(orderedNames);
|
|
1904
|
+
const cycleNodes = [...apps.keys()].filter((name) => !orderedSet.has(name));
|
|
1808
1905
|
throw new BusinessRuleError(ProjectConfigErrorCode.PcCircularDependency, `Circular dependency detected among: ${cycleNodes.join(", ")}`);
|
|
1809
1906
|
}
|
|
1810
1907
|
return { orderedApps: orderedNames.flatMap((name) => {
|
|
@@ -2346,6 +2443,20 @@ var apply_default$12 = define({
|
|
|
2346
2443
|
}
|
|
2347
2444
|
});
|
|
2348
2445
|
|
|
2446
|
+
//#endregion
|
|
2447
|
+
//#region src/core/domain/services/yamlConfigSerializer.ts
|
|
2448
|
+
function serializeToYaml(data) {
|
|
2449
|
+
try {
|
|
2450
|
+
return stringify(data, {
|
|
2451
|
+
lineWidth: 0,
|
|
2452
|
+
defaultKeyType: "PLAIN",
|
|
2453
|
+
defaultStringType: "PLAIN"
|
|
2454
|
+
});
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
throw new BusinessRuleError(BusinessRuleErrorCode.AcInvalidConfigStructure, `Failed to serialize config to YAML: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2349
2460
|
//#endregion
|
|
2350
2461
|
//#region src/core/domain/action/services/configSerializer.ts
|
|
2351
2462
|
function serializeDestApp(destApp) {
|
|
@@ -2382,11 +2493,7 @@ const ActionConfigSerializer = { serialize: (config) => {
|
|
|
2382
2493
|
const actions = {};
|
|
2383
2494
|
for (const [key, value] of Object.entries(config.actions)) actions[key] = serializeActionConfig(value);
|
|
2384
2495
|
serialized.actions = actions;
|
|
2385
|
-
return
|
|
2386
|
-
lineWidth: 0,
|
|
2387
|
-
defaultKeyType: "PLAIN",
|
|
2388
|
-
defaultStringType: "PLAIN"
|
|
2389
|
-
});
|
|
2496
|
+
return serializeToYaml(serialized);
|
|
2390
2497
|
} };
|
|
2391
2498
|
|
|
2392
2499
|
//#endregion
|
|
@@ -2505,7 +2612,7 @@ function deepEqualInner(a, b, seen) {
|
|
|
2505
2612
|
if (objB instanceof Map) return false;
|
|
2506
2613
|
if (objA instanceof Set) return isSetEqual(objA, objB, seen);
|
|
2507
2614
|
if (objB instanceof Set) return false;
|
|
2508
|
-
if (isRecord
|
|
2615
|
+
if (isRecord(objA) && isRecord(objB)) return isRecordEqual(objA, objB, seen);
|
|
2509
2616
|
return false;
|
|
2510
2617
|
}
|
|
2511
2618
|
/**
|
|
@@ -2528,7 +2635,7 @@ function deepEqualInner(a, b, seen) {
|
|
|
2528
2635
|
* (e.g. `a.self = a` vs `b.self = b`) return `false`. This is a conservative
|
|
2529
2636
|
* approach that prevents infinite recursion but may produce false negatives.
|
|
2530
2637
|
*/
|
|
2531
|
-
function deepEqual
|
|
2638
|
+
function deepEqual(a, b) {
|
|
2532
2639
|
return deepEqualInner(a, b, /* @__PURE__ */ new WeakSet());
|
|
2533
2640
|
}
|
|
2534
2641
|
|
|
@@ -2560,43 +2667,55 @@ function buildDiffResult(entries, warnings = []) {
|
|
|
2560
2667
|
};
|
|
2561
2668
|
}
|
|
2562
2669
|
|
|
2670
|
+
//#endregion
|
|
2671
|
+
//#region src/core/domain/services/recordDiffDetector.ts
|
|
2672
|
+
function detectRecordDiff(localRecord, remoteRecord, callbacks) {
|
|
2673
|
+
const entries = [];
|
|
2674
|
+
for (const [key, localValue] of Object.entries(localRecord)) if (!Object.hasOwn(remoteRecord, key)) entries.push(callbacks.onAdded(key, localValue));
|
|
2675
|
+
else {
|
|
2676
|
+
const entry = callbacks.onModified(key, localValue, remoteRecord[key]);
|
|
2677
|
+
if (entry !== void 0) entries.push(entry);
|
|
2678
|
+
}
|
|
2679
|
+
for (const [key, remoteValue] of Object.entries(remoteRecord)) if (!Object.hasOwn(localRecord, key)) entries.push(callbacks.onDeleted(key, remoteValue));
|
|
2680
|
+
return entries;
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2563
2683
|
//#endregion
|
|
2564
2684
|
//#region src/core/domain/action/services/diffDetector.ts
|
|
2565
2685
|
function compareActions$1(local, remote) {
|
|
2566
2686
|
const diffs = [];
|
|
2567
2687
|
if (local.index !== remote.index) diffs.push(`index: ${remote.index} -> ${local.index}`);
|
|
2568
|
-
if (local.
|
|
2569
|
-
if (!deepEqual$1(local.destApp, remote.destApp)) diffs.push("destApp changed");
|
|
2688
|
+
if (!deepEqual(local.destApp, remote.destApp)) diffs.push("destApp changed");
|
|
2570
2689
|
if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
|
|
2571
|
-
if (!deepEqual
|
|
2690
|
+
if (!deepEqual(local.mappings, remote.mappings)) if (local.mappings.length !== remote.mappings.length) diffs.push(`mappings: ${remote.mappings.length} -> ${local.mappings.length}`);
|
|
2572
2691
|
else diffs.push("mappings changed");
|
|
2573
|
-
if (!deepEqual
|
|
2692
|
+
if (!deepEqual(local.entities, remote.entities)) diffs.push("entities changed");
|
|
2574
2693
|
return diffs;
|
|
2575
2694
|
}
|
|
2695
|
+
function destAppLabel(action) {
|
|
2696
|
+
return `dest: ${action.destApp.app ?? action.destApp.code ?? "(unspecified)"}`;
|
|
2697
|
+
}
|
|
2576
2698
|
const ActionDiffDetector = { detect: (local, remote) => {
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
const remoteAction = remote.actions[name];
|
|
2580
|
-
if (!remoteAction) entries.push({
|
|
2699
|
+
return buildDiffResult(detectRecordDiff(local.actions, remote.actions, {
|
|
2700
|
+
onAdded: (name, localAction) => ({
|
|
2581
2701
|
type: "added",
|
|
2582
2702
|
actionName: name,
|
|
2583
|
-
details:
|
|
2584
|
-
})
|
|
2585
|
-
|
|
2703
|
+
details: destAppLabel(localAction)
|
|
2704
|
+
}),
|
|
2705
|
+
onModified: (name, localAction, remoteAction) => {
|
|
2586
2706
|
const diffs = compareActions$1(localAction, remoteAction);
|
|
2587
|
-
if (diffs.length > 0)
|
|
2707
|
+
if (diffs.length > 0) return {
|
|
2588
2708
|
type: "modified",
|
|
2589
2709
|
actionName: name,
|
|
2590
2710
|
details: diffs.join(", ")
|
|
2591
|
-
}
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
});
|
|
2599
|
-
return buildDiffResult(entries);
|
|
2711
|
+
};
|
|
2712
|
+
},
|
|
2713
|
+
onDeleted: (name, remoteAction) => ({
|
|
2714
|
+
type: "deleted",
|
|
2715
|
+
actionName: name,
|
|
2716
|
+
details: destAppLabel(remoteAction)
|
|
2717
|
+
})
|
|
2718
|
+
}));
|
|
2600
2719
|
} };
|
|
2601
2720
|
|
|
2602
2721
|
//#endregion
|
|
@@ -2703,7 +2822,7 @@ const AdminNotesConfigParser = { parse: (rawText) => {
|
|
|
2703
2822
|
} catch (error) {
|
|
2704
2823
|
throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
2705
2824
|
}
|
|
2706
|
-
if (!isRecord
|
|
2825
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must be a YAML object");
|
|
2707
2826
|
const obj = parsed;
|
|
2708
2827
|
if (typeof obj.content !== "string") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have a \"content\" string property");
|
|
2709
2828
|
if (typeof obj.includeInTemplateAndDuplicates !== "boolean") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have an \"includeInTemplateAndDuplicates\" boolean property");
|
|
@@ -2997,16 +3116,16 @@ var admin_notes_default = define({
|
|
|
2997
3116
|
|
|
2998
3117
|
//#endregion
|
|
2999
3118
|
//#region src/core/domain/appPermission/services/configParser.ts
|
|
3000
|
-
const VALID_ENTITY_TYPES$
|
|
3119
|
+
const VALID_ENTITY_TYPES$8 = new Set([
|
|
3001
3120
|
"USER",
|
|
3002
3121
|
"GROUP",
|
|
3003
3122
|
"ORGANIZATION",
|
|
3004
3123
|
"CREATOR"
|
|
3005
3124
|
]);
|
|
3006
3125
|
function parseEntity$3(raw, index) {
|
|
3007
|
-
if (!isRecord
|
|
3126
|
+
if (!isRecord(raw)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, `Entity at index ${index} must be an object`);
|
|
3008
3127
|
const obj = raw;
|
|
3009
|
-
if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$
|
|
3128
|
+
if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$8.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
3129
|
const type = obj.type;
|
|
3011
3130
|
if (type === "CREATOR") return {
|
|
3012
3131
|
type,
|
|
@@ -3024,7 +3143,7 @@ function parseBooleanField$1(obj, field, index) {
|
|
|
3024
3143
|
return value;
|
|
3025
3144
|
}
|
|
3026
3145
|
function parseAppRight(raw, index) {
|
|
3027
|
-
if (!isRecord
|
|
3146
|
+
if (!isRecord(raw)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, `App right at index ${index} must be an object`);
|
|
3028
3147
|
const obj = raw;
|
|
3029
3148
|
return {
|
|
3030
3149
|
entity: parseEntity$3(obj.entity, index),
|
|
@@ -3046,7 +3165,7 @@ const AppPermissionConfigParser = { parse: (rawText) => {
|
|
|
3046
3165
|
} catch (error) {
|
|
3047
3166
|
throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
3048
3167
|
}
|
|
3049
|
-
if (!isRecord
|
|
3168
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must be a YAML object");
|
|
3050
3169
|
const obj = parsed;
|
|
3051
3170
|
if (!Array.isArray(obj.rights)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
3052
3171
|
const rights = obj.rights.map((item, i) => parseAppRight(item, i));
|
|
@@ -3080,14 +3199,14 @@ async function applyAppPermission({ container }) {
|
|
|
3080
3199
|
|
|
3081
3200
|
//#endregion
|
|
3082
3201
|
//#region src/core/adapters/kintone/appPermissionConfigurator.ts
|
|
3083
|
-
const VALID_ENTITY_TYPES$
|
|
3202
|
+
const VALID_ENTITY_TYPES$7 = new Set([
|
|
3084
3203
|
"USER",
|
|
3085
3204
|
"GROUP",
|
|
3086
3205
|
"ORGANIZATION",
|
|
3087
3206
|
"CREATOR"
|
|
3088
3207
|
]);
|
|
3089
3208
|
function fromKintoneRight$2(raw) {
|
|
3090
|
-
if (!VALID_ENTITY_TYPES$
|
|
3209
|
+
if (!VALID_ENTITY_TYPES$7.has(raw.entity.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected entity type from kintone API: ${raw.entity.type}`);
|
|
3091
3210
|
const type = raw.entity.type;
|
|
3092
3211
|
let code;
|
|
3093
3212
|
if (type === "CREATOR") code = raw.entity.code ?? "";
|
|
@@ -3458,28 +3577,21 @@ const ResourceMerger = {
|
|
|
3458
3577
|
|
|
3459
3578
|
//#endregion
|
|
3460
3579
|
//#region src/core/domain/customization/services/configParser.ts
|
|
3461
|
-
const VALID_SCOPES = new Set([
|
|
3462
|
-
"ALL",
|
|
3463
|
-
"ADMIN",
|
|
3464
|
-
"NONE"
|
|
3465
|
-
]);
|
|
3466
|
-
const VALID_RESOURCE_TYPES = new Set(["FILE", "URL"]);
|
|
3467
3580
|
function parseResource(raw, index) {
|
|
3468
|
-
if (!isRecord
|
|
3469
|
-
const
|
|
3470
|
-
|
|
3471
|
-
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`);
|
|
3581
|
+
if (!isRecord(raw)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, `Resource at index ${index} must be an object`);
|
|
3582
|
+
const type = raw.type;
|
|
3583
|
+
if (typeof type !== "string" || !isResourceType(type)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidResourceType, `Resource at index ${index} has invalid type: ${String(type)}. Must be FILE or URL`);
|
|
3472
3584
|
if (type === "FILE") {
|
|
3473
|
-
if (typeof
|
|
3585
|
+
if (typeof raw.path !== "string" || raw.path.length === 0) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, `FILE resource at index ${index} must have a non-empty "path" property`);
|
|
3474
3586
|
return {
|
|
3475
3587
|
type: "FILE",
|
|
3476
|
-
path:
|
|
3588
|
+
path: raw.path
|
|
3477
3589
|
};
|
|
3478
3590
|
}
|
|
3479
|
-
if (typeof
|
|
3591
|
+
if (typeof raw.url !== "string" || raw.url.length === 0) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, `URL resource at index ${index} must have a non-empty "url" property`);
|
|
3480
3592
|
return {
|
|
3481
3593
|
type: "URL",
|
|
3482
|
-
url:
|
|
3594
|
+
url: raw.url
|
|
3483
3595
|
};
|
|
3484
3596
|
}
|
|
3485
3597
|
function parseResourceList(raw) {
|
|
@@ -3487,26 +3599,21 @@ function parseResourceList(raw) {
|
|
|
3487
3599
|
return raw.map((item, index) => parseResource(item, index));
|
|
3488
3600
|
}
|
|
3489
3601
|
function parsePlatform(raw) {
|
|
3490
|
-
if (!isRecord
|
|
3491
|
-
const obj = raw;
|
|
3602
|
+
if (!isRecord(raw)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, "Platform configuration must be an object");
|
|
3492
3603
|
return {
|
|
3493
|
-
js:
|
|
3494
|
-
css:
|
|
3604
|
+
js: raw.js === void 0 || raw.js === null ? [] : parseResourceList(raw.js),
|
|
3605
|
+
css: raw.css === void 0 || raw.css === null ? [] : parseResourceList(raw.css)
|
|
3495
3606
|
};
|
|
3496
3607
|
}
|
|
3497
|
-
const
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
}
|
|
3503
|
-
throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
3504
|
-
}
|
|
3505
|
-
if (!isRecord$1(parsed)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidConfigStructure, "Config must be a YAML object");
|
|
3506
|
-
const obj = parsed;
|
|
3608
|
+
const CustomizationConfigParser = { parse: (rawText) => {
|
|
3609
|
+
const obj = parseYamlConfig(rawText, {
|
|
3610
|
+
emptyConfigText: CustomizationErrorCode.CzEmptyConfigText,
|
|
3611
|
+
invalidConfigYaml: CustomizationErrorCode.CzInvalidConfigYaml,
|
|
3612
|
+
invalidConfigStructure: CustomizationErrorCode.CzInvalidConfigStructure
|
|
3613
|
+
}, "Customization");
|
|
3507
3614
|
let scope;
|
|
3508
3615
|
if (obj.scope !== void 0 && obj.scope !== null) {
|
|
3509
|
-
if (typeof obj.scope !== "string" || !
|
|
3616
|
+
if (typeof obj.scope !== "string" || !isCustomizationScope(obj.scope)) throw new BusinessRuleError(CustomizationErrorCode.CzInvalidScope, `Invalid scope: ${String(obj.scope)}. Must be ALL, ADMIN, or NONE`);
|
|
3510
3617
|
scope = obj.scope;
|
|
3511
3618
|
}
|
|
3512
3619
|
const desktop = obj.desktop === void 0 || obj.desktop === null ? {
|
|
@@ -3527,7 +3634,7 @@ const ConfigParser = { parse: (rawText) => {
|
|
|
3527
3634
|
//#endregion
|
|
3528
3635
|
//#region src/core/application/customization/parseConfig.ts
|
|
3529
3636
|
function parseConfigText(rawText) {
|
|
3530
|
-
return wrapBusinessRuleError(() =>
|
|
3637
|
+
return wrapBusinessRuleError(() => CustomizationConfigParser.parse(rawText));
|
|
3531
3638
|
}
|
|
3532
3639
|
|
|
3533
3640
|
//#endregion
|
|
@@ -3630,14 +3737,10 @@ function serializePlatform(platform) {
|
|
|
3630
3737
|
};
|
|
3631
3738
|
}
|
|
3632
3739
|
const CustomizationConfigSerializer = { serialize: (config) => {
|
|
3633
|
-
return
|
|
3740
|
+
return serializeToYaml({
|
|
3634
3741
|
...config.scope !== void 0 ? { scope: config.scope } : {},
|
|
3635
3742
|
...hasPlatformResources(config.desktop) ? { desktop: serializePlatform(config.desktop) } : {},
|
|
3636
3743
|
...hasPlatformResources(config.mobile) ? { mobile: serializePlatform(config.mobile) } : {}
|
|
3637
|
-
}, {
|
|
3638
|
-
lineWidth: 0,
|
|
3639
|
-
defaultKeyType: "PLAIN",
|
|
3640
|
-
defaultStringType: "PLAIN"
|
|
3641
3744
|
});
|
|
3642
3745
|
} };
|
|
3643
3746
|
|
|
@@ -3899,15 +4002,11 @@ var apply_default$9 = define({
|
|
|
3899
4002
|
}
|
|
3900
4003
|
});
|
|
3901
4004
|
|
|
3902
|
-
//#endregion
|
|
3903
|
-
//#region src/core/domain/customization/valueObject.ts
|
|
3904
|
-
const DEFAULT_CUSTOMIZATION_SCOPE = "ALL";
|
|
3905
|
-
|
|
3906
4005
|
//#endregion
|
|
3907
4006
|
//#region src/core/domain/customization/services/diffDetector.ts
|
|
3908
4007
|
function resourceName(resource) {
|
|
3909
4008
|
if (resource.type === "URL") return resource.url;
|
|
3910
|
-
const parts = resource.path.replace(/\\/g, "/").split("/");
|
|
4009
|
+
const parts = resource.path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
3911
4010
|
return parts[parts.length - 1];
|
|
3912
4011
|
}
|
|
3913
4012
|
function remoteResourceName(resource) {
|
|
@@ -4018,7 +4117,7 @@ const VALID_ACCESSIBILITIES$1 = new Set([
|
|
|
4018
4117
|
"WRITE",
|
|
4019
4118
|
"NONE"
|
|
4020
4119
|
]);
|
|
4021
|
-
const VALID_ENTITY_TYPES$
|
|
4120
|
+
const VALID_ENTITY_TYPES$6 = new Set([
|
|
4022
4121
|
"USER",
|
|
4023
4122
|
"GROUP",
|
|
4024
4123
|
"ORGANIZATION",
|
|
@@ -4026,7 +4125,7 @@ const VALID_ENTITY_TYPES$7 = new Set([
|
|
|
4026
4125
|
]);
|
|
4027
4126
|
function fromKintoneEntity$3(raw) {
|
|
4028
4127
|
if (!VALID_ACCESSIBILITIES$1.has(raw.accessibility)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected accessibility value from kintone API: ${raw.accessibility}`);
|
|
4029
|
-
if (!VALID_ENTITY_TYPES$
|
|
4128
|
+
if (!VALID_ENTITY_TYPES$6.has(raw.entity.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected entity type from kintone API: ${raw.entity.type}`);
|
|
4030
4129
|
const result = {
|
|
4031
4130
|
accessibility: raw.accessibility,
|
|
4032
4131
|
entity: {
|
|
@@ -4128,16 +4227,16 @@ const VALID_ACCESSIBILITIES = new Set([
|
|
|
4128
4227
|
"WRITE",
|
|
4129
4228
|
"NONE"
|
|
4130
4229
|
]);
|
|
4131
|
-
const VALID_ENTITY_TYPES$
|
|
4230
|
+
const VALID_ENTITY_TYPES$5 = new Set([
|
|
4132
4231
|
"USER",
|
|
4133
4232
|
"GROUP",
|
|
4134
4233
|
"ORGANIZATION",
|
|
4135
4234
|
"FIELD_ENTITY"
|
|
4136
4235
|
]);
|
|
4137
4236
|
function parseEntity$2(raw, index) {
|
|
4138
|
-
if (!isRecord
|
|
4237
|
+
if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Entity at index ${index} must be an object`);
|
|
4139
4238
|
const obj = raw;
|
|
4140
|
-
if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$
|
|
4239
|
+
if (typeof obj.type !== "string" || !VALID_ENTITY_TYPES$5.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
4240
|
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`);
|
|
4142
4241
|
return {
|
|
4143
4242
|
type: obj.type,
|
|
@@ -4145,7 +4244,7 @@ function parseEntity$2(raw, index) {
|
|
|
4145
4244
|
};
|
|
4146
4245
|
}
|
|
4147
4246
|
function parseFieldRightEntity(raw, index) {
|
|
4148
|
-
if (!isRecord
|
|
4247
|
+
if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right entity at index ${index} must be an object`);
|
|
4149
4248
|
const obj = raw;
|
|
4150
4249
|
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
4250
|
const entity = parseEntity$2(obj.entity, index);
|
|
@@ -4160,7 +4259,7 @@ function parseFieldRightEntity(raw, index) {
|
|
|
4160
4259
|
return result;
|
|
4161
4260
|
}
|
|
4162
4261
|
function parseFieldRight(raw, index) {
|
|
4163
|
-
if (!isRecord
|
|
4262
|
+
if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right at index ${index} must be an object`);
|
|
4164
4263
|
const obj = raw;
|
|
4165
4264
|
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
4265
|
if (!Array.isArray(obj.entities)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right at index ${index} must have an "entities" array`);
|
|
@@ -4178,7 +4277,7 @@ const FieldPermissionConfigParser = { parse: (rawText) => {
|
|
|
4178
4277
|
} catch (error) {
|
|
4179
4278
|
throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
4180
4279
|
}
|
|
4181
|
-
if (!isRecord
|
|
4280
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must be a YAML object");
|
|
4182
4281
|
const obj = parsed;
|
|
4183
4282
|
if (!Array.isArray(obj.rights)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
4184
4283
|
const rights = obj.rights.map((item, i) => parseFieldRight(item, i));
|
|
@@ -4363,7 +4462,7 @@ var capture_default$9 = define({
|
|
|
4363
4462
|
//#endregion
|
|
4364
4463
|
//#region src/core/domain/fieldPermission/services/diffDetector.ts
|
|
4365
4464
|
function areEntitiesEqual(a, b) {
|
|
4366
|
-
return deepEqual
|
|
4465
|
+
return deepEqual(a.entities.map((e) => ({
|
|
4367
4466
|
accessibility: e.accessibility,
|
|
4368
4467
|
type: e.entity.type,
|
|
4369
4468
|
code: e.entity.code,
|
|
@@ -4598,18 +4697,22 @@ function createGeneralSettingsCliContainer(config) {
|
|
|
4598
4697
|
}
|
|
4599
4698
|
|
|
4600
4699
|
//#endregion
|
|
4601
|
-
//#region src/core/
|
|
4602
|
-
const
|
|
4700
|
+
//#region src/core/domain/notification/valueObject.ts
|
|
4701
|
+
const ENTITY_TYPES = [
|
|
4603
4702
|
"USER",
|
|
4604
4703
|
"GROUP",
|
|
4605
4704
|
"ORGANIZATION",
|
|
4606
4705
|
"FIELD_ENTITY"
|
|
4607
|
-
]
|
|
4608
|
-
|
|
4609
|
-
|
|
4706
|
+
];
|
|
4707
|
+
const VALID_ENTITY_TYPES$4 = new Set(ENTITY_TYPES);
|
|
4708
|
+
function isNotificationEntityType(value) {
|
|
4709
|
+
return VALID_ENTITY_TYPES$4.has(value);
|
|
4610
4710
|
}
|
|
4711
|
+
|
|
4712
|
+
//#endregion
|
|
4713
|
+
//#region src/core/adapters/kintone/notificationConfigurator.ts
|
|
4611
4714
|
function fromKintoneEntity$2(raw) {
|
|
4612
|
-
|
|
4715
|
+
if (!isNotificationEntityType(raw.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected entity type from kintone API (entity): ${raw.type}`);
|
|
4613
4716
|
return {
|
|
4614
4717
|
type: raw.type,
|
|
4615
4718
|
code: raw.code
|
|
@@ -4630,7 +4733,7 @@ function fromKintoneGeneralNotification(raw) {
|
|
|
4630
4733
|
};
|
|
4631
4734
|
return result;
|
|
4632
4735
|
}
|
|
4633
|
-
function
|
|
4736
|
+
function fromKintoneTarget(raw) {
|
|
4634
4737
|
const result = { entity: fromKintoneEntity$2(raw.entity) };
|
|
4635
4738
|
if (raw.includeSubs !== void 0) return {
|
|
4636
4739
|
...result,
|
|
@@ -4642,29 +4745,27 @@ function fromKintonePerRecordNotification(raw) {
|
|
|
4642
4745
|
return {
|
|
4643
4746
|
filterCond: raw.filterCond,
|
|
4644
4747
|
title: raw.title,
|
|
4645
|
-
targets: raw.targets.map(
|
|
4748
|
+
targets: raw.targets.map(fromKintoneTarget)
|
|
4646
4749
|
};
|
|
4647
4750
|
}
|
|
4648
|
-
function fromKintoneReminderTarget(raw) {
|
|
4649
|
-
const result = { entity: fromKintoneEntity$2(raw.entity) };
|
|
4650
|
-
if (raw.includeSubs !== void 0) return {
|
|
4651
|
-
...result,
|
|
4652
|
-
includeSubs: raw.includeSubs
|
|
4653
|
-
};
|
|
4654
|
-
return result;
|
|
4655
|
-
}
|
|
4656
4751
|
function fromKintoneReminderNotification(raw) {
|
|
4752
|
+
const daysLater = Number(raw.timing.daysLater);
|
|
4753
|
+
if (!Number.isFinite(daysLater)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric daysLater from kintone API: ${raw.timing.daysLater}`);
|
|
4657
4754
|
const result = {
|
|
4658
4755
|
code: raw.timing.code,
|
|
4659
|
-
daysLater
|
|
4756
|
+
daysLater,
|
|
4660
4757
|
filterCond: raw.filterCond,
|
|
4661
4758
|
title: raw.title,
|
|
4662
|
-
targets: raw.targets.map(
|
|
4663
|
-
};
|
|
4664
|
-
if ("hoursLater" in raw.timing) return {
|
|
4665
|
-
...result,
|
|
4666
|
-
hoursLater: Number(raw.timing.hoursLater)
|
|
4759
|
+
targets: raw.targets.map(fromKintoneTarget)
|
|
4667
4760
|
};
|
|
4761
|
+
if ("hoursLater" in raw.timing) {
|
|
4762
|
+
const hoursLater = Number(raw.timing.hoursLater);
|
|
4763
|
+
if (!Number.isFinite(hoursLater)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric hoursLater from kintone API: ${raw.timing.hoursLater}`);
|
|
4764
|
+
return {
|
|
4765
|
+
...result,
|
|
4766
|
+
hoursLater
|
|
4767
|
+
};
|
|
4768
|
+
}
|
|
4668
4769
|
if ("time" in raw.timing) return {
|
|
4669
4770
|
...result,
|
|
4670
4771
|
time: raw.timing.time
|
|
@@ -4689,7 +4790,7 @@ function toKintoneGeneralNotification(notification) {
|
|
|
4689
4790
|
if (notification.includeSubs !== void 0) result.includeSubs = notification.includeSubs;
|
|
4690
4791
|
return result;
|
|
4691
4792
|
}
|
|
4692
|
-
function
|
|
4793
|
+
function toKintoneTarget(target) {
|
|
4693
4794
|
const result = { entity: toKintoneEntity$2(target.entity) };
|
|
4694
4795
|
if (target.includeSubs !== void 0) result.includeSubs = target.includeSubs;
|
|
4695
4796
|
return result;
|
|
@@ -4698,14 +4799,9 @@ function toKintonePerRecordNotification(notification) {
|
|
|
4698
4799
|
return {
|
|
4699
4800
|
filterCond: notification.filterCond,
|
|
4700
4801
|
title: notification.title,
|
|
4701
|
-
targets: notification.targets.map(
|
|
4802
|
+
targets: notification.targets.map(toKintoneTarget)
|
|
4702
4803
|
};
|
|
4703
4804
|
}
|
|
4704
|
-
function toKintoneReminderTarget(target) {
|
|
4705
|
-
const result = { entity: toKintoneEntity$2(target.entity) };
|
|
4706
|
-
if (target.includeSubs !== void 0) result.includeSubs = target.includeSubs;
|
|
4707
|
-
return result;
|
|
4708
|
-
}
|
|
4709
4805
|
function toKintoneReminderNotification(notification) {
|
|
4710
4806
|
if (notification.hoursLater !== void 0 && notification.time !== void 0) throw new SystemError(SystemErrorCode.ExternalApiError, `Reminder notification "${notification.code}" must not have both "hoursLater" and "time"`);
|
|
4711
4807
|
const timing = {
|
|
@@ -4718,7 +4814,7 @@ function toKintoneReminderNotification(notification) {
|
|
|
4718
4814
|
timing,
|
|
4719
4815
|
filterCond: notification.filterCond,
|
|
4720
4816
|
title: notification.title,
|
|
4721
|
-
targets: notification.targets.map(
|
|
4817
|
+
targets: notification.targets.map(toKintoneTarget)
|
|
4722
4818
|
};
|
|
4723
4819
|
}
|
|
4724
4820
|
var KintoneNotificationConfigurator = class {
|
|
@@ -4915,7 +5011,7 @@ const VALID_ASSIGNEE_TYPES$1 = new Set([
|
|
|
4915
5011
|
"ALL",
|
|
4916
5012
|
"ANY"
|
|
4917
5013
|
]);
|
|
4918
|
-
const VALID_ENTITY_TYPES$
|
|
5014
|
+
const VALID_ENTITY_TYPES$3 = new Set([
|
|
4919
5015
|
"USER",
|
|
4920
5016
|
"GROUP",
|
|
4921
5017
|
"ORGANIZATION",
|
|
@@ -4925,7 +5021,7 @@ const VALID_ENTITY_TYPES$4 = new Set([
|
|
|
4925
5021
|
]);
|
|
4926
5022
|
const VALID_ACTION_TYPES$1 = new Set(["PRIMARY", "SECONDARY"]);
|
|
4927
5023
|
function fromKintoneEntity$1(raw) {
|
|
4928
|
-
if (!VALID_ENTITY_TYPES$
|
|
5024
|
+
if (!VALID_ENTITY_TYPES$3.has(raw.entity.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected entity type from kintone API: ${raw.entity.type}`);
|
|
4929
5025
|
const result = { type: raw.entity.type };
|
|
4930
5026
|
const withCode = raw.entity.code !== void 0 ? {
|
|
4931
5027
|
...result,
|
|
@@ -5067,14 +5163,14 @@ function createProcessManagementCliContainer(config) {
|
|
|
5067
5163
|
|
|
5068
5164
|
//#endregion
|
|
5069
5165
|
//#region src/core/adapters/kintone/recordPermissionConfigurator.ts
|
|
5070
|
-
const VALID_ENTITY_TYPES$
|
|
5166
|
+
const VALID_ENTITY_TYPES$2 = new Set([
|
|
5071
5167
|
"USER",
|
|
5072
5168
|
"GROUP",
|
|
5073
5169
|
"ORGANIZATION",
|
|
5074
5170
|
"FIELD_ENTITY"
|
|
5075
5171
|
]);
|
|
5076
5172
|
function fromKintoneEntity(raw) {
|
|
5077
|
-
if (!VALID_ENTITY_TYPES$
|
|
5173
|
+
if (!VALID_ENTITY_TYPES$2.has(raw.entity.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected entity type from kintone API: ${raw.entity.type}`);
|
|
5078
5174
|
return {
|
|
5079
5175
|
entity: {
|
|
5080
5176
|
type: raw.entity.type,
|
|
@@ -5169,8 +5265,8 @@ function createRecordPermissionCliContainer(config) {
|
|
|
5169
5265
|
}
|
|
5170
5266
|
|
|
5171
5267
|
//#endregion
|
|
5172
|
-
//#region src/core/
|
|
5173
|
-
const
|
|
5268
|
+
//#region src/core/domain/report/valueObject.ts
|
|
5269
|
+
const CHART_TYPES = [
|
|
5174
5270
|
"BAR",
|
|
5175
5271
|
"COLUMN",
|
|
5176
5272
|
"PIE",
|
|
@@ -5180,13 +5276,21 @@ const VALID_CHART_TYPES$1 = new Set([
|
|
|
5180
5276
|
"AREA",
|
|
5181
5277
|
"SPLINE",
|
|
5182
5278
|
"SPLINE_AREA"
|
|
5183
|
-
]
|
|
5184
|
-
const
|
|
5279
|
+
];
|
|
5280
|
+
const VALID_CHART_TYPES = new Set(CHART_TYPES);
|
|
5281
|
+
function isChartType(value) {
|
|
5282
|
+
return VALID_CHART_TYPES.has(value);
|
|
5283
|
+
}
|
|
5284
|
+
const CHART_MODES = [
|
|
5185
5285
|
"NORMAL",
|
|
5186
5286
|
"STACKED",
|
|
5187
5287
|
"PERCENTAGE"
|
|
5188
|
-
]
|
|
5189
|
-
const
|
|
5288
|
+
];
|
|
5289
|
+
const VALID_CHART_MODES = new Set(CHART_MODES);
|
|
5290
|
+
function isChartMode(value) {
|
|
5291
|
+
return VALID_CHART_MODES.has(value);
|
|
5292
|
+
}
|
|
5293
|
+
const GROUP_PERS = [
|
|
5190
5294
|
"YEAR",
|
|
5191
5295
|
"QUARTER",
|
|
5192
5296
|
"MONTH",
|
|
@@ -5194,38 +5298,78 @@ const VALID_GROUP_PERS = new Set([
|
|
|
5194
5298
|
"DAY",
|
|
5195
5299
|
"HOUR",
|
|
5196
5300
|
"MINUTE"
|
|
5197
|
-
]
|
|
5198
|
-
const
|
|
5301
|
+
];
|
|
5302
|
+
const VALID_GROUP_PERS = new Set(GROUP_PERS);
|
|
5303
|
+
function isGroupPer(value) {
|
|
5304
|
+
return VALID_GROUP_PERS.has(value);
|
|
5305
|
+
}
|
|
5306
|
+
const AGGREGATION_TYPES = [
|
|
5199
5307
|
"COUNT",
|
|
5200
5308
|
"SUM",
|
|
5201
5309
|
"AVERAGE",
|
|
5202
5310
|
"MAX",
|
|
5203
5311
|
"MIN"
|
|
5204
|
-
]
|
|
5205
|
-
const
|
|
5312
|
+
];
|
|
5313
|
+
const VALID_AGGREGATION_TYPES = new Set(AGGREGATION_TYPES);
|
|
5314
|
+
function isAggregationType(value) {
|
|
5315
|
+
return VALID_AGGREGATION_TYPES.has(value);
|
|
5316
|
+
}
|
|
5317
|
+
const SORT_BYS = [
|
|
5206
5318
|
"TOTAL",
|
|
5207
5319
|
"GROUP1",
|
|
5208
5320
|
"GROUP2",
|
|
5209
5321
|
"GROUP3"
|
|
5210
|
-
]
|
|
5211
|
-
const
|
|
5212
|
-
|
|
5322
|
+
];
|
|
5323
|
+
const VALID_SORT_BYS = new Set(SORT_BYS);
|
|
5324
|
+
function isSortBy(value) {
|
|
5325
|
+
return VALID_SORT_BYS.has(value);
|
|
5326
|
+
}
|
|
5327
|
+
const SORT_ORDERS = ["ASC", "DESC"];
|
|
5328
|
+
const VALID_SORT_ORDERS = new Set(SORT_ORDERS);
|
|
5329
|
+
function isSortOrder(value) {
|
|
5330
|
+
return VALID_SORT_ORDERS.has(value);
|
|
5331
|
+
}
|
|
5332
|
+
const PERIODIC_REPORT_EVERYS = [
|
|
5213
5333
|
"YEAR",
|
|
5214
5334
|
"QUARTER",
|
|
5215
5335
|
"MONTH",
|
|
5216
5336
|
"WEEK",
|
|
5217
5337
|
"DAY",
|
|
5218
5338
|
"HOUR"
|
|
5219
|
-
]
|
|
5220
|
-
const
|
|
5339
|
+
];
|
|
5340
|
+
const VALID_PERIODIC_REPORT_EVERYS = new Set(PERIODIC_REPORT_EVERYS);
|
|
5341
|
+
function isPeriodicReportEvery(value) {
|
|
5342
|
+
return VALID_PERIODIC_REPORT_EVERYS.has(value);
|
|
5343
|
+
}
|
|
5344
|
+
const PERIODIC_REPORT_PATTERNS = [
|
|
5221
5345
|
"JAN_APR_JUL_OCT",
|
|
5222
5346
|
"FEB_MAY_AUG_NOV",
|
|
5223
5347
|
"MAR_JUN_SEP_DEC"
|
|
5224
|
-
]
|
|
5348
|
+
];
|
|
5349
|
+
const VALID_PERIODIC_REPORT_PATTERNS = new Set(PERIODIC_REPORT_PATTERNS);
|
|
5350
|
+
function isPeriodicReportPattern(value) {
|
|
5351
|
+
return VALID_PERIODIC_REPORT_PATTERNS.has(value);
|
|
5352
|
+
}
|
|
5353
|
+
const DAYS_OF_WEEK = [
|
|
5354
|
+
"SUNDAY",
|
|
5355
|
+
"MONDAY",
|
|
5356
|
+
"TUESDAY",
|
|
5357
|
+
"WEDNESDAY",
|
|
5358
|
+
"THURSDAY",
|
|
5359
|
+
"FRIDAY",
|
|
5360
|
+
"SATURDAY"
|
|
5361
|
+
];
|
|
5362
|
+
const VALID_DAYS_OF_WEEK = new Set(DAYS_OF_WEEK);
|
|
5363
|
+
function isDayOfWeek(value) {
|
|
5364
|
+
return VALID_DAYS_OF_WEEK.has(value);
|
|
5365
|
+
}
|
|
5366
|
+
|
|
5367
|
+
//#endregion
|
|
5368
|
+
//#region src/core/adapters/kintone/reportConfigurator.ts
|
|
5225
5369
|
function fromKintoneGroup(raw) {
|
|
5226
5370
|
const result = { code: raw.code };
|
|
5227
5371
|
if (raw.per !== void 0) {
|
|
5228
|
-
if (!
|
|
5372
|
+
if (!isGroupPer(raw.per)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected group per value from kintone API: ${raw.per}`);
|
|
5229
5373
|
return {
|
|
5230
5374
|
...result,
|
|
5231
5375
|
per: raw.per
|
|
@@ -5234,7 +5378,7 @@ function fromKintoneGroup(raw) {
|
|
|
5234
5378
|
return result;
|
|
5235
5379
|
}
|
|
5236
5380
|
function fromKintoneAggregation(raw) {
|
|
5237
|
-
if (!
|
|
5381
|
+
if (!isAggregationType(raw.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected aggregation type value from kintone API: ${raw.type}`);
|
|
5238
5382
|
const result = { type: raw.type };
|
|
5239
5383
|
if (raw.code !== void 0) return {
|
|
5240
5384
|
...result,
|
|
@@ -5243,30 +5387,37 @@ function fromKintoneAggregation(raw) {
|
|
|
5243
5387
|
return result;
|
|
5244
5388
|
}
|
|
5245
5389
|
function fromKintoneSort(raw) {
|
|
5246
|
-
if (!
|
|
5247
|
-
if (!
|
|
5390
|
+
if (!isSortBy(raw.by)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected sort by value from kintone API: ${raw.by}`);
|
|
5391
|
+
if (!isSortOrder(raw.order)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected sort order value from kintone API: ${raw.order}`);
|
|
5248
5392
|
return {
|
|
5249
5393
|
by: raw.by,
|
|
5250
5394
|
order: raw.order
|
|
5251
5395
|
};
|
|
5252
5396
|
}
|
|
5253
5397
|
function fromKintonePeriodicReportPeriod(raw) {
|
|
5254
|
-
if (!
|
|
5255
|
-
if (raw.pattern !== void 0 && !
|
|
5398
|
+
if (!isPeriodicReportEvery(raw.every)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected periodicReport every value from kintone API: ${raw.every}`);
|
|
5399
|
+
if (raw.pattern !== void 0 && !isPeriodicReportPattern(raw.pattern)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected periodicReport pattern value from kintone API: ${raw.pattern}`);
|
|
5256
5400
|
let dayOfMonth;
|
|
5257
5401
|
if (raw.dayOfMonth !== void 0) if (String(raw.dayOfMonth) === "END_OF_MONTH") dayOfMonth = "END_OF_MONTH";
|
|
5258
5402
|
else {
|
|
5259
5403
|
const parsed = Number(raw.dayOfMonth);
|
|
5260
|
-
if (Number.
|
|
5404
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected periodicReport dayOfMonth value from kintone API: ${String(raw.dayOfMonth)}`);
|
|
5261
5405
|
dayOfMonth = parsed;
|
|
5262
5406
|
}
|
|
5263
5407
|
return {
|
|
5264
5408
|
every: raw.every,
|
|
5265
|
-
...raw.month !== void 0 ? { month:
|
|
5266
|
-
|
|
5409
|
+
...raw.month !== void 0 ? { month: (() => {
|
|
5410
|
+
const m = Number(raw.month);
|
|
5411
|
+
if (!Number.isFinite(m)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric month from kintone API: ${raw.month}`);
|
|
5412
|
+
return m;
|
|
5413
|
+
})() } : {},
|
|
5414
|
+
...raw.pattern !== void 0 && isPeriodicReportPattern(raw.pattern) ? { pattern: raw.pattern } : {},
|
|
5267
5415
|
...dayOfMonth !== void 0 ? { dayOfMonth } : {},
|
|
5268
5416
|
...raw.time !== void 0 ? { time: raw.time } : {},
|
|
5269
|
-
...raw.dayOfWeek !== void 0 ?
|
|
5417
|
+
...raw.dayOfWeek !== void 0 ? (() => {
|
|
5418
|
+
if (!isDayOfWeek(raw.dayOfWeek)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected periodicReport dayOfWeek value from kintone API: ${raw.dayOfWeek}`);
|
|
5419
|
+
return { dayOfWeek: raw.dayOfWeek };
|
|
5420
|
+
})() : {},
|
|
5270
5421
|
...raw.minute !== void 0 ? { minute: raw.minute } : {}
|
|
5271
5422
|
};
|
|
5272
5423
|
}
|
|
@@ -5277,12 +5428,16 @@ function fromKintonePeriodicReport(raw) {
|
|
|
5277
5428
|
};
|
|
5278
5429
|
}
|
|
5279
5430
|
function fromKintoneReportConfig(raw) {
|
|
5280
|
-
if (!
|
|
5281
|
-
if (raw.chartMode !== void 0 && raw.chartMode !== "" && !
|
|
5431
|
+
if (!isChartType(raw.chartType)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected chartType value from kintone API: ${raw.chartType}`);
|
|
5432
|
+
if (raw.chartMode !== void 0 && raw.chartMode !== "" && !isChartMode(raw.chartMode)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected chartMode value from kintone API: ${raw.chartMode}`);
|
|
5282
5433
|
const result = {
|
|
5283
5434
|
chartType: raw.chartType,
|
|
5284
|
-
...raw.chartMode !== void 0 && raw.chartMode !== "" &&
|
|
5285
|
-
index:
|
|
5435
|
+
...raw.chartMode !== void 0 && raw.chartMode !== "" && isChartMode(raw.chartMode) ? { chartMode: raw.chartMode } : {},
|
|
5436
|
+
index: (() => {
|
|
5437
|
+
const idx = Number(raw.index);
|
|
5438
|
+
if (!Number.isFinite(idx)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric index from kintone API: ${raw.index}`);
|
|
5439
|
+
return idx;
|
|
5440
|
+
})(),
|
|
5286
5441
|
name: raw.name,
|
|
5287
5442
|
groups: raw.groups.map(fromKintoneGroup),
|
|
5288
5443
|
aggregations: raw.aggregations.map(fromKintoneAggregation),
|
|
@@ -5315,7 +5470,7 @@ function toKintonePeriodicReportPeriod(period) {
|
|
|
5315
5470
|
const result = { every: period.every };
|
|
5316
5471
|
if (period.month !== void 0) result.month = String(period.month);
|
|
5317
5472
|
if (period.pattern !== void 0) result.pattern = period.pattern;
|
|
5318
|
-
if (period.dayOfMonth !== void 0) result.dayOfMonth = period.dayOfMonth;
|
|
5473
|
+
if (period.dayOfMonth !== void 0) result.dayOfMonth = typeof period.dayOfMonth === "number" ? String(period.dayOfMonth) : period.dayOfMonth;
|
|
5319
5474
|
if (period.time !== void 0) result.time = period.time;
|
|
5320
5475
|
if (period.dayOfWeek !== void 0) result.dayOfWeek = period.dayOfWeek;
|
|
5321
5476
|
if (period.minute !== void 0) result.minute = period.minute;
|
|
@@ -5412,16 +5567,31 @@ const VIEW_TYPES = [
|
|
|
5412
5567
|
"CUSTOM"
|
|
5413
5568
|
];
|
|
5414
5569
|
const VALID_VIEW_TYPES = new Set(VIEW_TYPES);
|
|
5570
|
+
function isViewType(value) {
|
|
5571
|
+
return VALID_VIEW_TYPES.has(value);
|
|
5572
|
+
}
|
|
5415
5573
|
const DEVICE_TYPES = ["DESKTOP", "ANY"];
|
|
5416
5574
|
const VALID_DEVICE_TYPES = new Set(DEVICE_TYPES);
|
|
5575
|
+
function isDeviceType(value) {
|
|
5576
|
+
return VALID_DEVICE_TYPES.has(value);
|
|
5577
|
+
}
|
|
5417
5578
|
|
|
5418
5579
|
//#endregion
|
|
5419
5580
|
//#region src/core/adapters/kintone/viewConfigurator.ts
|
|
5420
5581
|
function fromKintoneView(name, raw) {
|
|
5421
|
-
if (!
|
|
5582
|
+
if (!isViewType(raw.type)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected view type from kintone API: ${raw.type}`);
|
|
5583
|
+
let device;
|
|
5584
|
+
if (raw.device !== void 0) {
|
|
5585
|
+
if (!isDeviceType(raw.device)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected device type from kintone API: ${raw.device}`);
|
|
5586
|
+
device = raw.device;
|
|
5587
|
+
}
|
|
5422
5588
|
return {
|
|
5423
5589
|
type: raw.type,
|
|
5424
|
-
index:
|
|
5590
|
+
index: (() => {
|
|
5591
|
+
const idx = typeof raw.index === "string" ? Number(raw.index) : raw.index;
|
|
5592
|
+
if (!Number.isFinite(idx)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric index from kintone API: ${raw.index}`);
|
|
5593
|
+
return idx;
|
|
5594
|
+
})(),
|
|
5425
5595
|
name,
|
|
5426
5596
|
...raw.builtinType !== void 0 && { builtinType: raw.builtinType },
|
|
5427
5597
|
...raw.fields !== void 0 && { fields: raw.fields },
|
|
@@ -5429,10 +5599,7 @@ function fromKintoneView(name, raw) {
|
|
|
5429
5599
|
...raw.title !== void 0 && { title: raw.title },
|
|
5430
5600
|
...raw.html !== void 0 && { html: raw.html },
|
|
5431
5601
|
...raw.pager !== void 0 && { pager: raw.pager },
|
|
5432
|
-
...
|
|
5433
|
-
if (!VALID_DEVICE_TYPES.has(raw.device)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected device type from kintone API: ${raw.device}`);
|
|
5434
|
-
return raw.device;
|
|
5435
|
-
})() },
|
|
5602
|
+
...device !== void 0 && { device },
|
|
5436
5603
|
...raw.filterCond !== void 0 && { filterCond: raw.filterCond },
|
|
5437
5604
|
...raw.sort !== void 0 && { sort: raw.sort }
|
|
5438
5605
|
};
|
|
@@ -5907,7 +6074,7 @@ function serializeGeneralNotification(notification) {
|
|
|
5907
6074
|
if (notification.includeSubs !== void 0) result.includeSubs = notification.includeSubs;
|
|
5908
6075
|
return result;
|
|
5909
6076
|
}
|
|
5910
|
-
function
|
|
6077
|
+
function serializeTarget(target) {
|
|
5911
6078
|
const result = { entity: serializeEntity$1(target.entity) };
|
|
5912
6079
|
if (target.includeSubs !== void 0) result.includeSubs = target.includeSubs;
|
|
5913
6080
|
return result;
|
|
@@ -5916,21 +6083,16 @@ function serializePerRecordNotification(notification) {
|
|
|
5916
6083
|
return {
|
|
5917
6084
|
filterCond: notification.filterCond,
|
|
5918
6085
|
title: notification.title,
|
|
5919
|
-
targets: notification.targets.map(
|
|
6086
|
+
targets: notification.targets.map(serializeTarget)
|
|
5920
6087
|
};
|
|
5921
6088
|
}
|
|
5922
|
-
function serializeReminderTarget(target) {
|
|
5923
|
-
const result = { entity: serializeEntity$1(target.entity) };
|
|
5924
|
-
if (target.includeSubs !== void 0) result.includeSubs = target.includeSubs;
|
|
5925
|
-
return result;
|
|
5926
|
-
}
|
|
5927
6089
|
function serializeReminderNotification(notification) {
|
|
5928
6090
|
const result = {
|
|
5929
6091
|
code: notification.code,
|
|
5930
6092
|
daysLater: notification.daysLater,
|
|
5931
6093
|
filterCond: notification.filterCond,
|
|
5932
6094
|
title: notification.title,
|
|
5933
|
-
targets: notification.targets.map(
|
|
6095
|
+
targets: notification.targets.map(serializeTarget)
|
|
5934
6096
|
};
|
|
5935
6097
|
if (notification.hoursLater !== void 0) result.hoursLater = notification.hoursLater;
|
|
5936
6098
|
if (notification.time !== void 0) result.time = notification.time;
|
|
@@ -5947,11 +6109,7 @@ const NotificationConfigSerializer = { serialize: (config) => {
|
|
|
5947
6109
|
timezone: config.reminder.timezone,
|
|
5948
6110
|
notifications: config.reminder.notifications.map(serializeReminderNotification)
|
|
5949
6111
|
};
|
|
5950
|
-
return
|
|
5951
|
-
lineWidth: 0,
|
|
5952
|
-
defaultKeyType: "PLAIN",
|
|
5953
|
-
defaultStringType: "PLAIN"
|
|
5954
|
-
});
|
|
6112
|
+
return serializeToYaml(serialized);
|
|
5955
6113
|
} };
|
|
5956
6114
|
|
|
5957
6115
|
//#endregion
|
|
@@ -5986,15 +6144,11 @@ async function saveNotification({ container, input }) {
|
|
|
5986
6144
|
//#endregion
|
|
5987
6145
|
//#region src/core/domain/plugin/services/configSerializer.ts
|
|
5988
6146
|
const PluginConfigSerializer = { serialize: (config) => {
|
|
5989
|
-
return
|
|
6147
|
+
return serializeToYaml({ plugins: config.plugins.map((plugin) => ({
|
|
5990
6148
|
id: plugin.id,
|
|
5991
6149
|
name: plugin.name,
|
|
5992
6150
|
enabled: plugin.enabled
|
|
5993
|
-
})) }
|
|
5994
|
-
lineWidth: 0,
|
|
5995
|
-
defaultKeyType: "PLAIN",
|
|
5996
|
-
defaultStringType: "PLAIN"
|
|
5997
|
-
});
|
|
6151
|
+
})) });
|
|
5998
6152
|
} };
|
|
5999
6153
|
|
|
6000
6154
|
//#endregion
|
|
@@ -6160,11 +6314,7 @@ const ReportConfigSerializer = { serialize: (config) => {
|
|
|
6160
6314
|
const reports = {};
|
|
6161
6315
|
for (const [name, reportConfig] of Object.entries(config.reports)) reports[name] = serializeReportConfig(reportConfig);
|
|
6162
6316
|
serialized.reports = reports;
|
|
6163
|
-
return
|
|
6164
|
-
lineWidth: 0,
|
|
6165
|
-
defaultKeyType: "PLAIN",
|
|
6166
|
-
defaultStringType: "PLAIN"
|
|
6167
|
-
});
|
|
6317
|
+
return serializeToYaml(serialized);
|
|
6168
6318
|
} };
|
|
6169
6319
|
|
|
6170
6320
|
//#endregion
|
|
@@ -6186,11 +6336,7 @@ async function saveReport({ container, input }) {
|
|
|
6186
6336
|
//#endregion
|
|
6187
6337
|
//#region src/core/domain/seedData/services/seedSerializer.ts
|
|
6188
6338
|
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
|
-
});
|
|
6339
|
+
const records = seedData.records.map((record) => ({ ...record }));
|
|
6194
6340
|
return stringify(seedData.key !== null ? {
|
|
6195
6341
|
key: seedData.key,
|
|
6196
6342
|
records
|
|
@@ -6252,11 +6398,7 @@ function serializeViewConfig(config) {
|
|
|
6252
6398
|
const ViewConfigSerializer = { serialize: (config) => {
|
|
6253
6399
|
const serialized = {};
|
|
6254
6400
|
for (const [name, viewConfig] of Object.entries(config.views)) serialized[name] = serializeViewConfig(viewConfig);
|
|
6255
|
-
return
|
|
6256
|
-
lineWidth: 0,
|
|
6257
|
-
defaultKeyType: "PLAIN",
|
|
6258
|
-
defaultStringType: "PLAIN"
|
|
6259
|
-
});
|
|
6401
|
+
return serializeToYaml({ views: serialized });
|
|
6260
6402
|
} };
|
|
6261
6403
|
|
|
6262
6404
|
//#endregion
|
|
@@ -6613,68 +6755,57 @@ var init_default = define({
|
|
|
6613
6755
|
|
|
6614
6756
|
//#endregion
|
|
6615
6757
|
//#region src/core/domain/notification/services/configParser.ts
|
|
6616
|
-
const VALID_ENTITY_TYPES$2 = new Set([
|
|
6617
|
-
"USER",
|
|
6618
|
-
"GROUP",
|
|
6619
|
-
"ORGANIZATION",
|
|
6620
|
-
"FIELD_ENTITY"
|
|
6621
|
-
]);
|
|
6622
6758
|
function parseEntity$1(raw, context) {
|
|
6623
|
-
if (!isRecord
|
|
6624
|
-
|
|
6625
|
-
if (typeof
|
|
6626
|
-
if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(NotificationErrorCode.NtEmptyEntityCode, `${context}: entity must have a non-empty "code" property`);
|
|
6759
|
+
if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `${context}: entity must be an object`);
|
|
6760
|
+
if (typeof raw.type !== "string" || !isNotificationEntityType(raw.type)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidEntityType, `${context}: entity has invalid type: ${String(raw.type)}. Must be USER, GROUP, ORGANIZATION, or FIELD_ENTITY`);
|
|
6761
|
+
if (typeof raw.code !== "string" || raw.code.length === 0) throw new BusinessRuleError(NotificationErrorCode.NtEmptyEntityCode, `${context}: entity must have a non-empty "code" property`);
|
|
6627
6762
|
return {
|
|
6628
|
-
type:
|
|
6629
|
-
code:
|
|
6763
|
+
type: raw.type,
|
|
6764
|
+
code: raw.code
|
|
6630
6765
|
};
|
|
6631
6766
|
}
|
|
6632
6767
|
function parseGeneralNotification(raw, index) {
|
|
6633
|
-
if (!isRecord
|
|
6634
|
-
const obj = raw;
|
|
6768
|
+
if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `General notification at index ${index} must be an object`);
|
|
6635
6769
|
const result = {
|
|
6636
|
-
entity: parseEntity$1(
|
|
6637
|
-
recordAdded: Boolean(
|
|
6638
|
-
recordEdited: Boolean(
|
|
6639
|
-
commentAdded: Boolean(
|
|
6640
|
-
statusChanged: Boolean(
|
|
6641
|
-
fileImported: Boolean(
|
|
6642
|
-
};
|
|
6643
|
-
if (
|
|
6770
|
+
entity: parseEntity$1(raw.entity, `General notification at index ${index}`),
|
|
6771
|
+
recordAdded: Boolean(raw.recordAdded),
|
|
6772
|
+
recordEdited: Boolean(raw.recordEdited),
|
|
6773
|
+
commentAdded: Boolean(raw.commentAdded),
|
|
6774
|
+
statusChanged: Boolean(raw.statusChanged),
|
|
6775
|
+
fileImported: Boolean(raw.fileImported)
|
|
6776
|
+
};
|
|
6777
|
+
if (raw.includeSubs !== void 0 && raw.includeSubs !== null) return {
|
|
6644
6778
|
...result,
|
|
6645
|
-
includeSubs: Boolean(
|
|
6779
|
+
includeSubs: Boolean(raw.includeSubs)
|
|
6646
6780
|
};
|
|
6647
6781
|
return result;
|
|
6648
6782
|
}
|
|
6649
6783
|
function parseGeneralConfig(raw) {
|
|
6650
|
-
if (!isRecord
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
const notifications = obj.notifications.map((item, i) => parseGeneralNotification(item, i));
|
|
6784
|
+
if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"general\" must be an object");
|
|
6785
|
+
if (!Array.isArray(raw.notifications)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"general\" must have a \"notifications\" array");
|
|
6786
|
+
const notifications = raw.notifications.map((item, i) => parseGeneralNotification(item, i));
|
|
6654
6787
|
return {
|
|
6655
|
-
notifyToCommenter: Boolean(
|
|
6788
|
+
notifyToCommenter: Boolean(raw.notifyToCommenter),
|
|
6656
6789
|
notifications
|
|
6657
6790
|
};
|
|
6658
6791
|
}
|
|
6659
|
-
function
|
|
6660
|
-
if (!isRecord
|
|
6661
|
-
const
|
|
6662
|
-
|
|
6663
|
-
if (obj.includeSubs !== void 0 && obj.includeSubs !== null) return {
|
|
6792
|
+
function parseTarget(raw, index, context) {
|
|
6793
|
+
if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `${context} target at index ${index} must be an object`);
|
|
6794
|
+
const result = { entity: parseEntity$1(raw.entity, `${context} target at index ${index}`) };
|
|
6795
|
+
if (raw.includeSubs !== void 0 && raw.includeSubs !== null) return {
|
|
6664
6796
|
...result,
|
|
6665
|
-
includeSubs: Boolean(
|
|
6797
|
+
includeSubs: Boolean(raw.includeSubs)
|
|
6666
6798
|
};
|
|
6667
6799
|
return result;
|
|
6668
6800
|
}
|
|
6669
6801
|
function parsePerRecordNotification(raw, index) {
|
|
6670
|
-
if (!isRecord
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
if (typeof obj.filterCond !== "string") throw new BusinessRuleError(NotificationErrorCode.NtMissingRequiredField, `Per-record notification at index ${index} must have a "filterCond" string property`);
|
|
6802
|
+
if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Per-record notification at index ${index} must be an object`);
|
|
6803
|
+
if (!Array.isArray(raw.targets)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Per-record notification at index ${index} must have a "targets" array`);
|
|
6804
|
+
const targets = raw.targets.map((item, i) => parseTarget(item, i, "Per-record"));
|
|
6805
|
+
if (typeof raw.filterCond !== "string") throw new BusinessRuleError(NotificationErrorCode.NtMissingRequiredField, `Per-record notification at index ${index} must have a "filterCond" string property`);
|
|
6675
6806
|
return {
|
|
6676
|
-
filterCond:
|
|
6677
|
-
title: typeof
|
|
6807
|
+
filterCond: raw.filterCond,
|
|
6808
|
+
title: typeof raw.title === "string" ? raw.title : "",
|
|
6678
6809
|
targets
|
|
6679
6810
|
};
|
|
6680
6811
|
}
|
|
@@ -6682,63 +6813,50 @@ function parsePerRecordConfig(raw) {
|
|
|
6682
6813
|
if (!Array.isArray(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"perRecord\" must be an array");
|
|
6683
6814
|
return raw.map((item, i) => parsePerRecordNotification(item, i));
|
|
6684
6815
|
}
|
|
6685
|
-
function parseReminderTarget(raw, index) {
|
|
6686
|
-
if (!isRecord$1(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder target at index ${index} must be an object`);
|
|
6687
|
-
const obj = raw;
|
|
6688
|
-
const result = { entity: parseEntity$1(obj.entity, `Reminder target at index ${index}`) };
|
|
6689
|
-
if (obj.includeSubs !== void 0 && obj.includeSubs !== null) return {
|
|
6690
|
-
...result,
|
|
6691
|
-
includeSubs: Boolean(obj.includeSubs)
|
|
6692
|
-
};
|
|
6693
|
-
return result;
|
|
6694
|
-
}
|
|
6695
6816
|
function parseReminderNotification(raw, index) {
|
|
6696
|
-
if (!isRecord
|
|
6697
|
-
|
|
6698
|
-
if (
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
if (
|
|
6702
|
-
const hasHoursLater =
|
|
6703
|
-
const hasTime =
|
|
6817
|
+
if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} must be an object`);
|
|
6818
|
+
if (typeof raw.code !== "string" || raw.code.length === 0) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} must have a non-empty "code" property`);
|
|
6819
|
+
if (!Array.isArray(raw.targets)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} must have a "targets" array`);
|
|
6820
|
+
const targets = raw.targets.map((item, i) => parseTarget(item, i, "Reminder"));
|
|
6821
|
+
if (typeof raw.daysLater !== "number") throw new BusinessRuleError(NotificationErrorCode.NtMissingRequiredField, `Reminder notification at index ${index} must have a "daysLater" property`);
|
|
6822
|
+
if (!Number.isInteger(raw.daysLater) || raw.daysLater < 0) throw new BusinessRuleError(NotificationErrorCode.NtInvalidDaysLater, `Reminder notification at index ${index} has invalid "daysLater": ${raw.daysLater}. Must be a non-negative integer`);
|
|
6823
|
+
const hasHoursLater = raw.hoursLater !== void 0 && raw.hoursLater !== null;
|
|
6824
|
+
const hasTime = raw.time !== void 0 && raw.time !== null;
|
|
6704
6825
|
if (hasHoursLater && hasTime) throw new BusinessRuleError(NotificationErrorCode.NtConflictingTimingFields, `Reminder notification at index ${index} must not have both "hoursLater" and "time"`);
|
|
6826
|
+
if (hasHoursLater && (typeof raw.hoursLater !== "number" || !Number.isInteger(raw.hoursLater) || raw.hoursLater < 0)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidHoursLater, `Reminder notification at index ${index} has invalid "hoursLater": ${String(raw.hoursLater)}. Must be a non-negative integer`);
|
|
6827
|
+
if (hasTime && typeof raw.time !== "string") throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `Reminder notification at index ${index} has non-string "time": ${String(raw.time)}`);
|
|
6705
6828
|
const result = {
|
|
6706
|
-
code:
|
|
6707
|
-
daysLater:
|
|
6708
|
-
filterCond: typeof
|
|
6709
|
-
title: typeof
|
|
6829
|
+
code: raw.code,
|
|
6830
|
+
daysLater: raw.daysLater,
|
|
6831
|
+
filterCond: typeof raw.filterCond === "string" ? raw.filterCond : "",
|
|
6832
|
+
title: typeof raw.title === "string" ? raw.title : "",
|
|
6710
6833
|
targets
|
|
6711
6834
|
};
|
|
6712
|
-
if (hasHoursLater) return {
|
|
6835
|
+
if (hasHoursLater && typeof raw.hoursLater === "number") return {
|
|
6713
6836
|
...result,
|
|
6714
|
-
hoursLater:
|
|
6837
|
+
hoursLater: raw.hoursLater
|
|
6715
6838
|
};
|
|
6716
6839
|
if (hasTime) return {
|
|
6717
6840
|
...result,
|
|
6718
|
-
time: typeof
|
|
6841
|
+
time: typeof raw.time === "string" ? raw.time : ""
|
|
6719
6842
|
};
|
|
6720
6843
|
return result;
|
|
6721
6844
|
}
|
|
6722
6845
|
function parseReminderConfig(raw) {
|
|
6723
|
-
if (!isRecord
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
const notifications = obj.notifications.map((item, i) => parseReminderNotification(item, i));
|
|
6846
|
+
if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"reminder\" must be an object");
|
|
6847
|
+
if (!Array.isArray(raw.notifications)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"reminder\" must have a \"notifications\" array");
|
|
6848
|
+
const notifications = raw.notifications.map((item, i) => parseReminderNotification(item, i));
|
|
6727
6849
|
return {
|
|
6728
|
-
timezone: typeof
|
|
6850
|
+
timezone: typeof raw.timezone === "string" ? raw.timezone : "Asia/Tokyo",
|
|
6729
6851
|
notifications
|
|
6730
6852
|
};
|
|
6731
6853
|
}
|
|
6732
6854
|
const NotificationConfigParser = { parse: (rawText) => {
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
}
|
|
6738
|
-
throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
6739
|
-
}
|
|
6740
|
-
if (!isRecord$1(parsed)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "Config must be a YAML object");
|
|
6741
|
-
const obj = parsed;
|
|
6855
|
+
const obj = parseYamlConfig(rawText, {
|
|
6856
|
+
emptyConfigText: NotificationErrorCode.NtEmptyConfigText,
|
|
6857
|
+
invalidConfigYaml: NotificationErrorCode.NtInvalidConfigYaml,
|
|
6858
|
+
invalidConfigStructure: NotificationErrorCode.NtInvalidConfigStructure
|
|
6859
|
+
}, "Notification");
|
|
6742
6860
|
const config = {};
|
|
6743
6861
|
if (obj.general !== void 0) config.general = parseGeneralConfig(obj.general);
|
|
6744
6862
|
if (obj.perRecord !== void 0) config.perRecord = parsePerRecordConfig(obj.perRecord);
|
|
@@ -6979,7 +7097,7 @@ function perRecordLabel(notif) {
|
|
|
6979
7097
|
function describePerRecordChanges(local, remote) {
|
|
6980
7098
|
const diffs = [];
|
|
6981
7099
|
if (local.title !== remote.title) diffs.push("title changed");
|
|
6982
|
-
if (!deepEqual
|
|
7100
|
+
if (!deepEqual(local.targets, remote.targets)) diffs.push("targets changed");
|
|
6983
7101
|
return diffs.length > 0 ? diffs.join(", ") : "changed";
|
|
6984
7102
|
}
|
|
6985
7103
|
function describeReminderChanges(local, remote) {
|
|
@@ -6989,7 +7107,7 @@ function describeReminderChanges(local, remote) {
|
|
|
6989
7107
|
if ((local.hoursLater ?? 0) !== (remote.hoursLater ?? 0)) diffs.push("hoursLater changed");
|
|
6990
7108
|
if ((local.time ?? "") !== (remote.time ?? "")) diffs.push("time changed");
|
|
6991
7109
|
if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
|
|
6992
|
-
if (!deepEqual
|
|
7110
|
+
if (!deepEqual(local.targets, remote.targets)) diffs.push("targets changed");
|
|
6993
7111
|
return diffs.length > 0 ? diffs.join(", ") : "changed";
|
|
6994
7112
|
}
|
|
6995
7113
|
function comparePerRecordSection(local, remote) {
|
|
@@ -7014,7 +7132,7 @@ function comparePerRecordSection(local, remote) {
|
|
|
7014
7132
|
name: perRecordLabel(remoteNotif),
|
|
7015
7133
|
details: "removed"
|
|
7016
7134
|
});
|
|
7017
|
-
else if (localNotif && remoteNotif && !deepEqual
|
|
7135
|
+
else if (localNotif && remoteNotif && !deepEqual(localNotif, remoteNotif)) {
|
|
7018
7136
|
const diffs = describePerRecordChanges(localNotif, remoteNotif);
|
|
7019
7137
|
entries.push({
|
|
7020
7138
|
type: "modified",
|
|
@@ -7045,7 +7163,7 @@ function compareReminderSection(local, remote) {
|
|
|
7045
7163
|
name: code,
|
|
7046
7164
|
details: `"${localNotif.title}"`
|
|
7047
7165
|
});
|
|
7048
|
-
else if (!deepEqual
|
|
7166
|
+
else if (!deepEqual(localNotif, remoteNotif)) entries.push({
|
|
7049
7167
|
type: "modified",
|
|
7050
7168
|
section: "reminder",
|
|
7051
7169
|
name: code,
|
|
@@ -7156,27 +7274,29 @@ var notification_default = define({
|
|
|
7156
7274
|
//#endregion
|
|
7157
7275
|
//#region src/core/domain/plugin/services/configParser.ts
|
|
7158
7276
|
function parsePluginEntry(raw, index) {
|
|
7159
|
-
if (!isRecord
|
|
7160
|
-
|
|
7161
|
-
if (
|
|
7277
|
+
if (!isRecord(raw)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, `Plugin at index ${index} must be an object`);
|
|
7278
|
+
if (typeof raw.id !== "string" || raw.id.length === 0) throw new BusinessRuleError(PluginErrorCode.PlEmptyPluginId, `Plugin at index ${index} must have a non-empty "id" property`);
|
|
7279
|
+
if (raw.enabled !== void 0 && raw.enabled !== null && typeof raw.enabled !== "boolean") throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, `Plugin at index ${index} has invalid "enabled": must be a boolean`);
|
|
7162
7280
|
return {
|
|
7163
|
-
id:
|
|
7164
|
-
name: typeof
|
|
7165
|
-
enabled: typeof
|
|
7281
|
+
id: raw.id,
|
|
7282
|
+
name: typeof raw.name === "string" ? raw.name : "",
|
|
7283
|
+
enabled: typeof raw.enabled === "boolean" ? raw.enabled : true
|
|
7166
7284
|
};
|
|
7167
7285
|
}
|
|
7168
7286
|
const PluginConfigParser = { parse: (rawText) => {
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
}
|
|
7174
|
-
throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
7175
|
-
}
|
|
7176
|
-
if (!isRecord$1(parsed)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, "Config must be a YAML object");
|
|
7177
|
-
const obj = parsed;
|
|
7287
|
+
const obj = parseYamlConfig(rawText, {
|
|
7288
|
+
emptyConfigText: PluginErrorCode.PlEmptyConfigText,
|
|
7289
|
+
invalidConfigYaml: PluginErrorCode.PlInvalidConfigYaml,
|
|
7290
|
+
invalidConfigStructure: PluginErrorCode.PlInvalidConfigStructure
|
|
7291
|
+
}, "Plugin");
|
|
7178
7292
|
if (!Array.isArray(obj.plugins)) throw new BusinessRuleError(PluginErrorCode.PlInvalidConfigStructure, "Config must have a \"plugins\" array");
|
|
7179
|
-
|
|
7293
|
+
const plugins = obj.plugins.map((item, i) => parsePluginEntry(item, i));
|
|
7294
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
7295
|
+
for (const plugin of plugins) {
|
|
7296
|
+
if (seenIds.has(plugin.id)) throw new BusinessRuleError(PluginErrorCode.PlDuplicatePluginId, `Duplicate plugin ID: "${plugin.id}"`);
|
|
7297
|
+
seenIds.add(plugin.id);
|
|
7298
|
+
}
|
|
7299
|
+
return { plugins };
|
|
7180
7300
|
} };
|
|
7181
7301
|
|
|
7182
7302
|
//#endregion
|
|
@@ -7399,7 +7519,7 @@ const VALID_ENTITY_TYPES$1 = new Set([
|
|
|
7399
7519
|
]);
|
|
7400
7520
|
const VALID_ACTION_TYPES = new Set(["PRIMARY", "SECONDARY"]);
|
|
7401
7521
|
function parseProcessEntity(raw, index) {
|
|
7402
|
-
if (!isRecord
|
|
7522
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Entity at index ${index} must be an object`);
|
|
7403
7523
|
const obj = raw;
|
|
7404
7524
|
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
7525
|
const result = { type: obj.type };
|
|
@@ -7414,7 +7534,7 @@ function parseProcessEntity(raw, index) {
|
|
|
7414
7534
|
return withCode;
|
|
7415
7535
|
}
|
|
7416
7536
|
function parseAssignee(raw, stateName) {
|
|
7417
|
-
if (!isRecord
|
|
7537
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must be an object`);
|
|
7418
7538
|
const obj = raw;
|
|
7419
7539
|
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
7540
|
if (!Array.isArray(obj.entities)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must have an "entities" array`);
|
|
@@ -7425,7 +7545,7 @@ function parseAssignee(raw, stateName) {
|
|
|
7425
7545
|
};
|
|
7426
7546
|
}
|
|
7427
7547
|
function parseState(raw, stateName) {
|
|
7428
|
-
if (!isRecord
|
|
7548
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must be an object`);
|
|
7429
7549
|
const obj = raw;
|
|
7430
7550
|
if (typeof obj.index !== "number") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must have a numeric "index" property`);
|
|
7431
7551
|
if (obj.assignee === void 0 || obj.assignee === null) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must have an "assignee" property`);
|
|
@@ -7436,13 +7556,13 @@ function parseState(raw, stateName) {
|
|
|
7436
7556
|
};
|
|
7437
7557
|
}
|
|
7438
7558
|
function parseExecutableUser(raw, actionIndex) {
|
|
7439
|
-
if (!isRecord
|
|
7559
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${actionIndex}: executableUser must be an object`);
|
|
7440
7560
|
const obj = raw;
|
|
7441
7561
|
if (!Array.isArray(obj.entities)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${actionIndex}: executableUser must have an "entities" array`);
|
|
7442
7562
|
return { entities: obj.entities.map((item, i) => parseProcessEntity(item, i)) };
|
|
7443
7563
|
}
|
|
7444
7564
|
function parseAction(raw, index) {
|
|
7445
|
-
if (!isRecord
|
|
7565
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must be an object`);
|
|
7446
7566
|
const obj = raw;
|
|
7447
7567
|
if (typeof obj.name !== "string") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must have a "name" string property`);
|
|
7448
7568
|
if (typeof obj.from !== "string") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must have a "from" string property`);
|
|
@@ -7470,11 +7590,11 @@ const ProcessManagementConfigParser = { parse: (rawText) => {
|
|
|
7470
7590
|
} catch (error) {
|
|
7471
7591
|
throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
7472
7592
|
}
|
|
7473
|
-
if (!isRecord
|
|
7593
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config must be a YAML object");
|
|
7474
7594
|
const obj = parsed;
|
|
7475
7595
|
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
|
|
7596
|
+
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)");
|
|
7597
|
+
const rawStates = isRecord(obj.states) ? obj.states : {};
|
|
7478
7598
|
const states = {};
|
|
7479
7599
|
for (const [name, value] of Object.entries(rawStates)) states[name] = parseState(value, name);
|
|
7480
7600
|
if (!Array.isArray(obj.actions) && obj.actions !== void 0) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config \"actions\" must be an array");
|
|
@@ -7775,7 +7895,7 @@ function parseBooleanField(value, fieldName, context) {
|
|
|
7775
7895
|
throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidPermissionValue, `${context} has invalid "${fieldName}" value: ${String(value)}. Must be a boolean`);
|
|
7776
7896
|
}
|
|
7777
7897
|
function parseEntity(raw, index) {
|
|
7778
|
-
if (!isRecord
|
|
7898
|
+
if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Entity at index ${index} must be an object`);
|
|
7779
7899
|
const obj = raw;
|
|
7780
7900
|
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
7901
|
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 +7905,7 @@ function parseEntity(raw, index) {
|
|
|
7785
7905
|
};
|
|
7786
7906
|
}
|
|
7787
7907
|
function parseRecordRightEntity(raw, index) {
|
|
7788
|
-
if (!isRecord
|
|
7908
|
+
if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right entity at index ${index} must be an object`);
|
|
7789
7909
|
const obj = raw;
|
|
7790
7910
|
const entity = parseEntity(obj.entity, index);
|
|
7791
7911
|
const context = `Record right entity at index ${index}`;
|
|
@@ -7798,7 +7918,7 @@ function parseRecordRightEntity(raw, index) {
|
|
|
7798
7918
|
};
|
|
7799
7919
|
}
|
|
7800
7920
|
function parseRecordRight(raw, index) {
|
|
7801
|
-
if (!isRecord
|
|
7921
|
+
if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right at index ${index} must be an object`);
|
|
7802
7922
|
const obj = raw;
|
|
7803
7923
|
if (!Array.isArray(obj.entities)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right at index ${index} must have an "entities" array`);
|
|
7804
7924
|
const entities = obj.entities.map((item, i) => parseRecordRightEntity(item, i));
|
|
@@ -7815,7 +7935,7 @@ const RecordPermissionConfigParser = { parse: (rawText) => {
|
|
|
7815
7935
|
} catch (error) {
|
|
7816
7936
|
throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
7817
7937
|
}
|
|
7818
|
-
if (!isRecord
|
|
7938
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, "Config must be a YAML object");
|
|
7819
7939
|
const obj = parsed;
|
|
7820
7940
|
if (!Array.isArray(obj.rights)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
7821
7941
|
return { rights: obj.rights.map((item, i) => parseRecordRight(item, i)) };
|
|
@@ -7954,7 +8074,7 @@ var capture_default$5 = define({
|
|
|
7954
8074
|
//#endregion
|
|
7955
8075
|
//#region src/core/domain/recordPermission/services/diffDetector.ts
|
|
7956
8076
|
function areRightsEqual(a, b) {
|
|
7957
|
-
return deepEqual
|
|
8077
|
+
return deepEqual(a.entities.map((e) => ({
|
|
7958
8078
|
type: e.entity.type,
|
|
7959
8079
|
code: e.entity.code,
|
|
7960
8080
|
viewable: e.viewable,
|
|
@@ -8064,140 +8184,76 @@ var record_acl_default = define({
|
|
|
8064
8184
|
|
|
8065
8185
|
//#endregion
|
|
8066
8186
|
//#region src/core/domain/report/services/configParser.ts
|
|
8067
|
-
const VALID_CHART_TYPES = new Set([
|
|
8068
|
-
"BAR",
|
|
8069
|
-
"COLUMN",
|
|
8070
|
-
"PIE",
|
|
8071
|
-
"LINE",
|
|
8072
|
-
"PIVOT_TABLE",
|
|
8073
|
-
"TABLE",
|
|
8074
|
-
"AREA",
|
|
8075
|
-
"SPLINE",
|
|
8076
|
-
"SPLINE_AREA"
|
|
8077
|
-
]);
|
|
8078
|
-
const VALID_CHART_MODES = new Set([
|
|
8079
|
-
"NORMAL",
|
|
8080
|
-
"STACKED",
|
|
8081
|
-
"PERCENTAGE"
|
|
8082
|
-
]);
|
|
8083
|
-
const VALID_GROUP_PER = new Set([
|
|
8084
|
-
"YEAR",
|
|
8085
|
-
"QUARTER",
|
|
8086
|
-
"MONTH",
|
|
8087
|
-
"WEEK",
|
|
8088
|
-
"DAY",
|
|
8089
|
-
"HOUR",
|
|
8090
|
-
"MINUTE"
|
|
8091
|
-
]);
|
|
8092
|
-
const VALID_AGGREGATION_TYPES = new Set([
|
|
8093
|
-
"COUNT",
|
|
8094
|
-
"SUM",
|
|
8095
|
-
"AVERAGE",
|
|
8096
|
-
"MAX",
|
|
8097
|
-
"MIN"
|
|
8098
|
-
]);
|
|
8099
|
-
const VALID_SORT_BY = new Set([
|
|
8100
|
-
"TOTAL",
|
|
8101
|
-
"GROUP1",
|
|
8102
|
-
"GROUP2",
|
|
8103
|
-
"GROUP3"
|
|
8104
|
-
]);
|
|
8105
|
-
const VALID_DAY_OF_WEEK = new Set([
|
|
8106
|
-
"SUNDAY",
|
|
8107
|
-
"MONDAY",
|
|
8108
|
-
"TUESDAY",
|
|
8109
|
-
"WEDNESDAY",
|
|
8110
|
-
"THURSDAY",
|
|
8111
|
-
"FRIDAY",
|
|
8112
|
-
"SATURDAY"
|
|
8113
|
-
]);
|
|
8114
|
-
const VALID_PERIODIC_PATTERN = new Set([
|
|
8115
|
-
"JAN_APR_JUL_OCT",
|
|
8116
|
-
"FEB_MAY_AUG_NOV",
|
|
8117
|
-
"MAR_JUN_SEP_DEC"
|
|
8118
|
-
]);
|
|
8119
|
-
const VALID_SORT_ORDER = new Set(["ASC", "DESC"]);
|
|
8120
|
-
const VALID_PERIODIC_EVERY = new Set([
|
|
8121
|
-
"YEAR",
|
|
8122
|
-
"QUARTER",
|
|
8123
|
-
"MONTH",
|
|
8124
|
-
"WEEK",
|
|
8125
|
-
"DAY",
|
|
8126
|
-
"HOUR"
|
|
8127
|
-
]);
|
|
8128
8187
|
function parseGroup(raw, index) {
|
|
8129
|
-
if (!isRecord
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
if (typeof obj.per !== "string" || !VALID_GROUP_PER.has(obj.per)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Group at index ${index} has invalid per: ${String(obj.per)}. Must be YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, or MINUTE`);
|
|
8188
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Group at index ${index} must be an object`);
|
|
8189
|
+
if (typeof raw.code !== "string" || raw.code.length === 0) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Group at index ${index} must have a non-empty "code" property`);
|
|
8190
|
+
const result = { code: raw.code };
|
|
8191
|
+
if (raw.per !== void 0 && raw.per !== null) {
|
|
8192
|
+
if (typeof raw.per !== "string" || !isGroupPer(raw.per)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Group at index ${index} has invalid per: ${String(raw.per)}. Must be YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, or MINUTE`);
|
|
8135
8193
|
return {
|
|
8136
8194
|
...result,
|
|
8137
|
-
per:
|
|
8195
|
+
per: raw.per
|
|
8138
8196
|
};
|
|
8139
8197
|
}
|
|
8140
8198
|
return result;
|
|
8141
8199
|
}
|
|
8142
8200
|
function parseAggregation(raw, index) {
|
|
8143
|
-
if (!isRecord
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
if (typeof obj.code !== "string") throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Aggregation at index ${index} has invalid code: must be a string`);
|
|
8201
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Aggregation at index ${index} must be an object`);
|
|
8202
|
+
if (typeof raw.type !== "string" || !isAggregationType(raw.type)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Aggregation at index ${index} has invalid type: ${String(raw.type)}. Must be COUNT, SUM, AVERAGE, MAX, or MIN`);
|
|
8203
|
+
const result = { type: raw.type };
|
|
8204
|
+
if (raw.code !== void 0 && raw.code !== null) {
|
|
8205
|
+
if (typeof raw.code !== "string") throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Aggregation at index ${index} has invalid code: must be a string`);
|
|
8149
8206
|
return {
|
|
8150
8207
|
...result,
|
|
8151
|
-
code:
|
|
8208
|
+
code: raw.code
|
|
8152
8209
|
};
|
|
8153
8210
|
}
|
|
8154
8211
|
return result;
|
|
8155
8212
|
}
|
|
8156
8213
|
function parseSort(raw, index) {
|
|
8157
|
-
if (!isRecord
|
|
8158
|
-
|
|
8159
|
-
if (typeof
|
|
8160
|
-
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`);
|
|
8214
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Sort at index ${index} must be an object`);
|
|
8215
|
+
if (typeof raw.by !== "string" || !isSortBy(raw.by)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Sort at index ${index} has invalid by: ${String(raw.by)}. Must be TOTAL, GROUP1, GROUP2, or GROUP3`);
|
|
8216
|
+
if (typeof raw.order !== "string" || !isSortOrder(raw.order)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Sort at index ${index} has invalid order: ${String(raw.order)}. Must be ASC or DESC`);
|
|
8161
8217
|
return {
|
|
8162
|
-
by:
|
|
8163
|
-
order:
|
|
8218
|
+
by: raw.by,
|
|
8219
|
+
order: raw.order
|
|
8164
8220
|
};
|
|
8165
8221
|
}
|
|
8166
8222
|
function parsePeriodicReportPeriod(raw) {
|
|
8167
|
-
if (!isRecord
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
const every = obj.every;
|
|
8223
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport.period must be an object");
|
|
8224
|
+
if (typeof raw.every !== "string" || !isPeriodicReportEvery(raw.every)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has invalid every: ${String(raw.every)}. Must be YEAR, QUARTER, MONTH, WEEK, DAY, or HOUR`);
|
|
8225
|
+
const every = raw.every;
|
|
8171
8226
|
let month;
|
|
8172
|
-
if (
|
|
8173
|
-
const parsed = Number(
|
|
8174
|
-
if (Number.
|
|
8227
|
+
if (raw.month !== void 0 && raw.month !== null) {
|
|
8228
|
+
const parsed = Number(raw.month);
|
|
8229
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 12) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has invalid month: ${String(raw.month)}. Must be an integer between 1 and 12`);
|
|
8175
8230
|
month = parsed;
|
|
8176
8231
|
}
|
|
8177
8232
|
let pattern;
|
|
8178
|
-
if (
|
|
8179
|
-
if (typeof
|
|
8180
|
-
pattern =
|
|
8233
|
+
if (raw.pattern !== void 0 && raw.pattern !== null) {
|
|
8234
|
+
if (typeof raw.pattern !== "string" || !isPeriodicReportPattern(raw.pattern)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has invalid pattern: ${String(raw.pattern)}. Must be JAN_APR_JUL_OCT, FEB_MAY_AUG_NOV, or MAR_JUN_SEP_DEC`);
|
|
8235
|
+
pattern = raw.pattern;
|
|
8181
8236
|
}
|
|
8182
8237
|
let dayOfMonth;
|
|
8183
|
-
if (
|
|
8238
|
+
if (raw.dayOfMonth !== void 0 && raw.dayOfMonth !== null) if (raw.dayOfMonth === "END_OF_MONTH") dayOfMonth = "END_OF_MONTH";
|
|
8184
8239
|
else {
|
|
8185
|
-
const parsed = Number(
|
|
8186
|
-
if (Number.
|
|
8240
|
+
const parsed = Number(raw.dayOfMonth);
|
|
8241
|
+
if (!Number.isInteger(parsed)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has invalid dayOfMonth: ${String(raw.dayOfMonth)}. Must be an integer or "END_OF_MONTH"`);
|
|
8242
|
+
if (parsed < 1 || parsed > 31) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has out-of-range dayOfMonth: ${parsed}. Must be 1-31`);
|
|
8187
8243
|
dayOfMonth = parsed;
|
|
8188
8244
|
}
|
|
8189
8245
|
let time;
|
|
8190
|
-
if (
|
|
8246
|
+
if (raw.time !== void 0 && raw.time !== null) time = String(raw.time);
|
|
8191
8247
|
let dayOfWeek;
|
|
8192
|
-
if (
|
|
8193
|
-
const dayStr = String(
|
|
8194
|
-
if (!
|
|
8248
|
+
if (raw.dayOfWeek !== void 0 && raw.dayOfWeek !== null) {
|
|
8249
|
+
const dayStr = String(raw.dayOfWeek);
|
|
8250
|
+
if (!isDayOfWeek(dayStr)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has invalid dayOfWeek: ${dayStr}. Must be SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, or SATURDAY`);
|
|
8195
8251
|
dayOfWeek = dayStr;
|
|
8196
8252
|
}
|
|
8197
8253
|
let minute;
|
|
8198
|
-
if (
|
|
8199
|
-
const parsed = Number(
|
|
8200
|
-
if (Number.
|
|
8254
|
+
if (raw.minute !== void 0 && raw.minute !== null) {
|
|
8255
|
+
const parsed = Number(raw.minute);
|
|
8256
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 50 || parsed % 10 !== 0) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `periodicReport.period has invalid minute: ${String(raw.minute)}. Must be a multiple of 10 (0, 10, 20, 30, 40, 50)`);
|
|
8201
8257
|
minute = parsed;
|
|
8202
8258
|
}
|
|
8203
8259
|
return {
|
|
@@ -8211,33 +8267,35 @@ function parsePeriodicReportPeriod(raw) {
|
|
|
8211
8267
|
};
|
|
8212
8268
|
}
|
|
8213
8269
|
function parsePeriodicReport(raw) {
|
|
8214
|
-
if (!isRecord
|
|
8215
|
-
const
|
|
8216
|
-
if (typeof
|
|
8217
|
-
const period = parsePeriodicReportPeriod(obj.period);
|
|
8270
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport must be an object");
|
|
8271
|
+
const active = raw.active;
|
|
8272
|
+
if (typeof active !== "boolean") throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "periodicReport.active must be a boolean");
|
|
8218
8273
|
return {
|
|
8219
|
-
active
|
|
8220
|
-
period
|
|
8274
|
+
active,
|
|
8275
|
+
period: parsePeriodicReportPeriod(raw.period)
|
|
8221
8276
|
};
|
|
8222
8277
|
}
|
|
8223
8278
|
function parseReportConfig(raw, reportName) {
|
|
8224
|
-
if (
|
|
8225
|
-
|
|
8226
|
-
if (typeof
|
|
8279
|
+
if (reportName.length === 0) throw new BusinessRuleError(ReportErrorCode.RtEmptyReportName, "Report name (key) must not be empty");
|
|
8280
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Report "${reportName}" must be an object`);
|
|
8281
|
+
if (typeof raw.chartType !== "string" || !isChartType(raw.chartType)) throw new BusinessRuleError(ReportErrorCode.RtInvalidChartType, `Report "${reportName}" has invalid chartType: ${String(raw.chartType)}. Must be BAR, COLUMN, PIE, LINE, PIVOT_TABLE, TABLE, AREA, SPLINE, or SPLINE_AREA`);
|
|
8227
8282
|
let chartMode;
|
|
8228
|
-
if (
|
|
8229
|
-
if (typeof
|
|
8230
|
-
chartMode =
|
|
8231
|
-
}
|
|
8232
|
-
const name = typeof
|
|
8233
|
-
if (
|
|
8234
|
-
const index =
|
|
8235
|
-
|
|
8236
|
-
const
|
|
8237
|
-
|
|
8238
|
-
const
|
|
8283
|
+
if (raw.chartMode !== void 0 && raw.chartMode !== null) {
|
|
8284
|
+
if (typeof raw.chartMode !== "string" || !isChartMode(raw.chartMode)) throw new BusinessRuleError(ReportErrorCode.RtInvalidChartMode, `Report "${reportName}" has invalid chartMode: ${String(raw.chartMode)}. Must be NORMAL, STACKED, or PERCENTAGE`);
|
|
8285
|
+
chartMode = raw.chartMode;
|
|
8286
|
+
}
|
|
8287
|
+
const name = typeof raw.name === "string" && raw.name.length > 0 ? raw.name : reportName;
|
|
8288
|
+
if (raw.index !== void 0 && raw.index !== null && (typeof raw.index !== "number" || !Number.isInteger(raw.index) || raw.index < 0)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Report "${reportName}" has invalid index: ${String(raw.index)}. Must be a non-negative integer`);
|
|
8289
|
+
const index = typeof raw.index === "number" ? raw.index : 0;
|
|
8290
|
+
if (raw.groups !== void 0 && !Array.isArray(raw.groups)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Report "${reportName}" has invalid groups: must be an array`);
|
|
8291
|
+
const groups = Array.isArray(raw.groups) ? raw.groups.map((item, i) => parseGroup(item, i)) : [];
|
|
8292
|
+
if (raw.aggregations !== void 0 && !Array.isArray(raw.aggregations)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Report "${reportName}" has invalid aggregations: must be an array`);
|
|
8293
|
+
const aggregations = Array.isArray(raw.aggregations) ? raw.aggregations.map((item, i) => parseAggregation(item, i)) : [];
|
|
8294
|
+
const filterCond = typeof raw.filterCond === "string" ? raw.filterCond : "";
|
|
8295
|
+
if (raw.sorts !== void 0 && !Array.isArray(raw.sorts)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, `Report "${reportName}" has invalid sorts: must be an array`);
|
|
8296
|
+
const sorts = Array.isArray(raw.sorts) ? raw.sorts.map((item, i) => parseSort(item, i)) : [];
|
|
8239
8297
|
const result = {
|
|
8240
|
-
chartType:
|
|
8298
|
+
chartType: raw.chartType,
|
|
8241
8299
|
...chartMode !== void 0 ? { chartMode } : {},
|
|
8242
8300
|
index,
|
|
8243
8301
|
name,
|
|
@@ -8246,23 +8304,19 @@ function parseReportConfig(raw, reportName) {
|
|
|
8246
8304
|
filterCond,
|
|
8247
8305
|
sorts
|
|
8248
8306
|
};
|
|
8249
|
-
if (
|
|
8307
|
+
if (raw.periodicReport !== void 0 && raw.periodicReport !== null) return {
|
|
8250
8308
|
...result,
|
|
8251
|
-
periodicReport: parsePeriodicReport(
|
|
8309
|
+
periodicReport: parsePeriodicReport(raw.periodicReport)
|
|
8252
8310
|
};
|
|
8253
8311
|
return result;
|
|
8254
8312
|
}
|
|
8255
8313
|
const ReportConfigParser = { parse: (rawText) => {
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
}
|
|
8261
|
-
|
|
8262
|
-
}
|
|
8263
|
-
if (!isRecord$1(parsed)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must be a YAML object");
|
|
8264
|
-
const obj = parsed;
|
|
8265
|
-
if (!isRecord$1(obj.reports)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must have a \"reports\" object");
|
|
8314
|
+
const obj = parseYamlConfig(rawText, {
|
|
8315
|
+
emptyConfigText: ReportErrorCode.RtEmptyConfigText,
|
|
8316
|
+
invalidConfigYaml: ReportErrorCode.RtInvalidConfigYaml,
|
|
8317
|
+
invalidConfigStructure: ReportErrorCode.RtInvalidConfigStructure
|
|
8318
|
+
}, "Report");
|
|
8319
|
+
if (!isRecord(obj.reports)) throw new BusinessRuleError(ReportErrorCode.RtInvalidConfigStructure, "Config must have a \"reports\" object");
|
|
8266
8320
|
const rawReports = obj.reports;
|
|
8267
8321
|
const reports = {};
|
|
8268
8322
|
for (const [name, value] of Object.entries(rawReports)) reports[name] = parseReportConfig(value, name);
|
|
@@ -8408,36 +8462,33 @@ function compareReports(local, remote) {
|
|
|
8408
8462
|
if ((local.chartMode ?? "") !== (remote.chartMode ?? "")) diffs.push(`chartMode: ${remote.chartMode ?? "(unset)"} -> ${local.chartMode ?? "(unset)"}`);
|
|
8409
8463
|
if (local.index !== remote.index) diffs.push(`index: ${remote.index} -> ${local.index}`);
|
|
8410
8464
|
if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
|
|
8411
|
-
if (!deepEqual
|
|
8412
|
-
if (!deepEqual
|
|
8413
|
-
if (!deepEqual
|
|
8414
|
-
if (!deepEqual
|
|
8465
|
+
if (!deepEqual(local.groups, remote.groups)) diffs.push("groups changed");
|
|
8466
|
+
if (!deepEqual(local.aggregations, remote.aggregations)) diffs.push("aggregations changed");
|
|
8467
|
+
if (!deepEqual(local.sorts, remote.sorts)) diffs.push("sorts changed");
|
|
8468
|
+
if (!deepEqual(local.periodicReport ?? null, remote.periodicReport ?? null)) diffs.push("periodicReport changed");
|
|
8415
8469
|
return diffs;
|
|
8416
8470
|
}
|
|
8417
8471
|
const ReportDiffDetector = { detect: (local, remote) => {
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
const remoteReport = remote.reports[name];
|
|
8421
|
-
if (!remoteReport) entries.push({
|
|
8472
|
+
return buildDiffResult(detectRecordDiff(local.reports, remote.reports, {
|
|
8473
|
+
onAdded: (name, localReport) => ({
|
|
8422
8474
|
type: "added",
|
|
8423
8475
|
reportName: name,
|
|
8424
8476
|
details: `chartType: ${localReport.chartType}`
|
|
8425
|
-
})
|
|
8426
|
-
|
|
8477
|
+
}),
|
|
8478
|
+
onModified: (name, localReport, remoteReport) => {
|
|
8427
8479
|
const diffs = compareReports(localReport, remoteReport);
|
|
8428
|
-
if (diffs.length > 0)
|
|
8480
|
+
if (diffs.length > 0) return {
|
|
8429
8481
|
type: "modified",
|
|
8430
8482
|
reportName: name,
|
|
8431
8483
|
details: diffs.join(", ")
|
|
8432
|
-
}
|
|
8433
|
-
}
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
});
|
|
8440
|
-
return buildDiffResult(entries);
|
|
8484
|
+
};
|
|
8485
|
+
},
|
|
8486
|
+
onDeleted: (name, remoteReport) => ({
|
|
8487
|
+
type: "deleted",
|
|
8488
|
+
reportName: name,
|
|
8489
|
+
details: `chartType: ${remoteReport.chartType}`
|
|
8490
|
+
})
|
|
8491
|
+
}));
|
|
8441
8492
|
} };
|
|
8442
8493
|
|
|
8443
8494
|
//#endregion
|
|
@@ -8539,26 +8590,26 @@ function isMapEqual(a, b) {
|
|
|
8539
8590
|
}
|
|
8540
8591
|
function isPropertiesEqual(a, b) {
|
|
8541
8592
|
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
|
|
8593
|
+
if (a.type === "REFERENCE_TABLE" && b.type === "REFERENCE_TABLE") return deepEqual(a.properties.referenceTable, b.properties.referenceTable);
|
|
8594
|
+
return deepEqual(a.properties, b.properties);
|
|
8544
8595
|
}
|
|
8545
8596
|
function isFieldEqual(a, b) {
|
|
8546
8597
|
if (a.type !== b.type) return false;
|
|
8547
8598
|
if (a.label !== b.label) return false;
|
|
8548
8599
|
if (a.code !== b.code) return false;
|
|
8549
|
-
if (
|
|
8600
|
+
if ((a.noLabel ?? false) !== (b.noLabel ?? false)) return false;
|
|
8550
8601
|
return isPropertiesEqual(a, b);
|
|
8551
8602
|
}
|
|
8552
8603
|
function describeChanges$1(before, after) {
|
|
8553
8604
|
const changes = [];
|
|
8554
8605
|
if (before.type !== after.type) changes.push(`type: ${before.type} -> ${after.type}`);
|
|
8555
8606
|
if (before.label !== after.label) changes.push(`label: ${before.label} -> ${after.label}`);
|
|
8556
|
-
if (
|
|
8607
|
+
if ((before.noLabel ?? false) !== (after.noLabel ?? false)) changes.push(`noLabel: ${before.noLabel ?? false} -> ${after.noLabel ?? false}`);
|
|
8557
8608
|
if (!isPropertiesEqual(before, after)) changes.push("properties changed");
|
|
8558
8609
|
return changes.length > 0 ? changes.join(", ") : "no visible changes";
|
|
8559
8610
|
}
|
|
8560
8611
|
function isLayoutEqual(a, b) {
|
|
8561
|
-
return deepEqual
|
|
8612
|
+
return deepEqual(a, b);
|
|
8562
8613
|
}
|
|
8563
8614
|
const DiffDetector = {
|
|
8564
8615
|
detectLayoutChanges: (schemaLayout, currentLayout) => {
|
|
@@ -8595,6 +8646,16 @@ const DiffDetector = {
|
|
|
8595
8646
|
}
|
|
8596
8647
|
};
|
|
8597
8648
|
|
|
8649
|
+
//#endregion
|
|
8650
|
+
//#region src/core/domain/formSchema/entity.ts
|
|
8651
|
+
const Schema = { create: (fields, layout) => {
|
|
8652
|
+
if (fields.size === 0) throw new BusinessRuleError(FormSchemaErrorCode.FsEmptyFields, "Schema must have at least one field");
|
|
8653
|
+
return {
|
|
8654
|
+
fields,
|
|
8655
|
+
layout
|
|
8656
|
+
};
|
|
8657
|
+
} };
|
|
8658
|
+
|
|
8598
8659
|
//#endregion
|
|
8599
8660
|
//#region src/core/domain/formSchema/services/schemaParser.ts
|
|
8600
8661
|
const VALID_UNIT_POSITIONS = new Set(["BEFORE", "AFTER"]);
|
|
@@ -8614,7 +8675,7 @@ const VALID_LINK_PROTOCOLS = new Set([
|
|
|
8614
8675
|
"MAIL"
|
|
8615
8676
|
]);
|
|
8616
8677
|
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(", ")}`);
|
|
8678
|
+
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
8679
|
}
|
|
8619
8680
|
function validateFieldProperties(code, fieldType, properties) {
|
|
8620
8681
|
switch (fieldType) {
|
|
@@ -8683,17 +8744,38 @@ const LAYOUT_ATTRIBUTES = new Set(["size"]);
|
|
|
8683
8744
|
const DECORATION_ATTRIBUTES = new Set(["elementId"]);
|
|
8684
8745
|
const GROUP_ATTRIBUTES = new Set(["openGroup", "layout"]);
|
|
8685
8746
|
const SUBTABLE_ATTRIBUTES = new Set(["fields"]);
|
|
8747
|
+
/**
|
|
8748
|
+
* Parses a raw size object into an ElementSize.
|
|
8749
|
+
* Returns undefined when no size properties are present, treating an empty
|
|
8750
|
+
* object the same as absent — layout elements without explicit sizing should
|
|
8751
|
+
* not carry a redundant empty size object.
|
|
8752
|
+
*/
|
|
8686
8753
|
function parseSize(raw) {
|
|
8687
|
-
if (!isRecord
|
|
8754
|
+
if (!isRecord(raw)) return void 0;
|
|
8688
8755
|
const obj = raw;
|
|
8756
|
+
if (obj.width === void 0 && obj.height === void 0 && obj.innerHeight === void 0) return;
|
|
8689
8757
|
return {
|
|
8690
8758
|
...obj.width !== void 0 ? { width: String(obj.width) } : {},
|
|
8691
8759
|
...obj.height !== void 0 ? { height: String(obj.height) } : {},
|
|
8692
8760
|
...obj.innerHeight !== void 0 ? { innerHeight: String(obj.innerHeight) } : {}
|
|
8693
8761
|
};
|
|
8694
8762
|
}
|
|
8695
|
-
|
|
8763
|
+
const BOOLEAN_PROPERTIES = new Set([
|
|
8764
|
+
"required",
|
|
8765
|
+
"unique",
|
|
8766
|
+
"digit",
|
|
8767
|
+
"hideExpression",
|
|
8768
|
+
"defaultNowValue",
|
|
8769
|
+
"openGroup"
|
|
8770
|
+
]);
|
|
8771
|
+
function normalizePropertyValue(key, value) {
|
|
8772
|
+
if (typeof value === "boolean") return value;
|
|
8696
8773
|
if (typeof value === "number") return String(value);
|
|
8774
|
+
if (BOOLEAN_PROPERTIES.has(key) && typeof value === "string") {
|
|
8775
|
+
if (value === "true") return true;
|
|
8776
|
+
if (value === "false") return false;
|
|
8777
|
+
throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Invalid boolean string "${value}" for property "${key}". Expected "true" or "false"`);
|
|
8778
|
+
}
|
|
8697
8779
|
return value;
|
|
8698
8780
|
}
|
|
8699
8781
|
function extractProperties(raw) {
|
|
@@ -8704,7 +8786,7 @@ function extractProperties(raw) {
|
|
|
8704
8786
|
if (DECORATION_ATTRIBUTES.has(key)) continue;
|
|
8705
8787
|
if (GROUP_ATTRIBUTES.has(key)) continue;
|
|
8706
8788
|
if (SUBTABLE_ATTRIBUTES.has(key)) continue;
|
|
8707
|
-
properties[key] = normalizePropertyValue(value);
|
|
8789
|
+
properties[key] = normalizePropertyValue(key, value);
|
|
8708
8790
|
}
|
|
8709
8791
|
return properties;
|
|
8710
8792
|
}
|
|
@@ -8822,10 +8904,10 @@ function parseFieldDefinitionFromFlat(raw) {
|
|
|
8822
8904
|
};
|
|
8823
8905
|
}
|
|
8824
8906
|
if (fieldType === "REFERENCE_TABLE") {
|
|
8825
|
-
if (!isRecord
|
|
8907
|
+
if (!isRecord(raw.referenceTable)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have a "referenceTable" property`);
|
|
8826
8908
|
const refTable = raw.referenceTable;
|
|
8827
|
-
if (!isRecord
|
|
8828
|
-
if (!isRecord
|
|
8909
|
+
if (!isRecord(refTable.relatedApp)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.relatedApp"`);
|
|
8910
|
+
if (!isRecord(refTable.condition)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.condition"`);
|
|
8829
8911
|
if (!Array.isArray(refTable.displayFields)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, `Field "${code}" of type REFERENCE_TABLE must have "referenceTable.displayFields" array`);
|
|
8830
8912
|
const condition = refTable.condition;
|
|
8831
8913
|
const displayFields = refTable.displayFields.map((f) => FieldCode.create(f));
|
|
@@ -8900,6 +8982,7 @@ function parseLayoutElement(raw) {
|
|
|
8900
8982
|
}
|
|
8901
8983
|
function parseLayoutRow(raw) {
|
|
8902
8984
|
if (raw.type !== "ROW") throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidLayoutStructure, `Expected layout row type "ROW", got "${String(raw.type)}"`);
|
|
8985
|
+
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
8986
|
return {
|
|
8904
8987
|
type: "ROW",
|
|
8905
8988
|
fields: (Array.isArray(raw.fields) ? raw.fields : []).map(parseLayoutElement)
|
|
@@ -8939,7 +9022,7 @@ function parseLayoutItem(raw) {
|
|
|
8939
9022
|
const label = String(raw.label ?? "");
|
|
8940
9023
|
const noLabel = typeof raw.noLabel === "boolean" ? raw.noLabel : void 0;
|
|
8941
9024
|
const openGroup = typeof raw.openGroup === "boolean" ? raw.openGroup : void 0;
|
|
8942
|
-
const rawLayout = Array.isArray(raw.layout) ? raw.layout.filter(isRecord
|
|
9025
|
+
const rawLayout = Array.isArray(raw.layout) ? raw.layout.filter(isRecord) : [];
|
|
8943
9026
|
let groupFields = /* @__PURE__ */ new Map();
|
|
8944
9027
|
const layout = [];
|
|
8945
9028
|
for (const r of rawLayout) {
|
|
@@ -9024,22 +9107,21 @@ const SchemaParser = { parse: (rawText) => {
|
|
|
9024
9107
|
} catch {
|
|
9025
9108
|
throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaFormat, "Schema text is not valid YAML/JSON");
|
|
9026
9109
|
}
|
|
9027
|
-
if (!isRecord
|
|
9110
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidSchemaStructure, "Schema must be an object");
|
|
9028
9111
|
const obj = parsed;
|
|
9029
9112
|
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
9113
|
if (!("layout" in obj) || !Array.isArray(obj.layout)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidLayoutStructure, "Schema must have a \"layout\" array");
|
|
9031
|
-
const rawLayout = obj.layout
|
|
9114
|
+
const rawLayout = obj.layout;
|
|
9032
9115
|
let fieldMap = /* @__PURE__ */ new Map();
|
|
9033
9116
|
const layout = [];
|
|
9034
|
-
for (
|
|
9117
|
+
for (let i = 0; i < rawLayout.length; i++) {
|
|
9118
|
+
const rawItem = rawLayout[i];
|
|
9119
|
+
if (!isRecord(rawItem)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidLayoutStructure, `Layout item at index ${i} must be an object`);
|
|
9035
9120
|
const result = parseLayoutItem(rawItem);
|
|
9036
9121
|
layout.push(result.item);
|
|
9037
9122
|
fieldMap = mergeFieldMaps(fieldMap, result.fields);
|
|
9038
9123
|
}
|
|
9039
|
-
return
|
|
9040
|
-
fields: fieldMap,
|
|
9041
|
-
layout
|
|
9042
|
-
};
|
|
9124
|
+
return Schema.create(fieldMap, layout);
|
|
9043
9125
|
} };
|
|
9044
9126
|
|
|
9045
9127
|
//#endregion
|
|
@@ -9863,17 +9945,17 @@ function normalizeValue(value) {
|
|
|
9863
9945
|
if (typeof first === "string") return value;
|
|
9864
9946
|
if (typeof first === "number") return value.map(String);
|
|
9865
9947
|
if (typeof first === "object" && first !== null && "code" in first && Object.keys(first).length === 1) return value;
|
|
9866
|
-
return value.filter(isRecord
|
|
9948
|
+
return value.filter(isRecord).map((row) => {
|
|
9867
9949
|
const normalized = {};
|
|
9868
9950
|
for (const [k, v] of Object.entries(row)) if (Array.isArray(v)) normalized[k] = v.map(String);
|
|
9869
9951
|
else normalized[k] = v === null || v === void 0 ? "" : String(v);
|
|
9870
9952
|
return normalized;
|
|
9871
9953
|
});
|
|
9872
9954
|
}
|
|
9873
|
-
|
|
9955
|
+
throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Unsupported value type: ${typeof value}`);
|
|
9874
9956
|
}
|
|
9875
9957
|
function parseRecord(raw, index) {
|
|
9876
|
-
if (!isRecord
|
|
9958
|
+
if (!isRecord(raw)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Record at index ${index} must be an object`);
|
|
9877
9959
|
const record = {};
|
|
9878
9960
|
for (const [key, value] of Object.entries(raw)) record[key] = normalizeValue(value);
|
|
9879
9961
|
return record;
|
|
@@ -9886,7 +9968,7 @@ const SeedParser = { parse: (rawText) => {
|
|
|
9886
9968
|
} catch {
|
|
9887
9969
|
throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedYaml, "Seed text is not valid YAML");
|
|
9888
9970
|
}
|
|
9889
|
-
if (!isRecord
|
|
9971
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, "Seed data must be an object");
|
|
9890
9972
|
const obj = parsed;
|
|
9891
9973
|
const key = "key" in obj && typeof obj.key === "string" ? UpsertKey.create(obj.key) : null;
|
|
9892
9974
|
if (!("records" in obj) || !Array.isArray(obj.records)) throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, "Seed data must have a \"records\" array");
|
|
@@ -9895,8 +9977,9 @@ const SeedParser = { parse: (rawText) => {
|
|
|
9895
9977
|
for (let i = 0; i < obj.records.length; i++) {
|
|
9896
9978
|
const record = parseRecord(obj.records[i], i);
|
|
9897
9979
|
if (key !== null) {
|
|
9898
|
-
|
|
9899
|
-
|
|
9980
|
+
const keyField = key;
|
|
9981
|
+
if (!(keyField in record)) throw new BusinessRuleError(SeedDataErrorCode.SdMissingKeyField, `Record at index ${i} is missing key field "${key}"`);
|
|
9982
|
+
const keyValue = record[keyField];
|
|
9900
9983
|
if (typeof keyValue !== "string") throw new BusinessRuleError(SeedDataErrorCode.SdInvalidSeedStructure, `Key field "${key}" value at index ${i} must be a string`);
|
|
9901
9984
|
if (seenKeys.has(keyValue)) throw new BusinessRuleError(SeedDataErrorCode.SdDuplicateKeyValue, `Duplicate key value "${keyValue}" at index ${i}`);
|
|
9902
9985
|
seenKeys.add(keyValue);
|
|
@@ -9911,30 +9994,6 @@ const SeedParser = { parse: (rawText) => {
|
|
|
9911
9994
|
|
|
9912
9995
|
//#endregion
|
|
9913
9996
|
//#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
9997
|
function recordsEqual(seed, existing, keyField) {
|
|
9939
9998
|
const seedKeys = Object.keys(seed).filter((k) => k !== keyField);
|
|
9940
9999
|
for (const key of seedKeys) {
|
|
@@ -10210,7 +10269,7 @@ const VALID_ROUNDING_MODES = new Set([
|
|
|
10210
10269
|
"DOWN"
|
|
10211
10270
|
]);
|
|
10212
10271
|
function parseIcon(raw) {
|
|
10213
|
-
if (!isRecord
|
|
10272
|
+
if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must be an object with \"type\" and \"key\" properties");
|
|
10214
10273
|
const obj = raw;
|
|
10215
10274
|
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
10275
|
if (typeof obj.key !== "string" || obj.key.length === 0) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must have a non-empty \"key\" property");
|
|
@@ -10220,7 +10279,7 @@ function parseIcon(raw) {
|
|
|
10220
10279
|
};
|
|
10221
10280
|
}
|
|
10222
10281
|
function parseTitleField(raw) {
|
|
10223
|
-
if (!isRecord
|
|
10282
|
+
if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "titleField must be an object with \"selectionMode\" property");
|
|
10224
10283
|
const obj = raw;
|
|
10225
10284
|
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
10285
|
const result = { selectionMode: obj.selectionMode };
|
|
@@ -10234,7 +10293,7 @@ function parseTitleField(raw) {
|
|
|
10234
10293
|
return result;
|
|
10235
10294
|
}
|
|
10236
10295
|
function parseNumberPrecision(raw) {
|
|
10237
|
-
if (!isRecord
|
|
10296
|
+
if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision must be an object");
|
|
10238
10297
|
const obj = raw;
|
|
10239
10298
|
if (typeof obj.digits !== "number") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision.digits must be a number");
|
|
10240
10299
|
if (typeof obj.decimalPlaces !== "number") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision.decimalPlaces must be a number");
|
|
@@ -10253,7 +10312,7 @@ const GeneralSettingsConfigParser = { parse: (rawText) => {
|
|
|
10253
10312
|
} catch (error) {
|
|
10254
10313
|
throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
10255
10314
|
}
|
|
10256
|
-
if (!isRecord
|
|
10315
|
+
if (!isRecord(parsed)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "Config must be a YAML object");
|
|
10257
10316
|
const obj = parsed;
|
|
10258
10317
|
let name;
|
|
10259
10318
|
if (obj.name !== void 0 && obj.name !== null) {
|
|
@@ -10473,7 +10532,7 @@ function compareConfigs(local, remote) {
|
|
|
10473
10532
|
});
|
|
10474
10533
|
}
|
|
10475
10534
|
function compareDeepEqual(field, l, r) {
|
|
10476
|
-
if (!deepEqual
|
|
10535
|
+
if (!deepEqual(l, r)) entries.push({
|
|
10477
10536
|
type: "modified",
|
|
10478
10537
|
field,
|
|
10479
10538
|
details: `${field} changed`
|
|
@@ -10538,40 +10597,44 @@ var settings_default = define({
|
|
|
10538
10597
|
|
|
10539
10598
|
//#endregion
|
|
10540
10599
|
//#region src/core/domain/view/services/configParser.ts
|
|
10600
|
+
function parseDeviceType(name, raw) {
|
|
10601
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
10602
|
+
const deviceStr = String(raw);
|
|
10603
|
+
if (!isDeviceType(deviceStr)) throw new BusinessRuleError(ViewErrorCode.VwInvalidDeviceType, `View "${name}" has invalid device type: ${deviceStr}. Must be DESKTOP or ANY`);
|
|
10604
|
+
return deviceStr;
|
|
10605
|
+
}
|
|
10541
10606
|
function parseViewConfig(name, raw) {
|
|
10542
|
-
if (!isRecord
|
|
10543
|
-
|
|
10544
|
-
if (typeof
|
|
10607
|
+
if (!isRecord(raw)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, `View "${name}" must be an object`);
|
|
10608
|
+
if (typeof raw.type !== "string" || !isViewType(raw.type)) throw new BusinessRuleError(ViewErrorCode.VwInvalidViewType, `View "${name}" has invalid type: ${String(raw.type)}. Must be LIST, CALENDAR, or CUSTOM`);
|
|
10609
|
+
if (raw.index !== void 0 && (typeof raw.index !== "number" || !Number.isInteger(raw.index) || raw.index < 0)) throw new BusinessRuleError(ViewErrorCode.VwInvalidIndex, `View "${name}" has invalid index: ${String(raw.index)}. Must be a non-negative integer`);
|
|
10610
|
+
if (raw.fields !== void 0 && !Array.isArray(raw.fields)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, `View "${name}" has invalid fields: must be an array`);
|
|
10611
|
+
if (raw.pager !== void 0 && typeof raw.pager !== "boolean") throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, `View "${name}" has invalid pager: must be a boolean`);
|
|
10612
|
+
const device = parseDeviceType(name, raw.device);
|
|
10545
10613
|
return {
|
|
10546
|
-
type:
|
|
10547
|
-
index: typeof
|
|
10614
|
+
type: raw.type,
|
|
10615
|
+
index: typeof raw.index === "number" ? raw.index : 0,
|
|
10548
10616
|
name,
|
|
10549
|
-
...
|
|
10550
|
-
...Array.isArray(
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
...
|
|
10555
|
-
...
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
...
|
|
10561
|
-
...obj.sort !== void 0 && { sort: String(obj.sort) }
|
|
10617
|
+
...raw.builtinType !== void 0 && { builtinType: String(raw.builtinType) },
|
|
10618
|
+
...Array.isArray(raw.fields) && { fields: raw.fields.map((f, i) => {
|
|
10619
|
+
if (typeof f !== "string") throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, `View "${name}" has non-string field at index ${i}: ${String(f)}`);
|
|
10620
|
+
return f;
|
|
10621
|
+
}) },
|
|
10622
|
+
...raw.date !== void 0 && { date: String(raw.date) },
|
|
10623
|
+
...raw.title !== void 0 && { title: String(raw.title) },
|
|
10624
|
+
...raw.html !== void 0 && { html: String(raw.html) },
|
|
10625
|
+
...raw.pager !== void 0 && { pager: raw.pager },
|
|
10626
|
+
...device !== void 0 && { device },
|
|
10627
|
+
...raw.filterCond !== void 0 && { filterCond: String(raw.filterCond) },
|
|
10628
|
+
...raw.sort !== void 0 && { sort: String(raw.sort) }
|
|
10562
10629
|
};
|
|
10563
10630
|
}
|
|
10564
10631
|
const ViewConfigParser = { parse: (rawText) => {
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
}
|
|
10570
|
-
|
|
10571
|
-
}
|
|
10572
|
-
if (!isRecord$1(parsed)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must be a YAML object");
|
|
10573
|
-
const obj = parsed;
|
|
10574
|
-
if (!isRecord$1(obj.views)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must have a \"views\" object");
|
|
10632
|
+
const obj = parseYamlConfig(rawText, {
|
|
10633
|
+
emptyConfigText: ViewErrorCode.VwEmptyConfigText,
|
|
10634
|
+
invalidConfigYaml: ViewErrorCode.VwInvalidConfigYaml,
|
|
10635
|
+
invalidConfigStructure: ViewErrorCode.VwInvalidConfigStructure
|
|
10636
|
+
}, "View");
|
|
10637
|
+
if (!isRecord(obj.views)) throw new BusinessRuleError(ViewErrorCode.VwInvalidConfigStructure, "Config must have a \"views\" object");
|
|
10575
10638
|
const viewsObj = obj.views;
|
|
10576
10639
|
const views = {};
|
|
10577
10640
|
for (const [name, value] of Object.entries(viewsObj)) {
|
|
@@ -10722,7 +10785,6 @@ var capture_default = define({
|
|
|
10722
10785
|
//#region src/core/domain/view/services/diffDetector.ts
|
|
10723
10786
|
function describeChanges(local, remote) {
|
|
10724
10787
|
const changes = [];
|
|
10725
|
-
if (local.name !== remote.name) changes.push(`name: "${remote.name}" -> "${local.name}"`);
|
|
10726
10788
|
if (local.type !== remote.type) changes.push(`type: ${remote.type} -> ${local.type}`);
|
|
10727
10789
|
if ((local.builtinType ?? "") !== (remote.builtinType ?? "")) changes.push("builtinType changed");
|
|
10728
10790
|
if (local.index !== remote.index) changes.push(`index: ${remote.index} -> ${local.index}`);
|
|
@@ -10733,33 +10795,30 @@ function describeChanges(local, remote) {
|
|
|
10733
10795
|
if ((local.html ?? "") !== (remote.html ?? "")) changes.push("html changed");
|
|
10734
10796
|
if ((local.pager ?? false) !== (remote.pager ?? false)) changes.push(`pager: ${String(remote.pager ?? false)} -> ${String(local.pager ?? false)}`);
|
|
10735
10797
|
if ((local.device ?? "") !== (remote.device ?? "")) changes.push("device changed");
|
|
10736
|
-
if (!deepEqual
|
|
10798
|
+
if (!deepEqual(local.fields ?? [], remote.fields ?? [])) changes.push("fields changed");
|
|
10737
10799
|
return changes;
|
|
10738
10800
|
}
|
|
10739
10801
|
const ViewDiffDetector = { detect: (localViews, remoteViews) => {
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
const remoteView = remoteViews[name];
|
|
10743
|
-
if (remoteView === void 0) entries.push({
|
|
10802
|
+
return buildDiffResult(detectRecordDiff(localViews, remoteViews, {
|
|
10803
|
+
onAdded: (name) => ({
|
|
10744
10804
|
type: "added",
|
|
10745
10805
|
viewName: name,
|
|
10746
10806
|
details: "new view"
|
|
10747
|
-
})
|
|
10748
|
-
|
|
10807
|
+
}),
|
|
10808
|
+
onModified: (name, localView, remoteView) => {
|
|
10749
10809
|
const changes = describeChanges(localView, remoteView);
|
|
10750
|
-
if (changes.length > 0)
|
|
10810
|
+
if (changes.length > 0) return {
|
|
10751
10811
|
type: "modified",
|
|
10752
10812
|
viewName: name,
|
|
10753
10813
|
details: changes.join(", ")
|
|
10754
|
-
}
|
|
10755
|
-
}
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
});
|
|
10762
|
-
return buildDiffResult(entries);
|
|
10814
|
+
};
|
|
10815
|
+
},
|
|
10816
|
+
onDeleted: (name) => ({
|
|
10817
|
+
type: "deleted",
|
|
10818
|
+
viewName: name,
|
|
10819
|
+
details: "removed"
|
|
10820
|
+
})
|
|
10821
|
+
}));
|
|
10763
10822
|
} };
|
|
10764
10823
|
|
|
10765
10824
|
//#endregion
|