kintone-migrator 0.24.3 → 0.24.5
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 +548 -447
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { parse, stringify } from "yaml";
|
|
|
7
7
|
import { KintoneRestAPIClient, KintoneRestAPIError } from "@kintone/rest-api-client";
|
|
8
8
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
9
9
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
10
|
+
import { realpathSync } from "node:fs";
|
|
10
11
|
import * as v from "valibot";
|
|
11
12
|
import pc from "picocolors";
|
|
12
13
|
|
|
@@ -290,6 +291,10 @@ var ConflictError = class extends ApplicationError {
|
|
|
290
291
|
function isConflictError(error) {
|
|
291
292
|
return error instanceof ConflictError;
|
|
292
293
|
}
|
|
294
|
+
const UnauthenticatedErrorCode = {
|
|
295
|
+
AuthenticationRequired: "AUTHENTICATION_REQUIRED",
|
|
296
|
+
InvalidCredentials: "INVALID_CREDENTIALS"
|
|
297
|
+
};
|
|
293
298
|
var UnauthenticatedError = class extends ApplicationError {
|
|
294
299
|
name = "UnauthenticatedError";
|
|
295
300
|
constructor(code, message, cause) {
|
|
@@ -300,6 +305,7 @@ var UnauthenticatedError = class extends ApplicationError {
|
|
|
300
305
|
function isUnauthenticatedError(error) {
|
|
301
306
|
return error instanceof UnauthenticatedError;
|
|
302
307
|
}
|
|
308
|
+
const ForbiddenErrorCode = { InsufficientPermissions: "INSUFFICIENT_PERMISSIONS" };
|
|
303
309
|
var ForbiddenError = class extends ApplicationError {
|
|
304
310
|
name = "ForbiddenError";
|
|
305
311
|
constructor(code, message, cause) {
|
|
@@ -340,6 +346,16 @@ function isSystemError(error) {
|
|
|
340
346
|
return error instanceof SystemError;
|
|
341
347
|
}
|
|
342
348
|
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/core/application/applyFromConfigBase.ts
|
|
351
|
+
async function applyFromConfig(config) {
|
|
352
|
+
const result = await config.getStorage();
|
|
353
|
+
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, config.notFoundMessage);
|
|
354
|
+
const parsed = config.parseConfig(result.content);
|
|
355
|
+
const remote = await config.fetchRemote();
|
|
356
|
+
await config.update(parsed, remote);
|
|
357
|
+
}
|
|
358
|
+
|
|
343
359
|
//#endregion
|
|
344
360
|
//#region src/lib/typeGuards.ts
|
|
345
361
|
/**
|
|
@@ -525,16 +541,74 @@ function parseActionConfigText(rawText) {
|
|
|
525
541
|
//#endregion
|
|
526
542
|
//#region src/core/application/action/applyAction.ts
|
|
527
543
|
async function applyAction({ container }) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
544
|
+
await applyFromConfig({
|
|
545
|
+
getStorage: () => container.actionStorage.get(),
|
|
546
|
+
parseConfig: parseActionConfigText,
|
|
547
|
+
fetchRemote: () => container.actionConfigurator.getActions(),
|
|
548
|
+
update: async (config, current) => {
|
|
549
|
+
await container.actionConfigurator.updateActions({
|
|
550
|
+
actions: config.actions,
|
|
551
|
+
revision: current.revision
|
|
552
|
+
});
|
|
553
|
+
},
|
|
554
|
+
notFoundMessage: "Action config file not found"
|
|
535
555
|
});
|
|
536
556
|
}
|
|
537
557
|
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/core/adapters/kintone/wrapKintoneError.ts
|
|
560
|
+
const KINTONE_REVISION_CONFLICT_CODE = "GAIA_CO02";
|
|
561
|
+
const KINTONE_MAINTENANCE_MODE_CODE = "GAIA_NO02";
|
|
562
|
+
function formatMessage(message, error) {
|
|
563
|
+
if (error instanceof KintoneRestAPIError && error.message) return `${message}: ${error.message}`;
|
|
564
|
+
if (error instanceof Error && error.message) return `${message}: ${error.message}`;
|
|
565
|
+
return message;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Converts an unknown error thrown during a kintone API call into the
|
|
569
|
+
* appropriate application-layer error.
|
|
570
|
+
*
|
|
571
|
+
* - {@link BusinessRuleError} and {@link ApplicationError} (including all
|
|
572
|
+
* subclasses such as {@link SystemError}, {@link ValidationError}, etc.)
|
|
573
|
+
* are re-thrown as-is so that errors raised inside a try block are never
|
|
574
|
+
* silently converted.
|
|
575
|
+
* - {@link KintoneRestAPIError} is mapped by HTTP status (401/403/404/409/400)
|
|
576
|
+
* and kintone-specific codes (`GAIA_CO02` revision conflict, `GAIA_NO02`
|
|
577
|
+
* maintenance mode).
|
|
578
|
+
* - Everything else becomes a {@link SystemError} with code `ExternalApiError`.
|
|
579
|
+
*
|
|
580
|
+
* **Note on 400 mapping**: All 400 errors (except `GAIA_CO02`) are mapped to
|
|
581
|
+
* {@link ValidationError}. This is intentionally simplified — some 400 codes
|
|
582
|
+
* (e.g. `GAIA_RE18` record limit, `GAIA_AP01` app unavailable) may have
|
|
583
|
+
* different semantics, but for this CLI tool a single `ValidationError`
|
|
584
|
+
* with the original kintone message in the error detail is sufficient.
|
|
585
|
+
*
|
|
586
|
+
* @throws {UnauthenticatedError} when kintone returns 401
|
|
587
|
+
* @throws {ForbiddenError} when kintone returns 403 (non-GAIA_NO02)
|
|
588
|
+
* @throws {SystemError} when kintone returns 403 with GAIA_NO02 (maintenance mode)
|
|
589
|
+
* @throws {NotFoundError} when kintone returns 404
|
|
590
|
+
* @throws {ConflictError} when kintone returns 409 or GAIA_CO02
|
|
591
|
+
* @throws {ValidationError} when kintone returns 400 (non-GAIA_CO02)
|
|
592
|
+
* @throws {SystemError} for all other kintone errors and unknown errors
|
|
593
|
+
*/
|
|
594
|
+
function wrapKintoneError(error, message) {
|
|
595
|
+
if (isBusinessRuleError(error)) throw error;
|
|
596
|
+
if (error instanceof ApplicationError) throw error;
|
|
597
|
+
const detail = formatMessage(message, error);
|
|
598
|
+
if (error instanceof KintoneRestAPIError) {
|
|
599
|
+
if (error.status === 401) throw new UnauthenticatedError(UnauthenticatedErrorCode.InvalidCredentials, detail, error);
|
|
600
|
+
if (error.status === 403) {
|
|
601
|
+
if (error.code === KINTONE_MAINTENANCE_MODE_CODE) throw new SystemError(SystemErrorCode.ExternalApiError, `${detail} (app is in maintenance mode — GAIA_NO02)`, error);
|
|
602
|
+
throw new ForbiddenError(ForbiddenErrorCode.InsufficientPermissions, detail, error);
|
|
603
|
+
}
|
|
604
|
+
if (error.status === 404) throw new NotFoundError(NotFoundErrorCode.NotFound, detail, error);
|
|
605
|
+
if (error.code === KINTONE_REVISION_CONFLICT_CODE) throw new ConflictError(ConflictErrorCode.Conflict, `${detail} (revision conflict — GAIA_CO02). Please retry the operation.`, error);
|
|
606
|
+
if (error.status === 409) throw new ConflictError(ConflictErrorCode.Conflict, detail, error);
|
|
607
|
+
if (error.status === 400) throw new ValidationError(ValidationErrorCode.InvalidInput, detail, error);
|
|
608
|
+
}
|
|
609
|
+
throw new SystemError(SystemErrorCode.ExternalApiError, detail, error);
|
|
610
|
+
}
|
|
611
|
+
|
|
538
612
|
//#endregion
|
|
539
613
|
//#region src/core/adapters/kintone/actionConfigurator.ts
|
|
540
614
|
function fromKintoneDestApp(raw) {
|
|
@@ -620,9 +694,7 @@ var KintoneActionConfigurator = class {
|
|
|
620
694
|
revision: response.revision
|
|
621
695
|
};
|
|
622
696
|
} catch (error) {
|
|
623
|
-
|
|
624
|
-
if (error instanceof SystemError) throw error;
|
|
625
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get app actions", error);
|
|
697
|
+
throw wrapKintoneError(error, "Failed to get app actions");
|
|
626
698
|
}
|
|
627
699
|
}
|
|
628
700
|
async updateActions(params) {
|
|
@@ -636,15 +708,22 @@ var KintoneActionConfigurator = class {
|
|
|
636
708
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
637
709
|
return { revision: (await this.client.app.updateAppActions(requestParams)).revision };
|
|
638
710
|
} catch (error) {
|
|
639
|
-
|
|
640
|
-
if (error instanceof SystemError) throw error;
|
|
641
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update app actions", error);
|
|
711
|
+
throw wrapKintoneError(error, "Failed to update app actions");
|
|
642
712
|
}
|
|
643
713
|
}
|
|
644
714
|
};
|
|
645
715
|
|
|
646
716
|
//#endregion
|
|
647
717
|
//#region src/core/adapters/kintone/appDeployer.ts
|
|
718
|
+
const VALID_DEPLOY_STATUSES = new Set([
|
|
719
|
+
"PROCESSING",
|
|
720
|
+
"SUCCESS",
|
|
721
|
+
"FAIL",
|
|
722
|
+
"CANCEL"
|
|
723
|
+
]);
|
|
724
|
+
function isDeployStatus(value) {
|
|
725
|
+
return VALID_DEPLOY_STATUSES.has(value);
|
|
726
|
+
}
|
|
648
727
|
const DEFAULT_POLL_INTERVAL_MS = 1e3;
|
|
649
728
|
const DEFAULT_MAX_RETRIES = 180;
|
|
650
729
|
var KintoneAppDeployer = class {
|
|
@@ -659,12 +738,10 @@ var KintoneAppDeployer = class {
|
|
|
659
738
|
async deploy() {
|
|
660
739
|
try {
|
|
661
740
|
await this.client.app.deployApp({ apps: [{ app: this.appId }] });
|
|
662
|
-
await this.waitForDeployment();
|
|
663
741
|
} catch (error) {
|
|
664
|
-
|
|
665
|
-
if (error instanceof SystemError) throw error;
|
|
666
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to deploy app", error);
|
|
742
|
+
throw wrapKintoneError(error, "Failed to deploy app");
|
|
667
743
|
}
|
|
744
|
+
await this.waitForDeployment();
|
|
668
745
|
}
|
|
669
746
|
async waitForDeployment() {
|
|
670
747
|
let lastPollError;
|
|
@@ -678,20 +755,21 @@ var KintoneAppDeployer = class {
|
|
|
678
755
|
consecutivePollFailures = 0;
|
|
679
756
|
} catch (error) {
|
|
680
757
|
if (isBusinessRuleError(error)) throw error;
|
|
681
|
-
if (error instanceof
|
|
758
|
+
if (error instanceof ApplicationError) throw error;
|
|
682
759
|
lastPollError = error;
|
|
683
760
|
consecutivePollFailures++;
|
|
684
761
|
if (consecutivePollFailures >= maxConsecutivePollFailures) throw new SystemError(SystemErrorCode.ExternalApiError, `Deploy status polling failed ${maxConsecutivePollFailures} consecutive times`, lastPollError);
|
|
685
762
|
continue;
|
|
686
763
|
}
|
|
687
|
-
|
|
688
|
-
|
|
764
|
+
if (apps.length === 0) throw new SystemError(SystemErrorCode.ExternalApiError, "Deploy status response contained no apps");
|
|
765
|
+
const rawStatus = apps[0].status;
|
|
766
|
+
if (rawStatus === void 0) throw new SystemError(SystemErrorCode.ExternalApiError, "Deploy status unavailable");
|
|
767
|
+
if (!isDeployStatus(rawStatus)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected deploy status: ${rawStatus}`);
|
|
768
|
+
switch (rawStatus) {
|
|
689
769
|
case "SUCCESS": return;
|
|
690
770
|
case "FAIL": throw new SystemError(SystemErrorCode.ExternalApiError, "App deployment failed");
|
|
691
771
|
case "CANCEL": throw new SystemError(SystemErrorCode.ExternalApiError, "App deployment was cancelled");
|
|
692
772
|
case "PROCESSING": continue;
|
|
693
|
-
case void 0: throw new SystemError(SystemErrorCode.ExternalApiError, "Deploy status unavailable");
|
|
694
|
-
default: throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected deploy status: ${status}`);
|
|
695
773
|
}
|
|
696
774
|
}
|
|
697
775
|
throw new SystemError(SystemErrorCode.ExternalApiError, "App deployment timed out", lastPollError);
|
|
@@ -820,9 +898,7 @@ var KintoneCustomizationConfigurator = class {
|
|
|
820
898
|
revision: response.revision
|
|
821
899
|
};
|
|
822
900
|
} catch (error) {
|
|
823
|
-
|
|
824
|
-
if (error instanceof SystemError) throw error;
|
|
825
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get app customization", error);
|
|
901
|
+
throw wrapKintoneError(error, "Failed to get app customization");
|
|
826
902
|
}
|
|
827
903
|
}
|
|
828
904
|
async updateCustomization(params) {
|
|
@@ -843,9 +919,7 @@ var KintoneCustomizationConfigurator = class {
|
|
|
843
919
|
const response = await this.client.app.updateAppCustomize(requestParams);
|
|
844
920
|
return { revision: String(response.revision) };
|
|
845
921
|
} catch (error) {
|
|
846
|
-
|
|
847
|
-
if (error instanceof SystemError) throw error;
|
|
848
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update app customization", error);
|
|
922
|
+
throw wrapKintoneError(error, "Failed to update app customization");
|
|
849
923
|
}
|
|
850
924
|
}
|
|
851
925
|
};
|
|
@@ -857,31 +931,77 @@ var KintoneFileDownloader = class {
|
|
|
857
931
|
this.client = client;
|
|
858
932
|
}
|
|
859
933
|
async download(fileKey) {
|
|
860
|
-
if (!fileKey) throw new
|
|
934
|
+
if (!fileKey) throw new ValidationError(ValidationErrorCode.InvalidInput, "fileKey must not be empty");
|
|
861
935
|
try {
|
|
862
936
|
return await this.client.file.downloadFile({ fileKey });
|
|
863
937
|
} catch (error) {
|
|
864
|
-
|
|
865
|
-
if (error instanceof SystemError) throw error;
|
|
866
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, `Failed to download file: ${fileKey}`, error);
|
|
938
|
+
throw wrapKintoneError(error, `Failed to download file: ${fileKey}`);
|
|
867
939
|
}
|
|
868
940
|
}
|
|
869
941
|
};
|
|
870
942
|
|
|
943
|
+
//#endregion
|
|
944
|
+
//#region src/lib/safePath.ts
|
|
945
|
+
/**
|
|
946
|
+
* Returns `true` if {@link targetPath} resolves to a location within
|
|
947
|
+
* {@link baseDir}. Follows symlinks via `realpathSync` for both the base
|
|
948
|
+
* directory and the target path when they exist on disk, falling back to
|
|
949
|
+
* textual `resolve` otherwise (e.g. in tests with virtual paths or when
|
|
950
|
+
* the target does not yet exist).
|
|
951
|
+
*
|
|
952
|
+
* {@link targetPath} may be either a relative path (resolved against
|
|
953
|
+
* {@link baseDir}) or an absolute path (used as-is by `path.resolve`).
|
|
954
|
+
* When callers have already resolved the path via `path.resolve(baseDir, x)`,
|
|
955
|
+
* passing the result as an absolute path is safe — `resolve(base, absPath)`
|
|
956
|
+
* returns `absPath` unchanged.
|
|
957
|
+
*
|
|
958
|
+
* **Limitation — symlinks**: If the target path does not exist on disk,
|
|
959
|
+
* symlink components within it cannot be resolved. The check falls back
|
|
960
|
+
* to a textual prefix comparison, which still catches `..` traversal but
|
|
961
|
+
* cannot detect symlink-based escapes for non-existent paths.
|
|
962
|
+
*
|
|
963
|
+
* **Limitation — TOCTOU**: This check is inherently subject to a
|
|
964
|
+
* time-of-check-to-time-of-use race: the filesystem may change between
|
|
965
|
+
* this call and the subsequent file operation. This is acceptable for a
|
|
966
|
+
* CLI tool where the user controls the local environment.
|
|
967
|
+
*
|
|
968
|
+
* **Note**: This function performs synchronous I/O (`realpathSync`).
|
|
969
|
+
*
|
|
970
|
+
* Callers decide how to handle the result.
|
|
971
|
+
*/
|
|
972
|
+
function isSafePath(targetPath, baseDir) {
|
|
973
|
+
if (targetPath.includes("\0") || baseDir.includes("\0")) return false;
|
|
974
|
+
let resolvedBase;
|
|
975
|
+
try {
|
|
976
|
+
resolvedBase = realpathSync(baseDir);
|
|
977
|
+
} catch {
|
|
978
|
+
resolvedBase = resolve(baseDir);
|
|
979
|
+
}
|
|
980
|
+
const textualTarget = resolve(resolvedBase, targetPath);
|
|
981
|
+
let resolvedTarget;
|
|
982
|
+
try {
|
|
983
|
+
resolvedTarget = realpathSync(textualTarget);
|
|
984
|
+
} catch {
|
|
985
|
+
resolvedTarget = textualTarget;
|
|
986
|
+
}
|
|
987
|
+
return resolvedTarget.startsWith(`${resolvedBase}/`) || resolvedTarget === resolvedBase;
|
|
988
|
+
}
|
|
989
|
+
|
|
871
990
|
//#endregion
|
|
872
991
|
//#region src/core/adapters/kintone/fileUploader.ts
|
|
873
992
|
var KintoneFileUploader = class {
|
|
874
|
-
constructor(client) {
|
|
993
|
+
constructor(client, baseDir) {
|
|
875
994
|
this.client = client;
|
|
995
|
+
this.baseDir = baseDir;
|
|
876
996
|
}
|
|
877
997
|
async upload(filePath) {
|
|
878
|
-
if (!filePath) throw new
|
|
998
|
+
if (!filePath) throw new ValidationError(ValidationErrorCode.InvalidInput, "filePath must not be empty");
|
|
999
|
+
const resolvedPath = resolve(this.baseDir, filePath);
|
|
1000
|
+
if (!isSafePath(resolvedPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${resolvedPath}" escapes base directory "${this.baseDir}"`);
|
|
879
1001
|
try {
|
|
880
|
-
return { fileKey: (await this.client.file.uploadFile({ file: { path:
|
|
1002
|
+
return { fileKey: (await this.client.file.uploadFile({ file: { path: resolvedPath } })).fileKey };
|
|
881
1003
|
} catch (error) {
|
|
882
|
-
|
|
883
|
-
if (error instanceof SystemError) throw error;
|
|
884
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, `Failed to upload file: ${filePath}`, error);
|
|
1004
|
+
throw wrapKintoneError(error, `Failed to upload file: ${filePath}`);
|
|
885
1005
|
}
|
|
886
1006
|
}
|
|
887
1007
|
};
|
|
@@ -962,10 +1082,6 @@ const DECORATION_TYPES$1 = new Set([
|
|
|
962
1082
|
"SPACER",
|
|
963
1083
|
"HR"
|
|
964
1084
|
]);
|
|
965
|
-
const KINTONE_REVISION_CONFLICT_CODE = "GAIA_CO02";
|
|
966
|
-
function isRevisionConflict(error) {
|
|
967
|
-
return error instanceof KintoneRestAPIError && error.code === KINTONE_REVISION_CONFLICT_CODE;
|
|
968
|
-
}
|
|
969
1085
|
/**
|
|
970
1086
|
* Tracks the latest known kintone form revision for optimistic concurrency control.
|
|
971
1087
|
*
|
|
@@ -978,10 +1094,13 @@ function isRevisionConflict(error) {
|
|
|
978
1094
|
var RevisionTracker = class {
|
|
979
1095
|
revision = void 0;
|
|
980
1096
|
track(revision) {
|
|
981
|
-
if (
|
|
1097
|
+
if (revision === "") throw new SystemError(SystemErrorCode.ExternalApiError, "Unexpected empty revision from kintone API");
|
|
1098
|
+
const revisionNum = Number(revision);
|
|
1099
|
+
if (!Number.isFinite(revisionNum)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric revision from kintone API: "${revision}"`);
|
|
1100
|
+
if (this.revision === void 0 || revisionNum > this.revision) this.revision = revisionNum;
|
|
982
1101
|
}
|
|
983
1102
|
get current() {
|
|
984
|
-
return this.revision;
|
|
1103
|
+
return this.revision !== void 0 ? String(this.revision) : void 0;
|
|
985
1104
|
}
|
|
986
1105
|
};
|
|
987
1106
|
function assertRecord(value, fieldPath) {
|
|
@@ -1253,7 +1372,7 @@ var KintoneFormConfigurator = class {
|
|
|
1253
1372
|
app: this.appId,
|
|
1254
1373
|
preview: true
|
|
1255
1374
|
});
|
|
1256
|
-
this.revisionTracker.track(revision);
|
|
1375
|
+
if (revision) this.revisionTracker.track(revision);
|
|
1257
1376
|
const fields = /* @__PURE__ */ new Map();
|
|
1258
1377
|
for (const [code, prop] of Object.entries(properties)) {
|
|
1259
1378
|
const kintoneProp = prop;
|
|
@@ -1264,9 +1383,7 @@ var KintoneFormConfigurator = class {
|
|
|
1264
1383
|
}
|
|
1265
1384
|
return fields;
|
|
1266
1385
|
} catch (error) {
|
|
1267
|
-
|
|
1268
|
-
if (error instanceof SystemError) throw error;
|
|
1269
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get form fields", error);
|
|
1386
|
+
throw wrapKintoneError(error, "Failed to get form fields");
|
|
1270
1387
|
}
|
|
1271
1388
|
}
|
|
1272
1389
|
async addFields(fields) {
|
|
@@ -1280,10 +1397,7 @@ var KintoneFormConfigurator = class {
|
|
|
1280
1397
|
});
|
|
1281
1398
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1282
1399
|
} catch (error) {
|
|
1283
|
-
|
|
1284
|
-
if (error instanceof SystemError) throw error;
|
|
1285
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1286
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to add form fields", error);
|
|
1400
|
+
throw wrapKintoneError(error, "Failed to add form fields");
|
|
1287
1401
|
}
|
|
1288
1402
|
}
|
|
1289
1403
|
async updateFields(fields) {
|
|
@@ -1297,10 +1411,7 @@ var KintoneFormConfigurator = class {
|
|
|
1297
1411
|
});
|
|
1298
1412
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1299
1413
|
} catch (error) {
|
|
1300
|
-
|
|
1301
|
-
if (error instanceof SystemError) throw error;
|
|
1302
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1303
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update form fields", error);
|
|
1414
|
+
throw wrapKintoneError(error, "Failed to update form fields");
|
|
1304
1415
|
}
|
|
1305
1416
|
}
|
|
1306
1417
|
async deleteFields(fieldCodes) {
|
|
@@ -1312,10 +1423,7 @@ var KintoneFormConfigurator = class {
|
|
|
1312
1423
|
});
|
|
1313
1424
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1314
1425
|
} catch (error) {
|
|
1315
|
-
|
|
1316
|
-
if (error instanceof SystemError) throw error;
|
|
1317
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1318
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to delete form fields", error);
|
|
1426
|
+
throw wrapKintoneError(error, "Failed to delete form fields");
|
|
1319
1427
|
}
|
|
1320
1428
|
}
|
|
1321
1429
|
async getLayout() {
|
|
@@ -1324,12 +1432,10 @@ var KintoneFormConfigurator = class {
|
|
|
1324
1432
|
app: this.appId,
|
|
1325
1433
|
preview: true
|
|
1326
1434
|
});
|
|
1327
|
-
this.revisionTracker.track(response.revision);
|
|
1435
|
+
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1328
1436
|
return response.layout.map(fromKintoneLayoutItem);
|
|
1329
1437
|
} catch (error) {
|
|
1330
|
-
|
|
1331
|
-
if (error instanceof SystemError) throw error;
|
|
1332
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get form layout", error);
|
|
1438
|
+
throw wrapKintoneError(error, "Failed to get form layout");
|
|
1333
1439
|
}
|
|
1334
1440
|
}
|
|
1335
1441
|
async updateLayout(layout) {
|
|
@@ -1342,10 +1448,7 @@ var KintoneFormConfigurator = class {
|
|
|
1342
1448
|
});
|
|
1343
1449
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1344
1450
|
} catch (error) {
|
|
1345
|
-
|
|
1346
|
-
if (error instanceof SystemError) throw error;
|
|
1347
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1348
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update form layout", error);
|
|
1451
|
+
throw wrapKintoneError(error, "Failed to update form layout");
|
|
1349
1452
|
}
|
|
1350
1453
|
}
|
|
1351
1454
|
};
|
|
@@ -1466,9 +1569,7 @@ var KintoneRecordManager = class {
|
|
|
1466
1569
|
};
|
|
1467
1570
|
});
|
|
1468
1571
|
} catch (error) {
|
|
1469
|
-
|
|
1470
|
-
if (error instanceof SystemError) throw error;
|
|
1471
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get records", error);
|
|
1572
|
+
throw wrapKintoneError(error, "Failed to get records");
|
|
1472
1573
|
}
|
|
1473
1574
|
}
|
|
1474
1575
|
async addRecords(records) {
|
|
@@ -1479,9 +1580,7 @@ var KintoneRecordManager = class {
|
|
|
1479
1580
|
records: records.map(toKintoneRecord)
|
|
1480
1581
|
});
|
|
1481
1582
|
} catch (error) {
|
|
1482
|
-
|
|
1483
|
-
if (error instanceof SystemError) throw error;
|
|
1484
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to add records", error);
|
|
1583
|
+
throw wrapKintoneError(error, "Failed to add records");
|
|
1485
1584
|
}
|
|
1486
1585
|
}
|
|
1487
1586
|
async updateRecords(records) {
|
|
@@ -1495,9 +1594,7 @@ var KintoneRecordManager = class {
|
|
|
1495
1594
|
}))
|
|
1496
1595
|
});
|
|
1497
1596
|
} catch (error) {
|
|
1498
|
-
|
|
1499
|
-
if (error instanceof SystemError) throw error;
|
|
1500
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update records", error);
|
|
1597
|
+
throw wrapKintoneError(error, "Failed to update records");
|
|
1501
1598
|
}
|
|
1502
1599
|
}
|
|
1503
1600
|
async deleteAllRecords() {
|
|
@@ -1514,9 +1611,7 @@ var KintoneRecordManager = class {
|
|
|
1514
1611
|
});
|
|
1515
1612
|
return { deletedCount: records.length };
|
|
1516
1613
|
} catch (error) {
|
|
1517
|
-
|
|
1518
|
-
if (error instanceof SystemError) throw error;
|
|
1519
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to delete all records", error);
|
|
1614
|
+
throw wrapKintoneError(error, "Failed to delete all records");
|
|
1520
1615
|
}
|
|
1521
1616
|
}
|
|
1522
1617
|
};
|
|
@@ -1530,10 +1625,15 @@ function createLocalFileCustomizationStorage(filePath) {
|
|
|
1530
1625
|
//#endregion
|
|
1531
1626
|
//#region src/core/adapters/local/fileWriter.ts
|
|
1532
1627
|
var LocalFileWriter = class {
|
|
1628
|
+
constructor(baseDir = process.cwd()) {
|
|
1629
|
+
this.baseDir = baseDir;
|
|
1630
|
+
}
|
|
1533
1631
|
async write(filePath, data) {
|
|
1632
|
+
const resolvedPath = resolve(this.baseDir, filePath);
|
|
1633
|
+
if (!isSafePath(resolvedPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${resolvedPath}" escapes base directory "${this.baseDir}"`);
|
|
1534
1634
|
try {
|
|
1535
|
-
await mkdir(dirname(
|
|
1536
|
-
await writeFile(
|
|
1635
|
+
await mkdir(dirname(resolvedPath), { recursive: true });
|
|
1636
|
+
await writeFile(resolvedPath, Buffer.from(new Uint8Array(data)));
|
|
1537
1637
|
} catch (error) {
|
|
1538
1638
|
throw new SystemError(SystemErrorCode.StorageError, `Failed to write file: ${filePath}`, error);
|
|
1539
1639
|
}
|
|
@@ -1562,11 +1662,7 @@ function buildKintoneAuth(auth) {
|
|
|
1562
1662
|
};
|
|
1563
1663
|
}
|
|
1564
1664
|
function createCliContainer(config) {
|
|
1565
|
-
const client =
|
|
1566
|
-
baseUrl: config.baseUrl,
|
|
1567
|
-
auth: buildKintoneAuth(config.auth),
|
|
1568
|
-
guestSpaceId: config.guestSpaceId
|
|
1569
|
-
});
|
|
1665
|
+
const client = config.client ?? createKintoneClient(config);
|
|
1570
1666
|
return {
|
|
1571
1667
|
formConfigurator: new KintoneFormConfigurator(client, config.appId),
|
|
1572
1668
|
schemaStorage: createLocalFileSchemaStorage(config.schemaFilePath),
|
|
@@ -1575,38 +1671,36 @@ function createCliContainer(config) {
|
|
|
1575
1671
|
}
|
|
1576
1672
|
function createSeedCliContainer(config) {
|
|
1577
1673
|
return {
|
|
1578
|
-
recordManager: new KintoneRecordManager(
|
|
1579
|
-
baseUrl: config.baseUrl,
|
|
1580
|
-
auth: buildKintoneAuth(config.auth),
|
|
1581
|
-
guestSpaceId: config.guestSpaceId
|
|
1582
|
-
}), config.appId),
|
|
1674
|
+
recordManager: new KintoneRecordManager(config.client ?? createKintoneClient(config), config.appId),
|
|
1583
1675
|
seedStorage: createLocalFileSeedStorage(config.seedFilePath)
|
|
1584
1676
|
};
|
|
1585
1677
|
}
|
|
1586
1678
|
function createCustomizationCliContainer(config) {
|
|
1587
|
-
const client =
|
|
1588
|
-
baseUrl: config.baseUrl,
|
|
1589
|
-
auth: buildKintoneAuth(config.auth),
|
|
1590
|
-
guestSpaceId: config.guestSpaceId
|
|
1591
|
-
});
|
|
1679
|
+
const client = config.client ?? createKintoneClient(config);
|
|
1592
1680
|
return {
|
|
1593
1681
|
customizationConfigurator: new KintoneCustomizationConfigurator(client, config.appId),
|
|
1594
1682
|
customizationStorage: createLocalFileCustomizationStorage(config.customizeFilePath),
|
|
1595
|
-
fileUploader: new KintoneFileUploader(client),
|
|
1683
|
+
fileUploader: new KintoneFileUploader(client, process.cwd()),
|
|
1596
1684
|
fileDownloader: new KintoneFileDownloader(client),
|
|
1597
|
-
fileWriter: new LocalFileWriter(),
|
|
1685
|
+
fileWriter: new LocalFileWriter(process.cwd()),
|
|
1598
1686
|
appDeployer: new KintoneAppDeployer(client, config.appId)
|
|
1599
1687
|
};
|
|
1600
1688
|
}
|
|
1601
1689
|
|
|
1602
1690
|
//#endregion
|
|
1603
|
-
//#region src/core/application/container/
|
|
1604
|
-
function
|
|
1605
|
-
|
|
1691
|
+
//#region src/core/application/container/kintoneClient.ts
|
|
1692
|
+
function createKintoneClient(config) {
|
|
1693
|
+
return new KintoneRestAPIClient({
|
|
1606
1694
|
baseUrl: config.baseUrl,
|
|
1607
1695
|
auth: buildKintoneAuth(config.auth),
|
|
1608
1696
|
guestSpaceId: config.guestSpaceId
|
|
1609
1697
|
});
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
//#endregion
|
|
1701
|
+
//#region src/core/application/container/actionCli.ts
|
|
1702
|
+
function createActionCliContainer(config) {
|
|
1703
|
+
const client = config.client ?? createKintoneClient(config);
|
|
1610
1704
|
return {
|
|
1611
1705
|
actionConfigurator: new KintoneActionConfigurator(client, config.appId),
|
|
1612
1706
|
actionStorage: createLocalFileActionStorage(config.actionFilePath),
|
|
@@ -2543,15 +2637,25 @@ const ActionConfigSerializer = { serialize: (config) => {
|
|
|
2543
2637
|
} };
|
|
2544
2638
|
|
|
2545
2639
|
//#endregion
|
|
2546
|
-
//#region src/core/application/
|
|
2547
|
-
async function
|
|
2548
|
-
const
|
|
2640
|
+
//#region src/core/application/captureFromConfigBase.ts
|
|
2641
|
+
async function captureFromConfig(config) {
|
|
2642
|
+
const remote = await config.fetchRemote();
|
|
2549
2643
|
return {
|
|
2550
|
-
configText:
|
|
2551
|
-
hasExistingConfig: (await
|
|
2644
|
+
configText: config.serialize(remote),
|
|
2645
|
+
hasExistingConfig: (await config.getStorage()).exists
|
|
2552
2646
|
};
|
|
2553
2647
|
}
|
|
2554
2648
|
|
|
2649
|
+
//#endregion
|
|
2650
|
+
//#region src/core/application/action/captureAction.ts
|
|
2651
|
+
async function captureAction({ container }) {
|
|
2652
|
+
return captureFromConfig({
|
|
2653
|
+
fetchRemote: () => container.actionConfigurator.getActions(),
|
|
2654
|
+
serialize: ({ actions }) => ActionConfigSerializer.serialize({ actions }),
|
|
2655
|
+
getStorage: () => container.actionStorage.get()
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2555
2659
|
//#endregion
|
|
2556
2660
|
//#region src/core/application/action/saveAction.ts
|
|
2557
2661
|
async function saveAction({ container, input }) {
|
|
@@ -2883,13 +2987,17 @@ function parseAdminNotesConfigText(rawText) {
|
|
|
2883
2987
|
//#endregion
|
|
2884
2988
|
//#region src/core/application/adminNotes/applyAdminNotes.ts
|
|
2885
2989
|
async function applyAdminNotes({ container }) {
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2990
|
+
await applyFromConfig({
|
|
2991
|
+
getStorage: () => container.adminNotesStorage.get(),
|
|
2992
|
+
parseConfig: parseAdminNotesConfigText,
|
|
2993
|
+
fetchRemote: () => container.adminNotesConfigurator.getAdminNotes(),
|
|
2994
|
+
update: async (config, current) => {
|
|
2995
|
+
await container.adminNotesConfigurator.updateAdminNotes({
|
|
2996
|
+
config,
|
|
2997
|
+
revision: current.revision
|
|
2998
|
+
});
|
|
2999
|
+
},
|
|
3000
|
+
notFoundMessage: "Admin notes config file not found"
|
|
2893
3001
|
});
|
|
2894
3002
|
}
|
|
2895
3003
|
|
|
@@ -2914,9 +3022,7 @@ var KintoneAdminNotesConfigurator = class {
|
|
|
2914
3022
|
revision: response.revision
|
|
2915
3023
|
};
|
|
2916
3024
|
} catch (error) {
|
|
2917
|
-
|
|
2918
|
-
if (error instanceof SystemError) throw error;
|
|
2919
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get admin notes", error);
|
|
3025
|
+
throw wrapKintoneError(error, "Failed to get admin notes");
|
|
2920
3026
|
}
|
|
2921
3027
|
}
|
|
2922
3028
|
async updateAdminNotes(params) {
|
|
@@ -2929,9 +3035,7 @@ var KintoneAdminNotesConfigurator = class {
|
|
|
2929
3035
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
2930
3036
|
return { revision: (await this.client.app.updateAdminNotes(requestParams)).revision };
|
|
2931
3037
|
} catch (error) {
|
|
2932
|
-
|
|
2933
|
-
if (error instanceof SystemError) throw error;
|
|
2934
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update admin notes", error);
|
|
3038
|
+
throw wrapKintoneError(error, "Failed to update admin notes");
|
|
2935
3039
|
}
|
|
2936
3040
|
}
|
|
2937
3041
|
};
|
|
@@ -2945,11 +3049,7 @@ function createLocalFileAdminNotesStorage(filePath) {
|
|
|
2945
3049
|
//#endregion
|
|
2946
3050
|
//#region src/core/application/container/adminNotesCli.ts
|
|
2947
3051
|
function createAdminNotesCliContainer(config) {
|
|
2948
|
-
const client =
|
|
2949
|
-
baseUrl: config.baseUrl,
|
|
2950
|
-
auth: buildKintoneAuth(config.auth),
|
|
2951
|
-
guestSpaceId: config.guestSpaceId
|
|
2952
|
-
});
|
|
3052
|
+
const client = config.client ?? createKintoneClient(config);
|
|
2953
3053
|
return {
|
|
2954
3054
|
adminNotesConfigurator: new KintoneAdminNotesConfigurator(client, config.appId),
|
|
2955
3055
|
adminNotesStorage: createLocalFileAdminNotesStorage(config.adminNotesFilePath),
|
|
@@ -3037,11 +3137,11 @@ const AdminNotesConfigSerializer = { serialize: (config) => {
|
|
|
3037
3137
|
//#endregion
|
|
3038
3138
|
//#region src/core/application/adminNotes/captureAdminNotes.ts
|
|
3039
3139
|
async function captureAdminNotes({ container }) {
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
};
|
|
3140
|
+
return captureFromConfig({
|
|
3141
|
+
fetchRemote: () => container.adminNotesConfigurator.getAdminNotes(),
|
|
3142
|
+
serialize: ({ config }) => AdminNotesConfigSerializer.serialize(config),
|
|
3143
|
+
getStorage: () => container.adminNotesStorage.get()
|
|
3144
|
+
});
|
|
3045
3145
|
}
|
|
3046
3146
|
|
|
3047
3147
|
//#endregion
|
|
@@ -3207,13 +3307,17 @@ function parseAppPermissionConfigText(rawText) {
|
|
|
3207
3307
|
//#endregion
|
|
3208
3308
|
//#region src/core/application/appPermission/applyAppPermission.ts
|
|
3209
3309
|
async function applyAppPermission({ container }) {
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3310
|
+
await applyFromConfig({
|
|
3311
|
+
getStorage: () => container.appPermissionStorage.get(),
|
|
3312
|
+
parseConfig: parseAppPermissionConfigText,
|
|
3313
|
+
fetchRemote: () => container.appPermissionConfigurator.getAppPermissions(),
|
|
3314
|
+
update: async (config, current) => {
|
|
3315
|
+
await container.appPermissionConfigurator.updateAppPermissions({
|
|
3316
|
+
rights: config.rights,
|
|
3317
|
+
revision: current.revision
|
|
3318
|
+
});
|
|
3319
|
+
},
|
|
3320
|
+
notFoundMessage: "App permission config file not found"
|
|
3217
3321
|
});
|
|
3218
3322
|
}
|
|
3219
3323
|
|
|
@@ -3281,9 +3385,7 @@ var KintoneAppPermissionConfigurator = class {
|
|
|
3281
3385
|
revision: response.revision
|
|
3282
3386
|
};
|
|
3283
3387
|
} catch (error) {
|
|
3284
|
-
|
|
3285
|
-
if (error instanceof SystemError) throw error;
|
|
3286
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get app ACL", error);
|
|
3388
|
+
throw wrapKintoneError(error, "Failed to get app ACL");
|
|
3287
3389
|
}
|
|
3288
3390
|
}
|
|
3289
3391
|
async updateAppPermissions(params) {
|
|
@@ -3295,9 +3397,7 @@ var KintoneAppPermissionConfigurator = class {
|
|
|
3295
3397
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
3296
3398
|
return { revision: (await this.client.app.updateAppAcl(requestParams)).revision };
|
|
3297
3399
|
} catch (error) {
|
|
3298
|
-
|
|
3299
|
-
if (error instanceof SystemError) throw error;
|
|
3300
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update app ACL", error);
|
|
3400
|
+
throw wrapKintoneError(error, "Failed to update app ACL");
|
|
3301
3401
|
}
|
|
3302
3402
|
}
|
|
3303
3403
|
};
|
|
@@ -3311,11 +3411,7 @@ function createLocalFileAppPermissionStorage(filePath) {
|
|
|
3311
3411
|
//#endregion
|
|
3312
3412
|
//#region src/core/application/container/appPermissionCli.ts
|
|
3313
3413
|
function createAppPermissionCliContainer(config) {
|
|
3314
|
-
const client =
|
|
3315
|
-
baseUrl: config.baseUrl,
|
|
3316
|
-
auth: buildKintoneAuth(config.auth),
|
|
3317
|
-
guestSpaceId: config.guestSpaceId
|
|
3318
|
-
});
|
|
3414
|
+
const client = config.client ?? createKintoneClient(config);
|
|
3319
3415
|
return {
|
|
3320
3416
|
appPermissionConfigurator: new KintoneAppPermissionConfigurator(client, config.appId),
|
|
3321
3417
|
appPermissionStorage: createLocalFileAppPermissionStorage(config.appAclFilePath),
|
|
@@ -3416,11 +3512,11 @@ const AppPermissionConfigSerializer = { serialize: (config) => {
|
|
|
3416
3512
|
//#endregion
|
|
3417
3513
|
//#region src/core/application/appPermission/captureAppPermission.ts
|
|
3418
3514
|
async function captureAppPermission({ container }) {
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
};
|
|
3515
|
+
return captureFromConfig({
|
|
3516
|
+
fetchRemote: () => container.appPermissionConfigurator.getAppPermissions(),
|
|
3517
|
+
serialize: ({ rights }) => AppPermissionConfigSerializer.serialize({ rights }),
|
|
3518
|
+
getStorage: () => container.appPermissionStorage.get()
|
|
3519
|
+
});
|
|
3424
3520
|
}
|
|
3425
3521
|
|
|
3426
3522
|
//#endregion
|
|
@@ -3856,8 +3952,8 @@ function planResources(resources, platformDir, resourceType, relativeBaseDir) {
|
|
|
3856
3952
|
filesToDownload
|
|
3857
3953
|
};
|
|
3858
3954
|
}
|
|
3859
|
-
function planPlatform(remotePlatform, platformName,
|
|
3860
|
-
const platformDir = join(
|
|
3955
|
+
function planPlatform(remotePlatform, platformName, basePath, filePrefix) {
|
|
3956
|
+
const platformDir = join(basePath, filePrefix, platformName);
|
|
3861
3957
|
const platformPrefix = platformName;
|
|
3862
3958
|
const jsPlan = planResources(remotePlatform.js, platformDir, "js", platformPrefix);
|
|
3863
3959
|
const cssPlan = planResources(remotePlatform.css, platformDir, "css", platformPrefix);
|
|
@@ -3885,18 +3981,18 @@ async function downloadFiles(files, container) {
|
|
|
3885
3981
|
await container.fileWriter.write(file.absolutePath, data);
|
|
3886
3982
|
}));
|
|
3887
3983
|
}
|
|
3888
|
-
async function captureCustomization(
|
|
3889
|
-
const existing = await
|
|
3890
|
-
const { scope, desktop, mobile } = await
|
|
3891
|
-
const desktopPlan = planPlatform(desktop, "desktop",
|
|
3892
|
-
const mobilePlan = planPlatform(mobile, "mobile",
|
|
3984
|
+
async function captureCustomization({ container, input }) {
|
|
3985
|
+
const existing = await container.customizationStorage.get();
|
|
3986
|
+
const { scope, desktop, mobile } = await container.customizationConfigurator.getCustomization();
|
|
3987
|
+
const desktopPlan = planPlatform(desktop, "desktop", input.basePath, input.filePrefix);
|
|
3988
|
+
const mobilePlan = planPlatform(mobile, "mobile", input.basePath, input.filePrefix);
|
|
3893
3989
|
const config = {
|
|
3894
3990
|
scope,
|
|
3895
3991
|
desktop: desktopPlan.platform,
|
|
3896
3992
|
mobile: mobilePlan.platform
|
|
3897
3993
|
};
|
|
3898
3994
|
const configText = CustomizationConfigSerializer.serialize(config);
|
|
3899
|
-
await downloadFiles([...desktopPlan.filesToDownload, ...mobilePlan.filesToDownload],
|
|
3995
|
+
await downloadFiles([...desktopPlan.filesToDownload, ...mobilePlan.filesToDownload], container);
|
|
3900
3996
|
return {
|
|
3901
3997
|
configText,
|
|
3902
3998
|
hasExistingConfig: existing.exists,
|
|
@@ -4194,9 +4290,7 @@ var KintoneFieldPermissionConfigurator = class {
|
|
|
4194
4290
|
revision: response.revision
|
|
4195
4291
|
};
|
|
4196
4292
|
} catch (error) {
|
|
4197
|
-
|
|
4198
|
-
if (error instanceof SystemError) throw error;
|
|
4199
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get field ACL", error);
|
|
4293
|
+
throw wrapKintoneError(error, "Failed to get field ACL");
|
|
4200
4294
|
}
|
|
4201
4295
|
}
|
|
4202
4296
|
async updateFieldPermissions(params) {
|
|
@@ -4208,9 +4302,7 @@ var KintoneFieldPermissionConfigurator = class {
|
|
|
4208
4302
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4209
4303
|
return { revision: (await this.client.app.updateFieldAcl(requestParams)).revision };
|
|
4210
4304
|
} catch (error) {
|
|
4211
|
-
|
|
4212
|
-
if (error instanceof SystemError) throw error;
|
|
4213
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update field ACL", error);
|
|
4305
|
+
throw wrapKintoneError(error, "Failed to update field ACL");
|
|
4214
4306
|
}
|
|
4215
4307
|
}
|
|
4216
4308
|
};
|
|
@@ -4224,11 +4316,7 @@ function createLocalFileFieldPermissionStorage(filePath) {
|
|
|
4224
4316
|
//#endregion
|
|
4225
4317
|
//#region src/core/application/container/fieldPermissionCli.ts
|
|
4226
4318
|
function createFieldPermissionCliContainer(config) {
|
|
4227
|
-
const client =
|
|
4228
|
-
baseUrl: config.baseUrl,
|
|
4229
|
-
auth: buildKintoneAuth(config.auth),
|
|
4230
|
-
guestSpaceId: config.guestSpaceId
|
|
4231
|
-
});
|
|
4319
|
+
const client = config.client ?? createKintoneClient(config);
|
|
4232
4320
|
return {
|
|
4233
4321
|
fieldPermissionConfigurator: new KintoneFieldPermissionConfigurator(client, config.appId),
|
|
4234
4322
|
fieldPermissionStorage: createLocalFileFieldPermissionStorage(config.fieldAclFilePath),
|
|
@@ -4303,13 +4391,17 @@ function parseFieldPermissionConfigText(rawText) {
|
|
|
4303
4391
|
//#endregion
|
|
4304
4392
|
//#region src/core/application/fieldPermission/applyFieldPermission.ts
|
|
4305
4393
|
async function applyFieldPermission({ container }) {
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4394
|
+
await applyFromConfig({
|
|
4395
|
+
getStorage: () => container.fieldPermissionStorage.get(),
|
|
4396
|
+
parseConfig: parseFieldPermissionConfigText,
|
|
4397
|
+
fetchRemote: () => container.fieldPermissionConfigurator.getFieldPermissions(),
|
|
4398
|
+
update: async (config, current) => {
|
|
4399
|
+
await container.fieldPermissionConfigurator.updateFieldPermissions({
|
|
4400
|
+
rights: config.rights,
|
|
4401
|
+
revision: current.revision
|
|
4402
|
+
});
|
|
4403
|
+
},
|
|
4404
|
+
notFoundMessage: "Field permission config file not found"
|
|
4313
4405
|
});
|
|
4314
4406
|
}
|
|
4315
4407
|
|
|
@@ -4404,11 +4496,11 @@ const FieldPermissionConfigSerializer = { serialize: (config) => {
|
|
|
4404
4496
|
//#endregion
|
|
4405
4497
|
//#region src/core/application/fieldPermission/captureFieldPermission.ts
|
|
4406
4498
|
async function captureFieldPermission({ container }) {
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
};
|
|
4499
|
+
return captureFromConfig({
|
|
4500
|
+
fetchRemote: () => container.fieldPermissionConfigurator.getFieldPermissions(),
|
|
4501
|
+
serialize: ({ rights }) => FieldPermissionConfigSerializer.serialize({ rights }),
|
|
4502
|
+
getStorage: () => container.fieldPermissionStorage.get()
|
|
4503
|
+
});
|
|
4412
4504
|
}
|
|
4413
4505
|
|
|
4414
4506
|
//#endregion
|
|
@@ -4539,6 +4631,14 @@ var field_acl_default = define({
|
|
|
4539
4631
|
run: () => {}
|
|
4540
4632
|
});
|
|
4541
4633
|
|
|
4634
|
+
//#endregion
|
|
4635
|
+
//#region src/core/adapters/kintone/parseKintoneIntegerField.ts
|
|
4636
|
+
function parseKintoneIntegerField(raw, fieldName) {
|
|
4637
|
+
const n = Number(raw);
|
|
4638
|
+
if (!Number.isFinite(n) || !Number.isInteger(n)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-integer ${fieldName} from kintone API: ${raw}`);
|
|
4639
|
+
return n;
|
|
4640
|
+
}
|
|
4641
|
+
|
|
4542
4642
|
//#endregion
|
|
4543
4643
|
//#region src/core/adapters/kintone/generalSettingsConfigurator.ts
|
|
4544
4644
|
const VALID_THEMES$1 = new Set([
|
|
@@ -4583,8 +4683,8 @@ function fromKintoneTitleField(raw) {
|
|
|
4583
4683
|
function fromKintoneNumberPrecision(raw) {
|
|
4584
4684
|
if (!VALID_ROUNDING_MODES$1.has(raw.roundingMode)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected roundingMode from kintone API: ${raw.roundingMode}`);
|
|
4585
4685
|
return {
|
|
4586
|
-
digits:
|
|
4587
|
-
decimalPlaces:
|
|
4686
|
+
digits: parseKintoneIntegerField(raw.digits, "digits"),
|
|
4687
|
+
decimalPlaces: parseKintoneIntegerField(raw.decimalPlaces, "decimalPlaces"),
|
|
4588
4688
|
roundingMode: raw.roundingMode
|
|
4589
4689
|
};
|
|
4590
4690
|
}
|
|
@@ -4602,7 +4702,7 @@ function fromKintoneSettings(raw) {
|
|
|
4602
4702
|
...raw.enableDuplicateRecord !== void 0 ? { enableDuplicateRecord: raw.enableDuplicateRecord } : {},
|
|
4603
4703
|
...raw.enableInlineRecordEditing !== void 0 ? { enableInlineRecordEditing: raw.enableInlineRecordEditing } : {},
|
|
4604
4704
|
...raw.numberPrecision !== void 0 ? { numberPrecision: fromKintoneNumberPrecision(raw.numberPrecision) } : {},
|
|
4605
|
-
...raw.firstMonthOfFiscalYear !== void 0 ? { firstMonthOfFiscalYear:
|
|
4705
|
+
...raw.firstMonthOfFiscalYear !== void 0 ? { firstMonthOfFiscalYear: parseKintoneIntegerField(raw.firstMonthOfFiscalYear, "firstMonthOfFiscalYear") } : {}
|
|
4606
4706
|
};
|
|
4607
4707
|
}
|
|
4608
4708
|
function toKintoneIcon(icon) {
|
|
@@ -4655,9 +4755,7 @@ var KintoneGeneralSettingsConfigurator = class {
|
|
|
4655
4755
|
revision: raw.revision ?? "-1"
|
|
4656
4756
|
};
|
|
4657
4757
|
} catch (error) {
|
|
4658
|
-
|
|
4659
|
-
if (error instanceof SystemError) throw error;
|
|
4660
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get general settings", error);
|
|
4758
|
+
throw wrapKintoneError(error, "Failed to get general settings");
|
|
4661
4759
|
}
|
|
4662
4760
|
}
|
|
4663
4761
|
async updateGeneralSettings(params) {
|
|
@@ -4669,9 +4767,7 @@ var KintoneGeneralSettingsConfigurator = class {
|
|
|
4669
4767
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4670
4768
|
return { revision: (await this.client.app.updateAppSettings(requestParams)).revision };
|
|
4671
4769
|
} catch (error) {
|
|
4672
|
-
|
|
4673
|
-
if (error instanceof SystemError) throw error;
|
|
4674
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update general settings", error);
|
|
4770
|
+
throw wrapKintoneError(error, "Failed to update general settings");
|
|
4675
4771
|
}
|
|
4676
4772
|
}
|
|
4677
4773
|
};
|
|
@@ -4685,11 +4781,7 @@ function createLocalFileGeneralSettingsStorage(filePath) {
|
|
|
4685
4781
|
//#endregion
|
|
4686
4782
|
//#region src/core/application/container/generalSettingsCli.ts
|
|
4687
4783
|
function createGeneralSettingsCliContainer(config) {
|
|
4688
|
-
const client =
|
|
4689
|
-
baseUrl: config.baseUrl,
|
|
4690
|
-
auth: buildKintoneAuth(config.auth),
|
|
4691
|
-
guestSpaceId: config.guestSpaceId
|
|
4692
|
-
});
|
|
4784
|
+
const client = config.client ?? createKintoneClient(config);
|
|
4693
4785
|
return {
|
|
4694
4786
|
generalSettingsConfigurator: new KintoneGeneralSettingsConfigurator(client, config.appId),
|
|
4695
4787
|
generalSettingsStorage: createLocalFileGeneralSettingsStorage(config.settingsFilePath),
|
|
@@ -4750,8 +4842,7 @@ function fromKintonePerRecordNotification(raw) {
|
|
|
4750
4842
|
};
|
|
4751
4843
|
}
|
|
4752
4844
|
function fromKintoneReminderNotification(raw) {
|
|
4753
|
-
const daysLater =
|
|
4754
|
-
if (!Number.isFinite(daysLater)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric daysLater from kintone API: ${raw.timing.daysLater}`);
|
|
4845
|
+
const daysLater = parseKintoneIntegerField(raw.timing.daysLater, "daysLater");
|
|
4755
4846
|
const result = {
|
|
4756
4847
|
code: raw.timing.code,
|
|
4757
4848
|
daysLater,
|
|
@@ -4760,8 +4851,7 @@ function fromKintoneReminderNotification(raw) {
|
|
|
4760
4851
|
targets: raw.targets.map(fromKintoneTarget)
|
|
4761
4852
|
};
|
|
4762
4853
|
if ("hoursLater" in raw.timing) {
|
|
4763
|
-
const hoursLater =
|
|
4764
|
-
if (!Number.isFinite(hoursLater)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric hoursLater from kintone API: ${raw.timing.hoursLater}`);
|
|
4854
|
+
const hoursLater = parseKintoneIntegerField(raw.timing.hoursLater, "hoursLater");
|
|
4765
4855
|
return {
|
|
4766
4856
|
...result,
|
|
4767
4857
|
hoursLater
|
|
@@ -4836,9 +4926,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4836
4926
|
revision: response.revision
|
|
4837
4927
|
};
|
|
4838
4928
|
} catch (error) {
|
|
4839
|
-
|
|
4840
|
-
if (error instanceof SystemError) throw error;
|
|
4841
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get general notifications", error);
|
|
4929
|
+
throw wrapKintoneError(error, "Failed to get general notifications");
|
|
4842
4930
|
}
|
|
4843
4931
|
}
|
|
4844
4932
|
async updateGeneralNotifications(params) {
|
|
@@ -4851,9 +4939,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4851
4939
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4852
4940
|
return { revision: (await this.client.app.updateGeneralNotifications(requestParams)).revision };
|
|
4853
4941
|
} catch (error) {
|
|
4854
|
-
|
|
4855
|
-
if (error instanceof SystemError) throw error;
|
|
4856
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update general notifications", error);
|
|
4942
|
+
throw wrapKintoneError(error, "Failed to update general notifications");
|
|
4857
4943
|
}
|
|
4858
4944
|
}
|
|
4859
4945
|
async getPerRecordNotifications() {
|
|
@@ -4867,9 +4953,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4867
4953
|
revision: response.revision
|
|
4868
4954
|
};
|
|
4869
4955
|
} catch (error) {
|
|
4870
|
-
|
|
4871
|
-
if (error instanceof SystemError) throw error;
|
|
4872
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get per-record notifications", error);
|
|
4956
|
+
throw wrapKintoneError(error, "Failed to get per-record notifications");
|
|
4873
4957
|
}
|
|
4874
4958
|
}
|
|
4875
4959
|
async updatePerRecordNotifications(params) {
|
|
@@ -4881,9 +4965,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4881
4965
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4882
4966
|
return { revision: (await this.client.app.updatePerRecordNotifications(requestParams)).revision };
|
|
4883
4967
|
} catch (error) {
|
|
4884
|
-
|
|
4885
|
-
if (error instanceof SystemError) throw error;
|
|
4886
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update per-record notifications", error);
|
|
4968
|
+
throw wrapKintoneError(error, "Failed to update per-record notifications");
|
|
4887
4969
|
}
|
|
4888
4970
|
}
|
|
4889
4971
|
async getReminderNotifications() {
|
|
@@ -4899,9 +4981,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4899
4981
|
revision: response.revision
|
|
4900
4982
|
};
|
|
4901
4983
|
} catch (error) {
|
|
4902
|
-
|
|
4903
|
-
if (error instanceof SystemError) throw error;
|
|
4904
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get reminder notifications", error);
|
|
4984
|
+
throw wrapKintoneError(error, "Failed to get reminder notifications");
|
|
4905
4985
|
}
|
|
4906
4986
|
}
|
|
4907
4987
|
async updateReminderNotifications(params) {
|
|
@@ -4914,9 +4994,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4914
4994
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4915
4995
|
return { revision: (await this.client.app.updateReminderNotifications(requestParams)).revision };
|
|
4916
4996
|
} catch (error) {
|
|
4917
|
-
|
|
4918
|
-
if (error instanceof SystemError) throw error;
|
|
4919
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update reminder notifications", error);
|
|
4997
|
+
throw wrapKintoneError(error, "Failed to update reminder notifications");
|
|
4920
4998
|
}
|
|
4921
4999
|
}
|
|
4922
5000
|
};
|
|
@@ -4930,11 +5008,7 @@ function createLocalFileNotificationStorage(filePath) {
|
|
|
4930
5008
|
//#endregion
|
|
4931
5009
|
//#region src/core/application/container/notificationCli.ts
|
|
4932
5010
|
function createNotificationCliContainer(config) {
|
|
4933
|
-
const client =
|
|
4934
|
-
baseUrl: config.baseUrl,
|
|
4935
|
-
auth: buildKintoneAuth(config.auth),
|
|
4936
|
-
guestSpaceId: config.guestSpaceId
|
|
4937
|
-
});
|
|
5011
|
+
const client = config.client ?? createKintoneClient(config);
|
|
4938
5012
|
return {
|
|
4939
5013
|
notificationConfigurator: new KintoneNotificationConfigurator(client, config.appId),
|
|
4940
5014
|
notificationStorage: createLocalFileNotificationStorage(config.notificationFilePath),
|
|
@@ -4964,22 +5038,18 @@ var KintonePluginConfigurator = class {
|
|
|
4964
5038
|
revision: response.revision
|
|
4965
5039
|
};
|
|
4966
5040
|
} catch (error) {
|
|
4967
|
-
|
|
4968
|
-
if (error instanceof SystemError) throw error;
|
|
4969
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get plugins", error);
|
|
5041
|
+
throw wrapKintoneError(error, "Failed to get plugins");
|
|
4970
5042
|
}
|
|
4971
5043
|
}
|
|
4972
5044
|
async addPlugins(params) {
|
|
4973
5045
|
try {
|
|
4974
5046
|
return { revision: (await this.client.app.addPlugins({
|
|
4975
5047
|
app: this.appId,
|
|
4976
|
-
ids: params.ids,
|
|
5048
|
+
ids: [...params.ids],
|
|
4977
5049
|
revision: params.revision
|
|
4978
5050
|
})).revision };
|
|
4979
5051
|
} catch (error) {
|
|
4980
|
-
|
|
4981
|
-
if (error instanceof SystemError) throw error;
|
|
4982
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to add plugins", error);
|
|
5052
|
+
throw wrapKintoneError(error, "Failed to add plugins");
|
|
4983
5053
|
}
|
|
4984
5054
|
}
|
|
4985
5055
|
};
|
|
@@ -4993,11 +5063,7 @@ function createLocalFilePluginStorage(filePath) {
|
|
|
4993
5063
|
//#endregion
|
|
4994
5064
|
//#region src/core/application/container/pluginCli.ts
|
|
4995
5065
|
function createPluginCliContainer(config) {
|
|
4996
|
-
const client =
|
|
4997
|
-
baseUrl: config.baseUrl,
|
|
4998
|
-
auth: buildKintoneAuth(config.auth),
|
|
4999
|
-
guestSpaceId: config.guestSpaceId
|
|
5000
|
-
});
|
|
5066
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5001
5067
|
return {
|
|
5002
5068
|
pluginConfigurator: new KintonePluginConfigurator(client, config.appId),
|
|
5003
5069
|
pluginStorage: createLocalFilePluginStorage(config.pluginFilePath),
|
|
@@ -5116,9 +5182,7 @@ var KintoneProcessManagementConfigurator = class {
|
|
|
5116
5182
|
revision: response.revision
|
|
5117
5183
|
};
|
|
5118
5184
|
} catch (error) {
|
|
5119
|
-
|
|
5120
|
-
if (error instanceof SystemError) throw error;
|
|
5121
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get process management settings", error);
|
|
5185
|
+
throw wrapKintoneError(error, "Failed to get process management settings");
|
|
5122
5186
|
}
|
|
5123
5187
|
}
|
|
5124
5188
|
async updateProcessManagement(params) {
|
|
@@ -5134,9 +5198,7 @@ var KintoneProcessManagementConfigurator = class {
|
|
|
5134
5198
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5135
5199
|
return { revision: (await this.client.app.updateProcessManagement(requestParams)).revision };
|
|
5136
5200
|
} catch (error) {
|
|
5137
|
-
|
|
5138
|
-
if (error instanceof SystemError) throw error;
|
|
5139
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update process management settings", error);
|
|
5201
|
+
throw wrapKintoneError(error, "Failed to update process management settings");
|
|
5140
5202
|
}
|
|
5141
5203
|
}
|
|
5142
5204
|
};
|
|
@@ -5150,11 +5212,7 @@ function createLocalFileProcessManagementStorage(filePath) {
|
|
|
5150
5212
|
//#endregion
|
|
5151
5213
|
//#region src/core/application/container/processManagementCli.ts
|
|
5152
5214
|
function createProcessManagementCliContainer(config) {
|
|
5153
|
-
const client =
|
|
5154
|
-
baseUrl: config.baseUrl,
|
|
5155
|
-
auth: buildKintoneAuth(config.auth),
|
|
5156
|
-
guestSpaceId: config.guestSpaceId
|
|
5157
|
-
});
|
|
5215
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5158
5216
|
return {
|
|
5159
5217
|
processManagementConfigurator: new KintoneProcessManagementConfigurator(client, config.appId),
|
|
5160
5218
|
processManagementStorage: createLocalFileProcessManagementStorage(config.processFilePath),
|
|
@@ -5223,9 +5281,7 @@ var KintoneRecordPermissionConfigurator = class {
|
|
|
5223
5281
|
revision: response.revision
|
|
5224
5282
|
};
|
|
5225
5283
|
} catch (error) {
|
|
5226
|
-
|
|
5227
|
-
if (error instanceof SystemError) throw error;
|
|
5228
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get record ACL", error);
|
|
5284
|
+
throw wrapKintoneError(error, "Failed to get record ACL");
|
|
5229
5285
|
}
|
|
5230
5286
|
}
|
|
5231
5287
|
async updateRecordPermissions(params) {
|
|
@@ -5237,9 +5293,7 @@ var KintoneRecordPermissionConfigurator = class {
|
|
|
5237
5293
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5238
5294
|
return { revision: (await this.client.app.updateRecordAcl(requestParams)).revision };
|
|
5239
5295
|
} catch (error) {
|
|
5240
|
-
|
|
5241
|
-
if (error instanceof SystemError) throw error;
|
|
5242
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update record ACL", error);
|
|
5296
|
+
throw wrapKintoneError(error, "Failed to update record ACL");
|
|
5243
5297
|
}
|
|
5244
5298
|
}
|
|
5245
5299
|
};
|
|
@@ -5253,11 +5307,7 @@ function createLocalFileRecordPermissionStorage(filePath) {
|
|
|
5253
5307
|
//#endregion
|
|
5254
5308
|
//#region src/core/application/container/recordPermissionCli.ts
|
|
5255
5309
|
function createRecordPermissionCliContainer(config) {
|
|
5256
|
-
const client =
|
|
5257
|
-
baseUrl: config.baseUrl,
|
|
5258
|
-
auth: buildKintoneAuth(config.auth),
|
|
5259
|
-
guestSpaceId: config.guestSpaceId
|
|
5260
|
-
});
|
|
5310
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5261
5311
|
return {
|
|
5262
5312
|
recordPermissionConfigurator: new KintoneRecordPermissionConfigurator(client, config.appId),
|
|
5263
5313
|
recordPermissionStorage: createLocalFileRecordPermissionStorage(config.recordAclFilePath),
|
|
@@ -5516,9 +5566,7 @@ var KintoneReportConfigurator = class {
|
|
|
5516
5566
|
revision: response.revision
|
|
5517
5567
|
};
|
|
5518
5568
|
} catch (error) {
|
|
5519
|
-
|
|
5520
|
-
if (error instanceof SystemError) throw error;
|
|
5521
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get reports", error);
|
|
5569
|
+
throw wrapKintoneError(error, "Failed to get reports");
|
|
5522
5570
|
}
|
|
5523
5571
|
}
|
|
5524
5572
|
async updateReports(params) {
|
|
@@ -5532,9 +5580,7 @@ var KintoneReportConfigurator = class {
|
|
|
5532
5580
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5533
5581
|
return { revision: (await this.client.app.updateReports(requestParams)).revision };
|
|
5534
5582
|
} catch (error) {
|
|
5535
|
-
|
|
5536
|
-
if (error instanceof SystemError) throw error;
|
|
5537
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update reports", error);
|
|
5583
|
+
throw wrapKintoneError(error, "Failed to update reports");
|
|
5538
5584
|
}
|
|
5539
5585
|
}
|
|
5540
5586
|
};
|
|
@@ -5548,11 +5594,7 @@ function createLocalFileReportStorage(filePath) {
|
|
|
5548
5594
|
//#endregion
|
|
5549
5595
|
//#region src/core/application/container/reportCli.ts
|
|
5550
5596
|
function createReportCliContainer(config) {
|
|
5551
|
-
const client =
|
|
5552
|
-
baseUrl: config.baseUrl,
|
|
5553
|
-
auth: buildKintoneAuth(config.auth),
|
|
5554
|
-
guestSpaceId: config.guestSpaceId
|
|
5555
|
-
});
|
|
5597
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5556
5598
|
return {
|
|
5557
5599
|
reportConfigurator: new KintoneReportConfigurator(client, config.appId),
|
|
5558
5600
|
reportStorage: createLocalFileReportStorage(config.reportFilePath),
|
|
@@ -5588,21 +5630,17 @@ function fromKintoneView(name, raw) {
|
|
|
5588
5630
|
}
|
|
5589
5631
|
return {
|
|
5590
5632
|
type: raw.type,
|
|
5591
|
-
index: (
|
|
5592
|
-
const idx = typeof raw.index === "string" ? Number(raw.index) : raw.index;
|
|
5593
|
-
if (!Number.isFinite(idx)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric index from kintone API: ${raw.index}`);
|
|
5594
|
-
return idx;
|
|
5595
|
-
})(),
|
|
5633
|
+
index: parseKintoneIntegerField(raw.index, "index"),
|
|
5596
5634
|
name,
|
|
5597
|
-
...raw.builtinType !== void 0
|
|
5598
|
-
...raw.fields !== void 0
|
|
5599
|
-
...raw.date !== void 0
|
|
5600
|
-
...raw.title !== void 0
|
|
5601
|
-
...raw.html !== void 0
|
|
5602
|
-
...raw.pager !== void 0
|
|
5603
|
-
...device !== void 0
|
|
5604
|
-
...raw.filterCond !== void 0
|
|
5605
|
-
...raw.sort !== void 0
|
|
5635
|
+
...raw.builtinType !== void 0 ? { builtinType: raw.builtinType } : {},
|
|
5636
|
+
...raw.fields !== void 0 ? { fields: raw.fields } : {},
|
|
5637
|
+
...raw.date !== void 0 ? { date: raw.date } : {},
|
|
5638
|
+
...raw.title !== void 0 ? { title: raw.title } : {},
|
|
5639
|
+
...raw.html !== void 0 ? { html: raw.html } : {},
|
|
5640
|
+
...raw.pager !== void 0 ? { pager: raw.pager } : {},
|
|
5641
|
+
...device !== void 0 ? { device } : {},
|
|
5642
|
+
...raw.filterCond !== void 0 ? { filterCond: raw.filterCond } : {},
|
|
5643
|
+
...raw.sort !== void 0 ? { sort: raw.sort } : {}
|
|
5606
5644
|
};
|
|
5607
5645
|
}
|
|
5608
5646
|
function toKintoneView(config) {
|
|
@@ -5642,9 +5680,7 @@ var KintoneViewConfigurator = class {
|
|
|
5642
5680
|
revision: response.revision
|
|
5643
5681
|
};
|
|
5644
5682
|
} catch (error) {
|
|
5645
|
-
|
|
5646
|
-
if (error instanceof SystemError) throw error;
|
|
5647
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get views", error);
|
|
5683
|
+
throw wrapKintoneError(error, "Failed to get views");
|
|
5648
5684
|
}
|
|
5649
5685
|
}
|
|
5650
5686
|
async updateViews(params) {
|
|
@@ -5658,9 +5694,7 @@ var KintoneViewConfigurator = class {
|
|
|
5658
5694
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5659
5695
|
return { revision: (await this.client.app.updateViews(requestParams)).revision };
|
|
5660
5696
|
} catch (error) {
|
|
5661
|
-
|
|
5662
|
-
if (error instanceof SystemError) throw error;
|
|
5663
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update views", error);
|
|
5697
|
+
throw wrapKintoneError(error, "Failed to update views");
|
|
5664
5698
|
}
|
|
5665
5699
|
}
|
|
5666
5700
|
};
|
|
@@ -5674,11 +5708,7 @@ function createLocalFileViewStorage(filePath) {
|
|
|
5674
5708
|
//#endregion
|
|
5675
5709
|
//#region src/core/application/container/viewCli.ts
|
|
5676
5710
|
function createViewCliContainer(config) {
|
|
5677
|
-
const client =
|
|
5678
|
-
baseUrl: config.baseUrl,
|
|
5679
|
-
auth: buildKintoneAuth(config.auth),
|
|
5680
|
-
guestSpaceId: config.guestSpaceId
|
|
5681
|
-
});
|
|
5711
|
+
const client = config.client ?? createKintoneClient(config);
|
|
5682
5712
|
return {
|
|
5683
5713
|
viewConfigurator: new KintoneViewConfigurator(client, config.appId),
|
|
5684
5714
|
viewStorage: createLocalFileViewStorage(config.viewFilePath),
|
|
@@ -5689,11 +5719,13 @@ function createViewCliContainer(config) {
|
|
|
5689
5719
|
//#endregion
|
|
5690
5720
|
//#region src/core/application/container/captureAllCli.ts
|
|
5691
5721
|
function createCliCaptureContainers(input) {
|
|
5722
|
+
const client = createKintoneClient(input);
|
|
5692
5723
|
const base = {
|
|
5693
5724
|
baseUrl: input.baseUrl,
|
|
5694
5725
|
auth: input.auth,
|
|
5695
5726
|
appId: input.appId,
|
|
5696
|
-
guestSpaceId: input.guestSpaceId
|
|
5727
|
+
guestSpaceId: input.guestSpaceId,
|
|
5728
|
+
client
|
|
5697
5729
|
};
|
|
5698
5730
|
const paths = buildAppFilePaths(input.appName, input.baseDir);
|
|
5699
5731
|
return {
|
|
@@ -5778,7 +5810,7 @@ var KintoneSpaceReader = class {
|
|
|
5778
5810
|
this.client = client;
|
|
5779
5811
|
}
|
|
5780
5812
|
async getSpaceApps(spaceId) {
|
|
5781
|
-
if (!spaceId) throw new
|
|
5813
|
+
if (!spaceId) throw new ValidationError(ValidationErrorCode.InvalidInput, "spaceId must not be empty");
|
|
5782
5814
|
try {
|
|
5783
5815
|
const rawApps = (await this.client.space.getSpace({ id: spaceId })).attachedApps;
|
|
5784
5816
|
if (rawApps === void 0) throw new SystemError(SystemErrorCode.ExternalApiError, `Space API response for space ID ${spaceId} does not contain attachedApps. The kintone API response format may have changed.`);
|
|
@@ -5797,9 +5829,7 @@ var KintoneSpaceReader = class {
|
|
|
5797
5829
|
}
|
|
5798
5830
|
return result;
|
|
5799
5831
|
} catch (error) {
|
|
5800
|
-
|
|
5801
|
-
if (error instanceof SystemError) throw error;
|
|
5802
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, `Failed to get space info for space ID: ${spaceId}`, error);
|
|
5832
|
+
throw wrapKintoneError(error, `Failed to get space info for space ID: ${spaceId}`);
|
|
5803
5833
|
}
|
|
5804
5834
|
}
|
|
5805
5835
|
};
|
|
@@ -5814,11 +5844,7 @@ function createLocalFileProjectConfigStorage(filePath) {
|
|
|
5814
5844
|
//#region src/core/application/container/initCli.ts
|
|
5815
5845
|
function createInitCliContainer(config) {
|
|
5816
5846
|
return {
|
|
5817
|
-
spaceReader: new KintoneSpaceReader(
|
|
5818
|
-
baseUrl: config.baseUrl,
|
|
5819
|
-
auth: buildKintoneAuth(config.auth),
|
|
5820
|
-
guestSpaceId: config.guestSpaceId
|
|
5821
|
-
})),
|
|
5847
|
+
spaceReader: new KintoneSpaceReader(config.client ?? createKintoneClient(config)),
|
|
5822
5848
|
projectConfigStorage: createLocalFileProjectConfigStorage(config.configFilePath)
|
|
5823
5849
|
};
|
|
5824
5850
|
}
|
|
@@ -6038,11 +6064,11 @@ const GeneralSettingsConfigSerializer = { serialize: (config) => {
|
|
|
6038
6064
|
//#endregion
|
|
6039
6065
|
//#region src/core/application/generalSettings/captureGeneralSettings.ts
|
|
6040
6066
|
async function captureGeneralSettings({ container }) {
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
};
|
|
6067
|
+
return captureFromConfig({
|
|
6068
|
+
fetchRemote: () => container.generalSettingsConfigurator.getGeneralSettings(),
|
|
6069
|
+
serialize: ({ config }) => GeneralSettingsConfigSerializer.serialize(config),
|
|
6070
|
+
getStorage: () => container.generalSettingsStorage.get()
|
|
6071
|
+
});
|
|
6046
6072
|
}
|
|
6047
6073
|
|
|
6048
6074
|
//#endregion
|
|
@@ -6112,9 +6138,11 @@ const NotificationConfigSerializer = { serialize: (config) => {
|
|
|
6112
6138
|
//#endregion
|
|
6113
6139
|
//#region src/core/application/notification/captureNotification.ts
|
|
6114
6140
|
async function captureNotification({ container }) {
|
|
6115
|
-
const general = await
|
|
6116
|
-
|
|
6117
|
-
|
|
6141
|
+
const [general, perRecord, reminder] = await Promise.all([
|
|
6142
|
+
container.notificationConfigurator.getGeneralNotifications(),
|
|
6143
|
+
container.notificationConfigurator.getPerRecordNotifications(),
|
|
6144
|
+
container.notificationConfigurator.getReminderNotifications()
|
|
6145
|
+
]);
|
|
6118
6146
|
const config = {
|
|
6119
6147
|
general: {
|
|
6120
6148
|
notifyToCommenter: general.notifyToCommenter,
|
|
@@ -6151,11 +6179,11 @@ const PluginConfigSerializer = { serialize: (config) => {
|
|
|
6151
6179
|
//#endregion
|
|
6152
6180
|
//#region src/core/application/plugin/capturePlugin.ts
|
|
6153
6181
|
async function capturePlugin({ container }) {
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
};
|
|
6182
|
+
return captureFromConfig({
|
|
6183
|
+
fetchRemote: () => container.pluginConfigurator.getPlugins(),
|
|
6184
|
+
serialize: ({ plugins }) => PluginConfigSerializer.serialize({ plugins }),
|
|
6185
|
+
getStorage: () => container.pluginStorage.get()
|
|
6186
|
+
});
|
|
6159
6187
|
}
|
|
6160
6188
|
|
|
6161
6189
|
//#endregion
|
|
@@ -6201,11 +6229,11 @@ const ProcessManagementConfigSerializer = { serialize: (config) => {
|
|
|
6201
6229
|
//#endregion
|
|
6202
6230
|
//#region src/core/application/processManagement/captureProcessManagement.ts
|
|
6203
6231
|
async function captureProcessManagement({ container }) {
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
};
|
|
6232
|
+
return captureFromConfig({
|
|
6233
|
+
fetchRemote: () => container.processManagementConfigurator.getProcessManagement(),
|
|
6234
|
+
serialize: ({ config }) => ProcessManagementConfigSerializer.serialize(config),
|
|
6235
|
+
getStorage: () => container.processManagementStorage.get()
|
|
6236
|
+
});
|
|
6209
6237
|
}
|
|
6210
6238
|
|
|
6211
6239
|
//#endregion
|
|
@@ -6238,11 +6266,11 @@ const RecordPermissionConfigSerializer = { serialize: (config) => {
|
|
|
6238
6266
|
//#endregion
|
|
6239
6267
|
//#region src/core/application/recordPermission/captureRecordPermission.ts
|
|
6240
6268
|
async function captureRecordPermission({ container }) {
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
};
|
|
6269
|
+
return captureFromConfig({
|
|
6270
|
+
fetchRemote: () => container.recordPermissionConfigurator.getRecordPermissions(),
|
|
6271
|
+
serialize: ({ rights }) => RecordPermissionConfigSerializer.serialize({ rights }),
|
|
6272
|
+
getStorage: () => container.recordPermissionStorage.get()
|
|
6273
|
+
});
|
|
6246
6274
|
}
|
|
6247
6275
|
|
|
6248
6276
|
//#endregion
|
|
@@ -6309,11 +6337,11 @@ const ReportConfigSerializer = { serialize: (config) => {
|
|
|
6309
6337
|
//#endregion
|
|
6310
6338
|
//#region src/core/application/report/captureReport.ts
|
|
6311
6339
|
async function captureReport({ container }) {
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
};
|
|
6340
|
+
return captureFromConfig({
|
|
6341
|
+
fetchRemote: () => container.reportConfigurator.getReports(),
|
|
6342
|
+
serialize: ({ reports }) => ReportConfigSerializer.serialize({ reports }),
|
|
6343
|
+
getStorage: () => container.reportStorage.get()
|
|
6344
|
+
});
|
|
6317
6345
|
}
|
|
6318
6346
|
|
|
6319
6347
|
//#endregion
|
|
@@ -6393,11 +6421,11 @@ const ViewConfigSerializer = { serialize: (config) => {
|
|
|
6393
6421
|
//#endregion
|
|
6394
6422
|
//#region src/core/application/view/captureView.ts
|
|
6395
6423
|
async function captureView({ container }) {
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
};
|
|
6424
|
+
return captureFromConfig({
|
|
6425
|
+
fetchRemote: () => container.viewConfigurator.getViews(),
|
|
6426
|
+
serialize: ({ views }) => ViewConfigSerializer.serialize({ views }),
|
|
6427
|
+
getStorage: () => container.viewStorage.get()
|
|
6428
|
+
});
|
|
6401
6429
|
}
|
|
6402
6430
|
|
|
6403
6431
|
//#endregion
|
|
@@ -6596,12 +6624,11 @@ function generateProjectConfig(input) {
|
|
|
6596
6624
|
files: buildAppFilePaths(name, input.baseDir)
|
|
6597
6625
|
};
|
|
6598
6626
|
}
|
|
6599
|
-
|
|
6627
|
+
return stringify({
|
|
6600
6628
|
domain: input.domain,
|
|
6629
|
+
...input.guestSpaceId !== void 0 ? { guestSpaceId: input.guestSpaceId } : {},
|
|
6601
6630
|
apps
|
|
6602
|
-
};
|
|
6603
|
-
if (input.guestSpaceId !== void 0) config.guestSpaceId = input.guestSpaceId;
|
|
6604
|
-
return stringify(config, { lineWidth: 0 });
|
|
6631
|
+
}, { lineWidth: 0 });
|
|
6605
6632
|
}
|
|
6606
6633
|
|
|
6607
6634
|
//#endregion
|
|
@@ -6861,6 +6888,15 @@ function parseNotificationConfigText(rawText) {
|
|
|
6861
6888
|
|
|
6862
6889
|
//#endregion
|
|
6863
6890
|
//#region src/core/application/notification/applyNotification.ts
|
|
6891
|
+
/**
|
|
6892
|
+
* Apply notification settings to kintone.
|
|
6893
|
+
*
|
|
6894
|
+
* Each notification section (general, perRecord, reminder) is updated
|
|
6895
|
+
* independently via separate API calls. If one section fails after others
|
|
6896
|
+
* have already been applied, the app will be in a partially-updated state.
|
|
6897
|
+
* This is a kintone API limitation — there is no transactional update
|
|
6898
|
+
* across notification types. Re-running the command is safe and idempotent.
|
|
6899
|
+
*/
|
|
6864
6900
|
async function applyNotification({ container }) {
|
|
6865
6901
|
const result = await container.notificationStorage.get();
|
|
6866
6902
|
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Notification config file not found");
|
|
@@ -7926,13 +7962,17 @@ function parseRecordPermissionConfigText(rawText) {
|
|
|
7926
7962
|
//#endregion
|
|
7927
7963
|
//#region src/core/application/recordPermission/applyRecordPermission.ts
|
|
7928
7964
|
async function applyRecordPermission({ container }) {
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7965
|
+
await applyFromConfig({
|
|
7966
|
+
getStorage: () => container.recordPermissionStorage.get(),
|
|
7967
|
+
parseConfig: parseRecordPermissionConfigText,
|
|
7968
|
+
fetchRemote: () => container.recordPermissionConfigurator.getRecordPermissions(),
|
|
7969
|
+
update: async (config, current) => {
|
|
7970
|
+
await container.recordPermissionConfigurator.updateRecordPermissions({
|
|
7971
|
+
rights: config.rights,
|
|
7972
|
+
revision: current.revision
|
|
7973
|
+
});
|
|
7974
|
+
},
|
|
7975
|
+
notFoundMessage: "Record permission config file not found"
|
|
7936
7976
|
});
|
|
7937
7977
|
}
|
|
7938
7978
|
|
|
@@ -8308,13 +8348,17 @@ function parseReportConfigText(rawText) {
|
|
|
8308
8348
|
//#endregion
|
|
8309
8349
|
//#region src/core/application/report/applyReport.ts
|
|
8310
8350
|
async function applyReport({ container }) {
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8351
|
+
await applyFromConfig({
|
|
8352
|
+
getStorage: () => container.reportStorage.get(),
|
|
8353
|
+
parseConfig: parseReportConfigText,
|
|
8354
|
+
fetchRemote: () => container.reportConfigurator.getReports(),
|
|
8355
|
+
update: async (config, current) => {
|
|
8356
|
+
await container.reportConfigurator.updateReports({
|
|
8357
|
+
reports: config.reports,
|
|
8358
|
+
revision: current.revision
|
|
8359
|
+
});
|
|
8360
|
+
},
|
|
8361
|
+
notFoundMessage: "Report config file not found"
|
|
8318
8362
|
});
|
|
8319
8363
|
}
|
|
8320
8364
|
|
|
@@ -9108,12 +9152,25 @@ function parseSchemaText(rawText) {
|
|
|
9108
9152
|
|
|
9109
9153
|
//#endregion
|
|
9110
9154
|
//#region src/core/application/formSchema/detectDiff.ts
|
|
9155
|
+
function fieldPropertiesToDto(field) {
|
|
9156
|
+
if (field.type === "SUBTABLE") {
|
|
9157
|
+
const innerFields = {};
|
|
9158
|
+
for (const [code, def] of field.properties.fields) innerFields[code] = {
|
|
9159
|
+
code: def.code,
|
|
9160
|
+
type: def.type,
|
|
9161
|
+
label: def.label,
|
|
9162
|
+
properties: def.properties
|
|
9163
|
+
};
|
|
9164
|
+
return { fields: innerFields };
|
|
9165
|
+
}
|
|
9166
|
+
return { ...field.properties };
|
|
9167
|
+
}
|
|
9111
9168
|
function toFieldDto(field) {
|
|
9112
9169
|
return {
|
|
9113
9170
|
code: field.code,
|
|
9114
9171
|
type: field.type,
|
|
9115
9172
|
label: field.label,
|
|
9116
|
-
properties: field
|
|
9173
|
+
properties: fieldPropertiesToDto(field)
|
|
9117
9174
|
};
|
|
9118
9175
|
}
|
|
9119
9176
|
async function detectDiff({ container }) {
|
|
@@ -9198,15 +9255,19 @@ var KintoneFormDumpReader = class {
|
|
|
9198
9255
|
}
|
|
9199
9256
|
async getRawFormData() {
|
|
9200
9257
|
try {
|
|
9201
|
-
const [fields, layout] = await Promise.all([this.client.app.getFormFields({
|
|
9258
|
+
const [fields, layout] = await Promise.all([this.client.app.getFormFields({
|
|
9259
|
+
app: this.appId,
|
|
9260
|
+
preview: true
|
|
9261
|
+
}), this.client.app.getFormLayout({
|
|
9262
|
+
app: this.appId,
|
|
9263
|
+
preview: true
|
|
9264
|
+
})]);
|
|
9202
9265
|
return {
|
|
9203
9266
|
fields,
|
|
9204
9267
|
layout
|
|
9205
9268
|
};
|
|
9206
9269
|
} catch (error) {
|
|
9207
|
-
|
|
9208
|
-
if (error instanceof SystemError) throw error;
|
|
9209
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to fetch raw form data for dump", error);
|
|
9270
|
+
throw wrapKintoneError(error, "Failed to fetch raw form data for dump");
|
|
9210
9271
|
}
|
|
9211
9272
|
}
|
|
9212
9273
|
};
|
|
@@ -9214,11 +9275,16 @@ var KintoneFormDumpReader = class {
|
|
|
9214
9275
|
//#endregion
|
|
9215
9276
|
//#region src/core/adapters/local/dumpStorage.ts
|
|
9216
9277
|
var LocalFileDumpStorage = class {
|
|
9217
|
-
constructor(filePrefix) {
|
|
9278
|
+
constructor(filePrefix, baseDir = process.cwd()) {
|
|
9218
9279
|
this.filePrefix = filePrefix;
|
|
9280
|
+
this.baseDir = baseDir;
|
|
9281
|
+
const fieldsPath = resolve(this.baseDir, `${this.filePrefix}fields.json`);
|
|
9282
|
+
if (!isSafePath(fieldsPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${fieldsPath}" escapes base directory "${this.baseDir}"`);
|
|
9283
|
+
const layoutPath = resolve(this.baseDir, `${this.filePrefix}layout.json`);
|
|
9284
|
+
if (!isSafePath(layoutPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${layoutPath}" escapes base directory "${this.baseDir}"`);
|
|
9219
9285
|
}
|
|
9220
9286
|
async saveFields(content) {
|
|
9221
|
-
const filePath = `${this.filePrefix}fields.json
|
|
9287
|
+
const filePath = resolve(this.baseDir, `${this.filePrefix}fields.json`);
|
|
9222
9288
|
try {
|
|
9223
9289
|
await mkdir(dirname(filePath), { recursive: true });
|
|
9224
9290
|
await writeFile(filePath, content, "utf-8");
|
|
@@ -9227,7 +9293,7 @@ var LocalFileDumpStorage = class {
|
|
|
9227
9293
|
}
|
|
9228
9294
|
}
|
|
9229
9295
|
async saveLayout(content) {
|
|
9230
|
-
const filePath = `${this.filePrefix}layout.json
|
|
9296
|
+
const filePath = resolve(this.baseDir, `${this.filePrefix}layout.json`);
|
|
9231
9297
|
try {
|
|
9232
9298
|
await mkdir(dirname(filePath), { recursive: true });
|
|
9233
9299
|
await writeFile(filePath, content, "utf-8");
|
|
@@ -9241,12 +9307,8 @@ var LocalFileDumpStorage = class {
|
|
|
9241
9307
|
//#region src/core/application/container/dumpCli.ts
|
|
9242
9308
|
function createDumpCliContainer(config) {
|
|
9243
9309
|
return {
|
|
9244
|
-
formDumpReader: new KintoneFormDumpReader(
|
|
9245
|
-
|
|
9246
|
-
auth: buildKintoneAuth(config.auth),
|
|
9247
|
-
guestSpaceId: config.guestSpaceId
|
|
9248
|
-
}), config.appId),
|
|
9249
|
-
dumpStorage: new LocalFileDumpStorage(config.filePrefix)
|
|
9310
|
+
formDumpReader: new KintoneFormDumpReader(config.client ?? createKintoneClient(config), config.appId),
|
|
9311
|
+
dumpStorage: new LocalFileDumpStorage(config.filePrefix, process.cwd())
|
|
9250
9312
|
};
|
|
9251
9313
|
}
|
|
9252
9314
|
|
|
@@ -9317,6 +9379,22 @@ var dump_default = define({
|
|
|
9317
9379
|
}
|
|
9318
9380
|
});
|
|
9319
9381
|
|
|
9382
|
+
//#endregion
|
|
9383
|
+
//#region src/core/domain/formSchema/services/subtableFieldSplitter.ts
|
|
9384
|
+
function splitSubtableInnerFields(desired, current) {
|
|
9385
|
+
const newInnerFields = /* @__PURE__ */ new Map();
|
|
9386
|
+
const existingInnerFields = /* @__PURE__ */ new Map();
|
|
9387
|
+
const deletedInnerFieldCodes = [];
|
|
9388
|
+
for (const [code, def] of desired.properties.fields) if (current.properties.fields.has(code)) existingInnerFields.set(code, def);
|
|
9389
|
+
else newInnerFields.set(code, def);
|
|
9390
|
+
for (const code of current.properties.fields.keys()) if (!desired.properties.fields.has(code)) deletedInnerFieldCodes.push(code);
|
|
9391
|
+
return {
|
|
9392
|
+
newInnerFields,
|
|
9393
|
+
existingInnerFields,
|
|
9394
|
+
deletedInnerFieldCodes
|
|
9395
|
+
};
|
|
9396
|
+
}
|
|
9397
|
+
|
|
9320
9398
|
//#endregion
|
|
9321
9399
|
//#region src/core/domain/formSchema/services/schemaValidator.ts
|
|
9322
9400
|
const SELECTION_TYPES = new Set([
|
|
@@ -9420,6 +9498,11 @@ function validateReferenceTableRelatedApp(field) {
|
|
|
9420
9498
|
if (app.trim().length === 0) return [issue("error", field.code, field.type, "EMPTY_RELATED_APP", `Field "${field.code}" referenceTable.relatedApp.app must be non-empty`)];
|
|
9421
9499
|
return [];
|
|
9422
9500
|
}
|
|
9501
|
+
function validateSubtableHasInnerFields(field) {
|
|
9502
|
+
if (field.type !== "SUBTABLE") return [];
|
|
9503
|
+
if (field.properties.fields.size === 0) return [issue("error", field.code, field.type, "EMPTY_SUBTABLE", `Subtable "${field.code}" must have at least one inner field`)];
|
|
9504
|
+
return [];
|
|
9505
|
+
}
|
|
9423
9506
|
const FIELD_VALIDATORS = [
|
|
9424
9507
|
validateLabelNonEmpty,
|
|
9425
9508
|
validateSelectionOptions,
|
|
@@ -9429,7 +9512,8 @@ const FIELD_VALIDATORS = [
|
|
|
9429
9512
|
validateFileThumbnailSize,
|
|
9430
9513
|
validateReferenceTableSize,
|
|
9431
9514
|
validateLookupStructure,
|
|
9432
|
-
validateReferenceTableRelatedApp
|
|
9515
|
+
validateReferenceTableRelatedApp,
|
|
9516
|
+
validateSubtableHasInnerFields
|
|
9433
9517
|
];
|
|
9434
9518
|
function validateField(field) {
|
|
9435
9519
|
return FIELD_VALIDATORS.flatMap((validator) => validator(field));
|
|
@@ -9478,6 +9562,7 @@ async function executeMigration({ container }) {
|
|
|
9478
9562
|
const deleted = diff.entries.filter((e) => e.type === "deleted");
|
|
9479
9563
|
const fieldsToAdd = [];
|
|
9480
9564
|
const fieldsToUpdate = [];
|
|
9565
|
+
const innerFieldsToDelete = [];
|
|
9481
9566
|
for (const entry of added) {
|
|
9482
9567
|
if (entry.after === void 0) continue;
|
|
9483
9568
|
if (subtableInnerCodes.has(entry.fieldCode)) continue;
|
|
@@ -9489,25 +9574,21 @@ async function executeMigration({ container }) {
|
|
|
9489
9574
|
const after = entry.after;
|
|
9490
9575
|
const before = entry.before;
|
|
9491
9576
|
if (after.type === "SUBTABLE" && before !== void 0 && before.type === "SUBTABLE") {
|
|
9492
|
-
const newInnerFields
|
|
9493
|
-
|
|
9494
|
-
for (const [code, def] of after.properties.fields) if (before.properties.fields.has(code)) existingInnerFields.set(code, def);
|
|
9495
|
-
else newInnerFields.set(code, def);
|
|
9496
|
-
if (newInnerFields.size > 0) fieldsToAdd.push({
|
|
9497
|
-
...after,
|
|
9498
|
-
properties: { fields: newInnerFields }
|
|
9499
|
-
});
|
|
9577
|
+
const { newInnerFields, existingInnerFields, deletedInnerFieldCodes } = splitSubtableInnerFields(after, before);
|
|
9578
|
+
if (newInnerFields.size > 0) throw new ValidationError(ValidationErrorCode.InvalidInput, `kintone REST API does not support adding fields to an existing subtable. Use the schema override command instead. Subtable: ${after.code}`);
|
|
9500
9579
|
if (existingInnerFields.size > 0) fieldsToUpdate.push({
|
|
9501
9580
|
...after,
|
|
9502
9581
|
properties: { fields: existingInnerFields }
|
|
9503
9582
|
});
|
|
9504
|
-
|
|
9583
|
+
for (const code of deletedInnerFieldCodes) innerFieldsToDelete.push(code);
|
|
9584
|
+
} else if (before !== void 0 && before.type !== after.type) throw new ValidationError(ValidationErrorCode.InvalidInput, `Field type change detected for "${after.code}" (${before.type} → ${after.type}). Use the schema override command instead.`);
|
|
9585
|
+
else fieldsToUpdate.push(after);
|
|
9505
9586
|
}
|
|
9506
9587
|
if (fieldsToAdd.length > 0) await container.formConfigurator.addFields(fieldsToAdd);
|
|
9507
9588
|
if (fieldsToUpdate.length > 0) await container.formConfigurator.updateFields(fieldsToUpdate);
|
|
9508
|
-
if (deleted.length > 0) {
|
|
9589
|
+
if (deleted.length > 0 || innerFieldsToDelete.length > 0) {
|
|
9509
9590
|
const currentSubtableInnerCodes = collectSubtableInnerFieldCodes(currentFields);
|
|
9510
|
-
const fieldCodes = deleted.filter((e) => !currentSubtableInnerCodes.has(e.fieldCode)).map((e) => e.fieldCode);
|
|
9591
|
+
const fieldCodes = [...deleted.filter((e) => !currentSubtableInnerCodes.has(e.fieldCode)).map((e) => e.fieldCode), ...innerFieldsToDelete];
|
|
9511
9592
|
if (fieldCodes.length > 0) await container.formConfigurator.deleteFields(fieldCodes);
|
|
9512
9593
|
}
|
|
9513
9594
|
if (hasLayoutChanges) await container.formConfigurator.updateLayout(schema.layout);
|
|
@@ -9622,25 +9703,35 @@ async function forceOverrideForm({ container }) {
|
|
|
9622
9703
|
const toAdd = [];
|
|
9623
9704
|
const toUpdate = [];
|
|
9624
9705
|
const toDelete = [];
|
|
9706
|
+
const innerFieldsToDelete = [];
|
|
9625
9707
|
for (const [fieldCode, schemaDef] of schema.fields) {
|
|
9626
9708
|
if (subtableInnerCodes.has(fieldCode)) continue;
|
|
9627
9709
|
if (currentFields.has(fieldCode)) if (schemaDef.type === "SUBTABLE") {
|
|
9628
9710
|
const currentDef = currentFields.get(fieldCode);
|
|
9629
9711
|
if (currentDef !== void 0 && currentDef.type === "SUBTABLE") {
|
|
9630
|
-
const newInnerFields
|
|
9631
|
-
const
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
}
|
|
9712
|
+
const { newInnerFields, existingInnerFields, deletedInnerFieldCodes } = splitSubtableInnerFields(schemaDef, currentDef);
|
|
9713
|
+
const allInnerFieldsRemoved = existingInnerFields.size === 0 && deletedInnerFieldCodes.length > 0;
|
|
9714
|
+
if (newInnerFields.size > 0 || allInnerFieldsRemoved) {
|
|
9715
|
+
toDelete.push(fieldCode);
|
|
9716
|
+
toAdd.push(schemaDef);
|
|
9717
|
+
} else {
|
|
9718
|
+
toUpdate.push({
|
|
9719
|
+
...schemaDef,
|
|
9720
|
+
properties: { fields: existingInnerFields }
|
|
9721
|
+
});
|
|
9722
|
+
for (const code of deletedInnerFieldCodes) innerFieldsToDelete.push(code);
|
|
9723
|
+
}
|
|
9724
|
+
} else {
|
|
9725
|
+
toDelete.push(fieldCode);
|
|
9726
|
+
toAdd.push(schemaDef);
|
|
9727
|
+
}
|
|
9728
|
+
} else {
|
|
9729
|
+
const currentDef = currentFields.get(fieldCode);
|
|
9730
|
+
if (currentDef !== void 0 && currentDef.type !== schemaDef.type) {
|
|
9731
|
+
toDelete.push(fieldCode);
|
|
9732
|
+
toAdd.push(schemaDef);
|
|
9642
9733
|
} else toUpdate.push(schemaDef);
|
|
9643
|
-
}
|
|
9734
|
+
}
|
|
9644
9735
|
else toAdd.push(schemaDef);
|
|
9645
9736
|
}
|
|
9646
9737
|
const currentSubtableInnerCodes = collectSubtableInnerFieldCodes(currentFields);
|
|
@@ -9648,9 +9739,9 @@ async function forceOverrideForm({ container }) {
|
|
|
9648
9739
|
if (currentSubtableInnerCodes.has(fieldCode)) continue;
|
|
9649
9740
|
if (!schema.fields.has(fieldCode)) toDelete.push(fieldCode);
|
|
9650
9741
|
}
|
|
9742
|
+
if (toDelete.length > 0 || innerFieldsToDelete.length > 0) await container.formConfigurator.deleteFields([...toDelete, ...innerFieldsToDelete]);
|
|
9651
9743
|
if (toAdd.length > 0) await container.formConfigurator.addFields(toAdd);
|
|
9652
9744
|
if (toUpdate.length > 0) await container.formConfigurator.updateFields(toUpdate);
|
|
9653
|
-
if (toDelete.length > 0) await container.formConfigurator.deleteFields(toDelete);
|
|
9654
9745
|
await container.formConfigurator.updateLayout(schema.layout);
|
|
9655
9746
|
}
|
|
9656
9747
|
|
|
@@ -9797,9 +9888,9 @@ async function validateSchema({ container }) {
|
|
|
9797
9888
|
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Schema file not found");
|
|
9798
9889
|
let schema;
|
|
9799
9890
|
try {
|
|
9800
|
-
schema =
|
|
9891
|
+
schema = parseSchemaText(result.content);
|
|
9801
9892
|
} catch (error) {
|
|
9802
|
-
if (
|
|
9893
|
+
if (isValidationError(error)) return {
|
|
9803
9894
|
parseError: error.message,
|
|
9804
9895
|
fieldCount: 0
|
|
9805
9896
|
};
|
|
@@ -9908,6 +9999,50 @@ var schema_default = define({
|
|
|
9908
9999
|
run: () => {}
|
|
9909
10000
|
});
|
|
9910
10001
|
|
|
10002
|
+
//#endregion
|
|
10003
|
+
//#region src/core/domain/seedData/services/upsertPlanner.ts
|
|
10004
|
+
function recordsEqual(seed, existing, keyField) {
|
|
10005
|
+
const seedKeys = Object.keys(seed).filter((k) => k !== keyField);
|
|
10006
|
+
for (const key of seedKeys) {
|
|
10007
|
+
const seedValue = seed[key];
|
|
10008
|
+
const existingValue = existing[key];
|
|
10009
|
+
if (seedValue === void 0 && existingValue === void 0) continue;
|
|
10010
|
+
if (seedValue === void 0 || existingValue === void 0) return false;
|
|
10011
|
+
if (!deepEqual(seedValue, existingValue)) return false;
|
|
10012
|
+
}
|
|
10013
|
+
return true;
|
|
10014
|
+
}
|
|
10015
|
+
const UpsertPlanner = { plan: (key, seedRecords, existingRecords) => {
|
|
10016
|
+
const keyField = key;
|
|
10017
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
10018
|
+
for (const { id, record } of existingRecords) {
|
|
10019
|
+
const keyValue = record[keyField];
|
|
10020
|
+
if (typeof keyValue === "string") existingMap.set(keyValue, {
|
|
10021
|
+
id,
|
|
10022
|
+
record
|
|
10023
|
+
});
|
|
10024
|
+
}
|
|
10025
|
+
const toAdd = [];
|
|
10026
|
+
const toUpdate = [];
|
|
10027
|
+
let unchanged = 0;
|
|
10028
|
+
for (const seedRecord of seedRecords) {
|
|
10029
|
+
const keyValue = seedRecord[keyField];
|
|
10030
|
+
if (typeof keyValue !== "string") throw new BusinessRuleError(SeedDataErrorCode.SdInvalidKeyFieldValue, `Key field "${keyField}" value must be a string, got ${typeof keyValue}`);
|
|
10031
|
+
const existing = existingMap.get(keyValue);
|
|
10032
|
+
if (existing === void 0) toAdd.push(seedRecord);
|
|
10033
|
+
else if (recordsEqual(seedRecord, existing.record, keyField)) unchanged++;
|
|
10034
|
+
else toUpdate.push({
|
|
10035
|
+
id: existing.id,
|
|
10036
|
+
record: seedRecord
|
|
10037
|
+
});
|
|
10038
|
+
}
|
|
10039
|
+
return {
|
|
10040
|
+
toAdd,
|
|
10041
|
+
toUpdate,
|
|
10042
|
+
unchanged
|
|
10043
|
+
};
|
|
10044
|
+
} };
|
|
10045
|
+
|
|
9911
10046
|
//#endregion
|
|
9912
10047
|
//#region src/core/domain/seedData/services/seedParser.ts
|
|
9913
10048
|
function normalizeValue(value) {
|
|
@@ -9969,55 +10104,17 @@ const SeedParser = { parse: (rawText) => {
|
|
|
9969
10104
|
} };
|
|
9970
10105
|
|
|
9971
10106
|
//#endregion
|
|
9972
|
-
//#region src/core/
|
|
9973
|
-
function
|
|
9974
|
-
|
|
9975
|
-
for (const key of seedKeys) {
|
|
9976
|
-
const seedValue = seed[key];
|
|
9977
|
-
const existingValue = existing[key];
|
|
9978
|
-
if (seedValue === void 0 && existingValue === void 0) continue;
|
|
9979
|
-
if (seedValue === void 0 || existingValue === void 0) return false;
|
|
9980
|
-
if (!deepEqual(seedValue, existingValue)) return false;
|
|
9981
|
-
}
|
|
9982
|
-
return true;
|
|
10107
|
+
//#region src/core/application/seedData/parseConfig.ts
|
|
10108
|
+
function parseSeedText(rawText) {
|
|
10109
|
+
return wrapBusinessRuleError(() => SeedParser.parse(rawText));
|
|
9983
10110
|
}
|
|
9984
|
-
const UpsertPlanner = { plan: (key, seedRecords, existingRecords) => {
|
|
9985
|
-
const keyField = key;
|
|
9986
|
-
const existingMap = /* @__PURE__ */ new Map();
|
|
9987
|
-
for (const { id, record } of existingRecords) {
|
|
9988
|
-
const keyValue = record[keyField];
|
|
9989
|
-
if (typeof keyValue === "string") existingMap.set(keyValue, {
|
|
9990
|
-
id,
|
|
9991
|
-
record
|
|
9992
|
-
});
|
|
9993
|
-
}
|
|
9994
|
-
const toAdd = [];
|
|
9995
|
-
const toUpdate = [];
|
|
9996
|
-
let unchanged = 0;
|
|
9997
|
-
for (const seedRecord of seedRecords) {
|
|
9998
|
-
const keyValue = seedRecord[keyField];
|
|
9999
|
-
if (typeof keyValue !== "string") throw new BusinessRuleError(SeedDataErrorCode.SdInvalidKeyFieldValue, `Key field "${keyField}" value must be a string, got ${typeof keyValue}`);
|
|
10000
|
-
const existing = existingMap.get(keyValue);
|
|
10001
|
-
if (existing === void 0) toAdd.push(seedRecord);
|
|
10002
|
-
else if (recordsEqual(seedRecord, existing.record, keyField)) unchanged++;
|
|
10003
|
-
else toUpdate.push({
|
|
10004
|
-
id: existing.id,
|
|
10005
|
-
record: seedRecord
|
|
10006
|
-
});
|
|
10007
|
-
}
|
|
10008
|
-
return {
|
|
10009
|
-
toAdd,
|
|
10010
|
-
toUpdate,
|
|
10011
|
-
unchanged
|
|
10012
|
-
};
|
|
10013
|
-
} };
|
|
10014
10111
|
|
|
10015
10112
|
//#endregion
|
|
10016
10113
|
//#region src/core/application/seedData/upsertSeed.ts
|
|
10017
10114
|
async function upsertSeed({ container, input }) {
|
|
10018
10115
|
const result = await container.seedStorage.get();
|
|
10019
10116
|
if (!result.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Seed file not found");
|
|
10020
|
-
const seedData =
|
|
10117
|
+
const seedData = parseSeedText(result.content);
|
|
10021
10118
|
if (input.clean) {
|
|
10022
10119
|
const { deletedCount } = await container.recordManager.deleteAllRecords();
|
|
10023
10120
|
if (seedData.records.length > 0) await container.recordManager.addRecords(seedData.records);
|
|
@@ -10341,13 +10438,17 @@ function parseGeneralSettingsConfigText(rawText) {
|
|
|
10341
10438
|
//#endregion
|
|
10342
10439
|
//#region src/core/application/generalSettings/applyGeneralSettings.ts
|
|
10343
10440
|
async function applyGeneralSettings({ container }) {
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10441
|
+
await applyFromConfig({
|
|
10442
|
+
getStorage: () => container.generalSettingsStorage.get(),
|
|
10443
|
+
parseConfig: parseGeneralSettingsConfigText,
|
|
10444
|
+
fetchRemote: () => container.generalSettingsConfigurator.getGeneralSettings(),
|
|
10445
|
+
update: async (config, current) => {
|
|
10446
|
+
await container.generalSettingsConfigurator.updateGeneralSettings({
|
|
10447
|
+
config,
|
|
10448
|
+
revision: current.revision
|
|
10449
|
+
});
|
|
10450
|
+
},
|
|
10451
|
+
notFoundMessage: "General settings config file not found"
|
|
10351
10452
|
});
|
|
10352
10453
|
}
|
|
10353
10454
|
|