kintone-migrator 0.24.4 → 0.24.6
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 +476 -331
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -4,9 +4,10 @@ import "dotenv/config";
|
|
|
4
4
|
import { cli, define } from "gunshi";
|
|
5
5
|
import * as p from "@clack/prompts";
|
|
6
6
|
import { parse, stringify } from "yaml";
|
|
7
|
+
import { KintoneRestAPIClient, KintoneRestAPIError } from "@kintone/rest-api-client";
|
|
7
8
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
8
9
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
9
|
-
import {
|
|
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) {
|
|
@@ -327,7 +333,8 @@ const SystemErrorCode = {
|
|
|
327
333
|
NetworkError: "NETWORK_ERROR",
|
|
328
334
|
StorageError: "STORAGE_ERROR",
|
|
329
335
|
DocumentGenerationError: "DOCUMENT_GENERATION_ERROR",
|
|
330
|
-
ExternalApiError: "EXTERNAL_API_ERROR"
|
|
336
|
+
ExternalApiError: "EXTERNAL_API_ERROR",
|
|
337
|
+
ExecutionError: "EXECUTION_ERROR"
|
|
331
338
|
};
|
|
332
339
|
var SystemError = class extends ApplicationError {
|
|
333
340
|
name = "SystemError";
|
|
@@ -549,6 +556,60 @@ async function applyAction({ container }) {
|
|
|
549
556
|
});
|
|
550
557
|
}
|
|
551
558
|
|
|
559
|
+
//#endregion
|
|
560
|
+
//#region src/core/adapters/kintone/wrapKintoneError.ts
|
|
561
|
+
const KINTONE_REVISION_CONFLICT_CODE = "GAIA_CO02";
|
|
562
|
+
const KINTONE_MAINTENANCE_MODE_CODE = "GAIA_NO02";
|
|
563
|
+
function formatMessage(message, error) {
|
|
564
|
+
if (error instanceof KintoneRestAPIError && error.message) return `${message}: ${error.message}`;
|
|
565
|
+
if (error instanceof Error && error.message) return `${message}: ${error.message}`;
|
|
566
|
+
return message;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Converts an unknown error thrown during a kintone API call into the
|
|
570
|
+
* appropriate application-layer error.
|
|
571
|
+
*
|
|
572
|
+
* - {@link BusinessRuleError} and {@link ApplicationError} (including all
|
|
573
|
+
* subclasses such as {@link SystemError}, {@link ValidationError}, etc.)
|
|
574
|
+
* are re-thrown as-is so that errors raised inside a try block are never
|
|
575
|
+
* silently converted.
|
|
576
|
+
* - {@link KintoneRestAPIError} is mapped by HTTP status (401/403/404/409/400)
|
|
577
|
+
* and kintone-specific codes (`GAIA_CO02` revision conflict, `GAIA_NO02`
|
|
578
|
+
* maintenance mode).
|
|
579
|
+
* - Everything else becomes a {@link SystemError} with code `ExternalApiError`.
|
|
580
|
+
*
|
|
581
|
+
* **Note on 400 mapping**: All 400 errors (except `GAIA_CO02`) are mapped to
|
|
582
|
+
* {@link ValidationError}. This is intentionally simplified — some 400 codes
|
|
583
|
+
* (e.g. `GAIA_RE18` record limit, `GAIA_AP01` app unavailable) may have
|
|
584
|
+
* different semantics, but for this CLI tool a single `ValidationError`
|
|
585
|
+
* with the original kintone message in the error detail is sufficient.
|
|
586
|
+
*
|
|
587
|
+
* @throws {UnauthenticatedError} when kintone returns 401
|
|
588
|
+
* @throws {ForbiddenError} when kintone returns 403 (non-GAIA_NO02)
|
|
589
|
+
* @throws {SystemError} when kintone returns 403 with GAIA_NO02 (maintenance mode)
|
|
590
|
+
* @throws {NotFoundError} when kintone returns 404
|
|
591
|
+
* @throws {ConflictError} when kintone returns 409 or GAIA_CO02
|
|
592
|
+
* @throws {ValidationError} when kintone returns 400 (non-GAIA_CO02)
|
|
593
|
+
* @throws {SystemError} for all other kintone errors and unknown errors
|
|
594
|
+
*/
|
|
595
|
+
function wrapKintoneError(error, message) {
|
|
596
|
+
if (isBusinessRuleError(error)) throw error;
|
|
597
|
+
if (error instanceof ApplicationError) throw error;
|
|
598
|
+
const detail = formatMessage(message, error);
|
|
599
|
+
if (error instanceof KintoneRestAPIError) {
|
|
600
|
+
if (error.status === 401) throw new UnauthenticatedError(UnauthenticatedErrorCode.InvalidCredentials, detail, error);
|
|
601
|
+
if (error.status === 403) {
|
|
602
|
+
if (error.code === KINTONE_MAINTENANCE_MODE_CODE) throw new SystemError(SystemErrorCode.ExternalApiError, `${detail} (app is in maintenance mode — GAIA_NO02)`, error);
|
|
603
|
+
throw new ForbiddenError(ForbiddenErrorCode.InsufficientPermissions, detail, error);
|
|
604
|
+
}
|
|
605
|
+
if (error.status === 404) throw new NotFoundError(NotFoundErrorCode.NotFound, detail, error);
|
|
606
|
+
if (error.code === KINTONE_REVISION_CONFLICT_CODE) throw new ConflictError(ConflictErrorCode.Conflict, `${detail} (revision conflict — GAIA_CO02). Please retry the operation.`, error);
|
|
607
|
+
if (error.status === 409) throw new ConflictError(ConflictErrorCode.Conflict, detail, error);
|
|
608
|
+
if (error.status === 400) throw new ValidationError(ValidationErrorCode.InvalidInput, detail, error);
|
|
609
|
+
}
|
|
610
|
+
throw new SystemError(SystemErrorCode.ExternalApiError, detail, error);
|
|
611
|
+
}
|
|
612
|
+
|
|
552
613
|
//#endregion
|
|
553
614
|
//#region src/core/adapters/kintone/actionConfigurator.ts
|
|
554
615
|
function fromKintoneDestApp(raw) {
|
|
@@ -634,9 +695,7 @@ var KintoneActionConfigurator = class {
|
|
|
634
695
|
revision: response.revision
|
|
635
696
|
};
|
|
636
697
|
} catch (error) {
|
|
637
|
-
|
|
638
|
-
if (error instanceof SystemError) throw error;
|
|
639
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get app actions", error);
|
|
698
|
+
throw wrapKintoneError(error, "Failed to get app actions");
|
|
640
699
|
}
|
|
641
700
|
}
|
|
642
701
|
async updateActions(params) {
|
|
@@ -650,15 +709,22 @@ var KintoneActionConfigurator = class {
|
|
|
650
709
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
651
710
|
return { revision: (await this.client.app.updateAppActions(requestParams)).revision };
|
|
652
711
|
} catch (error) {
|
|
653
|
-
|
|
654
|
-
if (error instanceof SystemError) throw error;
|
|
655
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update app actions", error);
|
|
712
|
+
throw wrapKintoneError(error, "Failed to update app actions");
|
|
656
713
|
}
|
|
657
714
|
}
|
|
658
715
|
};
|
|
659
716
|
|
|
660
717
|
//#endregion
|
|
661
718
|
//#region src/core/adapters/kintone/appDeployer.ts
|
|
719
|
+
const VALID_DEPLOY_STATUSES = new Set([
|
|
720
|
+
"PROCESSING",
|
|
721
|
+
"SUCCESS",
|
|
722
|
+
"FAIL",
|
|
723
|
+
"CANCEL"
|
|
724
|
+
]);
|
|
725
|
+
function isDeployStatus(value) {
|
|
726
|
+
return VALID_DEPLOY_STATUSES.has(value);
|
|
727
|
+
}
|
|
662
728
|
const DEFAULT_POLL_INTERVAL_MS = 1e3;
|
|
663
729
|
const DEFAULT_MAX_RETRIES = 180;
|
|
664
730
|
var KintoneAppDeployer = class {
|
|
@@ -673,12 +739,10 @@ var KintoneAppDeployer = class {
|
|
|
673
739
|
async deploy() {
|
|
674
740
|
try {
|
|
675
741
|
await this.client.app.deployApp({ apps: [{ app: this.appId }] });
|
|
676
|
-
await this.waitForDeployment();
|
|
677
742
|
} catch (error) {
|
|
678
|
-
|
|
679
|
-
if (error instanceof SystemError) throw error;
|
|
680
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to deploy app", error);
|
|
743
|
+
throw wrapKintoneError(error, "Failed to deploy app");
|
|
681
744
|
}
|
|
745
|
+
await this.waitForDeployment();
|
|
682
746
|
}
|
|
683
747
|
async waitForDeployment() {
|
|
684
748
|
let lastPollError;
|
|
@@ -692,20 +756,21 @@ var KintoneAppDeployer = class {
|
|
|
692
756
|
consecutivePollFailures = 0;
|
|
693
757
|
} catch (error) {
|
|
694
758
|
if (isBusinessRuleError(error)) throw error;
|
|
695
|
-
if (error instanceof
|
|
759
|
+
if (error instanceof ApplicationError) throw error;
|
|
696
760
|
lastPollError = error;
|
|
697
761
|
consecutivePollFailures++;
|
|
698
762
|
if (consecutivePollFailures >= maxConsecutivePollFailures) throw new SystemError(SystemErrorCode.ExternalApiError, `Deploy status polling failed ${maxConsecutivePollFailures} consecutive times`, lastPollError);
|
|
699
763
|
continue;
|
|
700
764
|
}
|
|
701
|
-
|
|
702
|
-
|
|
765
|
+
if (apps.length === 0) throw new SystemError(SystemErrorCode.ExternalApiError, "Deploy status response contained no apps");
|
|
766
|
+
const rawStatus = apps[0].status;
|
|
767
|
+
if (rawStatus === void 0) throw new SystemError(SystemErrorCode.ExternalApiError, "Deploy status unavailable");
|
|
768
|
+
if (!isDeployStatus(rawStatus)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected deploy status: ${rawStatus}`);
|
|
769
|
+
switch (rawStatus) {
|
|
703
770
|
case "SUCCESS": return;
|
|
704
771
|
case "FAIL": throw new SystemError(SystemErrorCode.ExternalApiError, "App deployment failed");
|
|
705
772
|
case "CANCEL": throw new SystemError(SystemErrorCode.ExternalApiError, "App deployment was cancelled");
|
|
706
773
|
case "PROCESSING": continue;
|
|
707
|
-
case void 0: throw new SystemError(SystemErrorCode.ExternalApiError, "Deploy status unavailable");
|
|
708
|
-
default: throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected deploy status: ${status}`);
|
|
709
774
|
}
|
|
710
775
|
}
|
|
711
776
|
throw new SystemError(SystemErrorCode.ExternalApiError, "App deployment timed out", lastPollError);
|
|
@@ -834,9 +899,7 @@ var KintoneCustomizationConfigurator = class {
|
|
|
834
899
|
revision: response.revision
|
|
835
900
|
};
|
|
836
901
|
} catch (error) {
|
|
837
|
-
|
|
838
|
-
if (error instanceof SystemError) throw error;
|
|
839
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get app customization", error);
|
|
902
|
+
throw wrapKintoneError(error, "Failed to get app customization");
|
|
840
903
|
}
|
|
841
904
|
}
|
|
842
905
|
async updateCustomization(params) {
|
|
@@ -857,9 +920,7 @@ var KintoneCustomizationConfigurator = class {
|
|
|
857
920
|
const response = await this.client.app.updateAppCustomize(requestParams);
|
|
858
921
|
return { revision: String(response.revision) };
|
|
859
922
|
} catch (error) {
|
|
860
|
-
|
|
861
|
-
if (error instanceof SystemError) throw error;
|
|
862
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update app customization", error);
|
|
923
|
+
throw wrapKintoneError(error, "Failed to update app customization");
|
|
863
924
|
}
|
|
864
925
|
}
|
|
865
926
|
};
|
|
@@ -871,31 +932,77 @@ var KintoneFileDownloader = class {
|
|
|
871
932
|
this.client = client;
|
|
872
933
|
}
|
|
873
934
|
async download(fileKey) {
|
|
874
|
-
if (!fileKey) throw new
|
|
935
|
+
if (!fileKey) throw new ValidationError(ValidationErrorCode.InvalidInput, "fileKey must not be empty");
|
|
875
936
|
try {
|
|
876
937
|
return await this.client.file.downloadFile({ fileKey });
|
|
877
938
|
} catch (error) {
|
|
878
|
-
|
|
879
|
-
if (error instanceof SystemError) throw error;
|
|
880
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, `Failed to download file: ${fileKey}`, error);
|
|
939
|
+
throw wrapKintoneError(error, `Failed to download file: ${fileKey}`);
|
|
881
940
|
}
|
|
882
941
|
}
|
|
883
942
|
};
|
|
884
943
|
|
|
944
|
+
//#endregion
|
|
945
|
+
//#region src/lib/safePath.ts
|
|
946
|
+
/**
|
|
947
|
+
* Returns `true` if {@link targetPath} resolves to a location within
|
|
948
|
+
* {@link baseDir}. Follows symlinks via `realpathSync` for both the base
|
|
949
|
+
* directory and the target path when they exist on disk, falling back to
|
|
950
|
+
* textual `resolve` otherwise (e.g. in tests with virtual paths or when
|
|
951
|
+
* the target does not yet exist).
|
|
952
|
+
*
|
|
953
|
+
* {@link targetPath} may be either a relative path (resolved against
|
|
954
|
+
* {@link baseDir}) or an absolute path (used as-is by `path.resolve`).
|
|
955
|
+
* When callers have already resolved the path via `path.resolve(baseDir, x)`,
|
|
956
|
+
* passing the result as an absolute path is safe — `resolve(base, absPath)`
|
|
957
|
+
* returns `absPath` unchanged.
|
|
958
|
+
*
|
|
959
|
+
* **Limitation — symlinks**: If the target path does not exist on disk,
|
|
960
|
+
* symlink components within it cannot be resolved. The check falls back
|
|
961
|
+
* to a textual prefix comparison, which still catches `..` traversal but
|
|
962
|
+
* cannot detect symlink-based escapes for non-existent paths.
|
|
963
|
+
*
|
|
964
|
+
* **Limitation — TOCTOU**: This check is inherently subject to a
|
|
965
|
+
* time-of-check-to-time-of-use race: the filesystem may change between
|
|
966
|
+
* this call and the subsequent file operation. This is acceptable for a
|
|
967
|
+
* CLI tool where the user controls the local environment.
|
|
968
|
+
*
|
|
969
|
+
* **Note**: This function performs synchronous I/O (`realpathSync`).
|
|
970
|
+
*
|
|
971
|
+
* Callers decide how to handle the result.
|
|
972
|
+
*/
|
|
973
|
+
function isSafePath(targetPath, baseDir) {
|
|
974
|
+
if (targetPath.includes("\0") || baseDir.includes("\0")) return false;
|
|
975
|
+
let resolvedBase;
|
|
976
|
+
try {
|
|
977
|
+
resolvedBase = realpathSync(baseDir);
|
|
978
|
+
} catch {
|
|
979
|
+
resolvedBase = resolve(baseDir);
|
|
980
|
+
}
|
|
981
|
+
const textualTarget = resolve(resolvedBase, targetPath);
|
|
982
|
+
let resolvedTarget;
|
|
983
|
+
try {
|
|
984
|
+
resolvedTarget = realpathSync(textualTarget);
|
|
985
|
+
} catch {
|
|
986
|
+
resolvedTarget = textualTarget;
|
|
987
|
+
}
|
|
988
|
+
return resolvedTarget.startsWith(`${resolvedBase}/`) || resolvedTarget === resolvedBase;
|
|
989
|
+
}
|
|
990
|
+
|
|
885
991
|
//#endregion
|
|
886
992
|
//#region src/core/adapters/kintone/fileUploader.ts
|
|
887
993
|
var KintoneFileUploader = class {
|
|
888
|
-
constructor(client) {
|
|
994
|
+
constructor(client, baseDir) {
|
|
889
995
|
this.client = client;
|
|
996
|
+
this.baseDir = baseDir;
|
|
890
997
|
}
|
|
891
998
|
async upload(filePath) {
|
|
892
|
-
if (!filePath) throw new
|
|
999
|
+
if (!filePath) throw new ValidationError(ValidationErrorCode.InvalidInput, "filePath must not be empty");
|
|
1000
|
+
const resolvedPath = resolve(this.baseDir, filePath);
|
|
1001
|
+
if (!isSafePath(resolvedPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${resolvedPath}" escapes base directory "${this.baseDir}"`);
|
|
893
1002
|
try {
|
|
894
|
-
return { fileKey: (await this.client.file.uploadFile({ file: { path:
|
|
1003
|
+
return { fileKey: (await this.client.file.uploadFile({ file: { path: resolvedPath } })).fileKey };
|
|
895
1004
|
} catch (error) {
|
|
896
|
-
|
|
897
|
-
if (error instanceof SystemError) throw error;
|
|
898
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, `Failed to upload file: ${filePath}`, error);
|
|
1005
|
+
throw wrapKintoneError(error, `Failed to upload file: ${filePath}`);
|
|
899
1006
|
}
|
|
900
1007
|
}
|
|
901
1008
|
};
|
|
@@ -911,7 +1018,7 @@ function hasControlChars(s) {
|
|
|
911
1018
|
return false;
|
|
912
1019
|
}
|
|
913
1020
|
/** Replaces control characters (0x00–0x1f, 0x7f) with escaped `\\xNN` representation for safe display. */
|
|
914
|
-
function sanitizeForDisplay(s) {
|
|
1021
|
+
function sanitizeForDisplay$1(s) {
|
|
915
1022
|
let result = "";
|
|
916
1023
|
for (let i = 0; i < s.length; i++) {
|
|
917
1024
|
const ch = s.charCodeAt(i);
|
|
@@ -933,7 +1040,7 @@ function hasInvalidFieldCodeChars(code) {
|
|
|
933
1040
|
}
|
|
934
1041
|
const FieldCode = { create: (code) => {
|
|
935
1042
|
if (code.length === 0) throw new BusinessRuleError(FormSchemaErrorCode.FsEmptyFieldCode, "Field code cannot be empty");
|
|
936
|
-
if (hasInvalidFieldCodeChars(code)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidFieldCode, `Field code "${sanitizeForDisplay(code)}" contains invalid characters`);
|
|
1043
|
+
if (hasInvalidFieldCodeChars(code)) throw new BusinessRuleError(FormSchemaErrorCode.FsInvalidFieldCode, `Field code "${sanitizeForDisplay$1(code)}" contains invalid characters`);
|
|
937
1044
|
return code;
|
|
938
1045
|
} };
|
|
939
1046
|
|
|
@@ -976,10 +1083,6 @@ const DECORATION_TYPES$1 = new Set([
|
|
|
976
1083
|
"SPACER",
|
|
977
1084
|
"HR"
|
|
978
1085
|
]);
|
|
979
|
-
const KINTONE_REVISION_CONFLICT_CODE = "GAIA_CO02";
|
|
980
|
-
function isRevisionConflict(error) {
|
|
981
|
-
return error instanceof KintoneRestAPIError && error.code === KINTONE_REVISION_CONFLICT_CODE;
|
|
982
|
-
}
|
|
983
1086
|
/**
|
|
984
1087
|
* Tracks the latest known kintone form revision for optimistic concurrency control.
|
|
985
1088
|
*
|
|
@@ -992,10 +1095,13 @@ function isRevisionConflict(error) {
|
|
|
992
1095
|
var RevisionTracker = class {
|
|
993
1096
|
revision = void 0;
|
|
994
1097
|
track(revision) {
|
|
995
|
-
if (
|
|
1098
|
+
if (revision === "") throw new SystemError(SystemErrorCode.ExternalApiError, "Unexpected empty revision from kintone API");
|
|
1099
|
+
const revisionNum = Number(revision);
|
|
1100
|
+
if (!Number.isFinite(revisionNum)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric revision from kintone API: "${revision}"`);
|
|
1101
|
+
if (this.revision === void 0 || revisionNum > this.revision) this.revision = revisionNum;
|
|
996
1102
|
}
|
|
997
1103
|
get current() {
|
|
998
|
-
return this.revision;
|
|
1104
|
+
return this.revision !== void 0 ? String(this.revision) : void 0;
|
|
999
1105
|
}
|
|
1000
1106
|
};
|
|
1001
1107
|
function assertRecord(value, fieldPath) {
|
|
@@ -1267,7 +1373,7 @@ var KintoneFormConfigurator = class {
|
|
|
1267
1373
|
app: this.appId,
|
|
1268
1374
|
preview: true
|
|
1269
1375
|
});
|
|
1270
|
-
this.revisionTracker.track(revision);
|
|
1376
|
+
if (revision) this.revisionTracker.track(revision);
|
|
1271
1377
|
const fields = /* @__PURE__ */ new Map();
|
|
1272
1378
|
for (const [code, prop] of Object.entries(properties)) {
|
|
1273
1379
|
const kintoneProp = prop;
|
|
@@ -1278,9 +1384,7 @@ var KintoneFormConfigurator = class {
|
|
|
1278
1384
|
}
|
|
1279
1385
|
return fields;
|
|
1280
1386
|
} catch (error) {
|
|
1281
|
-
|
|
1282
|
-
if (error instanceof SystemError) throw error;
|
|
1283
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get form fields", error);
|
|
1387
|
+
throw wrapKintoneError(error, "Failed to get form fields");
|
|
1284
1388
|
}
|
|
1285
1389
|
}
|
|
1286
1390
|
async addFields(fields) {
|
|
@@ -1294,10 +1398,7 @@ var KintoneFormConfigurator = class {
|
|
|
1294
1398
|
});
|
|
1295
1399
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1296
1400
|
} catch (error) {
|
|
1297
|
-
|
|
1298
|
-
if (error instanceof SystemError) throw error;
|
|
1299
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1300
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to add form fields", error);
|
|
1401
|
+
throw wrapKintoneError(error, "Failed to add form fields");
|
|
1301
1402
|
}
|
|
1302
1403
|
}
|
|
1303
1404
|
async updateFields(fields) {
|
|
@@ -1311,10 +1412,7 @@ var KintoneFormConfigurator = class {
|
|
|
1311
1412
|
});
|
|
1312
1413
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1313
1414
|
} catch (error) {
|
|
1314
|
-
|
|
1315
|
-
if (error instanceof SystemError) throw error;
|
|
1316
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1317
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update form fields", error);
|
|
1415
|
+
throw wrapKintoneError(error, "Failed to update form fields");
|
|
1318
1416
|
}
|
|
1319
1417
|
}
|
|
1320
1418
|
async deleteFields(fieldCodes) {
|
|
@@ -1326,10 +1424,7 @@ var KintoneFormConfigurator = class {
|
|
|
1326
1424
|
});
|
|
1327
1425
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1328
1426
|
} catch (error) {
|
|
1329
|
-
|
|
1330
|
-
if (error instanceof SystemError) throw error;
|
|
1331
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1332
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to delete form fields", error);
|
|
1427
|
+
throw wrapKintoneError(error, "Failed to delete form fields");
|
|
1333
1428
|
}
|
|
1334
1429
|
}
|
|
1335
1430
|
async getLayout() {
|
|
@@ -1338,12 +1433,10 @@ var KintoneFormConfigurator = class {
|
|
|
1338
1433
|
app: this.appId,
|
|
1339
1434
|
preview: true
|
|
1340
1435
|
});
|
|
1341
|
-
this.revisionTracker.track(response.revision);
|
|
1436
|
+
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1342
1437
|
return response.layout.map(fromKintoneLayoutItem);
|
|
1343
1438
|
} catch (error) {
|
|
1344
|
-
|
|
1345
|
-
if (error instanceof SystemError) throw error;
|
|
1346
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get form layout", error);
|
|
1439
|
+
throw wrapKintoneError(error, "Failed to get form layout");
|
|
1347
1440
|
}
|
|
1348
1441
|
}
|
|
1349
1442
|
async updateLayout(layout) {
|
|
@@ -1356,10 +1449,7 @@ var KintoneFormConfigurator = class {
|
|
|
1356
1449
|
});
|
|
1357
1450
|
if (response.revision) this.revisionTracker.track(response.revision);
|
|
1358
1451
|
} catch (error) {
|
|
1359
|
-
|
|
1360
|
-
if (error instanceof SystemError) throw error;
|
|
1361
|
-
if (isRevisionConflict(error)) throw new ConflictError(ConflictErrorCode.Conflict, "Form configuration was modified by another process. Please retry the operation.", error);
|
|
1362
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update form layout", error);
|
|
1452
|
+
throw wrapKintoneError(error, "Failed to update form layout");
|
|
1363
1453
|
}
|
|
1364
1454
|
}
|
|
1365
1455
|
};
|
|
@@ -1480,9 +1570,7 @@ var KintoneRecordManager = class {
|
|
|
1480
1570
|
};
|
|
1481
1571
|
});
|
|
1482
1572
|
} catch (error) {
|
|
1483
|
-
|
|
1484
|
-
if (error instanceof SystemError) throw error;
|
|
1485
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get records", error);
|
|
1573
|
+
throw wrapKintoneError(error, "Failed to get records");
|
|
1486
1574
|
}
|
|
1487
1575
|
}
|
|
1488
1576
|
async addRecords(records) {
|
|
@@ -1493,9 +1581,7 @@ var KintoneRecordManager = class {
|
|
|
1493
1581
|
records: records.map(toKintoneRecord)
|
|
1494
1582
|
});
|
|
1495
1583
|
} catch (error) {
|
|
1496
|
-
|
|
1497
|
-
if (error instanceof SystemError) throw error;
|
|
1498
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to add records", error);
|
|
1584
|
+
throw wrapKintoneError(error, "Failed to add records");
|
|
1499
1585
|
}
|
|
1500
1586
|
}
|
|
1501
1587
|
async updateRecords(records) {
|
|
@@ -1509,9 +1595,7 @@ var KintoneRecordManager = class {
|
|
|
1509
1595
|
}))
|
|
1510
1596
|
});
|
|
1511
1597
|
} catch (error) {
|
|
1512
|
-
|
|
1513
|
-
if (error instanceof SystemError) throw error;
|
|
1514
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update records", error);
|
|
1598
|
+
throw wrapKintoneError(error, "Failed to update records");
|
|
1515
1599
|
}
|
|
1516
1600
|
}
|
|
1517
1601
|
async deleteAllRecords() {
|
|
@@ -1528,9 +1612,7 @@ var KintoneRecordManager = class {
|
|
|
1528
1612
|
});
|
|
1529
1613
|
return { deletedCount: records.length };
|
|
1530
1614
|
} catch (error) {
|
|
1531
|
-
|
|
1532
|
-
if (error instanceof SystemError) throw error;
|
|
1533
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to delete all records", error);
|
|
1615
|
+
throw wrapKintoneError(error, "Failed to delete all records");
|
|
1534
1616
|
}
|
|
1535
1617
|
}
|
|
1536
1618
|
};
|
|
@@ -1544,10 +1626,15 @@ function createLocalFileCustomizationStorage(filePath) {
|
|
|
1544
1626
|
//#endregion
|
|
1545
1627
|
//#region src/core/adapters/local/fileWriter.ts
|
|
1546
1628
|
var LocalFileWriter = class {
|
|
1629
|
+
constructor(baseDir = process.cwd()) {
|
|
1630
|
+
this.baseDir = baseDir;
|
|
1631
|
+
}
|
|
1547
1632
|
async write(filePath, data) {
|
|
1633
|
+
const resolvedPath = resolve(this.baseDir, filePath);
|
|
1634
|
+
if (!isSafePath(resolvedPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${resolvedPath}" escapes base directory "${this.baseDir}"`);
|
|
1548
1635
|
try {
|
|
1549
|
-
await mkdir(dirname(
|
|
1550
|
-
await writeFile(
|
|
1636
|
+
await mkdir(dirname(resolvedPath), { recursive: true });
|
|
1637
|
+
await writeFile(resolvedPath, Buffer.from(new Uint8Array(data)));
|
|
1551
1638
|
} catch (error) {
|
|
1552
1639
|
throw new SystemError(SystemErrorCode.StorageError, `Failed to write file: ${filePath}`, error);
|
|
1553
1640
|
}
|
|
@@ -1594,9 +1681,9 @@ function createCustomizationCliContainer(config) {
|
|
|
1594
1681
|
return {
|
|
1595
1682
|
customizationConfigurator: new KintoneCustomizationConfigurator(client, config.appId),
|
|
1596
1683
|
customizationStorage: createLocalFileCustomizationStorage(config.customizeFilePath),
|
|
1597
|
-
fileUploader: new KintoneFileUploader(client),
|
|
1684
|
+
fileUploader: new KintoneFileUploader(client, process.cwd()),
|
|
1598
1685
|
fileDownloader: new KintoneFileDownloader(client),
|
|
1599
|
-
fileWriter: new LocalFileWriter(),
|
|
1686
|
+
fileWriter: new LocalFileWriter(process.cwd()),
|
|
1600
1687
|
appDeployer: new KintoneAppDeployer(client, config.appId)
|
|
1601
1688
|
};
|
|
1602
1689
|
}
|
|
@@ -1799,7 +1886,7 @@ function hasInvalidAppNameChars(name) {
|
|
|
1799
1886
|
}
|
|
1800
1887
|
const AppName = { create: (name) => {
|
|
1801
1888
|
if (name.length === 0) throw new BusinessRuleError(ProjectConfigErrorCode.PcEmptyAppName, "App name cannot be empty");
|
|
1802
|
-
if (hasInvalidAppNameChars(name)) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAppName, `App name "${sanitizeForDisplay(name)}" contains invalid characters (path separators or control characters are not allowed)`);
|
|
1889
|
+
if (hasInvalidAppNameChars(name)) throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAppName, `App name "${sanitizeForDisplay$1(name)}" contains invalid characters (path separators or control characters are not allowed)`);
|
|
1803
1890
|
if (name === "." || name === "..") throw new BusinessRuleError(ProjectConfigErrorCode.PcInvalidAppName, `App name "${name}" is not allowed (reserved path component)`);
|
|
1804
1891
|
return name;
|
|
1805
1892
|
} };
|
|
@@ -2005,14 +2092,17 @@ function buildAppFilePaths(appName, baseDir) {
|
|
|
2005
2092
|
};
|
|
2006
2093
|
}
|
|
2007
2094
|
|
|
2008
|
-
//#endregion
|
|
2009
|
-
//#region src/core/application/formSchema/deployApp.ts
|
|
2010
|
-
async function deployApp({ container }) {
|
|
2011
|
-
await container.appDeployer.deploy();
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
2095
|
//#endregion
|
|
2015
2096
|
//#region src/cli/handleError.ts
|
|
2097
|
+
/**
|
|
2098
|
+
* Log error details without terminating the process.
|
|
2099
|
+
* Use this in contexts where multiple errors may be reported (e.g. multi-app results).
|
|
2100
|
+
*
|
|
2101
|
+
* Note: This function intentionally does NOT show the "Set VERBOSE=1 ..." hint.
|
|
2102
|
+
* The hint is only shown by `handleCliError`, which is the top-level CLI handler.
|
|
2103
|
+
* `logError` is used for per-app error reporting within multi-app runs where the
|
|
2104
|
+
* hint would be noisy if repeated for each failure.
|
|
2105
|
+
*/
|
|
2016
2106
|
function logError(error) {
|
|
2017
2107
|
if (isBusinessRuleError(error)) {
|
|
2018
2108
|
p.log.error(`[BusinessRuleError] ${error.code}: ${error.message}`);
|
|
@@ -2021,11 +2111,14 @@ function logError(error) {
|
|
|
2021
2111
|
}
|
|
2022
2112
|
if (isValidationError(error)) {
|
|
2023
2113
|
p.log.error(`[ValidationError] ${error.code}: ${error.message}`);
|
|
2114
|
+
p.log.warn("Hint: Please check your input values and configuration.");
|
|
2024
2115
|
logErrorDetails(error);
|
|
2025
2116
|
return;
|
|
2026
2117
|
}
|
|
2027
2118
|
if (isSystemError(error)) {
|
|
2028
2119
|
p.log.error(`[SystemError] ${error.code}: ${error.message}`);
|
|
2120
|
+
const hint = systemErrorHints[error.code];
|
|
2121
|
+
if (hint) p.log.warn(`Hint: ${hint}`);
|
|
2029
2122
|
logErrorDetails(error);
|
|
2030
2123
|
return;
|
|
2031
2124
|
}
|
|
@@ -2065,42 +2158,83 @@ function logError(error) {
|
|
|
2065
2158
|
}
|
|
2066
2159
|
p.log.error(`[Error] Unexpected error occurred: ${String(error)}`);
|
|
2067
2160
|
}
|
|
2161
|
+
/**
|
|
2162
|
+
* Log error details and terminate the process with exit code 1.
|
|
2163
|
+
* Use this as the top-level error handler in CLI command `run` functions.
|
|
2164
|
+
*/
|
|
2068
2165
|
function handleCliError(error) {
|
|
2069
2166
|
logError(error);
|
|
2167
|
+
if (!isVerbose()) p.log.info("Set VERBOSE=1 for full stack traces.");
|
|
2070
2168
|
p.outro("Failed.");
|
|
2071
2169
|
process.exit(1);
|
|
2072
2170
|
}
|
|
2073
2171
|
function formatErrorForDisplay(error) {
|
|
2074
|
-
if (error instanceof Error) return error.message;
|
|
2075
|
-
if (typeof error === "object" && error !== null) return JSON.stringify(error, null, 2);
|
|
2076
|
-
return String(error);
|
|
2172
|
+
if (error instanceof Error) return sanitizeString(error.message);
|
|
2173
|
+
if (typeof error === "object" && error !== null) return JSON.stringify(sanitizeForDisplay(error), null, 2);
|
|
2174
|
+
return sanitizeString(String(error));
|
|
2175
|
+
}
|
|
2176
|
+
const systemErrorHints = {
|
|
2177
|
+
NETWORK_ERROR: "Please check your network connection and kintone domain.",
|
|
2178
|
+
EXTERNAL_API_ERROR: "The kintone API returned an unexpected error. Please retry or check the API status.",
|
|
2179
|
+
STORAGE_ERROR: "Failed to read/write a local file. Please check file permissions.",
|
|
2180
|
+
EXECUTION_ERROR: "One or more apps failed during execution. Check the individual errors above."
|
|
2181
|
+
};
|
|
2182
|
+
const SENSITIVE_KEYS = /^(authorization|apitoken|api-token|api_token|apikey|api-key|api_key|password|secret|credentials|x-cybozu-authorization)$/i;
|
|
2183
|
+
const SENSITIVE_VALUE_PATTERNS = /(?<=(?:password|apiToken|api[_-]?token|api[_-]?key|secret|credentials)[=:]\s*)\S+/gi;
|
|
2184
|
+
const AUTHORIZATION_VALUE_PATTERN = /(?<=authorization[=:]\s*)\S+(?:\s+\S+)?/gi;
|
|
2185
|
+
function sanitizeString(value) {
|
|
2186
|
+
return value.replace(AUTHORIZATION_VALUE_PATTERN, "[REDACTED]").replace(SENSITIVE_VALUE_PATTERNS, "[REDACTED]");
|
|
2187
|
+
}
|
|
2188
|
+
function sanitizeForDisplay(obj, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2189
|
+
if (typeof obj !== "object" || obj === null) return obj;
|
|
2190
|
+
if (seen.has(obj)) return "[Circular]";
|
|
2191
|
+
seen.add(obj);
|
|
2192
|
+
if (Array.isArray(obj)) return obj.map((item) => sanitizeForDisplay(item, seen));
|
|
2193
|
+
const result = {};
|
|
2194
|
+
if (obj instanceof Error) {
|
|
2195
|
+
result.message = sanitizeString(obj.message);
|
|
2196
|
+
if (obj.stack) result.stack = sanitizeString(obj.stack);
|
|
2197
|
+
}
|
|
2198
|
+
for (const [key, value] of Object.entries(obj)) if (SENSITIVE_KEYS.test(key)) result[key] = "[REDACTED]";
|
|
2199
|
+
else if (typeof value === "object" && value !== null) result[key] = sanitizeForDisplay(value, seen);
|
|
2200
|
+
else if (typeof value === "string") result[key] = sanitizeString(value);
|
|
2201
|
+
else result[key] = value;
|
|
2202
|
+
return result;
|
|
2203
|
+
}
|
|
2204
|
+
function isVerbose() {
|
|
2205
|
+
return process.env.VERBOSE === "1" || process.env.VERBOSE === "true" || process.env.VERBOSE === "yes";
|
|
2077
2206
|
}
|
|
2078
2207
|
function logErrorDetails(error) {
|
|
2079
2208
|
if (error.cause) {
|
|
2209
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2210
|
+
seen.add(error);
|
|
2080
2211
|
p.log.warn(`Cause: ${formatErrorForDisplay(error.cause)}`);
|
|
2081
|
-
logNestedErrorProperties(error.cause);
|
|
2212
|
+
logNestedErrorProperties(error.cause, seen);
|
|
2082
2213
|
}
|
|
2083
|
-
if (error.stack) p.log.warn(`Stack: ${error.stack}`);
|
|
2214
|
+
if (isVerbose() && error.stack) p.log.warn(`Stack: ${error.stack}`);
|
|
2084
2215
|
}
|
|
2085
|
-
function logNestedErrorProperties(target) {
|
|
2216
|
+
function logNestedErrorProperties(target, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2086
2217
|
if (typeof target !== "object" || target === null) return;
|
|
2218
|
+
if (seen.has(target)) return;
|
|
2219
|
+
seen.add(target);
|
|
2087
2220
|
const record = target;
|
|
2088
2221
|
if (record.error instanceof Error) {
|
|
2089
|
-
p.log.warn(` Error: ${record.error.message}`);
|
|
2090
|
-
|
|
2091
|
-
if (innerRecord.errors && typeof innerRecord.errors === "object") p.log.warn(` Details: ${JSON.stringify(innerRecord.errors, null, 2)}`);
|
|
2222
|
+
p.log.warn(` Error: ${sanitizeString(record.error.message)}`);
|
|
2223
|
+
if (hasObjectProperty(record.error, "errors")) p.log.warn(` Details: ${JSON.stringify(sanitizeForDisplay(record.error.errors), null, 2)}`);
|
|
2092
2224
|
}
|
|
2093
2225
|
if (Array.isArray(record.errors)) for (const e of record.errors) if (e instanceof Error) {
|
|
2094
|
-
p.log.warn(` - ${e.message}`);
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
else if (record.errors && typeof record.errors === "object" && !("error" in record)) p.log.warn(`Details: ${JSON.stringify(record.errors, null, 2)}`);
|
|
2226
|
+
p.log.warn(` - ${sanitizeString(e.message)}`);
|
|
2227
|
+
if (hasObjectProperty(e, "errors")) p.log.warn(` ${JSON.stringify(sanitizeForDisplay(e.errors), null, 2)}`);
|
|
2228
|
+
} else p.log.warn(` - ${JSON.stringify(sanitizeForDisplay(e), null, 2)}`);
|
|
2229
|
+
else if (record.errors && typeof record.errors === "object" && !(record.error instanceof Error)) p.log.warn(`Details: ${JSON.stringify(sanitizeForDisplay(record.errors), null, 2)}`);
|
|
2099
2230
|
if (target instanceof Error && target.cause) {
|
|
2100
2231
|
p.log.warn(` Caused by: ${formatErrorForDisplay(target.cause)}`);
|
|
2101
|
-
logNestedErrorProperties(target.cause);
|
|
2232
|
+
logNestedErrorProperties(target.cause, seen);
|
|
2102
2233
|
}
|
|
2103
2234
|
}
|
|
2235
|
+
function hasObjectProperty(obj, key) {
|
|
2236
|
+
return key in obj && typeof obj[key] === "object" && obj[key] !== null;
|
|
2237
|
+
}
|
|
2104
2238
|
function isApplicationError(error) {
|
|
2105
2239
|
return error instanceof ApplicationError;
|
|
2106
2240
|
}
|
|
@@ -2213,40 +2347,30 @@ async function confirmAndDeploy(containers, skipConfirm, successMessage = "Deplo
|
|
|
2213
2347
|
if (!skipConfirm) {
|
|
2214
2348
|
const shouldDeploy = await p.confirm({ message: "Deploy to production?" });
|
|
2215
2349
|
if (p.isCancel(shouldDeploy) || !shouldDeploy) {
|
|
2216
|
-
|
|
2350
|
+
const appNames = containers.map((c) => c.appName).filter((n) => n != null);
|
|
2351
|
+
if (appNames.length > 0) p.log.warn(`Applied to preview, but not deployed to production: ${appNames.join(", ")}`);
|
|
2352
|
+
else p.log.warn("Applied to preview, but not deployed to production.");
|
|
2217
2353
|
return;
|
|
2218
2354
|
}
|
|
2219
2355
|
}
|
|
2220
2356
|
const ds = p.spinner();
|
|
2221
2357
|
ds.start("Deploying to production...");
|
|
2358
|
+
const deployedNames = [];
|
|
2222
2359
|
try {
|
|
2223
|
-
for (const container of containers)
|
|
2360
|
+
for (const container of containers) {
|
|
2361
|
+
await container.appDeployer.deploy();
|
|
2362
|
+
if (container.appName) deployedNames.push(container.appName);
|
|
2363
|
+
}
|
|
2224
2364
|
ds.stop("Deployed to production.");
|
|
2225
2365
|
} catch (error) {
|
|
2226
2366
|
ds.stop("Deployment failed.");
|
|
2367
|
+
if (deployedNames.length > 0) p.log.warn(`${deployedNames.length}/${containers.length} app(s) were deployed before the failure: ${deployedNames.join(", ")}`);
|
|
2368
|
+
const notDeployed = containers.map((c) => c.appName).filter((n) => n != null).filter((n) => !deployedNames.includes(n));
|
|
2369
|
+
if (notDeployed.length > 0) p.log.warn(`Not deployed: ${notDeployed.join(", ")}`);
|
|
2227
2370
|
throw error;
|
|
2228
2371
|
}
|
|
2229
2372
|
p.log.success(successMessage);
|
|
2230
2373
|
}
|
|
2231
|
-
async function promptDeploy(container, skipConfirm) {
|
|
2232
|
-
if (!skipConfirm) {
|
|
2233
|
-
const shouldDeploy = await p.confirm({ message: "Deploy to production?" });
|
|
2234
|
-
if (p.isCancel(shouldDeploy) || !shouldDeploy) {
|
|
2235
|
-
p.log.warn("Applied to preview, but not deployed to production.");
|
|
2236
|
-
return;
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
const ds = p.spinner();
|
|
2240
|
-
ds.start("Deploying to production...");
|
|
2241
|
-
try {
|
|
2242
|
-
await deployApp({ container });
|
|
2243
|
-
ds.stop("Deployment complete.");
|
|
2244
|
-
} catch (error) {
|
|
2245
|
-
ds.stop("Deployment failed.");
|
|
2246
|
-
throw error;
|
|
2247
|
-
}
|
|
2248
|
-
p.log.success("Deployed to production.");
|
|
2249
|
-
}
|
|
2250
2374
|
|
|
2251
2375
|
//#endregion
|
|
2252
2376
|
//#region src/cli/projectConfig.ts
|
|
@@ -2352,10 +2476,30 @@ async function routeMultiApp(values, handlers) {
|
|
|
2352
2476
|
}
|
|
2353
2477
|
await handlers.multiApp(target.plan, target.config);
|
|
2354
2478
|
}
|
|
2479
|
+
/**
|
|
2480
|
+
* High-level multi-app executor that prints app headers before each executor call.
|
|
2481
|
+
* Use this when the executor does not print its own headers (most apply commands).
|
|
2482
|
+
* Delegates to `runMultiAppWithFailCheck` for execution and failure handling.
|
|
2483
|
+
*/
|
|
2484
|
+
async function runMultiAppWithHeaders(plan, executor, successMessage) {
|
|
2485
|
+
await runMultiAppWithFailCheck(plan, async (app) => {
|
|
2486
|
+
printAppHeader(app.name, app.appId);
|
|
2487
|
+
await executor(app);
|
|
2488
|
+
}, successMessage);
|
|
2489
|
+
}
|
|
2490
|
+
/**
|
|
2491
|
+
* Low-level multi-app executor that runs apps, prints results, and throws on failure.
|
|
2492
|
+
* Use this directly when the executor needs full control over output (e.g. schema migrate
|
|
2493
|
+
* prints its own headers and performs per-app deploy inside the executor callback).
|
|
2494
|
+
*/
|
|
2355
2495
|
async function runMultiAppWithFailCheck(plan, executor, successMessage) {
|
|
2356
2496
|
const multiResult = await executeMultiApp(plan, executor);
|
|
2357
2497
|
printMultiAppResult(multiResult);
|
|
2358
|
-
if (multiResult.hasFailure)
|
|
2498
|
+
if (multiResult.hasFailure) {
|
|
2499
|
+
const succeededCount = multiResult.results.filter((r) => r.status === "succeeded").length;
|
|
2500
|
+
if (succeededCount > 0) p.log.warn(`${succeededCount} app(s) were applied to preview but may not have been deployed. Check their status in kintone.`);
|
|
2501
|
+
throw new SystemError(SystemErrorCode.ExecutionError, "Execution stopped due to failure.");
|
|
2502
|
+
}
|
|
2359
2503
|
if (successMessage) p.log.success(successMessage);
|
|
2360
2504
|
}
|
|
2361
2505
|
async function configFileExists(configPath) {
|
|
@@ -2482,12 +2626,13 @@ var apply_default$12 = define({
|
|
|
2482
2626
|
},
|
|
2483
2627
|
multiApp: async (plan, projectConfig) => {
|
|
2484
2628
|
const containers = [];
|
|
2485
|
-
await
|
|
2486
|
-
const
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2629
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
2630
|
+
const container = await runAction(resolveActionAppContainerConfig(app, projectConfig, values));
|
|
2631
|
+
containers.push({
|
|
2632
|
+
appDeployer: container.appDeployer,
|
|
2633
|
+
appName: app.name
|
|
2634
|
+
});
|
|
2635
|
+
});
|
|
2491
2636
|
await confirmAndDeploy(containers, skipConfirm);
|
|
2492
2637
|
}
|
|
2493
2638
|
});
|
|
@@ -2936,9 +3081,7 @@ var KintoneAdminNotesConfigurator = class {
|
|
|
2936
3081
|
revision: response.revision
|
|
2937
3082
|
};
|
|
2938
3083
|
} catch (error) {
|
|
2939
|
-
|
|
2940
|
-
if (error instanceof SystemError) throw error;
|
|
2941
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get admin notes", error);
|
|
3084
|
+
throw wrapKintoneError(error, "Failed to get admin notes");
|
|
2942
3085
|
}
|
|
2943
3086
|
}
|
|
2944
3087
|
async updateAdminNotes(params) {
|
|
@@ -2951,9 +3094,7 @@ var KintoneAdminNotesConfigurator = class {
|
|
|
2951
3094
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
2952
3095
|
return { revision: (await this.client.app.updateAdminNotes(requestParams)).revision };
|
|
2953
3096
|
} catch (error) {
|
|
2954
|
-
|
|
2955
|
-
if (error instanceof SystemError) throw error;
|
|
2956
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update admin notes", error);
|
|
3097
|
+
throw wrapKintoneError(error, "Failed to update admin notes");
|
|
2957
3098
|
}
|
|
2958
3099
|
}
|
|
2959
3100
|
};
|
|
@@ -3028,12 +3169,13 @@ var apply_default$11 = define({
|
|
|
3028
3169
|
},
|
|
3029
3170
|
multiApp: async (plan, projectConfig) => {
|
|
3030
3171
|
const containers = [];
|
|
3031
|
-
await
|
|
3032
|
-
const
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3172
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
3173
|
+
const container = await runAdminNotes(resolveAdminNotesAppContainerConfig(app, projectConfig, values));
|
|
3174
|
+
containers.push({
|
|
3175
|
+
appDeployer: container.appDeployer,
|
|
3176
|
+
appName: app.name
|
|
3177
|
+
});
|
|
3178
|
+
});
|
|
3037
3179
|
await confirmAndDeploy(containers, skipConfirm);
|
|
3038
3180
|
}
|
|
3039
3181
|
});
|
|
@@ -3303,9 +3445,7 @@ var KintoneAppPermissionConfigurator = class {
|
|
|
3303
3445
|
revision: response.revision
|
|
3304
3446
|
};
|
|
3305
3447
|
} catch (error) {
|
|
3306
|
-
|
|
3307
|
-
if (error instanceof SystemError) throw error;
|
|
3308
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get app ACL", error);
|
|
3448
|
+
throw wrapKintoneError(error, "Failed to get app ACL");
|
|
3309
3449
|
}
|
|
3310
3450
|
}
|
|
3311
3451
|
async updateAppPermissions(params) {
|
|
@@ -3317,9 +3457,7 @@ var KintoneAppPermissionConfigurator = class {
|
|
|
3317
3457
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
3318
3458
|
return { revision: (await this.client.app.updateAppAcl(requestParams)).revision };
|
|
3319
3459
|
} catch (error) {
|
|
3320
|
-
|
|
3321
|
-
if (error instanceof SystemError) throw error;
|
|
3322
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update app ACL", error);
|
|
3460
|
+
throw wrapKintoneError(error, "Failed to update app ACL");
|
|
3323
3461
|
}
|
|
3324
3462
|
}
|
|
3325
3463
|
};
|
|
@@ -3394,12 +3532,13 @@ var apply_default$10 = define({
|
|
|
3394
3532
|
},
|
|
3395
3533
|
multiApp: async (plan, projectConfig) => {
|
|
3396
3534
|
const containers = [];
|
|
3397
|
-
await
|
|
3398
|
-
const
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3535
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
3536
|
+
const container = await runAppAcl(resolveAppAclAppContainerConfig(app, projectConfig, values));
|
|
3537
|
+
containers.push({
|
|
3538
|
+
appDeployer: container.appDeployer,
|
|
3539
|
+
appName: app.name
|
|
3540
|
+
});
|
|
3541
|
+
});
|
|
3403
3542
|
await confirmAndDeploy(containers, skipConfirm);
|
|
3404
3543
|
}
|
|
3405
3544
|
});
|
|
@@ -4021,12 +4160,13 @@ var apply_default$9 = define({
|
|
|
4021
4160
|
},
|
|
4022
4161
|
multiApp: async (plan, projectConfig) => {
|
|
4023
4162
|
const containers = [];
|
|
4024
|
-
await
|
|
4025
|
-
const
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4163
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
4164
|
+
const container = await applyCustomizationForApp(resolveCustomizeAppConfig(app, projectConfig, values));
|
|
4165
|
+
containers.push({
|
|
4166
|
+
appDeployer: container.appDeployer,
|
|
4167
|
+
appName: app.name
|
|
4168
|
+
});
|
|
4169
|
+
});
|
|
4030
4170
|
await confirmAndDeploy(containers, skipConfirm, "Customization applied and deployed successfully.");
|
|
4031
4171
|
}
|
|
4032
4172
|
});
|
|
@@ -4212,9 +4352,7 @@ var KintoneFieldPermissionConfigurator = class {
|
|
|
4212
4352
|
revision: response.revision
|
|
4213
4353
|
};
|
|
4214
4354
|
} catch (error) {
|
|
4215
|
-
|
|
4216
|
-
if (error instanceof SystemError) throw error;
|
|
4217
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get field ACL", error);
|
|
4355
|
+
throw wrapKintoneError(error, "Failed to get field ACL");
|
|
4218
4356
|
}
|
|
4219
4357
|
}
|
|
4220
4358
|
async updateFieldPermissions(params) {
|
|
@@ -4226,9 +4364,7 @@ var KintoneFieldPermissionConfigurator = class {
|
|
|
4226
4364
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4227
4365
|
return { revision: (await this.client.app.updateFieldAcl(requestParams)).revision };
|
|
4228
4366
|
} catch (error) {
|
|
4229
|
-
|
|
4230
|
-
if (error instanceof SystemError) throw error;
|
|
4231
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update field ACL", error);
|
|
4367
|
+
throw wrapKintoneError(error, "Failed to update field ACL");
|
|
4232
4368
|
}
|
|
4233
4369
|
}
|
|
4234
4370
|
};
|
|
@@ -4384,12 +4520,13 @@ var apply_default$8 = define({
|
|
|
4384
4520
|
},
|
|
4385
4521
|
multiApp: async (plan, projectConfig) => {
|
|
4386
4522
|
const containers = [];
|
|
4387
|
-
await
|
|
4388
|
-
const
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4523
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
4524
|
+
const container = await runFieldAcl(resolveFieldAclAppContainerConfig(app, projectConfig, values));
|
|
4525
|
+
containers.push({
|
|
4526
|
+
appDeployer: container.appDeployer,
|
|
4527
|
+
appName: app.name
|
|
4528
|
+
});
|
|
4529
|
+
});
|
|
4393
4530
|
await confirmAndDeploy(containers, skipConfirm);
|
|
4394
4531
|
}
|
|
4395
4532
|
});
|
|
@@ -4557,6 +4694,14 @@ var field_acl_default = define({
|
|
|
4557
4694
|
run: () => {}
|
|
4558
4695
|
});
|
|
4559
4696
|
|
|
4697
|
+
//#endregion
|
|
4698
|
+
//#region src/core/adapters/kintone/parseKintoneIntegerField.ts
|
|
4699
|
+
function parseKintoneIntegerField(raw, fieldName) {
|
|
4700
|
+
const n = Number(raw);
|
|
4701
|
+
if (!Number.isFinite(n) || !Number.isInteger(n)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-integer ${fieldName} from kintone API: ${raw}`);
|
|
4702
|
+
return n;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4560
4705
|
//#endregion
|
|
4561
4706
|
//#region src/core/adapters/kintone/generalSettingsConfigurator.ts
|
|
4562
4707
|
const VALID_THEMES$1 = new Set([
|
|
@@ -4601,8 +4746,8 @@ function fromKintoneTitleField(raw) {
|
|
|
4601
4746
|
function fromKintoneNumberPrecision(raw) {
|
|
4602
4747
|
if (!VALID_ROUNDING_MODES$1.has(raw.roundingMode)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected roundingMode from kintone API: ${raw.roundingMode}`);
|
|
4603
4748
|
return {
|
|
4604
|
-
digits:
|
|
4605
|
-
decimalPlaces:
|
|
4749
|
+
digits: parseKintoneIntegerField(raw.digits, "digits"),
|
|
4750
|
+
decimalPlaces: parseKintoneIntegerField(raw.decimalPlaces, "decimalPlaces"),
|
|
4606
4751
|
roundingMode: raw.roundingMode
|
|
4607
4752
|
};
|
|
4608
4753
|
}
|
|
@@ -4620,7 +4765,7 @@ function fromKintoneSettings(raw) {
|
|
|
4620
4765
|
...raw.enableDuplicateRecord !== void 0 ? { enableDuplicateRecord: raw.enableDuplicateRecord } : {},
|
|
4621
4766
|
...raw.enableInlineRecordEditing !== void 0 ? { enableInlineRecordEditing: raw.enableInlineRecordEditing } : {},
|
|
4622
4767
|
...raw.numberPrecision !== void 0 ? { numberPrecision: fromKintoneNumberPrecision(raw.numberPrecision) } : {},
|
|
4623
|
-
...raw.firstMonthOfFiscalYear !== void 0 ? { firstMonthOfFiscalYear:
|
|
4768
|
+
...raw.firstMonthOfFiscalYear !== void 0 ? { firstMonthOfFiscalYear: parseKintoneIntegerField(raw.firstMonthOfFiscalYear, "firstMonthOfFiscalYear") } : {}
|
|
4624
4769
|
};
|
|
4625
4770
|
}
|
|
4626
4771
|
function toKintoneIcon(icon) {
|
|
@@ -4673,9 +4818,7 @@ var KintoneGeneralSettingsConfigurator = class {
|
|
|
4673
4818
|
revision: raw.revision ?? "-1"
|
|
4674
4819
|
};
|
|
4675
4820
|
} catch (error) {
|
|
4676
|
-
|
|
4677
|
-
if (error instanceof SystemError) throw error;
|
|
4678
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get general settings", error);
|
|
4821
|
+
throw wrapKintoneError(error, "Failed to get general settings");
|
|
4679
4822
|
}
|
|
4680
4823
|
}
|
|
4681
4824
|
async updateGeneralSettings(params) {
|
|
@@ -4687,9 +4830,7 @@ var KintoneGeneralSettingsConfigurator = class {
|
|
|
4687
4830
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4688
4831
|
return { revision: (await this.client.app.updateAppSettings(requestParams)).revision };
|
|
4689
4832
|
} catch (error) {
|
|
4690
|
-
|
|
4691
|
-
if (error instanceof SystemError) throw error;
|
|
4692
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update general settings", error);
|
|
4833
|
+
throw wrapKintoneError(error, "Failed to update general settings");
|
|
4693
4834
|
}
|
|
4694
4835
|
}
|
|
4695
4836
|
};
|
|
@@ -4764,8 +4905,7 @@ function fromKintonePerRecordNotification(raw) {
|
|
|
4764
4905
|
};
|
|
4765
4906
|
}
|
|
4766
4907
|
function fromKintoneReminderNotification(raw) {
|
|
4767
|
-
const daysLater =
|
|
4768
|
-
if (!Number.isFinite(daysLater)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric daysLater from kintone API: ${raw.timing.daysLater}`);
|
|
4908
|
+
const daysLater = parseKintoneIntegerField(raw.timing.daysLater, "daysLater");
|
|
4769
4909
|
const result = {
|
|
4770
4910
|
code: raw.timing.code,
|
|
4771
4911
|
daysLater,
|
|
@@ -4774,8 +4914,7 @@ function fromKintoneReminderNotification(raw) {
|
|
|
4774
4914
|
targets: raw.targets.map(fromKintoneTarget)
|
|
4775
4915
|
};
|
|
4776
4916
|
if ("hoursLater" in raw.timing) {
|
|
4777
|
-
const hoursLater =
|
|
4778
|
-
if (!Number.isFinite(hoursLater)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric hoursLater from kintone API: ${raw.timing.hoursLater}`);
|
|
4917
|
+
const hoursLater = parseKintoneIntegerField(raw.timing.hoursLater, "hoursLater");
|
|
4779
4918
|
return {
|
|
4780
4919
|
...result,
|
|
4781
4920
|
hoursLater
|
|
@@ -4850,9 +4989,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4850
4989
|
revision: response.revision
|
|
4851
4990
|
};
|
|
4852
4991
|
} catch (error) {
|
|
4853
|
-
|
|
4854
|
-
if (error instanceof SystemError) throw error;
|
|
4855
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get general notifications", error);
|
|
4992
|
+
throw wrapKintoneError(error, "Failed to get general notifications");
|
|
4856
4993
|
}
|
|
4857
4994
|
}
|
|
4858
4995
|
async updateGeneralNotifications(params) {
|
|
@@ -4865,9 +5002,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4865
5002
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4866
5003
|
return { revision: (await this.client.app.updateGeneralNotifications(requestParams)).revision };
|
|
4867
5004
|
} catch (error) {
|
|
4868
|
-
|
|
4869
|
-
if (error instanceof SystemError) throw error;
|
|
4870
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update general notifications", error);
|
|
5005
|
+
throw wrapKintoneError(error, "Failed to update general notifications");
|
|
4871
5006
|
}
|
|
4872
5007
|
}
|
|
4873
5008
|
async getPerRecordNotifications() {
|
|
@@ -4881,9 +5016,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4881
5016
|
revision: response.revision
|
|
4882
5017
|
};
|
|
4883
5018
|
} catch (error) {
|
|
4884
|
-
|
|
4885
|
-
if (error instanceof SystemError) throw error;
|
|
4886
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get per-record notifications", error);
|
|
5019
|
+
throw wrapKintoneError(error, "Failed to get per-record notifications");
|
|
4887
5020
|
}
|
|
4888
5021
|
}
|
|
4889
5022
|
async updatePerRecordNotifications(params) {
|
|
@@ -4895,9 +5028,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4895
5028
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4896
5029
|
return { revision: (await this.client.app.updatePerRecordNotifications(requestParams)).revision };
|
|
4897
5030
|
} catch (error) {
|
|
4898
|
-
|
|
4899
|
-
if (error instanceof SystemError) throw error;
|
|
4900
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update per-record notifications", error);
|
|
5031
|
+
throw wrapKintoneError(error, "Failed to update per-record notifications");
|
|
4901
5032
|
}
|
|
4902
5033
|
}
|
|
4903
5034
|
async getReminderNotifications() {
|
|
@@ -4913,9 +5044,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4913
5044
|
revision: response.revision
|
|
4914
5045
|
};
|
|
4915
5046
|
} catch (error) {
|
|
4916
|
-
|
|
4917
|
-
if (error instanceof SystemError) throw error;
|
|
4918
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get reminder notifications", error);
|
|
5047
|
+
throw wrapKintoneError(error, "Failed to get reminder notifications");
|
|
4919
5048
|
}
|
|
4920
5049
|
}
|
|
4921
5050
|
async updateReminderNotifications(params) {
|
|
@@ -4928,9 +5057,7 @@ var KintoneNotificationConfigurator = class {
|
|
|
4928
5057
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
4929
5058
|
return { revision: (await this.client.app.updateReminderNotifications(requestParams)).revision };
|
|
4930
5059
|
} catch (error) {
|
|
4931
|
-
|
|
4932
|
-
if (error instanceof SystemError) throw error;
|
|
4933
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update reminder notifications", error);
|
|
5060
|
+
throw wrapKintoneError(error, "Failed to update reminder notifications");
|
|
4934
5061
|
}
|
|
4935
5062
|
}
|
|
4936
5063
|
};
|
|
@@ -4974,22 +5101,18 @@ var KintonePluginConfigurator = class {
|
|
|
4974
5101
|
revision: response.revision
|
|
4975
5102
|
};
|
|
4976
5103
|
} catch (error) {
|
|
4977
|
-
|
|
4978
|
-
if (error instanceof SystemError) throw error;
|
|
4979
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get plugins", error);
|
|
5104
|
+
throw wrapKintoneError(error, "Failed to get plugins");
|
|
4980
5105
|
}
|
|
4981
5106
|
}
|
|
4982
5107
|
async addPlugins(params) {
|
|
4983
5108
|
try {
|
|
4984
5109
|
return { revision: (await this.client.app.addPlugins({
|
|
4985
5110
|
app: this.appId,
|
|
4986
|
-
ids: params.ids,
|
|
5111
|
+
ids: [...params.ids],
|
|
4987
5112
|
revision: params.revision
|
|
4988
5113
|
})).revision };
|
|
4989
5114
|
} catch (error) {
|
|
4990
|
-
|
|
4991
|
-
if (error instanceof SystemError) throw error;
|
|
4992
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to add plugins", error);
|
|
5115
|
+
throw wrapKintoneError(error, "Failed to add plugins");
|
|
4993
5116
|
}
|
|
4994
5117
|
}
|
|
4995
5118
|
};
|
|
@@ -5122,9 +5245,7 @@ var KintoneProcessManagementConfigurator = class {
|
|
|
5122
5245
|
revision: response.revision
|
|
5123
5246
|
};
|
|
5124
5247
|
} catch (error) {
|
|
5125
|
-
|
|
5126
|
-
if (error instanceof SystemError) throw error;
|
|
5127
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get process management settings", error);
|
|
5248
|
+
throw wrapKintoneError(error, "Failed to get process management settings");
|
|
5128
5249
|
}
|
|
5129
5250
|
}
|
|
5130
5251
|
async updateProcessManagement(params) {
|
|
@@ -5140,9 +5261,7 @@ var KintoneProcessManagementConfigurator = class {
|
|
|
5140
5261
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5141
5262
|
return { revision: (await this.client.app.updateProcessManagement(requestParams)).revision };
|
|
5142
5263
|
} catch (error) {
|
|
5143
|
-
|
|
5144
|
-
if (error instanceof SystemError) throw error;
|
|
5145
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update process management settings", error);
|
|
5264
|
+
throw wrapKintoneError(error, "Failed to update process management settings");
|
|
5146
5265
|
}
|
|
5147
5266
|
}
|
|
5148
5267
|
};
|
|
@@ -5225,9 +5344,7 @@ var KintoneRecordPermissionConfigurator = class {
|
|
|
5225
5344
|
revision: response.revision
|
|
5226
5345
|
};
|
|
5227
5346
|
} catch (error) {
|
|
5228
|
-
|
|
5229
|
-
if (error instanceof SystemError) throw error;
|
|
5230
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get record ACL", error);
|
|
5347
|
+
throw wrapKintoneError(error, "Failed to get record ACL");
|
|
5231
5348
|
}
|
|
5232
5349
|
}
|
|
5233
5350
|
async updateRecordPermissions(params) {
|
|
@@ -5239,9 +5356,7 @@ var KintoneRecordPermissionConfigurator = class {
|
|
|
5239
5356
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5240
5357
|
return { revision: (await this.client.app.updateRecordAcl(requestParams)).revision };
|
|
5241
5358
|
} catch (error) {
|
|
5242
|
-
|
|
5243
|
-
if (error instanceof SystemError) throw error;
|
|
5244
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update record ACL", error);
|
|
5359
|
+
throw wrapKintoneError(error, "Failed to update record ACL");
|
|
5245
5360
|
}
|
|
5246
5361
|
}
|
|
5247
5362
|
};
|
|
@@ -5514,9 +5629,7 @@ var KintoneReportConfigurator = class {
|
|
|
5514
5629
|
revision: response.revision
|
|
5515
5630
|
};
|
|
5516
5631
|
} catch (error) {
|
|
5517
|
-
|
|
5518
|
-
if (error instanceof SystemError) throw error;
|
|
5519
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get reports", error);
|
|
5632
|
+
throw wrapKintoneError(error, "Failed to get reports");
|
|
5520
5633
|
}
|
|
5521
5634
|
}
|
|
5522
5635
|
async updateReports(params) {
|
|
@@ -5530,9 +5643,7 @@ var KintoneReportConfigurator = class {
|
|
|
5530
5643
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5531
5644
|
return { revision: (await this.client.app.updateReports(requestParams)).revision };
|
|
5532
5645
|
} catch (error) {
|
|
5533
|
-
|
|
5534
|
-
if (error instanceof SystemError) throw error;
|
|
5535
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update reports", error);
|
|
5646
|
+
throw wrapKintoneError(error, "Failed to update reports");
|
|
5536
5647
|
}
|
|
5537
5648
|
}
|
|
5538
5649
|
};
|
|
@@ -5582,21 +5693,17 @@ function fromKintoneView(name, raw) {
|
|
|
5582
5693
|
}
|
|
5583
5694
|
return {
|
|
5584
5695
|
type: raw.type,
|
|
5585
|
-
index: (
|
|
5586
|
-
const idx = typeof raw.index === "string" ? Number(raw.index) : raw.index;
|
|
5587
|
-
if (!Number.isFinite(idx)) throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected non-numeric index from kintone API: ${raw.index}`);
|
|
5588
|
-
return idx;
|
|
5589
|
-
})(),
|
|
5696
|
+
index: parseKintoneIntegerField(raw.index, "index"),
|
|
5590
5697
|
name,
|
|
5591
|
-
...raw.builtinType !== void 0
|
|
5592
|
-
...raw.fields !== void 0
|
|
5593
|
-
...raw.date !== void 0
|
|
5594
|
-
...raw.title !== void 0
|
|
5595
|
-
...raw.html !== void 0
|
|
5596
|
-
...raw.pager !== void 0
|
|
5597
|
-
...device !== void 0
|
|
5598
|
-
...raw.filterCond !== void 0
|
|
5599
|
-
...raw.sort !== void 0
|
|
5698
|
+
...raw.builtinType !== void 0 ? { builtinType: raw.builtinType } : {},
|
|
5699
|
+
...raw.fields !== void 0 ? { fields: raw.fields } : {},
|
|
5700
|
+
...raw.date !== void 0 ? { date: raw.date } : {},
|
|
5701
|
+
...raw.title !== void 0 ? { title: raw.title } : {},
|
|
5702
|
+
...raw.html !== void 0 ? { html: raw.html } : {},
|
|
5703
|
+
...raw.pager !== void 0 ? { pager: raw.pager } : {},
|
|
5704
|
+
...device !== void 0 ? { device } : {},
|
|
5705
|
+
...raw.filterCond !== void 0 ? { filterCond: raw.filterCond } : {},
|
|
5706
|
+
...raw.sort !== void 0 ? { sort: raw.sort } : {}
|
|
5600
5707
|
};
|
|
5601
5708
|
}
|
|
5602
5709
|
function toKintoneView(config) {
|
|
@@ -5636,9 +5743,7 @@ var KintoneViewConfigurator = class {
|
|
|
5636
5743
|
revision: response.revision
|
|
5637
5744
|
};
|
|
5638
5745
|
} catch (error) {
|
|
5639
|
-
|
|
5640
|
-
if (error instanceof SystemError) throw error;
|
|
5641
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to get views", error);
|
|
5746
|
+
throw wrapKintoneError(error, "Failed to get views");
|
|
5642
5747
|
}
|
|
5643
5748
|
}
|
|
5644
5749
|
async updateViews(params) {
|
|
@@ -5652,9 +5757,7 @@ var KintoneViewConfigurator = class {
|
|
|
5652
5757
|
if (params.revision !== void 0) requestParams.revision = params.revision;
|
|
5653
5758
|
return { revision: (await this.client.app.updateViews(requestParams)).revision };
|
|
5654
5759
|
} catch (error) {
|
|
5655
|
-
|
|
5656
|
-
if (error instanceof SystemError) throw error;
|
|
5657
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to update views", error);
|
|
5760
|
+
throw wrapKintoneError(error, "Failed to update views");
|
|
5658
5761
|
}
|
|
5659
5762
|
}
|
|
5660
5763
|
};
|
|
@@ -5770,7 +5873,7 @@ var KintoneSpaceReader = class {
|
|
|
5770
5873
|
this.client = client;
|
|
5771
5874
|
}
|
|
5772
5875
|
async getSpaceApps(spaceId) {
|
|
5773
|
-
if (!spaceId) throw new
|
|
5876
|
+
if (!spaceId) throw new ValidationError(ValidationErrorCode.InvalidInput, "spaceId must not be empty");
|
|
5774
5877
|
try {
|
|
5775
5878
|
const rawApps = (await this.client.space.getSpace({ id: spaceId })).attachedApps;
|
|
5776
5879
|
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.`);
|
|
@@ -5789,9 +5892,7 @@ var KintoneSpaceReader = class {
|
|
|
5789
5892
|
}
|
|
5790
5893
|
return result;
|
|
5791
5894
|
} catch (error) {
|
|
5792
|
-
|
|
5793
|
-
if (error instanceof SystemError) throw error;
|
|
5794
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, `Failed to get space info for space ID: ${spaceId}`, error);
|
|
5895
|
+
throw wrapKintoneError(error, `Failed to get space info for space ID: ${spaceId}`);
|
|
5795
5896
|
}
|
|
5796
5897
|
}
|
|
5797
5898
|
};
|
|
@@ -6638,7 +6739,7 @@ var init_default = define({
|
|
|
6638
6739
|
try {
|
|
6639
6740
|
const values = ctx.values;
|
|
6640
6741
|
const spaceId = values["space-id"];
|
|
6641
|
-
if (
|
|
6742
|
+
if (!/^[1-9]\d*$/.test(spaceId)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Invalid space ID: "${spaceId}" (must be a positive integer, e.g. 1, 42, 100)`);
|
|
6642
6743
|
const kintoneDomain = values.domain ?? process.env.KINTONE_DOMAIN;
|
|
6643
6744
|
if (!kintoneDomain) throw new ValidationError(ValidationErrorCode.InvalidInput, "Missing required configuration:\n KINTONE_DOMAIN is required");
|
|
6644
6745
|
const apiToken = values["api-token"] ?? process.env.KINTONE_API_TOKEN;
|
|
@@ -6941,12 +7042,13 @@ var apply_default$7 = define({
|
|
|
6941
7042
|
},
|
|
6942
7043
|
multiApp: async (plan, projectConfig) => {
|
|
6943
7044
|
const containers = [];
|
|
6944
|
-
await
|
|
6945
|
-
const
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
7045
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
7046
|
+
const container = await runNotification(resolveNotificationAppContainerConfig(app, projectConfig, values));
|
|
7047
|
+
containers.push({
|
|
7048
|
+
appDeployer: container.appDeployer,
|
|
7049
|
+
appName: app.name
|
|
7050
|
+
});
|
|
7051
|
+
});
|
|
6950
7052
|
await confirmAndDeploy(containers, skipConfirm);
|
|
6951
7053
|
}
|
|
6952
7054
|
});
|
|
@@ -7360,12 +7462,13 @@ var apply_default$6 = define({
|
|
|
7360
7462
|
},
|
|
7361
7463
|
multiApp: async (plan, projectConfig) => {
|
|
7362
7464
|
const containers = [];
|
|
7363
|
-
await
|
|
7364
|
-
const
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7465
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
7466
|
+
const container = await runPlugin(resolvePluginAppContainerConfig(app, projectConfig, values));
|
|
7467
|
+
containers.push({
|
|
7468
|
+
appDeployer: container.appDeployer,
|
|
7469
|
+
appName: app.name
|
|
7470
|
+
});
|
|
7471
|
+
});
|
|
7369
7472
|
await confirmAndDeploy(containers, skipConfirm);
|
|
7370
7473
|
}
|
|
7371
7474
|
});
|
|
@@ -7668,12 +7771,13 @@ var apply_default$5 = define({
|
|
|
7668
7771
|
},
|
|
7669
7772
|
multiApp: async (plan, projectConfig) => {
|
|
7670
7773
|
const containers = [];
|
|
7671
|
-
await
|
|
7672
|
-
const
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7774
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
7775
|
+
const container = await runProcessApply(resolveProcessAppContainerConfig(app, projectConfig, values));
|
|
7776
|
+
containers.push({
|
|
7777
|
+
appDeployer: container.appDeployer,
|
|
7778
|
+
appName: app.name
|
|
7779
|
+
});
|
|
7780
|
+
});
|
|
7677
7781
|
await confirmAndDeploy(containers, skipConfirm);
|
|
7678
7782
|
}
|
|
7679
7783
|
});
|
|
@@ -7991,12 +8095,13 @@ var apply_default$4 = define({
|
|
|
7991
8095
|
},
|
|
7992
8096
|
multiApp: async (plan, projectConfig) => {
|
|
7993
8097
|
const containers = [];
|
|
7994
|
-
await
|
|
7995
|
-
const
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8098
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
8099
|
+
const container = await runRecordAcl(resolveRecordAclAppContainerConfig(app, projectConfig, values));
|
|
8100
|
+
containers.push({
|
|
8101
|
+
appDeployer: container.appDeployer,
|
|
8102
|
+
appName: app.name
|
|
8103
|
+
});
|
|
8104
|
+
});
|
|
8000
8105
|
await confirmAndDeploy(containers, skipConfirm);
|
|
8001
8106
|
}
|
|
8002
8107
|
});
|
|
@@ -8377,12 +8482,13 @@ var apply_default$3 = define({
|
|
|
8377
8482
|
},
|
|
8378
8483
|
multiApp: async (plan, projectConfig) => {
|
|
8379
8484
|
const containers = [];
|
|
8380
|
-
await
|
|
8381
|
-
const
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8485
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
8486
|
+
const container = await runReport(resolveReportAppContainerConfig(app, projectConfig, values));
|
|
8487
|
+
containers.push({
|
|
8488
|
+
appDeployer: container.appDeployer,
|
|
8489
|
+
appName: app.name
|
|
8490
|
+
});
|
|
8491
|
+
});
|
|
8386
8492
|
await confirmAndDeploy(containers, skipConfirm);
|
|
8387
8493
|
}
|
|
8388
8494
|
});
|
|
@@ -9167,7 +9273,7 @@ async function detectDiff({ container }) {
|
|
|
9167
9273
|
//#region src/cli/commands/schema/diff.ts
|
|
9168
9274
|
async function runDiff(container) {
|
|
9169
9275
|
const s = p.spinner();
|
|
9170
|
-
s.start("
|
|
9276
|
+
s.start("Comparing schema...");
|
|
9171
9277
|
let result;
|
|
9172
9278
|
try {
|
|
9173
9279
|
result = await detectDiff({ container });
|
|
@@ -9175,7 +9281,7 @@ async function runDiff(container) {
|
|
|
9175
9281
|
s.stop("Comparison failed.");
|
|
9176
9282
|
throw error;
|
|
9177
9283
|
}
|
|
9178
|
-
s.stop("
|
|
9284
|
+
s.stop("Comparison complete.");
|
|
9179
9285
|
printDiffResult(result);
|
|
9180
9286
|
}
|
|
9181
9287
|
var diff_default$2 = define({
|
|
@@ -9217,15 +9323,19 @@ var KintoneFormDumpReader = class {
|
|
|
9217
9323
|
}
|
|
9218
9324
|
async getRawFormData() {
|
|
9219
9325
|
try {
|
|
9220
|
-
const [fields, layout] = await Promise.all([this.client.app.getFormFields({
|
|
9326
|
+
const [fields, layout] = await Promise.all([this.client.app.getFormFields({
|
|
9327
|
+
app: this.appId,
|
|
9328
|
+
preview: true
|
|
9329
|
+
}), this.client.app.getFormLayout({
|
|
9330
|
+
app: this.appId,
|
|
9331
|
+
preview: true
|
|
9332
|
+
})]);
|
|
9221
9333
|
return {
|
|
9222
9334
|
fields,
|
|
9223
9335
|
layout
|
|
9224
9336
|
};
|
|
9225
9337
|
} catch (error) {
|
|
9226
|
-
|
|
9227
|
-
if (error instanceof SystemError) throw error;
|
|
9228
|
-
throw new SystemError(SystemErrorCode.ExternalApiError, "Failed to fetch raw form data for dump", error);
|
|
9338
|
+
throw wrapKintoneError(error, "Failed to fetch raw form data for dump");
|
|
9229
9339
|
}
|
|
9230
9340
|
}
|
|
9231
9341
|
};
|
|
@@ -9233,11 +9343,16 @@ var KintoneFormDumpReader = class {
|
|
|
9233
9343
|
//#endregion
|
|
9234
9344
|
//#region src/core/adapters/local/dumpStorage.ts
|
|
9235
9345
|
var LocalFileDumpStorage = class {
|
|
9236
|
-
constructor(filePrefix) {
|
|
9346
|
+
constructor(filePrefix, baseDir = process.cwd()) {
|
|
9237
9347
|
this.filePrefix = filePrefix;
|
|
9348
|
+
this.baseDir = baseDir;
|
|
9349
|
+
const fieldsPath = resolve(this.baseDir, `${this.filePrefix}fields.json`);
|
|
9350
|
+
if (!isSafePath(fieldsPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${fieldsPath}" escapes base directory "${this.baseDir}"`);
|
|
9351
|
+
const layoutPath = resolve(this.baseDir, `${this.filePrefix}layout.json`);
|
|
9352
|
+
if (!isSafePath(layoutPath, this.baseDir)) throw new ValidationError(ValidationErrorCode.InvalidInput, `Path traversal detected: "${layoutPath}" escapes base directory "${this.baseDir}"`);
|
|
9238
9353
|
}
|
|
9239
9354
|
async saveFields(content) {
|
|
9240
|
-
const filePath = `${this.filePrefix}fields.json
|
|
9355
|
+
const filePath = resolve(this.baseDir, `${this.filePrefix}fields.json`);
|
|
9241
9356
|
try {
|
|
9242
9357
|
await mkdir(dirname(filePath), { recursive: true });
|
|
9243
9358
|
await writeFile(filePath, content, "utf-8");
|
|
@@ -9246,7 +9361,7 @@ var LocalFileDumpStorage = class {
|
|
|
9246
9361
|
}
|
|
9247
9362
|
}
|
|
9248
9363
|
async saveLayout(content) {
|
|
9249
|
-
const filePath = `${this.filePrefix}layout.json
|
|
9364
|
+
const filePath = resolve(this.baseDir, `${this.filePrefix}layout.json`);
|
|
9250
9365
|
try {
|
|
9251
9366
|
await mkdir(dirname(filePath), { recursive: true });
|
|
9252
9367
|
await writeFile(filePath, content, "utf-8");
|
|
@@ -9261,7 +9376,7 @@ var LocalFileDumpStorage = class {
|
|
|
9261
9376
|
function createDumpCliContainer(config) {
|
|
9262
9377
|
return {
|
|
9263
9378
|
formDumpReader: new KintoneFormDumpReader(config.client ?? createKintoneClient(config), config.appId),
|
|
9264
|
-
dumpStorage: new LocalFileDumpStorage(config.filePrefix)
|
|
9379
|
+
dumpStorage: new LocalFileDumpStorage(config.filePrefix, process.cwd())
|
|
9265
9380
|
};
|
|
9266
9381
|
}
|
|
9267
9382
|
|
|
@@ -9332,16 +9447,25 @@ var dump_default = define({
|
|
|
9332
9447
|
}
|
|
9333
9448
|
});
|
|
9334
9449
|
|
|
9450
|
+
//#endregion
|
|
9451
|
+
//#region src/core/application/formSchema/deployApp.ts
|
|
9452
|
+
async function deployApp({ container }) {
|
|
9453
|
+
await container.appDeployer.deploy();
|
|
9454
|
+
}
|
|
9455
|
+
|
|
9335
9456
|
//#endregion
|
|
9336
9457
|
//#region src/core/domain/formSchema/services/subtableFieldSplitter.ts
|
|
9337
9458
|
function splitSubtableInnerFields(desired, current) {
|
|
9338
9459
|
const newInnerFields = /* @__PURE__ */ new Map();
|
|
9339
9460
|
const existingInnerFields = /* @__PURE__ */ new Map();
|
|
9461
|
+
const deletedInnerFieldCodes = [];
|
|
9340
9462
|
for (const [code, def] of desired.properties.fields) if (current.properties.fields.has(code)) existingInnerFields.set(code, def);
|
|
9341
9463
|
else newInnerFields.set(code, def);
|
|
9464
|
+
for (const code of current.properties.fields.keys()) if (!desired.properties.fields.has(code)) deletedInnerFieldCodes.push(code);
|
|
9342
9465
|
return {
|
|
9343
9466
|
newInnerFields,
|
|
9344
|
-
existingInnerFields
|
|
9467
|
+
existingInnerFields,
|
|
9468
|
+
deletedInnerFieldCodes
|
|
9345
9469
|
};
|
|
9346
9470
|
}
|
|
9347
9471
|
|
|
@@ -9448,6 +9572,11 @@ function validateReferenceTableRelatedApp(field) {
|
|
|
9448
9572
|
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`)];
|
|
9449
9573
|
return [];
|
|
9450
9574
|
}
|
|
9575
|
+
function validateSubtableHasInnerFields(field) {
|
|
9576
|
+
if (field.type !== "SUBTABLE") return [];
|
|
9577
|
+
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`)];
|
|
9578
|
+
return [];
|
|
9579
|
+
}
|
|
9451
9580
|
const FIELD_VALIDATORS = [
|
|
9452
9581
|
validateLabelNonEmpty,
|
|
9453
9582
|
validateSelectionOptions,
|
|
@@ -9457,7 +9586,8 @@ const FIELD_VALIDATORS = [
|
|
|
9457
9586
|
validateFileThumbnailSize,
|
|
9458
9587
|
validateReferenceTableSize,
|
|
9459
9588
|
validateLookupStructure,
|
|
9460
|
-
validateReferenceTableRelatedApp
|
|
9589
|
+
validateReferenceTableRelatedApp,
|
|
9590
|
+
validateSubtableHasInnerFields
|
|
9461
9591
|
];
|
|
9462
9592
|
function validateField(field) {
|
|
9463
9593
|
return FIELD_VALIDATORS.flatMap((validator) => validator(field));
|
|
@@ -9506,6 +9636,7 @@ async function executeMigration({ container }) {
|
|
|
9506
9636
|
const deleted = diff.entries.filter((e) => e.type === "deleted");
|
|
9507
9637
|
const fieldsToAdd = [];
|
|
9508
9638
|
const fieldsToUpdate = [];
|
|
9639
|
+
const innerFieldsToDelete = [];
|
|
9509
9640
|
for (const entry of added) {
|
|
9510
9641
|
if (entry.after === void 0) continue;
|
|
9511
9642
|
if (subtableInnerCodes.has(entry.fieldCode)) continue;
|
|
@@ -9517,22 +9648,21 @@ async function executeMigration({ container }) {
|
|
|
9517
9648
|
const after = entry.after;
|
|
9518
9649
|
const before = entry.before;
|
|
9519
9650
|
if (after.type === "SUBTABLE" && before !== void 0 && before.type === "SUBTABLE") {
|
|
9520
|
-
const { newInnerFields, existingInnerFields } = splitSubtableInnerFields(after, before);
|
|
9521
|
-
if (newInnerFields.size > 0)
|
|
9522
|
-
...after,
|
|
9523
|
-
properties: { fields: newInnerFields }
|
|
9524
|
-
});
|
|
9651
|
+
const { newInnerFields, existingInnerFields, deletedInnerFieldCodes } = splitSubtableInnerFields(after, before);
|
|
9652
|
+
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}`);
|
|
9525
9653
|
if (existingInnerFields.size > 0) fieldsToUpdate.push({
|
|
9526
9654
|
...after,
|
|
9527
9655
|
properties: { fields: existingInnerFields }
|
|
9528
9656
|
});
|
|
9529
|
-
|
|
9657
|
+
for (const code of deletedInnerFieldCodes) innerFieldsToDelete.push(code);
|
|
9658
|
+
} 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.`);
|
|
9659
|
+
else fieldsToUpdate.push(after);
|
|
9530
9660
|
}
|
|
9531
9661
|
if (fieldsToAdd.length > 0) await container.formConfigurator.addFields(fieldsToAdd);
|
|
9532
9662
|
if (fieldsToUpdate.length > 0) await container.formConfigurator.updateFields(fieldsToUpdate);
|
|
9533
|
-
if (deleted.length > 0) {
|
|
9663
|
+
if (deleted.length > 0 || innerFieldsToDelete.length > 0) {
|
|
9534
9664
|
const currentSubtableInnerCodes = collectSubtableInnerFieldCodes(currentFields);
|
|
9535
|
-
const fieldCodes = deleted.filter((e) => !currentSubtableInnerCodes.has(e.fieldCode)).map((e) => e.fieldCode);
|
|
9665
|
+
const fieldCodes = [...deleted.filter((e) => !currentSubtableInnerCodes.has(e.fieldCode)).map((e) => e.fieldCode), ...innerFieldsToDelete];
|
|
9536
9666
|
if (fieldCodes.length > 0) await container.formConfigurator.deleteFields(fieldCodes);
|
|
9537
9667
|
}
|
|
9538
9668
|
if (hasLayoutChanges) await container.formConfigurator.updateLayout(schema.layout);
|
|
@@ -9562,7 +9692,7 @@ async function runSingleMigrate(container, skipConfirm) {
|
|
|
9562
9692
|
await executeMigration({ container });
|
|
9563
9693
|
ms.stop("Migration applied.");
|
|
9564
9694
|
p.log.success("Migration completed successfully.");
|
|
9565
|
-
await
|
|
9695
|
+
await confirmAndDeploy([container], skipConfirm);
|
|
9566
9696
|
}
|
|
9567
9697
|
var migrate_default = define({
|
|
9568
9698
|
name: "migrate",
|
|
@@ -9611,7 +9741,7 @@ var migrate_default = define({
|
|
|
9611
9741
|
}
|
|
9612
9742
|
await runMultiAppWithFailCheck(plan, async (app) => {
|
|
9613
9743
|
const entry = appContainers.find((a) => a.app.name === app.name);
|
|
9614
|
-
if (!entry)
|
|
9744
|
+
if (!entry) throw new SystemError(SystemErrorCode.InternalServerError, `App container not found for "${app.name}"`);
|
|
9615
9745
|
const { container, hasChanges } = entry;
|
|
9616
9746
|
printAppHeader(app.name, app.appId);
|
|
9617
9747
|
if (!hasChanges) {
|
|
@@ -9647,22 +9777,35 @@ async function forceOverrideForm({ container }) {
|
|
|
9647
9777
|
const toAdd = [];
|
|
9648
9778
|
const toUpdate = [];
|
|
9649
9779
|
const toDelete = [];
|
|
9780
|
+
const innerFieldsToDelete = [];
|
|
9650
9781
|
for (const [fieldCode, schemaDef] of schema.fields) {
|
|
9651
9782
|
if (subtableInnerCodes.has(fieldCode)) continue;
|
|
9652
9783
|
if (currentFields.has(fieldCode)) if (schemaDef.type === "SUBTABLE") {
|
|
9653
9784
|
const currentDef = currentFields.get(fieldCode);
|
|
9654
9785
|
if (currentDef !== void 0 && currentDef.type === "SUBTABLE") {
|
|
9655
|
-
const { newInnerFields, existingInnerFields } = splitSubtableInnerFields(schemaDef, currentDef);
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9786
|
+
const { newInnerFields, existingInnerFields, deletedInnerFieldCodes } = splitSubtableInnerFields(schemaDef, currentDef);
|
|
9787
|
+
const allInnerFieldsRemoved = existingInnerFields.size === 0 && deletedInnerFieldCodes.length > 0;
|
|
9788
|
+
if (newInnerFields.size > 0 || allInnerFieldsRemoved) {
|
|
9789
|
+
toDelete.push(fieldCode);
|
|
9790
|
+
toAdd.push(schemaDef);
|
|
9791
|
+
} else {
|
|
9792
|
+
toUpdate.push({
|
|
9793
|
+
...schemaDef,
|
|
9794
|
+
properties: { fields: existingInnerFields }
|
|
9795
|
+
});
|
|
9796
|
+
for (const code of deletedInnerFieldCodes) innerFieldsToDelete.push(code);
|
|
9797
|
+
}
|
|
9798
|
+
} else {
|
|
9799
|
+
toDelete.push(fieldCode);
|
|
9800
|
+
toAdd.push(schemaDef);
|
|
9801
|
+
}
|
|
9802
|
+
} else {
|
|
9803
|
+
const currentDef = currentFields.get(fieldCode);
|
|
9804
|
+
if (currentDef !== void 0 && currentDef.type !== schemaDef.type) {
|
|
9805
|
+
toDelete.push(fieldCode);
|
|
9806
|
+
toAdd.push(schemaDef);
|
|
9664
9807
|
} else toUpdate.push(schemaDef);
|
|
9665
|
-
}
|
|
9808
|
+
}
|
|
9666
9809
|
else toAdd.push(schemaDef);
|
|
9667
9810
|
}
|
|
9668
9811
|
const currentSubtableInnerCodes = collectSubtableInnerFieldCodes(currentFields);
|
|
@@ -9670,9 +9813,9 @@ async function forceOverrideForm({ container }) {
|
|
|
9670
9813
|
if (currentSubtableInnerCodes.has(fieldCode)) continue;
|
|
9671
9814
|
if (!schema.fields.has(fieldCode)) toDelete.push(fieldCode);
|
|
9672
9815
|
}
|
|
9816
|
+
if (toDelete.length > 0 || innerFieldsToDelete.length > 0) await container.formConfigurator.deleteFields([...toDelete, ...innerFieldsToDelete]);
|
|
9673
9817
|
if (toAdd.length > 0) await container.formConfigurator.addFields(toAdd);
|
|
9674
9818
|
if (toUpdate.length > 0) await container.formConfigurator.updateFields(toUpdate);
|
|
9675
|
-
if (toDelete.length > 0) await container.formConfigurator.deleteFields(toDelete);
|
|
9676
9819
|
await container.formConfigurator.updateLayout(schema.layout);
|
|
9677
9820
|
}
|
|
9678
9821
|
|
|
@@ -9707,7 +9850,7 @@ async function runSingleOverride(container, skipConfirm) {
|
|
|
9707
9850
|
await forceOverrideForm({ container });
|
|
9708
9851
|
s.stop("Force override applied.");
|
|
9709
9852
|
p.log.success("Force override completed successfully.");
|
|
9710
|
-
await
|
|
9853
|
+
await confirmAndDeploy([container], skipConfirm);
|
|
9711
9854
|
}
|
|
9712
9855
|
async function runSingleReset(container, skipConfirm) {
|
|
9713
9856
|
p.log.warn(`${pc.bold(pc.red("WARNING:"))} This will delete ALL custom fields, resetting the form to empty.`);
|
|
@@ -9723,7 +9866,7 @@ async function runSingleReset(container, skipConfirm) {
|
|
|
9723
9866
|
await resetForm({ container });
|
|
9724
9867
|
s.stop("Form reset applied.");
|
|
9725
9868
|
p.log.success("Reset completed successfully.");
|
|
9726
|
-
await
|
|
9869
|
+
await confirmAndDeploy([container], skipConfirm);
|
|
9727
9870
|
}
|
|
9728
9871
|
var override_default = define({
|
|
9729
9872
|
name: "override",
|
|
@@ -10436,12 +10579,13 @@ var apply_default$1 = define({
|
|
|
10436
10579
|
},
|
|
10437
10580
|
multiApp: async (plan, projectConfig) => {
|
|
10438
10581
|
const containers = [];
|
|
10439
|
-
await
|
|
10440
|
-
const
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10582
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
10583
|
+
const container = await runSettings(resolveSettingsAppContainerConfig(app, projectConfig, values));
|
|
10584
|
+
containers.push({
|
|
10585
|
+
appDeployer: container.appDeployer,
|
|
10586
|
+
appName: app.name
|
|
10587
|
+
});
|
|
10588
|
+
});
|
|
10445
10589
|
await confirmAndDeploy(containers, skipConfirm);
|
|
10446
10590
|
}
|
|
10447
10591
|
});
|
|
@@ -10723,12 +10867,13 @@ var apply_default = define({
|
|
|
10723
10867
|
},
|
|
10724
10868
|
multiApp: async (plan, projectConfig) => {
|
|
10725
10869
|
const containers = [];
|
|
10726
|
-
await
|
|
10727
|
-
const
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10870
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
10871
|
+
const container = await runView(resolveViewAppContainerConfig(app, projectConfig, values));
|
|
10872
|
+
containers.push({
|
|
10873
|
+
appDeployer: container.appDeployer,
|
|
10874
|
+
appName: app.name
|
|
10875
|
+
});
|
|
10876
|
+
});
|
|
10732
10877
|
await confirmAndDeploy(containers, skipConfirm);
|
|
10733
10878
|
}
|
|
10734
10879
|
});
|