@tailor-platform/sdk 1.32.1 → 1.33.0
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/CHANGELOG.md +37 -0
- package/dist/{application-p2GujXmg.mjs → application-CfAom-vi.mjs} +33 -25
- package/dist/application-CfAom-vi.mjs.map +1 -0
- package/dist/{application-Cwt_ifTT.mjs → application-ChVyhwe-.mjs} +4 -4
- package/dist/cli/index.mjs +9 -9
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +9 -6
- package/dist/cli/lib.mjs +7 -7
- package/dist/configure/index.d.mts +5 -5
- package/dist/configure/index.mjs +81 -11
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{enum-constants-CkKARYb7.mjs → enum-constants-Piv_E-2M.mjs} +2 -1
- package/dist/{enum-constants-CkKARYb7.mjs.map → enum-constants-Piv_E-2M.mjs.map} +1 -1
- package/dist/{env-BZLTIlIo.d.mts → env-CSZ9CKg7.d.mts} +2 -2
- package/dist/{file-utils-D2TxR_kj.mjs → file-utils-B7xME5IK.mjs} +2 -1
- package/dist/{file-utils-D2TxR_kj.mjs.map → file-utils-B7xME5IK.mjs.map} +1 -1
- package/dist/{index-BYk_9R3S.d.mts → index-BdlrrjvD.d.mts} +133 -24
- package/dist/{index-BQKAzTPA.d.mts → index-Dlpe_4Nd.d.mts} +3 -2
- package/dist/{index-vVGamLOw.d.mts → index-IHl7P_9I.d.mts} +3 -2
- package/dist/{index-CgMytw2A.d.mts → index-dg3Sf-No.d.mts} +3 -2
- package/dist/{index-CoReoodF.d.mts → index-uNv9YJgx.d.mts} +3 -2
- package/dist/{kysely-type-BK0b4Rqt.mjs → kysely-type-t5MbP7iJ.mjs} +2 -1
- package/dist/{kysely-type-BK0b4Rqt.mjs.map → kysely-type-t5MbP7iJ.mjs.map} +1 -1
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/enum-constants/index.mjs +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.mjs +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/index.d.mts +1 -1
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/index.d.mts +2 -2
- package/dist/{plugin-IIDZW9GG.d.mts → plugin-BC7WQrjm.d.mts} +24 -13
- package/dist/{runtime-7DOyTTxR.mjs → runtime-3P9JFpe9.mjs} +1018 -303
- package/dist/runtime-3P9JFpe9.mjs.map +1 -0
- package/dist/{schema-BITbkmq3.mjs → schema-D27cW0Ca.mjs} +2 -1
- package/dist/{schema-BITbkmq3.mjs.map → schema-D27cW0Ca.mjs.map} +1 -1
- package/dist/{seed-BXrSEJbv.mjs → seed-DtYgudLq.mjs} +11 -3
- package/dist/seed-DtYgudLq.mjs.map +1 -0
- package/dist/utils/test/index.d.mts +2 -2
- package/dist/{workflow.generated-C2A5Ye0m.d.mts → workflow.generated-Cd5dsFnf.d.mts} +2 -2
- package/docs/cli/application.md +17 -0
- package/docs/services/executor.md +54 -0
- package/package.json +8 -8
- package/dist/application-p2GujXmg.mjs.map +0 -1
- package/dist/runtime-7DOyTTxR.mjs.map +0 -1
- package/dist/seed-BXrSEJbv.mjs.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import { t as db } from "./schema-
|
|
2
|
+
import { t as db } from "./schema-D27cW0Ca.mjs";
|
|
3
3
|
import { i as symbols, n as logger, r as styles, t as CIPromptError } from "./logger-qz-Y4sBV.mjs";
|
|
4
4
|
import { A as ExecutorTriggerType, C as TailorDBType_PermitAction, E as FunctionExecution_Status, F as AuthOAuth2Client_GrantType, G as Condition_Operator, H as UserProfileProviderConfig_UserProfileProviderType, I as AuthSCIMAttribute_Mutability, J as ApplicationSchemaUpdateAttemptStatus, K as FilterSchema, L as AuthSCIMAttribute_Type, M as AuthIDPConfig_AuthType, N as AuthInvokerSchema, O as ExecutorJobStatus, P as AuthOAuth2Client_ClientType, R as AuthSCIMAttribute_Uniqueness, S as TailorDBType_Permission_Permit, T as IdPLang, U as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, V as TenantProviderConfig_TenantProviderType, W as ConditionSchema, Y as Subgraph_ServiceType, _ as WorkflowJobExecution_Status, a as fetchMachineUserToken, b as TailorDBGQLPermission_Permit, f as platformBaseUrl, g as WorkflowExecution_Status, h as WorkspacePlatformUserRole, i as fetchAll, j as AuthHookPoint, k as ExecutorTargetType, m as userAgent, p as resolveStaticWebsiteUrls, q as PageDirection, u as initOperatorClient, v as TailorDBGQLPermission_Action, w as PipelineResolver_OperationType, x as TailorDBType_Permission_Operator, y as TailorDBGQLPermission_Operator, z as AuthSCIMConfig_AuthorizationType } from "./client-D5P1myz0.mjs";
|
|
5
5
|
import { t as readPackageJson } from "./package-json-VqyFvGiP.mjs";
|
|
6
|
-
import { S as readPlatformConfig, T as writePlatformConfig, _ as hashFile, a as loadConfig, b as loadAccessToken, d as TailorDBTypeSchema, f as stringifyFunction, g as getDistDir, h as createBundleCache, l as OAuth2ClientSchema, m as loadFilesWithIgnores, n as generatePluginFilesIfNeeded, p as tailorUserMap, r as loadApplication, s as createExecutorService, t as defineApplication, x as loadWorkspaceId } from "./application-
|
|
6
|
+
import { S as readPlatformConfig, T as writePlatformConfig, _ as hashFile, a as loadConfig, b as loadAccessToken, d as TailorDBTypeSchema, f as stringifyFunction, g as getDistDir, h as createBundleCache, l as OAuth2ClientSchema, m as loadFilesWithIgnores, n as generatePluginFilesIfNeeded, p as tailorUserMap, r as loadApplication, s as createExecutorService, t as defineApplication, x as loadWorkspaceId } from "./application-CfAom-vi.mjs";
|
|
7
7
|
import { r as withSpan } from "./telemetry-B4sp-dD2.mjs";
|
|
8
8
|
import { arg, createDefineCommand, defineCommand, runCommand } from "politty";
|
|
9
9
|
import { z } from "zod";
|
|
@@ -891,6 +891,7 @@ function createChangeSet(title) {
|
|
|
891
891
|
const updates = [];
|
|
892
892
|
const deletes = [];
|
|
893
893
|
const replaces = [];
|
|
894
|
+
const unchanged = [];
|
|
894
895
|
const isEmpty = () => creates.length === 0 && updates.length === 0 && deletes.length === 0 && replaces.length === 0;
|
|
895
896
|
return {
|
|
896
897
|
title,
|
|
@@ -898,6 +899,7 @@ function createChangeSet(title) {
|
|
|
898
899
|
updates,
|
|
899
900
|
deletes,
|
|
900
901
|
replaces,
|
|
902
|
+
unchanged,
|
|
901
903
|
isEmpty,
|
|
902
904
|
print: () => {
|
|
903
905
|
if (isEmpty()) return;
|
|
@@ -909,6 +911,83 @@ function createChangeSet(title) {
|
|
|
909
911
|
}
|
|
910
912
|
};
|
|
911
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* Summarize resource counts across multiple change sets.
|
|
916
|
+
* @param changeSets - Change sets to aggregate
|
|
917
|
+
* @returns Aggregated plan counts by action
|
|
918
|
+
*/
|
|
919
|
+
function summarizeChangeSets(changeSets) {
|
|
920
|
+
const summary = {
|
|
921
|
+
create: 0,
|
|
922
|
+
update: 0,
|
|
923
|
+
delete: 0,
|
|
924
|
+
replace: 0,
|
|
925
|
+
unchanged: 0
|
|
926
|
+
};
|
|
927
|
+
for (const changeSet of changeSets) {
|
|
928
|
+
summary.create += changeSet.creates.length;
|
|
929
|
+
summary.update += changeSet.updates.length;
|
|
930
|
+
summary.delete += changeSet.deletes.length;
|
|
931
|
+
summary.replace += changeSet.replaces.length;
|
|
932
|
+
summary.unchanged += changeSet.unchanged.length;
|
|
933
|
+
}
|
|
934
|
+
return summary;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Format an aggregated plan summary for CLI output.
|
|
938
|
+
* @param summary - Aggregated plan counts
|
|
939
|
+
* @returns Human-readable plan summary line
|
|
940
|
+
*/
|
|
941
|
+
function formatPlanSummary(summary) {
|
|
942
|
+
const parts = [
|
|
943
|
+
`${summary.create} to create`,
|
|
944
|
+
`${summary.update} to update`,
|
|
945
|
+
`${summary.delete} to delete`
|
|
946
|
+
];
|
|
947
|
+
if (summary.replace > 0) parts.push(`${summary.replace} to replace`);
|
|
948
|
+
parts.push(`${summary.unchanged} unchanged`);
|
|
949
|
+
return `Plan: ${parts.join(", ")}`;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
//#endregion
|
|
953
|
+
//#region src/cli/commands/apply/compare.ts
|
|
954
|
+
/**
|
|
955
|
+
* Stable JSON-like serialization that sorts object keys and ignores proto runtime metadata.
|
|
956
|
+
* @param value - Value to serialize
|
|
957
|
+
* @returns Stable serialized string
|
|
958
|
+
*/
|
|
959
|
+
function stableStringify(value) {
|
|
960
|
+
if (Array.isArray(value)) return `[${value.map((item) => item === void 0 ? "null" : stableStringify(item)).join(",")}]`;
|
|
961
|
+
if (value && typeof value === "object") return `{${Object.entries(value).filter(([key, entryValue]) => key !== "$typeName" && entryValue !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableStringify(entryValue)}`).join(",")}}`;
|
|
962
|
+
if (typeof value === "bigint") return JSON.stringify(value.toString());
|
|
963
|
+
return JSON.stringify(value);
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Normalize a proto-ish object into a plain JSON-compatible structure for comparison.
|
|
967
|
+
* @param value - Value to normalize
|
|
968
|
+
* @returns Normalized value
|
|
969
|
+
*/
|
|
970
|
+
function normalizeProtoConfig(value) {
|
|
971
|
+
if (value === void 0 || value === null) return value;
|
|
972
|
+
return JSON.parse(stableStringify(value));
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Sort a string array for order-insensitive comparison.
|
|
976
|
+
* @param values - Values to sort
|
|
977
|
+
* @returns Sorted values
|
|
978
|
+
*/
|
|
979
|
+
function normalizeStringArray(values) {
|
|
980
|
+
return [...values ?? []].sort();
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Compare two values after proto normalization.
|
|
984
|
+
* @param left - Left value
|
|
985
|
+
* @param right - Right value
|
|
986
|
+
* @returns True when normalized values are equal
|
|
987
|
+
*/
|
|
988
|
+
function areNormalizedEqual(left, right) {
|
|
989
|
+
return stableStringify(normalizeProtoConfig(left)) === stableStringify(normalizeProtoConfig(right));
|
|
990
|
+
}
|
|
912
991
|
|
|
913
992
|
//#endregion
|
|
914
993
|
//#region src/cli/commands/apply/label.ts
|
|
@@ -921,6 +1000,16 @@ function trnPrefix(workspaceId) {
|
|
|
921
1000
|
return `trn:v1:workspace:${workspaceId}`;
|
|
922
1001
|
}
|
|
923
1002
|
const sdkNameLabelKey = "sdk-name";
|
|
1003
|
+
const sdkVersionLabelKey = "sdk-version";
|
|
1004
|
+
/**
|
|
1005
|
+
* Check whether existing metadata was produced by the current SDK version.
|
|
1006
|
+
* @param existingLabels - Labels currently stored on the remote resource
|
|
1007
|
+
* @param desiredLabels - Labels that will be written by the current apply run
|
|
1008
|
+
* @returns True when sdk-version matches
|
|
1009
|
+
*/
|
|
1010
|
+
function hasMatchingSdkVersion(existingLabels, desiredLabels) {
|
|
1011
|
+
return existingLabels?.[sdkVersionLabelKey] === desiredLabels?.[sdkVersionLabelKey];
|
|
1012
|
+
}
|
|
924
1013
|
/**
|
|
925
1014
|
* Build metadata request with SDK labels.
|
|
926
1015
|
* @param trn - Target TRN
|
|
@@ -936,7 +1025,7 @@ async function buildMetaRequest(trn, appName, existingLabels) {
|
|
|
936
1025
|
labels: {
|
|
937
1026
|
...existingLabels ?? {},
|
|
938
1027
|
[sdkNameLabelKey]: appName,
|
|
939
|
-
|
|
1028
|
+
[sdkVersionLabelKey]: sdkVersion
|
|
940
1029
|
}
|
|
941
1030
|
};
|
|
942
1031
|
}
|
|
@@ -967,6 +1056,54 @@ async function applyApplication(client, changeSet, phase = "create-update") {
|
|
|
967
1056
|
function trn$6(workspaceId, name) {
|
|
968
1057
|
return `trn:v1:workspace:${workspaceId}:application:${name}`;
|
|
969
1058
|
}
|
|
1059
|
+
function sortStrings(values) {
|
|
1060
|
+
return [...values ?? []].sort();
|
|
1061
|
+
}
|
|
1062
|
+
function normalizeSubgraphs(subgraphs) {
|
|
1063
|
+
return [...subgraphs ?? []].map((subgraph) => ({
|
|
1064
|
+
serviceType: subgraph.serviceType,
|
|
1065
|
+
serviceNamespace: subgraph.serviceNamespace ?? ""
|
|
1066
|
+
})).sort((left, right) => {
|
|
1067
|
+
if (left.serviceType !== right.serviceType) return left.serviceType - right.serviceType;
|
|
1068
|
+
return left.serviceNamespace.localeCompare(right.serviceNamespace);
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
function toComparableApplication(input) {
|
|
1072
|
+
return {
|
|
1073
|
+
authNamespace: input.authNamespace,
|
|
1074
|
+
authIdpConfigName: input.authIdpConfigName,
|
|
1075
|
+
cors: sortStrings(input.cors),
|
|
1076
|
+
subgraphs: [...input.subgraphs],
|
|
1077
|
+
allowedIpAddresses: sortStrings(input.allowedIpAddresses),
|
|
1078
|
+
disableIntrospection: input.disableIntrospection,
|
|
1079
|
+
disabled: input.disabled
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
function normalizeComparableApplication(application, authNamespace, authIdpConfigName, cors) {
|
|
1083
|
+
return toComparableApplication({
|
|
1084
|
+
authNamespace: authNamespace ?? "",
|
|
1085
|
+
authIdpConfigName: authIdpConfigName ?? "",
|
|
1086
|
+
cors,
|
|
1087
|
+
subgraphs: normalizeSubgraphs(application.subgraphs.map((subgraph) => protoSubgraph(subgraph))),
|
|
1088
|
+
allowedIpAddresses: application.config.allowedIpAddresses ?? [],
|
|
1089
|
+
disableIntrospection: application.config.disableIntrospection ?? false,
|
|
1090
|
+
disabled: false
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
function normalizeComparableExistingApplication(app) {
|
|
1094
|
+
return toComparableApplication({
|
|
1095
|
+
authNamespace: app.authNamespace,
|
|
1096
|
+
authIdpConfigName: app.authIdpConfigName,
|
|
1097
|
+
cors: app.cors,
|
|
1098
|
+
subgraphs: normalizeSubgraphs(app.subgraphs),
|
|
1099
|
+
allowedIpAddresses: app.allowedIpAddresses,
|
|
1100
|
+
disableIntrospection: app.disableIntrospection,
|
|
1101
|
+
disabled: app.disabled
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
function areApplicationsEqual(existing, desired) {
|
|
1105
|
+
return areNormalizedEqual(normalizeComparableExistingApplication(existing), desired);
|
|
1106
|
+
}
|
|
970
1107
|
/**
|
|
971
1108
|
* Plan application changes based on current and desired state.
|
|
972
1109
|
* @param context - Planning context
|
|
@@ -1028,32 +1165,30 @@ async function planApplication(context) {
|
|
|
1028
1165
|
if (idpConfigs.length > 0) authIdpConfigName = idpConfigs[0].name;
|
|
1029
1166
|
}
|
|
1030
1167
|
const metaRequest = await buildMetaRequest(trn$6(workspaceId, application.name), application.name);
|
|
1031
|
-
|
|
1168
|
+
const resolvedCors = await resolveStaticWebsiteUrls(client, workspaceId, application.config.cors, "CORS");
|
|
1169
|
+
const desired = normalizeComparableApplication(application, authNamespace, authIdpConfigName, resolvedCors);
|
|
1170
|
+
const request = {
|
|
1171
|
+
workspaceId,
|
|
1172
|
+
applicationName: application.name,
|
|
1173
|
+
authNamespace,
|
|
1174
|
+
authIdpConfigName,
|
|
1175
|
+
cors: application.config.cors,
|
|
1176
|
+
subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
1177
|
+
allowedIpAddresses: application.config.allowedIpAddresses,
|
|
1178
|
+
disableIntrospection: application.config.disableIntrospection
|
|
1179
|
+
};
|
|
1180
|
+
const existing = existingApplications.find((app) => app.name === application.name);
|
|
1181
|
+
if (existing) {
|
|
1182
|
+
const { metadata } = await client.getMetadata({ trn: trn$6(workspaceId, application.name) });
|
|
1183
|
+
if (metadata?.labels?.["sdk-name"] === application.name && hasMatchingSdkVersion(metadata?.labels, metaRequest.labels) && areApplicationsEqual(existing, desired)) changeSet.unchanged.push({ name: application.name });
|
|
1184
|
+
else changeSet.updates.push({
|
|
1185
|
+
name: application.name,
|
|
1186
|
+
request,
|
|
1187
|
+
metaRequest
|
|
1188
|
+
});
|
|
1189
|
+
} else changeSet.creates.push({
|
|
1032
1190
|
name: application.name,
|
|
1033
|
-
request
|
|
1034
|
-
workspaceId,
|
|
1035
|
-
applicationName: application.name,
|
|
1036
|
-
authNamespace,
|
|
1037
|
-
authIdpConfigName,
|
|
1038
|
-
cors: application.config.cors,
|
|
1039
|
-
subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
1040
|
-
allowedIpAddresses: application.config.allowedIpAddresses,
|
|
1041
|
-
disableIntrospection: application.config.disableIntrospection
|
|
1042
|
-
},
|
|
1043
|
-
metaRequest
|
|
1044
|
-
});
|
|
1045
|
-
else changeSet.creates.push({
|
|
1046
|
-
name: application.name,
|
|
1047
|
-
request: {
|
|
1048
|
-
workspaceId,
|
|
1049
|
-
applicationName: application.name,
|
|
1050
|
-
authNamespace,
|
|
1051
|
-
authIdpConfigName,
|
|
1052
|
-
cors: application.config.cors,
|
|
1053
|
-
subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
1054
|
-
allowedIpAddresses: application.config.allowedIpAddresses,
|
|
1055
|
-
disableIntrospection: application.config.disableIntrospection
|
|
1056
|
-
},
|
|
1191
|
+
request,
|
|
1057
1192
|
metaRequest
|
|
1058
1193
|
});
|
|
1059
1194
|
changeSet.print();
|
|
@@ -1093,7 +1228,7 @@ const CHUNK_SIZE = 64 * 1024;
|
|
|
1093
1228
|
function computeContentHash(content) {
|
|
1094
1229
|
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
1095
1230
|
}
|
|
1096
|
-
function functionRegistryTrn(workspaceId, name) {
|
|
1231
|
+
function functionRegistryTrn$1(workspaceId, name) {
|
|
1097
1232
|
return `trn:v1:workspace:${workspaceId}:function_registry:${name}`;
|
|
1098
1233
|
}
|
|
1099
1234
|
/**
|
|
@@ -1199,6 +1334,16 @@ function collectFunctionEntries(application, workflowJobs, bundledScripts) {
|
|
|
1199
1334
|
return entries;
|
|
1200
1335
|
}
|
|
1201
1336
|
/**
|
|
1337
|
+
* Filter collected workflow jobs down to the ones actually bundled.
|
|
1338
|
+
* @param jobs - All collected workflow jobs
|
|
1339
|
+
* @param usedJobNames - Job names that were bundled
|
|
1340
|
+
* @returns Bundled workflow jobs only
|
|
1341
|
+
*/
|
|
1342
|
+
function filterBundledWorkflowJobs(jobs, usedJobNames) {
|
|
1343
|
+
const used = new Set(usedJobNames);
|
|
1344
|
+
return jobs.filter((job) => used.has(job.name));
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1202
1347
|
* Plan function registry changes based on current and desired state.
|
|
1203
1348
|
* @param client - Operator client instance
|
|
1204
1349
|
* @param workspaceId - Workspace ID
|
|
@@ -1229,16 +1374,18 @@ async function planFunctionRegistry(client, workspaceId, appName, entries) {
|
|
|
1229
1374
|
});
|
|
1230
1375
|
const existingMap = {};
|
|
1231
1376
|
await Promise.all(existingFunctions.map(async (func) => {
|
|
1232
|
-
const { metadata } = await client.getMetadata({ trn: functionRegistryTrn(workspaceId, func.name) });
|
|
1377
|
+
const { metadata } = await client.getMetadata({ trn: functionRegistryTrn$1(workspaceId, func.name) });
|
|
1233
1378
|
existingMap[func.name] = {
|
|
1234
1379
|
resource: func,
|
|
1235
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
1380
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
1381
|
+
allLabels: metadata?.labels
|
|
1236
1382
|
};
|
|
1237
1383
|
}));
|
|
1238
1384
|
for (const entry of entries) {
|
|
1239
1385
|
const existing = existingMap[entry.name];
|
|
1240
|
-
const metaRequest = await buildMetaRequest(functionRegistryTrn(workspaceId, entry.name), appName);
|
|
1386
|
+
const metaRequest = await buildMetaRequest(functionRegistryTrn$1(workspaceId, entry.name), appName);
|
|
1241
1387
|
if (existing) {
|
|
1388
|
+
const isManagedByApp = existing.label === appName;
|
|
1242
1389
|
if (!existing.label) unmanaged.push({
|
|
1243
1390
|
resourceType: "Function registry",
|
|
1244
1391
|
resourceName: entry.name
|
|
@@ -1248,7 +1395,8 @@ async function planFunctionRegistry(client, workspaceId, appName, entries) {
|
|
|
1248
1395
|
resourceName: entry.name,
|
|
1249
1396
|
currentOwner: existing.label
|
|
1250
1397
|
});
|
|
1251
|
-
changeSet.
|
|
1398
|
+
if (existing.resource.contentHash === entry.contentHash && isManagedByApp && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)) changeSet.unchanged.push({ name: entry.name });
|
|
1399
|
+
else changeSet.updates.push({
|
|
1252
1400
|
name: entry.name,
|
|
1253
1401
|
entry,
|
|
1254
1402
|
metaRequest
|
|
@@ -1435,10 +1583,10 @@ async function applyIdP(client, result, phase = "create-update") {
|
|
|
1435
1583
|
* @returns Planned changes and metadata
|
|
1436
1584
|
*/
|
|
1437
1585
|
async function planIdP(context) {
|
|
1438
|
-
const { client, workspaceId, application, forRemoval } = context;
|
|
1586
|
+
const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;
|
|
1439
1587
|
const idps = forRemoval ? [] : application.idpServices;
|
|
1440
1588
|
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$3(client, workspaceId, application.name, idps);
|
|
1441
|
-
const clientChangeSet = await planClients(client, workspaceId, idps, serviceChangeSet.deletes.map((del) => del.name));
|
|
1589
|
+
const clientChangeSet = await planClients(client, workspaceId, idps, serviceChangeSet.deletes.map((del) => del.name), forceApplyAll);
|
|
1442
1590
|
serviceChangeSet.print();
|
|
1443
1591
|
clientChangeSet.print();
|
|
1444
1592
|
return {
|
|
@@ -1454,6 +1602,49 @@ async function planIdP(context) {
|
|
|
1454
1602
|
function trn$5(workspaceId, name) {
|
|
1455
1603
|
return `trn:v1:workspace:${workspaceId}:idp:${name}`;
|
|
1456
1604
|
}
|
|
1605
|
+
function normalizeComparableUserAuthPolicy(policy) {
|
|
1606
|
+
return {
|
|
1607
|
+
useNonEmailIdentifier: policy?.useNonEmailIdentifier ?? false,
|
|
1608
|
+
allowSelfPasswordReset: policy?.allowSelfPasswordReset ?? false,
|
|
1609
|
+
passwordRequireUppercase: policy?.passwordRequireUppercase ?? false,
|
|
1610
|
+
passwordRequireLowercase: policy?.passwordRequireLowercase ?? false,
|
|
1611
|
+
passwordRequireNonAlphanumeric: policy?.passwordRequireNonAlphanumeric ?? false,
|
|
1612
|
+
passwordRequireNumeric: policy?.passwordRequireNumeric ?? false,
|
|
1613
|
+
passwordMinLength: policy?.passwordMinLength ?? 0,
|
|
1614
|
+
passwordMaxLength: policy?.passwordMaxLength ?? 0,
|
|
1615
|
+
allowedEmailDomains: [...policy?.allowedEmailDomains ?? []].sort(),
|
|
1616
|
+
allowGoogleOauth: policy?.allowGoogleOauth ?? false,
|
|
1617
|
+
disablePasswordAuth: policy?.disablePasswordAuth ?? false,
|
|
1618
|
+
allowMicrosoftOauth: policy?.allowMicrosoftOauth ?? false
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
function normalizeComparableDisableGqlOperations(value) {
|
|
1622
|
+
return {
|
|
1623
|
+
create: value?.create ?? false,
|
|
1624
|
+
update: value?.update ?? false,
|
|
1625
|
+
delete: value?.delete ?? false,
|
|
1626
|
+
read: value?.read ?? false,
|
|
1627
|
+
sendPasswordResetEmail: value?.sendPasswordResetEmail ?? false
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1630
|
+
function normalizeComparableIdPService(input) {
|
|
1631
|
+
return {
|
|
1632
|
+
authorization: input.authorization,
|
|
1633
|
+
lang: input.lang === IdPLang.UNSPECIFIED ? IdPLang.EN : input.lang,
|
|
1634
|
+
userAuthPolicy: input.userAuthPolicy,
|
|
1635
|
+
publishUserEvents: input.publishUserEvents,
|
|
1636
|
+
disableGqlOperations: input.disableGqlOperations
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
function areIdPServicesEqual(existing, desired) {
|
|
1640
|
+
return areNormalizedEqual(normalizeComparableIdPService({
|
|
1641
|
+
authorization: existing.authorization,
|
|
1642
|
+
lang: existing.lang,
|
|
1643
|
+
userAuthPolicy: normalizeComparableUserAuthPolicy(existing.userAuthPolicy),
|
|
1644
|
+
publishUserEvents: existing.publishUserEvents,
|
|
1645
|
+
disableGqlOperations: normalizeComparableDisableGqlOperations(existing.disableGqlOperations)
|
|
1646
|
+
}), desired);
|
|
1647
|
+
}
|
|
1457
1648
|
async function planServices$3(client, workspaceId, appName, idps) {
|
|
1458
1649
|
const changeSet = createChangeSet("IdP services");
|
|
1459
1650
|
const conflicts = [];
|
|
@@ -1478,7 +1669,8 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1478
1669
|
const { metadata } = await client.getMetadata({ trn: trn$5(workspaceId, resource.namespace.name) });
|
|
1479
1670
|
existingServices[resource.namespace.name] = {
|
|
1480
1671
|
resource,
|
|
1481
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
1672
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
1673
|
+
allLabels: metadata?.labels
|
|
1482
1674
|
};
|
|
1483
1675
|
}));
|
|
1484
1676
|
for (const idp of idps) {
|
|
@@ -1499,7 +1691,25 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1499
1691
|
}
|
|
1500
1692
|
const lang = convertLang(idp.lang);
|
|
1501
1693
|
const userAuthPolicy = idp.userAuthPolicy;
|
|
1694
|
+
const publishUserEvents = idp.publishUserEvents ?? false;
|
|
1695
|
+
const desired = normalizeComparableIdPService({
|
|
1696
|
+
authorization,
|
|
1697
|
+
lang,
|
|
1698
|
+
userAuthPolicy: normalizeComparableUserAuthPolicy(userAuthPolicy),
|
|
1699
|
+
publishUserEvents,
|
|
1700
|
+
disableGqlOperations: normalizeComparableDisableGqlOperations(convertGqlOperationsToDisable(idp.gqlOperations))
|
|
1701
|
+
});
|
|
1702
|
+
const request = {
|
|
1703
|
+
workspaceId,
|
|
1704
|
+
namespaceName,
|
|
1705
|
+
authorization,
|
|
1706
|
+
lang,
|
|
1707
|
+
userAuthPolicy,
|
|
1708
|
+
publishUserEvents,
|
|
1709
|
+
disableGqlOperations: convertGqlOperationsToDisable(idp.gqlOperations)
|
|
1710
|
+
};
|
|
1502
1711
|
if (existing) {
|
|
1712
|
+
const isManagedByApp = existing.label === appName;
|
|
1503
1713
|
if (!existing.label) unmanaged.push({
|
|
1504
1714
|
resourceType: "IdP service",
|
|
1505
1715
|
resourceName: idp.name
|
|
@@ -1509,31 +1719,16 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1509
1719
|
resourceName: idp.name,
|
|
1510
1720
|
currentOwner: existing.label
|
|
1511
1721
|
});
|
|
1512
|
-
changeSet.
|
|
1722
|
+
if (isManagedByApp && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areIdPServicesEqual(existing.resource, desired)) changeSet.unchanged.push({ name: namespaceName });
|
|
1723
|
+
else changeSet.updates.push({
|
|
1513
1724
|
name: namespaceName,
|
|
1514
|
-
request
|
|
1515
|
-
workspaceId,
|
|
1516
|
-
namespaceName,
|
|
1517
|
-
authorization,
|
|
1518
|
-
lang,
|
|
1519
|
-
userAuthPolicy,
|
|
1520
|
-
publishUserEvents: idp.publishUserEvents,
|
|
1521
|
-
disableGqlOperations: convertGqlOperationsToDisable(idp.gqlOperations)
|
|
1522
|
-
},
|
|
1725
|
+
request,
|
|
1523
1726
|
metaRequest
|
|
1524
1727
|
});
|
|
1525
1728
|
delete existingServices[namespaceName];
|
|
1526
1729
|
} else changeSet.creates.push({
|
|
1527
1730
|
name: namespaceName,
|
|
1528
|
-
request
|
|
1529
|
-
workspaceId,
|
|
1530
|
-
namespaceName,
|
|
1531
|
-
authorization,
|
|
1532
|
-
lang,
|
|
1533
|
-
userAuthPolicy,
|
|
1534
|
-
publishUserEvents: idp.publishUserEvents,
|
|
1535
|
-
disableGqlOperations: convertGqlOperationsToDisable(idp.gqlOperations)
|
|
1536
|
-
},
|
|
1731
|
+
request,
|
|
1537
1732
|
metaRequest
|
|
1538
1733
|
});
|
|
1539
1734
|
}
|
|
@@ -1555,7 +1750,7 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1555
1750
|
resourceOwners
|
|
1556
1751
|
};
|
|
1557
1752
|
}
|
|
1558
|
-
async function planClients(client, workspaceId, idps, deletedServices) {
|
|
1753
|
+
async function planClients(client, workspaceId, idps, deletedServices, forceApplyAll = false) {
|
|
1559
1754
|
const changeSet = createChangeSet("IdP clients");
|
|
1560
1755
|
const fetchClients = (namespaceName) => {
|
|
1561
1756
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -1583,12 +1778,13 @@ async function planClients(client, workspaceId, idps, deletedServices) {
|
|
|
1583
1778
|
existingNameMap.set(client.name, client.clientSecret);
|
|
1584
1779
|
});
|
|
1585
1780
|
for (const name of idp.clients) if (existingNameMap.has(name)) {
|
|
1586
|
-
changeSet.updates.push({
|
|
1781
|
+
if (forceApplyAll) changeSet.updates.push({
|
|
1587
1782
|
name,
|
|
1588
1783
|
workspaceId,
|
|
1589
1784
|
namespaceName,
|
|
1590
|
-
clientSecret: existingNameMap.get(name)
|
|
1785
|
+
clientSecret: existingNameMap.get(name) ?? ""
|
|
1591
1786
|
});
|
|
1787
|
+
else changeSet.unchanged.push({ name });
|
|
1592
1788
|
existingNameMap.delete(name);
|
|
1593
1789
|
} else changeSet.creates.push({
|
|
1594
1790
|
name,
|
|
@@ -1598,7 +1794,7 @@ async function planClients(client, workspaceId, idps, deletedServices) {
|
|
|
1598
1794
|
client: { name }
|
|
1599
1795
|
}
|
|
1600
1796
|
});
|
|
1601
|
-
existingNameMap.forEach((name) => {
|
|
1797
|
+
existingNameMap.forEach((_clientSecret, name) => {
|
|
1602
1798
|
changeSet.deletes.push({
|
|
1603
1799
|
name,
|
|
1604
1800
|
request: {
|
|
@@ -1704,21 +1900,21 @@ async function applyAuth(client, result, phase = "create-update") {
|
|
|
1704
1900
|
* @returns Planned auth changes and metadata
|
|
1705
1901
|
*/
|
|
1706
1902
|
async function planAuth(context) {
|
|
1707
|
-
const { client, workspaceId, application, forRemoval } = context;
|
|
1903
|
+
const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;
|
|
1708
1904
|
const auths = [];
|
|
1709
1905
|
if (!forRemoval && application.authService) {
|
|
1710
1906
|
await application.authService.resolveNamespaces();
|
|
1711
1907
|
auths.push(application.authService);
|
|
1712
1908
|
}
|
|
1713
|
-
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$2(client, workspaceId, application.name, auths);
|
|
1909
|
+
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$2(client, workspaceId, application.name, auths, forceApplyAll);
|
|
1714
1910
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
1715
1911
|
const [idpConfigChangeSet, userProfileConfigChangeSet, tenantConfigChangeSet, machineUserChangeSet, authHookChangeSet, oauth2ClientChangeSet, scimChangeSet, scimResourceChangeSet] = await Promise.all([
|
|
1716
|
-
planIdPConfigs(client, workspaceId, auths, deletedServices),
|
|
1717
|
-
planUserProfileConfigs(client, workspaceId, auths, deletedServices),
|
|
1718
|
-
planTenantConfigs(client, workspaceId, auths, deletedServices),
|
|
1719
|
-
planMachineUsers(client, workspaceId, auths, deletedServices),
|
|
1720
|
-
planAuthHooks(client, workspaceId, auths, deletedServices),
|
|
1721
|
-
planOAuth2Clients(client, workspaceId, auths, deletedServices),
|
|
1912
|
+
planIdPConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1913
|
+
planUserProfileConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1914
|
+
planTenantConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1915
|
+
planMachineUsers(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1916
|
+
planAuthHooks(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1917
|
+
planOAuth2Clients(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1722
1918
|
planSCIMConfigs(client, workspaceId, auths, deletedServices),
|
|
1723
1919
|
planSCIMResources(client, workspaceId, auths, deletedServices)
|
|
1724
1920
|
]);
|
|
@@ -1751,7 +1947,7 @@ async function planAuth(context) {
|
|
|
1751
1947
|
function trn$4(workspaceId, name) {
|
|
1752
1948
|
return `trn:v1:workspace:${workspaceId}:auth:${name}`;
|
|
1753
1949
|
}
|
|
1754
|
-
async function planServices$2(client, workspaceId, appName, auths) {
|
|
1950
|
+
async function planServices$2(client, workspaceId, appName, auths, forceApplyAll = false) {
|
|
1755
1951
|
const changeSet = createChangeSet("Auth services");
|
|
1756
1952
|
const conflicts = [];
|
|
1757
1953
|
const unmanaged = [];
|
|
@@ -1782,7 +1978,13 @@ async function planServices$2(client, workspaceId, appName, auths) {
|
|
|
1782
1978
|
const { parsedConfig: config } = auth;
|
|
1783
1979
|
const existing = existingServices[config.name];
|
|
1784
1980
|
const metaRequest = await buildMetaRequest(trn$4(workspaceId, config.name), appName);
|
|
1981
|
+
const request = {
|
|
1982
|
+
workspaceId,
|
|
1983
|
+
namespaceName: config.name,
|
|
1984
|
+
publishSessionEvents: config.publishSessionEvents
|
|
1985
|
+
};
|
|
1785
1986
|
if (existing) {
|
|
1987
|
+
const isManagedByApp = existing.label === appName;
|
|
1786
1988
|
if (!existing.label) unmanaged.push({
|
|
1787
1989
|
resourceType: "Auth service",
|
|
1788
1990
|
resourceName: config.name
|
|
@@ -1792,23 +1994,16 @@ async function planServices$2(client, workspaceId, appName, auths) {
|
|
|
1792
1994
|
resourceName: config.name,
|
|
1793
1995
|
currentOwner: existing.label
|
|
1794
1996
|
});
|
|
1795
|
-
changeSet.
|
|
1997
|
+
if (!forceApplyAll && existing.resource.publishSessionEvents === (config.publishSessionEvents ?? false) && isManagedByApp) changeSet.unchanged.push({ name: config.name });
|
|
1998
|
+
else changeSet.updates.push({
|
|
1796
1999
|
name: config.name,
|
|
1797
|
-
request
|
|
1798
|
-
workspaceId,
|
|
1799
|
-
namespaceName: config.name,
|
|
1800
|
-
publishSessionEvents: config.publishSessionEvents
|
|
1801
|
-
},
|
|
2000
|
+
request,
|
|
1802
2001
|
metaRequest
|
|
1803
2002
|
});
|
|
1804
2003
|
delete existingServices[config.name];
|
|
1805
2004
|
} else changeSet.creates.push({
|
|
1806
2005
|
name: config.name,
|
|
1807
|
-
request
|
|
1808
|
-
workspaceId,
|
|
1809
|
-
namespaceName: config.name,
|
|
1810
|
-
publishSessionEvents: config.publishSessionEvents
|
|
1811
|
-
},
|
|
2006
|
+
request,
|
|
1812
2007
|
metaRequest
|
|
1813
2008
|
});
|
|
1814
2009
|
}
|
|
@@ -1830,7 +2025,7 @@ async function planServices$2(client, workspaceId, appName, auths) {
|
|
|
1830
2025
|
resourceOwners
|
|
1831
2026
|
};
|
|
1832
2027
|
}
|
|
1833
|
-
async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
2028
|
+
async function planIdPConfigs(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
1834
2029
|
const changeSet = createChangeSet("Auth idpConfigs");
|
|
1835
2030
|
const fetchIdPConfigs = (namespaceName) => {
|
|
1836
2031
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -1851,32 +2046,51 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
1851
2046
|
for (const authService of auths) {
|
|
1852
2047
|
const { parsedConfig: config } = authService;
|
|
1853
2048
|
const existingIdPConfigs = await fetchIdPConfigs(config.name);
|
|
1854
|
-
const
|
|
2049
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
1855
2050
|
existingIdPConfigs.forEach((idpConfig) => {
|
|
1856
|
-
|
|
2051
|
+
existingMap.set(idpConfig.name, idpConfig);
|
|
1857
2052
|
});
|
|
1858
2053
|
const idpConfig = config.idProvider;
|
|
1859
|
-
if (idpConfig)
|
|
1860
|
-
|
|
2054
|
+
if (idpConfig) {
|
|
2055
|
+
const desired = protoIdPConfig(idpConfig);
|
|
2056
|
+
const existing = existingMap.get(idpConfig.name);
|
|
2057
|
+
if (existing) {
|
|
2058
|
+
const desiredComparable = await protoIdPConfigForComparison(client, workspaceId, idpConfig, desired);
|
|
2059
|
+
if (!desiredComparable) {
|
|
2060
|
+
changeSet.updates.push({
|
|
2061
|
+
name: idpConfig.name,
|
|
2062
|
+
idpConfig,
|
|
2063
|
+
request: {
|
|
2064
|
+
workspaceId,
|
|
2065
|
+
namespaceName: config.name,
|
|
2066
|
+
idpConfig: desired
|
|
2067
|
+
}
|
|
2068
|
+
});
|
|
2069
|
+
existingMap.delete(idpConfig.name);
|
|
2070
|
+
continue;
|
|
2071
|
+
}
|
|
2072
|
+
if (!forceApplyAll && areAuthIdPConfigsEqual(existing, desiredComparable)) changeSet.unchanged.push({ name: idpConfig.name });
|
|
2073
|
+
else changeSet.updates.push({
|
|
2074
|
+
name: idpConfig.name,
|
|
2075
|
+
idpConfig,
|
|
2076
|
+
request: {
|
|
2077
|
+
workspaceId,
|
|
2078
|
+
namespaceName: config.name,
|
|
2079
|
+
idpConfig: desired
|
|
2080
|
+
}
|
|
2081
|
+
});
|
|
2082
|
+
existingMap.delete(idpConfig.name);
|
|
2083
|
+
} else changeSet.creates.push({
|
|
1861
2084
|
name: idpConfig.name,
|
|
1862
2085
|
idpConfig,
|
|
1863
2086
|
request: {
|
|
1864
2087
|
workspaceId,
|
|
1865
2088
|
namespaceName: config.name,
|
|
1866
|
-
idpConfig:
|
|
2089
|
+
idpConfig: desired
|
|
1867
2090
|
}
|
|
1868
2091
|
});
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
name: idpConfig.name,
|
|
1872
|
-
idpConfig,
|
|
1873
|
-
request: {
|
|
1874
|
-
workspaceId,
|
|
1875
|
-
namespaceName: config.name,
|
|
1876
|
-
idpConfig: protoIdPConfig(idpConfig)
|
|
1877
|
-
}
|
|
1878
|
-
});
|
|
1879
|
-
existingNameSet.forEach((name) => {
|
|
2092
|
+
}
|
|
2093
|
+
existingMap.forEach((_, name) => {
|
|
1880
2094
|
changeSet.deletes.push({
|
|
1881
2095
|
name,
|
|
1882
2096
|
request: {
|
|
@@ -1899,6 +2113,32 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
1899
2113
|
});
|
|
1900
2114
|
return changeSet;
|
|
1901
2115
|
}
|
|
2116
|
+
async function protoIdPConfigForComparison(client, workspaceId, idpConfig, desired) {
|
|
2117
|
+
if (idpConfig.kind !== "BuiltInIdP") return desired;
|
|
2118
|
+
const config = await tryProtoBuiltinIdPConfig(client, workspaceId, idpConfig);
|
|
2119
|
+
return config ? {
|
|
2120
|
+
...desired,
|
|
2121
|
+
config
|
|
2122
|
+
} : void 0;
|
|
2123
|
+
}
|
|
2124
|
+
function normalizeComparableAuthIdPConfig(idpConfig) {
|
|
2125
|
+
const configCase = idpConfig.config?.config?.case;
|
|
2126
|
+
const oidcValue = configCase === "oidc" && typeof idpConfig.config?.config?.value === "object" && idpConfig.config.config.value !== null ? idpConfig.config.config.value : void 0;
|
|
2127
|
+
return normalizeProtoConfig({
|
|
2128
|
+
name: idpConfig.name,
|
|
2129
|
+
authType: idpConfig.authType,
|
|
2130
|
+
config: configCase === "oidc" ? { config: {
|
|
2131
|
+
case: "oidc",
|
|
2132
|
+
value: {
|
|
2133
|
+
...oidcValue ?? {},
|
|
2134
|
+
issuerUrl: oidcValue && "issuerUrl" in oidcValue ? oidcValue.issuerUrl || void 0 : void 0
|
|
2135
|
+
}
|
|
2136
|
+
} } : idpConfig.config
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
function areAuthIdPConfigsEqual(existing, desired) {
|
|
2140
|
+
return areNormalizedEqual(normalizeComparableAuthIdPConfig(existing), normalizeComparableAuthIdPConfig(desired));
|
|
2141
|
+
}
|
|
1902
2142
|
function protoIdPConfig(idpConfig) {
|
|
1903
2143
|
switch (idpConfig.kind) {
|
|
1904
2144
|
case "IDToken": return {
|
|
@@ -1951,6 +2191,11 @@ function protoIdPConfig(idpConfig) {
|
|
|
1951
2191
|
}
|
|
1952
2192
|
}
|
|
1953
2193
|
async function protoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
2194
|
+
const config = await tryProtoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig);
|
|
2195
|
+
if (!config) throw new Error(`Built-in IdP "${builtinIdPConfig.namespace}" not found. Please ensure that idp is configured correctly.`);
|
|
2196
|
+
return config;
|
|
2197
|
+
}
|
|
2198
|
+
async function tryProtoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
1954
2199
|
let idpService;
|
|
1955
2200
|
try {
|
|
1956
2201
|
idpService = await client.getIdPService({
|
|
@@ -1958,14 +2203,20 @@ async function protoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
|
1958
2203
|
namespaceName: builtinIdPConfig.namespace
|
|
1959
2204
|
});
|
|
1960
2205
|
} catch (error) {
|
|
1961
|
-
if (error instanceof ConnectError && error.code === Code.NotFound)
|
|
2206
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return;
|
|
2207
|
+
throw error;
|
|
2208
|
+
}
|
|
2209
|
+
let idpClient;
|
|
2210
|
+
try {
|
|
2211
|
+
idpClient = await client.getIdPClient({
|
|
2212
|
+
workspaceId,
|
|
2213
|
+
namespaceName: builtinIdPConfig.namespace,
|
|
2214
|
+
name: builtinIdPConfig.clientName
|
|
2215
|
+
});
|
|
2216
|
+
} catch (error) {
|
|
2217
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return;
|
|
1962
2218
|
throw error;
|
|
1963
2219
|
}
|
|
1964
|
-
const idpClient = await client.getIdPClient({
|
|
1965
|
-
workspaceId,
|
|
1966
|
-
namespaceName: builtinIdPConfig.namespace,
|
|
1967
|
-
name: builtinIdPConfig.clientName
|
|
1968
|
-
});
|
|
1969
2220
|
const vaultName = idpClientVaultName(builtinIdPConfig.namespace, builtinIdPConfig.clientName);
|
|
1970
2221
|
const secretKey = idpClientSecretName(builtinIdPConfig.namespace, builtinIdPConfig.clientName);
|
|
1971
2222
|
return { config: {
|
|
@@ -1981,16 +2232,35 @@ async function protoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
|
1981
2232
|
}
|
|
1982
2233
|
} };
|
|
1983
2234
|
}
|
|
1984
|
-
async function planUserProfileConfigs(client, workspaceId, auths, deletedServices) {
|
|
2235
|
+
async function planUserProfileConfigs(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
1985
2236
|
const changeSet = createChangeSet("Auth userProfileConfigs");
|
|
1986
2237
|
for (const auth of auths) {
|
|
1987
2238
|
const { parsedConfig: config } = auth;
|
|
1988
2239
|
const name = `${config.name}-user-profile-config`;
|
|
1989
2240
|
try {
|
|
1990
|
-
await client.getUserProfileConfig({
|
|
2241
|
+
const { userProfileProviderConfig } = await client.getUserProfileConfig({
|
|
1991
2242
|
workspaceId,
|
|
1992
2243
|
namespaceName: config.name
|
|
1993
2244
|
});
|
|
2245
|
+
const userProfileForUpdate = auth.userProfile;
|
|
2246
|
+
if (userProfileForUpdate) {
|
|
2247
|
+
const desired = protoUserProfileConfig(userProfileForUpdate);
|
|
2248
|
+
if (!forceApplyAll && areUserProfileConfigsEqual(userProfileProviderConfig ?? {}, desired)) changeSet.unchanged.push({ name });
|
|
2249
|
+
else changeSet.updates.push({
|
|
2250
|
+
name,
|
|
2251
|
+
request: {
|
|
2252
|
+
workspaceId,
|
|
2253
|
+
namespaceName: config.name,
|
|
2254
|
+
userProfileProviderConfig: desired
|
|
2255
|
+
}
|
|
2256
|
+
});
|
|
2257
|
+
} else changeSet.deletes.push({
|
|
2258
|
+
name,
|
|
2259
|
+
request: {
|
|
2260
|
+
workspaceId,
|
|
2261
|
+
namespaceName: config.name
|
|
2262
|
+
}
|
|
2263
|
+
});
|
|
1994
2264
|
} catch (error) {
|
|
1995
2265
|
if (error instanceof ConnectError && error.code === Code.NotFound) {
|
|
1996
2266
|
const userProfileForCreate = auth.userProfile;
|
|
@@ -2006,22 +2276,6 @@ async function planUserProfileConfigs(client, workspaceId, auths, deletedService
|
|
|
2006
2276
|
}
|
|
2007
2277
|
throw error;
|
|
2008
2278
|
}
|
|
2009
|
-
const userProfileForUpdate = auth.userProfile;
|
|
2010
|
-
if (userProfileForUpdate) changeSet.updates.push({
|
|
2011
|
-
name,
|
|
2012
|
-
request: {
|
|
2013
|
-
workspaceId,
|
|
2014
|
-
namespaceName: config.name,
|
|
2015
|
-
userProfileProviderConfig: protoUserProfileConfig(userProfileForUpdate)
|
|
2016
|
-
}
|
|
2017
|
-
});
|
|
2018
|
-
else changeSet.deletes.push({
|
|
2019
|
-
name,
|
|
2020
|
-
request: {
|
|
2021
|
-
workspaceId,
|
|
2022
|
-
namespaceName: config.name
|
|
2023
|
-
}
|
|
2024
|
-
});
|
|
2025
2279
|
}
|
|
2026
2280
|
for (const namespaceName of deletedServices) {
|
|
2027
2281
|
try {
|
|
@@ -2061,16 +2315,34 @@ function protoUserProfileConfig(userProfile) {
|
|
|
2061
2315
|
} }
|
|
2062
2316
|
};
|
|
2063
2317
|
}
|
|
2064
|
-
async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
|
|
2318
|
+
async function planTenantConfigs(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2065
2319
|
const changeSet = createChangeSet("Auth tenantConfigs");
|
|
2066
2320
|
for (const auth of auths) {
|
|
2067
2321
|
const { parsedConfig: config } = auth;
|
|
2068
2322
|
const name = `${config.name}-tenant-config`;
|
|
2069
2323
|
try {
|
|
2070
|
-
await client.getTenantConfig({
|
|
2324
|
+
const { tenantProviderConfig } = await client.getTenantConfig({
|
|
2071
2325
|
workspaceId,
|
|
2072
2326
|
namespaceName: config.name
|
|
2073
2327
|
});
|
|
2328
|
+
if (config.tenantProvider) {
|
|
2329
|
+
const desired = protoTenantConfig(config.tenantProvider);
|
|
2330
|
+
if (!forceApplyAll && areTenantProviderConfigsEqual(tenantProviderConfig, desired)) changeSet.unchanged.push({ name });
|
|
2331
|
+
else changeSet.updates.push({
|
|
2332
|
+
name,
|
|
2333
|
+
request: {
|
|
2334
|
+
workspaceId,
|
|
2335
|
+
namespaceName: config.name,
|
|
2336
|
+
tenantProviderConfig: desired
|
|
2337
|
+
}
|
|
2338
|
+
});
|
|
2339
|
+
} else changeSet.deletes.push({
|
|
2340
|
+
name,
|
|
2341
|
+
request: {
|
|
2342
|
+
workspaceId,
|
|
2343
|
+
namespaceName: config.name
|
|
2344
|
+
}
|
|
2345
|
+
});
|
|
2074
2346
|
} catch (error) {
|
|
2075
2347
|
if (error instanceof ConnectError && error.code === Code.NotFound) {
|
|
2076
2348
|
if (config.tenantProvider) changeSet.creates.push({
|
|
@@ -2085,21 +2357,6 @@ async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
2085
2357
|
}
|
|
2086
2358
|
throw error;
|
|
2087
2359
|
}
|
|
2088
|
-
if (config.tenantProvider) changeSet.updates.push({
|
|
2089
|
-
name,
|
|
2090
|
-
request: {
|
|
2091
|
-
workspaceId,
|
|
2092
|
-
namespaceName: config.name,
|
|
2093
|
-
tenantProviderConfig: protoTenantConfig(config.tenantProvider)
|
|
2094
|
-
}
|
|
2095
|
-
});
|
|
2096
|
-
else changeSet.deletes.push({
|
|
2097
|
-
name,
|
|
2098
|
-
request: {
|
|
2099
|
-
workspaceId,
|
|
2100
|
-
namespaceName: config.name
|
|
2101
|
-
}
|
|
2102
|
-
});
|
|
2103
2360
|
}
|
|
2104
2361
|
for (const namespaceName of deletedServices) {
|
|
2105
2362
|
try {
|
|
@@ -2134,7 +2391,7 @@ function protoTenantConfig(tenantConfig) {
|
|
|
2134
2391
|
} }
|
|
2135
2392
|
};
|
|
2136
2393
|
}
|
|
2137
|
-
async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
2394
|
+
async function planMachineUsers(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2138
2395
|
const changeSet = createChangeSet("Auth machineUsers");
|
|
2139
2396
|
const fetchMachineUsers = (authNamespace) => {
|
|
2140
2397
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -2155,25 +2412,31 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
|
2155
2412
|
for (const auth of auths) {
|
|
2156
2413
|
const { parsedConfig: config } = auth;
|
|
2157
2414
|
const existingMachineUsers = await fetchMachineUsers(config.name);
|
|
2158
|
-
const
|
|
2415
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
2159
2416
|
existingMachineUsers.forEach((machineUser) => {
|
|
2160
|
-
|
|
2417
|
+
existingMap.set(machineUser.name, machineUser);
|
|
2161
2418
|
});
|
|
2162
2419
|
for (const machineUsername of Object.keys(config.machineUsers ?? {})) {
|
|
2163
2420
|
const machineUser = config.machineUsers?.[machineUsername];
|
|
2164
2421
|
if (!machineUser) continue;
|
|
2165
|
-
|
|
2166
|
-
|
|
2422
|
+
const desiredMachineUser = {
|
|
2423
|
+
attributes: machineUser.attributeList,
|
|
2424
|
+
attributeMap: machineUser.attributes ? protoMachineUserAttributeMap(machineUser.attributes) : void 0
|
|
2425
|
+
};
|
|
2426
|
+
const existing = existingMap.get(machineUsername);
|
|
2427
|
+
if (existing) {
|
|
2428
|
+
if (!forceApplyAll && areMachineUsersEqual(existing, desiredMachineUser)) changeSet.unchanged.push({ name: machineUsername });
|
|
2429
|
+
else changeSet.updates.push({
|
|
2167
2430
|
name: machineUsername,
|
|
2168
2431
|
request: {
|
|
2169
2432
|
workspaceId,
|
|
2170
2433
|
authNamespace: config.name,
|
|
2171
2434
|
name: machineUsername,
|
|
2172
2435
|
attributes: machineUser.attributeList,
|
|
2173
|
-
attributeMap:
|
|
2436
|
+
attributeMap: desiredMachineUser.attributeMap
|
|
2174
2437
|
}
|
|
2175
2438
|
});
|
|
2176
|
-
|
|
2439
|
+
existingMap.delete(machineUsername);
|
|
2177
2440
|
} else changeSet.creates.push({
|
|
2178
2441
|
name: machineUsername,
|
|
2179
2442
|
request: {
|
|
@@ -2181,11 +2444,11 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
|
2181
2444
|
authNamespace: config.name,
|
|
2182
2445
|
name: machineUsername,
|
|
2183
2446
|
attributes: machineUser.attributeList,
|
|
2184
|
-
attributeMap:
|
|
2447
|
+
attributeMap: desiredMachineUser.attributeMap
|
|
2185
2448
|
}
|
|
2186
2449
|
});
|
|
2187
2450
|
}
|
|
2188
|
-
|
|
2451
|
+
existingMap.forEach((_, name) => {
|
|
2189
2452
|
changeSet.deletes.push({
|
|
2190
2453
|
name,
|
|
2191
2454
|
request: {
|
|
@@ -2213,7 +2476,60 @@ function protoMachineUserAttributeMap(attributeMap) {
|
|
|
2213
2476
|
for (const [key, value] of Object.entries(attributeMap)) ret[key] = fromJson(ValueSchema, value ?? null);
|
|
2214
2477
|
return ret;
|
|
2215
2478
|
}
|
|
2216
|
-
|
|
2479
|
+
function normalizeComparableUserProfileConfig(config) {
|
|
2480
|
+
const comparableConfig = config.config?.config;
|
|
2481
|
+
const tailorDBConfig = comparableConfig?.case === "tailordb" ? comparableConfig.value : void 0;
|
|
2482
|
+
return normalizeProtoConfig({
|
|
2483
|
+
providerType: config.providerType,
|
|
2484
|
+
config: { config: {
|
|
2485
|
+
case: comparableConfig?.case,
|
|
2486
|
+
value: tailorDBConfig ? {
|
|
2487
|
+
...tailorDBConfig,
|
|
2488
|
+
tenantIdField: tailorDBConfig.tenantIdField || void 0,
|
|
2489
|
+
attributesFields: normalizeStringArray(tailorDBConfig.attributesFields),
|
|
2490
|
+
attributeMap: normalizeProtoConfig(tailorDBConfig.attributeMap)
|
|
2491
|
+
} : comparableConfig?.value
|
|
2492
|
+
} }
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
function areUserProfileConfigsEqual(existing, desired) {
|
|
2496
|
+
return areNormalizedEqual(normalizeComparableUserProfileConfig(existing), normalizeComparableUserProfileConfig(desired));
|
|
2497
|
+
}
|
|
2498
|
+
function normalizeComparableTenantProviderConfig(config) {
|
|
2499
|
+
return normalizeProtoConfig(config);
|
|
2500
|
+
}
|
|
2501
|
+
function areTenantProviderConfigsEqual(existing, desired) {
|
|
2502
|
+
return areNormalizedEqual(normalizeComparableTenantProviderConfig(existing), normalizeComparableTenantProviderConfig(desired));
|
|
2503
|
+
}
|
|
2504
|
+
function normalizeComparableMachineUser(input) {
|
|
2505
|
+
return normalizeProtoConfig({
|
|
2506
|
+
attributes: normalizeStringArray(input.attributes),
|
|
2507
|
+
attributeMap: normalizeProtoConfig(input.attributeMap ?? {})
|
|
2508
|
+
});
|
|
2509
|
+
}
|
|
2510
|
+
function areMachineUsersEqual(existing, desired) {
|
|
2511
|
+
return areNormalizedEqual(normalizeComparableMachineUser(existing), normalizeComparableMachineUser(desired));
|
|
2512
|
+
}
|
|
2513
|
+
function normalizeComparableOAuth2Client(client) {
|
|
2514
|
+
const accessTokenLifetime = oauth2LifetimeToSeconds(client.accessTokenLifetime);
|
|
2515
|
+
const refreshTokenLifetime = oauth2LifetimeToSeconds(client.refreshTokenLifetime);
|
|
2516
|
+
return normalizeProtoConfig({
|
|
2517
|
+
...client,
|
|
2518
|
+
redirectUris: normalizeStringArray(client.redirectUris),
|
|
2519
|
+
grantTypes: [...client.grantTypes ?? []].sort((left, right) => left - right),
|
|
2520
|
+
accessTokenLifetime: accessTokenLifetime ?? 86400,
|
|
2521
|
+
refreshTokenLifetime: refreshTokenLifetime ?? 604800,
|
|
2522
|
+
requireDpop: client.requireDpop ?? false
|
|
2523
|
+
});
|
|
2524
|
+
}
|
|
2525
|
+
function oauth2LifetimeToSeconds(lifetime) {
|
|
2526
|
+
if (typeof lifetime === "number") return lifetime;
|
|
2527
|
+
if (lifetime?.seconds != null) return Number(lifetime.seconds);
|
|
2528
|
+
}
|
|
2529
|
+
function areOAuth2ClientsEqual(existing, desired) {
|
|
2530
|
+
return areNormalizedEqual(normalizeComparableOAuth2Client(existing), normalizeComparableOAuth2Client(desired));
|
|
2531
|
+
}
|
|
2532
|
+
async function planOAuth2Clients(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2217
2533
|
const changeSet = createChangeSet("Auth oauth2Clients");
|
|
2218
2534
|
const fetchOAuth2Clients = (namespaceName) => {
|
|
2219
2535
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -2236,14 +2552,16 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
|
|
|
2236
2552
|
const existingOAuth2Clients = await fetchOAuth2Clients(config.name);
|
|
2237
2553
|
const existingClientsMap = /* @__PURE__ */ new Map();
|
|
2238
2554
|
existingOAuth2Clients.forEach((oauth2Client) => {
|
|
2239
|
-
existingClientsMap.set(oauth2Client.name, oauth2Client
|
|
2555
|
+
existingClientsMap.set(oauth2Client.name, oauth2Client);
|
|
2240
2556
|
});
|
|
2241
2557
|
for (const oauth2ClientName of Object.keys(config.oauth2Clients ?? {})) {
|
|
2242
2558
|
const oauth2Client = config.oauth2Clients?.[oauth2ClientName];
|
|
2243
2559
|
if (!oauth2Client) continue;
|
|
2244
2560
|
const newOAuth2Client = protoOAuth2Client(oauth2ClientName, oauth2Client);
|
|
2561
|
+
const resolvedRedirectUris = await resolveStaticWebsiteUrls(client, workspaceId, newOAuth2Client.redirectUris ?? [], "OAuth2 redirect URIs");
|
|
2245
2562
|
if (existingClientsMap.has(oauth2ClientName)) {
|
|
2246
|
-
|
|
2563
|
+
const existingClient = existingClientsMap.get(oauth2ClientName);
|
|
2564
|
+
if (existingClient.clientType !== newOAuth2Client.clientType) changeSet.replaces.push({
|
|
2247
2565
|
name: oauth2ClientName,
|
|
2248
2566
|
deleteRequest: {
|
|
2249
2567
|
workspaceId,
|
|
@@ -2256,14 +2574,33 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
|
|
|
2256
2574
|
oauth2Client: newOAuth2Client
|
|
2257
2575
|
}
|
|
2258
2576
|
});
|
|
2259
|
-
else
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
}
|
|
2266
|
-
|
|
2577
|
+
else {
|
|
2578
|
+
const desiredComparable = {
|
|
2579
|
+
...newOAuth2Client,
|
|
2580
|
+
redirectUris: resolvedRedirectUris,
|
|
2581
|
+
accessTokenLifetime: oauth2LifetimeToSeconds(newOAuth2Client.accessTokenLifetime),
|
|
2582
|
+
refreshTokenLifetime: oauth2LifetimeToSeconds(newOAuth2Client.refreshTokenLifetime)
|
|
2583
|
+
};
|
|
2584
|
+
const existingComparable = {
|
|
2585
|
+
name: existingClient.name,
|
|
2586
|
+
description: existingClient.description,
|
|
2587
|
+
grantTypes: existingClient.grantTypes,
|
|
2588
|
+
redirectUris: existingClient.redirectUris,
|
|
2589
|
+
clientType: existingClient.clientType,
|
|
2590
|
+
accessTokenLifetime: oauth2LifetimeToSeconds(existingClient.accessTokenLifetime),
|
|
2591
|
+
refreshTokenLifetime: oauth2LifetimeToSeconds(existingClient.refreshTokenLifetime),
|
|
2592
|
+
requireDpop: existingClient.requireDpop
|
|
2593
|
+
};
|
|
2594
|
+
if (!forceApplyAll && areOAuth2ClientsEqual(existingComparable, desiredComparable)) changeSet.unchanged.push({ name: oauth2ClientName });
|
|
2595
|
+
else changeSet.updates.push({
|
|
2596
|
+
name: oauth2ClientName,
|
|
2597
|
+
request: {
|
|
2598
|
+
workspaceId,
|
|
2599
|
+
namespaceName: config.name,
|
|
2600
|
+
oauth2Client: newOAuth2Client
|
|
2601
|
+
}
|
|
2602
|
+
});
|
|
2603
|
+
}
|
|
2267
2604
|
existingClientsMap.delete(oauth2ClientName);
|
|
2268
2605
|
} else changeSet.creates.push({
|
|
2269
2606
|
name: oauth2ClientName,
|
|
@@ -2538,21 +2875,36 @@ function protoSCIMAttribute(attr) {
|
|
|
2538
2875
|
subAttributes: attr.subAttributes?.map((attr) => protoSCIMAttribute(attr))
|
|
2539
2876
|
};
|
|
2540
2877
|
}
|
|
2541
|
-
|
|
2878
|
+
function areAuthHooksEqual(existing, desired) {
|
|
2879
|
+
return areNormalizedEqual({
|
|
2880
|
+
scriptRef: existing.scriptRef ?? "",
|
|
2881
|
+
invoker: existing.invoker ? {
|
|
2882
|
+
namespace: existing.invoker.namespace ?? "",
|
|
2883
|
+
machineUserName: existing.invoker.machineUserName ?? ""
|
|
2884
|
+
} : void 0
|
|
2885
|
+
}, {
|
|
2886
|
+
scriptRef: desired.scriptRef ?? "",
|
|
2887
|
+
invoker: desired.invoker ? {
|
|
2888
|
+
namespace: desired.invoker.namespace ?? "",
|
|
2889
|
+
machineUserName: desired.invoker.machineUserName ?? ""
|
|
2890
|
+
} : void 0
|
|
2891
|
+
});
|
|
2892
|
+
}
|
|
2893
|
+
async function planAuthHooks(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2542
2894
|
const changeSet = createChangeSet("Auth hooks");
|
|
2543
2895
|
for (const auth of auths) {
|
|
2544
2896
|
const { parsedConfig: config } = auth;
|
|
2545
2897
|
const beforeLogin = config.hooks?.beforeLogin;
|
|
2546
2898
|
let existingHook;
|
|
2547
2899
|
try {
|
|
2548
|
-
await client.getAuthHook({
|
|
2900
|
+
const { hook } = await client.getAuthHook({
|
|
2549
2901
|
workspaceId,
|
|
2550
2902
|
namespaceName: config.name,
|
|
2551
2903
|
hookPoint: AuthHookPoint.BEFORE_LOGIN
|
|
2552
2904
|
});
|
|
2553
|
-
existingHook =
|
|
2905
|
+
existingHook = hook;
|
|
2554
2906
|
} catch (error) {
|
|
2555
|
-
if (error instanceof ConnectError && error.code === Code.NotFound) existingHook =
|
|
2907
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) existingHook = void 0;
|
|
2556
2908
|
else throw error;
|
|
2557
2909
|
}
|
|
2558
2910
|
if (beforeLogin) {
|
|
@@ -2568,7 +2920,8 @@ async function planAuthHooks(client, workspaceId, auths, deletedServices) {
|
|
|
2568
2920
|
}
|
|
2569
2921
|
}
|
|
2570
2922
|
};
|
|
2571
|
-
if (existingHook) changeSet.
|
|
2923
|
+
if (existingHook) if (!forceApplyAll && areAuthHooksEqual(existingHook, hookRequest.hook)) changeSet.unchanged.push({ name: `${config.name}/before-login` });
|
|
2924
|
+
else changeSet.updates.push({
|
|
2572
2925
|
name: `${config.name}/before-login`,
|
|
2573
2926
|
request: hookRequest
|
|
2574
2927
|
});
|
|
@@ -2751,19 +3104,10 @@ const ACTOR_TRANSFORM_EXPR = "actor: args.actor ? (({ attributeMap, attributes:
|
|
|
2751
3104
|
function buildExecutorArgsExpr(triggerKind, env) {
|
|
2752
3105
|
const envExpr = `env: ${JSON.stringify(env)}`;
|
|
2753
3106
|
switch (triggerKind) {
|
|
2754
|
-
case "schedule":
|
|
2755
|
-
case "recordCreated":
|
|
2756
|
-
case "recordUpdated":
|
|
2757
|
-
case "recordDeleted":
|
|
2758
|
-
case "idpUserCreated":
|
|
2759
|
-
case "idpUserUpdated":
|
|
2760
|
-
case "idpUserDeleted":
|
|
2761
|
-
case "authAccessTokenIssued":
|
|
2762
|
-
case "authAccessTokenRefreshed":
|
|
2763
|
-
case "authAccessTokenRevoked": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
3107
|
+
case "schedule": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
2764
3108
|
case "resolverExecuted": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, success: !!args.succeeded, result: args.succeeded?.result.resolver, error: args.failed?.error, ${envExpr} })`;
|
|
2765
3109
|
case "incomingWebhook": return `({ ...args, appNamespace: args.namespaceName, rawBody: args.raw_body, ${envExpr} })`;
|
|
2766
|
-
default:
|
|
3110
|
+
default: return `({ ...args, event: args.eventType?.split(".").pop(), rawEvent: args.eventType, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
2767
3111
|
}
|
|
2768
3112
|
}
|
|
2769
3113
|
/**
|
|
@@ -2833,13 +3177,15 @@ async function planExecutor(context) {
|
|
|
2833
3177
|
const { metadata } = await client.getMetadata({ trn: trn$3(workspaceId, resource.name) });
|
|
2834
3178
|
existingExecutors[resource.name] = {
|
|
2835
3179
|
resource,
|
|
2836
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
3180
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
3181
|
+
allLabels: metadata?.labels
|
|
2837
3182
|
};
|
|
2838
3183
|
}));
|
|
2839
3184
|
const executors = forRemoval ? {} : await application.executorService?.loadExecutors() ?? {};
|
|
2840
3185
|
for (const executor of Object.values(executors)) {
|
|
2841
3186
|
const existing = existingExecutors[executor.name];
|
|
2842
3187
|
const metaRequest = await buildMetaRequest(trn$3(workspaceId, executor.name), application.name);
|
|
3188
|
+
const desiredExecutor = protoExecutor(application, executor);
|
|
2843
3189
|
if (existing) {
|
|
2844
3190
|
if (!existing.label) unmanaged.push({
|
|
2845
3191
|
resourceType: "Executor",
|
|
@@ -2850,11 +3196,12 @@ async function planExecutor(context) {
|
|
|
2850
3196
|
resourceName: executor.name,
|
|
2851
3197
|
currentOwner: existing.label
|
|
2852
3198
|
});
|
|
2853
|
-
changeSet.
|
|
3199
|
+
if (existing.label === application.name && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areExecutorsEqual(existing.resource, desiredExecutor)) changeSet.unchanged.push({ name: executor.name });
|
|
3200
|
+
else changeSet.updates.push({
|
|
2854
3201
|
name: executor.name,
|
|
2855
3202
|
request: {
|
|
2856
3203
|
workspaceId,
|
|
2857
|
-
executor:
|
|
3204
|
+
executor: desiredExecutor
|
|
2858
3205
|
},
|
|
2859
3206
|
metaRequest
|
|
2860
3207
|
});
|
|
@@ -2863,7 +3210,7 @@ async function planExecutor(context) {
|
|
|
2863
3210
|
name: executor.name,
|
|
2864
3211
|
request: {
|
|
2865
3212
|
workspaceId,
|
|
2866
|
-
executor:
|
|
3213
|
+
executor: desiredExecutor
|
|
2867
3214
|
},
|
|
2868
3215
|
metaRequest
|
|
2869
3216
|
});
|
|
@@ -2887,6 +3234,56 @@ async function planExecutor(context) {
|
|
|
2887
3234
|
resourceOwners
|
|
2888
3235
|
};
|
|
2889
3236
|
}
|
|
3237
|
+
function normalizeComparableExecutor(executor) {
|
|
3238
|
+
const normalized = normalizeProtoConfig(executor) ?? {};
|
|
3239
|
+
const webhookHeaders = normalized.targetConfig?.config?.case === "webhook" ? [...normalized.targetConfig.config.value.headers ?? []].sort((left, right) => (left.key ?? "").localeCompare(right.key ?? "")) : void 0;
|
|
3240
|
+
const triggerConfig = normalized.triggerConfig?.config?.case === "incomingWebhook" ? {
|
|
3241
|
+
...normalized.triggerConfig,
|
|
3242
|
+
config: {
|
|
3243
|
+
...normalized.triggerConfig.config,
|
|
3244
|
+
value: {}
|
|
3245
|
+
}
|
|
3246
|
+
} : normalized.triggerConfig?.config?.case === "event" ? {
|
|
3247
|
+
...normalized.triggerConfig,
|
|
3248
|
+
config: {
|
|
3249
|
+
...normalized.triggerConfig.config,
|
|
3250
|
+
value: {
|
|
3251
|
+
...normalized.triggerConfig.config.value,
|
|
3252
|
+
eventType: void 0
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
} : normalized.triggerConfig;
|
|
3256
|
+
return {
|
|
3257
|
+
name: normalized.name,
|
|
3258
|
+
description: normalized.description ?? "",
|
|
3259
|
+
disabled: normalized.disabled ?? false,
|
|
3260
|
+
triggerType: normalized.triggerType,
|
|
3261
|
+
triggerConfig,
|
|
3262
|
+
targetType: normalized.targetType,
|
|
3263
|
+
targetConfig: normalized.targetConfig?.config?.case === "webhook" ? {
|
|
3264
|
+
...normalized.targetConfig,
|
|
3265
|
+
config: {
|
|
3266
|
+
...normalized.targetConfig.config,
|
|
3267
|
+
value: {
|
|
3268
|
+
...normalized.targetConfig.config.value,
|
|
3269
|
+
headers: webhookHeaders
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
} : normalized.targetConfig?.config?.case === "function" ? {
|
|
3273
|
+
...normalized.targetConfig,
|
|
3274
|
+
config: {
|
|
3275
|
+
...normalized.targetConfig.config,
|
|
3276
|
+
value: {
|
|
3277
|
+
...normalized.targetConfig.config.value,
|
|
3278
|
+
script: void 0
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
} : normalized.targetConfig
|
|
3282
|
+
};
|
|
3283
|
+
}
|
|
3284
|
+
function areExecutorsEqual(existing, desired) {
|
|
3285
|
+
return areNormalizedEqual(normalizeComparableExecutor(existing), normalizeComparableExecutor(desired));
|
|
3286
|
+
}
|
|
2890
3287
|
function resolveTailorDBNamespace(application, typeName) {
|
|
2891
3288
|
for (const service of application.tailorDBServices) if (service.types[typeName]) return service.namespace;
|
|
2892
3289
|
throw new Error(`TailorDB type "${typeName}" not found in any namespace. Available namespaces: ${application.tailorDBServices.map((s) => s.namespace).join(", ")}`);
|
|
@@ -2911,18 +3308,6 @@ function protoExecutor(application, executor) {
|
|
|
2911
3308
|
let triggerType;
|
|
2912
3309
|
let triggerConfig;
|
|
2913
3310
|
const argsExpr = buildExecutorArgsExpr(trigger.kind, env);
|
|
2914
|
-
const eventType = {
|
|
2915
|
-
recordCreated: "tailordb.type_record.created",
|
|
2916
|
-
recordUpdated: "tailordb.type_record.updated",
|
|
2917
|
-
recordDeleted: "tailordb.type_record.deleted",
|
|
2918
|
-
resolverExecuted: "pipeline.resolver.executed",
|
|
2919
|
-
idpUserCreated: "idp.user.created",
|
|
2920
|
-
idpUserUpdated: "idp.user.updated",
|
|
2921
|
-
idpUserDeleted: "idp.user.deleted",
|
|
2922
|
-
authAccessTokenIssued: "auth.access_token.issued",
|
|
2923
|
-
authAccessTokenRefreshed: "auth.access_token.refreshed",
|
|
2924
|
-
authAccessTokenRevoked: "auth.access_token.revoked"
|
|
2925
|
-
};
|
|
2926
3311
|
function typedEventTrigger(typedConfig) {
|
|
2927
3312
|
return { config: {
|
|
2928
3313
|
case: "event",
|
|
@@ -2940,14 +3325,12 @@ function protoExecutor(application, executor) {
|
|
|
2940
3325
|
}
|
|
2941
3326
|
} };
|
|
2942
3327
|
break;
|
|
2943
|
-
case "
|
|
2944
|
-
case "recordUpdated":
|
|
2945
|
-
case "recordDeleted":
|
|
3328
|
+
case "tailordb":
|
|
2946
3329
|
triggerType = ExecutorTriggerType.EVENT;
|
|
2947
3330
|
triggerConfig = typedEventTrigger({
|
|
2948
3331
|
case: "tailordb",
|
|
2949
3332
|
value: {
|
|
2950
|
-
eventTypes:
|
|
3333
|
+
eventTypes: trigger.events,
|
|
2951
3334
|
namespaceName: resolveTailorDBNamespace(application, trigger.typeName),
|
|
2952
3335
|
typeName: trigger.typeName,
|
|
2953
3336
|
...trigger.condition ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } } : {}
|
|
@@ -2959,7 +3342,7 @@ function protoExecutor(application, executor) {
|
|
|
2959
3342
|
triggerConfig = typedEventTrigger({
|
|
2960
3343
|
case: "pipeline",
|
|
2961
3344
|
value: {
|
|
2962
|
-
eventTypes: [
|
|
3345
|
+
eventTypes: ["pipeline.resolver.executed"],
|
|
2963
3346
|
namespaceName: resolveResolverNamespace(application, trigger.resolverName),
|
|
2964
3347
|
resolverName: trigger.resolverName,
|
|
2965
3348
|
...trigger.condition ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } } : {}
|
|
@@ -2973,26 +3356,22 @@ function protoExecutor(application, executor) {
|
|
|
2973
3356
|
value: {}
|
|
2974
3357
|
} };
|
|
2975
3358
|
break;
|
|
2976
|
-
case "
|
|
2977
|
-
case "idpUserUpdated":
|
|
2978
|
-
case "idpUserDeleted":
|
|
3359
|
+
case "idpUser":
|
|
2979
3360
|
triggerType = ExecutorTriggerType.EVENT;
|
|
2980
3361
|
triggerConfig = typedEventTrigger({
|
|
2981
3362
|
case: "idp",
|
|
2982
3363
|
value: {
|
|
2983
|
-
eventTypes:
|
|
3364
|
+
eventTypes: trigger.events,
|
|
2984
3365
|
namespaceName: resolveIdpNamespace(application)
|
|
2985
3366
|
}
|
|
2986
3367
|
});
|
|
2987
3368
|
break;
|
|
2988
|
-
case "
|
|
2989
|
-
case "authAccessTokenRefreshed":
|
|
2990
|
-
case "authAccessTokenRevoked":
|
|
3369
|
+
case "authAccessToken":
|
|
2991
3370
|
triggerType = ExecutorTriggerType.EVENT;
|
|
2992
3371
|
triggerConfig = typedEventTrigger({
|
|
2993
3372
|
case: "auth",
|
|
2994
3373
|
value: {
|
|
2995
|
-
eventTypes:
|
|
3374
|
+
eventTypes: trigger.events,
|
|
2996
3375
|
namespaceName: resolveAuthNamespace(application)
|
|
2997
3376
|
}
|
|
2998
3377
|
});
|
|
@@ -3148,7 +3527,7 @@ async function applyPipeline(client, result, phase = "create-update") {
|
|
|
3148
3527
|
* @returns Planned changes
|
|
3149
3528
|
*/
|
|
3150
3529
|
async function planPipeline(context) {
|
|
3151
|
-
const { client, workspaceId, application, forRemoval } = context;
|
|
3530
|
+
const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;
|
|
3152
3531
|
const pipelines = [];
|
|
3153
3532
|
if (!forRemoval) for (const pipeline of application.resolverServices) {
|
|
3154
3533
|
await pipeline.loadResolvers();
|
|
@@ -3156,7 +3535,7 @@ async function planPipeline(context) {
|
|
|
3156
3535
|
}
|
|
3157
3536
|
const executors = forRemoval ? [] : Object.values(await application.executorService?.loadExecutors() ?? {});
|
|
3158
3537
|
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$1(client, workspaceId, application.name, pipelines);
|
|
3159
|
-
const resolverChangeSet = await planResolvers(client, workspaceId, pipelines, executors, serviceChangeSet.deletes.map((del) => del.name), application.env);
|
|
3538
|
+
const resolverChangeSet = await planResolvers(client, workspaceId, pipelines, executors, serviceChangeSet.deletes.map((del) => del.name), application.env, forceApplyAll);
|
|
3160
3539
|
serviceChangeSet.print();
|
|
3161
3540
|
resolverChangeSet.print();
|
|
3162
3541
|
return {
|
|
@@ -3196,7 +3575,8 @@ async function planServices$1(client, workspaceId, appName, pipelines) {
|
|
|
3196
3575
|
const { metadata } = await client.getMetadata({ trn: trn$2(workspaceId, resource.namespace.name) });
|
|
3197
3576
|
existingServices[resource.namespace.name] = {
|
|
3198
3577
|
resource,
|
|
3199
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
3578
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
3579
|
+
allLabels: metadata?.labels
|
|
3200
3580
|
};
|
|
3201
3581
|
}));
|
|
3202
3582
|
for (const pipeline of pipelines) {
|
|
@@ -3212,7 +3592,8 @@ async function planServices$1(client, workspaceId, appName, pipelines) {
|
|
|
3212
3592
|
resourceName: pipeline.namespace,
|
|
3213
3593
|
currentOwner: existing.label
|
|
3214
3594
|
});
|
|
3215
|
-
changeSet.
|
|
3595
|
+
if (existing.label === appName && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)) changeSet.unchanged.push({ name: pipeline.namespace });
|
|
3596
|
+
else changeSet.updates.push({
|
|
3216
3597
|
name: pipeline.namespace,
|
|
3217
3598
|
request: {
|
|
3218
3599
|
workspaceId,
|
|
@@ -3248,7 +3629,7 @@ async function planServices$1(client, workspaceId, appName, pipelines) {
|
|
|
3248
3629
|
resourceOwners
|
|
3249
3630
|
};
|
|
3250
3631
|
}
|
|
3251
|
-
async function planResolvers(client, workspaceId, pipelines, executors, deletedServices, env) {
|
|
3632
|
+
async function planResolvers(client, workspaceId, pipelines, executors, deletedServices, env, forceApplyAll = false) {
|
|
3252
3633
|
const changeSet = createChangeSet("Pipeline resolvers");
|
|
3253
3634
|
const fetchResolvers = (namespaceName) => {
|
|
3254
3635
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -3271,29 +3652,35 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
3271
3652
|
for (const pipeline of pipelines) for (const resolver of Object.values(pipeline.resolvers)) if (executorUsedResolvers.has(resolver.name) && resolver.publishEvents === false) throw new Error(`Resolver "${resolver.name}" has publishEvents set to false, but it is used by an executor with a resolverExecuted trigger. Either remove the publishEvents: false setting or remove the executor trigger for this resolver.`);
|
|
3272
3653
|
for (const pipeline of pipelines) {
|
|
3273
3654
|
const existingResolvers = await fetchResolvers(pipeline.namespace);
|
|
3274
|
-
const
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3655
|
+
const existingResolversMap = new Map(existingResolvers.map((resolver) => [resolver.name, resolver]));
|
|
3656
|
+
for (const resolver of Object.values(pipeline.resolvers)) {
|
|
3657
|
+
const desiredResolver = processResolver(pipeline.namespace, resolver, executorUsedResolvers, env);
|
|
3658
|
+
if (existingResolversMap.get(resolver.name)) {
|
|
3659
|
+
const { pipelineResolver: existingResolverDetail } = await client.getPipelineResolver({
|
|
3660
|
+
workspaceId,
|
|
3661
|
+
namespaceName: pipeline.namespace,
|
|
3662
|
+
resolverName: resolver.name
|
|
3663
|
+
});
|
|
3664
|
+
if (!forceApplyAll && existingResolverDetail && areResolversEqual(existingResolverDetail, desiredResolver)) changeSet.unchanged.push({ name: resolver.name });
|
|
3665
|
+
else changeSet.updates.push({
|
|
3666
|
+
name: resolver.name,
|
|
3667
|
+
request: {
|
|
3668
|
+
workspaceId,
|
|
3669
|
+
namespaceName: pipeline.namespace,
|
|
3670
|
+
pipelineResolver: desiredResolver
|
|
3671
|
+
}
|
|
3672
|
+
});
|
|
3673
|
+
existingResolversMap.delete(resolver.name);
|
|
3674
|
+
} else changeSet.creates.push({
|
|
3280
3675
|
name: resolver.name,
|
|
3281
3676
|
request: {
|
|
3282
3677
|
workspaceId,
|
|
3283
3678
|
namespaceName: pipeline.namespace,
|
|
3284
|
-
pipelineResolver:
|
|
3679
|
+
pipelineResolver: desiredResolver
|
|
3285
3680
|
}
|
|
3286
3681
|
});
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
name: resolver.name,
|
|
3290
|
-
request: {
|
|
3291
|
-
workspaceId,
|
|
3292
|
-
namespaceName: pipeline.namespace,
|
|
3293
|
-
pipelineResolver: processResolver(pipeline.namespace, resolver, executorUsedResolvers, env)
|
|
3294
|
-
}
|
|
3295
|
-
});
|
|
3296
|
-
existingNameSet.forEach((name) => {
|
|
3682
|
+
}
|
|
3683
|
+
existingResolversMap.forEach((_resolver, name) => {
|
|
3297
3684
|
changeSet.deletes.push({
|
|
3298
3685
|
name,
|
|
3299
3686
|
request: {
|
|
@@ -3316,6 +3703,59 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
3316
3703
|
});
|
|
3317
3704
|
return changeSet;
|
|
3318
3705
|
}
|
|
3706
|
+
function normalizeComparableResolver(resolver) {
|
|
3707
|
+
const normalized = normalizeProtoConfig(resolver) ?? {};
|
|
3708
|
+
return {
|
|
3709
|
+
name: normalized.name,
|
|
3710
|
+
description: normalized.description ?? "",
|
|
3711
|
+
authorization: normalized.authorization ?? "",
|
|
3712
|
+
operationType: normalized.operationType,
|
|
3713
|
+
publishExecutionEvents: normalized.publishExecutionEvents ?? false,
|
|
3714
|
+
inputs: normalizeComparableFields(normalized.inputs),
|
|
3715
|
+
response: normalizeComparableField(normalized.response),
|
|
3716
|
+
pipelines: normalizeComparablePipelines(normalized.pipelines)
|
|
3717
|
+
};
|
|
3718
|
+
}
|
|
3719
|
+
function areResolversEqual(existing, desired) {
|
|
3720
|
+
return areNormalizedEqual(normalizeComparableResolver(existing), normalizeComparableResolver(desired));
|
|
3721
|
+
}
|
|
3722
|
+
function normalizeComparablePipelines(pipelines) {
|
|
3723
|
+
return (pipelines ?? []).map((pipeline) => ({
|
|
3724
|
+
name: pipeline.name ?? "",
|
|
3725
|
+
operationName: pipeline.operationName ?? "",
|
|
3726
|
+
description: pipeline.description ?? "",
|
|
3727
|
+
operationType: pipeline.operationType,
|
|
3728
|
+
operationSourceRef: pipeline.operationSourceRef ?? "",
|
|
3729
|
+
operationHook: pipeline.operationHook?.expr ?? "",
|
|
3730
|
+
postScript: pipeline.postScript ?? "",
|
|
3731
|
+
skipOperationOnError: pipeline.skipOperationOnError ?? false,
|
|
3732
|
+
invoker: pipeline.invoker ?? void 0
|
|
3733
|
+
}));
|
|
3734
|
+
}
|
|
3735
|
+
function normalizeComparableFields(fields) {
|
|
3736
|
+
return (fields ?? []).map((field) => normalizeComparableField(field));
|
|
3737
|
+
}
|
|
3738
|
+
function normalizeComparableField(field) {
|
|
3739
|
+
if (!field) return;
|
|
3740
|
+
return {
|
|
3741
|
+
name: field.name ?? "",
|
|
3742
|
+
array: field.array ?? false,
|
|
3743
|
+
required: field.required ?? true,
|
|
3744
|
+
description: field.description ?? "",
|
|
3745
|
+
type: normalizeComparableType(field.type)
|
|
3746
|
+
};
|
|
3747
|
+
}
|
|
3748
|
+
function normalizeComparableType(type) {
|
|
3749
|
+
if (!type) return;
|
|
3750
|
+
return {
|
|
3751
|
+
kind: type.kind ?? "",
|
|
3752
|
+
name: type.name ?? "",
|
|
3753
|
+
required: type.required ?? true,
|
|
3754
|
+
description: type.description ?? "",
|
|
3755
|
+
allowedValues: type.allowedValues ?? [],
|
|
3756
|
+
fields: (type.fields ?? []).map((field) => normalizeComparableField(field))
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3319
3759
|
function processResolver(namespace, resolver, executorUsedResolvers, env) {
|
|
3320
3760
|
const pipelines = [{
|
|
3321
3761
|
name: "body",
|
|
@@ -3431,7 +3871,7 @@ function hashValue(value) {
|
|
|
3431
3871
|
* @returns Planned changes for vaults and secrets
|
|
3432
3872
|
*/
|
|
3433
3873
|
async function planSecretManager(context) {
|
|
3434
|
-
const { client, workspaceId, application, forRemoval } = context;
|
|
3874
|
+
const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;
|
|
3435
3875
|
const secretVaults = forRemoval ? [] : application.secrets;
|
|
3436
3876
|
const vaultChangeSet = createChangeSet("Secret Manager vaults");
|
|
3437
3877
|
const secretChangeSet = createChangeSet("Secret Manager secrets");
|
|
@@ -3453,10 +3893,11 @@ async function planSecretManager(context) {
|
|
|
3453
3893
|
});
|
|
3454
3894
|
const existingVaults = {};
|
|
3455
3895
|
await Promise.all(existingVaultList.map(async (resource) => {
|
|
3456
|
-
const { metadata } = await client.getMetadata({ trn: vaultTrn(workspaceId, resource.name) });
|
|
3896
|
+
const { metadata } = await client.getMetadata({ trn: vaultTrn$1(workspaceId, resource.name) });
|
|
3457
3897
|
existingVaults[resource.name] = {
|
|
3458
3898
|
resource,
|
|
3459
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
3899
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
3900
|
+
allLabels: metadata?.labels
|
|
3460
3901
|
};
|
|
3461
3902
|
}));
|
|
3462
3903
|
const state = loadSecretsState();
|
|
@@ -3464,6 +3905,7 @@ async function planSecretManager(context) {
|
|
|
3464
3905
|
const vaultName = vault.vaultName;
|
|
3465
3906
|
const existing = existingVaults[vaultName];
|
|
3466
3907
|
if (existing) {
|
|
3908
|
+
const metaRequest = await buildMetaRequest(vaultTrn$1(workspaceId, vaultName), application.name);
|
|
3467
3909
|
if (!existing.label) unmanaged.push({
|
|
3468
3910
|
resourceType: "Secret Manager vault",
|
|
3469
3911
|
resourceName: vaultName
|
|
@@ -3473,7 +3915,8 @@ async function planSecretManager(context) {
|
|
|
3473
3915
|
resourceName: vaultName,
|
|
3474
3916
|
currentOwner: existing.label
|
|
3475
3917
|
});
|
|
3476
|
-
vaultChangeSet.
|
|
3918
|
+
if (existing.label === application.name && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)) vaultChangeSet.unchanged.push({ name: vaultName });
|
|
3919
|
+
else vaultChangeSet.updates.push({
|
|
3477
3920
|
name: vaultName,
|
|
3478
3921
|
workspaceId
|
|
3479
3922
|
});
|
|
@@ -3499,7 +3942,9 @@ async function planSecretManager(context) {
|
|
|
3499
3942
|
})).map((s) => s.name);
|
|
3500
3943
|
const existingSet = new Set(existingSecrets);
|
|
3501
3944
|
for (const secret of vault.secrets) if (existingSet.has(secret.name)) {
|
|
3502
|
-
|
|
3945
|
+
const currentHash = hashValue(secret.value);
|
|
3946
|
+
const storedHash = state.vaults[vaultName]?.[secret.name];
|
|
3947
|
+
if (forceApplyAll || currentHash !== storedHash) secretChangeSet.updates.push({
|
|
3503
3948
|
name: `${vaultName}/${secret.name}`,
|
|
3504
3949
|
secretName: secret.name,
|
|
3505
3950
|
workspaceId,
|
|
@@ -3562,7 +4007,7 @@ async function planSecretManager(context) {
|
|
|
3562
4007
|
resourceOwners
|
|
3563
4008
|
};
|
|
3564
4009
|
}
|
|
3565
|
-
function vaultTrn(workspaceId, name) {
|
|
4010
|
+
function vaultTrn$1(workspaceId, name) {
|
|
3566
4011
|
return `trn:v1:workspace:${workspaceId}:vault:${name}`;
|
|
3567
4012
|
}
|
|
3568
4013
|
/**
|
|
@@ -3582,12 +4027,12 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
3582
4027
|
secretmanagerVaultName: create.name
|
|
3583
4028
|
});
|
|
3584
4029
|
if (application) {
|
|
3585
|
-
const metaRequest = await buildMetaRequest(vaultTrn(create.workspaceId, create.name), application.name);
|
|
4030
|
+
const metaRequest = await buildMetaRequest(vaultTrn$1(create.workspaceId, create.name), application.name);
|
|
3586
4031
|
await client.setMetadata(metaRequest);
|
|
3587
4032
|
}
|
|
3588
4033
|
}));
|
|
3589
4034
|
if (application) await Promise.all(vaultChangeSet.updates.map(async (update) => {
|
|
3590
|
-
const metaRequest = await buildMetaRequest(vaultTrn(update.workspaceId, update.name), application.name);
|
|
4035
|
+
const metaRequest = await buildMetaRequest(vaultTrn$1(update.workspaceId, update.name), application.name);
|
|
3591
4036
|
await client.setMetadata(metaRequest);
|
|
3592
4037
|
}));
|
|
3593
4038
|
await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret({
|
|
@@ -3655,6 +4100,21 @@ async function applyStaticWebsite(client, result, phase = "create-update") {
|
|
|
3655
4100
|
function trn$1(workspaceId, name) {
|
|
3656
4101
|
return `trn:v1:workspace:${workspaceId}:staticwebsite:${name}`;
|
|
3657
4102
|
}
|
|
4103
|
+
function normalizeComparableStaticWebsiteShape(input) {
|
|
4104
|
+
return {
|
|
4105
|
+
description: input.description,
|
|
4106
|
+
allowedIpAddresses: [...input.allowedIpAddresses].sort()
|
|
4107
|
+
};
|
|
4108
|
+
}
|
|
4109
|
+
function normalizeComparableStaticWebsite(input) {
|
|
4110
|
+
return normalizeComparableStaticWebsiteShape({
|
|
4111
|
+
description: input.description || "",
|
|
4112
|
+
allowedIpAddresses: [...input.allowedIpAddresses || []]
|
|
4113
|
+
});
|
|
4114
|
+
}
|
|
4115
|
+
function areStaticWebsitesEqual(existing, desired) {
|
|
4116
|
+
return areNormalizedEqual(normalizeComparableStaticWebsite(existing), normalizeComparableStaticWebsite(desired));
|
|
4117
|
+
}
|
|
3658
4118
|
/**
|
|
3659
4119
|
* Plan static website changes based on current and desired state.
|
|
3660
4120
|
* @param context - Planning context
|
|
@@ -3684,7 +4144,8 @@ async function planStaticWebsite(context) {
|
|
|
3684
4144
|
const { metadata } = await client.getMetadata({ trn: trn$1(workspaceId, resource.name) });
|
|
3685
4145
|
existingWebsites[resource.name] = {
|
|
3686
4146
|
resource,
|
|
3687
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
4147
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
4148
|
+
allLabels: metadata?.labels
|
|
3688
4149
|
};
|
|
3689
4150
|
}));
|
|
3690
4151
|
const staticWebsiteServices = forRemoval ? [] : application.staticWebsiteServices;
|
|
@@ -3693,7 +4154,17 @@ async function planStaticWebsite(context) {
|
|
|
3693
4154
|
const name = websiteService.name;
|
|
3694
4155
|
const existing = existingWebsites[name];
|
|
3695
4156
|
const metaRequest = await buildMetaRequest(trn$1(workspaceId, name), application.name);
|
|
4157
|
+
const desired = normalizeComparableStaticWebsite(config);
|
|
4158
|
+
const request = {
|
|
4159
|
+
workspaceId,
|
|
4160
|
+
staticwebsite: {
|
|
4161
|
+
name,
|
|
4162
|
+
description: config.description || "",
|
|
4163
|
+
allowedIpAddresses: config.allowedIpAddresses || []
|
|
4164
|
+
}
|
|
4165
|
+
};
|
|
3696
4166
|
if (existing) {
|
|
4167
|
+
const isManagedByApp = existing.label === application.name;
|
|
3697
4168
|
if (!existing.label) unmanaged.push({
|
|
3698
4169
|
resourceType: "StaticWebsite",
|
|
3699
4170
|
resourceName: name
|
|
@@ -3703,29 +4174,16 @@ async function planStaticWebsite(context) {
|
|
|
3703
4174
|
resourceName: name,
|
|
3704
4175
|
currentOwner: existing.label
|
|
3705
4176
|
});
|
|
3706
|
-
changeSet.
|
|
4177
|
+
if (isManagedByApp && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areStaticWebsitesEqual(existing.resource, desired)) changeSet.unchanged.push({ name });
|
|
4178
|
+
else changeSet.updates.push({
|
|
3707
4179
|
name,
|
|
3708
|
-
request
|
|
3709
|
-
workspaceId,
|
|
3710
|
-
staticwebsite: {
|
|
3711
|
-
name,
|
|
3712
|
-
description: config.description || "",
|
|
3713
|
-
allowedIpAddresses: config.allowedIpAddresses || []
|
|
3714
|
-
}
|
|
3715
|
-
},
|
|
4180
|
+
request,
|
|
3716
4181
|
metaRequest
|
|
3717
4182
|
});
|
|
3718
4183
|
delete existingWebsites[name];
|
|
3719
4184
|
} else changeSet.creates.push({
|
|
3720
4185
|
name,
|
|
3721
|
-
request
|
|
3722
|
-
workspaceId,
|
|
3723
|
-
staticwebsite: {
|
|
3724
|
-
name,
|
|
3725
|
-
description: config.description || "",
|
|
3726
|
-
allowedIpAddresses: config.allowedIpAddresses || []
|
|
3727
|
-
}
|
|
3728
|
-
},
|
|
4186
|
+
request,
|
|
3729
4187
|
metaRequest
|
|
3730
4188
|
});
|
|
3731
4189
|
}
|
|
@@ -3949,8 +4407,11 @@ const INITIAL_SCHEMA_NUMBER = 0;
|
|
|
3949
4407
|
* Migration file names (used within migration directories)
|
|
3950
4408
|
*/
|
|
3951
4409
|
const SCHEMA_FILE_NAME = "schema.json";
|
|
4410
|
+
/** File name for migration diff metadata. */
|
|
3952
4411
|
const DIFF_FILE_NAME = "diff.json";
|
|
4412
|
+
/** File name for migration script. */
|
|
3953
4413
|
const MIGRATE_FILE_NAME = "migrate.ts";
|
|
4414
|
+
/** File name for generated DB type definitions. */
|
|
3954
4415
|
const DB_TYPES_FILE_NAME = "db.ts";
|
|
3955
4416
|
/**
|
|
3956
4417
|
* Pattern for validating migration number format (4-digit sequential number)
|
|
@@ -5848,7 +6309,7 @@ async function executeSingleMigrationPostPhase(client, changeSet, migration) {
|
|
|
5848
6309
|
* @returns Planned changes
|
|
5849
6310
|
*/
|
|
5850
6311
|
async function planTailorDB(context) {
|
|
5851
|
-
const { client, workspaceId, application, forRemoval, config, noSchemaCheck } = context;
|
|
6312
|
+
const { client, workspaceId, application, forRemoval, config, noSchemaCheck, forceApplyAll = false } = context;
|
|
5852
6313
|
const tailordbs = [];
|
|
5853
6314
|
if (!forRemoval) for (const tailordb of application.tailorDBServices) {
|
|
5854
6315
|
await tailordb.loadTypes();
|
|
@@ -5857,7 +6318,7 @@ async function planTailorDB(context) {
|
|
|
5857
6318
|
const executors = forRemoval ? [] : Object.values(await application.executorService?.loadExecutors() ?? {});
|
|
5858
6319
|
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices(client, workspaceId, application.name, tailordbs);
|
|
5859
6320
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
5860
|
-
const [typeChangeSet, gqlPermissionChangeSet] = await Promise.all([planTypes(client, workspaceId, tailordbs, executors, deletedServices), planGqlPermissions(client, workspaceId, tailordbs, deletedServices)]);
|
|
6321
|
+
const [typeChangeSet, gqlPermissionChangeSet] = await Promise.all([planTypes(client, workspaceId, tailordbs, executors, deletedServices, void 0, forceApplyAll), planGqlPermissions(client, workspaceId, tailordbs, deletedServices, forceApplyAll)]);
|
|
5861
6322
|
serviceChangeSet.print();
|
|
5862
6323
|
typeChangeSet.print();
|
|
5863
6324
|
gqlPermissionChangeSet.print();
|
|
@@ -5881,6 +6342,21 @@ async function planTailorDB(context) {
|
|
|
5881
6342
|
function trn(workspaceId, name) {
|
|
5882
6343
|
return `${trnPrefix(workspaceId)}:tailordb:${name}`;
|
|
5883
6344
|
}
|
|
6345
|
+
function normalizeComparableTailorDBService(service) {
|
|
6346
|
+
return normalizeProtoConfig({
|
|
6347
|
+
namespace: service.namespace,
|
|
6348
|
+
defaultTimezone: service.defaultTimezone || "UTC"
|
|
6349
|
+
});
|
|
6350
|
+
}
|
|
6351
|
+
function areTailorDBServicesEqual(existing, desired) {
|
|
6352
|
+
return areNormalizedEqual(normalizeComparableTailorDBService({
|
|
6353
|
+
namespace: existing.namespace?.name,
|
|
6354
|
+
defaultTimezone: existing.defaultTimezone
|
|
6355
|
+
}), normalizeComparableTailorDBService({
|
|
6356
|
+
namespace: desired.namespace,
|
|
6357
|
+
defaultTimezone: "UTC"
|
|
6358
|
+
}));
|
|
6359
|
+
}
|
|
5884
6360
|
async function planServices(client, workspaceId, appName, tailordbs) {
|
|
5885
6361
|
const changeSet = createChangeSet("TailorDB services");
|
|
5886
6362
|
const conflicts = [];
|
|
@@ -5922,7 +6398,8 @@ async function planServices(client, workspaceId, appName, tailordbs) {
|
|
|
5922
6398
|
resourceName: tailordb.namespace,
|
|
5923
6399
|
currentOwner: existing.label
|
|
5924
6400
|
});
|
|
5925
|
-
changeSet.
|
|
6401
|
+
if (existing.label === appName && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areTailorDBServicesEqual(existing.resource, tailordb)) changeSet.unchanged.push({ name: tailordb.namespace });
|
|
6402
|
+
else changeSet.updates.push({
|
|
5926
6403
|
name: tailordb.namespace,
|
|
5927
6404
|
metaRequest
|
|
5928
6405
|
});
|
|
@@ -5955,7 +6432,7 @@ async function planServices(client, workspaceId, appName, tailordbs) {
|
|
|
5955
6432
|
resourceOwners
|
|
5956
6433
|
};
|
|
5957
6434
|
}
|
|
5958
|
-
async function planTypes(client, workspaceId, tailordbs, executors, deletedServices, filteredTypesByNamespace) {
|
|
6435
|
+
async function planTypes(client, workspaceId, tailordbs, executors, deletedServices, filteredTypesByNamespace, forceApplyAll = false) {
|
|
5959
6436
|
const changeSet = createChangeSet("TailorDB types");
|
|
5960
6437
|
const fetchTypes = (namespaceName) => {
|
|
5961
6438
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -5974,7 +6451,7 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
5974
6451
|
});
|
|
5975
6452
|
};
|
|
5976
6453
|
const executorUsedTypes = /* @__PURE__ */ new Set();
|
|
5977
|
-
for (const executor of executors) if (executor.trigger.kind === "
|
|
6454
|
+
for (const executor of executors) if (executor.trigger.kind === "tailordb") executorUsedTypes.add(executor.trigger.typeName);
|
|
5978
6455
|
for (const tailordb of tailordbs) {
|
|
5979
6456
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
5980
6457
|
for (const typeName of Object.keys(types)) {
|
|
@@ -5984,13 +6461,14 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
5984
6461
|
}
|
|
5985
6462
|
for (const tailordb of tailordbs) {
|
|
5986
6463
|
const existingTypes = await fetchTypes(tailordb.namespace);
|
|
5987
|
-
const
|
|
5988
|
-
existingTypes.forEach((type) => existingNameSet.add(type.name));
|
|
6464
|
+
const existingTypesMap = new Map(existingTypes.map((type) => [type.name, type]));
|
|
5989
6465
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
5990
6466
|
for (const typeName of Object.keys(types)) {
|
|
5991
6467
|
const tailordbType = generateTailorDBTypeManifest(types[typeName], executorUsedTypes, tailordb.config.gqlOperations);
|
|
5992
|
-
|
|
5993
|
-
|
|
6468
|
+
const existingType = existingTypesMap.get(typeName);
|
|
6469
|
+
if (existingType) {
|
|
6470
|
+
if (!forceApplyAll && areNormalizedEqual(normalizeComparableTailorDBType(existingType), normalizeComparableTailorDBType(tailordbType))) changeSet.unchanged.push({ name: typeName });
|
|
6471
|
+
else changeSet.updates.push({
|
|
5994
6472
|
name: typeName,
|
|
5995
6473
|
request: {
|
|
5996
6474
|
workspaceId,
|
|
@@ -5998,7 +6476,7 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
5998
6476
|
tailordbType
|
|
5999
6477
|
}
|
|
6000
6478
|
});
|
|
6001
|
-
|
|
6479
|
+
existingTypesMap.delete(typeName);
|
|
6002
6480
|
} else changeSet.creates.push({
|
|
6003
6481
|
name: typeName,
|
|
6004
6482
|
request: {
|
|
@@ -6008,7 +6486,7 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
6008
6486
|
}
|
|
6009
6487
|
});
|
|
6010
6488
|
}
|
|
6011
|
-
|
|
6489
|
+
existingTypesMap.forEach((_type, name) => {
|
|
6012
6490
|
changeSet.deletes.push({
|
|
6013
6491
|
name,
|
|
6014
6492
|
request: {
|
|
@@ -6031,6 +6509,66 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
6031
6509
|
});
|
|
6032
6510
|
return changeSet;
|
|
6033
6511
|
}
|
|
6512
|
+
function isPlainObject(value) {
|
|
6513
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6514
|
+
}
|
|
6515
|
+
const tailordbCompareKnownDefaults = {
|
|
6516
|
+
disableGqlOperations: {
|
|
6517
|
+
create: false,
|
|
6518
|
+
update: false,
|
|
6519
|
+
delete: false,
|
|
6520
|
+
read: false
|
|
6521
|
+
},
|
|
6522
|
+
emptyExpression: "",
|
|
6523
|
+
numericStringPaths: new Set([
|
|
6524
|
+
"schema.fields.*.serial.start",
|
|
6525
|
+
"schema.fields.*.serial.maxValue",
|
|
6526
|
+
"schema.settings.defaultQueryLimitSize",
|
|
6527
|
+
"schema.settings.maxBulkUpsertSize"
|
|
6528
|
+
])
|
|
6529
|
+
};
|
|
6530
|
+
function normalizeComparableTailorDBType(type) {
|
|
6531
|
+
const normalized = normalizeProtoConfig(type);
|
|
6532
|
+
return normalizeTailorDBCompareValue({
|
|
6533
|
+
name: normalized?.name ?? "",
|
|
6534
|
+
schema: {
|
|
6535
|
+
description: normalized?.schema?.description ?? "",
|
|
6536
|
+
fields: normalized?.schema?.fields ?? {},
|
|
6537
|
+
relationships: normalized?.schema?.relationships ?? {},
|
|
6538
|
+
settings: normalized?.schema?.settings ?? {},
|
|
6539
|
+
indexes: normalized?.schema?.indexes ?? {},
|
|
6540
|
+
files: normalized?.schema?.files ?? {},
|
|
6541
|
+
permission: normalized?.schema?.permission ?? {}
|
|
6542
|
+
}
|
|
6543
|
+
}, []);
|
|
6544
|
+
}
|
|
6545
|
+
function normalizeTailorDBCompareValue(value, path) {
|
|
6546
|
+
if (value === void 0 || value === null) return value;
|
|
6547
|
+
if (typeof value === "number" || typeof value === "bigint" || typeof value === "string") {
|
|
6548
|
+
if (matchesNumericStringPath(path) && isNumericLikeValue(value)) return String(value);
|
|
6549
|
+
if (path.at(-1) === "expr" && value === tailordbCompareKnownDefaults.emptyExpression) return;
|
|
6550
|
+
return value;
|
|
6551
|
+
}
|
|
6552
|
+
if (Array.isArray(value)) return value.map((item, index) => normalizeTailorDBCompareValue(item, [...path, index])).filter((item) => item !== void 0);
|
|
6553
|
+
if (!isPlainObject(value)) return value;
|
|
6554
|
+
const normalizedEntries = Object.entries(value).map(([key, entryValue]) => [key, normalizeTailorDBCompareValue(entryValue, [...path, key])]).filter(([, entryValue]) => entryValue !== void 0);
|
|
6555
|
+
const normalizedObject = Object.fromEntries(normalizedEntries);
|
|
6556
|
+
if (path.at(-1) === "fields" && Object.keys(normalizedObject).length === 0) return;
|
|
6557
|
+
if (path.at(-1) === "disableGqlOperations" && areNormalizedEqual(normalizedObject, tailordbCompareKnownDefaults.disableGqlOperations)) return;
|
|
6558
|
+
return normalizedObject;
|
|
6559
|
+
}
|
|
6560
|
+
function matchesNumericStringPath(path) {
|
|
6561
|
+
const pathKey = path.map((segment) => String(segment)).join(".");
|
|
6562
|
+
return [...tailordbCompareKnownDefaults.numericStringPaths].some((pattern) => {
|
|
6563
|
+
const patternParts = pattern.split(".");
|
|
6564
|
+
const pathParts = pathKey.split(".");
|
|
6565
|
+
if (patternParts.length !== pathParts.length) return false;
|
|
6566
|
+
return patternParts.every((part, index) => part === "*" || part === pathParts[index]);
|
|
6567
|
+
});
|
|
6568
|
+
}
|
|
6569
|
+
function isNumericLikeValue(value) {
|
|
6570
|
+
return typeof value === "number" || typeof value === "bigint" || /^-?\d+$/.test(value);
|
|
6571
|
+
}
|
|
6034
6572
|
/**
|
|
6035
6573
|
* Generate a TailorDB type manifest from parsed type
|
|
6036
6574
|
* @param {TailorDBType} type - Parsed TailorDB type
|
|
@@ -6267,7 +6805,7 @@ function protoOperand(operand) {
|
|
|
6267
6805
|
value: fromJson(ValueSchema, operand)
|
|
6268
6806
|
} };
|
|
6269
6807
|
}
|
|
6270
|
-
async function planGqlPermissions(client, workspaceId, tailordbs, deletedServices) {
|
|
6808
|
+
async function planGqlPermissions(client, workspaceId, tailordbs, deletedServices, forceApplyAll = false) {
|
|
6271
6809
|
const changeSet = createChangeSet("TailorDB gqlPermissions");
|
|
6272
6810
|
const fetchGqlPermissions = (namespaceName) => {
|
|
6273
6811
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -6295,14 +6833,17 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
6295
6833
|
for (const typeName of Object.keys(types)) {
|
|
6296
6834
|
const gqlPermission = types[typeName].permissions.gql;
|
|
6297
6835
|
if (!gqlPermission) continue;
|
|
6836
|
+
const desiredPermission = protoGqlPermission(gqlPermission);
|
|
6837
|
+
const existingPermission = existingGqlPermissions.find((entry) => entry.typeName === typeName);
|
|
6298
6838
|
if (existingNameSet.has(typeName)) {
|
|
6299
|
-
changeSet.
|
|
6839
|
+
if (!forceApplyAll && existingPermission && areNormalizedEqual(normalizeComparableGqlPermission(existingPermission.permission), normalizeComparableGqlPermission(desiredPermission))) changeSet.unchanged.push({ name: typeName });
|
|
6840
|
+
else changeSet.updates.push({
|
|
6300
6841
|
name: typeName,
|
|
6301
6842
|
request: {
|
|
6302
6843
|
workspaceId,
|
|
6303
6844
|
namespaceName: tailordb.namespace,
|
|
6304
6845
|
typeName,
|
|
6305
|
-
permission:
|
|
6846
|
+
permission: desiredPermission
|
|
6306
6847
|
}
|
|
6307
6848
|
});
|
|
6308
6849
|
existingNameSet.delete(typeName);
|
|
@@ -6312,7 +6853,7 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
6312
6853
|
workspaceId,
|
|
6313
6854
|
namespaceName: tailordb.namespace,
|
|
6314
6855
|
typeName,
|
|
6315
|
-
permission:
|
|
6856
|
+
permission: desiredPermission
|
|
6316
6857
|
}
|
|
6317
6858
|
});
|
|
6318
6859
|
}
|
|
@@ -6339,6 +6880,12 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
6339
6880
|
});
|
|
6340
6881
|
return changeSet;
|
|
6341
6882
|
}
|
|
6883
|
+
function normalizeComparableGqlPermission(permission) {
|
|
6884
|
+
return { policies: (normalizeProtoConfig(permission)?.policies ?? []).map((policy) => ({
|
|
6885
|
+
...policy,
|
|
6886
|
+
actions: [...policy.actions ?? []].sort((left, right) => left - right)
|
|
6887
|
+
})) };
|
|
6888
|
+
}
|
|
6342
6889
|
function protoGqlPermission(permission) {
|
|
6343
6890
|
return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
|
|
6344
6891
|
}
|
|
@@ -6503,7 +7050,7 @@ function formatMigrationCheckResults(results) {
|
|
|
6503
7050
|
async function applyWorkflow(client, result, phase = "create-update") {
|
|
6504
7051
|
const { changeSet, appName } = result;
|
|
6505
7052
|
if (phase === "create-update") {
|
|
6506
|
-
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName);
|
|
7053
|
+
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, result.unchangedWorkflowJobNames);
|
|
6507
7054
|
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
6508
7055
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
|
|
6509
7056
|
await client.createWorkflow({
|
|
@@ -6549,14 +7096,16 @@ function filterJobFunctionVersions(allVersions, usedJobNames) {
|
|
|
6549
7096
|
* @param client - Operator client instance
|
|
6550
7097
|
* @param changeSet - Workflow change set
|
|
6551
7098
|
* @param appName - Application name
|
|
7099
|
+
* @param unchangedWorkflowJobNames - Job function names used by unchanged workflows
|
|
6552
7100
|
* @returns Map of job function names to versions
|
|
6553
7101
|
*/
|
|
6554
|
-
async function registerJobFunctions(client, changeSet, appName) {
|
|
7102
|
+
async function registerJobFunctions(client, changeSet, appName, unchangedWorkflowJobNames = /* @__PURE__ */ new Set()) {
|
|
6555
7103
|
const jobFunctionVersions = {};
|
|
6556
|
-
const firstWorkflow = changeSet.creates[0] || changeSet.updates[0];
|
|
7104
|
+
const firstWorkflow = changeSet.creates[0] || changeSet.updates[0] || changeSet.deletes[0];
|
|
6557
7105
|
if (!firstWorkflow) return jobFunctionVersions;
|
|
6558
7106
|
const { workspaceId } = firstWorkflow;
|
|
6559
7107
|
const allUsedJobNames = /* @__PURE__ */ new Set();
|
|
7108
|
+
unchangedWorkflowJobNames.forEach((jobName) => allUsedJobNames.add(jobName));
|
|
6560
7109
|
for (const item of [...changeSet.creates, ...changeSet.updates]) for (const jobName of item.usedJobNames) allUsedJobNames.add(jobName);
|
|
6561
7110
|
const existingJobFunctions = await fetchAll(async (pageToken, maxPageSize) => {
|
|
6562
7111
|
const response = await client.listWorkflowJobFunctions({
|
|
@@ -6567,23 +7116,25 @@ async function registerJobFunctions(client, changeSet, appName) {
|
|
|
6567
7116
|
return [response.jobFunctions.map((j) => j.name), response.nextPageToken];
|
|
6568
7117
|
});
|
|
6569
7118
|
const existingJobNamesSet = new Set(existingJobFunctions);
|
|
6570
|
-
|
|
6571
|
-
const
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
7119
|
+
if (changeSet.creates.length > 0 || changeSet.updates.length > 0) {
|
|
7120
|
+
const results = await Promise.all(Array.from(allUsedJobNames).map(async (jobName) => {
|
|
7121
|
+
const response = existingJobNamesSet.has(jobName) ? await client.updateWorkflowJobFunction({
|
|
7122
|
+
workspaceId,
|
|
7123
|
+
jobFunctionName: jobName,
|
|
7124
|
+
scriptRef: workflowJobFunctionName(jobName)
|
|
7125
|
+
}) : await client.createWorkflowJobFunction({
|
|
7126
|
+
workspaceId,
|
|
7127
|
+
jobFunctionName: jobName,
|
|
7128
|
+
scriptRef: workflowJobFunctionName(jobName)
|
|
7129
|
+
});
|
|
7130
|
+
await client.setMetadata(await buildMetaRequest(jobFunctionTrn(workspaceId, jobName), appName));
|
|
7131
|
+
return {
|
|
7132
|
+
jobName,
|
|
7133
|
+
version: response.jobFunction?.version
|
|
7134
|
+
};
|
|
7135
|
+
}));
|
|
7136
|
+
for (const { jobName, version } of results) if (version) jobFunctionVersions[jobName] = version;
|
|
7137
|
+
}
|
|
6587
7138
|
const unusedJobFunctions = existingJobFunctions.filter((jobName) => !allUsedJobNames.has(jobName));
|
|
6588
7139
|
await Promise.all(unusedJobFunctions.map(async (jobName) => {
|
|
6589
7140
|
const { metadata } = await client.getMetadata({ trn: jobFunctionTrn(workspaceId, jobName) });
|
|
@@ -6611,7 +7162,7 @@ function toRetryPolicy(policy) {
|
|
|
6611
7162
|
backoffMultiplier: policy.backoffMultiplier
|
|
6612
7163
|
};
|
|
6613
7164
|
}
|
|
6614
|
-
function workflowTrn(workspaceId, name) {
|
|
7165
|
+
function workflowTrn$1(workspaceId, name) {
|
|
6615
7166
|
return `trn:v1:workspace:${workspaceId}:workflow:${name}`;
|
|
6616
7167
|
}
|
|
6617
7168
|
function jobFunctionTrn(workspaceId, name) {
|
|
@@ -6624,35 +7175,35 @@ function jobFunctionTrn(workspaceId, name) {
|
|
|
6624
7175
|
* @param appName - Application name
|
|
6625
7176
|
* @param workflows - Parsed workflows
|
|
6626
7177
|
* @param mainJobDeps - Main job dependencies by workflow
|
|
7178
|
+
* @param unchangedJobFunctions - Job functions already proven unchanged by function registry plan
|
|
6627
7179
|
* @returns Planned workflow changes
|
|
6628
7180
|
*/
|
|
6629
|
-
async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps) {
|
|
7181
|
+
async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps, unchangedJobFunctions = /* @__PURE__ */ new Set()) {
|
|
6630
7182
|
const changeSet = createChangeSet("Workflows");
|
|
6631
7183
|
const conflicts = [];
|
|
6632
7184
|
const unmanaged = [];
|
|
6633
7185
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
7186
|
+
const unchangedWorkflowJobNames = /* @__PURE__ */ new Set();
|
|
6634
7187
|
const withoutLabel = await fetchAll(async (pageToken, maxPageSize) => {
|
|
6635
7188
|
const response = await client.listWorkflows({
|
|
6636
7189
|
workspaceId,
|
|
6637
7190
|
pageToken,
|
|
6638
7191
|
pageSize: maxPageSize
|
|
6639
7192
|
});
|
|
6640
|
-
return [response.workflows.
|
|
6641
|
-
id: w.id,
|
|
6642
|
-
name: w.name
|
|
6643
|
-
})), response.nextPageToken];
|
|
7193
|
+
return [response.workflows, response.nextPageToken];
|
|
6644
7194
|
});
|
|
6645
7195
|
const existingWorkflows = {};
|
|
6646
7196
|
await Promise.all(withoutLabel.map(async (resource) => {
|
|
6647
|
-
const { metadata } = await client.getMetadata({ trn: workflowTrn(workspaceId, resource.name) });
|
|
7197
|
+
const { metadata } = await client.getMetadata({ trn: workflowTrn$1(workspaceId, resource.name) });
|
|
6648
7198
|
existingWorkflows[resource.name] = {
|
|
6649
7199
|
resource,
|
|
6650
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
7200
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
7201
|
+
allLabels: metadata?.labels
|
|
6651
7202
|
};
|
|
6652
7203
|
}));
|
|
6653
7204
|
for (const workflow of Object.values(workflows)) {
|
|
6654
7205
|
const existing = existingWorkflows[workflow.name];
|
|
6655
|
-
const metaRequest = await buildMetaRequest(workflowTrn(workspaceId, workflow.name), appName);
|
|
7206
|
+
const metaRequest = await buildMetaRequest(workflowTrn$1(workspaceId, workflow.name), appName);
|
|
6656
7207
|
const usedJobNames = mainJobDeps[workflow.mainJob.name];
|
|
6657
7208
|
if (!usedJobNames) throw new Error(`Job "${workflow.mainJob.name}" (mainJob of workflow "${workflow.name}") was not found.\n\nPossible causes:\n - The job is not exported as a named export\n - The file containing the job is not included in workflow.files glob pattern\n\nSolution:\n export const ${workflow.mainJob.name} = createWorkflowJob({ name: "${workflow.mainJob.name}", ... })`);
|
|
6658
7209
|
if (existing) {
|
|
@@ -6665,7 +7216,10 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
6665
7216
|
resourceName: workflow.name,
|
|
6666
7217
|
currentOwner: existing.label
|
|
6667
7218
|
});
|
|
6668
|
-
|
|
7219
|
+
if (existing.label === appName && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && canTreatWorkflowAsUnchanged(existing.resource, workflow, usedJobNames, unchangedJobFunctions)) {
|
|
7220
|
+
changeSet.unchanged.push({ name: workflow.name });
|
|
7221
|
+
for (const jobName of usedJobNames) unchangedWorkflowJobNames.add(jobName);
|
|
7222
|
+
} else changeSet.updates.push({
|
|
6669
7223
|
name: workflow.name,
|
|
6670
7224
|
workspaceId,
|
|
6671
7225
|
workflow,
|
|
@@ -6696,12 +7250,158 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
6696
7250
|
conflicts,
|
|
6697
7251
|
unmanaged,
|
|
6698
7252
|
resourceOwners,
|
|
6699
|
-
appName
|
|
7253
|
+
appName,
|
|
7254
|
+
unchangedWorkflowJobNames
|
|
7255
|
+
};
|
|
7256
|
+
}
|
|
7257
|
+
function canTreatWorkflowAsUnchanged(existing, workflow, usedJobNames, unchangedJobFunctions) {
|
|
7258
|
+
if (!usedJobNames.every((jobName) => unchangedJobFunctions.has(jobName))) return false;
|
|
7259
|
+
return areWorkflowsEqual(existing, workflow, usedJobNames);
|
|
7260
|
+
}
|
|
7261
|
+
function areWorkflowsEqual(existing, workflow, usedJobNames) {
|
|
7262
|
+
return existing.mainJobFunctionName === workflow.mainJob.name && areNormalizedEqual(normalizeComparableExistingWorkflowRetryPolicy(existing.retryPolicy), normalizeComparableWorkflowRetryPolicy(workflow.retryPolicy)) && areNormalizedEqual(normalizeComparableWorkflowJobNames(existing.jobFunctions), normalizeComparableWorkflowJobNames(usedJobNames));
|
|
7263
|
+
}
|
|
7264
|
+
function normalizeComparableExistingWorkflowRetryPolicy(policy) {
|
|
7265
|
+
if (!policy) return;
|
|
7266
|
+
return normalizeRetryPolicyForCompare({
|
|
7267
|
+
maxRetries: policy.maxRetries ?? 0,
|
|
7268
|
+
backoffMultiplier: policy.backoffMultiplier ?? 0,
|
|
7269
|
+
initialBackoff: {
|
|
7270
|
+
seconds: policy.initialBackoff?.seconds ?? 0n,
|
|
7271
|
+
nanos: policy.initialBackoff?.nanos ?? 0
|
|
7272
|
+
},
|
|
7273
|
+
maxBackoff: {
|
|
7274
|
+
seconds: policy.maxBackoff?.seconds ?? 0n,
|
|
7275
|
+
nanos: policy.maxBackoff?.nanos ?? 0
|
|
7276
|
+
}
|
|
7277
|
+
});
|
|
7278
|
+
}
|
|
7279
|
+
function normalizeComparableWorkflowRetryPolicy(policy) {
|
|
7280
|
+
if (!policy) return;
|
|
7281
|
+
return normalizeRetryPolicyForCompare({
|
|
7282
|
+
maxRetries: policy.maxRetries,
|
|
7283
|
+
backoffMultiplier: policy.backoffMultiplier,
|
|
7284
|
+
initialBackoff: parseDurationToProto(policy.initialBackoff),
|
|
7285
|
+
maxBackoff: parseDurationToProto(policy.maxBackoff)
|
|
7286
|
+
});
|
|
7287
|
+
}
|
|
7288
|
+
function normalizeComparableWorkflowJobNames(jobFunctions) {
|
|
7289
|
+
return Array.isArray(jobFunctions) ? [...jobFunctions].sort() : Object.keys(jobFunctions ?? {}).sort();
|
|
7290
|
+
}
|
|
7291
|
+
function normalizeRetryPolicyForCompare(policy) {
|
|
7292
|
+
return {
|
|
7293
|
+
maxRetries: policy.maxRetries,
|
|
7294
|
+
backoffMultiplier: policy.backoffMultiplier,
|
|
7295
|
+
initialBackoff: {
|
|
7296
|
+
seconds: String(policy.initialBackoff.seconds),
|
|
7297
|
+
nanos: policy.initialBackoff.nanos
|
|
7298
|
+
},
|
|
7299
|
+
maxBackoff: {
|
|
7300
|
+
seconds: String(policy.maxBackoff.seconds),
|
|
7301
|
+
nanos: policy.maxBackoff.nanos
|
|
7302
|
+
}
|
|
6700
7303
|
};
|
|
6701
7304
|
}
|
|
6702
7305
|
|
|
6703
7306
|
//#endregion
|
|
6704
7307
|
//#region src/cli/commands/apply/apply.ts
|
|
7308
|
+
function applicationTrn(workspaceId, name) {
|
|
7309
|
+
return `trn:v1:workspace:${workspaceId}:application:${name}`;
|
|
7310
|
+
}
|
|
7311
|
+
function functionRegistryTrn(workspaceId, name) {
|
|
7312
|
+
return `trn:v1:workspace:${workspaceId}:function_registry:${name}`;
|
|
7313
|
+
}
|
|
7314
|
+
function pipelineTrn(workspaceId, name) {
|
|
7315
|
+
return `trn:v1:workspace:${workspaceId}:pipeline:${name}`;
|
|
7316
|
+
}
|
|
7317
|
+
function idpTrn(workspaceId, name) {
|
|
7318
|
+
return `trn:v1:workspace:${workspaceId}:idp:${name}`;
|
|
7319
|
+
}
|
|
7320
|
+
function authTrn(workspaceId, name) {
|
|
7321
|
+
return `trn:v1:workspace:${workspaceId}:auth:${name}`;
|
|
7322
|
+
}
|
|
7323
|
+
function executorTrn(workspaceId, name) {
|
|
7324
|
+
return `trn:v1:workspace:${workspaceId}:executor:${name}`;
|
|
7325
|
+
}
|
|
7326
|
+
function workflowTrn(workspaceId, name) {
|
|
7327
|
+
return `trn:v1:workspace:${workspaceId}:workflow:${name}`;
|
|
7328
|
+
}
|
|
7329
|
+
function staticWebsiteTrn(workspaceId, name) {
|
|
7330
|
+
return `trn:v1:workspace:${workspaceId}:staticwebsite:${name}`;
|
|
7331
|
+
}
|
|
7332
|
+
function tailorDBTrn(workspaceId, name) {
|
|
7333
|
+
return `trn:v1:workspace:${workspaceId}:tailordb:${name}`;
|
|
7334
|
+
}
|
|
7335
|
+
function vaultTrn(workspaceId, name) {
|
|
7336
|
+
return `trn:v1:workspace:${workspaceId}:vault:${name}`;
|
|
7337
|
+
}
|
|
7338
|
+
async function shouldForceApplyAll(client, workspaceId, application, functionEntries) {
|
|
7339
|
+
const desiredLabels = (await buildMetaRequest(applicationTrn(workspaceId, application.name), application.name)).labels;
|
|
7340
|
+
const candidateTrns = /* @__PURE__ */ new Set();
|
|
7341
|
+
if (application.subgraphs.length > 0) candidateTrns.add(applicationTrn(workspaceId, application.name));
|
|
7342
|
+
application.staticWebsiteServices.forEach((website) => {
|
|
7343
|
+
candidateTrns.add(staticWebsiteTrn(workspaceId, website.name));
|
|
7344
|
+
});
|
|
7345
|
+
application.resolverServices.forEach((pipeline) => {
|
|
7346
|
+
candidateTrns.add(pipelineTrn(workspaceId, pipeline.namespace));
|
|
7347
|
+
});
|
|
7348
|
+
application.idpServices.forEach((idp) => {
|
|
7349
|
+
candidateTrns.add(idpTrn(workspaceId, idp.name));
|
|
7350
|
+
});
|
|
7351
|
+
if (application.authService) candidateTrns.add(authTrn(workspaceId, application.authService.config.name));
|
|
7352
|
+
Object.values(application.executorService?.executors ?? {}).forEach((executor) => {
|
|
7353
|
+
candidateTrns.add(executorTrn(workspaceId, executor.name));
|
|
7354
|
+
});
|
|
7355
|
+
Object.values(application.workflowService?.workflows ?? {}).forEach((workflow) => {
|
|
7356
|
+
candidateTrns.add(workflowTrn(workspaceId, workflow.name));
|
|
7357
|
+
});
|
|
7358
|
+
application.tailorDBServices.forEach((service) => {
|
|
7359
|
+
candidateTrns.add(tailorDBTrn(workspaceId, service.namespace));
|
|
7360
|
+
});
|
|
7361
|
+
application.secrets.forEach((vault) => {
|
|
7362
|
+
candidateTrns.add(vaultTrn(workspaceId, vault.vaultName));
|
|
7363
|
+
});
|
|
7364
|
+
functionEntries.forEach((entry) => {
|
|
7365
|
+
candidateTrns.add(functionRegistryTrn(workspaceId, entry.name));
|
|
7366
|
+
});
|
|
7367
|
+
for (const trn of candidateTrns) try {
|
|
7368
|
+
const { metadata } = await client.getMetadata({ trn });
|
|
7369
|
+
if (metadata?.labels?.["sdk-name"] !== application.name) continue;
|
|
7370
|
+
if (!hasMatchingSdkVersion(metadata.labels, desiredLabels)) return true;
|
|
7371
|
+
} catch (error) {
|
|
7372
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) continue;
|
|
7373
|
+
throw error;
|
|
7374
|
+
}
|
|
7375
|
+
return false;
|
|
7376
|
+
}
|
|
7377
|
+
function printPlanSummary(results) {
|
|
7378
|
+
const summary = summarizeChangeSets([
|
|
7379
|
+
results.functionRegistry.changeSet,
|
|
7380
|
+
results.tailorDB.changeSet.service,
|
|
7381
|
+
results.tailorDB.changeSet.type,
|
|
7382
|
+
results.tailorDB.changeSet.gqlPermission,
|
|
7383
|
+
results.staticWebsite.changeSet,
|
|
7384
|
+
results.idp.changeSet.service,
|
|
7385
|
+
results.idp.changeSet.client,
|
|
7386
|
+
results.auth.changeSet.service,
|
|
7387
|
+
results.auth.changeSet.idpConfig,
|
|
7388
|
+
results.auth.changeSet.userProfileConfig,
|
|
7389
|
+
results.auth.changeSet.tenantConfig,
|
|
7390
|
+
results.auth.changeSet.machineUser,
|
|
7391
|
+
results.auth.changeSet.oauth2Client,
|
|
7392
|
+
results.auth.changeSet.authHook,
|
|
7393
|
+
results.auth.changeSet.scim,
|
|
7394
|
+
results.auth.changeSet.scimResource,
|
|
7395
|
+
results.pipeline.changeSet.service,
|
|
7396
|
+
results.pipeline.changeSet.resolver,
|
|
7397
|
+
results.app,
|
|
7398
|
+
results.executor.changeSet,
|
|
7399
|
+
results.workflow.changeSet,
|
|
7400
|
+
results.secretManager.vaultChangeSet,
|
|
7401
|
+
results.secretManager.secretChangeSet
|
|
7402
|
+
]);
|
|
7403
|
+
logger.log(formatPlanSummary(summary));
|
|
7404
|
+
}
|
|
6705
7405
|
/**
|
|
6706
7406
|
* Apply the configured application to the Tailor platform.
|
|
6707
7407
|
* @param options - Options for apply execution
|
|
@@ -6775,9 +7475,10 @@ async function apply(options) {
|
|
|
6775
7475
|
rootSpan.setAttribute("app.name", application.name);
|
|
6776
7476
|
rootSpan.setAttribute("workspace.id", workspaceId);
|
|
6777
7477
|
const workflowService = application.workflowService;
|
|
6778
|
-
const functionEntries = collectFunctionEntries(application, workflowService?.jobs ?? [], bundledScripts);
|
|
7478
|
+
const functionEntries = collectFunctionEntries(application, filterBundledWorkflowJobs(workflowService?.jobs ?? [], workflowBuildResult?.usedJobNames ?? []), bundledScripts);
|
|
6779
7479
|
const dryRun = options?.dryRun ?? false;
|
|
6780
7480
|
const yes = options?.yes ?? false;
|
|
7481
|
+
const forceApplyAll = await withSpan("plan.detectSdkVersionChange", () => shouldForceApplyAll(client, workspaceId, application, functionEntries));
|
|
6781
7482
|
const { functionRegistry, tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager } = await withSpan("plan", async () => {
|
|
6782
7483
|
const ctx = {
|
|
6783
7484
|
client,
|
|
@@ -6785,10 +7486,12 @@ async function apply(options) {
|
|
|
6785
7486
|
application,
|
|
6786
7487
|
forRemoval: false,
|
|
6787
7488
|
config,
|
|
6788
|
-
noSchemaCheck: options?.noSchemaCheck
|
|
7489
|
+
noSchemaCheck: options?.noSchemaCheck,
|
|
7490
|
+
forceApplyAll
|
|
6789
7491
|
};
|
|
6790
|
-
const
|
|
6791
|
-
|
|
7492
|
+
const functionRegistry = await withSpan("plan.functionRegistry", () => planFunctionRegistry(client, workspaceId, application.name, functionEntries));
|
|
7493
|
+
const unchangedWorkflowJobs = new Set(functionRegistry.changeSet.unchanged.map((entry) => entry.name).filter((name) => name.startsWith("workflow--")).map((name) => name.slice(10)));
|
|
7494
|
+
const [tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager] = await Promise.all([
|
|
6792
7495
|
withSpan("plan.tailorDB", () => planTailorDB(ctx)),
|
|
6793
7496
|
withSpan("plan.staticWebsite", () => planStaticWebsite(ctx)),
|
|
6794
7497
|
withSpan("plan.idp", () => planIdP(ctx)),
|
|
@@ -6796,7 +7499,7 @@ async function apply(options) {
|
|
|
6796
7499
|
withSpan("plan.pipeline", () => planPipeline(ctx)),
|
|
6797
7500
|
withSpan("plan.application", () => planApplication(ctx)),
|
|
6798
7501
|
withSpan("plan.executor", () => planExecutor(ctx)),
|
|
6799
|
-
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {})),
|
|
7502
|
+
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {}, unchangedWorkflowJobs)),
|
|
6800
7503
|
withSpan("plan.secretManager", () => planSecretManager(ctx))
|
|
6801
7504
|
]);
|
|
6802
7505
|
return {
|
|
@@ -6882,6 +7585,18 @@ async function apply(options) {
|
|
|
6882
7585
|
}
|
|
6883
7586
|
});
|
|
6884
7587
|
});
|
|
7588
|
+
printPlanSummary({
|
|
7589
|
+
functionRegistry,
|
|
7590
|
+
tailorDB,
|
|
7591
|
+
staticWebsite,
|
|
7592
|
+
idp,
|
|
7593
|
+
auth,
|
|
7594
|
+
pipeline,
|
|
7595
|
+
app,
|
|
7596
|
+
executor,
|
|
7597
|
+
workflow,
|
|
7598
|
+
secretManager
|
|
7599
|
+
});
|
|
6885
7600
|
if (dryRun) {
|
|
6886
7601
|
logger.info("Dry run enabled. No changes applied.");
|
|
6887
7602
|
return;
|
|
@@ -10965,7 +11680,7 @@ async function generate(options) {
|
|
|
10965
11680
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
10966
11681
|
let pluginManager;
|
|
10967
11682
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
10968
|
-
const { defineApplication } = await import("./application-
|
|
11683
|
+
const { defineApplication } = await import("./application-ChVyhwe-.mjs");
|
|
10969
11684
|
const application = defineApplication({
|
|
10970
11685
|
config,
|
|
10971
11686
|
pluginManager
|
|
@@ -13170,4 +13885,4 @@ function isDeno() {
|
|
|
13170
13885
|
|
|
13171
13886
|
//#endregion
|
|
13172
13887
|
export { getFolder as $, getNextMigrationNumber as $t, listWorkflows as A, functionExecutionStatusToString as At, updateCommand$1 as B, DB_TYPES_FILE_NAME as Bt, listApps as C, startCommand as Ct, resumeCommand as D, executionsCommand as Dt, healthCommand as E, getWorkflow as Et, show as F, executeScript as Ft, listOrganizations as G, compareLocalTypesWithSnapshot as Gt, organizationTree as H, INITIAL_SCHEMA_NUMBER as Ht, showCommand as I, waitForExecution$1 as It, updateCommand$2 as J, formatMigrationNumber as Jt, getCommand$1 as K, compareSnapshots as Kt, logBetaWarning as L, MIGRATION_LABEL_KEY as Lt, truncateCommand as M, getCommand$5 as Mt, generate as N, getExecutor as Nt, resumeWorkflow as O, getWorkflowExecution as Ot, generateCommand as P, apply as Pt, getCommand$2 as Q, getMigrationFiles as Qt, remove as R, parseMigrationLabelNumber as Rt, createWorkspace as S, watchExecutorJob as St, getAppHealth as T, getCommand$4 as Tt, treeCommand as U, MIGRATE_FILE_NAME as Ut, updateOrganization as V, DIFF_FILE_NAME as Vt, listCommand$4 as W, SCHEMA_FILE_NAME as Wt, listCommand$5 as X, getMigrationDirPath as Xt, updateFolder as Y, getLatestMigrationNumber as Yt, listFolders as Z, getMigrationFilePath as Zt, getCommand as _, isVerbose as _n, listCommand$8 as _t, updateCommand as a, hasChanges as an, listOAuth2Clients as at, deleteWorkspace as b, jobsCommand as bt, removeUser as c, sdkNameLabelKey as cn, getMachineUserToken as ct, inviteCommand as d, apiCall as dn, listMachineUsers as dt, isValidMigrationNumber as en, deleteCommand$1 as et, inviteUser as f, apiCommand as fn, generate$1 as ft, listWorkspaces as g, deploymentArgs as gn, triggerExecutor as gt, listCommand$1 as h, confirmationArgs as hn, triggerCommand as ht, isCLIError as i, formatMigrationDiff as in, listCommand$6 as it, truncate as j, formatKeyValueTable as jt, listCommand$3 as k, listWorkflowExecutions as kt, listCommand as l, trnPrefix as ln, tokenCommand as lt, restoreWorkspace as m, commonArgs as mn, webhookCommand as mt, query as n, reconstructSnapshotFromMigrations as nn, createCommand$1 as nt, updateUser as o, getNamespacesWithMigrations as on, getCommand$3 as ot, restoreCommand as p, defineAppCommand as pn, listWebhookExecutors as pt, getOrganization as q, createSnapshotFromLocalTypes as qt, queryCommand as r, formatDiffSummary as rn, createFolder as rt, removeCommand as s, prompt as sn, getOAuth2Client as st, isNativeTypeScriptRuntime as t, loadDiff as tn, deleteFolder as tt, listUsers as u, generateUserTypes as un, listCommand$7 as ut, getWorkspace as v, workspaceArgs as vn, listExecutors as vt, listCommand$2 as w, startWorkflow as wt, createCommand as x, listExecutorJobs as xt, deleteCommand as y, getExecutorJob as yt, removeCommand$1 as z, bundleMigrationScript as zt };
|
|
13173
|
-
//# sourceMappingURL=runtime-
|
|
13888
|
+
//# sourceMappingURL=runtime-3P9JFpe9.mjs.map
|