@tailor-platform/sdk 1.32.1 → 1.33.1
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 +95 -0
- package/dist/{application-p2GujXmg.mjs → application-CYPU-WIc.mjs} +58 -43
- package/dist/application-CYPU-WIc.mjs.map +1 -0
- package/dist/application-dnB8CQiT.mjs +4 -0
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.mjs +28 -35
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +104 -12
- package/dist/cli/lib.mjs +7 -13
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/skills.mjs +0 -1
- package/dist/cli/skills.mjs.map +1 -1
- package/dist/{client-D5P1myz0.mjs → client-CYGsf3Zl.mjs} +91 -27
- package/dist/client-CYGsf3Zl.mjs.map +1 -0
- package/dist/{client-gpRgZl1b.mjs → client-ea1w8SmG.mjs} +1 -4
- package/dist/configure/index.d.mts +5 -5
- package/dist/configure/index.mjs +81 -12
- package/dist/configure/index.mjs.map +1 -1
- package/dist/crash-report-CbueUPaP.mjs +4 -0
- package/dist/{crash-report-DnwITWeV.mjs → crash-report-OXafT1iS.mjs} +3 -3
- package/dist/{crash-report-DnwITWeV.mjs.map → crash-report-OXafT1iS.mjs.map} +1 -1
- package/dist/{enum-constants-CkKARYb7.mjs → enum-constants-DI85-fPE.mjs} +2 -1
- package/dist/{enum-constants-CkKARYb7.mjs.map → enum-constants-DI85-fPE.mjs.map} +1 -1
- package/dist/{env-BZLTIlIo.d.mts → env-BvIWsJxg.d.mts} +2 -2
- package/dist/{file-utils-D2TxR_kj.mjs → file-utils-C4rXlOVt.mjs} +2 -1
- package/dist/{file-utils-D2TxR_kj.mjs.map → file-utils-C4rXlOVt.mjs.map} +1 -1
- package/dist/{index-CgMytw2A.d.mts → index-0H-YH8Ya.d.mts} +3 -2
- package/dist/{index-vVGamLOw.d.mts → index-BM2SqNfO.d.mts} +3 -2
- package/dist/{index-CoReoodF.d.mts → index-BU6fmwJC.d.mts} +3 -2
- package/dist/{index-BYk_9R3S.d.mts → index-DlivLpTN.d.mts} +145 -32
- package/dist/{index-BQKAzTPA.d.mts → index-mAV9kYJA.d.mts} +3 -2
- package/dist/{interceptor-1LL1gBsF.mjs → interceptor-f7slMkCC.mjs} +1 -2
- package/dist/{interceptor-1LL1gBsF.mjs.map → interceptor-f7slMkCC.mjs.map} +1 -1
- package/dist/kysely/index.d.mts +5 -1
- package/dist/kysely/index.mjs +0 -1
- package/dist/kysely/index.mjs.map +1 -1
- package/dist/{kysely-type-BK0b4Rqt.mjs → kysely-type-BwMqaL3z.mjs} +18 -7
- package/dist/kysely-type-BwMqaL3z.mjs.map +1 -0
- package/dist/{package-json-VqyFvGiP.mjs → package-json-CfUqjJaQ.mjs} +1 -1
- package/dist/{package-json-VqyFvGiP.mjs.map → package-json-CfUqjJaQ.mjs.map} +1 -1
- package/dist/package-json-D5Km1jjt.mjs +4 -0
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/enum-constants/index.mjs +1 -2
- package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.mjs +1 -2
- package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -2
- package/dist/plugin/builtin/seed/index.d.mts +1 -1
- package/dist/plugin/builtin/seed/index.mjs +1 -2
- package/dist/plugin/index.d.mts +2 -2
- package/dist/plugin/index.mjs +0 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/{plugin-IIDZW9GG.d.mts → plugin-DQqzlulP.d.mts} +46 -33
- package/dist/{runtime-7DOyTTxR.mjs → runtime-CDvdBV66.mjs} +1032 -306
- package/dist/runtime-CDvdBV66.mjs.map +1 -0
- package/dist/{schema-BITbkmq3.mjs → schema-D27cW0Ca.mjs} +2 -1
- package/dist/schema-D27cW0Ca.mjs.map +1 -0
- package/dist/seed/index.mjs +0 -1
- package/dist/seed/index.mjs.map +1 -1
- package/dist/{seed-BXrSEJbv.mjs → seed-BZIFDG27.mjs} +11 -3
- package/dist/seed-BZIFDG27.mjs.map +1 -0
- package/dist/telemetry-C508zIi1.mjs +4 -0
- package/dist/{telemetry-B4sp-dD2.mjs → telemetry-CREcGK8y.mjs} +2 -2
- package/dist/{telemetry-B4sp-dD2.mjs.map → telemetry-CREcGK8y.mjs.map} +1 -1
- package/dist/utils/test/index.d.mts +2 -2
- package/dist/utils/test/index.mjs +0 -2
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/{workflow.generated-C2A5Ye0m.d.mts → workflow.generated-u9MgzqbM.d.mts} +14 -3
- package/docs/cli/application.md +17 -0
- package/docs/cli/auth.md +1 -1
- package/docs/cli/crash-report.md +1 -1
- package/docs/cli/executor.md +2 -2
- package/docs/cli/secret.md +3 -3
- package/docs/cli/staticwebsite.md +1 -1
- package/docs/cli/tailordb.md +4 -2
- package/docs/cli/user.md +2 -2
- package/docs/cli-reference.md +116 -100
- package/docs/generator/builtin.md +1 -1
- package/docs/services/executor.md +54 -0
- package/docs/services/idp.md +22 -0
- package/package.json +20 -20
- package/dist/application-Cwt_ifTT.mjs +0 -12
- package/dist/application-p2GujXmg.mjs.map +0 -1
- package/dist/chunk-COzJYswC.mjs +0 -9
- package/dist/client-D5P1myz0.mjs.map +0 -1
- package/dist/crash-report-Cm9vFmTN.mjs +0 -7
- package/dist/kysely-type-BK0b4Rqt.mjs.map +0 -1
- package/dist/package-json-88x7bPKC.mjs +0 -5
- package/dist/runtime-7DOyTTxR.mjs.map +0 -1
- package/dist/schema-BITbkmq3.mjs.map +0 -1
- package/dist/seed-BXrSEJbv.mjs.map +0 -1
- package/dist/telemetry-DXIGGa6A.mjs +0 -5
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
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-CYGsf3Zl.mjs";
|
|
3
|
+
import { t as db } from "./schema-D27cW0Ca.mjs";
|
|
3
4
|
import { i as symbols, n as logger, r as styles, t as CIPromptError } from "./logger-qz-Y4sBV.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
7
|
-
import { r as withSpan } from "./telemetry-B4sp-dD2.mjs";
|
|
5
|
+
import { t as readPackageJson } from "./package-json-CfUqjJaQ.mjs";
|
|
6
|
+
import { S as readPlatformConfig, T as writePlatformConfig, _ as hashFile, a as loadConfig, b as loadAccessToken, c as createExecutorService, d as TailorDBTypeSchema, f as stringifyFunction, g as getDistDir, h as createBundleCache, m as loadFilesWithIgnores, n as generatePluginFilesIfNeeded, p as tailorUserMap, r as loadApplication, t as defineApplication, u as OAuth2ClientSchema, x as loadWorkspaceId } from "./application-CYPU-WIc.mjs";
|
|
7
|
+
import { r as withSpan } from "./telemetry-CREcGK8y.mjs";
|
|
8
8
|
import { arg, createDefineCommand, defineCommand, runCommand } from "politty";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import * as fs$1 from "node:fs";
|
|
@@ -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
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
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({
|
|
1046
1190
|
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,57 @@ 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 normalizeComparableEmailConfig(value) {
|
|
1631
|
+
return {
|
|
1632
|
+
fromName: value?.fromName ?? "",
|
|
1633
|
+
passwordResetSubject: value?.passwordResetSubject ?? ""
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
function normalizeComparableIdPService(input) {
|
|
1637
|
+
return {
|
|
1638
|
+
authorization: input.authorization,
|
|
1639
|
+
lang: input.lang === IdPLang.UNSPECIFIED ? IdPLang.EN : input.lang,
|
|
1640
|
+
userAuthPolicy: input.userAuthPolicy,
|
|
1641
|
+
publishUserEvents: input.publishUserEvents,
|
|
1642
|
+
disableGqlOperations: input.disableGqlOperations,
|
|
1643
|
+
emailConfig: input.emailConfig
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
function areIdPServicesEqual(existing, desired) {
|
|
1647
|
+
return areNormalizedEqual(normalizeComparableIdPService({
|
|
1648
|
+
authorization: existing.authorization,
|
|
1649
|
+
lang: existing.lang,
|
|
1650
|
+
userAuthPolicy: normalizeComparableUserAuthPolicy(existing.userAuthPolicy),
|
|
1651
|
+
publishUserEvents: existing.publishUserEvents,
|
|
1652
|
+
disableGqlOperations: normalizeComparableDisableGqlOperations(existing.disableGqlOperations),
|
|
1653
|
+
emailConfig: normalizeComparableEmailConfig(existing.emailConfig)
|
|
1654
|
+
}), desired);
|
|
1655
|
+
}
|
|
1457
1656
|
async function planServices$3(client, workspaceId, appName, idps) {
|
|
1458
1657
|
const changeSet = createChangeSet("IdP services");
|
|
1459
1658
|
const conflicts = [];
|
|
@@ -1478,7 +1677,8 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1478
1677
|
const { metadata } = await client.getMetadata({ trn: trn$5(workspaceId, resource.namespace.name) });
|
|
1479
1678
|
existingServices[resource.namespace.name] = {
|
|
1480
1679
|
resource,
|
|
1481
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
1680
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
1681
|
+
allLabels: metadata?.labels
|
|
1482
1682
|
};
|
|
1483
1683
|
}));
|
|
1484
1684
|
for (const idp of idps) {
|
|
@@ -1499,7 +1699,28 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1499
1699
|
}
|
|
1500
1700
|
const lang = convertLang(idp.lang);
|
|
1501
1701
|
const userAuthPolicy = idp.userAuthPolicy;
|
|
1702
|
+
const publishUserEvents = idp.publishUserEvents ?? false;
|
|
1703
|
+
const emailConfig = idp.emailConfig;
|
|
1704
|
+
const desired = normalizeComparableIdPService({
|
|
1705
|
+
authorization,
|
|
1706
|
+
lang,
|
|
1707
|
+
userAuthPolicy: normalizeComparableUserAuthPolicy(userAuthPolicy),
|
|
1708
|
+
publishUserEvents,
|
|
1709
|
+
disableGqlOperations: normalizeComparableDisableGqlOperations(convertGqlOperationsToDisable(idp.gqlOperations)),
|
|
1710
|
+
emailConfig: normalizeComparableEmailConfig(emailConfig)
|
|
1711
|
+
});
|
|
1712
|
+
const request = {
|
|
1713
|
+
workspaceId,
|
|
1714
|
+
namespaceName,
|
|
1715
|
+
authorization,
|
|
1716
|
+
lang,
|
|
1717
|
+
userAuthPolicy,
|
|
1718
|
+
publishUserEvents,
|
|
1719
|
+
disableGqlOperations: convertGqlOperationsToDisable(idp.gqlOperations),
|
|
1720
|
+
emailConfig
|
|
1721
|
+
};
|
|
1502
1722
|
if (existing) {
|
|
1723
|
+
const isManagedByApp = existing.label === appName;
|
|
1503
1724
|
if (!existing.label) unmanaged.push({
|
|
1504
1725
|
resourceType: "IdP service",
|
|
1505
1726
|
resourceName: idp.name
|
|
@@ -1509,31 +1730,16 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1509
1730
|
resourceName: idp.name,
|
|
1510
1731
|
currentOwner: existing.label
|
|
1511
1732
|
});
|
|
1512
|
-
changeSet.
|
|
1733
|
+
if (isManagedByApp && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areIdPServicesEqual(existing.resource, desired)) changeSet.unchanged.push({ name: namespaceName });
|
|
1734
|
+
else changeSet.updates.push({
|
|
1513
1735
|
name: namespaceName,
|
|
1514
|
-
request
|
|
1515
|
-
workspaceId,
|
|
1516
|
-
namespaceName,
|
|
1517
|
-
authorization,
|
|
1518
|
-
lang,
|
|
1519
|
-
userAuthPolicy,
|
|
1520
|
-
publishUserEvents: idp.publishUserEvents,
|
|
1521
|
-
disableGqlOperations: convertGqlOperationsToDisable(idp.gqlOperations)
|
|
1522
|
-
},
|
|
1736
|
+
request,
|
|
1523
1737
|
metaRequest
|
|
1524
1738
|
});
|
|
1525
1739
|
delete existingServices[namespaceName];
|
|
1526
1740
|
} else changeSet.creates.push({
|
|
1527
1741
|
name: namespaceName,
|
|
1528
|
-
request
|
|
1529
|
-
workspaceId,
|
|
1530
|
-
namespaceName,
|
|
1531
|
-
authorization,
|
|
1532
|
-
lang,
|
|
1533
|
-
userAuthPolicy,
|
|
1534
|
-
publishUserEvents: idp.publishUserEvents,
|
|
1535
|
-
disableGqlOperations: convertGqlOperationsToDisable(idp.gqlOperations)
|
|
1536
|
-
},
|
|
1742
|
+
request,
|
|
1537
1743
|
metaRequest
|
|
1538
1744
|
});
|
|
1539
1745
|
}
|
|
@@ -1555,7 +1761,7 @@ async function planServices$3(client, workspaceId, appName, idps) {
|
|
|
1555
1761
|
resourceOwners
|
|
1556
1762
|
};
|
|
1557
1763
|
}
|
|
1558
|
-
async function planClients(client, workspaceId, idps, deletedServices) {
|
|
1764
|
+
async function planClients(client, workspaceId, idps, deletedServices, forceApplyAll = false) {
|
|
1559
1765
|
const changeSet = createChangeSet("IdP clients");
|
|
1560
1766
|
const fetchClients = (namespaceName) => {
|
|
1561
1767
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -1583,12 +1789,13 @@ async function planClients(client, workspaceId, idps, deletedServices) {
|
|
|
1583
1789
|
existingNameMap.set(client.name, client.clientSecret);
|
|
1584
1790
|
});
|
|
1585
1791
|
for (const name of idp.clients) if (existingNameMap.has(name)) {
|
|
1586
|
-
changeSet.updates.push({
|
|
1792
|
+
if (forceApplyAll) changeSet.updates.push({
|
|
1587
1793
|
name,
|
|
1588
1794
|
workspaceId,
|
|
1589
1795
|
namespaceName,
|
|
1590
|
-
clientSecret: existingNameMap.get(name)
|
|
1796
|
+
clientSecret: existingNameMap.get(name) ?? ""
|
|
1591
1797
|
});
|
|
1798
|
+
else changeSet.unchanged.push({ name });
|
|
1592
1799
|
existingNameMap.delete(name);
|
|
1593
1800
|
} else changeSet.creates.push({
|
|
1594
1801
|
name,
|
|
@@ -1598,7 +1805,7 @@ async function planClients(client, workspaceId, idps, deletedServices) {
|
|
|
1598
1805
|
client: { name }
|
|
1599
1806
|
}
|
|
1600
1807
|
});
|
|
1601
|
-
existingNameMap.forEach((name) => {
|
|
1808
|
+
existingNameMap.forEach((_clientSecret, name) => {
|
|
1602
1809
|
changeSet.deletes.push({
|
|
1603
1810
|
name,
|
|
1604
1811
|
request: {
|
|
@@ -1704,21 +1911,21 @@ async function applyAuth(client, result, phase = "create-update") {
|
|
|
1704
1911
|
* @returns Planned auth changes and metadata
|
|
1705
1912
|
*/
|
|
1706
1913
|
async function planAuth(context) {
|
|
1707
|
-
const { client, workspaceId, application, forRemoval } = context;
|
|
1914
|
+
const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;
|
|
1708
1915
|
const auths = [];
|
|
1709
1916
|
if (!forRemoval && application.authService) {
|
|
1710
1917
|
await application.authService.resolveNamespaces();
|
|
1711
1918
|
auths.push(application.authService);
|
|
1712
1919
|
}
|
|
1713
|
-
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$2(client, workspaceId, application.name, auths);
|
|
1920
|
+
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$2(client, workspaceId, application.name, auths, forceApplyAll);
|
|
1714
1921
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
1715
1922
|
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),
|
|
1923
|
+
planIdPConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1924
|
+
planUserProfileConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1925
|
+
planTenantConfigs(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1926
|
+
planMachineUsers(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1927
|
+
planAuthHooks(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1928
|
+
planOAuth2Clients(client, workspaceId, auths, deletedServices, forceApplyAll),
|
|
1722
1929
|
planSCIMConfigs(client, workspaceId, auths, deletedServices),
|
|
1723
1930
|
planSCIMResources(client, workspaceId, auths, deletedServices)
|
|
1724
1931
|
]);
|
|
@@ -1751,7 +1958,7 @@ async function planAuth(context) {
|
|
|
1751
1958
|
function trn$4(workspaceId, name) {
|
|
1752
1959
|
return `trn:v1:workspace:${workspaceId}:auth:${name}`;
|
|
1753
1960
|
}
|
|
1754
|
-
async function planServices$2(client, workspaceId, appName, auths) {
|
|
1961
|
+
async function planServices$2(client, workspaceId, appName, auths, forceApplyAll = false) {
|
|
1755
1962
|
const changeSet = createChangeSet("Auth services");
|
|
1756
1963
|
const conflicts = [];
|
|
1757
1964
|
const unmanaged = [];
|
|
@@ -1782,7 +1989,13 @@ async function planServices$2(client, workspaceId, appName, auths) {
|
|
|
1782
1989
|
const { parsedConfig: config } = auth;
|
|
1783
1990
|
const existing = existingServices[config.name];
|
|
1784
1991
|
const metaRequest = await buildMetaRequest(trn$4(workspaceId, config.name), appName);
|
|
1992
|
+
const request = {
|
|
1993
|
+
workspaceId,
|
|
1994
|
+
namespaceName: config.name,
|
|
1995
|
+
publishSessionEvents: config.publishSessionEvents
|
|
1996
|
+
};
|
|
1785
1997
|
if (existing) {
|
|
1998
|
+
const isManagedByApp = existing.label === appName;
|
|
1786
1999
|
if (!existing.label) unmanaged.push({
|
|
1787
2000
|
resourceType: "Auth service",
|
|
1788
2001
|
resourceName: config.name
|
|
@@ -1792,23 +2005,16 @@ async function planServices$2(client, workspaceId, appName, auths) {
|
|
|
1792
2005
|
resourceName: config.name,
|
|
1793
2006
|
currentOwner: existing.label
|
|
1794
2007
|
});
|
|
1795
|
-
changeSet.
|
|
2008
|
+
if (!forceApplyAll && existing.resource.publishSessionEvents === (config.publishSessionEvents ?? false) && isManagedByApp) changeSet.unchanged.push({ name: config.name });
|
|
2009
|
+
else changeSet.updates.push({
|
|
1796
2010
|
name: config.name,
|
|
1797
|
-
request
|
|
1798
|
-
workspaceId,
|
|
1799
|
-
namespaceName: config.name,
|
|
1800
|
-
publishSessionEvents: config.publishSessionEvents
|
|
1801
|
-
},
|
|
2011
|
+
request,
|
|
1802
2012
|
metaRequest
|
|
1803
2013
|
});
|
|
1804
2014
|
delete existingServices[config.name];
|
|
1805
2015
|
} else changeSet.creates.push({
|
|
1806
2016
|
name: config.name,
|
|
1807
|
-
request
|
|
1808
|
-
workspaceId,
|
|
1809
|
-
namespaceName: config.name,
|
|
1810
|
-
publishSessionEvents: config.publishSessionEvents
|
|
1811
|
-
},
|
|
2017
|
+
request,
|
|
1812
2018
|
metaRequest
|
|
1813
2019
|
});
|
|
1814
2020
|
}
|
|
@@ -1830,7 +2036,7 @@ async function planServices$2(client, workspaceId, appName, auths) {
|
|
|
1830
2036
|
resourceOwners
|
|
1831
2037
|
};
|
|
1832
2038
|
}
|
|
1833
|
-
async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
2039
|
+
async function planIdPConfigs(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
1834
2040
|
const changeSet = createChangeSet("Auth idpConfigs");
|
|
1835
2041
|
const fetchIdPConfigs = (namespaceName) => {
|
|
1836
2042
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -1851,32 +2057,51 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
1851
2057
|
for (const authService of auths) {
|
|
1852
2058
|
const { parsedConfig: config } = authService;
|
|
1853
2059
|
const existingIdPConfigs = await fetchIdPConfigs(config.name);
|
|
1854
|
-
const
|
|
2060
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
1855
2061
|
existingIdPConfigs.forEach((idpConfig) => {
|
|
1856
|
-
|
|
2062
|
+
existingMap.set(idpConfig.name, idpConfig);
|
|
1857
2063
|
});
|
|
1858
2064
|
const idpConfig = config.idProvider;
|
|
1859
|
-
if (idpConfig)
|
|
1860
|
-
|
|
2065
|
+
if (idpConfig) {
|
|
2066
|
+
const desired = protoIdPConfig(idpConfig);
|
|
2067
|
+
const existing = existingMap.get(idpConfig.name);
|
|
2068
|
+
if (existing) {
|
|
2069
|
+
const desiredComparable = await protoIdPConfigForComparison(client, workspaceId, idpConfig, desired);
|
|
2070
|
+
if (!desiredComparable) {
|
|
2071
|
+
changeSet.updates.push({
|
|
2072
|
+
name: idpConfig.name,
|
|
2073
|
+
idpConfig,
|
|
2074
|
+
request: {
|
|
2075
|
+
workspaceId,
|
|
2076
|
+
namespaceName: config.name,
|
|
2077
|
+
idpConfig: desired
|
|
2078
|
+
}
|
|
2079
|
+
});
|
|
2080
|
+
existingMap.delete(idpConfig.name);
|
|
2081
|
+
continue;
|
|
2082
|
+
}
|
|
2083
|
+
if (!forceApplyAll && areAuthIdPConfigsEqual(existing, desiredComparable)) changeSet.unchanged.push({ name: idpConfig.name });
|
|
2084
|
+
else changeSet.updates.push({
|
|
2085
|
+
name: idpConfig.name,
|
|
2086
|
+
idpConfig,
|
|
2087
|
+
request: {
|
|
2088
|
+
workspaceId,
|
|
2089
|
+
namespaceName: config.name,
|
|
2090
|
+
idpConfig: desired
|
|
2091
|
+
}
|
|
2092
|
+
});
|
|
2093
|
+
existingMap.delete(idpConfig.name);
|
|
2094
|
+
} else changeSet.creates.push({
|
|
1861
2095
|
name: idpConfig.name,
|
|
1862
2096
|
idpConfig,
|
|
1863
2097
|
request: {
|
|
1864
2098
|
workspaceId,
|
|
1865
2099
|
namespaceName: config.name,
|
|
1866
|
-
idpConfig:
|
|
2100
|
+
idpConfig: desired
|
|
1867
2101
|
}
|
|
1868
2102
|
});
|
|
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) => {
|
|
2103
|
+
}
|
|
2104
|
+
existingMap.forEach((_, name) => {
|
|
1880
2105
|
changeSet.deletes.push({
|
|
1881
2106
|
name,
|
|
1882
2107
|
request: {
|
|
@@ -1899,6 +2124,32 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
1899
2124
|
});
|
|
1900
2125
|
return changeSet;
|
|
1901
2126
|
}
|
|
2127
|
+
async function protoIdPConfigForComparison(client, workspaceId, idpConfig, desired) {
|
|
2128
|
+
if (idpConfig.kind !== "BuiltInIdP") return desired;
|
|
2129
|
+
const config = await tryProtoBuiltinIdPConfig(client, workspaceId, idpConfig);
|
|
2130
|
+
return config ? {
|
|
2131
|
+
...desired,
|
|
2132
|
+
config
|
|
2133
|
+
} : void 0;
|
|
2134
|
+
}
|
|
2135
|
+
function normalizeComparableAuthIdPConfig(idpConfig) {
|
|
2136
|
+
const configCase = idpConfig.config?.config?.case;
|
|
2137
|
+
const oidcValue = configCase === "oidc" && typeof idpConfig.config?.config?.value === "object" && idpConfig.config.config.value !== null ? idpConfig.config.config.value : void 0;
|
|
2138
|
+
return normalizeProtoConfig({
|
|
2139
|
+
name: idpConfig.name,
|
|
2140
|
+
authType: idpConfig.authType,
|
|
2141
|
+
config: configCase === "oidc" ? { config: {
|
|
2142
|
+
case: "oidc",
|
|
2143
|
+
value: {
|
|
2144
|
+
...oidcValue ?? {},
|
|
2145
|
+
issuerUrl: oidcValue && "issuerUrl" in oidcValue ? oidcValue.issuerUrl || void 0 : void 0
|
|
2146
|
+
}
|
|
2147
|
+
} } : idpConfig.config
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
function areAuthIdPConfigsEqual(existing, desired) {
|
|
2151
|
+
return areNormalizedEqual(normalizeComparableAuthIdPConfig(existing), normalizeComparableAuthIdPConfig(desired));
|
|
2152
|
+
}
|
|
1902
2153
|
function protoIdPConfig(idpConfig) {
|
|
1903
2154
|
switch (idpConfig.kind) {
|
|
1904
2155
|
case "IDToken": return {
|
|
@@ -1951,6 +2202,11 @@ function protoIdPConfig(idpConfig) {
|
|
|
1951
2202
|
}
|
|
1952
2203
|
}
|
|
1953
2204
|
async function protoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
2205
|
+
const config = await tryProtoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig);
|
|
2206
|
+
if (!config) throw new Error(`Built-in IdP "${builtinIdPConfig.namespace}" not found. Please ensure that idp is configured correctly.`);
|
|
2207
|
+
return config;
|
|
2208
|
+
}
|
|
2209
|
+
async function tryProtoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
1954
2210
|
let idpService;
|
|
1955
2211
|
try {
|
|
1956
2212
|
idpService = await client.getIdPService({
|
|
@@ -1958,14 +2214,20 @@ async function protoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
|
1958
2214
|
namespaceName: builtinIdPConfig.namespace
|
|
1959
2215
|
});
|
|
1960
2216
|
} catch (error) {
|
|
1961
|
-
if (error instanceof ConnectError && error.code === Code.NotFound)
|
|
2217
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return;
|
|
2218
|
+
throw error;
|
|
2219
|
+
}
|
|
2220
|
+
let idpClient;
|
|
2221
|
+
try {
|
|
2222
|
+
idpClient = await client.getIdPClient({
|
|
2223
|
+
workspaceId,
|
|
2224
|
+
namespaceName: builtinIdPConfig.namespace,
|
|
2225
|
+
name: builtinIdPConfig.clientName
|
|
2226
|
+
});
|
|
2227
|
+
} catch (error) {
|
|
2228
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return;
|
|
1962
2229
|
throw error;
|
|
1963
2230
|
}
|
|
1964
|
-
const idpClient = await client.getIdPClient({
|
|
1965
|
-
workspaceId,
|
|
1966
|
-
namespaceName: builtinIdPConfig.namespace,
|
|
1967
|
-
name: builtinIdPConfig.clientName
|
|
1968
|
-
});
|
|
1969
2231
|
const vaultName = idpClientVaultName(builtinIdPConfig.namespace, builtinIdPConfig.clientName);
|
|
1970
2232
|
const secretKey = idpClientSecretName(builtinIdPConfig.namespace, builtinIdPConfig.clientName);
|
|
1971
2233
|
return { config: {
|
|
@@ -1981,16 +2243,35 @@ async function protoBuiltinIdPConfig(client, workspaceId, builtinIdPConfig) {
|
|
|
1981
2243
|
}
|
|
1982
2244
|
} };
|
|
1983
2245
|
}
|
|
1984
|
-
async function planUserProfileConfigs(client, workspaceId, auths, deletedServices) {
|
|
2246
|
+
async function planUserProfileConfigs(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
1985
2247
|
const changeSet = createChangeSet("Auth userProfileConfigs");
|
|
1986
2248
|
for (const auth of auths) {
|
|
1987
2249
|
const { parsedConfig: config } = auth;
|
|
1988
2250
|
const name = `${config.name}-user-profile-config`;
|
|
1989
2251
|
try {
|
|
1990
|
-
await client.getUserProfileConfig({
|
|
2252
|
+
const { userProfileProviderConfig } = await client.getUserProfileConfig({
|
|
1991
2253
|
workspaceId,
|
|
1992
2254
|
namespaceName: config.name
|
|
1993
2255
|
});
|
|
2256
|
+
const userProfileForUpdate = auth.userProfile;
|
|
2257
|
+
if (userProfileForUpdate) {
|
|
2258
|
+
const desired = protoUserProfileConfig(userProfileForUpdate);
|
|
2259
|
+
if (!forceApplyAll && areUserProfileConfigsEqual(userProfileProviderConfig ?? {}, desired)) changeSet.unchanged.push({ name });
|
|
2260
|
+
else changeSet.updates.push({
|
|
2261
|
+
name,
|
|
2262
|
+
request: {
|
|
2263
|
+
workspaceId,
|
|
2264
|
+
namespaceName: config.name,
|
|
2265
|
+
userProfileProviderConfig: desired
|
|
2266
|
+
}
|
|
2267
|
+
});
|
|
2268
|
+
} else changeSet.deletes.push({
|
|
2269
|
+
name,
|
|
2270
|
+
request: {
|
|
2271
|
+
workspaceId,
|
|
2272
|
+
namespaceName: config.name
|
|
2273
|
+
}
|
|
2274
|
+
});
|
|
1994
2275
|
} catch (error) {
|
|
1995
2276
|
if (error instanceof ConnectError && error.code === Code.NotFound) {
|
|
1996
2277
|
const userProfileForCreate = auth.userProfile;
|
|
@@ -2006,22 +2287,6 @@ async function planUserProfileConfigs(client, workspaceId, auths, deletedService
|
|
|
2006
2287
|
}
|
|
2007
2288
|
throw error;
|
|
2008
2289
|
}
|
|
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
2290
|
}
|
|
2026
2291
|
for (const namespaceName of deletedServices) {
|
|
2027
2292
|
try {
|
|
@@ -2061,16 +2326,34 @@ function protoUserProfileConfig(userProfile) {
|
|
|
2061
2326
|
} }
|
|
2062
2327
|
};
|
|
2063
2328
|
}
|
|
2064
|
-
async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
|
|
2329
|
+
async function planTenantConfigs(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2065
2330
|
const changeSet = createChangeSet("Auth tenantConfigs");
|
|
2066
2331
|
for (const auth of auths) {
|
|
2067
2332
|
const { parsedConfig: config } = auth;
|
|
2068
2333
|
const name = `${config.name}-tenant-config`;
|
|
2069
2334
|
try {
|
|
2070
|
-
await client.getTenantConfig({
|
|
2335
|
+
const { tenantProviderConfig } = await client.getTenantConfig({
|
|
2071
2336
|
workspaceId,
|
|
2072
2337
|
namespaceName: config.name
|
|
2073
2338
|
});
|
|
2339
|
+
if (config.tenantProvider) {
|
|
2340
|
+
const desired = protoTenantConfig(config.tenantProvider);
|
|
2341
|
+
if (!forceApplyAll && areTenantProviderConfigsEqual(tenantProviderConfig, desired)) changeSet.unchanged.push({ name });
|
|
2342
|
+
else changeSet.updates.push({
|
|
2343
|
+
name,
|
|
2344
|
+
request: {
|
|
2345
|
+
workspaceId,
|
|
2346
|
+
namespaceName: config.name,
|
|
2347
|
+
tenantProviderConfig: desired
|
|
2348
|
+
}
|
|
2349
|
+
});
|
|
2350
|
+
} else changeSet.deletes.push({
|
|
2351
|
+
name,
|
|
2352
|
+
request: {
|
|
2353
|
+
workspaceId,
|
|
2354
|
+
namespaceName: config.name
|
|
2355
|
+
}
|
|
2356
|
+
});
|
|
2074
2357
|
} catch (error) {
|
|
2075
2358
|
if (error instanceof ConnectError && error.code === Code.NotFound) {
|
|
2076
2359
|
if (config.tenantProvider) changeSet.creates.push({
|
|
@@ -2085,21 +2368,6 @@ async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
2085
2368
|
}
|
|
2086
2369
|
throw error;
|
|
2087
2370
|
}
|
|
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
2371
|
}
|
|
2104
2372
|
for (const namespaceName of deletedServices) {
|
|
2105
2373
|
try {
|
|
@@ -2134,7 +2402,7 @@ function protoTenantConfig(tenantConfig) {
|
|
|
2134
2402
|
} }
|
|
2135
2403
|
};
|
|
2136
2404
|
}
|
|
2137
|
-
async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
2405
|
+
async function planMachineUsers(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2138
2406
|
const changeSet = createChangeSet("Auth machineUsers");
|
|
2139
2407
|
const fetchMachineUsers = (authNamespace) => {
|
|
2140
2408
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -2155,25 +2423,31 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
|
2155
2423
|
for (const auth of auths) {
|
|
2156
2424
|
const { parsedConfig: config } = auth;
|
|
2157
2425
|
const existingMachineUsers = await fetchMachineUsers(config.name);
|
|
2158
|
-
const
|
|
2426
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
2159
2427
|
existingMachineUsers.forEach((machineUser) => {
|
|
2160
|
-
|
|
2428
|
+
existingMap.set(machineUser.name, machineUser);
|
|
2161
2429
|
});
|
|
2162
2430
|
for (const machineUsername of Object.keys(config.machineUsers ?? {})) {
|
|
2163
2431
|
const machineUser = config.machineUsers?.[machineUsername];
|
|
2164
2432
|
if (!machineUser) continue;
|
|
2165
|
-
|
|
2166
|
-
|
|
2433
|
+
const desiredMachineUser = {
|
|
2434
|
+
attributes: machineUser.attributeList,
|
|
2435
|
+
attributeMap: machineUser.attributes ? protoMachineUserAttributeMap(machineUser.attributes) : void 0
|
|
2436
|
+
};
|
|
2437
|
+
const existing = existingMap.get(machineUsername);
|
|
2438
|
+
if (existing) {
|
|
2439
|
+
if (!forceApplyAll && areMachineUsersEqual(existing, desiredMachineUser)) changeSet.unchanged.push({ name: machineUsername });
|
|
2440
|
+
else changeSet.updates.push({
|
|
2167
2441
|
name: machineUsername,
|
|
2168
2442
|
request: {
|
|
2169
2443
|
workspaceId,
|
|
2170
2444
|
authNamespace: config.name,
|
|
2171
2445
|
name: machineUsername,
|
|
2172
2446
|
attributes: machineUser.attributeList,
|
|
2173
|
-
attributeMap:
|
|
2447
|
+
attributeMap: desiredMachineUser.attributeMap
|
|
2174
2448
|
}
|
|
2175
2449
|
});
|
|
2176
|
-
|
|
2450
|
+
existingMap.delete(machineUsername);
|
|
2177
2451
|
} else changeSet.creates.push({
|
|
2178
2452
|
name: machineUsername,
|
|
2179
2453
|
request: {
|
|
@@ -2181,11 +2455,11 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
|
2181
2455
|
authNamespace: config.name,
|
|
2182
2456
|
name: machineUsername,
|
|
2183
2457
|
attributes: machineUser.attributeList,
|
|
2184
|
-
attributeMap:
|
|
2458
|
+
attributeMap: desiredMachineUser.attributeMap
|
|
2185
2459
|
}
|
|
2186
2460
|
});
|
|
2187
2461
|
}
|
|
2188
|
-
|
|
2462
|
+
existingMap.forEach((_, name) => {
|
|
2189
2463
|
changeSet.deletes.push({
|
|
2190
2464
|
name,
|
|
2191
2465
|
request: {
|
|
@@ -2213,7 +2487,60 @@ function protoMachineUserAttributeMap(attributeMap) {
|
|
|
2213
2487
|
for (const [key, value] of Object.entries(attributeMap)) ret[key] = fromJson(ValueSchema, value ?? null);
|
|
2214
2488
|
return ret;
|
|
2215
2489
|
}
|
|
2216
|
-
|
|
2490
|
+
function normalizeComparableUserProfileConfig(config) {
|
|
2491
|
+
const comparableConfig = config.config?.config;
|
|
2492
|
+
const tailorDBConfig = comparableConfig?.case === "tailordb" ? comparableConfig.value : void 0;
|
|
2493
|
+
return normalizeProtoConfig({
|
|
2494
|
+
providerType: config.providerType,
|
|
2495
|
+
config: { config: {
|
|
2496
|
+
case: comparableConfig?.case,
|
|
2497
|
+
value: tailorDBConfig ? {
|
|
2498
|
+
...tailorDBConfig,
|
|
2499
|
+
tenantIdField: tailorDBConfig.tenantIdField || void 0,
|
|
2500
|
+
attributesFields: normalizeStringArray(tailorDBConfig.attributesFields),
|
|
2501
|
+
attributeMap: normalizeProtoConfig(tailorDBConfig.attributeMap)
|
|
2502
|
+
} : comparableConfig?.value
|
|
2503
|
+
} }
|
|
2504
|
+
});
|
|
2505
|
+
}
|
|
2506
|
+
function areUserProfileConfigsEqual(existing, desired) {
|
|
2507
|
+
return areNormalizedEqual(normalizeComparableUserProfileConfig(existing), normalizeComparableUserProfileConfig(desired));
|
|
2508
|
+
}
|
|
2509
|
+
function normalizeComparableTenantProviderConfig(config) {
|
|
2510
|
+
return normalizeProtoConfig(config);
|
|
2511
|
+
}
|
|
2512
|
+
function areTenantProviderConfigsEqual(existing, desired) {
|
|
2513
|
+
return areNormalizedEqual(normalizeComparableTenantProviderConfig(existing), normalizeComparableTenantProviderConfig(desired));
|
|
2514
|
+
}
|
|
2515
|
+
function normalizeComparableMachineUser(input) {
|
|
2516
|
+
return normalizeProtoConfig({
|
|
2517
|
+
attributes: normalizeStringArray(input.attributes),
|
|
2518
|
+
attributeMap: normalizeProtoConfig(input.attributeMap ?? {})
|
|
2519
|
+
});
|
|
2520
|
+
}
|
|
2521
|
+
function areMachineUsersEqual(existing, desired) {
|
|
2522
|
+
return areNormalizedEqual(normalizeComparableMachineUser(existing), normalizeComparableMachineUser(desired));
|
|
2523
|
+
}
|
|
2524
|
+
function normalizeComparableOAuth2Client(client) {
|
|
2525
|
+
const accessTokenLifetime = oauth2LifetimeToSeconds(client.accessTokenLifetime);
|
|
2526
|
+
const refreshTokenLifetime = oauth2LifetimeToSeconds(client.refreshTokenLifetime);
|
|
2527
|
+
return normalizeProtoConfig({
|
|
2528
|
+
...client,
|
|
2529
|
+
redirectUris: normalizeStringArray(client.redirectUris),
|
|
2530
|
+
grantTypes: [...client.grantTypes ?? []].sort((left, right) => left - right),
|
|
2531
|
+
accessTokenLifetime: accessTokenLifetime ?? 86400,
|
|
2532
|
+
refreshTokenLifetime: refreshTokenLifetime ?? 604800,
|
|
2533
|
+
requireDpop: client.requireDpop ?? false
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
function oauth2LifetimeToSeconds(lifetime) {
|
|
2537
|
+
if (typeof lifetime === "number") return lifetime;
|
|
2538
|
+
if (lifetime?.seconds != null) return Number(lifetime.seconds);
|
|
2539
|
+
}
|
|
2540
|
+
function areOAuth2ClientsEqual(existing, desired) {
|
|
2541
|
+
return areNormalizedEqual(normalizeComparableOAuth2Client(existing), normalizeComparableOAuth2Client(desired));
|
|
2542
|
+
}
|
|
2543
|
+
async function planOAuth2Clients(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2217
2544
|
const changeSet = createChangeSet("Auth oauth2Clients");
|
|
2218
2545
|
const fetchOAuth2Clients = (namespaceName) => {
|
|
2219
2546
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -2236,14 +2563,16 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
|
|
|
2236
2563
|
const existingOAuth2Clients = await fetchOAuth2Clients(config.name);
|
|
2237
2564
|
const existingClientsMap = /* @__PURE__ */ new Map();
|
|
2238
2565
|
existingOAuth2Clients.forEach((oauth2Client) => {
|
|
2239
|
-
existingClientsMap.set(oauth2Client.name, oauth2Client
|
|
2566
|
+
existingClientsMap.set(oauth2Client.name, oauth2Client);
|
|
2240
2567
|
});
|
|
2241
2568
|
for (const oauth2ClientName of Object.keys(config.oauth2Clients ?? {})) {
|
|
2242
2569
|
const oauth2Client = config.oauth2Clients?.[oauth2ClientName];
|
|
2243
2570
|
if (!oauth2Client) continue;
|
|
2244
2571
|
const newOAuth2Client = protoOAuth2Client(oauth2ClientName, oauth2Client);
|
|
2572
|
+
const resolvedRedirectUris = await resolveStaticWebsiteUrls(client, workspaceId, newOAuth2Client.redirectUris ?? [], "OAuth2 redirect URIs");
|
|
2245
2573
|
if (existingClientsMap.has(oauth2ClientName)) {
|
|
2246
|
-
|
|
2574
|
+
const existingClient = existingClientsMap.get(oauth2ClientName);
|
|
2575
|
+
if (existingClient.clientType !== newOAuth2Client.clientType) changeSet.replaces.push({
|
|
2247
2576
|
name: oauth2ClientName,
|
|
2248
2577
|
deleteRequest: {
|
|
2249
2578
|
workspaceId,
|
|
@@ -2256,14 +2585,33 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
|
|
|
2256
2585
|
oauth2Client: newOAuth2Client
|
|
2257
2586
|
}
|
|
2258
2587
|
});
|
|
2259
|
-
else
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
}
|
|
2266
|
-
|
|
2588
|
+
else {
|
|
2589
|
+
const desiredComparable = {
|
|
2590
|
+
...newOAuth2Client,
|
|
2591
|
+
redirectUris: resolvedRedirectUris,
|
|
2592
|
+
accessTokenLifetime: oauth2LifetimeToSeconds(newOAuth2Client.accessTokenLifetime),
|
|
2593
|
+
refreshTokenLifetime: oauth2LifetimeToSeconds(newOAuth2Client.refreshTokenLifetime)
|
|
2594
|
+
};
|
|
2595
|
+
const existingComparable = {
|
|
2596
|
+
name: existingClient.name,
|
|
2597
|
+
description: existingClient.description,
|
|
2598
|
+
grantTypes: existingClient.grantTypes,
|
|
2599
|
+
redirectUris: existingClient.redirectUris,
|
|
2600
|
+
clientType: existingClient.clientType,
|
|
2601
|
+
accessTokenLifetime: oauth2LifetimeToSeconds(existingClient.accessTokenLifetime),
|
|
2602
|
+
refreshTokenLifetime: oauth2LifetimeToSeconds(existingClient.refreshTokenLifetime),
|
|
2603
|
+
requireDpop: existingClient.requireDpop
|
|
2604
|
+
};
|
|
2605
|
+
if (!forceApplyAll && areOAuth2ClientsEqual(existingComparable, desiredComparable)) changeSet.unchanged.push({ name: oauth2ClientName });
|
|
2606
|
+
else changeSet.updates.push({
|
|
2607
|
+
name: oauth2ClientName,
|
|
2608
|
+
request: {
|
|
2609
|
+
workspaceId,
|
|
2610
|
+
namespaceName: config.name,
|
|
2611
|
+
oauth2Client: newOAuth2Client
|
|
2612
|
+
}
|
|
2613
|
+
});
|
|
2614
|
+
}
|
|
2267
2615
|
existingClientsMap.delete(oauth2ClientName);
|
|
2268
2616
|
} else changeSet.creates.push({
|
|
2269
2617
|
name: oauth2ClientName,
|
|
@@ -2538,21 +2886,36 @@ function protoSCIMAttribute(attr) {
|
|
|
2538
2886
|
subAttributes: attr.subAttributes?.map((attr) => protoSCIMAttribute(attr))
|
|
2539
2887
|
};
|
|
2540
2888
|
}
|
|
2541
|
-
|
|
2889
|
+
function areAuthHooksEqual(existing, desired) {
|
|
2890
|
+
return areNormalizedEqual({
|
|
2891
|
+
scriptRef: existing.scriptRef ?? "",
|
|
2892
|
+
invoker: existing.invoker ? {
|
|
2893
|
+
namespace: existing.invoker.namespace ?? "",
|
|
2894
|
+
machineUserName: existing.invoker.machineUserName ?? ""
|
|
2895
|
+
} : void 0
|
|
2896
|
+
}, {
|
|
2897
|
+
scriptRef: desired.scriptRef ?? "",
|
|
2898
|
+
invoker: desired.invoker ? {
|
|
2899
|
+
namespace: desired.invoker.namespace ?? "",
|
|
2900
|
+
machineUserName: desired.invoker.machineUserName ?? ""
|
|
2901
|
+
} : void 0
|
|
2902
|
+
});
|
|
2903
|
+
}
|
|
2904
|
+
async function planAuthHooks(client, workspaceId, auths, deletedServices, forceApplyAll = false) {
|
|
2542
2905
|
const changeSet = createChangeSet("Auth hooks");
|
|
2543
2906
|
for (const auth of auths) {
|
|
2544
2907
|
const { parsedConfig: config } = auth;
|
|
2545
2908
|
const beforeLogin = config.hooks?.beforeLogin;
|
|
2546
2909
|
let existingHook;
|
|
2547
2910
|
try {
|
|
2548
|
-
await client.getAuthHook({
|
|
2911
|
+
const { hook } = await client.getAuthHook({
|
|
2549
2912
|
workspaceId,
|
|
2550
2913
|
namespaceName: config.name,
|
|
2551
2914
|
hookPoint: AuthHookPoint.BEFORE_LOGIN
|
|
2552
2915
|
});
|
|
2553
|
-
existingHook =
|
|
2916
|
+
existingHook = hook;
|
|
2554
2917
|
} catch (error) {
|
|
2555
|
-
if (error instanceof ConnectError && error.code === Code.NotFound) existingHook =
|
|
2918
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) existingHook = void 0;
|
|
2556
2919
|
else throw error;
|
|
2557
2920
|
}
|
|
2558
2921
|
if (beforeLogin) {
|
|
@@ -2568,7 +2931,8 @@ async function planAuthHooks(client, workspaceId, auths, deletedServices) {
|
|
|
2568
2931
|
}
|
|
2569
2932
|
}
|
|
2570
2933
|
};
|
|
2571
|
-
if (existingHook) changeSet.
|
|
2934
|
+
if (existingHook) if (!forceApplyAll && areAuthHooksEqual(existingHook, hookRequest.hook)) changeSet.unchanged.push({ name: `${config.name}/before-login` });
|
|
2935
|
+
else changeSet.updates.push({
|
|
2572
2936
|
name: `${config.name}/before-login`,
|
|
2573
2937
|
request: hookRequest
|
|
2574
2938
|
});
|
|
@@ -2751,19 +3115,10 @@ const ACTOR_TRANSFORM_EXPR = "actor: args.actor ? (({ attributeMap, attributes:
|
|
|
2751
3115
|
function buildExecutorArgsExpr(triggerKind, env) {
|
|
2752
3116
|
const envExpr = `env: ${JSON.stringify(env)}`;
|
|
2753
3117
|
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} })`;
|
|
3118
|
+
case "schedule": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
2764
3119
|
case "resolverExecuted": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, success: !!args.succeeded, result: args.succeeded?.result.resolver, error: args.failed?.error, ${envExpr} })`;
|
|
2765
3120
|
case "incomingWebhook": return `({ ...args, appNamespace: args.namespaceName, rawBody: args.raw_body, ${envExpr} })`;
|
|
2766
|
-
default:
|
|
3121
|
+
default: return `({ ...args, event: args.eventType?.split(".").pop(), rawEvent: args.eventType, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
2767
3122
|
}
|
|
2768
3123
|
}
|
|
2769
3124
|
/**
|
|
@@ -2833,13 +3188,15 @@ async function planExecutor(context) {
|
|
|
2833
3188
|
const { metadata } = await client.getMetadata({ trn: trn$3(workspaceId, resource.name) });
|
|
2834
3189
|
existingExecutors[resource.name] = {
|
|
2835
3190
|
resource,
|
|
2836
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
3191
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
3192
|
+
allLabels: metadata?.labels
|
|
2837
3193
|
};
|
|
2838
3194
|
}));
|
|
2839
3195
|
const executors = forRemoval ? {} : await application.executorService?.loadExecutors() ?? {};
|
|
2840
3196
|
for (const executor of Object.values(executors)) {
|
|
2841
3197
|
const existing = existingExecutors[executor.name];
|
|
2842
3198
|
const metaRequest = await buildMetaRequest(trn$3(workspaceId, executor.name), application.name);
|
|
3199
|
+
const desiredExecutor = protoExecutor(application, executor);
|
|
2843
3200
|
if (existing) {
|
|
2844
3201
|
if (!existing.label) unmanaged.push({
|
|
2845
3202
|
resourceType: "Executor",
|
|
@@ -2850,11 +3207,12 @@ async function planExecutor(context) {
|
|
|
2850
3207
|
resourceName: executor.name,
|
|
2851
3208
|
currentOwner: existing.label
|
|
2852
3209
|
});
|
|
2853
|
-
changeSet.
|
|
3210
|
+
if (existing.label === application.name && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areExecutorsEqual(existing.resource, desiredExecutor)) changeSet.unchanged.push({ name: executor.name });
|
|
3211
|
+
else changeSet.updates.push({
|
|
2854
3212
|
name: executor.name,
|
|
2855
3213
|
request: {
|
|
2856
3214
|
workspaceId,
|
|
2857
|
-
executor:
|
|
3215
|
+
executor: desiredExecutor
|
|
2858
3216
|
},
|
|
2859
3217
|
metaRequest
|
|
2860
3218
|
});
|
|
@@ -2863,7 +3221,7 @@ async function planExecutor(context) {
|
|
|
2863
3221
|
name: executor.name,
|
|
2864
3222
|
request: {
|
|
2865
3223
|
workspaceId,
|
|
2866
|
-
executor:
|
|
3224
|
+
executor: desiredExecutor
|
|
2867
3225
|
},
|
|
2868
3226
|
metaRequest
|
|
2869
3227
|
});
|
|
@@ -2887,6 +3245,56 @@ async function planExecutor(context) {
|
|
|
2887
3245
|
resourceOwners
|
|
2888
3246
|
};
|
|
2889
3247
|
}
|
|
3248
|
+
function normalizeComparableExecutor(executor) {
|
|
3249
|
+
const normalized = normalizeProtoConfig(executor) ?? {};
|
|
3250
|
+
const webhookHeaders = normalized.targetConfig?.config?.case === "webhook" ? [...normalized.targetConfig.config.value.headers ?? []].sort((left, right) => (left.key ?? "").localeCompare(right.key ?? "")) : void 0;
|
|
3251
|
+
const triggerConfig = normalized.triggerConfig?.config?.case === "incomingWebhook" ? {
|
|
3252
|
+
...normalized.triggerConfig,
|
|
3253
|
+
config: {
|
|
3254
|
+
...normalized.triggerConfig.config,
|
|
3255
|
+
value: {}
|
|
3256
|
+
}
|
|
3257
|
+
} : normalized.triggerConfig?.config?.case === "event" ? {
|
|
3258
|
+
...normalized.triggerConfig,
|
|
3259
|
+
config: {
|
|
3260
|
+
...normalized.triggerConfig.config,
|
|
3261
|
+
value: {
|
|
3262
|
+
...normalized.triggerConfig.config.value,
|
|
3263
|
+
eventType: void 0
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
} : normalized.triggerConfig;
|
|
3267
|
+
return {
|
|
3268
|
+
name: normalized.name,
|
|
3269
|
+
description: normalized.description ?? "",
|
|
3270
|
+
disabled: normalized.disabled ?? false,
|
|
3271
|
+
triggerType: normalized.triggerType,
|
|
3272
|
+
triggerConfig,
|
|
3273
|
+
targetType: normalized.targetType,
|
|
3274
|
+
targetConfig: normalized.targetConfig?.config?.case === "webhook" ? {
|
|
3275
|
+
...normalized.targetConfig,
|
|
3276
|
+
config: {
|
|
3277
|
+
...normalized.targetConfig.config,
|
|
3278
|
+
value: {
|
|
3279
|
+
...normalized.targetConfig.config.value,
|
|
3280
|
+
headers: webhookHeaders
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
} : normalized.targetConfig?.config?.case === "function" ? {
|
|
3284
|
+
...normalized.targetConfig,
|
|
3285
|
+
config: {
|
|
3286
|
+
...normalized.targetConfig.config,
|
|
3287
|
+
value: {
|
|
3288
|
+
...normalized.targetConfig.config.value,
|
|
3289
|
+
script: void 0
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
} : normalized.targetConfig
|
|
3293
|
+
};
|
|
3294
|
+
}
|
|
3295
|
+
function areExecutorsEqual(existing, desired) {
|
|
3296
|
+
return areNormalizedEqual(normalizeComparableExecutor(existing), normalizeComparableExecutor(desired));
|
|
3297
|
+
}
|
|
2890
3298
|
function resolveTailorDBNamespace(application, typeName) {
|
|
2891
3299
|
for (const service of application.tailorDBServices) if (service.types[typeName]) return service.namespace;
|
|
2892
3300
|
throw new Error(`TailorDB type "${typeName}" not found in any namespace. Available namespaces: ${application.tailorDBServices.map((s) => s.namespace).join(", ")}`);
|
|
@@ -2911,18 +3319,6 @@ function protoExecutor(application, executor) {
|
|
|
2911
3319
|
let triggerType;
|
|
2912
3320
|
let triggerConfig;
|
|
2913
3321
|
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
3322
|
function typedEventTrigger(typedConfig) {
|
|
2927
3323
|
return { config: {
|
|
2928
3324
|
case: "event",
|
|
@@ -2940,14 +3336,12 @@ function protoExecutor(application, executor) {
|
|
|
2940
3336
|
}
|
|
2941
3337
|
} };
|
|
2942
3338
|
break;
|
|
2943
|
-
case "
|
|
2944
|
-
case "recordUpdated":
|
|
2945
|
-
case "recordDeleted":
|
|
3339
|
+
case "tailordb":
|
|
2946
3340
|
triggerType = ExecutorTriggerType.EVENT;
|
|
2947
3341
|
triggerConfig = typedEventTrigger({
|
|
2948
3342
|
case: "tailordb",
|
|
2949
3343
|
value: {
|
|
2950
|
-
eventTypes:
|
|
3344
|
+
eventTypes: trigger.events,
|
|
2951
3345
|
namespaceName: resolveTailorDBNamespace(application, trigger.typeName),
|
|
2952
3346
|
typeName: trigger.typeName,
|
|
2953
3347
|
...trigger.condition ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } } : {}
|
|
@@ -2959,7 +3353,7 @@ function protoExecutor(application, executor) {
|
|
|
2959
3353
|
triggerConfig = typedEventTrigger({
|
|
2960
3354
|
case: "pipeline",
|
|
2961
3355
|
value: {
|
|
2962
|
-
eventTypes: [
|
|
3356
|
+
eventTypes: ["pipeline.resolver.executed"],
|
|
2963
3357
|
namespaceName: resolveResolverNamespace(application, trigger.resolverName),
|
|
2964
3358
|
resolverName: trigger.resolverName,
|
|
2965
3359
|
...trigger.condition ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } } : {}
|
|
@@ -2973,26 +3367,22 @@ function protoExecutor(application, executor) {
|
|
|
2973
3367
|
value: {}
|
|
2974
3368
|
} };
|
|
2975
3369
|
break;
|
|
2976
|
-
case "
|
|
2977
|
-
case "idpUserUpdated":
|
|
2978
|
-
case "idpUserDeleted":
|
|
3370
|
+
case "idpUser":
|
|
2979
3371
|
triggerType = ExecutorTriggerType.EVENT;
|
|
2980
3372
|
triggerConfig = typedEventTrigger({
|
|
2981
3373
|
case: "idp",
|
|
2982
3374
|
value: {
|
|
2983
|
-
eventTypes:
|
|
3375
|
+
eventTypes: trigger.events,
|
|
2984
3376
|
namespaceName: resolveIdpNamespace(application)
|
|
2985
3377
|
}
|
|
2986
3378
|
});
|
|
2987
3379
|
break;
|
|
2988
|
-
case "
|
|
2989
|
-
case "authAccessTokenRefreshed":
|
|
2990
|
-
case "authAccessTokenRevoked":
|
|
3380
|
+
case "authAccessToken":
|
|
2991
3381
|
triggerType = ExecutorTriggerType.EVENT;
|
|
2992
3382
|
triggerConfig = typedEventTrigger({
|
|
2993
3383
|
case: "auth",
|
|
2994
3384
|
value: {
|
|
2995
|
-
eventTypes:
|
|
3385
|
+
eventTypes: trigger.events,
|
|
2996
3386
|
namespaceName: resolveAuthNamespace(application)
|
|
2997
3387
|
}
|
|
2998
3388
|
});
|
|
@@ -3148,7 +3538,7 @@ async function applyPipeline(client, result, phase = "create-update") {
|
|
|
3148
3538
|
* @returns Planned changes
|
|
3149
3539
|
*/
|
|
3150
3540
|
async function planPipeline(context) {
|
|
3151
|
-
const { client, workspaceId, application, forRemoval } = context;
|
|
3541
|
+
const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;
|
|
3152
3542
|
const pipelines = [];
|
|
3153
3543
|
if (!forRemoval) for (const pipeline of application.resolverServices) {
|
|
3154
3544
|
await pipeline.loadResolvers();
|
|
@@ -3156,7 +3546,7 @@ async function planPipeline(context) {
|
|
|
3156
3546
|
}
|
|
3157
3547
|
const executors = forRemoval ? [] : Object.values(await application.executorService?.loadExecutors() ?? {});
|
|
3158
3548
|
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);
|
|
3549
|
+
const resolverChangeSet = await planResolvers(client, workspaceId, pipelines, executors, serviceChangeSet.deletes.map((del) => del.name), application.env, forceApplyAll);
|
|
3160
3550
|
serviceChangeSet.print();
|
|
3161
3551
|
resolverChangeSet.print();
|
|
3162
3552
|
return {
|
|
@@ -3196,7 +3586,8 @@ async function planServices$1(client, workspaceId, appName, pipelines) {
|
|
|
3196
3586
|
const { metadata } = await client.getMetadata({ trn: trn$2(workspaceId, resource.namespace.name) });
|
|
3197
3587
|
existingServices[resource.namespace.name] = {
|
|
3198
3588
|
resource,
|
|
3199
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
3589
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
3590
|
+
allLabels: metadata?.labels
|
|
3200
3591
|
};
|
|
3201
3592
|
}));
|
|
3202
3593
|
for (const pipeline of pipelines) {
|
|
@@ -3212,7 +3603,8 @@ async function planServices$1(client, workspaceId, appName, pipelines) {
|
|
|
3212
3603
|
resourceName: pipeline.namespace,
|
|
3213
3604
|
currentOwner: existing.label
|
|
3214
3605
|
});
|
|
3215
|
-
changeSet.
|
|
3606
|
+
if (existing.label === appName && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)) changeSet.unchanged.push({ name: pipeline.namespace });
|
|
3607
|
+
else changeSet.updates.push({
|
|
3216
3608
|
name: pipeline.namespace,
|
|
3217
3609
|
request: {
|
|
3218
3610
|
workspaceId,
|
|
@@ -3248,7 +3640,7 @@ async function planServices$1(client, workspaceId, appName, pipelines) {
|
|
|
3248
3640
|
resourceOwners
|
|
3249
3641
|
};
|
|
3250
3642
|
}
|
|
3251
|
-
async function planResolvers(client, workspaceId, pipelines, executors, deletedServices, env) {
|
|
3643
|
+
async function planResolvers(client, workspaceId, pipelines, executors, deletedServices, env, forceApplyAll = false) {
|
|
3252
3644
|
const changeSet = createChangeSet("Pipeline resolvers");
|
|
3253
3645
|
const fetchResolvers = (namespaceName) => {
|
|
3254
3646
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -3271,29 +3663,35 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
3271
3663
|
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
3664
|
for (const pipeline of pipelines) {
|
|
3273
3665
|
const existingResolvers = await fetchResolvers(pipeline.namespace);
|
|
3274
|
-
const
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3666
|
+
const existingResolversMap = new Map(existingResolvers.map((resolver) => [resolver.name, resolver]));
|
|
3667
|
+
for (const resolver of Object.values(pipeline.resolvers)) {
|
|
3668
|
+
const desiredResolver = processResolver(pipeline.namespace, resolver, executorUsedResolvers, env);
|
|
3669
|
+
if (existingResolversMap.get(resolver.name)) {
|
|
3670
|
+
const { pipelineResolver: existingResolverDetail } = await client.getPipelineResolver({
|
|
3671
|
+
workspaceId,
|
|
3672
|
+
namespaceName: pipeline.namespace,
|
|
3673
|
+
resolverName: resolver.name
|
|
3674
|
+
});
|
|
3675
|
+
if (!forceApplyAll && existingResolverDetail && areResolversEqual(existingResolverDetail, desiredResolver)) changeSet.unchanged.push({ name: resolver.name });
|
|
3676
|
+
else changeSet.updates.push({
|
|
3677
|
+
name: resolver.name,
|
|
3678
|
+
request: {
|
|
3679
|
+
workspaceId,
|
|
3680
|
+
namespaceName: pipeline.namespace,
|
|
3681
|
+
pipelineResolver: desiredResolver
|
|
3682
|
+
}
|
|
3683
|
+
});
|
|
3684
|
+
existingResolversMap.delete(resolver.name);
|
|
3685
|
+
} else changeSet.creates.push({
|
|
3280
3686
|
name: resolver.name,
|
|
3281
3687
|
request: {
|
|
3282
3688
|
workspaceId,
|
|
3283
3689
|
namespaceName: pipeline.namespace,
|
|
3284
|
-
pipelineResolver:
|
|
3690
|
+
pipelineResolver: desiredResolver
|
|
3285
3691
|
}
|
|
3286
3692
|
});
|
|
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) => {
|
|
3693
|
+
}
|
|
3694
|
+
existingResolversMap.forEach((_resolver, name) => {
|
|
3297
3695
|
changeSet.deletes.push({
|
|
3298
3696
|
name,
|
|
3299
3697
|
request: {
|
|
@@ -3316,6 +3714,59 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
3316
3714
|
});
|
|
3317
3715
|
return changeSet;
|
|
3318
3716
|
}
|
|
3717
|
+
function normalizeComparableResolver(resolver) {
|
|
3718
|
+
const normalized = normalizeProtoConfig(resolver) ?? {};
|
|
3719
|
+
return {
|
|
3720
|
+
name: normalized.name,
|
|
3721
|
+
description: normalized.description ?? "",
|
|
3722
|
+
authorization: normalized.authorization ?? "",
|
|
3723
|
+
operationType: normalized.operationType,
|
|
3724
|
+
publishExecutionEvents: normalized.publishExecutionEvents ?? false,
|
|
3725
|
+
inputs: normalizeComparableFields(normalized.inputs),
|
|
3726
|
+
response: normalizeComparableField(normalized.response),
|
|
3727
|
+
pipelines: normalizeComparablePipelines(normalized.pipelines)
|
|
3728
|
+
};
|
|
3729
|
+
}
|
|
3730
|
+
function areResolversEqual(existing, desired) {
|
|
3731
|
+
return areNormalizedEqual(normalizeComparableResolver(existing), normalizeComparableResolver(desired));
|
|
3732
|
+
}
|
|
3733
|
+
function normalizeComparablePipelines(pipelines) {
|
|
3734
|
+
return (pipelines ?? []).map((pipeline) => ({
|
|
3735
|
+
name: pipeline.name ?? "",
|
|
3736
|
+
operationName: pipeline.operationName ?? "",
|
|
3737
|
+
description: pipeline.description ?? "",
|
|
3738
|
+
operationType: pipeline.operationType,
|
|
3739
|
+
operationSourceRef: pipeline.operationSourceRef ?? "",
|
|
3740
|
+
operationHook: pipeline.operationHook?.expr ?? "",
|
|
3741
|
+
postScript: pipeline.postScript ?? "",
|
|
3742
|
+
skipOperationOnError: pipeline.skipOperationOnError ?? false,
|
|
3743
|
+
invoker: pipeline.invoker ?? void 0
|
|
3744
|
+
}));
|
|
3745
|
+
}
|
|
3746
|
+
function normalizeComparableFields(fields) {
|
|
3747
|
+
return (fields ?? []).map((field) => normalizeComparableField(field));
|
|
3748
|
+
}
|
|
3749
|
+
function normalizeComparableField(field) {
|
|
3750
|
+
if (!field) return;
|
|
3751
|
+
return {
|
|
3752
|
+
name: field.name ?? "",
|
|
3753
|
+
array: field.array ?? false,
|
|
3754
|
+
required: field.required ?? true,
|
|
3755
|
+
description: field.description ?? "",
|
|
3756
|
+
type: normalizeComparableType(field.type)
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3759
|
+
function normalizeComparableType(type) {
|
|
3760
|
+
if (!type) return;
|
|
3761
|
+
return {
|
|
3762
|
+
kind: type.kind ?? "",
|
|
3763
|
+
name: type.name ?? "",
|
|
3764
|
+
required: type.required ?? true,
|
|
3765
|
+
description: type.description ?? "",
|
|
3766
|
+
allowedValues: type.allowedValues ?? [],
|
|
3767
|
+
fields: (type.fields ?? []).map((field) => normalizeComparableField(field))
|
|
3768
|
+
};
|
|
3769
|
+
}
|
|
3319
3770
|
function processResolver(namespace, resolver, executorUsedResolvers, env) {
|
|
3320
3771
|
const pipelines = [{
|
|
3321
3772
|
name: "body",
|
|
@@ -3431,7 +3882,7 @@ function hashValue(value) {
|
|
|
3431
3882
|
* @returns Planned changes for vaults and secrets
|
|
3432
3883
|
*/
|
|
3433
3884
|
async function planSecretManager(context) {
|
|
3434
|
-
const { client, workspaceId, application, forRemoval } = context;
|
|
3885
|
+
const { client, workspaceId, application, forRemoval, forceApplyAll = false } = context;
|
|
3435
3886
|
const secretVaults = forRemoval ? [] : application.secrets;
|
|
3436
3887
|
const vaultChangeSet = createChangeSet("Secret Manager vaults");
|
|
3437
3888
|
const secretChangeSet = createChangeSet("Secret Manager secrets");
|
|
@@ -3453,10 +3904,11 @@ async function planSecretManager(context) {
|
|
|
3453
3904
|
});
|
|
3454
3905
|
const existingVaults = {};
|
|
3455
3906
|
await Promise.all(existingVaultList.map(async (resource) => {
|
|
3456
|
-
const { metadata } = await client.getMetadata({ trn: vaultTrn(workspaceId, resource.name) });
|
|
3907
|
+
const { metadata } = await client.getMetadata({ trn: vaultTrn$1(workspaceId, resource.name) });
|
|
3457
3908
|
existingVaults[resource.name] = {
|
|
3458
3909
|
resource,
|
|
3459
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
3910
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
3911
|
+
allLabels: metadata?.labels
|
|
3460
3912
|
};
|
|
3461
3913
|
}));
|
|
3462
3914
|
const state = loadSecretsState();
|
|
@@ -3464,6 +3916,7 @@ async function planSecretManager(context) {
|
|
|
3464
3916
|
const vaultName = vault.vaultName;
|
|
3465
3917
|
const existing = existingVaults[vaultName];
|
|
3466
3918
|
if (existing) {
|
|
3919
|
+
const metaRequest = await buildMetaRequest(vaultTrn$1(workspaceId, vaultName), application.name);
|
|
3467
3920
|
if (!existing.label) unmanaged.push({
|
|
3468
3921
|
resourceType: "Secret Manager vault",
|
|
3469
3922
|
resourceName: vaultName
|
|
@@ -3473,7 +3926,8 @@ async function planSecretManager(context) {
|
|
|
3473
3926
|
resourceName: vaultName,
|
|
3474
3927
|
currentOwner: existing.label
|
|
3475
3928
|
});
|
|
3476
|
-
vaultChangeSet.
|
|
3929
|
+
if (existing.label === application.name && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels)) vaultChangeSet.unchanged.push({ name: vaultName });
|
|
3930
|
+
else vaultChangeSet.updates.push({
|
|
3477
3931
|
name: vaultName,
|
|
3478
3932
|
workspaceId
|
|
3479
3933
|
});
|
|
@@ -3499,7 +3953,9 @@ async function planSecretManager(context) {
|
|
|
3499
3953
|
})).map((s) => s.name);
|
|
3500
3954
|
const existingSet = new Set(existingSecrets);
|
|
3501
3955
|
for (const secret of vault.secrets) if (existingSet.has(secret.name)) {
|
|
3502
|
-
|
|
3956
|
+
const currentHash = hashValue(secret.value);
|
|
3957
|
+
const storedHash = state.vaults[vaultName]?.[secret.name];
|
|
3958
|
+
if (forceApplyAll || currentHash !== storedHash) secretChangeSet.updates.push({
|
|
3503
3959
|
name: `${vaultName}/${secret.name}`,
|
|
3504
3960
|
secretName: secret.name,
|
|
3505
3961
|
workspaceId,
|
|
@@ -3562,7 +4018,7 @@ async function planSecretManager(context) {
|
|
|
3562
4018
|
resourceOwners
|
|
3563
4019
|
};
|
|
3564
4020
|
}
|
|
3565
|
-
function vaultTrn(workspaceId, name) {
|
|
4021
|
+
function vaultTrn$1(workspaceId, name) {
|
|
3566
4022
|
return `trn:v1:workspace:${workspaceId}:vault:${name}`;
|
|
3567
4023
|
}
|
|
3568
4024
|
/**
|
|
@@ -3582,12 +4038,12 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
3582
4038
|
secretmanagerVaultName: create.name
|
|
3583
4039
|
});
|
|
3584
4040
|
if (application) {
|
|
3585
|
-
const metaRequest = await buildMetaRequest(vaultTrn(create.workspaceId, create.name), application.name);
|
|
4041
|
+
const metaRequest = await buildMetaRequest(vaultTrn$1(create.workspaceId, create.name), application.name);
|
|
3586
4042
|
await client.setMetadata(metaRequest);
|
|
3587
4043
|
}
|
|
3588
4044
|
}));
|
|
3589
4045
|
if (application) await Promise.all(vaultChangeSet.updates.map(async (update) => {
|
|
3590
|
-
const metaRequest = await buildMetaRequest(vaultTrn(update.workspaceId, update.name), application.name);
|
|
4046
|
+
const metaRequest = await buildMetaRequest(vaultTrn$1(update.workspaceId, update.name), application.name);
|
|
3591
4047
|
await client.setMetadata(metaRequest);
|
|
3592
4048
|
}));
|
|
3593
4049
|
await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret({
|
|
@@ -3655,6 +4111,21 @@ async function applyStaticWebsite(client, result, phase = "create-update") {
|
|
|
3655
4111
|
function trn$1(workspaceId, name) {
|
|
3656
4112
|
return `trn:v1:workspace:${workspaceId}:staticwebsite:${name}`;
|
|
3657
4113
|
}
|
|
4114
|
+
function normalizeComparableStaticWebsiteShape(input) {
|
|
4115
|
+
return {
|
|
4116
|
+
description: input.description,
|
|
4117
|
+
allowedIpAddresses: [...input.allowedIpAddresses].sort()
|
|
4118
|
+
};
|
|
4119
|
+
}
|
|
4120
|
+
function normalizeComparableStaticWebsite(input) {
|
|
4121
|
+
return normalizeComparableStaticWebsiteShape({
|
|
4122
|
+
description: input.description || "",
|
|
4123
|
+
allowedIpAddresses: [...input.allowedIpAddresses || []]
|
|
4124
|
+
});
|
|
4125
|
+
}
|
|
4126
|
+
function areStaticWebsitesEqual(existing, desired) {
|
|
4127
|
+
return areNormalizedEqual(normalizeComparableStaticWebsite(existing), normalizeComparableStaticWebsite(desired));
|
|
4128
|
+
}
|
|
3658
4129
|
/**
|
|
3659
4130
|
* Plan static website changes based on current and desired state.
|
|
3660
4131
|
* @param context - Planning context
|
|
@@ -3684,7 +4155,8 @@ async function planStaticWebsite(context) {
|
|
|
3684
4155
|
const { metadata } = await client.getMetadata({ trn: trn$1(workspaceId, resource.name) });
|
|
3685
4156
|
existingWebsites[resource.name] = {
|
|
3686
4157
|
resource,
|
|
3687
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
4158
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
4159
|
+
allLabels: metadata?.labels
|
|
3688
4160
|
};
|
|
3689
4161
|
}));
|
|
3690
4162
|
const staticWebsiteServices = forRemoval ? [] : application.staticWebsiteServices;
|
|
@@ -3693,7 +4165,17 @@ async function planStaticWebsite(context) {
|
|
|
3693
4165
|
const name = websiteService.name;
|
|
3694
4166
|
const existing = existingWebsites[name];
|
|
3695
4167
|
const metaRequest = await buildMetaRequest(trn$1(workspaceId, name), application.name);
|
|
4168
|
+
const desired = normalizeComparableStaticWebsite(config);
|
|
4169
|
+
const request = {
|
|
4170
|
+
workspaceId,
|
|
4171
|
+
staticwebsite: {
|
|
4172
|
+
name,
|
|
4173
|
+
description: config.description || "",
|
|
4174
|
+
allowedIpAddresses: config.allowedIpAddresses || []
|
|
4175
|
+
}
|
|
4176
|
+
};
|
|
3696
4177
|
if (existing) {
|
|
4178
|
+
const isManagedByApp = existing.label === application.name;
|
|
3697
4179
|
if (!existing.label) unmanaged.push({
|
|
3698
4180
|
resourceType: "StaticWebsite",
|
|
3699
4181
|
resourceName: name
|
|
@@ -3703,29 +4185,16 @@ async function planStaticWebsite(context) {
|
|
|
3703
4185
|
resourceName: name,
|
|
3704
4186
|
currentOwner: existing.label
|
|
3705
4187
|
});
|
|
3706
|
-
changeSet.
|
|
4188
|
+
if (isManagedByApp && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areStaticWebsitesEqual(existing.resource, desired)) changeSet.unchanged.push({ name });
|
|
4189
|
+
else changeSet.updates.push({
|
|
3707
4190
|
name,
|
|
3708
|
-
request
|
|
3709
|
-
workspaceId,
|
|
3710
|
-
staticwebsite: {
|
|
3711
|
-
name,
|
|
3712
|
-
description: config.description || "",
|
|
3713
|
-
allowedIpAddresses: config.allowedIpAddresses || []
|
|
3714
|
-
}
|
|
3715
|
-
},
|
|
4191
|
+
request,
|
|
3716
4192
|
metaRequest
|
|
3717
4193
|
});
|
|
3718
4194
|
delete existingWebsites[name];
|
|
3719
4195
|
} else changeSet.creates.push({
|
|
3720
4196
|
name,
|
|
3721
|
-
request
|
|
3722
|
-
workspaceId,
|
|
3723
|
-
staticwebsite: {
|
|
3724
|
-
name,
|
|
3725
|
-
description: config.description || "",
|
|
3726
|
-
allowedIpAddresses: config.allowedIpAddresses || []
|
|
3727
|
-
}
|
|
3728
|
-
},
|
|
4197
|
+
request,
|
|
3729
4198
|
metaRequest
|
|
3730
4199
|
});
|
|
3731
4200
|
}
|
|
@@ -3949,8 +4418,11 @@ const INITIAL_SCHEMA_NUMBER = 0;
|
|
|
3949
4418
|
* Migration file names (used within migration directories)
|
|
3950
4419
|
*/
|
|
3951
4420
|
const SCHEMA_FILE_NAME = "schema.json";
|
|
4421
|
+
/** File name for migration diff metadata. */
|
|
3952
4422
|
const DIFF_FILE_NAME = "diff.json";
|
|
4423
|
+
/** File name for migration script. */
|
|
3953
4424
|
const MIGRATE_FILE_NAME = "migrate.ts";
|
|
4425
|
+
/** File name for generated DB type definitions. */
|
|
3954
4426
|
const DB_TYPES_FILE_NAME = "db.ts";
|
|
3955
4427
|
/**
|
|
3956
4428
|
* Pattern for validating migration number format (4-digit sequential number)
|
|
@@ -5848,7 +6320,7 @@ async function executeSingleMigrationPostPhase(client, changeSet, migration) {
|
|
|
5848
6320
|
* @returns Planned changes
|
|
5849
6321
|
*/
|
|
5850
6322
|
async function planTailorDB(context) {
|
|
5851
|
-
const { client, workspaceId, application, forRemoval, config, noSchemaCheck } = context;
|
|
6323
|
+
const { client, workspaceId, application, forRemoval, config, noSchemaCheck, forceApplyAll = false } = context;
|
|
5852
6324
|
const tailordbs = [];
|
|
5853
6325
|
if (!forRemoval) for (const tailordb of application.tailorDBServices) {
|
|
5854
6326
|
await tailordb.loadTypes();
|
|
@@ -5857,7 +6329,7 @@ async function planTailorDB(context) {
|
|
|
5857
6329
|
const executors = forRemoval ? [] : Object.values(await application.executorService?.loadExecutors() ?? {});
|
|
5858
6330
|
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices(client, workspaceId, application.name, tailordbs);
|
|
5859
6331
|
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)]);
|
|
6332
|
+
const [typeChangeSet, gqlPermissionChangeSet] = await Promise.all([planTypes(client, workspaceId, tailordbs, executors, deletedServices, void 0, forceApplyAll), planGqlPermissions(client, workspaceId, tailordbs, deletedServices, forceApplyAll)]);
|
|
5861
6333
|
serviceChangeSet.print();
|
|
5862
6334
|
typeChangeSet.print();
|
|
5863
6335
|
gqlPermissionChangeSet.print();
|
|
@@ -5881,6 +6353,21 @@ async function planTailorDB(context) {
|
|
|
5881
6353
|
function trn(workspaceId, name) {
|
|
5882
6354
|
return `${trnPrefix(workspaceId)}:tailordb:${name}`;
|
|
5883
6355
|
}
|
|
6356
|
+
function normalizeComparableTailorDBService(service) {
|
|
6357
|
+
return normalizeProtoConfig({
|
|
6358
|
+
namespace: service.namespace,
|
|
6359
|
+
defaultTimezone: service.defaultTimezone || "UTC"
|
|
6360
|
+
});
|
|
6361
|
+
}
|
|
6362
|
+
function areTailorDBServicesEqual(existing, desired) {
|
|
6363
|
+
return areNormalizedEqual(normalizeComparableTailorDBService({
|
|
6364
|
+
namespace: existing.namespace?.name,
|
|
6365
|
+
defaultTimezone: existing.defaultTimezone
|
|
6366
|
+
}), normalizeComparableTailorDBService({
|
|
6367
|
+
namespace: desired.namespace,
|
|
6368
|
+
defaultTimezone: "UTC"
|
|
6369
|
+
}));
|
|
6370
|
+
}
|
|
5884
6371
|
async function planServices(client, workspaceId, appName, tailordbs) {
|
|
5885
6372
|
const changeSet = createChangeSet("TailorDB services");
|
|
5886
6373
|
const conflicts = [];
|
|
@@ -5922,7 +6409,8 @@ async function planServices(client, workspaceId, appName, tailordbs) {
|
|
|
5922
6409
|
resourceName: tailordb.namespace,
|
|
5923
6410
|
currentOwner: existing.label
|
|
5924
6411
|
});
|
|
5925
|
-
changeSet.
|
|
6412
|
+
if (existing.label === appName && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areTailorDBServicesEqual(existing.resource, tailordb)) changeSet.unchanged.push({ name: tailordb.namespace });
|
|
6413
|
+
else changeSet.updates.push({
|
|
5926
6414
|
name: tailordb.namespace,
|
|
5927
6415
|
metaRequest
|
|
5928
6416
|
});
|
|
@@ -5955,7 +6443,7 @@ async function planServices(client, workspaceId, appName, tailordbs) {
|
|
|
5955
6443
|
resourceOwners
|
|
5956
6444
|
};
|
|
5957
6445
|
}
|
|
5958
|
-
async function planTypes(client, workspaceId, tailordbs, executors, deletedServices, filteredTypesByNamespace) {
|
|
6446
|
+
async function planTypes(client, workspaceId, tailordbs, executors, deletedServices, filteredTypesByNamespace, forceApplyAll = false) {
|
|
5959
6447
|
const changeSet = createChangeSet("TailorDB types");
|
|
5960
6448
|
const fetchTypes = (namespaceName) => {
|
|
5961
6449
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -5974,7 +6462,7 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
5974
6462
|
});
|
|
5975
6463
|
};
|
|
5976
6464
|
const executorUsedTypes = /* @__PURE__ */ new Set();
|
|
5977
|
-
for (const executor of executors) if (executor.trigger.kind === "
|
|
6465
|
+
for (const executor of executors) if (executor.trigger.kind === "tailordb") executorUsedTypes.add(executor.trigger.typeName);
|
|
5978
6466
|
for (const tailordb of tailordbs) {
|
|
5979
6467
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
5980
6468
|
for (const typeName of Object.keys(types)) {
|
|
@@ -5984,13 +6472,14 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
5984
6472
|
}
|
|
5985
6473
|
for (const tailordb of tailordbs) {
|
|
5986
6474
|
const existingTypes = await fetchTypes(tailordb.namespace);
|
|
5987
|
-
const
|
|
5988
|
-
existingTypes.forEach((type) => existingNameSet.add(type.name));
|
|
6475
|
+
const existingTypesMap = new Map(existingTypes.map((type) => [type.name, type]));
|
|
5989
6476
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
5990
6477
|
for (const typeName of Object.keys(types)) {
|
|
5991
6478
|
const tailordbType = generateTailorDBTypeManifest(types[typeName], executorUsedTypes, tailordb.config.gqlOperations);
|
|
5992
|
-
|
|
5993
|
-
|
|
6479
|
+
const existingType = existingTypesMap.get(typeName);
|
|
6480
|
+
if (existingType) {
|
|
6481
|
+
if (!forceApplyAll && areNormalizedEqual(normalizeComparableTailorDBType(existingType), normalizeComparableTailorDBType(tailordbType))) changeSet.unchanged.push({ name: typeName });
|
|
6482
|
+
else changeSet.updates.push({
|
|
5994
6483
|
name: typeName,
|
|
5995
6484
|
request: {
|
|
5996
6485
|
workspaceId,
|
|
@@ -5998,7 +6487,7 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
5998
6487
|
tailordbType
|
|
5999
6488
|
}
|
|
6000
6489
|
});
|
|
6001
|
-
|
|
6490
|
+
existingTypesMap.delete(typeName);
|
|
6002
6491
|
} else changeSet.creates.push({
|
|
6003
6492
|
name: typeName,
|
|
6004
6493
|
request: {
|
|
@@ -6008,7 +6497,7 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
6008
6497
|
}
|
|
6009
6498
|
});
|
|
6010
6499
|
}
|
|
6011
|
-
|
|
6500
|
+
existingTypesMap.forEach((_type, name) => {
|
|
6012
6501
|
changeSet.deletes.push({
|
|
6013
6502
|
name,
|
|
6014
6503
|
request: {
|
|
@@ -6031,6 +6520,66 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
6031
6520
|
});
|
|
6032
6521
|
return changeSet;
|
|
6033
6522
|
}
|
|
6523
|
+
function isPlainObject(value) {
|
|
6524
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6525
|
+
}
|
|
6526
|
+
const tailordbCompareKnownDefaults = {
|
|
6527
|
+
disableGqlOperations: {
|
|
6528
|
+
create: false,
|
|
6529
|
+
update: false,
|
|
6530
|
+
delete: false,
|
|
6531
|
+
read: false
|
|
6532
|
+
},
|
|
6533
|
+
emptyExpression: "",
|
|
6534
|
+
numericStringPaths: new Set([
|
|
6535
|
+
"schema.fields.*.serial.start",
|
|
6536
|
+
"schema.fields.*.serial.maxValue",
|
|
6537
|
+
"schema.settings.defaultQueryLimitSize",
|
|
6538
|
+
"schema.settings.maxBulkUpsertSize"
|
|
6539
|
+
])
|
|
6540
|
+
};
|
|
6541
|
+
function normalizeComparableTailorDBType(type) {
|
|
6542
|
+
const normalized = normalizeProtoConfig(type);
|
|
6543
|
+
return normalizeTailorDBCompareValue({
|
|
6544
|
+
name: normalized?.name ?? "",
|
|
6545
|
+
schema: {
|
|
6546
|
+
description: normalized?.schema?.description ?? "",
|
|
6547
|
+
fields: normalized?.schema?.fields ?? {},
|
|
6548
|
+
relationships: normalized?.schema?.relationships ?? {},
|
|
6549
|
+
settings: normalized?.schema?.settings ?? {},
|
|
6550
|
+
indexes: normalized?.schema?.indexes ?? {},
|
|
6551
|
+
files: normalized?.schema?.files ?? {},
|
|
6552
|
+
permission: normalized?.schema?.permission ?? {}
|
|
6553
|
+
}
|
|
6554
|
+
}, []);
|
|
6555
|
+
}
|
|
6556
|
+
function normalizeTailorDBCompareValue(value, path) {
|
|
6557
|
+
if (value === void 0 || value === null) return value;
|
|
6558
|
+
if (typeof value === "number" || typeof value === "bigint" || typeof value === "string") {
|
|
6559
|
+
if (matchesNumericStringPath(path) && isNumericLikeValue(value)) return String(value);
|
|
6560
|
+
if (path.at(-1) === "expr" && value === tailordbCompareKnownDefaults.emptyExpression) return;
|
|
6561
|
+
return value;
|
|
6562
|
+
}
|
|
6563
|
+
if (Array.isArray(value)) return value.map((item, index) => normalizeTailorDBCompareValue(item, [...path, index])).filter((item) => item !== void 0);
|
|
6564
|
+
if (!isPlainObject(value)) return value;
|
|
6565
|
+
const normalizedEntries = Object.entries(value).map(([key, entryValue]) => [key, normalizeTailorDBCompareValue(entryValue, [...path, key])]).filter(([, entryValue]) => entryValue !== void 0);
|
|
6566
|
+
const normalizedObject = Object.fromEntries(normalizedEntries);
|
|
6567
|
+
if (path.at(-1) === "fields" && Object.keys(normalizedObject).length === 0) return;
|
|
6568
|
+
if (path.at(-1) === "disableGqlOperations" && areNormalizedEqual(normalizedObject, tailordbCompareKnownDefaults.disableGqlOperations)) return;
|
|
6569
|
+
return normalizedObject;
|
|
6570
|
+
}
|
|
6571
|
+
function matchesNumericStringPath(path) {
|
|
6572
|
+
const pathKey = path.map((segment) => String(segment)).join(".");
|
|
6573
|
+
return [...tailordbCompareKnownDefaults.numericStringPaths].some((pattern) => {
|
|
6574
|
+
const patternParts = pattern.split(".");
|
|
6575
|
+
const pathParts = pathKey.split(".");
|
|
6576
|
+
if (patternParts.length !== pathParts.length) return false;
|
|
6577
|
+
return patternParts.every((part, index) => part === "*" || part === pathParts[index]);
|
|
6578
|
+
});
|
|
6579
|
+
}
|
|
6580
|
+
function isNumericLikeValue(value) {
|
|
6581
|
+
return typeof value === "number" || typeof value === "bigint" || /^-?\d+$/.test(value);
|
|
6582
|
+
}
|
|
6034
6583
|
/**
|
|
6035
6584
|
* Generate a TailorDB type manifest from parsed type
|
|
6036
6585
|
* @param {TailorDBType} type - Parsed TailorDB type
|
|
@@ -6267,7 +6816,7 @@ function protoOperand(operand) {
|
|
|
6267
6816
|
value: fromJson(ValueSchema, operand)
|
|
6268
6817
|
} };
|
|
6269
6818
|
}
|
|
6270
|
-
async function planGqlPermissions(client, workspaceId, tailordbs, deletedServices) {
|
|
6819
|
+
async function planGqlPermissions(client, workspaceId, tailordbs, deletedServices, forceApplyAll = false) {
|
|
6271
6820
|
const changeSet = createChangeSet("TailorDB gqlPermissions");
|
|
6272
6821
|
const fetchGqlPermissions = (namespaceName) => {
|
|
6273
6822
|
return fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -6295,14 +6844,17 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
6295
6844
|
for (const typeName of Object.keys(types)) {
|
|
6296
6845
|
const gqlPermission = types[typeName].permissions.gql;
|
|
6297
6846
|
if (!gqlPermission) continue;
|
|
6847
|
+
const desiredPermission = protoGqlPermission(gqlPermission);
|
|
6848
|
+
const existingPermission = existingGqlPermissions.find((entry) => entry.typeName === typeName);
|
|
6298
6849
|
if (existingNameSet.has(typeName)) {
|
|
6299
|
-
changeSet.
|
|
6850
|
+
if (!forceApplyAll && existingPermission && areNormalizedEqual(normalizeComparableGqlPermission(existingPermission.permission), normalizeComparableGqlPermission(desiredPermission))) changeSet.unchanged.push({ name: typeName });
|
|
6851
|
+
else changeSet.updates.push({
|
|
6300
6852
|
name: typeName,
|
|
6301
6853
|
request: {
|
|
6302
6854
|
workspaceId,
|
|
6303
6855
|
namespaceName: tailordb.namespace,
|
|
6304
6856
|
typeName,
|
|
6305
|
-
permission:
|
|
6857
|
+
permission: desiredPermission
|
|
6306
6858
|
}
|
|
6307
6859
|
});
|
|
6308
6860
|
existingNameSet.delete(typeName);
|
|
@@ -6312,7 +6864,7 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
6312
6864
|
workspaceId,
|
|
6313
6865
|
namespaceName: tailordb.namespace,
|
|
6314
6866
|
typeName,
|
|
6315
|
-
permission:
|
|
6867
|
+
permission: desiredPermission
|
|
6316
6868
|
}
|
|
6317
6869
|
});
|
|
6318
6870
|
}
|
|
@@ -6339,6 +6891,12 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
6339
6891
|
});
|
|
6340
6892
|
return changeSet;
|
|
6341
6893
|
}
|
|
6894
|
+
function normalizeComparableGqlPermission(permission) {
|
|
6895
|
+
return { policies: (normalizeProtoConfig(permission)?.policies ?? []).map((policy) => ({
|
|
6896
|
+
...policy,
|
|
6897
|
+
actions: [...policy.actions ?? []].sort((left, right) => left - right)
|
|
6898
|
+
})) };
|
|
6899
|
+
}
|
|
6342
6900
|
function protoGqlPermission(permission) {
|
|
6343
6901
|
return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
|
|
6344
6902
|
}
|
|
@@ -6503,7 +7061,7 @@ function formatMigrationCheckResults(results) {
|
|
|
6503
7061
|
async function applyWorkflow(client, result, phase = "create-update") {
|
|
6504
7062
|
const { changeSet, appName } = result;
|
|
6505
7063
|
if (phase === "create-update") {
|
|
6506
|
-
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName);
|
|
7064
|
+
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, result.unchangedWorkflowJobNames);
|
|
6507
7065
|
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
6508
7066
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
|
|
6509
7067
|
await client.createWorkflow({
|
|
@@ -6549,14 +7107,16 @@ function filterJobFunctionVersions(allVersions, usedJobNames) {
|
|
|
6549
7107
|
* @param client - Operator client instance
|
|
6550
7108
|
* @param changeSet - Workflow change set
|
|
6551
7109
|
* @param appName - Application name
|
|
7110
|
+
* @param unchangedWorkflowJobNames - Job function names used by unchanged workflows
|
|
6552
7111
|
* @returns Map of job function names to versions
|
|
6553
7112
|
*/
|
|
6554
|
-
async function registerJobFunctions(client, changeSet, appName) {
|
|
7113
|
+
async function registerJobFunctions(client, changeSet, appName, unchangedWorkflowJobNames = /* @__PURE__ */ new Set()) {
|
|
6555
7114
|
const jobFunctionVersions = {};
|
|
6556
|
-
const firstWorkflow = changeSet.creates[0] || changeSet.updates[0];
|
|
7115
|
+
const firstWorkflow = changeSet.creates[0] || changeSet.updates[0] || changeSet.deletes[0];
|
|
6557
7116
|
if (!firstWorkflow) return jobFunctionVersions;
|
|
6558
7117
|
const { workspaceId } = firstWorkflow;
|
|
6559
7118
|
const allUsedJobNames = /* @__PURE__ */ new Set();
|
|
7119
|
+
unchangedWorkflowJobNames.forEach((jobName) => allUsedJobNames.add(jobName));
|
|
6560
7120
|
for (const item of [...changeSet.creates, ...changeSet.updates]) for (const jobName of item.usedJobNames) allUsedJobNames.add(jobName);
|
|
6561
7121
|
const existingJobFunctions = await fetchAll(async (pageToken, maxPageSize) => {
|
|
6562
7122
|
const response = await client.listWorkflowJobFunctions({
|
|
@@ -6567,23 +7127,25 @@ async function registerJobFunctions(client, changeSet, appName) {
|
|
|
6567
7127
|
return [response.jobFunctions.map((j) => j.name), response.nextPageToken];
|
|
6568
7128
|
});
|
|
6569
7129
|
const existingJobNamesSet = new Set(existingJobFunctions);
|
|
6570
|
-
|
|
6571
|
-
const
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
7130
|
+
if (changeSet.creates.length > 0 || changeSet.updates.length > 0) {
|
|
7131
|
+
const results = await Promise.all(Array.from(allUsedJobNames).map(async (jobName) => {
|
|
7132
|
+
const response = existingJobNamesSet.has(jobName) ? await client.updateWorkflowJobFunction({
|
|
7133
|
+
workspaceId,
|
|
7134
|
+
jobFunctionName: jobName,
|
|
7135
|
+
scriptRef: workflowJobFunctionName(jobName)
|
|
7136
|
+
}) : await client.createWorkflowJobFunction({
|
|
7137
|
+
workspaceId,
|
|
7138
|
+
jobFunctionName: jobName,
|
|
7139
|
+
scriptRef: workflowJobFunctionName(jobName)
|
|
7140
|
+
});
|
|
7141
|
+
await client.setMetadata(await buildMetaRequest(jobFunctionTrn(workspaceId, jobName), appName));
|
|
7142
|
+
return {
|
|
7143
|
+
jobName,
|
|
7144
|
+
version: response.jobFunction?.version
|
|
7145
|
+
};
|
|
7146
|
+
}));
|
|
7147
|
+
for (const { jobName, version } of results) if (version) jobFunctionVersions[jobName] = version;
|
|
7148
|
+
}
|
|
6587
7149
|
const unusedJobFunctions = existingJobFunctions.filter((jobName) => !allUsedJobNames.has(jobName));
|
|
6588
7150
|
await Promise.all(unusedJobFunctions.map(async (jobName) => {
|
|
6589
7151
|
const { metadata } = await client.getMetadata({ trn: jobFunctionTrn(workspaceId, jobName) });
|
|
@@ -6611,7 +7173,7 @@ function toRetryPolicy(policy) {
|
|
|
6611
7173
|
backoffMultiplier: policy.backoffMultiplier
|
|
6612
7174
|
};
|
|
6613
7175
|
}
|
|
6614
|
-
function workflowTrn(workspaceId, name) {
|
|
7176
|
+
function workflowTrn$1(workspaceId, name) {
|
|
6615
7177
|
return `trn:v1:workspace:${workspaceId}:workflow:${name}`;
|
|
6616
7178
|
}
|
|
6617
7179
|
function jobFunctionTrn(workspaceId, name) {
|
|
@@ -6624,35 +7186,35 @@ function jobFunctionTrn(workspaceId, name) {
|
|
|
6624
7186
|
* @param appName - Application name
|
|
6625
7187
|
* @param workflows - Parsed workflows
|
|
6626
7188
|
* @param mainJobDeps - Main job dependencies by workflow
|
|
7189
|
+
* @param unchangedJobFunctions - Job functions already proven unchanged by function registry plan
|
|
6627
7190
|
* @returns Planned workflow changes
|
|
6628
7191
|
*/
|
|
6629
|
-
async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps) {
|
|
7192
|
+
async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps, unchangedJobFunctions = /* @__PURE__ */ new Set()) {
|
|
6630
7193
|
const changeSet = createChangeSet("Workflows");
|
|
6631
7194
|
const conflicts = [];
|
|
6632
7195
|
const unmanaged = [];
|
|
6633
7196
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
7197
|
+
const unchangedWorkflowJobNames = /* @__PURE__ */ new Set();
|
|
6634
7198
|
const withoutLabel = await fetchAll(async (pageToken, maxPageSize) => {
|
|
6635
7199
|
const response = await client.listWorkflows({
|
|
6636
7200
|
workspaceId,
|
|
6637
7201
|
pageToken,
|
|
6638
7202
|
pageSize: maxPageSize
|
|
6639
7203
|
});
|
|
6640
|
-
return [response.workflows.
|
|
6641
|
-
id: w.id,
|
|
6642
|
-
name: w.name
|
|
6643
|
-
})), response.nextPageToken];
|
|
7204
|
+
return [response.workflows, response.nextPageToken];
|
|
6644
7205
|
});
|
|
6645
7206
|
const existingWorkflows = {};
|
|
6646
7207
|
await Promise.all(withoutLabel.map(async (resource) => {
|
|
6647
|
-
const { metadata } = await client.getMetadata({ trn: workflowTrn(workspaceId, resource.name) });
|
|
7208
|
+
const { metadata } = await client.getMetadata({ trn: workflowTrn$1(workspaceId, resource.name) });
|
|
6648
7209
|
existingWorkflows[resource.name] = {
|
|
6649
7210
|
resource,
|
|
6650
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
7211
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
7212
|
+
allLabels: metadata?.labels
|
|
6651
7213
|
};
|
|
6652
7214
|
}));
|
|
6653
7215
|
for (const workflow of Object.values(workflows)) {
|
|
6654
7216
|
const existing = existingWorkflows[workflow.name];
|
|
6655
|
-
const metaRequest = await buildMetaRequest(workflowTrn(workspaceId, workflow.name), appName);
|
|
7217
|
+
const metaRequest = await buildMetaRequest(workflowTrn$1(workspaceId, workflow.name), appName);
|
|
6656
7218
|
const usedJobNames = mainJobDeps[workflow.mainJob.name];
|
|
6657
7219
|
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
7220
|
if (existing) {
|
|
@@ -6665,7 +7227,10 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
6665
7227
|
resourceName: workflow.name,
|
|
6666
7228
|
currentOwner: existing.label
|
|
6667
7229
|
});
|
|
6668
|
-
|
|
7230
|
+
if (existing.label === appName && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && canTreatWorkflowAsUnchanged(existing.resource, workflow, usedJobNames, unchangedJobFunctions)) {
|
|
7231
|
+
changeSet.unchanged.push({ name: workflow.name });
|
|
7232
|
+
for (const jobName of usedJobNames) unchangedWorkflowJobNames.add(jobName);
|
|
7233
|
+
} else changeSet.updates.push({
|
|
6669
7234
|
name: workflow.name,
|
|
6670
7235
|
workspaceId,
|
|
6671
7236
|
workflow,
|
|
@@ -6696,12 +7261,158 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
6696
7261
|
conflicts,
|
|
6697
7262
|
unmanaged,
|
|
6698
7263
|
resourceOwners,
|
|
6699
|
-
appName
|
|
7264
|
+
appName,
|
|
7265
|
+
unchangedWorkflowJobNames
|
|
7266
|
+
};
|
|
7267
|
+
}
|
|
7268
|
+
function canTreatWorkflowAsUnchanged(existing, workflow, usedJobNames, unchangedJobFunctions) {
|
|
7269
|
+
if (!usedJobNames.every((jobName) => unchangedJobFunctions.has(jobName))) return false;
|
|
7270
|
+
return areWorkflowsEqual(existing, workflow, usedJobNames);
|
|
7271
|
+
}
|
|
7272
|
+
function areWorkflowsEqual(existing, workflow, usedJobNames) {
|
|
7273
|
+
return existing.mainJobFunctionName === workflow.mainJob.name && areNormalizedEqual(normalizeComparableExistingWorkflowRetryPolicy(existing.retryPolicy), normalizeComparableWorkflowRetryPolicy(workflow.retryPolicy)) && areNormalizedEqual(normalizeComparableWorkflowJobNames(existing.jobFunctions), normalizeComparableWorkflowJobNames(usedJobNames));
|
|
7274
|
+
}
|
|
7275
|
+
function normalizeComparableExistingWorkflowRetryPolicy(policy) {
|
|
7276
|
+
if (!policy) return;
|
|
7277
|
+
return normalizeRetryPolicyForCompare({
|
|
7278
|
+
maxRetries: policy.maxRetries ?? 0,
|
|
7279
|
+
backoffMultiplier: policy.backoffMultiplier ?? 0,
|
|
7280
|
+
initialBackoff: {
|
|
7281
|
+
seconds: policy.initialBackoff?.seconds ?? 0n,
|
|
7282
|
+
nanos: policy.initialBackoff?.nanos ?? 0
|
|
7283
|
+
},
|
|
7284
|
+
maxBackoff: {
|
|
7285
|
+
seconds: policy.maxBackoff?.seconds ?? 0n,
|
|
7286
|
+
nanos: policy.maxBackoff?.nanos ?? 0
|
|
7287
|
+
}
|
|
7288
|
+
});
|
|
7289
|
+
}
|
|
7290
|
+
function normalizeComparableWorkflowRetryPolicy(policy) {
|
|
7291
|
+
if (!policy) return;
|
|
7292
|
+
return normalizeRetryPolicyForCompare({
|
|
7293
|
+
maxRetries: policy.maxRetries,
|
|
7294
|
+
backoffMultiplier: policy.backoffMultiplier,
|
|
7295
|
+
initialBackoff: parseDurationToProto(policy.initialBackoff),
|
|
7296
|
+
maxBackoff: parseDurationToProto(policy.maxBackoff)
|
|
7297
|
+
});
|
|
7298
|
+
}
|
|
7299
|
+
function normalizeComparableWorkflowJobNames(jobFunctions) {
|
|
7300
|
+
return Array.isArray(jobFunctions) ? [...jobFunctions].sort() : Object.keys(jobFunctions ?? {}).sort();
|
|
7301
|
+
}
|
|
7302
|
+
function normalizeRetryPolicyForCompare(policy) {
|
|
7303
|
+
return {
|
|
7304
|
+
maxRetries: policy.maxRetries,
|
|
7305
|
+
backoffMultiplier: policy.backoffMultiplier,
|
|
7306
|
+
initialBackoff: {
|
|
7307
|
+
seconds: String(policy.initialBackoff.seconds),
|
|
7308
|
+
nanos: policy.initialBackoff.nanos
|
|
7309
|
+
},
|
|
7310
|
+
maxBackoff: {
|
|
7311
|
+
seconds: String(policy.maxBackoff.seconds),
|
|
7312
|
+
nanos: policy.maxBackoff.nanos
|
|
7313
|
+
}
|
|
6700
7314
|
};
|
|
6701
7315
|
}
|
|
6702
7316
|
|
|
6703
7317
|
//#endregion
|
|
6704
7318
|
//#region src/cli/commands/apply/apply.ts
|
|
7319
|
+
function applicationTrn(workspaceId, name) {
|
|
7320
|
+
return `trn:v1:workspace:${workspaceId}:application:${name}`;
|
|
7321
|
+
}
|
|
7322
|
+
function functionRegistryTrn(workspaceId, name) {
|
|
7323
|
+
return `trn:v1:workspace:${workspaceId}:function_registry:${name}`;
|
|
7324
|
+
}
|
|
7325
|
+
function pipelineTrn(workspaceId, name) {
|
|
7326
|
+
return `trn:v1:workspace:${workspaceId}:pipeline:${name}`;
|
|
7327
|
+
}
|
|
7328
|
+
function idpTrn(workspaceId, name) {
|
|
7329
|
+
return `trn:v1:workspace:${workspaceId}:idp:${name}`;
|
|
7330
|
+
}
|
|
7331
|
+
function authTrn(workspaceId, name) {
|
|
7332
|
+
return `trn:v1:workspace:${workspaceId}:auth:${name}`;
|
|
7333
|
+
}
|
|
7334
|
+
function executorTrn(workspaceId, name) {
|
|
7335
|
+
return `trn:v1:workspace:${workspaceId}:executor:${name}`;
|
|
7336
|
+
}
|
|
7337
|
+
function workflowTrn(workspaceId, name) {
|
|
7338
|
+
return `trn:v1:workspace:${workspaceId}:workflow:${name}`;
|
|
7339
|
+
}
|
|
7340
|
+
function staticWebsiteTrn(workspaceId, name) {
|
|
7341
|
+
return `trn:v1:workspace:${workspaceId}:staticwebsite:${name}`;
|
|
7342
|
+
}
|
|
7343
|
+
function tailorDBTrn(workspaceId, name) {
|
|
7344
|
+
return `trn:v1:workspace:${workspaceId}:tailordb:${name}`;
|
|
7345
|
+
}
|
|
7346
|
+
function vaultTrn(workspaceId, name) {
|
|
7347
|
+
return `trn:v1:workspace:${workspaceId}:vault:${name}`;
|
|
7348
|
+
}
|
|
7349
|
+
async function shouldForceApplyAll(client, workspaceId, application, functionEntries) {
|
|
7350
|
+
const desiredLabels = (await buildMetaRequest(applicationTrn(workspaceId, application.name), application.name)).labels;
|
|
7351
|
+
const candidateTrns = /* @__PURE__ */ new Set();
|
|
7352
|
+
if (application.subgraphs.length > 0) candidateTrns.add(applicationTrn(workspaceId, application.name));
|
|
7353
|
+
application.staticWebsiteServices.forEach((website) => {
|
|
7354
|
+
candidateTrns.add(staticWebsiteTrn(workspaceId, website.name));
|
|
7355
|
+
});
|
|
7356
|
+
application.resolverServices.forEach((pipeline) => {
|
|
7357
|
+
candidateTrns.add(pipelineTrn(workspaceId, pipeline.namespace));
|
|
7358
|
+
});
|
|
7359
|
+
application.idpServices.forEach((idp) => {
|
|
7360
|
+
candidateTrns.add(idpTrn(workspaceId, idp.name));
|
|
7361
|
+
});
|
|
7362
|
+
if (application.authService) candidateTrns.add(authTrn(workspaceId, application.authService.config.name));
|
|
7363
|
+
Object.values(application.executorService?.executors ?? {}).forEach((executor) => {
|
|
7364
|
+
candidateTrns.add(executorTrn(workspaceId, executor.name));
|
|
7365
|
+
});
|
|
7366
|
+
Object.values(application.workflowService?.workflows ?? {}).forEach((workflow) => {
|
|
7367
|
+
candidateTrns.add(workflowTrn(workspaceId, workflow.name));
|
|
7368
|
+
});
|
|
7369
|
+
application.tailorDBServices.forEach((service) => {
|
|
7370
|
+
candidateTrns.add(tailorDBTrn(workspaceId, service.namespace));
|
|
7371
|
+
});
|
|
7372
|
+
application.secrets.forEach((vault) => {
|
|
7373
|
+
candidateTrns.add(vaultTrn(workspaceId, vault.vaultName));
|
|
7374
|
+
});
|
|
7375
|
+
functionEntries.forEach((entry) => {
|
|
7376
|
+
candidateTrns.add(functionRegistryTrn(workspaceId, entry.name));
|
|
7377
|
+
});
|
|
7378
|
+
for (const trn of candidateTrns) try {
|
|
7379
|
+
const { metadata } = await client.getMetadata({ trn });
|
|
7380
|
+
if (metadata?.labels?.["sdk-name"] !== application.name) continue;
|
|
7381
|
+
if (!hasMatchingSdkVersion(metadata.labels, desiredLabels)) return true;
|
|
7382
|
+
} catch (error) {
|
|
7383
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) continue;
|
|
7384
|
+
throw error;
|
|
7385
|
+
}
|
|
7386
|
+
return false;
|
|
7387
|
+
}
|
|
7388
|
+
function printPlanSummary(results) {
|
|
7389
|
+
const summary = summarizeChangeSets([
|
|
7390
|
+
results.functionRegistry.changeSet,
|
|
7391
|
+
results.tailorDB.changeSet.service,
|
|
7392
|
+
results.tailorDB.changeSet.type,
|
|
7393
|
+
results.tailorDB.changeSet.gqlPermission,
|
|
7394
|
+
results.staticWebsite.changeSet,
|
|
7395
|
+
results.idp.changeSet.service,
|
|
7396
|
+
results.idp.changeSet.client,
|
|
7397
|
+
results.auth.changeSet.service,
|
|
7398
|
+
results.auth.changeSet.idpConfig,
|
|
7399
|
+
results.auth.changeSet.userProfileConfig,
|
|
7400
|
+
results.auth.changeSet.tenantConfig,
|
|
7401
|
+
results.auth.changeSet.machineUser,
|
|
7402
|
+
results.auth.changeSet.oauth2Client,
|
|
7403
|
+
results.auth.changeSet.authHook,
|
|
7404
|
+
results.auth.changeSet.scim,
|
|
7405
|
+
results.auth.changeSet.scimResource,
|
|
7406
|
+
results.pipeline.changeSet.service,
|
|
7407
|
+
results.pipeline.changeSet.resolver,
|
|
7408
|
+
results.app,
|
|
7409
|
+
results.executor.changeSet,
|
|
7410
|
+
results.workflow.changeSet,
|
|
7411
|
+
results.secretManager.vaultChangeSet,
|
|
7412
|
+
results.secretManager.secretChangeSet
|
|
7413
|
+
]);
|
|
7414
|
+
logger.log(formatPlanSummary(summary));
|
|
7415
|
+
}
|
|
6705
7416
|
/**
|
|
6706
7417
|
* Apply the configured application to the Tailor platform.
|
|
6707
7418
|
* @param options - Options for apply execution
|
|
@@ -6775,9 +7486,10 @@ async function apply(options) {
|
|
|
6775
7486
|
rootSpan.setAttribute("app.name", application.name);
|
|
6776
7487
|
rootSpan.setAttribute("workspace.id", workspaceId);
|
|
6777
7488
|
const workflowService = application.workflowService;
|
|
6778
|
-
const functionEntries = collectFunctionEntries(application, workflowService?.jobs ?? [], bundledScripts);
|
|
7489
|
+
const functionEntries = collectFunctionEntries(application, filterBundledWorkflowJobs(workflowService?.jobs ?? [], workflowBuildResult?.usedJobNames ?? []), bundledScripts);
|
|
6779
7490
|
const dryRun = options?.dryRun ?? false;
|
|
6780
7491
|
const yes = options?.yes ?? false;
|
|
7492
|
+
const forceApplyAll = await withSpan("plan.detectSdkVersionChange", () => shouldForceApplyAll(client, workspaceId, application, functionEntries));
|
|
6781
7493
|
const { functionRegistry, tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager } = await withSpan("plan", async () => {
|
|
6782
7494
|
const ctx = {
|
|
6783
7495
|
client,
|
|
@@ -6785,10 +7497,12 @@ async function apply(options) {
|
|
|
6785
7497
|
application,
|
|
6786
7498
|
forRemoval: false,
|
|
6787
7499
|
config,
|
|
6788
|
-
noSchemaCheck: options?.noSchemaCheck
|
|
7500
|
+
noSchemaCheck: options?.noSchemaCheck,
|
|
7501
|
+
forceApplyAll
|
|
6789
7502
|
};
|
|
6790
|
-
const
|
|
6791
|
-
|
|
7503
|
+
const functionRegistry = await withSpan("plan.functionRegistry", () => planFunctionRegistry(client, workspaceId, application.name, functionEntries));
|
|
7504
|
+
const unchangedWorkflowJobs = new Set(functionRegistry.changeSet.unchanged.map((entry) => entry.name).filter((name) => name.startsWith("workflow--")).map((name) => name.slice(10)));
|
|
7505
|
+
const [tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager] = await Promise.all([
|
|
6792
7506
|
withSpan("plan.tailorDB", () => planTailorDB(ctx)),
|
|
6793
7507
|
withSpan("plan.staticWebsite", () => planStaticWebsite(ctx)),
|
|
6794
7508
|
withSpan("plan.idp", () => planIdP(ctx)),
|
|
@@ -6796,7 +7510,7 @@ async function apply(options) {
|
|
|
6796
7510
|
withSpan("plan.pipeline", () => planPipeline(ctx)),
|
|
6797
7511
|
withSpan("plan.application", () => planApplication(ctx)),
|
|
6798
7512
|
withSpan("plan.executor", () => planExecutor(ctx)),
|
|
6799
|
-
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {})),
|
|
7513
|
+
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {}, unchangedWorkflowJobs)),
|
|
6800
7514
|
withSpan("plan.secretManager", () => planSecretManager(ctx))
|
|
6801
7515
|
]);
|
|
6802
7516
|
return {
|
|
@@ -6882,6 +7596,18 @@ async function apply(options) {
|
|
|
6882
7596
|
}
|
|
6883
7597
|
});
|
|
6884
7598
|
});
|
|
7599
|
+
printPlanSummary({
|
|
7600
|
+
functionRegistry,
|
|
7601
|
+
tailorDB,
|
|
7602
|
+
staticWebsite,
|
|
7603
|
+
idp,
|
|
7604
|
+
auth,
|
|
7605
|
+
pipeline,
|
|
7606
|
+
app,
|
|
7607
|
+
executor,
|
|
7608
|
+
workflow,
|
|
7609
|
+
secretManager
|
|
7610
|
+
});
|
|
6885
7611
|
if (dryRun) {
|
|
6886
7612
|
logger.info("Dry run enabled. No changes applied.");
|
|
6887
7613
|
return;
|
|
@@ -10965,7 +11691,7 @@ async function generate(options) {
|
|
|
10965
11691
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
10966
11692
|
let pluginManager;
|
|
10967
11693
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
10968
|
-
const { defineApplication } = await import("./application-
|
|
11694
|
+
const { defineApplication } = await import("./application-dnB8CQiT.mjs");
|
|
10969
11695
|
const application = defineApplication({
|
|
10970
11696
|
config,
|
|
10971
11697
|
pluginManager
|
|
@@ -13170,4 +13896,4 @@ function isDeno() {
|
|
|
13170
13896
|
|
|
13171
13897
|
//#endregion
|
|
13172
13898
|
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-
|
|
13899
|
+
//# sourceMappingURL=runtime-CDvdBV66.mjs.map
|