kintone-migrator 0.24.2 → 0.24.4
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 +510 -510
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4,9 +4,9 @@ import "dotenv/config";
|
|
|
4
4
|
import { cli, define } from "gunshi";
|
|
5
5
|
import * as p from "@clack/prompts";
|
|
6
6
|
import { parse, stringify } from "yaml";
|
|
7
|
-
import { KintoneRestAPIClient, KintoneRestAPIError } from "@kintone/rest-api-client";
|
|
8
7
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
9
8
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
9
|
+
import { KintoneRestAPIClient, KintoneRestAPIError } from "@kintone/rest-api-client";
|
|
10
10
|
import * as v from "valibot";
|
|
11
11
|
import pc from "picocolors";
|
|
12
12
|
|
|
@@ -68,6 +68,7 @@ const FieldPermissionErrorCode = {
|
|
|
68
68
|
FpInvalidConfigStructure: "FP_INVALID_CONFIG_STRUCTURE",
|
|
69
69
|
FpInvalidAccessibility: "FP_INVALID_ACCESSIBILITY",
|
|
70
70
|
FpInvalidEntityType: "FP_INVALID_ENTITY_TYPE",
|
|
71
|
+
FpInvalidBooleanField: "FP_INVALID_BOOLEAN_FIELD",
|
|
71
72
|
FpEmptyFieldCode: "FP_EMPTY_FIELD_CODE",
|
|
72
73
|
FpEmptyEntityCode: "FP_EMPTY_ENTITY_CODE",
|
|
73
74
|
FpDuplicateFieldCode: "FP_DUPLICATE_FIELD_CODE"
|
|
@@ -95,7 +96,9 @@ const GeneralSettingsErrorCode = {
|
|
|
95
96
|
GsInvalidConfigYaml: "GS_INVALID_CONFIG_YAML",
|
|
96
97
|
GsInvalidConfigStructure: "GS_INVALID_CONFIG_STRUCTURE",
|
|
97
98
|
GsInvalidTheme: "GS_INVALID_THEME",
|
|
98
|
-
GsInvalidIconType: "GS_INVALID_ICON_TYPE"
|
|
99
|
+
GsInvalidIconType: "GS_INVALID_ICON_TYPE",
|
|
100
|
+
GsInvalidBooleanField: "GS_INVALID_BOOLEAN_FIELD",
|
|
101
|
+
GsInvalidNumberPrecision: "GS_INVALID_NUMBER_PRECISION"
|
|
99
102
|
};
|
|
100
103
|
|
|
101
104
|
//#endregion
|
|
@@ -130,7 +133,9 @@ const ProcessManagementErrorCode = {
|
|
|
130
133
|
PmInvalidConfigStructure: "PM_INVALID_CONFIG_STRUCTURE",
|
|
131
134
|
PmInvalidAssigneeType: "PM_INVALID_ASSIGNEE_TYPE",
|
|
132
135
|
PmInvalidEntityType: "PM_INVALID_ENTITY_TYPE",
|
|
133
|
-
|
|
136
|
+
PmInvalidBooleanField: "PM_INVALID_BOOLEAN_FIELD",
|
|
137
|
+
PmInvalidActionReference: "PM_INVALID_ACTION_REFERENCE",
|
|
138
|
+
PmDuplicateActionName: "PM_DUPLICATE_ACTION_NAME"
|
|
134
139
|
};
|
|
135
140
|
|
|
136
141
|
//#endregion
|
|
@@ -154,7 +159,8 @@ const RecordPermissionErrorCode = {
|
|
|
154
159
|
RpInvalidConfigStructure: "RP_INVALID_CONFIG_STRUCTURE",
|
|
155
160
|
RpInvalidEntityType: "RP_INVALID_ENTITY_TYPE",
|
|
156
161
|
RpEmptyEntityCode: "RP_EMPTY_ENTITY_CODE",
|
|
157
|
-
RpInvalidPermissionValue: "RP_INVALID_PERMISSION_VALUE"
|
|
162
|
+
RpInvalidPermissionValue: "RP_INVALID_PERMISSION_VALUE",
|
|
163
|
+
RpDuplicateEntity: "RP_DUPLICATE_ENTITY"
|
|
158
164
|
};
|
|
159
165
|
|
|
160
166
|
//#endregion
|
|
@@ -180,6 +186,10 @@ const SeedDataErrorCode = {
|
|
|
180
186
|
SdInvalidKeyFieldValue: "SD_INVALID_KEY_FIELD_VALUE"
|
|
181
187
|
};
|
|
182
188
|
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/core/domain/services/errorCode.ts
|
|
191
|
+
const DomainServiceErrorCode = { YamlSerializationFailed: "DS_YAML_SERIALIZATION_FAILED" };
|
|
192
|
+
|
|
183
193
|
//#endregion
|
|
184
194
|
//#region src/core/domain/view/errorCode.ts
|
|
185
195
|
const ViewErrorCode = {
|
|
@@ -209,6 +219,7 @@ const BusinessRuleErrorCode = {
|
|
|
209
219
|
...RecordPermissionErrorCode,
|
|
210
220
|
...ReportErrorCode,
|
|
211
221
|
...SeedDataErrorCode,
|
|
222
|
+
...DomainServiceErrorCode,
|
|
212
223
|
...ViewErrorCode
|
|
213
224
|
};
|
|
214
225
|
/**
|
|
@@ -329,6 +340,16 @@ function isSystemError(error) {
|
|
|
329
340
|
return error instanceof SystemError;
|
|
330
341
|
}
|
|
331
342
|
|
|
343
|
+
//#endregion
|
|
344
|
+
//#region src/core/application/applyFromConfigBase.ts
|
|
345
|
+
async function applyFromConfig(config) {
|
|
346
|
+
const result = await config.getStorage();
|
|
347
|
+
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, config.notFoundMessage);
|
|
348
|
+
const parsed = config.parseConfig(result.content);
|
|
349
|
+
const remote = await config.fetchRemote();
|
|
350
|
+
await config.update(parsed, remote);
|
|
351
|
+
}
|
|
352
|
+
|
|
332
353
|
//#endregion
|
|
333
354
|
//#region src/lib/typeGuards.ts
|
|
334
355
|
/**
|
|
@@ -344,10 +365,6 @@ function isRecord(value) {
|
|
|
344
365
|
//#endregion
|
|
345
366
|
//#region src/core/domain/typeGuards.ts
|
|
346
367
|
/**
|
|
347
|
-
* Type guard utilities for safe runtime type narrowing.
|
|
348
|
-
* Use these functions instead of `as` casts when working with `unknown` values.
|
|
349
|
-
*/
|
|
350
|
-
/**
|
|
351
368
|
* Narrows `unknown` to `{ code: string }`.
|
|
352
369
|
*/
|
|
353
370
|
function hasCode(value) {
|
|
@@ -369,6 +386,45 @@ function hasOptionalType(value) {
|
|
|
369
386
|
if (!isRecord(value)) return false;
|
|
370
387
|
return value.type === void 0 || typeof value.type === "string";
|
|
371
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Strict boolean validation — rejects non-boolean values.
|
|
391
|
+
* Returns the boolean value if valid, or `defaultValue` when the value is undefined/null.
|
|
392
|
+
* Throws `BusinessRuleError` when the value is present but not a boolean.
|
|
393
|
+
*/
|
|
394
|
+
function parseStrictBoolean(value, fieldName, context, errorCode, defaultValue) {
|
|
395
|
+
if (value === void 0 || value === null) {
|
|
396
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
397
|
+
throw new BusinessRuleError(errorCode, `${context} must have a boolean "${fieldName}" property`);
|
|
398
|
+
}
|
|
399
|
+
if (typeof value !== "boolean") throw new BusinessRuleError(errorCode, `${context} has invalid "${fieldName}" value: ${String(value)}. Must be a boolean`);
|
|
400
|
+
return value;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Validates that an unknown value is a string within an allowed set and returns a typed value.
|
|
404
|
+
* Replaces manual `typeof` + `Set.has` + `as` cast patterns.
|
|
405
|
+
*/
|
|
406
|
+
function parseEnum(value, validValues, errorCode, message) {
|
|
407
|
+
if (typeof value !== "string" || !validValues.has(value)) throw new BusinessRuleError(errorCode, message);
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Shared entity parsing logic for domains that use `{ type, code }` entities.
|
|
412
|
+
* Handles common validation: isRecord check, type enum validation, and code non-empty check.
|
|
413
|
+
* Use `allowEmptyCode` to permit empty/missing code for specific entity types (e.g., CREATOR).
|
|
414
|
+
*/
|
|
415
|
+
function parseEntityBase(raw, index, validTypes, errorCodes, options) {
|
|
416
|
+
if (!isRecord(raw)) throw new BusinessRuleError(errorCodes.invalidStructure, `Entity at index ${index} must be an object`);
|
|
417
|
+
const type = parseEnum(raw.type, validTypes, errorCodes.invalidType, `Entity at index ${index} has invalid type: ${String(raw.type)}. Must be ${[...validTypes].join(", ")}`);
|
|
418
|
+
if (options?.allowEmptyCode?.(type)) return {
|
|
419
|
+
type,
|
|
420
|
+
code: typeof raw.code === "string" ? raw.code : ""
|
|
421
|
+
};
|
|
422
|
+
if (typeof raw.code !== "string" || raw.code.length === 0) throw new BusinessRuleError(errorCodes.emptyCode, `Entity at index ${index} must have a non-empty "code" property`);
|
|
423
|
+
return {
|
|
424
|
+
type,
|
|
425
|
+
code: raw.code
|
|
426
|
+
};
|
|
427
|
+
}
|
|
372
428
|
|
|
373
429
|
//#endregion
|
|
374
430
|
//#region src/core/domain/services/yamlConfigParser.ts
|
|
@@ -479,13 +535,17 @@ function parseActionConfigText(rawText) {
|
|
|
479
535
|
//#endregion
|
|
480
536
|
//#region src/core/application/action/applyAction.ts
|
|
481
537
|
async function applyAction({ container }) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
538
|
+
await applyFromConfig({
|
|
539
|
+
getStorage: () => container.actionStorage.get(),
|
|
540
|
+
parseConfig: parseActionConfigText,
|
|
541
|
+
fetchRemote: () => container.actionConfigurator.getActions(),
|
|
542
|
+
update: async (config, current) => {
|
|
543
|
+
await container.actionConfigurator.updateActions({
|
|
544
|
+
actions: config.actions,
|
|
545
|
+
revision: current.revision
|
|
546
|
+
});
|
|
547
|
+
},
|
|
548
|
+
notFoundMessage: "Action config file not found"
|
|
489
549
|
});
|
|
490
550
|
}
|
|
491
551
|
|
|
@@ -1516,11 +1576,7 @@ function buildKintoneAuth(auth) {
|
|
|
1516
1576
|
};
|
|
1517
1577
|
}
|
|
1518
1578
|
function createCliContainer(config) {
|
|
1519
|
-
const client =
|
|
1520
|
-
baseUrl: config.baseUrl,
|
|
1521
|
-
auth: buildKintoneAuth(config.auth),
|
|
1522
|
-
guestSpaceId: config.guestSpaceId
|
|
1523
|
-
});
|
|
1579
|
+
const client = config.client ?? createKintoneClient(config);
|
|
1524
1580
|
return {
|
|
1525
1581
|
formConfigurator: new KintoneFormConfigurator(client, config.appId),
|
|
1526
1582
|
schemaStorage: createLocalFileSchemaStorage(config.schemaFilePath),
|
|
@@ -1529,20 +1585,12 @@ function createCliContainer(config) {
|
|
|
1529
1585
|
}
|
|
1530
1586
|
function createSeedCliContainer(config) {
|
|
1531
1587
|
return {
|
|
1532
|
-
recordManager: new KintoneRecordManager(
|
|
1533
|
-
baseUrl: config.baseUrl,
|
|
1534
|
-
auth: buildKintoneAuth(config.auth),
|
|
1535
|
-
guestSpaceId: config.guestSpaceId
|
|
1536
|
-
}), config.appId),
|
|
1588
|
+
recordManager: new KintoneRecordManager(config.client ?? createKintoneClient(config), config.appId),
|
|
1537
1589
|
seedStorage: createLocalFileSeedStorage(config.seedFilePath)
|
|
1538
1590
|
};
|
|
1539
1591
|
}
|
|
1540
1592
|
function createCustomizationCliContainer(config) {
|
|
1541
|
-
const client =
|
|
1542
|
-
baseUrl: config.baseUrl,
|
|
1543
|
-
auth: buildKintoneAuth(config.auth),
|
|
1544
|
-
guestSpaceId: config.guestSpaceId
|
|
1545
|
-
});
|
|
1593
|
+
const client = config.client ?? createKintoneClient(config);
|
|
1546
1594
|
return {
|
|
1547
1595
|
customizationConfigurator: new KintoneCustomizationConfigurator(client, config.appId),
|
|
1548
1596
|
customizationStorage: createLocalFileCustomizationStorage(config.customizeFilePath),
|
|
@@ -1554,13 +1602,19 @@ function createCustomizationCliContainer(config) {
|
|
|
1554
1602
|
}
|
|
1555
1603
|
|
|
1556
1604
|
//#endregion
|
|
1557
|
-
//#region src/core/application/container/
|
|
1558
|
-
function
|
|
1559
|
-
|
|
1605
|
+
//#region src/core/application/container/kintoneClient.ts
|
|
1606
|
+
function createKintoneClient(config) {
|
|
1607
|
+
return new KintoneRestAPIClient({
|
|
1560
1608
|
baseUrl: config.baseUrl,
|
|
1561
1609
|
auth: buildKintoneAuth(config.auth),
|
|
1562
1610
|
guestSpaceId: config.guestSpaceId
|
|
1563
1611
|
});
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
//#endregion
|
|
1615
|
+
//#region src/core/application/container/actionCli.ts
|
|
1616
|
+
function createActionCliContainer(config) {
|
|
1617
|
+
const client = config.client ?? createKintoneClient(config);
|
|
1564
1618
|
return {
|
|
1565
1619
|
actionConfigurator: new KintoneActionConfigurator(client, config.appId),
|
|
1566
1620
|
actionStorage: createLocalFileActionStorage(config.actionFilePath),
|
|
@@ -2453,7 +2507,7 @@ function serializeToYaml(data) {
|
|
|
2453
2507
|
defaultStringType: "PLAIN"
|
|
2454
2508
|
});
|
|
2455
2509
|
} catch (error) {
|
|
2456
|
-
throw new BusinessRuleError(
|
|
2510
|
+
throw new BusinessRuleError(DomainServiceErrorCode.YamlSerializationFailed, `Failed to serialize config to YAML: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
2457
2511
|
}
|
|
2458
2512
|
}
|
|
2459
2513
|
|
|
@@ -2497,15 +2551,25 @@ const ActionConfigSerializer = { serialize: (config) => {
|
|
|
2497
2551
|
} };
|
|
2498
2552
|
|
|
2499
2553
|
//#endregion
|
|
2500
|
-
//#region src/core/application/
|
|
2501
|
-
async function
|
|
2502
|
-
const
|
|
2554
|
+
//#region src/core/application/captureFromConfigBase.ts
|
|
2555
|
+
async function captureFromConfig(config) {
|
|
2556
|
+
const remote = await config.fetchRemote();
|
|
2503
2557
|
return {
|
|
2504
|
-
configText:
|
|
2505
|
-
hasExistingConfig: (await
|
|
2558
|
+
configText: config.serialize(remote),
|
|
2559
|
+
hasExistingConfig: (await config.getStorage()).exists
|
|
2506
2560
|
};
|
|
2507
2561
|
}
|
|
2508
2562
|
|
|
2563
|
+
//#endregion
|
|
2564
|
+
//#region src/core/application/action/captureAction.ts
|
|
2565
|
+
async function captureAction({ container }) {
|
|
2566
|
+
return captureFromConfig({
|
|
2567
|
+
fetchRemote: () => container.actionConfigurator.getActions(),
|
|
2568
|
+
serialize: ({ actions }) => ActionConfigSerializer.serialize({ actions }),
|
|
2569
|
+
getStorage: () => container.actionStorage.get()
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2509
2573
|
//#endregion
|
|
2510
2574
|
//#region src/core/application/action/saveAction.ts
|
|
2511
2575
|
async function saveAction({ container, input }) {
|
|
@@ -2815,20 +2879,16 @@ var action_default = define({
|
|
|
2815
2879
|
//#endregion
|
|
2816
2880
|
//#region src/core/domain/adminNotes/services/configParser.ts
|
|
2817
2881
|
const AdminNotesConfigParser = { parse: (rawText) => {
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
}
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
if (!isRecord(parsed)) throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must be a YAML object");
|
|
2826
|
-
const obj = parsed;
|
|
2827
|
-
if (typeof obj.content !== "string") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have a \"content\" string property");
|
|
2828
|
-
if (typeof obj.includeInTemplateAndDuplicates !== "boolean") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have an \"includeInTemplateAndDuplicates\" boolean property");
|
|
2882
|
+
const parsed = parseYamlConfig(rawText, {
|
|
2883
|
+
emptyConfigText: AdminNotesErrorCode.AnEmptyConfigText,
|
|
2884
|
+
invalidConfigYaml: AdminNotesErrorCode.AnInvalidConfigYaml,
|
|
2885
|
+
invalidConfigStructure: AdminNotesErrorCode.AnInvalidConfigStructure
|
|
2886
|
+
}, "Admin notes");
|
|
2887
|
+
if (typeof parsed.content !== "string") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have a \"content\" string property");
|
|
2888
|
+
if (typeof parsed.includeInTemplateAndDuplicates !== "boolean") throw new BusinessRuleError(AdminNotesErrorCode.AnInvalidConfigStructure, "Config must have an \"includeInTemplateAndDuplicates\" boolean property");
|
|
2829
2889
|
return {
|
|
2830
|
-
content:
|
|
2831
|
-
includeInTemplateAndDuplicates:
|
|
2890
|
+
content: parsed.content,
|
|
2891
|
+
includeInTemplateAndDuplicates: parsed.includeInTemplateAndDuplicates
|
|
2832
2892
|
};
|
|
2833
2893
|
} };
|
|
2834
2894
|
|
|
@@ -2841,13 +2901,17 @@ function parseAdminNotesConfigText(rawText) {
|
|
|
2841
2901
|
//#endregion
|
|
2842
2902
|
//#region src/core/application/adminNotes/applyAdminNotes.ts
|
|
2843
2903
|
async function applyAdminNotes({ container }) {
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2904
|
+
await applyFromConfig({
|
|
2905
|
+
getStorage: () => container.adminNotesStorage.get(),
|
|
2906
|
+
parseConfig: parseAdminNotesConfigText,
|
|
2907
|
+
fetchRemote: () => container.adminNotesConfigurator.getAdminNotes(),
|
|
2908
|
+
update: async (config, current) => {
|
|
2909
|
+
await container.adminNotesConfigurator.updateAdminNotes({
|
|
2910
|
+
config,
|
|
2911
|
+
revision: current.revision
|
|
2912
|
+
});
|
|
2913
|
+
},
|
|
2914
|
+
notFoundMessage: "Admin notes config file not found"
|
|
2851
2915
|
});
|
|
2852
2916
|
}
|
|
2853
2917
|
|
|
@@ -2903,11 +2967,7 @@ function createLocalFileAdminNotesStorage(filePath) {
|
|
|
2903
2967
|
//#endregion
|
|
2904
2968
|
//#region src/core/application/container/adminNotesCli.ts
|
|
2905
2969
|
function createAdminNotesCliContainer(config) {
|
|
2906
|
-
const client =
|
|
2907
|
-
baseUrl: config.baseUrl,
|
|
2908
|
-
auth: buildKintoneAuth(config.auth),
|
|
2909
|
-
guestSpaceId: config.guestSpaceId
|
|
2910
|
-
});
|
|
2970
|
+
const client = config.client ?? createKintoneClient(config);
|
|
2911
2971
|
return {
|
|
2912
2972
|
adminNotesConfigurator: new KintoneAdminNotesConfigurator(client, config.appId),
|
|
2913
2973
|
adminNotesStorage: createLocalFileAdminNotesStorage(config.adminNotesFilePath),
|
|
@@ -2986,24 +3046,20 @@ var apply_default$11 = define({
|
|
|
2986
3046
|
//#endregion
|
|
2987
3047
|
//#region src/core/domain/adminNotes/services/configSerializer.ts
|
|
2988
3048
|
const AdminNotesConfigSerializer = { serialize: (config) => {
|
|
2989
|
-
return
|
|
3049
|
+
return serializeToYaml({
|
|
2990
3050
|
content: config.content,
|
|
2991
3051
|
includeInTemplateAndDuplicates: config.includeInTemplateAndDuplicates
|
|
2992
|
-
}, {
|
|
2993
|
-
lineWidth: 0,
|
|
2994
|
-
defaultKeyType: "PLAIN",
|
|
2995
|
-
defaultStringType: "PLAIN"
|
|
2996
3052
|
});
|
|
2997
3053
|
} };
|
|
2998
3054
|
|
|
2999
3055
|
//#endregion
|
|
3000
3056
|
//#region src/core/application/adminNotes/captureAdminNotes.ts
|
|
3001
3057
|
async function captureAdminNotes({ container }) {
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
};
|
|
3058
|
+
return captureFromConfig({
|
|
3059
|
+
fetchRemote: () => container.adminNotesConfigurator.getAdminNotes(),
|
|
3060
|
+
serialize: ({ config }) => AdminNotesConfigSerializer.serialize(config),
|
|
3061
|
+
getStorage: () => container.adminNotesStorage.get()
|
|
3062
|
+
});
|
|
3007
3063
|
}
|
|
3008
3064
|
|
|
3009
3065
|
//#endregion
|
|
@@ -3123,52 +3179,34 @@ const VALID_ENTITY_TYPES$8 = new Set([
|
|
|
3123
3179
|
"CREATOR"
|
|
3124
3180
|
]);
|
|
3125
3181
|
function parseEntity$3(raw, index) {
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
type,
|
|
3132
|
-
code: typeof obj.code === "string" ? obj.code : ""
|
|
3133
|
-
};
|
|
3134
|
-
if (typeof obj.code !== "string" || obj.code.length === 0) throw new BusinessRuleError(AppPermissionErrorCode.ApEmptyEntityCode, `Entity at index ${index} must have a non-empty "code" property`);
|
|
3135
|
-
return {
|
|
3136
|
-
type,
|
|
3137
|
-
code: obj.code
|
|
3138
|
-
};
|
|
3139
|
-
}
|
|
3140
|
-
function parseBooleanField$1(obj, field, index) {
|
|
3141
|
-
const value = obj[field];
|
|
3142
|
-
if (typeof value !== "boolean") throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidBooleanField, `App right at index ${index} must have a boolean "${field}" property`);
|
|
3143
|
-
return value;
|
|
3182
|
+
return parseEntityBase(raw, index, VALID_ENTITY_TYPES$8, {
|
|
3183
|
+
invalidStructure: AppPermissionErrorCode.ApInvalidConfigStructure,
|
|
3184
|
+
invalidType: AppPermissionErrorCode.ApInvalidEntityType,
|
|
3185
|
+
emptyCode: AppPermissionErrorCode.ApEmptyEntityCode
|
|
3186
|
+
}, { allowEmptyCode: (type) => type === "CREATOR" });
|
|
3144
3187
|
}
|
|
3145
3188
|
function parseAppRight(raw, index) {
|
|
3146
3189
|
if (!isRecord(raw)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, `App right at index ${index} must be an object`);
|
|
3147
|
-
const obj = raw;
|
|
3148
3190
|
return {
|
|
3149
|
-
entity: parseEntity$3(
|
|
3150
|
-
includeSubs:
|
|
3151
|
-
appEditable:
|
|
3152
|
-
recordViewable:
|
|
3153
|
-
recordAddable:
|
|
3154
|
-
recordEditable:
|
|
3155
|
-
recordDeletable:
|
|
3156
|
-
recordImportable:
|
|
3157
|
-
recordExportable:
|
|
3191
|
+
entity: parseEntity$3(raw.entity, index),
|
|
3192
|
+
includeSubs: parseStrictBoolean(raw.includeSubs, "includeSubs", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField),
|
|
3193
|
+
appEditable: parseStrictBoolean(raw.appEditable, "appEditable", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField),
|
|
3194
|
+
recordViewable: parseStrictBoolean(raw.recordViewable, "recordViewable", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField),
|
|
3195
|
+
recordAddable: parseStrictBoolean(raw.recordAddable, "recordAddable", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField),
|
|
3196
|
+
recordEditable: parseStrictBoolean(raw.recordEditable, "recordEditable", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField),
|
|
3197
|
+
recordDeletable: parseStrictBoolean(raw.recordDeletable, "recordDeletable", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField),
|
|
3198
|
+
recordImportable: parseStrictBoolean(raw.recordImportable, "recordImportable", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField),
|
|
3199
|
+
recordExportable: parseStrictBoolean(raw.recordExportable, "recordExportable", `App right at index ${index}`, AppPermissionErrorCode.ApInvalidBooleanField)
|
|
3158
3200
|
};
|
|
3159
3201
|
}
|
|
3160
3202
|
const AppPermissionConfigParser = { parse: (rawText) => {
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
}
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
if (!isRecord(parsed)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must be a YAML object");
|
|
3169
|
-
const obj = parsed;
|
|
3170
|
-
if (!Array.isArray(obj.rights)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
3171
|
-
const rights = obj.rights.map((item, i) => parseAppRight(item, i));
|
|
3203
|
+
const parsed = parseYamlConfig(rawText, {
|
|
3204
|
+
emptyConfigText: AppPermissionErrorCode.ApEmptyConfigText,
|
|
3205
|
+
invalidConfigYaml: AppPermissionErrorCode.ApInvalidConfigYaml,
|
|
3206
|
+
invalidConfigStructure: AppPermissionErrorCode.ApInvalidConfigStructure
|
|
3207
|
+
}, "App permission");
|
|
3208
|
+
if (!Array.isArray(parsed.rights)) throw new BusinessRuleError(AppPermissionErrorCode.ApInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
3209
|
+
const rights = parsed.rights.map((item, i) => parseAppRight(item, i));
|
|
3172
3210
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
3173
3211
|
for (const right of rights) {
|
|
3174
3212
|
const key = `${right.entity.type}:${right.entity.code}`;
|
|
@@ -3187,13 +3225,17 @@ function parseAppPermissionConfigText(rawText) {
|
|
|
3187
3225
|
//#endregion
|
|
3188
3226
|
//#region src/core/application/appPermission/applyAppPermission.ts
|
|
3189
3227
|
async function applyAppPermission({ container }) {
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3228
|
+
await applyFromConfig({
|
|
3229
|
+
getStorage: () => container.appPermissionStorage.get(),
|
|
3230
|
+
parseConfig: parseAppPermissionConfigText,
|
|
3231
|
+
fetchRemote: () => container.appPermissionConfigurator.getAppPermissions(),
|
|
3232
|
+
update: async (config, current) => {
|
|
3233
|
+
await container.appPermissionConfigurator.updateAppPermissions({
|
|
3234
|
+
rights: config.rights,
|
|
3235
|
+
revision: current.revision
|
|
3236
|
+
});
|
|
3237
|
+
},
|
|
3238
|
+
notFoundMessage: "App permission config file not found"
|
|
3197
3239
|
});
|
|
3198
3240
|
}
|
|
3199
3241
|
|
|
@@ -3291,11 +3333,7 @@ function createLocalFileAppPermissionStorage(filePath) {
|
|
|
3291
3333
|
//#endregion
|
|
3292
3334
|
//#region src/core/application/container/appPermissionCli.ts
|
|
3293
3335
|
function createAppPermissionCliContainer(config) {
|
|
3294
|
-
const client =
|
|
3295
|
-
baseUrl: config.baseUrl,
|
|
3296
|
-
auth: buildKintoneAuth(config.auth),
|
|
3297
|
-
guestSpaceId: config.guestSpaceId
|
|
3298
|
-
});
|
|
3336
|
+
const client = config.client ?? createKintoneClient(config);
|
|
3299
3337
|
return {
|
|
3300
3338
|
appPermissionConfigurator: new KintoneAppPermissionConfigurator(client, config.appId),
|
|
3301
3339
|
appPermissionStorage: createLocalFileAppPermissionStorage(config.appAclFilePath),
|
|
@@ -3390,21 +3428,17 @@ function serializeAppRight(right) {
|
|
|
3390
3428
|
};
|
|
3391
3429
|
}
|
|
3392
3430
|
const AppPermissionConfigSerializer = { serialize: (config) => {
|
|
3393
|
-
return
|
|
3394
|
-
lineWidth: 0,
|
|
3395
|
-
defaultKeyType: "PLAIN",
|
|
3396
|
-
defaultStringType: "PLAIN"
|
|
3397
|
-
});
|
|
3431
|
+
return serializeToYaml({ rights: config.rights.map(serializeAppRight) });
|
|
3398
3432
|
} };
|
|
3399
3433
|
|
|
3400
3434
|
//#endregion
|
|
3401
3435
|
//#region src/core/application/appPermission/captureAppPermission.ts
|
|
3402
3436
|
async function captureAppPermission({ container }) {
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
};
|
|
3437
|
+
return captureFromConfig({
|
|
3438
|
+
fetchRemote: () => container.appPermissionConfigurator.getAppPermissions(),
|
|
3439
|
+
serialize: ({ rights }) => AppPermissionConfigSerializer.serialize({ rights }),
|
|
3440
|
+
getStorage: () => container.appPermissionStorage.get()
|
|
3441
|
+
});
|
|
3408
3442
|
}
|
|
3409
3443
|
|
|
3410
3444
|
//#endregion
|
|
@@ -3840,8 +3874,8 @@ function planResources(resources, platformDir, resourceType, relativeBaseDir) {
|
|
|
3840
3874
|
filesToDownload
|
|
3841
3875
|
};
|
|
3842
3876
|
}
|
|
3843
|
-
function planPlatform(remotePlatform, platformName,
|
|
3844
|
-
const platformDir = join(
|
|
3877
|
+
function planPlatform(remotePlatform, platformName, basePath, filePrefix) {
|
|
3878
|
+
const platformDir = join(basePath, filePrefix, platformName);
|
|
3845
3879
|
const platformPrefix = platformName;
|
|
3846
3880
|
const jsPlan = planResources(remotePlatform.js, platformDir, "js", platformPrefix);
|
|
3847
3881
|
const cssPlan = planResources(remotePlatform.css, platformDir, "css", platformPrefix);
|
|
@@ -3869,18 +3903,18 @@ async function downloadFiles(files, container) {
|
|
|
3869
3903
|
await container.fileWriter.write(file.absolutePath, data);
|
|
3870
3904
|
}));
|
|
3871
3905
|
}
|
|
3872
|
-
async function captureCustomization(
|
|
3873
|
-
const existing = await
|
|
3874
|
-
const { scope, desktop, mobile } = await
|
|
3875
|
-
const desktopPlan = planPlatform(desktop, "desktop",
|
|
3876
|
-
const mobilePlan = planPlatform(mobile, "mobile",
|
|
3906
|
+
async function captureCustomization({ container, input }) {
|
|
3907
|
+
const existing = await container.customizationStorage.get();
|
|
3908
|
+
const { scope, desktop, mobile } = await container.customizationConfigurator.getCustomization();
|
|
3909
|
+
const desktopPlan = planPlatform(desktop, "desktop", input.basePath, input.filePrefix);
|
|
3910
|
+
const mobilePlan = planPlatform(mobile, "mobile", input.basePath, input.filePrefix);
|
|
3877
3911
|
const config = {
|
|
3878
3912
|
scope,
|
|
3879
3913
|
desktop: desktopPlan.platform,
|
|
3880
3914
|
mobile: mobilePlan.platform
|
|
3881
3915
|
};
|
|
3882
3916
|
const configText = CustomizationConfigSerializer.serialize(config);
|
|
3883
|
-
await downloadFiles([...desktopPlan.filesToDownload, ...mobilePlan.filesToDownload],
|
|
3917
|
+
await downloadFiles([...desktopPlan.filesToDownload, ...mobilePlan.filesToDownload], container);
|
|
3884
3918
|
return {
|
|
3885
3919
|
configText,
|
|
3886
3920
|
hasExistingConfig: existing.exists,
|
|
@@ -4208,11 +4242,7 @@ function createLocalFileFieldPermissionStorage(filePath) {
|
|
|
4208
4242
|
//#endregion
|
|
4209
4243
|
//#region src/core/application/container/fieldPermissionCli.ts
|
|
4210
4244
|
function createFieldPermissionCliContainer(config) {
|
|
4211
|
-
const client =
|
|
4212
|
-
baseUrl: config.baseUrl,
|
|
4213
|
-
auth: buildKintoneAuth(config.auth),
|
|
4214
|
-
guestSpaceId: config.guestSpaceId
|
|
4215
|
-
});
|
|
4245
|
+
const client = config.client ?? createKintoneClient(config);
|
|
4216
4246
|
return {
|
|
4217
4247
|
fieldPermissionConfigurator: new KintoneFieldPermissionConfigurator(client, config.appId),
|
|
4218
4248
|
fieldPermissionStorage: createLocalFileFieldPermissionStorage(config.fieldAclFilePath),
|
|
@@ -4234,53 +4264,42 @@ const VALID_ENTITY_TYPES$5 = new Set([
|
|
|
4234
4264
|
"FIELD_ENTITY"
|
|
4235
4265
|
]);
|
|
4236
4266
|
function parseEntity$2(raw, index) {
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
type: obj.type,
|
|
4243
|
-
code: obj.code
|
|
4244
|
-
};
|
|
4267
|
+
return parseEntityBase(raw, index, VALID_ENTITY_TYPES$5, {
|
|
4268
|
+
invalidStructure: FieldPermissionErrorCode.FpInvalidConfigStructure,
|
|
4269
|
+
invalidType: FieldPermissionErrorCode.FpInvalidEntityType,
|
|
4270
|
+
emptyCode: FieldPermissionErrorCode.FpEmptyEntityCode
|
|
4271
|
+
});
|
|
4245
4272
|
}
|
|
4246
4273
|
function parseFieldRightEntity(raw, index) {
|
|
4247
4274
|
if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right entity at index ${index} must be an object`);
|
|
4248
|
-
const obj = raw;
|
|
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`);
|
|
4250
|
-
const entity = parseEntity$2(obj.entity, index);
|
|
4251
4275
|
const result = {
|
|
4252
|
-
accessibility:
|
|
4253
|
-
entity
|
|
4276
|
+
accessibility: parseEnum(raw.accessibility, VALID_ACCESSIBILITIES, FieldPermissionErrorCode.FpInvalidAccessibility, `Field right entity at index ${index} has invalid accessibility: ${String(raw.accessibility)}. Must be READ, WRITE, or NONE`),
|
|
4277
|
+
entity: parseEntity$2(raw.entity, index)
|
|
4254
4278
|
};
|
|
4255
|
-
if (
|
|
4279
|
+
if (raw.includeSubs !== void 0 && raw.includeSubs !== null) return {
|
|
4256
4280
|
...result,
|
|
4257
|
-
includeSubs:
|
|
4281
|
+
includeSubs: parseStrictBoolean(raw.includeSubs, "includeSubs", `Field right entity at index ${index}`, FieldPermissionErrorCode.FpInvalidBooleanField)
|
|
4258
4282
|
};
|
|
4259
4283
|
return result;
|
|
4260
4284
|
}
|
|
4261
4285
|
function parseFieldRight(raw, index) {
|
|
4262
4286
|
if (!isRecord(raw)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right at index ${index} must be an object`);
|
|
4263
|
-
|
|
4264
|
-
if (
|
|
4265
|
-
|
|
4266
|
-
const entities = obj.entities.map((item, i) => parseFieldRightEntity(item, i));
|
|
4287
|
+
if (typeof raw.code !== "string" || raw.code.length === 0) throw new BusinessRuleError(FieldPermissionErrorCode.FpEmptyFieldCode, `Field right at index ${index} must have a non-empty "code" property`);
|
|
4288
|
+
if (!Array.isArray(raw.entities)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, `Field right at index ${index} must have an "entities" array`);
|
|
4289
|
+
const entities = raw.entities.map((item, i) => parseFieldRightEntity(item, i));
|
|
4267
4290
|
return {
|
|
4268
|
-
code:
|
|
4291
|
+
code: raw.code,
|
|
4269
4292
|
entities
|
|
4270
4293
|
};
|
|
4271
4294
|
}
|
|
4272
4295
|
const FieldPermissionConfigParser = { parse: (rawText) => {
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
}
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
if (!isRecord(parsed)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must be a YAML object");
|
|
4281
|
-
const obj = parsed;
|
|
4282
|
-
if (!Array.isArray(obj.rights)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
4283
|
-
const rights = obj.rights.map((item, i) => parseFieldRight(item, i));
|
|
4296
|
+
const parsed = parseYamlConfig(rawText, {
|
|
4297
|
+
emptyConfigText: FieldPermissionErrorCode.FpEmptyConfigText,
|
|
4298
|
+
invalidConfigYaml: FieldPermissionErrorCode.FpInvalidConfigYaml,
|
|
4299
|
+
invalidConfigStructure: FieldPermissionErrorCode.FpInvalidConfigStructure
|
|
4300
|
+
}, "Field permission");
|
|
4301
|
+
if (!Array.isArray(parsed.rights)) throw new BusinessRuleError(FieldPermissionErrorCode.FpInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
4302
|
+
const rights = parsed.rights.map((item, i) => parseFieldRight(item, i));
|
|
4284
4303
|
const seenCodes = /* @__PURE__ */ new Set();
|
|
4285
4304
|
for (const right of rights) {
|
|
4286
4305
|
if (seenCodes.has(right.code)) throw new BusinessRuleError(FieldPermissionErrorCode.FpDuplicateFieldCode, `Duplicate field code: ${right.code}`);
|
|
@@ -4298,13 +4317,17 @@ function parseFieldPermissionConfigText(rawText) {
|
|
|
4298
4317
|
//#endregion
|
|
4299
4318
|
//#region src/core/application/fieldPermission/applyFieldPermission.ts
|
|
4300
4319
|
async function applyFieldPermission({ container }) {
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4320
|
+
await applyFromConfig({
|
|
4321
|
+
getStorage: () => container.fieldPermissionStorage.get(),
|
|
4322
|
+
parseConfig: parseFieldPermissionConfigText,
|
|
4323
|
+
fetchRemote: () => container.fieldPermissionConfigurator.getFieldPermissions(),
|
|
4324
|
+
update: async (config, current) => {
|
|
4325
|
+
await container.fieldPermissionConfigurator.updateFieldPermissions({
|
|
4326
|
+
rights: config.rights,
|
|
4327
|
+
revision: current.revision
|
|
4328
|
+
});
|
|
4329
|
+
},
|
|
4330
|
+
notFoundMessage: "Field permission config file not found"
|
|
4308
4331
|
});
|
|
4309
4332
|
}
|
|
4310
4333
|
|
|
@@ -4390,24 +4413,20 @@ function serializeFieldRightEntity(entity) {
|
|
|
4390
4413
|
return result;
|
|
4391
4414
|
}
|
|
4392
4415
|
const FieldPermissionConfigSerializer = { serialize: (config) => {
|
|
4393
|
-
return
|
|
4416
|
+
return serializeToYaml({ rights: config.rights.map((right) => ({
|
|
4394
4417
|
code: right.code,
|
|
4395
4418
|
entities: right.entities.map(serializeFieldRightEntity)
|
|
4396
|
-
})) }
|
|
4397
|
-
lineWidth: 0,
|
|
4398
|
-
defaultKeyType: "PLAIN",
|
|
4399
|
-
defaultStringType: "PLAIN"
|
|
4400
|
-
});
|
|
4419
|
+
})) });
|
|
4401
4420
|
} };
|
|
4402
4421
|
|
|
4403
4422
|
//#endregion
|
|
4404
4423
|
//#region src/core/application/fieldPermission/captureFieldPermission.ts
|
|
4405
4424
|
async function captureFieldPermission({ container }) {
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
};
|
|
4425
|
+
return captureFromConfig({
|
|
4426
|
+
fetchRemote: () => container.fieldPermissionConfigurator.getFieldPermissions(),
|
|
4427
|
+
serialize: ({ rights }) => FieldPermissionConfigSerializer.serialize({ rights }),
|
|
4428
|
+
getStorage: () => container.fieldPermissionStorage.get()
|
|
4429
|
+
});
|
|
4411
4430
|
}
|
|
4412
4431
|
|
|
4413
4432
|
//#endregion
|
|
@@ -4461,7 +4480,7 @@ var capture_default$9 = define({
|
|
|
4461
4480
|
|
|
4462
4481
|
//#endregion
|
|
4463
4482
|
//#region src/core/domain/fieldPermission/services/diffDetector.ts
|
|
4464
|
-
function
|
|
4483
|
+
function isEntitiesEqual$1(a, b) {
|
|
4465
4484
|
return deepEqual(a.entities.map((e) => ({
|
|
4466
4485
|
accessibility: e.accessibility,
|
|
4467
4486
|
type: e.entity.type,
|
|
@@ -4485,7 +4504,7 @@ const FieldPermissionDiffDetector = { detect: (local, remote) => {
|
|
|
4485
4504
|
fieldCode: code,
|
|
4486
4505
|
details: `${localRight.entities.length} entities`
|
|
4487
4506
|
});
|
|
4488
|
-
else if (!
|
|
4507
|
+
else if (!isEntitiesEqual$1(localRight, remoteRight)) entries.push({
|
|
4489
4508
|
type: "modified",
|
|
4490
4509
|
fieldCode: code,
|
|
4491
4510
|
details: "entities changed"
|
|
@@ -4684,11 +4703,7 @@ function createLocalFileGeneralSettingsStorage(filePath) {
|
|
|
4684
4703
|
//#endregion
|
|
4685
4704
|
//#region src/core/application/container/generalSettingsCli.ts
|
|
4686
4705
|
function createGeneralSettingsCliContainer(config) {
|
|
4687
|
-
const client =
|
|
4688
|
-
baseUrl: config.baseUrl,
|
|
4689
|
-
auth: buildKintoneAuth(config.auth),
|
|
4690
|
-
guestSpaceId: config.guestSpaceId
|
|
4691
|
-
});
|
|
4706
|
+
const client = config.client ?? createKintoneClient(config);
|
|
4692
4707
|
return {
|
|
4693
4708
|
generalSettingsConfigurator: new KintoneGeneralSettingsConfigurator(client, config.appId),
|
|
4694
4709
|
generalSettingsStorage: createLocalFileGeneralSettingsStorage(config.settingsFilePath),
|
|
@@ -4929,11 +4944,7 @@ function createLocalFileNotificationStorage(filePath) {
|
|
|
4929
4944
|
//#endregion
|
|
4930
4945
|
//#region src/core/application/container/notificationCli.ts
|
|
4931
4946
|
function createNotificationCliContainer(config) {
|
|
4932
|
-
const client =
|
|
4933
|
-
baseUrl: config.baseUrl,
|
|
4934
|
-
auth: buildKintoneAuth(config.auth),
|
|
4935
|
-
guestSpaceId: config.guestSpaceId
|
|
4936
|
-
});
|
|
4947
|
+
const client = config.client ?? createKintoneClient(config);
|
|
4937
4948
|
return {
|
|
4938
4949
|
notificationConfigurator: new KintoneNotificationConfigurator(client, config.appId),
|
|
4939
4950
|
notificationStorage: createLocalFileNotificationStorage(config.notificationFilePath),
|
|
@@ -4992,11 +5003,7 @@ function createLocalFilePluginStorage(filePath) {
|
|
|
4992
5003
|
//#endregion
|
|
4993
5004
|
//#region src/core/application/container/pluginCli.ts
|
|
4994
5005
|
function createPluginCliContainer(config) {
|
|
4995
|
-
const client =
|
|
4996
|
-
baseUrl: config.baseUrl,
|
|
4997
|
-
auth: buildKintoneAuth(config.auth),
|
|
4998
|
-
guestSpaceId: config.guestSpaceId
|
|
4999
|
-
});
|
|
5006
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5000
5007
|
return {
|
|
5001
5008
|
pluginConfigurator: new KintonePluginConfigurator(client, config.appId),
|
|
5002
5009
|
pluginStorage: createLocalFilePluginStorage(config.pluginFilePath),
|
|
@@ -5149,11 +5156,7 @@ function createLocalFileProcessManagementStorage(filePath) {
|
|
|
5149
5156
|
//#endregion
|
|
5150
5157
|
//#region src/core/application/container/processManagementCli.ts
|
|
5151
5158
|
function createProcessManagementCliContainer(config) {
|
|
5152
|
-
const client =
|
|
5153
|
-
baseUrl: config.baseUrl,
|
|
5154
|
-
auth: buildKintoneAuth(config.auth),
|
|
5155
|
-
guestSpaceId: config.guestSpaceId
|
|
5156
|
-
});
|
|
5159
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5157
5160
|
return {
|
|
5158
5161
|
processManagementConfigurator: new KintoneProcessManagementConfigurator(client, config.appId),
|
|
5159
5162
|
processManagementStorage: createLocalFileProcessManagementStorage(config.processFilePath),
|
|
@@ -5252,11 +5255,7 @@ function createLocalFileRecordPermissionStorage(filePath) {
|
|
|
5252
5255
|
//#endregion
|
|
5253
5256
|
//#region src/core/application/container/recordPermissionCli.ts
|
|
5254
5257
|
function createRecordPermissionCliContainer(config) {
|
|
5255
|
-
const client =
|
|
5256
|
-
baseUrl: config.baseUrl,
|
|
5257
|
-
auth: buildKintoneAuth(config.auth),
|
|
5258
|
-
guestSpaceId: config.guestSpaceId
|
|
5259
|
-
});
|
|
5258
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5260
5259
|
return {
|
|
5261
5260
|
recordPermissionConfigurator: new KintoneRecordPermissionConfigurator(client, config.appId),
|
|
5262
5261
|
recordPermissionStorage: createLocalFileRecordPermissionStorage(config.recordAclFilePath),
|
|
@@ -5547,11 +5546,7 @@ function createLocalFileReportStorage(filePath) {
|
|
|
5547
5546
|
//#endregion
|
|
5548
5547
|
//#region src/core/application/container/reportCli.ts
|
|
5549
5548
|
function createReportCliContainer(config) {
|
|
5550
|
-
const client =
|
|
5551
|
-
baseUrl: config.baseUrl,
|
|
5552
|
-
auth: buildKintoneAuth(config.auth),
|
|
5553
|
-
guestSpaceId: config.guestSpaceId
|
|
5554
|
-
});
|
|
5549
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5555
5550
|
return {
|
|
5556
5551
|
reportConfigurator: new KintoneReportConfigurator(client, config.appId),
|
|
5557
5552
|
reportStorage: createLocalFileReportStorage(config.reportFilePath),
|
|
@@ -5673,11 +5668,7 @@ function createLocalFileViewStorage(filePath) {
|
|
|
5673
5668
|
//#endregion
|
|
5674
5669
|
//#region src/core/application/container/viewCli.ts
|
|
5675
5670
|
function createViewCliContainer(config) {
|
|
5676
|
-
const client =
|
|
5677
|
-
baseUrl: config.baseUrl,
|
|
5678
|
-
auth: buildKintoneAuth(config.auth),
|
|
5679
|
-
guestSpaceId: config.guestSpaceId
|
|
5680
|
-
});
|
|
5671
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5681
5672
|
return {
|
|
5682
5673
|
viewConfigurator: new KintoneViewConfigurator(client, config.appId),
|
|
5683
5674
|
viewStorage: createLocalFileViewStorage(config.viewFilePath),
|
|
@@ -5688,11 +5679,13 @@ function createViewCliContainer(config) {
|
|
|
5688
5679
|
//#endregion
|
|
5689
5680
|
//#region src/core/application/container/captureAllCli.ts
|
|
5690
5681
|
function createCliCaptureContainers(input) {
|
|
5682
|
+
const client = createKintoneClient(input);
|
|
5691
5683
|
const base = {
|
|
5692
5684
|
baseUrl: input.baseUrl,
|
|
5693
5685
|
auth: input.auth,
|
|
5694
5686
|
appId: input.appId,
|
|
5695
|
-
guestSpaceId: input.guestSpaceId
|
|
5687
|
+
guestSpaceId: input.guestSpaceId,
|
|
5688
|
+
client
|
|
5696
5689
|
};
|
|
5697
5690
|
const paths = buildAppFilePaths(input.appName, input.baseDir);
|
|
5698
5691
|
return {
|
|
@@ -5813,11 +5806,7 @@ function createLocalFileProjectConfigStorage(filePath) {
|
|
|
5813
5806
|
//#region src/core/application/container/initCli.ts
|
|
5814
5807
|
function createInitCliContainer(config) {
|
|
5815
5808
|
return {
|
|
5816
|
-
spaceReader: new KintoneSpaceReader(
|
|
5817
|
-
baseUrl: config.baseUrl,
|
|
5818
|
-
auth: buildKintoneAuth(config.auth),
|
|
5819
|
-
guestSpaceId: config.guestSpaceId
|
|
5820
|
-
})),
|
|
5809
|
+
spaceReader: new KintoneSpaceReader(config.client ?? createKintoneClient(config)),
|
|
5821
5810
|
projectConfigStorage: createLocalFileProjectConfigStorage(config.configFilePath)
|
|
5822
5811
|
};
|
|
5823
5812
|
}
|
|
@@ -6031,21 +6020,17 @@ function serializeConfig(config) {
|
|
|
6031
6020
|
return result;
|
|
6032
6021
|
}
|
|
6033
6022
|
const GeneralSettingsConfigSerializer = { serialize: (config) => {
|
|
6034
|
-
return
|
|
6035
|
-
lineWidth: 0,
|
|
6036
|
-
defaultKeyType: "PLAIN",
|
|
6037
|
-
defaultStringType: "PLAIN"
|
|
6038
|
-
});
|
|
6023
|
+
return serializeToYaml(serializeConfig(config));
|
|
6039
6024
|
} };
|
|
6040
6025
|
|
|
6041
6026
|
//#endregion
|
|
6042
6027
|
//#region src/core/application/generalSettings/captureGeneralSettings.ts
|
|
6043
6028
|
async function captureGeneralSettings({ container }) {
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
};
|
|
6029
|
+
return captureFromConfig({
|
|
6030
|
+
fetchRemote: () => container.generalSettingsConfigurator.getGeneralSettings(),
|
|
6031
|
+
serialize: ({ config }) => GeneralSettingsConfigSerializer.serialize(config),
|
|
6032
|
+
getStorage: () => container.generalSettingsStorage.get()
|
|
6033
|
+
});
|
|
6049
6034
|
}
|
|
6050
6035
|
|
|
6051
6036
|
//#endregion
|
|
@@ -6115,9 +6100,11 @@ const NotificationConfigSerializer = { serialize: (config) => {
|
|
|
6115
6100
|
//#endregion
|
|
6116
6101
|
//#region src/core/application/notification/captureNotification.ts
|
|
6117
6102
|
async function captureNotification({ container }) {
|
|
6118
|
-
const general = await
|
|
6119
|
-
|
|
6120
|
-
|
|
6103
|
+
const [general, perRecord, reminder] = await Promise.all([
|
|
6104
|
+
container.notificationConfigurator.getGeneralNotifications(),
|
|
6105
|
+
container.notificationConfigurator.getPerRecordNotifications(),
|
|
6106
|
+
container.notificationConfigurator.getReminderNotifications()
|
|
6107
|
+
]);
|
|
6121
6108
|
const config = {
|
|
6122
6109
|
general: {
|
|
6123
6110
|
notifyToCommenter: general.notifyToCommenter,
|
|
@@ -6154,11 +6141,11 @@ const PluginConfigSerializer = { serialize: (config) => {
|
|
|
6154
6141
|
//#endregion
|
|
6155
6142
|
//#region src/core/application/plugin/capturePlugin.ts
|
|
6156
6143
|
async function capturePlugin({ container }) {
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
};
|
|
6144
|
+
return captureFromConfig({
|
|
6145
|
+
fetchRemote: () => container.pluginConfigurator.getPlugins(),
|
|
6146
|
+
serialize: ({ plugins }) => PluginConfigSerializer.serialize({ plugins }),
|
|
6147
|
+
getStorage: () => container.pluginStorage.get()
|
|
6148
|
+
});
|
|
6162
6149
|
}
|
|
6163
6150
|
|
|
6164
6151
|
//#endregion
|
|
@@ -6184,7 +6171,7 @@ const ProcessManagementConfigSerializer = { serialize: (config) => {
|
|
|
6184
6171
|
entities: state.assignee.entities.map(serializeProcessEntity)
|
|
6185
6172
|
}
|
|
6186
6173
|
};
|
|
6187
|
-
return
|
|
6174
|
+
return serializeToYaml({
|
|
6188
6175
|
enable: config.enable,
|
|
6189
6176
|
states: serializedStates,
|
|
6190
6177
|
actions: config.actions.map((action) => {
|
|
@@ -6198,21 +6185,17 @@ const ProcessManagementConfigSerializer = { serialize: (config) => {
|
|
|
6198
6185
|
if (action.executableUser !== void 0) serializedAction.executableUser = { entities: action.executableUser.entities.map(serializeProcessEntity) };
|
|
6199
6186
|
return serializedAction;
|
|
6200
6187
|
})
|
|
6201
|
-
}, {
|
|
6202
|
-
lineWidth: 0,
|
|
6203
|
-
defaultKeyType: "PLAIN",
|
|
6204
|
-
defaultStringType: "PLAIN"
|
|
6205
6188
|
});
|
|
6206
6189
|
} };
|
|
6207
6190
|
|
|
6208
6191
|
//#endregion
|
|
6209
6192
|
//#region src/core/application/processManagement/captureProcessManagement.ts
|
|
6210
6193
|
async function captureProcessManagement({ container }) {
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
};
|
|
6194
|
+
return captureFromConfig({
|
|
6195
|
+
fetchRemote: () => container.processManagementConfigurator.getProcessManagement(),
|
|
6196
|
+
serialize: ({ config }) => ProcessManagementConfigSerializer.serialize(config),
|
|
6197
|
+
getStorage: () => container.processManagementStorage.get()
|
|
6198
|
+
});
|
|
6216
6199
|
}
|
|
6217
6200
|
|
|
6218
6201
|
//#endregion
|
|
@@ -6236,24 +6219,20 @@ function serializeRecordRightEntity(entity) {
|
|
|
6236
6219
|
};
|
|
6237
6220
|
}
|
|
6238
6221
|
const RecordPermissionConfigSerializer = { serialize: (config) => {
|
|
6239
|
-
return
|
|
6222
|
+
return serializeToYaml({ rights: config.rights.map((right) => ({
|
|
6240
6223
|
filterCond: right.filterCond,
|
|
6241
6224
|
entities: right.entities.map(serializeRecordRightEntity)
|
|
6242
|
-
})) }
|
|
6243
|
-
lineWidth: 0,
|
|
6244
|
-
defaultKeyType: "PLAIN",
|
|
6245
|
-
defaultStringType: "PLAIN"
|
|
6246
|
-
});
|
|
6225
|
+
})) });
|
|
6247
6226
|
} };
|
|
6248
6227
|
|
|
6249
6228
|
//#endregion
|
|
6250
6229
|
//#region src/core/application/recordPermission/captureRecordPermission.ts
|
|
6251
6230
|
async function captureRecordPermission({ container }) {
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
};
|
|
6231
|
+
return captureFromConfig({
|
|
6232
|
+
fetchRemote: () => container.recordPermissionConfigurator.getRecordPermissions(),
|
|
6233
|
+
serialize: ({ rights }) => RecordPermissionConfigSerializer.serialize({ rights }),
|
|
6234
|
+
getStorage: () => container.recordPermissionStorage.get()
|
|
6235
|
+
});
|
|
6257
6236
|
}
|
|
6258
6237
|
|
|
6259
6238
|
//#endregion
|
|
@@ -6320,11 +6299,11 @@ const ReportConfigSerializer = { serialize: (config) => {
|
|
|
6320
6299
|
//#endregion
|
|
6321
6300
|
//#region src/core/application/report/captureReport.ts
|
|
6322
6301
|
async function captureReport({ container }) {
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
};
|
|
6302
|
+
return captureFromConfig({
|
|
6303
|
+
fetchRemote: () => container.reportConfigurator.getReports(),
|
|
6304
|
+
serialize: ({ reports }) => ReportConfigSerializer.serialize({ reports }),
|
|
6305
|
+
getStorage: () => container.reportStorage.get()
|
|
6306
|
+
});
|
|
6328
6307
|
}
|
|
6329
6308
|
|
|
6330
6309
|
//#endregion
|
|
@@ -6404,11 +6383,11 @@ const ViewConfigSerializer = { serialize: (config) => {
|
|
|
6404
6383
|
//#endregion
|
|
6405
6384
|
//#region src/core/application/view/captureView.ts
|
|
6406
6385
|
async function captureView({ container }) {
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
};
|
|
6386
|
+
return captureFromConfig({
|
|
6387
|
+
fetchRemote: () => container.viewConfigurator.getViews(),
|
|
6388
|
+
serialize: ({ views }) => ViewConfigSerializer.serialize({ views }),
|
|
6389
|
+
getStorage: () => container.viewStorage.get()
|
|
6390
|
+
});
|
|
6412
6391
|
}
|
|
6413
6392
|
|
|
6414
6393
|
//#endregion
|
|
@@ -6607,12 +6586,11 @@ function generateProjectConfig(input) {
|
|
|
6607
6586
|
files: buildAppFilePaths(name, input.baseDir)
|
|
6608
6587
|
};
|
|
6609
6588
|
}
|
|
6610
|
-
|
|
6589
|
+
return stringify({
|
|
6611
6590
|
domain: input.domain,
|
|
6591
|
+
...input.guestSpaceId !== void 0 ? { guestSpaceId: input.guestSpaceId } : {},
|
|
6612
6592
|
apps
|
|
6613
|
-
};
|
|
6614
|
-
if (input.guestSpaceId !== void 0) config.guestSpaceId = input.guestSpaceId;
|
|
6615
|
-
return stringify(config, { lineWidth: 0 });
|
|
6593
|
+
}, { lineWidth: 0 });
|
|
6616
6594
|
}
|
|
6617
6595
|
|
|
6618
6596
|
//#endregion
|
|
@@ -6872,6 +6850,15 @@ function parseNotificationConfigText(rawText) {
|
|
|
6872
6850
|
|
|
6873
6851
|
//#endregion
|
|
6874
6852
|
//#region src/core/application/notification/applyNotification.ts
|
|
6853
|
+
/**
|
|
6854
|
+
* Apply notification settings to kintone.
|
|
6855
|
+
*
|
|
6856
|
+
* Each notification section (general, perRecord, reminder) is updated
|
|
6857
|
+
* independently via separate API calls. If one section fails after others
|
|
6858
|
+
* have already been applied, the app will be in a partially-updated state.
|
|
6859
|
+
* This is a kintone API limitation — there is no transactional update
|
|
6860
|
+
* across notification types. Re-running the command is safe and idempotent.
|
|
6861
|
+
*/
|
|
6875
6862
|
async function applyNotification({ container }) {
|
|
6876
6863
|
const result = await container.notificationStorage.get();
|
|
6877
6864
|
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Notification config file not found");
|
|
@@ -7520,85 +7507,77 @@ const VALID_ENTITY_TYPES$1 = new Set([
|
|
|
7520
7507
|
const VALID_ACTION_TYPES = new Set(["PRIMARY", "SECONDARY"]);
|
|
7521
7508
|
function parseProcessEntity(raw, index) {
|
|
7522
7509
|
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Entity at index ${index} must be an object`);
|
|
7523
|
-
const
|
|
7524
|
-
|
|
7525
|
-
const result = { type: obj.type };
|
|
7526
|
-
const withCode = obj.code !== void 0 && obj.code !== null ? {
|
|
7510
|
+
const result = { type: parseEnum(raw.type, VALID_ENTITY_TYPES$1, ProcessManagementErrorCode.PmInvalidEntityType, `Entity at index ${index} has invalid type: ${String(raw.type)}. Must be USER, GROUP, ORGANIZATION, FIELD_ENTITY, CREATOR, or CUSTOM_FIELD`) };
|
|
7511
|
+
const withCode = raw.code !== void 0 && raw.code !== null ? {
|
|
7527
7512
|
...result,
|
|
7528
|
-
code: String(
|
|
7513
|
+
code: String(raw.code)
|
|
7529
7514
|
} : result;
|
|
7530
|
-
if (
|
|
7515
|
+
if (raw.includeSubs !== void 0 && raw.includeSubs !== null) return {
|
|
7531
7516
|
...withCode,
|
|
7532
|
-
includeSubs:
|
|
7517
|
+
includeSubs: parseStrictBoolean(raw.includeSubs, "includeSubs", `Entity at index ${index}`, ProcessManagementErrorCode.PmInvalidBooleanField)
|
|
7533
7518
|
};
|
|
7534
7519
|
return withCode;
|
|
7535
7520
|
}
|
|
7536
7521
|
function parseAssignee(raw, stateName) {
|
|
7537
7522
|
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must be an object`);
|
|
7538
|
-
|
|
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`);
|
|
7540
|
-
if (!Array.isArray(obj.entities)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must have an "entities" array`);
|
|
7541
|
-
const entities = obj.entities.map((item, i) => parseProcessEntity(item, i));
|
|
7523
|
+
if (!Array.isArray(raw.entities)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Assignee for state "${stateName}" must have an "entities" array`);
|
|
7542
7524
|
return {
|
|
7543
|
-
type:
|
|
7544
|
-
entities
|
|
7525
|
+
type: parseEnum(raw.type, VALID_ASSIGNEE_TYPES, ProcessManagementErrorCode.PmInvalidAssigneeType, `Assignee for state "${stateName}" has invalid type: ${String(raw.type)}. Must be ONE, ALL, or ANY`),
|
|
7526
|
+
entities: raw.entities.map((item, i) => parseProcessEntity(item, i))
|
|
7545
7527
|
};
|
|
7546
7528
|
}
|
|
7547
7529
|
function parseState(raw, stateName) {
|
|
7548
7530
|
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must be an object`);
|
|
7549
|
-
|
|
7550
|
-
if (
|
|
7551
|
-
|
|
7552
|
-
const assignee = parseAssignee(obj.assignee, stateName);
|
|
7531
|
+
if (typeof raw.index !== "number") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must have a numeric "index" property`);
|
|
7532
|
+
if (raw.assignee === void 0 || raw.assignee === null) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `State "${stateName}" must have an "assignee" property`);
|
|
7533
|
+
const assignee = parseAssignee(raw.assignee, stateName);
|
|
7553
7534
|
return {
|
|
7554
|
-
index:
|
|
7535
|
+
index: raw.index,
|
|
7555
7536
|
assignee
|
|
7556
7537
|
};
|
|
7557
7538
|
}
|
|
7558
7539
|
function parseExecutableUser(raw, actionIndex) {
|
|
7559
7540
|
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${actionIndex}: executableUser must be an object`);
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
return { entities: obj.entities.map((item, i) => parseProcessEntity(item, i)) };
|
|
7541
|
+
if (!Array.isArray(raw.entities)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${actionIndex}: executableUser must have an "entities" array`);
|
|
7542
|
+
return { entities: raw.entities.map((item, i) => parseProcessEntity(item, i)) };
|
|
7563
7543
|
}
|
|
7564
7544
|
function parseAction(raw, index) {
|
|
7565
7545
|
if (!isRecord(raw)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must be an object`);
|
|
7566
|
-
|
|
7567
|
-
if (typeof
|
|
7568
|
-
if (typeof
|
|
7569
|
-
|
|
7570
|
-
if (obj.type !== void 0 && obj.type !== null && (typeof obj.type !== "string" || !VALID_ACTION_TYPES.has(obj.type))) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} has invalid type: ${String(obj.type)}. Must be PRIMARY or SECONDARY`);
|
|
7571
|
-
const actionType = typeof obj.type === "string" && VALID_ACTION_TYPES.has(obj.type) ? obj.type : "PRIMARY";
|
|
7546
|
+
if (typeof raw.name !== "string") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must have a "name" string property`);
|
|
7547
|
+
if (typeof raw.from !== "string") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must have a "from" string property`);
|
|
7548
|
+
if (typeof raw.to !== "string") throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} must have a "to" string property`);
|
|
7549
|
+
const actionType = raw.type === void 0 || raw.type === null ? "PRIMARY" : parseEnum(raw.type, VALID_ACTION_TYPES, ProcessManagementErrorCode.PmInvalidConfigStructure, `Action at index ${index} has invalid type: ${String(raw.type)}. Must be PRIMARY or SECONDARY`);
|
|
7572
7550
|
const result = {
|
|
7573
|
-
name:
|
|
7574
|
-
from:
|
|
7575
|
-
to:
|
|
7576
|
-
filterCond: typeof
|
|
7551
|
+
name: raw.name,
|
|
7552
|
+
from: raw.from,
|
|
7553
|
+
to: raw.to,
|
|
7554
|
+
filterCond: typeof raw.filterCond === "string" ? raw.filterCond : "",
|
|
7577
7555
|
type: actionType
|
|
7578
7556
|
};
|
|
7579
|
-
if (actionType === "SECONDARY" &&
|
|
7557
|
+
if (actionType === "SECONDARY" && raw.executableUser !== void 0 && raw.executableUser !== null) return {
|
|
7580
7558
|
...result,
|
|
7581
|
-
executableUser: parseExecutableUser(
|
|
7559
|
+
executableUser: parseExecutableUser(raw.executableUser, index)
|
|
7582
7560
|
};
|
|
7583
7561
|
return result;
|
|
7584
7562
|
}
|
|
7585
7563
|
const ProcessManagementConfigParser = { parse: (rawText) => {
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
}
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
const obj = parsed;
|
|
7595
|
-
const enable = obj.enable !== void 0 && obj.enable !== null ? Boolean(obj.enable) : false;
|
|
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 : {};
|
|
7564
|
+
const parsed = parseYamlConfig(rawText, {
|
|
7565
|
+
emptyConfigText: ProcessManagementErrorCode.PmEmptyConfigText,
|
|
7566
|
+
invalidConfigYaml: ProcessManagementErrorCode.PmInvalidConfigYaml,
|
|
7567
|
+
invalidConfigStructure: ProcessManagementErrorCode.PmInvalidConfigStructure
|
|
7568
|
+
}, "Process management");
|
|
7569
|
+
const enable = parsed.enable !== void 0 && parsed.enable !== null ? parseStrictBoolean(parsed.enable, "enable", "Config", ProcessManagementErrorCode.PmInvalidBooleanField) : false;
|
|
7570
|
+
if (parsed.states !== void 0 && parsed.states !== null && !isRecord(parsed.states)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config \"states\" must be an object (map of state name to state definition)");
|
|
7571
|
+
const rawStates = isRecord(parsed.states) ? parsed.states : {};
|
|
7598
7572
|
const states = {};
|
|
7599
7573
|
for (const [name, value] of Object.entries(rawStates)) states[name] = parseState(value, name);
|
|
7600
|
-
if (!Array.isArray(
|
|
7601
|
-
const actions = (
|
|
7574
|
+
if (!Array.isArray(parsed.actions) && parsed.actions !== void 0) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config \"actions\" must be an array");
|
|
7575
|
+
const actions = (Array.isArray(parsed.actions) ? parsed.actions : []).map((item, i) => parseAction(item, i));
|
|
7576
|
+
const actionNames = /* @__PURE__ */ new Set();
|
|
7577
|
+
for (const action of actions) {
|
|
7578
|
+
if (actionNames.has(action.name)) throw new BusinessRuleError(ProcessManagementErrorCode.PmDuplicateActionName, `Duplicate action name: "${action.name}"`);
|
|
7579
|
+
actionNames.add(action.name);
|
|
7580
|
+
}
|
|
7602
7581
|
const stateNames = new Set(Object.keys(states));
|
|
7603
7582
|
for (const action of actions) {
|
|
7604
7583
|
if (!stateNames.has(action.from)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidActionReference, `Action "${action.name}" references unknown "from" state: "${action.from}"`);
|
|
@@ -7751,7 +7730,7 @@ var capture_default$6 = define({
|
|
|
7751
7730
|
//#region src/core/domain/processManagement/services/diffDetector.ts
|
|
7752
7731
|
function isEntityEqual(a, b) {
|
|
7753
7732
|
if (a.type !== b.type) return false;
|
|
7754
|
-
if (a.code !== b.code) return false;
|
|
7733
|
+
if ((a.code ?? "") !== (b.code ?? "")) return false;
|
|
7755
7734
|
if (Boolean(a.includeSubs) !== Boolean(b.includeSubs)) return false;
|
|
7756
7735
|
return true;
|
|
7757
7736
|
}
|
|
@@ -7889,56 +7868,51 @@ const VALID_ENTITY_TYPES = new Set([
|
|
|
7889
7868
|
"ORGANIZATION",
|
|
7890
7869
|
"FIELD_ENTITY"
|
|
7891
7870
|
]);
|
|
7892
|
-
function parseBooleanField(value, fieldName, context) {
|
|
7893
|
-
if (value === void 0) return false;
|
|
7894
|
-
if (typeof value === "boolean") return value;
|
|
7895
|
-
throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidPermissionValue, `${context} has invalid "${fieldName}" value: ${String(value)}. Must be a boolean`);
|
|
7896
|
-
}
|
|
7897
7871
|
function parseEntity(raw, index) {
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
type: obj.type,
|
|
7904
|
-
code: obj.code
|
|
7905
|
-
};
|
|
7872
|
+
return parseEntityBase(raw, index, VALID_ENTITY_TYPES, {
|
|
7873
|
+
invalidStructure: RecordPermissionErrorCode.RpInvalidConfigStructure,
|
|
7874
|
+
invalidType: RecordPermissionErrorCode.RpInvalidEntityType,
|
|
7875
|
+
emptyCode: RecordPermissionErrorCode.RpEmptyEntityCode
|
|
7876
|
+
});
|
|
7906
7877
|
}
|
|
7907
7878
|
function parseRecordRightEntity(raw, index) {
|
|
7908
7879
|
if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right entity at index ${index} must be an object`);
|
|
7909
|
-
const
|
|
7910
|
-
const entity = parseEntity(obj.entity, index);
|
|
7880
|
+
const entity = parseEntity(raw.entity, index);
|
|
7911
7881
|
const context = `Record right entity at index ${index}`;
|
|
7912
7882
|
return {
|
|
7913
7883
|
entity,
|
|
7914
|
-
viewable:
|
|
7915
|
-
editable:
|
|
7916
|
-
deletable:
|
|
7917
|
-
includeSubs:
|
|
7884
|
+
viewable: parseStrictBoolean(raw.viewable, "viewable", context, RecordPermissionErrorCode.RpInvalidPermissionValue, false),
|
|
7885
|
+
editable: parseStrictBoolean(raw.editable, "editable", context, RecordPermissionErrorCode.RpInvalidPermissionValue, false),
|
|
7886
|
+
deletable: parseStrictBoolean(raw.deletable, "deletable", context, RecordPermissionErrorCode.RpInvalidPermissionValue, false),
|
|
7887
|
+
includeSubs: parseStrictBoolean(raw.includeSubs, "includeSubs", context, RecordPermissionErrorCode.RpInvalidPermissionValue, false)
|
|
7918
7888
|
};
|
|
7919
7889
|
}
|
|
7920
7890
|
function parseRecordRight(raw, index) {
|
|
7921
7891
|
if (!isRecord(raw)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right at index ${index} must be an object`);
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
const entities = obj.entities.map((item, i) => parseRecordRightEntity(item, i));
|
|
7892
|
+
if (!Array.isArray(raw.entities)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, `Record right at index ${index} must have an "entities" array`);
|
|
7893
|
+
const entities = raw.entities.map((item, i) => parseRecordRightEntity(item, i));
|
|
7925
7894
|
return {
|
|
7926
|
-
filterCond: typeof
|
|
7895
|
+
filterCond: typeof raw.filterCond === "string" ? raw.filterCond : "",
|
|
7927
7896
|
entities
|
|
7928
7897
|
};
|
|
7929
7898
|
}
|
|
7930
7899
|
const RecordPermissionConfigParser = { parse: (rawText) => {
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
}
|
|
7936
|
-
|
|
7900
|
+
const parsed = parseYamlConfig(rawText, {
|
|
7901
|
+
emptyConfigText: RecordPermissionErrorCode.RpEmptyConfigText,
|
|
7902
|
+
invalidConfigYaml: RecordPermissionErrorCode.RpInvalidConfigYaml,
|
|
7903
|
+
invalidConfigStructure: RecordPermissionErrorCode.RpInvalidConfigStructure
|
|
7904
|
+
}, "Record permission");
|
|
7905
|
+
if (!Array.isArray(parsed.rights)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
7906
|
+
const rights = parsed.rights.map((item, i) => parseRecordRight(item, i));
|
|
7907
|
+
for (const right of rights) {
|
|
7908
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
7909
|
+
for (const re of right.entities) {
|
|
7910
|
+
const key = `${re.entity.type}:${re.entity.code}`;
|
|
7911
|
+
if (seenKeys.has(key)) throw new BusinessRuleError(RecordPermissionErrorCode.RpDuplicateEntity, `Duplicate entity in filterCond "${right.filterCond}": ${re.entity.type} ${re.entity.code}`);
|
|
7912
|
+
seenKeys.add(key);
|
|
7913
|
+
}
|
|
7937
7914
|
}
|
|
7938
|
-
|
|
7939
|
-
const obj = parsed;
|
|
7940
|
-
if (!Array.isArray(obj.rights)) throw new BusinessRuleError(RecordPermissionErrorCode.RpInvalidConfigStructure, "Config must have a \"rights\" array");
|
|
7941
|
-
return { rights: obj.rights.map((item, i) => parseRecordRight(item, i)) };
|
|
7915
|
+
return { rights };
|
|
7942
7916
|
} };
|
|
7943
7917
|
|
|
7944
7918
|
//#endregion
|
|
@@ -7950,13 +7924,17 @@ function parseRecordPermissionConfigText(rawText) {
|
|
|
7950
7924
|
//#endregion
|
|
7951
7925
|
//#region src/core/application/recordPermission/applyRecordPermission.ts
|
|
7952
7926
|
async function applyRecordPermission({ container }) {
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7927
|
+
await applyFromConfig({
|
|
7928
|
+
getStorage: () => container.recordPermissionStorage.get(),
|
|
7929
|
+
parseConfig: parseRecordPermissionConfigText,
|
|
7930
|
+
fetchRemote: () => container.recordPermissionConfigurator.getRecordPermissions(),
|
|
7931
|
+
update: async (config, current) => {
|
|
7932
|
+
await container.recordPermissionConfigurator.updateRecordPermissions({
|
|
7933
|
+
rights: config.rights,
|
|
7934
|
+
revision: current.revision
|
|
7935
|
+
});
|
|
7936
|
+
},
|
|
7937
|
+
notFoundMessage: "Record permission config file not found"
|
|
7960
7938
|
});
|
|
7961
7939
|
}
|
|
7962
7940
|
|
|
@@ -8073,7 +8051,7 @@ var capture_default$5 = define({
|
|
|
8073
8051
|
|
|
8074
8052
|
//#endregion
|
|
8075
8053
|
//#region src/core/domain/recordPermission/services/diffDetector.ts
|
|
8076
|
-
function
|
|
8054
|
+
function isRightEqual(a, b) {
|
|
8077
8055
|
return deepEqual(a.entities.map((e) => ({
|
|
8078
8056
|
type: e.entity.type,
|
|
8079
8057
|
code: e.entity.code,
|
|
@@ -8122,7 +8100,7 @@ const RecordPermissionDiffDetector = { detect: (local, remote) => {
|
|
|
8122
8100
|
details: describeRight(remoteRight)
|
|
8123
8101
|
});
|
|
8124
8102
|
else if (localRight && remoteRight) {
|
|
8125
|
-
if (!
|
|
8103
|
+
if (!isRightEqual(localRight, remoteRight)) {
|
|
8126
8104
|
const diffs = [];
|
|
8127
8105
|
if (localRight.entities.length !== remoteRight.entities.length) diffs.push(`entities: ${remoteRight.entities.length} -> ${localRight.entities.length}`);
|
|
8128
8106
|
else diffs.push("entities changed");
|
|
@@ -8332,13 +8310,17 @@ function parseReportConfigText(rawText) {
|
|
|
8332
8310
|
//#endregion
|
|
8333
8311
|
//#region src/core/application/report/applyReport.ts
|
|
8334
8312
|
async function applyReport({ container }) {
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8313
|
+
await applyFromConfig({
|
|
8314
|
+
getStorage: () => container.reportStorage.get(),
|
|
8315
|
+
parseConfig: parseReportConfigText,
|
|
8316
|
+
fetchRemote: () => container.reportConfigurator.getReports(),
|
|
8317
|
+
update: async (config, current) => {
|
|
8318
|
+
await container.reportConfigurator.updateReports({
|
|
8319
|
+
reports: config.reports,
|
|
8320
|
+
revision: current.revision
|
|
8321
|
+
});
|
|
8322
|
+
},
|
|
8323
|
+
notFoundMessage: "Report config file not found"
|
|
8342
8324
|
});
|
|
8343
8325
|
}
|
|
8344
8326
|
|
|
@@ -9132,12 +9114,25 @@ function parseSchemaText(rawText) {
|
|
|
9132
9114
|
|
|
9133
9115
|
//#endregion
|
|
9134
9116
|
//#region src/core/application/formSchema/detectDiff.ts
|
|
9117
|
+
function fieldPropertiesToDto(field) {
|
|
9118
|
+
if (field.type === "SUBTABLE") {
|
|
9119
|
+
const innerFields = {};
|
|
9120
|
+
for (const [code, def] of field.properties.fields) innerFields[code] = {
|
|
9121
|
+
code: def.code,
|
|
9122
|
+
type: def.type,
|
|
9123
|
+
label: def.label,
|
|
9124
|
+
properties: def.properties
|
|
9125
|
+
};
|
|
9126
|
+
return { fields: innerFields };
|
|
9127
|
+
}
|
|
9128
|
+
return { ...field.properties };
|
|
9129
|
+
}
|
|
9135
9130
|
function toFieldDto(field) {
|
|
9136
9131
|
return {
|
|
9137
9132
|
code: field.code,
|
|
9138
9133
|
type: field.type,
|
|
9139
9134
|
label: field.label,
|
|
9140
|
-
properties: field
|
|
9135
|
+
properties: fieldPropertiesToDto(field)
|
|
9141
9136
|
};
|
|
9142
9137
|
}
|
|
9143
9138
|
async function detectDiff({ container }) {
|
|
@@ -9265,11 +9260,7 @@ var LocalFileDumpStorage = class {
|
|
|
9265
9260
|
//#region src/core/application/container/dumpCli.ts
|
|
9266
9261
|
function createDumpCliContainer(config) {
|
|
9267
9262
|
return {
|
|
9268
|
-
formDumpReader: new KintoneFormDumpReader(
|
|
9269
|
-
baseUrl: config.baseUrl,
|
|
9270
|
-
auth: buildKintoneAuth(config.auth),
|
|
9271
|
-
guestSpaceId: config.guestSpaceId
|
|
9272
|
-
}), config.appId),
|
|
9263
|
+
formDumpReader: new KintoneFormDumpReader(config.client ?? createKintoneClient(config), config.appId),
|
|
9273
9264
|
dumpStorage: new LocalFileDumpStorage(config.filePrefix)
|
|
9274
9265
|
};
|
|
9275
9266
|
}
|
|
@@ -9341,6 +9332,19 @@ var dump_default = define({
|
|
|
9341
9332
|
}
|
|
9342
9333
|
});
|
|
9343
9334
|
|
|
9335
|
+
//#endregion
|
|
9336
|
+
//#region src/core/domain/formSchema/services/subtableFieldSplitter.ts
|
|
9337
|
+
function splitSubtableInnerFields(desired, current) {
|
|
9338
|
+
const newInnerFields = /* @__PURE__ */ new Map();
|
|
9339
|
+
const existingInnerFields = /* @__PURE__ */ new Map();
|
|
9340
|
+
for (const [code, def] of desired.properties.fields) if (current.properties.fields.has(code)) existingInnerFields.set(code, def);
|
|
9341
|
+
else newInnerFields.set(code, def);
|
|
9342
|
+
return {
|
|
9343
|
+
newInnerFields,
|
|
9344
|
+
existingInnerFields
|
|
9345
|
+
};
|
|
9346
|
+
}
|
|
9347
|
+
|
|
9344
9348
|
//#endregion
|
|
9345
9349
|
//#region src/core/domain/formSchema/services/schemaValidator.ts
|
|
9346
9350
|
const SELECTION_TYPES = new Set([
|
|
@@ -9513,10 +9517,7 @@ async function executeMigration({ container }) {
|
|
|
9513
9517
|
const after = entry.after;
|
|
9514
9518
|
const before = entry.before;
|
|
9515
9519
|
if (after.type === "SUBTABLE" && before !== void 0 && before.type === "SUBTABLE") {
|
|
9516
|
-
const newInnerFields
|
|
9517
|
-
const existingInnerFields = /* @__PURE__ */ new Map();
|
|
9518
|
-
for (const [code, def] of after.properties.fields) if (before.properties.fields.has(code)) existingInnerFields.set(code, def);
|
|
9519
|
-
else newInnerFields.set(code, def);
|
|
9520
|
+
const { newInnerFields, existingInnerFields } = splitSubtableInnerFields(after, before);
|
|
9520
9521
|
if (newInnerFields.size > 0) fieldsToAdd.push({
|
|
9521
9522
|
...after,
|
|
9522
9523
|
properties: { fields: newInnerFields }
|
|
@@ -9651,10 +9652,7 @@ async function forceOverrideForm({ container }) {
|
|
|
9651
9652
|
if (currentFields.has(fieldCode)) if (schemaDef.type === "SUBTABLE") {
|
|
9652
9653
|
const currentDef = currentFields.get(fieldCode);
|
|
9653
9654
|
if (currentDef !== void 0 && currentDef.type === "SUBTABLE") {
|
|
9654
|
-
const newInnerFields
|
|
9655
|
-
const existingInnerFields = /* @__PURE__ */ new Map();
|
|
9656
|
-
for (const [code, def] of schemaDef.properties.fields) if (currentDef.properties.fields.has(code)) existingInnerFields.set(code, def);
|
|
9657
|
-
else newInnerFields.set(code, def);
|
|
9655
|
+
const { newInnerFields, existingInnerFields } = splitSubtableInnerFields(schemaDef, currentDef);
|
|
9658
9656
|
if (newInnerFields.size > 0) toAdd.push({
|
|
9659
9657
|
...schemaDef,
|
|
9660
9658
|
properties: { fields: newInnerFields }
|
|
@@ -9821,9 +9819,9 @@ async function validateSchema({ container }) {
|
|
|
9821
9819
|
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Schema file not found");
|
|
9822
9820
|
let schema;
|
|
9823
9821
|
try {
|
|
9824
|
-
schema =
|
|
9822
|
+
schema = parseSchemaText(result.content);
|
|
9825
9823
|
} catch (error) {
|
|
9826
|
-
if (
|
|
9824
|
+
if (isValidationError(error)) return {
|
|
9827
9825
|
parseError: error.message,
|
|
9828
9826
|
fieldCount: 0
|
|
9829
9827
|
};
|
|
@@ -9932,6 +9930,50 @@ var schema_default = define({
|
|
|
9932
9930
|
run: () => {}
|
|
9933
9931
|
});
|
|
9934
9932
|
|
|
9933
|
+
//#endregion
|
|
9934
|
+
//#region src/core/domain/seedData/services/upsertPlanner.ts
|
|
9935
|
+
function recordsEqual(seed, existing, keyField) {
|
|
9936
|
+
const seedKeys = Object.keys(seed).filter((k) => k !== keyField);
|
|
9937
|
+
for (const key of seedKeys) {
|
|
9938
|
+
const seedValue = seed[key];
|
|
9939
|
+
const existingValue = existing[key];
|
|
9940
|
+
if (seedValue === void 0 && existingValue === void 0) continue;
|
|
9941
|
+
if (seedValue === void 0 || existingValue === void 0) return false;
|
|
9942
|
+
if (!deepEqual(seedValue, existingValue)) return false;
|
|
9943
|
+
}
|
|
9944
|
+
return true;
|
|
9945
|
+
}
|
|
9946
|
+
const UpsertPlanner = { plan: (key, seedRecords, existingRecords) => {
|
|
9947
|
+
const keyField = key;
|
|
9948
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
9949
|
+
for (const { id, record } of existingRecords) {
|
|
9950
|
+
const keyValue = record[keyField];
|
|
9951
|
+
if (typeof keyValue === "string") existingMap.set(keyValue, {
|
|
9952
|
+
id,
|
|
9953
|
+
record
|
|
9954
|
+
});
|
|
9955
|
+
}
|
|
9956
|
+
const toAdd = [];
|
|
9957
|
+
const toUpdate = [];
|
|
9958
|
+
let unchanged = 0;
|
|
9959
|
+
for (const seedRecord of seedRecords) {
|
|
9960
|
+
const keyValue = seedRecord[keyField];
|
|
9961
|
+
if (typeof keyValue !== "string") throw new BusinessRuleError(SeedDataErrorCode.SdInvalidKeyFieldValue, `Key field "${keyField}" value must be a string, got ${typeof keyValue}`);
|
|
9962
|
+
const existing = existingMap.get(keyValue);
|
|
9963
|
+
if (existing === void 0) toAdd.push(seedRecord);
|
|
9964
|
+
else if (recordsEqual(seedRecord, existing.record, keyField)) unchanged++;
|
|
9965
|
+
else toUpdate.push({
|
|
9966
|
+
id: existing.id,
|
|
9967
|
+
record: seedRecord
|
|
9968
|
+
});
|
|
9969
|
+
}
|
|
9970
|
+
return {
|
|
9971
|
+
toAdd,
|
|
9972
|
+
toUpdate,
|
|
9973
|
+
unchanged
|
|
9974
|
+
};
|
|
9975
|
+
} };
|
|
9976
|
+
|
|
9935
9977
|
//#endregion
|
|
9936
9978
|
//#region src/core/domain/seedData/services/seedParser.ts
|
|
9937
9979
|
function normalizeValue(value) {
|
|
@@ -9993,55 +10035,17 @@ const SeedParser = { parse: (rawText) => {
|
|
|
9993
10035
|
} };
|
|
9994
10036
|
|
|
9995
10037
|
//#endregion
|
|
9996
|
-
//#region src/core/
|
|
9997
|
-
function
|
|
9998
|
-
|
|
9999
|
-
for (const key of seedKeys) {
|
|
10000
|
-
const seedValue = seed[key];
|
|
10001
|
-
const existingValue = existing[key];
|
|
10002
|
-
if (seedValue === void 0 && existingValue === void 0) continue;
|
|
10003
|
-
if (seedValue === void 0 || existingValue === void 0) return false;
|
|
10004
|
-
if (!deepEqual(seedValue, existingValue)) return false;
|
|
10005
|
-
}
|
|
10006
|
-
return true;
|
|
10038
|
+
//#region src/core/application/seedData/parseConfig.ts
|
|
10039
|
+
function parseSeedText(rawText) {
|
|
10040
|
+
return wrapBusinessRuleError(() => SeedParser.parse(rawText));
|
|
10007
10041
|
}
|
|
10008
|
-
const UpsertPlanner = { plan: (key, seedRecords, existingRecords) => {
|
|
10009
|
-
const keyField = key;
|
|
10010
|
-
const existingMap = /* @__PURE__ */ new Map();
|
|
10011
|
-
for (const { id, record } of existingRecords) {
|
|
10012
|
-
const keyValue = record[keyField];
|
|
10013
|
-
if (typeof keyValue === "string") existingMap.set(keyValue, {
|
|
10014
|
-
id,
|
|
10015
|
-
record
|
|
10016
|
-
});
|
|
10017
|
-
}
|
|
10018
|
-
const toAdd = [];
|
|
10019
|
-
const toUpdate = [];
|
|
10020
|
-
let unchanged = 0;
|
|
10021
|
-
for (const seedRecord of seedRecords) {
|
|
10022
|
-
const keyValue = seedRecord[keyField];
|
|
10023
|
-
if (typeof keyValue !== "string") throw new BusinessRuleError(SeedDataErrorCode.SdInvalidKeyFieldValue, `Key field "${keyField}" value must be a string, got ${typeof keyValue}`);
|
|
10024
|
-
const existing = existingMap.get(keyValue);
|
|
10025
|
-
if (existing === void 0) toAdd.push(seedRecord);
|
|
10026
|
-
else if (recordsEqual(seedRecord, existing.record, keyField)) unchanged++;
|
|
10027
|
-
else toUpdate.push({
|
|
10028
|
-
id: existing.id,
|
|
10029
|
-
record: seedRecord
|
|
10030
|
-
});
|
|
10031
|
-
}
|
|
10032
|
-
return {
|
|
10033
|
-
toAdd,
|
|
10034
|
-
toUpdate,
|
|
10035
|
-
unchanged
|
|
10036
|
-
};
|
|
10037
|
-
} };
|
|
10038
10042
|
|
|
10039
10043
|
//#endregion
|
|
10040
10044
|
//#region src/core/application/seedData/upsertSeed.ts
|
|
10041
10045
|
async function upsertSeed({ container, input }) {
|
|
10042
10046
|
const result = await container.seedStorage.get();
|
|
10043
10047
|
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Seed file not found");
|
|
10044
|
-
const seedData =
|
|
10048
|
+
const seedData = parseSeedText(result.content);
|
|
10045
10049
|
if (input.clean) {
|
|
10046
10050
|
const { deletedCount } = await container.recordManager.deleteAllRecords();
|
|
10047
10051
|
if (seedData.records.length > 0) await container.recordManager.addRecords(seedData.records);
|
|
@@ -10249,6 +10253,11 @@ var seed_default = define({
|
|
|
10249
10253
|
|
|
10250
10254
|
//#endregion
|
|
10251
10255
|
//#region src/core/domain/generalSettings/services/configParser.ts
|
|
10256
|
+
function parseOptionalBoolean(parsed, fieldName) {
|
|
10257
|
+
const value = parsed[fieldName];
|
|
10258
|
+
if (value === void 0 || value === null) return void 0;
|
|
10259
|
+
return parseStrictBoolean(value, fieldName, "Config", GeneralSettingsErrorCode.GsInvalidBooleanField);
|
|
10260
|
+
}
|
|
10252
10261
|
const VALID_THEMES = new Set([
|
|
10253
10262
|
"WHITE",
|
|
10254
10263
|
"RED",
|
|
@@ -10270,86 +10279,70 @@ const VALID_ROUNDING_MODES = new Set([
|
|
|
10270
10279
|
]);
|
|
10271
10280
|
function parseIcon(raw) {
|
|
10272
10281
|
if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must be an object with \"type\" and \"key\" properties");
|
|
10273
|
-
|
|
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)}`);
|
|
10275
|
-
if (typeof obj.key !== "string" || obj.key.length === 0) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must have a non-empty \"key\" property");
|
|
10282
|
+
if (typeof raw.key !== "string" || raw.key.length === 0) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "icon must have a non-empty \"key\" property");
|
|
10276
10283
|
return {
|
|
10277
|
-
type:
|
|
10278
|
-
key:
|
|
10284
|
+
type: parseEnum(raw.type, VALID_ICON_TYPES, GeneralSettingsErrorCode.GsInvalidIconType, `icon.type must be PRESET or FILE, got: ${String(raw.type)}`),
|
|
10285
|
+
key: raw.key
|
|
10279
10286
|
};
|
|
10280
10287
|
}
|
|
10281
10288
|
function parseTitleField(raw) {
|
|
10282
10289
|
if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "titleField must be an object with \"selectionMode\" property");
|
|
10283
|
-
const
|
|
10284
|
-
if (
|
|
10285
|
-
|
|
10286
|
-
if (obj.code !== void 0 && obj.code !== null) {
|
|
10287
|
-
if (typeof obj.code !== "string") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "titleField.code must be a string");
|
|
10290
|
+
const result = { selectionMode: parseEnum(raw.selectionMode, VALID_SELECTION_MODES, GeneralSettingsErrorCode.GsInvalidConfigStructure, `titleField.selectionMode must be AUTO or MANUAL, got: ${String(raw.selectionMode)}`) };
|
|
10291
|
+
if (raw.code !== void 0 && raw.code !== null) {
|
|
10292
|
+
if (typeof raw.code !== "string") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "titleField.code must be a string");
|
|
10288
10293
|
return {
|
|
10289
10294
|
...result,
|
|
10290
|
-
code:
|
|
10295
|
+
code: raw.code
|
|
10291
10296
|
};
|
|
10292
10297
|
}
|
|
10293
10298
|
return result;
|
|
10294
10299
|
}
|
|
10295
10300
|
function parseNumberPrecision(raw) {
|
|
10296
10301
|
if (!isRecord(raw)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision must be an object");
|
|
10297
|
-
|
|
10298
|
-
if (
|
|
10299
|
-
if (typeof
|
|
10300
|
-
if (
|
|
10302
|
+
if (typeof raw.digits !== "number") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision.digits must be a number");
|
|
10303
|
+
if (!Number.isInteger(raw.digits) || raw.digits < 0) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidNumberPrecision, `numberPrecision.digits must be a non-negative integer, got: ${raw.digits}`);
|
|
10304
|
+
if (typeof raw.decimalPlaces !== "number") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "numberPrecision.decimalPlaces must be a number");
|
|
10305
|
+
if (!Number.isInteger(raw.decimalPlaces) || raw.decimalPlaces < 0) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidNumberPrecision, `numberPrecision.decimalPlaces must be a non-negative integer, got: ${raw.decimalPlaces}`);
|
|
10301
10306
|
return {
|
|
10302
|
-
digits:
|
|
10303
|
-
decimalPlaces:
|
|
10304
|
-
roundingMode:
|
|
10307
|
+
digits: raw.digits,
|
|
10308
|
+
decimalPlaces: raw.decimalPlaces,
|
|
10309
|
+
roundingMode: parseEnum(raw.roundingMode, VALID_ROUNDING_MODES, GeneralSettingsErrorCode.GsInvalidConfigStructure, `numberPrecision.roundingMode must be HALF_EVEN, UP, or DOWN, got: ${String(raw.roundingMode)}`)
|
|
10305
10310
|
};
|
|
10306
10311
|
}
|
|
10307
10312
|
const GeneralSettingsConfigParser = { parse: (rawText) => {
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
}
|
|
10313
|
-
throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigYaml, `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
10314
|
-
}
|
|
10315
|
-
if (!isRecord(parsed)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "Config must be a YAML object");
|
|
10316
|
-
const obj = parsed;
|
|
10313
|
+
const parsed = parseYamlConfig(rawText, {
|
|
10314
|
+
emptyConfigText: GeneralSettingsErrorCode.GsEmptyConfigText,
|
|
10315
|
+
invalidConfigYaml: GeneralSettingsErrorCode.GsInvalidConfigYaml,
|
|
10316
|
+
invalidConfigStructure: GeneralSettingsErrorCode.GsInvalidConfigStructure
|
|
10317
|
+
}, "General settings");
|
|
10317
10318
|
let name;
|
|
10318
|
-
if (
|
|
10319
|
-
if (typeof
|
|
10320
|
-
name =
|
|
10319
|
+
if (parsed.name !== void 0 && parsed.name !== null) {
|
|
10320
|
+
if (typeof parsed.name !== "string") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "name must be a string");
|
|
10321
|
+
name = parsed.name;
|
|
10321
10322
|
}
|
|
10322
10323
|
let description;
|
|
10323
|
-
if (
|
|
10324
|
-
if (typeof
|
|
10325
|
-
description =
|
|
10324
|
+
if (parsed.description !== void 0 && parsed.description !== null) {
|
|
10325
|
+
if (typeof parsed.description !== "string") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "description must be a string");
|
|
10326
|
+
description = parsed.description;
|
|
10326
10327
|
}
|
|
10327
10328
|
let icon;
|
|
10328
|
-
if (
|
|
10329
|
+
if (parsed.icon !== void 0 && parsed.icon !== null) icon = parseIcon(parsed.icon);
|
|
10329
10330
|
let theme;
|
|
10330
|
-
if (
|
|
10331
|
-
if (typeof obj.theme !== "string" || !VALID_THEMES.has(obj.theme)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidTheme, `theme must be WHITE, RED, GREEN, BLUE, YELLOW, BLACK, CLIPBOARD, BINDER, PENCIL, or CLIPS, got: ${String(obj.theme)}`);
|
|
10332
|
-
theme = obj.theme;
|
|
10333
|
-
}
|
|
10331
|
+
if (parsed.theme !== void 0 && parsed.theme !== null) theme = parseEnum(parsed.theme, VALID_THEMES, GeneralSettingsErrorCode.GsInvalidTheme, `theme must be WHITE, RED, GREEN, BLUE, YELLOW, BLACK, CLIPBOARD, BINDER, PENCIL, or CLIPS, got: ${String(parsed.theme)}`);
|
|
10334
10332
|
let titleField;
|
|
10335
|
-
if (
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
if (obj.enableComments !== void 0 && obj.enableComments !== null) enableComments = Boolean(obj.enableComments);
|
|
10342
|
-
let enableDuplicateRecord;
|
|
10343
|
-
if (obj.enableDuplicateRecord !== void 0 && obj.enableDuplicateRecord !== null) enableDuplicateRecord = Boolean(obj.enableDuplicateRecord);
|
|
10344
|
-
let enableInlineRecordEditing;
|
|
10345
|
-
if (obj.enableInlineRecordEditing !== void 0 && obj.enableInlineRecordEditing !== null) enableInlineRecordEditing = Boolean(obj.enableInlineRecordEditing);
|
|
10333
|
+
if (parsed.titleField !== void 0 && parsed.titleField !== null) titleField = parseTitleField(parsed.titleField);
|
|
10334
|
+
const enableThumbnails = parseOptionalBoolean(parsed, "enableThumbnails");
|
|
10335
|
+
const enableBulkDeletion = parseOptionalBoolean(parsed, "enableBulkDeletion");
|
|
10336
|
+
const enableComments = parseOptionalBoolean(parsed, "enableComments");
|
|
10337
|
+
const enableDuplicateRecord = parseOptionalBoolean(parsed, "enableDuplicateRecord");
|
|
10338
|
+
const enableInlineRecordEditing = parseOptionalBoolean(parsed, "enableInlineRecordEditing");
|
|
10346
10339
|
let numberPrecision;
|
|
10347
|
-
if (
|
|
10340
|
+
if (parsed.numberPrecision !== void 0 && parsed.numberPrecision !== null) numberPrecision = parseNumberPrecision(parsed.numberPrecision);
|
|
10348
10341
|
let firstMonthOfFiscalYear;
|
|
10349
|
-
if (
|
|
10350
|
-
if (typeof
|
|
10351
|
-
if (
|
|
10352
|
-
firstMonthOfFiscalYear =
|
|
10342
|
+
if (parsed.firstMonthOfFiscalYear !== void 0 && parsed.firstMonthOfFiscalYear !== null) {
|
|
10343
|
+
if (typeof parsed.firstMonthOfFiscalYear !== "number") throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, "firstMonthOfFiscalYear must be a number");
|
|
10344
|
+
if (parsed.firstMonthOfFiscalYear < 1 || parsed.firstMonthOfFiscalYear > 12 || !Number.isInteger(parsed.firstMonthOfFiscalYear)) throw new BusinessRuleError(GeneralSettingsErrorCode.GsInvalidConfigStructure, `firstMonthOfFiscalYear must be an integer between 1 and 12, got: ${parsed.firstMonthOfFiscalYear}`);
|
|
10345
|
+
firstMonthOfFiscalYear = parsed.firstMonthOfFiscalYear;
|
|
10353
10346
|
}
|
|
10354
10347
|
return {
|
|
10355
10348
|
...name !== void 0 ? { name } : {},
|
|
@@ -10376,13 +10369,17 @@ function parseGeneralSettingsConfigText(rawText) {
|
|
|
10376
10369
|
//#endregion
|
|
10377
10370
|
//#region src/core/application/generalSettings/applyGeneralSettings.ts
|
|
10378
10371
|
async function applyGeneralSettings({ container }) {
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
|
|
10372
|
+
await applyFromConfig({
|
|
10373
|
+
getStorage: () => container.generalSettingsStorage.get(),
|
|
10374
|
+
parseConfig: parseGeneralSettingsConfigText,
|
|
10375
|
+
fetchRemote: () => container.generalSettingsConfigurator.getGeneralSettings(),
|
|
10376
|
+
update: async (config, current) => {
|
|
10377
|
+
await container.generalSettingsConfigurator.updateGeneralSettings({
|
|
10378
|
+
config,
|
|
10379
|
+
revision: current.revision
|
|
10380
|
+
});
|
|
10381
|
+
},
|
|
10382
|
+
notFoundMessage: "General settings config file not found"
|
|
10386
10383
|
});
|
|
10387
10384
|
}
|
|
10388
10385
|
|
|
@@ -10531,11 +10528,14 @@ function compareConfigs(local, remote) {
|
|
|
10531
10528
|
details: `${rv} -> ${lv}`
|
|
10532
10529
|
});
|
|
10533
10530
|
}
|
|
10531
|
+
function formatValue(v) {
|
|
10532
|
+
return v === void 0 ? "(none)" : JSON.stringify(v);
|
|
10533
|
+
}
|
|
10534
10534
|
function compareDeepEqual(field, l, r) {
|
|
10535
10535
|
if (!deepEqual(l, r)) entries.push({
|
|
10536
10536
|
type: "modified",
|
|
10537
10537
|
field,
|
|
10538
|
-
details: `${
|
|
10538
|
+
details: `${formatValue(r)} -> ${formatValue(l)}`
|
|
10539
10539
|
});
|
|
10540
10540
|
}
|
|
10541
10541
|
compareString("name", local.name, remote.name, DEFAULT_STRING);
|