@tailor-platform/sdk 1.60.2 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +1 -0
- package/dist/{application-pusdxz35.mjs → application-BezXGbrU.mjs} +73 -509
- package/dist/application-BezXGbrU.mjs.map +1 -0
- package/dist/application-DSXntqnV.mjs +4 -0
- package/dist/assert-CKfwrmCV.mjs +10 -0
- package/dist/assert-CKfwrmCV.mjs.map +1 -0
- package/dist/cli/index.mjs +376 -136
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +3 -1
- package/dist/cli/lib.mjs +13 -6
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/{client-B-jRdlC_.mjs → client-C68VWo4g.mjs} +1 -1
- package/dist/{client-W5P4NYYX.mjs → client-CobIRHl-.mjs} +207 -2
- package/dist/{client-W5P4NYYX.mjs.map → client-CobIRHl-.mjs.map} +1 -1
- package/dist/configure/index.mjs +2 -2
- package/dist/{crashreport-D3DvAzdg.mjs → crashreport-BhD0y14F.mjs} +2 -2
- package/dist/{crashreport-D3DvAzdg.mjs.map → crashreport-BhD0y14F.mjs.map} +1 -1
- package/dist/{crashreport-lnVTnbB5.mjs → crashreport-D1wKBJ8N.mjs} +1 -1
- package/dist/{mock-Dpu__UeJ.mjs → mock-DMgIygjE.mjs} +3 -2
- package/dist/mock-DMgIygjE.mjs.map +1 -0
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/index.mjs +1 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/registry-D0uB0OrK.mjs.map +1 -1
- package/dist/{repl-editor-Y9QJDL0K.mjs → repl-editor-CJG3sz7A.mjs} +11 -9
- package/dist/repl-editor-CJG3sz7A.mjs.map +1 -0
- package/dist/{runtime-CZpsV8vj.mjs → runtime-C6o4hiYq.mjs} +994 -590
- package/dist/runtime-C6o4hiYq.mjs.map +1 -0
- package/dist/{schema-DYKNTu-n.mjs → schema-1msIhXwA.mjs} +12 -7
- package/dist/schema-1msIhXwA.mjs.map +1 -0
- package/dist/{seed-C0fE2sJB.mjs → seed-BH2FbrPV.mjs} +4 -3
- package/dist/seed-BH2FbrPV.mjs.map +1 -0
- package/dist/service-BHQIerYh.mjs +4 -0
- package/dist/{service-aPT0fx3y.mjs → service-DMohAx8a2.mjs} +3 -3
- package/dist/service-DMohAx8a2.mjs.map +1 -0
- package/dist/service-wI3Hvrgx.mjs +460 -0
- package/dist/service-wI3Hvrgx.mjs.map +1 -0
- package/dist/{types-Ccwchyj5.mjs → types-2Be3wSMc.mjs} +1 -1
- package/dist/{types-BwGth3a1.mjs → types-CmzfQP_m.mjs} +3 -3
- package/dist/types-CmzfQP_m.mjs.map +1 -0
- package/dist/utils/test/index.mjs +1 -1
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/index.mjs +7 -4
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/setup.mjs +1 -1
- package/docs/cli/application.md +11 -10
- package/docs/cli/tailordb.md +54 -0
- package/docs/cli-reference.md +1 -0
- package/docs/configuration.md +2 -0
- package/docs/multi-environment.md +74 -0
- package/docs/services/staticwebsite.md +2 -0
- package/docs/services/tailordb-migration.md +17 -1
- package/package.json +2 -1
- package/dist/application-D4tRNn90.mjs +0 -4
- package/dist/application-pusdxz35.mjs.map +0 -1
- package/dist/mock-Dpu__UeJ.mjs.map +0 -1
- package/dist/repl-editor-Y9QJDL0K.mjs.map +0 -1
- package/dist/runtime-CZpsV8vj.mjs.map +0 -1
- package/dist/schema-DYKNTu-n.mjs.map +0 -1
- package/dist/seed-C0fE2sJB.mjs.map +0 -1
- package/dist/service-aPT0fx3y.mjs.map +0 -1
- package/dist/types-BwGth3a1.mjs.map +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
import { t as db } from "./schema-
|
|
3
|
-
import { $ as
|
|
2
|
+
import { t as db } from "./schema-1msIhXwA.mjs";
|
|
3
|
+
import { $ as CreateExecutorExecutorRequestSchema, A as TailorDBGQLPermission_Permit, At as AuthSCIMAttribute_Type, B as UpdateSecretManagerSecretRequestSchema, Bt as Subgraph_ServiceType, C as WorkflowExecution_Status, Ct as AuthConnection_Type, D as UpdateTailorDBTypeRequestSchema, Dt as AuthOAuth2Client_ClientType, E as CreateTailorDBTypeRequestSchema, Et as AuthInvokerSchema, F as CreateStaticWebsiteRequestSchema, Ft as UserProfileProviderConfig_UserProfileProviderType, G as PipelineResolver_OperationType, H as CreatePipelineServiceRequestSchema, Ht as Condition_Operator, I as UpdateStaticWebsiteRequestSchema, It as CreateApplicationRequestSchema, J as IdPLang, K as CreateIdPServiceRequestSchema, Lt as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, M as TailorDBType_Permission_Permit, Mt as AuthSCIMConfig_AuthorizationType, N as TailorDBType_PermitAction, O as TailorDBGQLPermission_Action, Ot as AuthOAuth2Client_GrantType, P as AddCustomDomainRequestSchema, Pt as TenantProviderConfig_TenantProviderType, R as CreateSecretManagerSecretRequestSchema, Rt as UpdateApplicationRequestSchema, S as UpdateWorkflowRequestSchema, St as UpdateUserProfileConfigRequestSchema, T as CreateTailorDBServiceRequestSchema, Tt as AuthIDPConfig_AuthType, U as UpdatePipelineResolverRequestSchema, Ut as FilterSchema, V as CreatePipelineResolverRequestSchema, Vt as ConditionSchema, W as UpdatePipelineServiceRequestSchema, Wt as PageDirection, X as IdPPermissionPermit, Y as IdPPermissionOperator, Z as FunctionExecution_Status, _ as userAgent, _t as UpdateAuthOAuth2ClientRequestSchema, a as fetchAll, at as CreateAuthHookRequestSchema, b as CreateWorkflowJobFunctionRequestSchema, bt as UpdateAuthServiceRequestSchema, ct as CreateAuthOAuth2ClientRequestSchema, dt as CreateAuthServiceRequestSchema, et as UpdateExecutorExecutorRequestSchema, f as initOperatorClient, ft as CreateTenantConfigRequestSchema, gt as UpdateAuthMachineUserRequestSchema, h as resolveStaticWebsiteUrls, ht as UpdateAuthIDPConfigRequestSchema, it as CreateAuthConnectionRequestSchema, j as TailorDBType_Permission_Operator, jt as AuthSCIMAttribute_Uniqueness, k as TailorDBGQLPermission_Operator, kt as AuthSCIMAttribute_Mutability, lt as CreateAuthSCIMConfigRequestSchema, m as platformBaseUrl, mt as UpdateAuthHookRequestSchema, nt as ExecutorTargetType, o as fetchMachineUserToken, ot as CreateAuthIDPConfigRequestSchema, pt as CreateUserProfileConfigRequestSchema, q as UpdateIdPServiceRequestSchema, rt as ExecutorTriggerType, s as fetchPaged, st as CreateAuthMachineUserRequestSchema, tt as ExecutorJobStatus, ut as CreateAuthSCIMResourceRequestSchema, v as OperatorService, vt as UpdateAuthSCIMConfigRequestSchema, w as WorkflowJobExecution_Status, wt as AuthHookPoint, x as CreateWorkflowRequestSchema, xt as UpdateTenantConfigRequestSchema, y as WorkspacePlatformUserRole, yt as UpdateAuthSCIMResourceRequestSchema, z as CreateSecretManagerVaultRequestSchema, zt as ApplicationSchemaUpdateAttemptStatus } from "./client-CobIRHl-.mjs";
|
|
4
|
+
import { t as assertDefined } from "./assert-CKfwrmCV.mjs";
|
|
4
5
|
import { a as parseBoolean, i as symbols, n as logger, r as styles, t as CIPromptError } from "./logger-DpJyJvNz.mjs";
|
|
5
|
-
import {
|
|
6
|
+
import { C as loadConfig, D as loadConfigPath, E as loadAccessToken, M as writePlatformConfig, O as loadWorkspaceId, S as hashFile, b as getDistDir, d as assertUniqueLocalTailorDBTypeNames, f as assertUniqueTailorDBTypeNamesWithExternal, h as platformBundleDefinePlugin, k as readPlatformConfig, l as buildExecutorArgsExpr, m as stringifyFunction, n as generatePluginFilesIfNeeded, p as TailorDBTypeSchema, r as loadApplication, s as HTTP_METHODS, t as defineApplication, u as buildResolverOperationHookExpr, y as createBundleCache } from "./application-BezXGbrU.mjs";
|
|
7
|
+
import { o as loadFilesWithIgnores, t as createExecutorService } from "./service-wI3Hvrgx.mjs";
|
|
6
8
|
import { t as multiline } from "./multiline-Cf9ODpr1.mjs";
|
|
7
9
|
import { t as readPackageJson } from "./package-json-DcQApfPQ.mjs";
|
|
8
10
|
import { n as isCLIError, t as createCLIError } from "./errors-EsY4XO6O.mjs";
|
|
@@ -33,6 +35,9 @@ import * as fs from "node:fs/promises";
|
|
|
33
35
|
import { glob } from "node:fs/promises";
|
|
34
36
|
import { parseSync } from "oxc-parser";
|
|
35
37
|
import * as inflection from "inflection";
|
|
38
|
+
import pLimit from "p-limit";
|
|
39
|
+
import { pathToString } from "@bufbuild/protobuf/reflect";
|
|
40
|
+
import { createValidator } from "@bufbuild/protovalidate";
|
|
36
41
|
import { setTimeout as setTimeout$1 } from "timers/promises";
|
|
37
42
|
import { spawn } from "node:child_process";
|
|
38
43
|
import { watch } from "chokidar";
|
|
@@ -54,7 +59,9 @@ const durationPattern = /^(\d+)(ms|s|m)$/;
|
|
|
54
59
|
*/
|
|
55
60
|
const durationArg = z.string().refine((val) => durationPattern.test(val), { message: "Invalid duration format. Expected format: '3s', '500ms', '1m'" }).refine((val) => {
|
|
56
61
|
const match = val.match(durationPattern);
|
|
57
|
-
|
|
62
|
+
if (!match) return false;
|
|
63
|
+
const digits = match[1];
|
|
64
|
+
return digits !== void 0 && parseInt(digits, 10) > 0;
|
|
58
65
|
}, { message: "Duration must be greater than 0" });
|
|
59
66
|
/**
|
|
60
67
|
* Parse a validated duration string into milliseconds
|
|
@@ -62,8 +69,8 @@ const durationArg = z.string().refine((val) => durationPattern.test(val), { mess
|
|
|
62
69
|
* @returns Duration in milliseconds
|
|
63
70
|
*/
|
|
64
71
|
function parseDuration(duration) {
|
|
65
|
-
const match = duration.match(durationPattern);
|
|
66
|
-
return parseInt(match[1], 10) * unitToMs[match[2]];
|
|
72
|
+
const match = assertDefined(duration.match(durationPattern), `invalid duration format: ${duration}`);
|
|
73
|
+
return parseInt(assertDefined(match[1], "duration digits group missing"), 10) * unitToMs[assertDefined(match[2], "duration unit group missing")];
|
|
67
74
|
}
|
|
68
75
|
/**
|
|
69
76
|
* Schema for positive integer validation (from string input)
|
|
@@ -308,10 +315,7 @@ async function assertWritable(opts) {
|
|
|
308
315
|
* @returns Response status and data
|
|
309
316
|
*/
|
|
310
317
|
async function apiCall(options) {
|
|
311
|
-
const accessToken = await loadAccessToken({
|
|
312
|
-
useProfile: true,
|
|
313
|
-
profile: options.profile
|
|
314
|
-
});
|
|
318
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
315
319
|
let endpointPath;
|
|
316
320
|
if (options.endpoint.includes("/")) endpointPath = options.endpoint;
|
|
317
321
|
else endpointPath = `tailor.v1.OperatorService/${options.endpoint}`;
|
|
@@ -650,7 +654,7 @@ const listCommand$10 = defineAppCommand({
|
|
|
650
654
|
function resolveNamespaceName(methodName, config) {
|
|
651
655
|
if (/Auth|Tenant|UserProfile/.test(methodName)) return config.auth?.name;
|
|
652
656
|
if (/IdP/.test(methodName)) {
|
|
653
|
-
if (config.idp?.length === 1) return config.idp[0].name;
|
|
657
|
+
if (config.idp?.length === 1) return assertDefined(config.idp[0], "idp config missing").name;
|
|
654
658
|
return;
|
|
655
659
|
}
|
|
656
660
|
if (/TailorDB/.test(methodName)) {
|
|
@@ -691,12 +695,12 @@ function parseBodyAsObject(body) {
|
|
|
691
695
|
function setNestedPath(obj, path, value) {
|
|
692
696
|
let cursor = obj;
|
|
693
697
|
for (let i = 0; i < path.length - 1; i++) {
|
|
694
|
-
const key = path[i];
|
|
698
|
+
const key = assertDefined(path[i], "path segment missing");
|
|
695
699
|
const next = cursor[key];
|
|
696
700
|
if (typeof next !== "object" || next === null || Array.isArray(next)) cursor[key] = {};
|
|
697
701
|
cursor = cursor[key];
|
|
698
702
|
}
|
|
699
|
-
cursor[path[path.length - 1]] = value;
|
|
703
|
+
cursor[assertDefined(path[path.length - 1], "path last segment missing")] = value;
|
|
700
704
|
}
|
|
701
705
|
/**
|
|
702
706
|
* Coerces a raw `--field` string value to match the leaf proto type so the
|
|
@@ -1321,7 +1325,7 @@ var PluginManager = class {
|
|
|
1321
1325
|
};
|
|
1322
1326
|
}
|
|
1323
1327
|
if (output.types && Object.keys(output.types).length > 0) {
|
|
1324
|
-
const importPath = plugin.importPath;
|
|
1328
|
+
const importPath = assertDefined(plugin.importPath, `plugin "${plugin.id}" missing importPath`);
|
|
1325
1329
|
for (const [kind, type] of Object.entries(output.types)) this.generatedTypes.push({
|
|
1326
1330
|
pluginId: context.pluginId,
|
|
1327
1331
|
pluginImportPath: importPath,
|
|
@@ -1384,7 +1388,7 @@ var PluginManager = class {
|
|
|
1384
1388
|
});
|
|
1385
1389
|
}
|
|
1386
1390
|
if (output.types && Object.keys(output.types).length > 0) {
|
|
1387
|
-
const importPath = plugin.importPath;
|
|
1391
|
+
const importPath = assertDefined(plugin.importPath, `plugin "${plugin.id}" missing importPath`);
|
|
1388
1392
|
for (const [kind, type] of Object.entries(output.types)) {
|
|
1389
1393
|
const typeKey = `${pluginId}:${kind}:${type.name}`;
|
|
1390
1394
|
if (this.namespaceGeneratedTypeKeys.has(typeKey)) continue;
|
|
@@ -1593,13 +1597,13 @@ function copyMetadataToExtendedType(original, extended) {
|
|
|
1593
1597
|
let result = extended;
|
|
1594
1598
|
if (original._description) result = result.description(original._description);
|
|
1595
1599
|
const metadata = original.metadata;
|
|
1596
|
-
if (
|
|
1600
|
+
if (Object.keys(metadata.files).length > 0) result = result.files(metadata.files);
|
|
1597
1601
|
if (metadata.settings) {
|
|
1598
1602
|
const { pluralForm: _pluralForm, ...features } = metadata.settings;
|
|
1599
1603
|
if (Object.keys(features).length > 0) result = result.features(features);
|
|
1600
1604
|
}
|
|
1601
|
-
if (metadata.permissions
|
|
1602
|
-
if (metadata.permissions
|
|
1605
|
+
if (metadata.permissions.record) result = result.permission(metadata.permissions.record);
|
|
1606
|
+
if (metadata.permissions.gql) result = result.gqlPermission(metadata.permissions.gql);
|
|
1603
1607
|
if (metadata.indexes && Object.keys(metadata.indexes).length > 0) {
|
|
1604
1608
|
const indexDefs = Object.entries(metadata.indexes).map(([name, def]) => ({
|
|
1605
1609
|
name,
|
|
@@ -1608,7 +1612,7 @@ function copyMetadataToExtendedType(original, extended) {
|
|
|
1608
1612
|
}));
|
|
1609
1613
|
result = result.indexes(...indexDefs);
|
|
1610
1614
|
}
|
|
1611
|
-
if (original.plugins
|
|
1615
|
+
if (original.plugins.length > 0) for (const plugin of original.plugins) result = result.plugin({ [plugin.pluginId]: plugin.config });
|
|
1612
1616
|
return result;
|
|
1613
1617
|
}
|
|
1614
1618
|
|
|
@@ -1815,15 +1819,15 @@ async function applyApplication(client, changeSet, phase = "create-update") {
|
|
|
1815
1819
|
if (phase === "create-update") {
|
|
1816
1820
|
const updates = [...changeSet.updates, ...changeSet.unchanged];
|
|
1817
1821
|
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
1818
|
-
create.request.cors = await resolveStaticWebsiteUrls(client, create.request.workspaceId, create.request.cors, "CORS");
|
|
1822
|
+
create.request.cors = await resolveStaticWebsiteUrls(client, assertDefined(create.request.workspaceId, "request missing workspaceId"), create.request.cors, "CORS");
|
|
1819
1823
|
await client.createApplication(create.request);
|
|
1820
1824
|
await client.setMetadata(create.metaRequest);
|
|
1821
1825
|
}), ...updates.map(async (update) => {
|
|
1822
|
-
update.request.cors = await resolveStaticWebsiteUrls(client, update.request.workspaceId, update.request.cors, "CORS");
|
|
1826
|
+
update.request.cors = await resolveStaticWebsiteUrls(client, assertDefined(update.request.workspaceId, "request missing workspaceId"), update.request.cors, "CORS");
|
|
1823
1827
|
await client.updateApplication(update.request);
|
|
1824
1828
|
await client.setMetadata(update.metaRequest);
|
|
1825
1829
|
})]);
|
|
1826
|
-
} else
|
|
1830
|
+
} else await Promise.all(changeSet.deletes.map(async (del) => {
|
|
1827
1831
|
await client.deleteApplication(del.request);
|
|
1828
1832
|
}));
|
|
1829
1833
|
}
|
|
@@ -1832,7 +1836,7 @@ function sortStrings(values) {
|
|
|
1832
1836
|
}
|
|
1833
1837
|
function normalizeSubgraphs(subgraphs) {
|
|
1834
1838
|
return [...subgraphs ?? []].map((subgraph) => ({
|
|
1835
|
-
serviceType: subgraph.serviceType,
|
|
1839
|
+
serviceType: assertDefined(subgraph.serviceType, "subgraph missing serviceType"),
|
|
1836
1840
|
serviceNamespace: subgraph.serviceNamespace ?? ""
|
|
1837
1841
|
})).toSorted((left, right) => {
|
|
1838
1842
|
if (left.serviceType !== right.serviceType) return left.serviceType - right.serviceType;
|
|
@@ -1928,7 +1932,7 @@ async function planApplication(context, httpAdapterBuildResult) {
|
|
|
1928
1932
|
if (application.subgraphs.length === 0) return changeSet;
|
|
1929
1933
|
let authNamespace;
|
|
1930
1934
|
let authIdpConfigName;
|
|
1931
|
-
if (application.authService
|
|
1935
|
+
if (application.authService) {
|
|
1932
1936
|
authNamespace = application.authService.config.name;
|
|
1933
1937
|
const idProvider = application.authService.config.idProvider;
|
|
1934
1938
|
if (idProvider) authIdpConfigName = idProvider.name;
|
|
@@ -1938,7 +1942,7 @@ async function planApplication(context, httpAdapterBuildResult) {
|
|
|
1938
1942
|
try {
|
|
1939
1943
|
const { idpConfigs, nextPageToken } = await client.listAuthIDPConfigs({
|
|
1940
1944
|
workspaceId,
|
|
1941
|
-
namespaceName: authNamespace,
|
|
1945
|
+
namespaceName: assertDefined(authNamespace, "authNamespace must be set before listing IDP configs"),
|
|
1942
1946
|
pageToken,
|
|
1943
1947
|
pageSize: maxPageSize
|
|
1944
1948
|
});
|
|
@@ -1948,7 +1952,10 @@ async function planApplication(context, httpAdapterBuildResult) {
|
|
|
1948
1952
|
throw error;
|
|
1949
1953
|
}
|
|
1950
1954
|
});
|
|
1951
|
-
if (idpConfigs.length > 0)
|
|
1955
|
+
if (idpConfigs.length > 0) {
|
|
1956
|
+
const [firstConfig] = idpConfigs;
|
|
1957
|
+
if (firstConfig) authIdpConfigName = firstConfig.name;
|
|
1958
|
+
}
|
|
1952
1959
|
}
|
|
1953
1960
|
const metaRequest = await buildMetaRequest({
|
|
1954
1961
|
trn: resourceTrn(workspaceId, "application", application.name),
|
|
@@ -2191,7 +2198,7 @@ async function planAuthConnections(client, workspaceId, appName, appId, auths) {
|
|
|
2191
2198
|
const unmanaged = [];
|
|
2192
2199
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
2193
2200
|
const desiredConnections = {};
|
|
2194
|
-
for (const auth of auths)
|
|
2201
|
+
for (const auth of auths) for (const [name, config] of Object.entries(auth.connections)) desiredConnections[name] = config;
|
|
2195
2202
|
const existingList = await fetchAll(async (pageToken, maxPageSize) => {
|
|
2196
2203
|
try {
|
|
2197
2204
|
const { connections, nextPageToken } = await client.listAuthConnections({
|
|
@@ -2280,7 +2287,7 @@ async function planAuthConnections(client, workspaceId, appName, appId, auths) {
|
|
|
2280
2287
|
function extractOAuth2Config(connection) {
|
|
2281
2288
|
if (!connection) return void 0;
|
|
2282
2289
|
const config = connection.config;
|
|
2283
|
-
if (!config || config.case !== "oauth2"
|
|
2290
|
+
if (!config || config.case !== "oauth2") return void 0;
|
|
2284
2291
|
const v = config.value;
|
|
2285
2292
|
return {
|
|
2286
2293
|
type: "oauth2",
|
|
@@ -2324,7 +2331,7 @@ async function applyAuthConnections(client, result, phase) {
|
|
|
2324
2331
|
if (oauth2) state.connections[replace.name] = hashConnectionConfig(oauth2);
|
|
2325
2332
|
}
|
|
2326
2333
|
saveSecretsState(state);
|
|
2327
|
-
} else
|
|
2334
|
+
} else {
|
|
2328
2335
|
await Promise.all(changeSet.deletes.map(async (del) => {
|
|
2329
2336
|
await client.deleteAuthConnection(del.request);
|
|
2330
2337
|
}));
|
|
@@ -2662,7 +2669,7 @@ async function applyFunctionRegistry(client, workspaceId, result, phase = "creat
|
|
|
2662
2669
|
await uploadFunctionScript(client, workspaceId, update.entry, false);
|
|
2663
2670
|
await client.setMetadata(update.metaRequest);
|
|
2664
2671
|
}
|
|
2665
|
-
} else
|
|
2672
|
+
} else await Promise.all(changeSet.deletes.map((del) => client.deleteFunctionRegistry({
|
|
2666
2673
|
workspaceId: del.workspaceId,
|
|
2667
2674
|
name: del.name
|
|
2668
2675
|
})));
|
|
@@ -2874,11 +2881,11 @@ function printGroupedDisplaySection(title, entries, serviceActions) {
|
|
|
2874
2881
|
namespaceOrder.push(ns);
|
|
2875
2882
|
byNamespace.set(ns, []);
|
|
2876
2883
|
}
|
|
2877
|
-
byNamespace.get(ns).push(entry);
|
|
2884
|
+
assertDefined(byNamespace.get(ns), "namespace group missing").push(entry);
|
|
2878
2885
|
}
|
|
2879
2886
|
const printedServices = /* @__PURE__ */ new Set();
|
|
2880
2887
|
for (const ns of namespaceOrder) {
|
|
2881
|
-
const group = byNamespace.get(ns);
|
|
2888
|
+
const group = assertDefined(byNamespace.get(ns), "namespace group missing");
|
|
2882
2889
|
if (ns) {
|
|
2883
2890
|
const svcAction = serviceMap.get(ns);
|
|
2884
2891
|
const prefix = svcAction ? `${ACTION_SYMBOLS[svcAction]} ` : "";
|
|
@@ -3041,8 +3048,8 @@ async function applyIdP(client, result, phase = "create-update") {
|
|
|
3041
3048
|
})]);
|
|
3042
3049
|
await Promise.all([...changeSet.client.creates.map(async (create) => {
|
|
3043
3050
|
const resp = await client.createIdPClient(create.request);
|
|
3044
|
-
const vaultName = idpClientVaultName(create.request.namespaceName, create.request.client?.name || "");
|
|
3045
|
-
const secretName = idpClientSecretName(create.request.namespaceName, create.request.client?.name || "");
|
|
3051
|
+
const vaultName = idpClientVaultName(assertDefined(create.request.namespaceName, "request missing namespaceName"), create.request.client?.name || "");
|
|
3052
|
+
const secretName = idpClientSecretName(assertDefined(create.request.namespaceName, "request missing namespaceName"), create.request.client?.name || "");
|
|
3046
3053
|
await client.createSecretManagerVault({
|
|
3047
3054
|
workspaceId: create.request.workspaceId,
|
|
3048
3055
|
secretmanagerVaultName: vaultName
|
|
@@ -3084,7 +3091,7 @@ async function applyIdP(client, result, phase = "create-update") {
|
|
|
3084
3091
|
secretmanagerVaultName: vaultName
|
|
3085
3092
|
});
|
|
3086
3093
|
}));
|
|
3087
|
-
else
|
|
3094
|
+
else await Promise.all(changeSet.service.deletes.map((del) => client.deleteIdPService(del.request)));
|
|
3088
3095
|
}
|
|
3089
3096
|
/**
|
|
3090
3097
|
* Plan IdP-related changes based on current and desired state.
|
|
@@ -3323,10 +3330,9 @@ async function planClients(client, workspaceId, idps, deletedServices, forceAppl
|
|
|
3323
3330
|
});
|
|
3324
3331
|
};
|
|
3325
3332
|
const clientsByIdp = await Promise.all(idps.map((idp) => fetchClients(idp.name)));
|
|
3326
|
-
for (
|
|
3327
|
-
const idp = idps[i];
|
|
3333
|
+
for (const [i, idp] of idps.entries()) {
|
|
3328
3334
|
const namespaceName = idp.name;
|
|
3329
|
-
const existingClients = clientsByIdp[i];
|
|
3335
|
+
const existingClients = assertDefined(clientsByIdp[i], "clientsByIdp missing entry for idp index");
|
|
3330
3336
|
const existingNameMap = /* @__PURE__ */ new Map();
|
|
3331
3337
|
existingClients.forEach((client) => {
|
|
3332
3338
|
existingNameMap.set(client.name, client.clientSecret);
|
|
@@ -3360,19 +3366,16 @@ async function planClients(client, workspaceId, idps, deletedServices, forceAppl
|
|
|
3360
3366
|
});
|
|
3361
3367
|
}
|
|
3362
3368
|
const deletedClientsByService = await Promise.all(deletedServices.map((namespaceName) => fetchClients(namespaceName)));
|
|
3363
|
-
for (
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
name: client.name
|
|
3372
|
-
}
|
|
3373
|
-
});
|
|
3369
|
+
for (const [i, namespaceName] of deletedServices.entries()) assertDefined(deletedClientsByService[i], "deletedClientsByService missing entry for service index").forEach((client) => {
|
|
3370
|
+
changeSet.deletes.push({
|
|
3371
|
+
name: client.name,
|
|
3372
|
+
request: {
|
|
3373
|
+
workspaceId,
|
|
3374
|
+
namespaceName,
|
|
3375
|
+
name: client.name
|
|
3376
|
+
}
|
|
3374
3377
|
});
|
|
3375
|
-
}
|
|
3378
|
+
});
|
|
3376
3379
|
return changeSet;
|
|
3377
3380
|
}
|
|
3378
3381
|
function convertLang(lang) {
|
|
@@ -3487,12 +3490,12 @@ async function applyAuth(client, result, phase = "create-update") {
|
|
|
3487
3490
|
await client.updateAuthService(update.request);
|
|
3488
3491
|
await client.setMetadata(update.metaRequest);
|
|
3489
3492
|
})]);
|
|
3490
|
-
|
|
3493
|
+
await applyAuthConnections(client, { changeSet: changeSet.connection }, "create-update");
|
|
3491
3494
|
await Promise.all([...changeSet.idpConfig.creates.map(async (create) => {
|
|
3492
|
-
if (create.idpConfig.kind === "BuiltInIdP") create.request.idpConfig.config = await protoBuiltinIdPConfig(client, create.request.workspaceId, create.idpConfig);
|
|
3495
|
+
if (create.idpConfig.kind === "BuiltInIdP") assertDefined(create.request.idpConfig, "request missing idpConfig").config = await protoBuiltinIdPConfig(client, assertDefined(create.request.workspaceId, "request missing workspaceId"), create.idpConfig);
|
|
3493
3496
|
return client.createAuthIDPConfig(create.request);
|
|
3494
3497
|
}), ...changeSet.idpConfig.updates.map(async (update) => {
|
|
3495
|
-
if (update.idpConfig.kind === "BuiltInIdP") update.request.idpConfig.config = await protoBuiltinIdPConfig(client, update.request.workspaceId, update.idpConfig);
|
|
3498
|
+
if (update.idpConfig.kind === "BuiltInIdP") assertDefined(update.request.idpConfig, "request missing idpConfig").config = await protoBuiltinIdPConfig(client, assertDefined(update.request.workspaceId, "request missing workspaceId"), update.idpConfig);
|
|
3496
3499
|
return client.updateAuthIDPConfig(update.request);
|
|
3497
3500
|
})]);
|
|
3498
3501
|
await Promise.all([...changeSet.userProfileConfig.creates.map((create) => client.createUserProfileConfig(create.request)), ...changeSet.userProfileConfig.updates.map((update) => client.updateUserProfileConfig(update.request))]);
|
|
@@ -3500,15 +3503,18 @@ async function applyAuth(client, result, phase = "create-update") {
|
|
|
3500
3503
|
await Promise.all([...changeSet.machineUser.creates.map((create) => client.createAuthMachineUser(create.request)), ...changeSet.machineUser.updates.map((update) => client.updateAuthMachineUser(update.request))]);
|
|
3501
3504
|
await Promise.all([...changeSet.authHook.creates.map((create) => client.createAuthHook(create.request)), ...changeSet.authHook.updates.map((update) => client.updateAuthHook(update.request))]);
|
|
3502
3505
|
await Promise.all([...changeSet.oauth2Client.creates.map(async (create) => {
|
|
3503
|
-
|
|
3506
|
+
const oauth2Client = assertDefined(create.request.oauth2Client, "request missing oauth2Client");
|
|
3507
|
+
oauth2Client.redirectUris = await resolveStaticWebsiteUrls(client, assertDefined(create.request.workspaceId, "request missing workspaceId"), oauth2Client.redirectUris, "OAuth2 redirect URIs");
|
|
3504
3508
|
return client.createAuthOAuth2Client(create.request);
|
|
3505
3509
|
}), ...changeSet.oauth2Client.updates.map(async (update) => {
|
|
3506
|
-
|
|
3510
|
+
const oauth2Client = assertDefined(update.request.oauth2Client, "request missing oauth2Client");
|
|
3511
|
+
oauth2Client.redirectUris = await resolveStaticWebsiteUrls(client, assertDefined(update.request.workspaceId, "request missing workspaceId"), oauth2Client.redirectUris, "OAuth2 redirect URIs");
|
|
3507
3512
|
return client.updateAuthOAuth2Client(update.request);
|
|
3508
3513
|
})]);
|
|
3509
3514
|
for (const replace of changeSet.oauth2Client.replaces) {
|
|
3510
3515
|
await client.deleteAuthOAuth2Client(replace.deleteRequest);
|
|
3511
|
-
|
|
3516
|
+
const replaceOauth2Client = assertDefined(replace.createRequest.oauth2Client, "createRequest missing oauth2Client");
|
|
3517
|
+
replaceOauth2Client.redirectUris = await resolveStaticWebsiteUrls(client, assertDefined(replace.createRequest.workspaceId, "createRequest missing workspaceId"), replaceOauth2Client.redirectUris, "OAuth2 redirect URIs");
|
|
3512
3518
|
await client.createAuthOAuth2Client(replace.createRequest);
|
|
3513
3519
|
}
|
|
3514
3520
|
await Promise.all([...changeSet.scim.creates.map((create) => client.createAuthSCIMConfig(create.request)), ...changeSet.scim.updates.map((update) => client.updateAuthSCIMConfig(update.request))]);
|
|
@@ -3522,8 +3528,8 @@ async function applyAuth(client, result, phase = "create-update") {
|
|
|
3522
3528
|
await Promise.all(changeSet.tenantConfig.deletes.map((del) => client.deleteTenantConfig(del.request)));
|
|
3523
3529
|
await Promise.all(changeSet.userProfileConfig.deletes.map((del) => client.deleteUserProfileConfig(del.request)));
|
|
3524
3530
|
await Promise.all(changeSet.idpConfig.deletes.map((del) => client.deleteAuthIDPConfig(del.request)));
|
|
3525
|
-
|
|
3526
|
-
} else
|
|
3531
|
+
await applyAuthConnections(client, { changeSet: changeSet.connection }, "delete-resources");
|
|
3532
|
+
} else await Promise.all(changeSet.service.deletes.map((del) => client.deleteAuthService(del.request)));
|
|
3527
3533
|
}
|
|
3528
3534
|
/**
|
|
3529
3535
|
* Plan auth-related changes based on current and desired state.
|
|
@@ -3789,7 +3795,7 @@ function protoIdPConfig(idpConfig) {
|
|
|
3789
3795
|
config: { config: {
|
|
3790
3796
|
case: "saml",
|
|
3791
3797
|
value: {
|
|
3792
|
-
...idpConfig.metadataURL !== void 0 ? { metadataUrl: idpConfig.metadataURL } : { rawMetadata: idpConfig.rawMetadata },
|
|
3798
|
+
...idpConfig.metadataURL !== void 0 ? { metadataUrl: idpConfig.metadataURL } : { rawMetadata: assertDefined(idpConfig.rawMetadata, "SAML config missing rawMetadata") },
|
|
3793
3799
|
enableSignRequest: idpConfig.enableSignRequest,
|
|
3794
3800
|
defaultRedirectUrl: idpConfig.defaultRedirectURL
|
|
3795
3801
|
}
|
|
@@ -4191,7 +4197,7 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices, ex
|
|
|
4191
4197
|
const newOAuth2Client = protoOAuth2Client(oauth2ClientName, oauth2Client);
|
|
4192
4198
|
const resolvedRedirectUris = await resolveStaticWebsiteUrls(client, workspaceId, newOAuth2Client.redirectUris ?? [], "OAuth2 redirect URIs", { expectedLocalNames: expectedLocalWebsites });
|
|
4193
4199
|
if (existingClientsMap.has(oauth2ClientName)) {
|
|
4194
|
-
const existingClient = existingClientsMap.get(oauth2ClientName);
|
|
4200
|
+
const existingClient = assertDefined(existingClientsMap.get(oauth2ClientName), "existingClientsMap missing entry for oauth2ClientName");
|
|
4195
4201
|
if (existingClient.clientType !== newOAuth2Client.clientType) changeSet.replaces.push({
|
|
4196
4202
|
name: oauth2ClientName,
|
|
4197
4203
|
deleteRequest: {
|
|
@@ -4648,7 +4654,7 @@ async function ensureConfigId(configPath) {
|
|
|
4648
4654
|
findDefineConfigCalls(program, calls);
|
|
4649
4655
|
if (calls.length === 0) return null;
|
|
4650
4656
|
if (calls.length > 1) throw new Error(`Multiple defineConfig() calls found in ${configPath}. Only one is supported.`);
|
|
4651
|
-
const { configObj } = calls[0];
|
|
4657
|
+
const { configObj } = assertDefined(calls[0], "defineConfig call site missing");
|
|
4652
4658
|
if (!configObj) throw new Error(`defineConfig() argument must be an inline object literal in ${configPath} so the SDK can manage the 'id' field.`);
|
|
4653
4659
|
const idProp = findIdProperty(configObj);
|
|
4654
4660
|
if (idProp) {
|
|
@@ -4675,7 +4681,7 @@ const idComment = "// SDK-managed app id — do not edit, except when copying th
|
|
|
4675
4681
|
function insertIdProperty(source, configObj, id) {
|
|
4676
4682
|
const idLiteral = `id: ${JSON.stringify(id)}`;
|
|
4677
4683
|
if (configObj.properties.length > 0) {
|
|
4678
|
-
const firstProp = configObj.properties[0];
|
|
4684
|
+
const firstProp = assertDefined(configObj.properties[0], "first property missing");
|
|
4679
4685
|
const lineStart = source.lastIndexOf("\n", firstProp.start - 1) + 1;
|
|
4680
4686
|
const indent = source.slice(lineStart, firstProp.start);
|
|
4681
4687
|
const insertion = `${idComment}\n${indent}${idLiteral},\n${indent}`;
|
|
@@ -4927,7 +4933,7 @@ async function applyExecutor(client, result, phase = "create-update") {
|
|
|
4927
4933
|
await client.updateExecutorExecutor(update.request);
|
|
4928
4934
|
await client.setMetadata(update.metaRequest);
|
|
4929
4935
|
})]);
|
|
4930
|
-
else
|
|
4936
|
+
else await Promise.all(changeSet.deletes.map((del) => client.deleteExecutorExecutor(del.request)));
|
|
4931
4937
|
}
|
|
4932
4938
|
/**
|
|
4933
4939
|
* Plan executor-related changes based on current and desired state.
|
|
@@ -5042,7 +5048,7 @@ function formatExecutorChangeEntries(changeSet, executors, functionRegistryExecu
|
|
|
5042
5048
|
});
|
|
5043
5049
|
}
|
|
5044
5050
|
function normalizeComparableExecutor(executor) {
|
|
5045
|
-
const normalized = normalizeProtoConfig(executor)
|
|
5051
|
+
const normalized = normalizeProtoConfig(executor);
|
|
5046
5052
|
const webhookHeaders = normalized.targetConfig?.config?.case === "webhook" ? (normalized.targetConfig.config.value.headers ?? []).toSorted((left, right) => (left.key ?? "").localeCompare(right.key ?? "")) : void 0;
|
|
5047
5053
|
const triggerConfig = normalized.triggerConfig?.config?.case === "incomingWebhook" ? {
|
|
5048
5054
|
...normalized.triggerConfig,
|
|
@@ -5095,7 +5101,7 @@ function areExecutorsEqual(existing, desired) {
|
|
|
5095
5101
|
return areNormalizedEqual(normalizeComparableExecutor(existing), normalizeComparableExecutor(desired));
|
|
5096
5102
|
}
|
|
5097
5103
|
function resolveTailorDBNamespace(application, typeName) {
|
|
5098
|
-
for (const service of application.tailorDBServices) if (service.types
|
|
5104
|
+
for (const service of application.tailorDBServices) if (Object.hasOwn(service.types, typeName)) return service.namespace;
|
|
5099
5105
|
throw new Error(`TailorDB type "${typeName}" not found in any namespace. Available namespaces: ${application.tailorDBServices.map((s) => s.namespace).join(", ")}`);
|
|
5100
5106
|
}
|
|
5101
5107
|
function resolveResolverNamespace(application, resolverName) {
|
|
@@ -5116,7 +5122,7 @@ function resolveIdpNamespace(application, executorName, idpName) {
|
|
|
5116
5122
|
const available = application.idpServices.map((idp) => idp.name).join(", ");
|
|
5117
5123
|
throw new Error(`Executor "${executorName}" uses an idpUser trigger but the project defines multiple IdPs (${available}). Specify which IdP to subscribe to via the trigger's "idp" option.`);
|
|
5118
5124
|
}
|
|
5119
|
-
return application.idpServices[0].name;
|
|
5125
|
+
return assertDefined(application.idpServices[0], "idp service missing").name;
|
|
5120
5126
|
}
|
|
5121
5127
|
function resolveAuthNamespace(application) {
|
|
5122
5128
|
if (!application.authService) throw new Error("No Auth service configured");
|
|
@@ -5345,7 +5351,7 @@ async function applyPipeline(client, result, phase = "create-update") {
|
|
|
5345
5351
|
})]);
|
|
5346
5352
|
await Promise.all([...changeSet.resolver.creates.map((create) => client.createPipelineResolver(create.request)), ...changeSet.resolver.updates.map((update) => client.updatePipelineResolver(update.request))]);
|
|
5347
5353
|
} else if (phase === "delete-resources") await Promise.all(changeSet.resolver.deletes.map((del) => client.deletePipelineResolver(del.request)));
|
|
5348
|
-
else
|
|
5354
|
+
else await Promise.all(changeSet.service.deletes.map((del) => client.deletePipelineService(del.request)));
|
|
5349
5355
|
}
|
|
5350
5356
|
/**
|
|
5351
5357
|
* Plan resolver pipeline changes based on current and desired state.
|
|
@@ -5544,7 +5550,7 @@ function formatResolverChangeEntries(changeSet, resolverFunctionChanges) {
|
|
|
5544
5550
|
}, { getNamespace: (item) => item.request.namespaceName });
|
|
5545
5551
|
}
|
|
5546
5552
|
function normalizeComparableResolver(resolver) {
|
|
5547
|
-
const normalized = normalizeProtoConfig(resolver)
|
|
5553
|
+
const normalized = normalizeProtoConfig(resolver);
|
|
5548
5554
|
return {
|
|
5549
5555
|
name: normalized.name,
|
|
5550
5556
|
description: normalized.description ?? "",
|
|
@@ -5609,7 +5615,7 @@ function processResolver(namespace, resolver, executorUsedResolvers, env, authNa
|
|
|
5609
5615
|
}];
|
|
5610
5616
|
const typeBaseName = inflection.camelize(resolver.name);
|
|
5611
5617
|
const inputs = resolver.input ? protoFields(resolver.input, `${typeBaseName}Input`, true) : [];
|
|
5612
|
-
const response = protoFields({ "": resolver.output }, `${typeBaseName}Output`, false)[0];
|
|
5618
|
+
const response = assertDefined(protoFields({ "": resolver.output }, `${typeBaseName}Output`, false)[0], "resolver output field missing");
|
|
5613
5619
|
const resolverDescription = resolver.description || `${resolver.name} resolver`;
|
|
5614
5620
|
const outputDescription = resolver.output.metadata.description;
|
|
5615
5621
|
const combinedDescription = outputDescription ? `${resolverDescription}\n\nReturns:\n${outputDescription}` : resolverDescription;
|
|
@@ -5628,7 +5634,6 @@ function processResolver(namespace, resolver, executorUsedResolvers, env, authNa
|
|
|
5628
5634
|
};
|
|
5629
5635
|
}
|
|
5630
5636
|
function protoFields(fields, baseName, isInput) {
|
|
5631
|
-
if (!fields) return [];
|
|
5632
5637
|
return Object.entries(fields).map(([fieldName, field]) => {
|
|
5633
5638
|
let type;
|
|
5634
5639
|
const required = isInput && field.metadata.hooks?.create !== void 0 ? false : field.metadata.required ?? true;
|
|
@@ -5664,6 +5669,43 @@ function protoFields(fields, baseName, isInput) {
|
|
|
5664
5669
|
//#endregion
|
|
5665
5670
|
//#region src/cli/commands/deploy/secret-manager.ts
|
|
5666
5671
|
/**
|
|
5672
|
+
* Build the CreateSecretManagerVault request for a planned vault create.
|
|
5673
|
+
* @param create - Planned vault create
|
|
5674
|
+
* @returns Request init shape
|
|
5675
|
+
*/
|
|
5676
|
+
function vaultCreateRequest(create) {
|
|
5677
|
+
return {
|
|
5678
|
+
workspaceId: create.workspaceId,
|
|
5679
|
+
secretmanagerVaultName: create.name
|
|
5680
|
+
};
|
|
5681
|
+
}
|
|
5682
|
+
/**
|
|
5683
|
+
* Build the CreateSecretManagerSecret request for a planned secret create.
|
|
5684
|
+
* @param create - Planned secret create
|
|
5685
|
+
* @returns Request init shape
|
|
5686
|
+
*/
|
|
5687
|
+
function secretCreateRequest(create) {
|
|
5688
|
+
return {
|
|
5689
|
+
workspaceId: create.workspaceId,
|
|
5690
|
+
secretmanagerVaultName: create.vaultName,
|
|
5691
|
+
secretmanagerSecretName: create.secretName,
|
|
5692
|
+
secretmanagerSecretValue: create.value
|
|
5693
|
+
};
|
|
5694
|
+
}
|
|
5695
|
+
/**
|
|
5696
|
+
* Build the UpdateSecretManagerSecret request for a planned secret update.
|
|
5697
|
+
* @param update - Planned secret update
|
|
5698
|
+
* @returns Request init shape
|
|
5699
|
+
*/
|
|
5700
|
+
function secretUpdateRequest(update) {
|
|
5701
|
+
return {
|
|
5702
|
+
workspaceId: update.workspaceId,
|
|
5703
|
+
secretmanagerVaultName: update.vaultName,
|
|
5704
|
+
secretmanagerSecretName: update.secretName,
|
|
5705
|
+
secretmanagerSecretValue: update.value
|
|
5706
|
+
};
|
|
5707
|
+
}
|
|
5708
|
+
/**
|
|
5667
5709
|
* Plan secret manager changes based on current and desired state.
|
|
5668
5710
|
* @param context - Planning context
|
|
5669
5711
|
* @returns Planned changes for vaults and secrets
|
|
@@ -5830,10 +5872,7 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5830
5872
|
const { vaultChangeSet, secretChangeSet } = result;
|
|
5831
5873
|
if (phase === "create-update") {
|
|
5832
5874
|
await Promise.all(vaultChangeSet.creates.map(async (create) => {
|
|
5833
|
-
await client.createSecretManagerVault(
|
|
5834
|
-
workspaceId: create.workspaceId,
|
|
5835
|
-
secretmanagerVaultName: create.name
|
|
5836
|
-
});
|
|
5875
|
+
await client.createSecretManagerVault(vaultCreateRequest(create));
|
|
5837
5876
|
if (application) {
|
|
5838
5877
|
const metaRequest = await buildMetaRequest({
|
|
5839
5878
|
trn: resourceTrn(create.workspaceId, "vault", create.name),
|
|
@@ -5851,27 +5890,17 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5851
5890
|
});
|
|
5852
5891
|
await client.setMetadata(metaRequest);
|
|
5853
5892
|
}));
|
|
5854
|
-
await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret(
|
|
5855
|
-
|
|
5856
|
-
secretmanagerVaultName: create.vaultName,
|
|
5857
|
-
secretmanagerSecretName: create.secretName,
|
|
5858
|
-
secretmanagerSecretValue: create.value
|
|
5859
|
-
})));
|
|
5860
|
-
await Promise.all(secretChangeSet.updates.map((update) => client.updateSecretManagerSecret({
|
|
5861
|
-
workspaceId: update.workspaceId,
|
|
5862
|
-
secretmanagerVaultName: update.vaultName,
|
|
5863
|
-
secretmanagerSecretName: update.secretName,
|
|
5864
|
-
secretmanagerSecretValue: update.value
|
|
5865
|
-
})));
|
|
5893
|
+
await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret(secretCreateRequest(create))));
|
|
5894
|
+
await Promise.all(secretChangeSet.updates.map((update) => client.updateSecretManagerSecret(secretUpdateRequest(update))));
|
|
5866
5895
|
if (application) {
|
|
5867
5896
|
const state = loadSecretsState();
|
|
5868
5897
|
for (const vault of application.secrets) {
|
|
5869
|
-
if (!state.vaults
|
|
5870
|
-
for (const secret of vault.secrets) if (secret.value != null) state.vaults[vault.vaultName][secret.name] = hashValue(secret.value);
|
|
5898
|
+
if (!Object.hasOwn(state.vaults, vault.vaultName)) state.vaults[vault.vaultName] = {};
|
|
5899
|
+
for (const secret of vault.secrets) if (secret.value != null) assertDefined(state.vaults[vault.vaultName], "vault state entry missing")[secret.name] = hashValue(secret.value);
|
|
5871
5900
|
}
|
|
5872
5901
|
saveSecretsState(state);
|
|
5873
5902
|
}
|
|
5874
|
-
} else
|
|
5903
|
+
} else {
|
|
5875
5904
|
await Promise.all(secretChangeSet.deletes.map((del) => client.deleteSecretManagerSecret({
|
|
5876
5905
|
workspaceId: del.workspaceId,
|
|
5877
5906
|
secretmanagerVaultName: del.vaultName,
|
|
@@ -5883,9 +5912,9 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5883
5912
|
})));
|
|
5884
5913
|
if (secretChangeSet.deletes.length > 0 || vaultChangeSet.deletes.length > 0) {
|
|
5885
5914
|
const state = loadSecretsState();
|
|
5886
|
-
for (const del of secretChangeSet.deletes) if (state.vaults
|
|
5887
|
-
delete state.vaults[del.vaultName][del.secretName];
|
|
5888
|
-
if (Object.keys(state.vaults[del.vaultName]).length === 0) delete state.vaults[del.vaultName];
|
|
5915
|
+
for (const del of secretChangeSet.deletes) if (Object.hasOwn(state.vaults, del.vaultName)) {
|
|
5916
|
+
delete assertDefined(state.vaults[del.vaultName], "vault state entry missing")[del.secretName];
|
|
5917
|
+
if (Object.keys(assertDefined(state.vaults[del.vaultName], "vault state entry missing")).length === 0) delete state.vaults[del.vaultName];
|
|
5889
5918
|
}
|
|
5890
5919
|
for (const del of vaultChangeSet.deletes) delete state.vaults[del.name];
|
|
5891
5920
|
saveSecretsState(state);
|
|
@@ -5916,7 +5945,7 @@ async function applyStaticWebsite(client, result, phase = "create-update") {
|
|
|
5916
5945
|
await client.addCustomDomain(add.request);
|
|
5917
5946
|
await client.setMetadata(add.metaRequest);
|
|
5918
5947
|
}), ...customDomainChangeSet.deletes.map((del) => client.removeCustomDomain(del.request))]);
|
|
5919
|
-
} else
|
|
5948
|
+
} else await Promise.all(changeSet.deletes.map((del) => client.deleteStaticWebsite(del.request)));
|
|
5920
5949
|
}
|
|
5921
5950
|
function customDomainTrn(workspaceId, websiteName, domain) {
|
|
5922
5951
|
return `trn:v1:workspace:${workspaceId}:staticwebsite:${websiteName}:custom_domain:${domain}`;
|
|
@@ -6296,6 +6325,24 @@ function formatDiffSummary(diff) {
|
|
|
6296
6325
|
function formatMigrationNumber(num) {
|
|
6297
6326
|
return num.toString().padStart(4, "0");
|
|
6298
6327
|
}
|
|
6328
|
+
/**
|
|
6329
|
+
* Parse a migration number CLI argument.
|
|
6330
|
+
*
|
|
6331
|
+
* Accepts the canonical 4-digit form ("0001") or a bare integer without
|
|
6332
|
+
* leading zeros ("0"–"9999"). Commands that disallow the baseline reject
|
|
6333
|
+
* 0 themselves with a context-specific message.
|
|
6334
|
+
* @param numberStr - Raw CLI argument
|
|
6335
|
+
* @returns Parsed migration number
|
|
6336
|
+
*/
|
|
6337
|
+
function parseMigrationNumberArg(numberStr) {
|
|
6338
|
+
if (/^\d{4}$/.test(numberStr)) return parseInt(numberStr, 10);
|
|
6339
|
+
if (/^(0|[1-9]\d*)$/.test(numberStr)) {
|
|
6340
|
+
const parsed = parseInt(numberStr, 10);
|
|
6341
|
+
if (parsed > 9999) throw new Error(`Migration number ${numberStr} is out of range. Expected 0-9999.`);
|
|
6342
|
+
return parsed;
|
|
6343
|
+
}
|
|
6344
|
+
throw new Error(`Invalid migration number format: ${numberStr}. Expected 4-digit format (e.g., 0001) or integer 0-9999 (e.g., 1).`);
|
|
6345
|
+
}
|
|
6299
6346
|
|
|
6300
6347
|
//#endregion
|
|
6301
6348
|
//#region src/cli/commands/tailordb/migrate/snapshot-types.ts
|
|
@@ -6675,96 +6722,112 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6675
6722
|
case "type_removed":
|
|
6676
6723
|
delete types[change.typeName];
|
|
6677
6724
|
break;
|
|
6678
|
-
case "type_modified":
|
|
6679
|
-
|
|
6725
|
+
case "type_modified": {
|
|
6726
|
+
const existing = types[change.typeName];
|
|
6727
|
+
if (existing && change.after) {
|
|
6680
6728
|
const after = change.after;
|
|
6681
6729
|
types[change.typeName] = {
|
|
6682
|
-
...
|
|
6730
|
+
...existing,
|
|
6683
6731
|
...after.indexes !== void 0 && { indexes: after.indexes },
|
|
6684
6732
|
...after.files !== void 0 && { files: after.files }
|
|
6685
6733
|
};
|
|
6686
6734
|
}
|
|
6687
6735
|
break;
|
|
6736
|
+
}
|
|
6688
6737
|
case "field_added":
|
|
6689
|
-
case "field_modified":
|
|
6690
|
-
|
|
6691
|
-
|
|
6738
|
+
case "field_modified": {
|
|
6739
|
+
const existing = types[change.typeName];
|
|
6740
|
+
if (existing && change.fieldName) types[change.typeName] = {
|
|
6741
|
+
...existing,
|
|
6692
6742
|
fields: {
|
|
6693
|
-
...
|
|
6743
|
+
...existing.fields,
|
|
6694
6744
|
[change.fieldName]: change.after
|
|
6695
6745
|
}
|
|
6696
6746
|
};
|
|
6697
6747
|
break;
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6748
|
+
}
|
|
6749
|
+
case "field_removed": {
|
|
6750
|
+
const existing = types[change.typeName];
|
|
6751
|
+
if (existing && change.fieldName) {
|
|
6752
|
+
const { [change.fieldName]: _, ...remainingFields } = existing.fields;
|
|
6701
6753
|
types[change.typeName] = {
|
|
6702
|
-
...
|
|
6754
|
+
...existing,
|
|
6703
6755
|
fields: remainingFields
|
|
6704
6756
|
};
|
|
6705
6757
|
}
|
|
6706
6758
|
break;
|
|
6759
|
+
}
|
|
6707
6760
|
case "index_added":
|
|
6708
|
-
case "index_modified":
|
|
6709
|
-
|
|
6710
|
-
|
|
6761
|
+
case "index_modified": {
|
|
6762
|
+
const existing = types[change.typeName];
|
|
6763
|
+
if (existing && change.indexName) types[change.typeName] = {
|
|
6764
|
+
...existing,
|
|
6711
6765
|
indexes: {
|
|
6712
|
-
...
|
|
6766
|
+
...existing.indexes,
|
|
6713
6767
|
[change.indexName]: change.after
|
|
6714
6768
|
}
|
|
6715
6769
|
};
|
|
6716
6770
|
break;
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6771
|
+
}
|
|
6772
|
+
case "index_removed": {
|
|
6773
|
+
const existing = types[change.typeName];
|
|
6774
|
+
if (existing && change.indexName && existing.indexes) {
|
|
6775
|
+
const { [change.indexName]: _, ...remainingIndexes } = existing.indexes;
|
|
6720
6776
|
types[change.typeName] = {
|
|
6721
|
-
...
|
|
6777
|
+
...existing,
|
|
6722
6778
|
indexes: Object.keys(remainingIndexes).length > 0 ? remainingIndexes : void 0
|
|
6723
6779
|
};
|
|
6724
6780
|
}
|
|
6725
6781
|
break;
|
|
6782
|
+
}
|
|
6726
6783
|
case "file_added":
|
|
6727
|
-
case "file_modified":
|
|
6728
|
-
|
|
6729
|
-
|
|
6784
|
+
case "file_modified": {
|
|
6785
|
+
const existing = types[change.typeName];
|
|
6786
|
+
if (existing && change.fieldName) types[change.typeName] = {
|
|
6787
|
+
...existing,
|
|
6730
6788
|
files: {
|
|
6731
|
-
...
|
|
6789
|
+
...existing.files,
|
|
6732
6790
|
[change.fieldName]: change.after
|
|
6733
6791
|
}
|
|
6734
6792
|
};
|
|
6735
6793
|
break;
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6794
|
+
}
|
|
6795
|
+
case "file_removed": {
|
|
6796
|
+
const existing = types[change.typeName];
|
|
6797
|
+
if (existing && change.fieldName && existing.files) {
|
|
6798
|
+
const { [change.fieldName]: _, ...remainingFiles } = existing.files;
|
|
6739
6799
|
types[change.typeName] = {
|
|
6740
|
-
...
|
|
6800
|
+
...existing,
|
|
6741
6801
|
files: Object.keys(remainingFiles).length > 0 ? remainingFiles : void 0
|
|
6742
6802
|
};
|
|
6743
6803
|
}
|
|
6744
6804
|
break;
|
|
6805
|
+
}
|
|
6745
6806
|
case "relationship_added":
|
|
6746
|
-
case "relationship_modified":
|
|
6747
|
-
|
|
6807
|
+
case "relationship_modified": {
|
|
6808
|
+
const existing = types[change.typeName];
|
|
6809
|
+
if (existing && change.relationshipName) {
|
|
6748
6810
|
const rel = change.after;
|
|
6749
|
-
if ((change.relationshipType ?? (
|
|
6750
|
-
...
|
|
6811
|
+
if ((change.relationshipType ?? (existing.forwardRelationships?.[change.relationshipName] ? "forward" : existing.backwardRelationships?.[change.relationshipName] ? "backward" : "forward")) === "forward") types[change.typeName] = {
|
|
6812
|
+
...existing,
|
|
6751
6813
|
forwardRelationships: {
|
|
6752
|
-
...
|
|
6814
|
+
...existing.forwardRelationships,
|
|
6753
6815
|
[change.relationshipName]: rel
|
|
6754
6816
|
}
|
|
6755
6817
|
};
|
|
6756
6818
|
else types[change.typeName] = {
|
|
6757
|
-
...
|
|
6819
|
+
...existing,
|
|
6758
6820
|
backwardRelationships: {
|
|
6759
|
-
...
|
|
6821
|
+
...existing.backwardRelationships,
|
|
6760
6822
|
[change.relationshipName]: rel
|
|
6761
6823
|
}
|
|
6762
6824
|
};
|
|
6763
6825
|
}
|
|
6764
6826
|
break;
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6827
|
+
}
|
|
6828
|
+
case "relationship_removed": {
|
|
6829
|
+
const type = types[change.typeName];
|
|
6830
|
+
if (type && change.relationshipName) {
|
|
6768
6831
|
const targetType = change.relationshipType ?? (type.forwardRelationships?.[change.relationshipName] ? "forward" : type.backwardRelationships?.[change.relationshipName] ? "backward" : null);
|
|
6769
6832
|
if (targetType === "forward" && type.forwardRelationships?.[change.relationshipName]) {
|
|
6770
6833
|
const { [change.relationshipName]: _, ...remaining } = type.forwardRelationships;
|
|
@@ -6781,11 +6844,13 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6781
6844
|
}
|
|
6782
6845
|
}
|
|
6783
6846
|
break;
|
|
6784
|
-
|
|
6785
|
-
|
|
6847
|
+
}
|
|
6848
|
+
case "permission_modified": {
|
|
6849
|
+
const existing = types[change.typeName];
|
|
6850
|
+
if (existing && change.after) {
|
|
6786
6851
|
const after = change.after;
|
|
6787
6852
|
types[change.typeName] = {
|
|
6788
|
-
...
|
|
6853
|
+
...existing,
|
|
6789
6854
|
permissions: {
|
|
6790
6855
|
record: after.recordPermission,
|
|
6791
6856
|
gql: after.gqlPermission
|
|
@@ -6793,6 +6858,7 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6793
6858
|
};
|
|
6794
6859
|
}
|
|
6795
6860
|
break;
|
|
6861
|
+
}
|
|
6796
6862
|
}
|
|
6797
6863
|
return {
|
|
6798
6864
|
...snapshot,
|
|
@@ -6869,8 +6935,10 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
6869
6935
|
const newValidate = newField.validate ?? [];
|
|
6870
6936
|
if (oldValidate.length !== newValidate.length) return true;
|
|
6871
6937
|
for (let i = 0; i < oldValidate.length; i++) {
|
|
6872
|
-
|
|
6873
|
-
|
|
6938
|
+
const oldV = assertDefined(oldValidate[i], `oldValidate missing index ${i}`);
|
|
6939
|
+
const newV = assertDefined(newValidate[i], `newValidate missing index ${i}`);
|
|
6940
|
+
if (oldV.script.expr !== newV.script.expr) return true;
|
|
6941
|
+
if (oldV.errorMessage !== newV.errorMessage) return true;
|
|
6874
6942
|
}
|
|
6875
6943
|
const oldSerial = oldField.serial;
|
|
6876
6944
|
const newSerial = newField.serial;
|
|
@@ -6887,8 +6955,10 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
6887
6955
|
const newFieldNames = Object.keys(newFields);
|
|
6888
6956
|
if (oldFieldNames.length !== newFieldNames.length) return true;
|
|
6889
6957
|
for (const fieldName of oldFieldNames) {
|
|
6890
|
-
|
|
6891
|
-
|
|
6958
|
+
const oldF = oldFields[fieldName];
|
|
6959
|
+
const newF = newFields[fieldName];
|
|
6960
|
+
if (!newF) return true;
|
|
6961
|
+
if (areFieldsDifferent(assertDefined(oldF, `field "${fieldName}" missing from oldFields`), newF)) return true;
|
|
6892
6962
|
}
|
|
6893
6963
|
return false;
|
|
6894
6964
|
}
|
|
@@ -6973,22 +7043,28 @@ function addChange(ctx, change, oldField, newField) {
|
|
|
6973
7043
|
function compareTypeFields(ctx, typeName, prevType, currType) {
|
|
6974
7044
|
const prevFieldNames = new Set(Object.keys(prevType.fields));
|
|
6975
7045
|
const currFieldNames = new Set(Object.keys(currType.fields));
|
|
6976
|
-
for (const fieldName of currFieldNames) if (!prevFieldNames.has(fieldName))
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
7046
|
+
for (const fieldName of currFieldNames) if (!prevFieldNames.has(fieldName)) {
|
|
7047
|
+
const currField = assertDefined(currType.fields[fieldName], `field "${fieldName}" missing from currType`);
|
|
7048
|
+
addChange(ctx, {
|
|
7049
|
+
kind: "field_added",
|
|
7050
|
+
typeName,
|
|
7051
|
+
fieldName,
|
|
7052
|
+
after: currField
|
|
7053
|
+
}, void 0, currField);
|
|
7054
|
+
}
|
|
7055
|
+
for (const fieldName of prevFieldNames) if (!currFieldNames.has(fieldName)) {
|
|
7056
|
+
const prevField = assertDefined(prevType.fields[fieldName], `field "${fieldName}" missing from prevType`);
|
|
7057
|
+
addChange(ctx, {
|
|
7058
|
+
kind: "field_removed",
|
|
7059
|
+
typeName,
|
|
7060
|
+
fieldName,
|
|
7061
|
+
before: prevField
|
|
7062
|
+
}, prevField, void 0);
|
|
7063
|
+
}
|
|
6988
7064
|
for (const fieldName of currFieldNames) {
|
|
6989
7065
|
if (!prevFieldNames.has(fieldName)) continue;
|
|
6990
|
-
const prevField = prevType.fields[fieldName];
|
|
6991
|
-
const currField = currType.fields[fieldName];
|
|
7066
|
+
const prevField = assertDefined(prevType.fields[fieldName], `field "${fieldName}" missing from prevType`);
|
|
7067
|
+
const currField = assertDefined(currType.fields[fieldName], `field "${fieldName}" missing from currType`);
|
|
6992
7068
|
if (areFieldsDifferent(prevField, currField)) addChange(ctx, {
|
|
6993
7069
|
kind: "field_modified",
|
|
6994
7070
|
typeName,
|
|
@@ -7009,21 +7085,20 @@ function compareTypeFields(ctx, typeName, prevType, currType) {
|
|
|
7009
7085
|
function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
|
|
7010
7086
|
const oldKeys = new Set(Object.keys(oldIndexes || {}));
|
|
7011
7087
|
const newKeys = new Set(Object.keys(newIndexes || {}));
|
|
7012
|
-
for (const indexName of
|
|
7088
|
+
for (const [indexName, indexConfig] of Object.entries(newIndexes ?? {})) if (!oldKeys.has(indexName)) ctx.changes.push({
|
|
7013
7089
|
kind: "index_added",
|
|
7014
7090
|
typeName,
|
|
7015
7091
|
indexName,
|
|
7016
|
-
after:
|
|
7092
|
+
after: indexConfig
|
|
7017
7093
|
});
|
|
7018
|
-
for (const indexName of
|
|
7094
|
+
for (const [indexName, indexConfig] of Object.entries(oldIndexes ?? {})) if (!newKeys.has(indexName)) ctx.changes.push({
|
|
7019
7095
|
kind: "index_removed",
|
|
7020
7096
|
typeName,
|
|
7021
7097
|
indexName,
|
|
7022
|
-
before:
|
|
7098
|
+
before: indexConfig
|
|
7023
7099
|
});
|
|
7024
|
-
for (const indexName of
|
|
7025
|
-
const oldIndex = oldIndexes[indexName];
|
|
7026
|
-
const newIndex = newIndexes[indexName];
|
|
7100
|
+
for (const [indexName, newIndex] of Object.entries(newIndexes ?? {})) if (oldKeys.has(indexName)) {
|
|
7101
|
+
const oldIndex = assertDefined(assertDefined(oldIndexes, "oldIndexes is undefined when oldKeys has entry")[indexName], `index "${indexName}" missing from oldIndexes`);
|
|
7027
7102
|
const oldFieldsStr = JSON.stringify(oldIndex.fields.toSorted());
|
|
7028
7103
|
const newFieldsStr = JSON.stringify(newIndex.fields.toSorted());
|
|
7029
7104
|
if (oldFieldsStr !== newFieldsStr || oldIndex.unique !== newIndex.unique) {
|
|
@@ -7052,26 +7127,27 @@ function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
|
|
|
7052
7127
|
function compareFiles(ctx, typeName, oldFiles, newFiles) {
|
|
7053
7128
|
const oldKeys = new Set(Object.keys(oldFiles || {}));
|
|
7054
7129
|
const newKeys = new Set(Object.keys(newFiles || {}));
|
|
7055
|
-
for (const fileName of
|
|
7130
|
+
for (const [fileName, fileDesc] of Object.entries(newFiles ?? {})) if (!oldKeys.has(fileName)) ctx.changes.push({
|
|
7056
7131
|
kind: "file_added",
|
|
7057
7132
|
typeName,
|
|
7058
7133
|
fieldName: fileName,
|
|
7059
|
-
after:
|
|
7134
|
+
after: fileDesc
|
|
7060
7135
|
});
|
|
7061
|
-
for (const fileName of
|
|
7136
|
+
for (const [fileName, fileDesc] of Object.entries(oldFiles ?? {})) if (!newKeys.has(fileName)) ctx.changes.push({
|
|
7062
7137
|
kind: "file_removed",
|
|
7063
7138
|
typeName,
|
|
7064
7139
|
fieldName: fileName,
|
|
7065
|
-
before:
|
|
7140
|
+
before: fileDesc
|
|
7066
7141
|
});
|
|
7067
|
-
for (const fileName of
|
|
7068
|
-
|
|
7142
|
+
for (const [fileName, newDesc] of Object.entries(newFiles ?? {})) if (oldKeys.has(fileName)) {
|
|
7143
|
+
const oldDesc = assertDefined(assertDefined(oldFiles, "oldFiles is undefined when oldKeys has entry")[fileName], `file "${fileName}" missing from oldFiles`);
|
|
7144
|
+
if (oldDesc !== newDesc) ctx.changes.push({
|
|
7069
7145
|
kind: "file_modified",
|
|
7070
7146
|
typeName,
|
|
7071
7147
|
fieldName: fileName,
|
|
7072
7148
|
reason: "description changed",
|
|
7073
|
-
before:
|
|
7074
|
-
after:
|
|
7149
|
+
before: oldDesc,
|
|
7150
|
+
after: newDesc
|
|
7075
7151
|
});
|
|
7076
7152
|
}
|
|
7077
7153
|
}
|
|
@@ -7087,23 +7163,22 @@ function compareFiles(ctx, typeName, oldFiles, newFiles) {
|
|
|
7087
7163
|
function compareRelationships(ctx, typeName, relationshipType, oldRelationships, newRelationships) {
|
|
7088
7164
|
const oldKeys = new Set(Object.keys(oldRelationships || {}));
|
|
7089
7165
|
const newKeys = new Set(Object.keys(newRelationships || {}));
|
|
7090
|
-
for (const relName of
|
|
7166
|
+
for (const [relName, rel] of Object.entries(newRelationships ?? {})) if (!oldKeys.has(relName)) ctx.changes.push({
|
|
7091
7167
|
kind: "relationship_added",
|
|
7092
7168
|
typeName,
|
|
7093
7169
|
relationshipName: relName,
|
|
7094
7170
|
relationshipType,
|
|
7095
|
-
after:
|
|
7171
|
+
after: rel
|
|
7096
7172
|
});
|
|
7097
|
-
for (const relName of
|
|
7173
|
+
for (const [relName, rel] of Object.entries(oldRelationships ?? {})) if (!newKeys.has(relName)) ctx.changes.push({
|
|
7098
7174
|
kind: "relationship_removed",
|
|
7099
7175
|
typeName,
|
|
7100
7176
|
relationshipName: relName,
|
|
7101
7177
|
relationshipType,
|
|
7102
|
-
before:
|
|
7178
|
+
before: rel
|
|
7103
7179
|
});
|
|
7104
|
-
for (const relName of
|
|
7105
|
-
const oldRel = oldRelationships[relName];
|
|
7106
|
-
const newRel = newRelationships[relName];
|
|
7180
|
+
for (const [relName, newRel] of Object.entries(newRelationships ?? {})) if (oldKeys.has(relName)) {
|
|
7181
|
+
const oldRel = assertDefined(assertDefined(oldRelationships, "oldRelationships is undefined when oldKeys has entry")[relName], `relationship "${relName}" missing from oldRelationships`);
|
|
7107
7182
|
const reasons = [];
|
|
7108
7183
|
if (oldRel.targetType !== newRel.targetType) reasons.push("targetType changed");
|
|
7109
7184
|
if (oldRel.targetField !== newRel.targetField) reasons.push("targetField changed");
|
|
@@ -7168,16 +7243,16 @@ function compareSnapshots(previous, current) {
|
|
|
7168
7243
|
};
|
|
7169
7244
|
const previousTypeNames = new Set(Object.keys(previous.types));
|
|
7170
7245
|
const currentTypeNames = new Set(Object.keys(current.types));
|
|
7171
|
-
for (const typeName of
|
|
7246
|
+
for (const [typeName, type] of Object.entries(current.types)) if (!previousTypeNames.has(typeName)) ctx.changes.push({
|
|
7172
7247
|
kind: "type_added",
|
|
7173
7248
|
typeName,
|
|
7174
|
-
after:
|
|
7249
|
+
after: type
|
|
7175
7250
|
});
|
|
7176
|
-
for (const typeName of
|
|
7251
|
+
for (const [typeName, type] of Object.entries(previous.types)) if (!currentTypeNames.has(typeName)) {
|
|
7177
7252
|
ctx.changes.push({
|
|
7178
7253
|
kind: "type_removed",
|
|
7179
7254
|
typeName,
|
|
7180
|
-
before:
|
|
7255
|
+
before: type
|
|
7181
7256
|
});
|
|
7182
7257
|
ctx.warnings.push({
|
|
7183
7258
|
typeName,
|
|
@@ -7186,8 +7261,8 @@ function compareSnapshots(previous, current) {
|
|
|
7186
7261
|
}
|
|
7187
7262
|
for (const typeName of currentTypeNames) {
|
|
7188
7263
|
if (!previousTypeNames.has(typeName)) continue;
|
|
7189
|
-
const prevType = previous.types[typeName];
|
|
7190
|
-
const currType = current.types[typeName];
|
|
7264
|
+
const prevType = assertDefined(previous.types[typeName], `type "${typeName}" missing from previous snapshot`);
|
|
7265
|
+
const currType = assertDefined(current.types[typeName], `type "${typeName}" missing from current snapshot`);
|
|
7191
7266
|
compareTypeFields(ctx, typeName, prevType, currType);
|
|
7192
7267
|
compareIndexes(ctx, typeName, prevType.indexes, currType.indexes);
|
|
7193
7268
|
compareFiles(ctx, typeName, prevType.files, currType.files);
|
|
@@ -7245,7 +7320,7 @@ function validateMigrationFiles(migrationsDir) {
|
|
|
7245
7320
|
const schemaFiles = [];
|
|
7246
7321
|
const diffFiles = [];
|
|
7247
7322
|
for (const file of migrationFiles) if (file.type === "schema") schemaFiles.push(file.number);
|
|
7248
|
-
else
|
|
7323
|
+
else diffFiles.push(file.number);
|
|
7249
7324
|
if (!schemaFiles.includes(0)) errors.push({
|
|
7250
7325
|
type: "missing_schema",
|
|
7251
7326
|
message: `Initial schema snapshot (${formatMigrationNumber(0)}/schema.json) is missing`,
|
|
@@ -7414,8 +7489,8 @@ function compareRemoteWithSnapshot(remoteTypes, snapshot) {
|
|
|
7414
7489
|
});
|
|
7415
7490
|
for (const typeName of snapshotTypeNames) {
|
|
7416
7491
|
if (!remoteTypeNames.has(typeName)) continue;
|
|
7417
|
-
const remoteType = remoteTypeMap.get(typeName);
|
|
7418
|
-
const snapshotType = snapshot.types[typeName];
|
|
7492
|
+
const remoteType = assertDefined(remoteTypeMap.get(typeName), `type "${typeName}" missing from remoteTypeMap`);
|
|
7493
|
+
const snapshotType = assertDefined(snapshot.types[typeName], `type "${typeName}" missing from snapshot`);
|
|
7419
7494
|
const remoteFields = convertRemoteFieldsToSnapshot(remoteType);
|
|
7420
7495
|
const snapshotFields = snapshotType.fields;
|
|
7421
7496
|
const remoteFieldNames = new Set(Object.keys(remoteFields).filter((f) => !SYSTEM_FIELDS.has(f)));
|
|
@@ -7434,7 +7509,7 @@ function compareRemoteWithSnapshot(remoteTypes, snapshot) {
|
|
|
7434
7509
|
});
|
|
7435
7510
|
for (const fieldName of snapshotFieldNames) {
|
|
7436
7511
|
if (!remoteFieldNames.has(fieldName)) continue;
|
|
7437
|
-
const drift = compareFields(typeName, fieldName, remoteFields[fieldName], snapshotFields[fieldName]);
|
|
7512
|
+
const drift = compareFields(typeName, fieldName, assertDefined(remoteFields[fieldName], `field "${fieldName}" missing from remoteFields`), assertDefined(snapshotFields[fieldName], `field "${fieldName}" missing from snapshotFields`));
|
|
7438
7513
|
if (drift) drifts.push(drift);
|
|
7439
7514
|
}
|
|
7440
7515
|
}
|
|
@@ -7752,6 +7827,145 @@ function convertOperandToProto(operand) {
|
|
|
7752
7827
|
value: fromJson(ValueSchema, operand)
|
|
7753
7828
|
} };
|
|
7754
7829
|
}
|
|
7830
|
+
/**
|
|
7831
|
+
* Generate all TailorDB type manifests from a schema snapshot
|
|
7832
|
+
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
7833
|
+
* @param {GenerateAllManifestsOptions} options - Generation options
|
|
7834
|
+
* @returns {Map<string, MessageInitShape<typeof TailorDBTypeSchema>>} Map of type name to manifest
|
|
7835
|
+
*/
|
|
7836
|
+
function generateAllTypeManifestsFromSnapshot(snapshot, options = {}) {
|
|
7837
|
+
const manifests = /* @__PURE__ */ new Map();
|
|
7838
|
+
const { executorUsedTypes, ...baseOptions } = options;
|
|
7839
|
+
for (const [typeName, snapshotType] of Object.entries(snapshot.types)) {
|
|
7840
|
+
if (executorUsedTypes?.has(typeName) && snapshotType.settings?.publishEvents === false) throw new Error(`Type "${typeName}" has publishEvents set to false, but it is used by an executor with a record trigger. Either remove the publishEvents: false setting or remove the executor trigger for this type.`);
|
|
7841
|
+
let publishRecordEvents;
|
|
7842
|
+
if (snapshotType.settings?.publishEvents !== void 0) publishRecordEvents = snapshotType.settings.publishEvents;
|
|
7843
|
+
else if (executorUsedTypes?.has(typeName)) publishRecordEvents = true;
|
|
7844
|
+
else publishRecordEvents = baseOptions.publishRecordEvents ?? false;
|
|
7845
|
+
const typeOptions = {
|
|
7846
|
+
...baseOptions,
|
|
7847
|
+
publishRecordEvents
|
|
7848
|
+
};
|
|
7849
|
+
manifests.set(typeName, generateTailorDBTypeManifestFromSnapshot(snapshotType, typeOptions));
|
|
7850
|
+
}
|
|
7851
|
+
return manifests;
|
|
7852
|
+
}
|
|
7853
|
+
/**
|
|
7854
|
+
* Compare snapshot types with existing remote type names
|
|
7855
|
+
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
7856
|
+
* @param {ReadonlySet<string>} existingTypeNames - Set of existing type names in remote
|
|
7857
|
+
* @returns {SnapshotTypeComparison} Comparison result
|
|
7858
|
+
*/
|
|
7859
|
+
function compareSnapshotWithRemote(snapshot, existingTypeNames) {
|
|
7860
|
+
const snapshotTypeNames = new Set(Object.keys(snapshot.types));
|
|
7861
|
+
const creates = [];
|
|
7862
|
+
const updates = [];
|
|
7863
|
+
const deletes = [];
|
|
7864
|
+
for (const typeName of snapshotTypeNames) if (existingTypeNames.has(typeName)) updates.push(typeName);
|
|
7865
|
+
else creates.push(typeName);
|
|
7866
|
+
for (const typeName of existingTypeNames) if (!snapshotTypeNames.has(typeName)) deletes.push(typeName);
|
|
7867
|
+
return {
|
|
7868
|
+
creates,
|
|
7869
|
+
updates,
|
|
7870
|
+
deletes
|
|
7871
|
+
};
|
|
7872
|
+
}
|
|
7873
|
+
/**
|
|
7874
|
+
* Convert snapshot GQL permission policies to the proto request shape.
|
|
7875
|
+
* @param permission - Snapshot GQL permission policies
|
|
7876
|
+
* @returns Proto GQL permission
|
|
7877
|
+
*/
|
|
7878
|
+
function protoGqlPermission(permission) {
|
|
7879
|
+
return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
|
|
7880
|
+
}
|
|
7881
|
+
function protoGqlPolicy(policy) {
|
|
7882
|
+
const actions = [];
|
|
7883
|
+
for (const action of policy.actions) switch (action) {
|
|
7884
|
+
case "all":
|
|
7885
|
+
actions.push(TailorDBGQLPermission_Action.ALL);
|
|
7886
|
+
break;
|
|
7887
|
+
case "create":
|
|
7888
|
+
actions.push(TailorDBGQLPermission_Action.CREATE);
|
|
7889
|
+
break;
|
|
7890
|
+
case "read":
|
|
7891
|
+
actions.push(TailorDBGQLPermission_Action.READ);
|
|
7892
|
+
break;
|
|
7893
|
+
case "update":
|
|
7894
|
+
actions.push(TailorDBGQLPermission_Action.UPDATE);
|
|
7895
|
+
break;
|
|
7896
|
+
case "delete":
|
|
7897
|
+
actions.push(TailorDBGQLPermission_Action.DELETE);
|
|
7898
|
+
break;
|
|
7899
|
+
case "aggregate":
|
|
7900
|
+
actions.push(TailorDBGQLPermission_Action.AGGREGATE);
|
|
7901
|
+
break;
|
|
7902
|
+
case "bulkUpsert":
|
|
7903
|
+
actions.push(TailorDBGQLPermission_Action.BULK_UPSERT);
|
|
7904
|
+
break;
|
|
7905
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
7906
|
+
}
|
|
7907
|
+
let permit;
|
|
7908
|
+
switch (policy.permit) {
|
|
7909
|
+
case "allow":
|
|
7910
|
+
permit = TailorDBGQLPermission_Permit.ALLOW;
|
|
7911
|
+
break;
|
|
7912
|
+
case "deny":
|
|
7913
|
+
permit = TailorDBGQLPermission_Permit.DENY;
|
|
7914
|
+
break;
|
|
7915
|
+
default: throw new Error(`Unknown permission: ${policy.permit}`);
|
|
7916
|
+
}
|
|
7917
|
+
return {
|
|
7918
|
+
conditions: policy.conditions.map((cond) => protoGqlCondition(cond)),
|
|
7919
|
+
actions,
|
|
7920
|
+
permit,
|
|
7921
|
+
description: policy.description
|
|
7922
|
+
};
|
|
7923
|
+
}
|
|
7924
|
+
function protoGqlCondition(condition) {
|
|
7925
|
+
const [left, operator, right] = condition;
|
|
7926
|
+
const l = protoGqlOperand(left);
|
|
7927
|
+
const r = protoGqlOperand(right);
|
|
7928
|
+
let op;
|
|
7929
|
+
switch (operator) {
|
|
7930
|
+
case "eq":
|
|
7931
|
+
op = TailorDBGQLPermission_Operator.EQ;
|
|
7932
|
+
break;
|
|
7933
|
+
case "ne":
|
|
7934
|
+
op = TailorDBGQLPermission_Operator.NE;
|
|
7935
|
+
break;
|
|
7936
|
+
case "in":
|
|
7937
|
+
op = TailorDBGQLPermission_Operator.IN;
|
|
7938
|
+
break;
|
|
7939
|
+
case "nin":
|
|
7940
|
+
op = TailorDBGQLPermission_Operator.NIN;
|
|
7941
|
+
break;
|
|
7942
|
+
case "hasAny":
|
|
7943
|
+
op = TailorDBGQLPermission_Operator.HAS_ANY;
|
|
7944
|
+
break;
|
|
7945
|
+
case "nhasAny":
|
|
7946
|
+
op = TailorDBGQLPermission_Operator.NHAS_ANY;
|
|
7947
|
+
break;
|
|
7948
|
+
default: throw new Error(`Unknown operator: ${operator}`);
|
|
7949
|
+
}
|
|
7950
|
+
return {
|
|
7951
|
+
left: l,
|
|
7952
|
+
operator: op,
|
|
7953
|
+
right: r
|
|
7954
|
+
};
|
|
7955
|
+
}
|
|
7956
|
+
function protoGqlOperand(operand) {
|
|
7957
|
+
if (isSnapshotFieldRefOperand(operand)) {
|
|
7958
|
+
if ("user" in operand) return { kind: {
|
|
7959
|
+
case: "userField",
|
|
7960
|
+
value: operand.user
|
|
7961
|
+
} };
|
|
7962
|
+
throw new Error(`Unsupported field-ref operand in GQL permission: ${JSON.stringify(operand)} — GQL permissions only support { user } field references`);
|
|
7963
|
+
}
|
|
7964
|
+
return { kind: {
|
|
7965
|
+
case: "value",
|
|
7966
|
+
value: fromJson(ValueSchema, operand)
|
|
7967
|
+
} };
|
|
7968
|
+
}
|
|
7755
7969
|
|
|
7756
7970
|
//#endregion
|
|
7757
7971
|
//#region src/cli/commands/tailordb/migrate/pre-migration-schema.ts
|
|
@@ -7850,6 +8064,45 @@ function applyPreMigrationFieldAdjustments(fields, typeChanges) {
|
|
|
7850
8064
|
}
|
|
7851
8065
|
}
|
|
7852
8066
|
|
|
8067
|
+
//#endregion
|
|
8068
|
+
//#region src/cli/commands/tailordb/migrate/types.ts
|
|
8069
|
+
/**
|
|
8070
|
+
* Types for TailorDB migration execution
|
|
8071
|
+
*/
|
|
8072
|
+
/**
|
|
8073
|
+
* Prefix added to migration numbers in labels (required because migration names start with numbers)
|
|
8074
|
+
*/
|
|
8075
|
+
const MIGRATION_LABEL_PREFIX = "m";
|
|
8076
|
+
/**
|
|
8077
|
+
* Label key for storing migration state in TailorDB Service metadata
|
|
8078
|
+
*/
|
|
8079
|
+
const MIGRATION_LABEL_KEY = "sdk-migration";
|
|
8080
|
+
/**
|
|
8081
|
+
* Parse migration number from label value
|
|
8082
|
+
* @param {string} label - Label value (e.g., "m0001")
|
|
8083
|
+
* @returns {number | null} Parsed number or null if invalid
|
|
8084
|
+
*/
|
|
8085
|
+
function parseMigrationLabelNumber(label) {
|
|
8086
|
+
if (!label.startsWith("m")) return null;
|
|
8087
|
+
const numStr = label.slice(1);
|
|
8088
|
+
if (!/^\d+$/.test(numStr)) return null;
|
|
8089
|
+
const num = parseInt(numStr, 10);
|
|
8090
|
+
return num > 9999 ? null : num;
|
|
8091
|
+
}
|
|
8092
|
+
/**
|
|
8093
|
+
* Handle optional-to-required field change error with helpful message
|
|
8094
|
+
* @param {unknown} error - Error to handle
|
|
8095
|
+
* @param {string[]} messages - Additional messages to display
|
|
8096
|
+
*/
|
|
8097
|
+
function handleOptionalToRequiredError(error, messages) {
|
|
8098
|
+
if (error instanceof ConnectError && error.code === Code.FailedPrecondition && error.message.includes("cannot be updated from non-required to required when records exist")) {
|
|
8099
|
+
logger.error("Schema change failed: Cannot change field from optional to required when records exist.");
|
|
8100
|
+
logger.newline();
|
|
8101
|
+
for (const message of messages) logger.info(message);
|
|
8102
|
+
}
|
|
8103
|
+
throw error;
|
|
8104
|
+
}
|
|
8105
|
+
|
|
7853
8106
|
//#endregion
|
|
7854
8107
|
//#region src/cli/commands/tailordb/migrate/bundler.ts
|
|
7855
8108
|
/**
|
|
@@ -7929,28 +8182,6 @@ async function bundleMigrationScript(sourceFile, namespace, migrationNumber, env
|
|
|
7929
8182
|
};
|
|
7930
8183
|
}
|
|
7931
8184
|
|
|
7932
|
-
//#endregion
|
|
7933
|
-
//#region src/cli/commands/tailordb/migrate/types.ts
|
|
7934
|
-
/**
|
|
7935
|
-
* Prefix added to migration numbers in labels (required because migration names start with numbers)
|
|
7936
|
-
*/
|
|
7937
|
-
const MIGRATION_LABEL_PREFIX = "m";
|
|
7938
|
-
/**
|
|
7939
|
-
* Label key for storing migration state in TailorDB Service metadata
|
|
7940
|
-
*/
|
|
7941
|
-
const MIGRATION_LABEL_KEY = "sdk-migration";
|
|
7942
|
-
/**
|
|
7943
|
-
* Parse migration number from label value
|
|
7944
|
-
* @param {string} label - Label value (e.g., "m0001")
|
|
7945
|
-
* @returns {number | null} Parsed number or null if invalid
|
|
7946
|
-
*/
|
|
7947
|
-
function parseMigrationLabelNumber(label) {
|
|
7948
|
-
if (!label.startsWith("m")) return null;
|
|
7949
|
-
const numStr = label.slice(1);
|
|
7950
|
-
const num = parseInt(numStr, 10);
|
|
7951
|
-
return isNaN(num) ? null : num;
|
|
7952
|
-
}
|
|
7953
|
-
|
|
7954
8185
|
//#endregion
|
|
7955
8186
|
//#region src/cli/shared/script-executor.ts
|
|
7956
8187
|
/**
|
|
@@ -8155,7 +8386,7 @@ var Spinner = class {
|
|
|
8155
8386
|
#renderFrame() {
|
|
8156
8387
|
this.#stream.write(SYNC_BEGIN);
|
|
8157
8388
|
this.#clearDrawn();
|
|
8158
|
-
const frame = styles.info(FRAMES[this.#frame] ?? FRAMES[0]);
|
|
8389
|
+
const frame = styles.info(FRAMES[this.#frame] ?? assertDefined(FRAMES[0], "spinner frames empty"));
|
|
8159
8390
|
this.#frame = (this.#frame + 1) % FRAMES.length;
|
|
8160
8391
|
const line = `${" ".repeat(this.#indent)}${frame} ${this.text}`;
|
|
8161
8392
|
this.#stream.write(line);
|
|
@@ -8401,10 +8632,10 @@ async function getRemoteMigrationNumber(client, workspaceId, namespace) {
|
|
|
8401
8632
|
try {
|
|
8402
8633
|
const trn = resourceTrn(workspaceId, "tailordb", namespace);
|
|
8403
8634
|
const { metadata } = await client.getMetadata({ trn });
|
|
8404
|
-
const label = metadata?.labels
|
|
8635
|
+
const label = metadata?.labels["sdk-migration"];
|
|
8405
8636
|
if (!label) return null;
|
|
8406
8637
|
const match = label.match(/^m(\d+)$/);
|
|
8407
|
-
return match ? parseInt(match[1], 10) : null;
|
|
8638
|
+
return match ? parseInt(assertDefined(match[1], "migration label capture group missing"), 10) : null;
|
|
8408
8639
|
} catch {
|
|
8409
8640
|
return null;
|
|
8410
8641
|
}
|
|
@@ -8619,20 +8850,7 @@ async function applyTailorDB(client, result, phase = "create-update") {
|
|
|
8619
8850
|
} else if (phase === "delete-resources") {
|
|
8620
8851
|
await Promise.all(changeSet.gqlPermission.deletes.map((del) => client.deleteTailorDBGQLPermission(del.request)));
|
|
8621
8852
|
await Promise.all(changeSet.type.deletes.map((del) => client.deleteTailorDBType(del.request)));
|
|
8622
|
-
} else
|
|
8623
|
-
}
|
|
8624
|
-
/**
|
|
8625
|
-
* Handle optional-to-required field change error with helpful message
|
|
8626
|
-
* @param {unknown} error - Error to handle
|
|
8627
|
-
* @param {string[]} messages - Additional messages to display
|
|
8628
|
-
*/
|
|
8629
|
-
function handleOptionalToRequiredError(error, messages) {
|
|
8630
|
-
if (error instanceof ConnectError && error.code === Code.FailedPrecondition && error.message.includes("cannot be updated from non-required to required when records exist")) {
|
|
8631
|
-
logger.error("Schema change failed: Cannot change field from optional to required when records exist.");
|
|
8632
|
-
logger.newline();
|
|
8633
|
-
for (const message of messages) logger.info(message);
|
|
8634
|
-
}
|
|
8635
|
-
throw error;
|
|
8853
|
+
} else await Promise.all(changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)));
|
|
8636
8854
|
}
|
|
8637
8855
|
/**
|
|
8638
8856
|
* Get the set of type names affected by a migration
|
|
@@ -8746,7 +8964,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
8746
8964
|
const clonedRequest = structuredClone(create.request);
|
|
8747
8965
|
clonedRequest.tailordbType = snapshotType;
|
|
8748
8966
|
const typeChanges = typeName ? preMigrationChanges.get(typeName) : void 0;
|
|
8749
|
-
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType
|
|
8967
|
+
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
|
|
8750
8968
|
return client.createTailorDBType(clonedRequest);
|
|
8751
8969
|
}),
|
|
8752
8970
|
...changeSet.type.creates.filter((create) => {
|
|
@@ -8777,7 +8995,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
8777
8995
|
const clonedRequest = structuredClone(update.request);
|
|
8778
8996
|
clonedRequest.tailordbType = snapshotType;
|
|
8779
8997
|
const typeChanges = typeName ? preMigrationChanges.get(typeName) : void 0;
|
|
8780
|
-
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType
|
|
8998
|
+
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
|
|
8781
8999
|
return client.updateTailorDBType(clonedRequest);
|
|
8782
9000
|
})
|
|
8783
9001
|
]);
|
|
@@ -9075,17 +9293,14 @@ async function planTypes(client, workspaceId, tailordbs, executorUsedTypes, dele
|
|
|
9075
9293
|
};
|
|
9076
9294
|
for (const tailordb of tailordbs) {
|
|
9077
9295
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
9078
|
-
for (const typeName of Object.
|
|
9079
|
-
const type = types[typeName];
|
|
9080
|
-
if (executorUsedTypes.has(typeName) && type.settings?.publishEvents === false) throw new Error(`Type "${typeName}" has publishEvents set to false, but it is used by an executor with a record trigger. Either remove the publishEvents: false setting or remove the executor trigger for this type.`);
|
|
9081
|
-
}
|
|
9296
|
+
for (const [typeName, type] of Object.entries(types)) if (executorUsedTypes.has(typeName) && type.settings?.publishEvents === false) throw new Error(`Type "${typeName}" has publishEvents set to false, but it is used by an executor with a record trigger. Either remove the publishEvents: false setting or remove the executor trigger for this type.`);
|
|
9082
9297
|
}
|
|
9083
9298
|
for (const tailordb of tailordbs) {
|
|
9084
9299
|
const existingTypes = await fetchTypes(tailordb.namespace);
|
|
9085
9300
|
const existingTypesMap = new Map(existingTypes.map((type) => [type.name, type]));
|
|
9086
9301
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
9087
|
-
for (const typeName of Object.
|
|
9088
|
-
const tailordbType = generateTailorDBTypeManifestFromSnapshot(
|
|
9302
|
+
for (const [typeName, tailordbTypeSnapshot] of Object.entries(types)) {
|
|
9303
|
+
const tailordbType = generateTailorDBTypeManifestFromSnapshot(tailordbTypeSnapshot, {
|
|
9089
9304
|
publishRecordEvents: executorUsedTypes.has(typeName),
|
|
9090
9305
|
namespaceGqlOperations: tailordb.config.gqlOperations
|
|
9091
9306
|
});
|
|
@@ -9230,8 +9445,8 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
9230
9445
|
existingNameSet.add(gqlPermission.typeName);
|
|
9231
9446
|
});
|
|
9232
9447
|
const types = tailordb.types;
|
|
9233
|
-
for (const typeName of Object.
|
|
9234
|
-
const gqlPermission =
|
|
9448
|
+
for (const [typeName, typeEntry] of Object.entries(types)) {
|
|
9449
|
+
const gqlPermission = typeEntry.permissions?.gql;
|
|
9235
9450
|
if (!gqlPermission) continue;
|
|
9236
9451
|
const desiredPermission = protoGqlPermission(gqlPermission);
|
|
9237
9452
|
const existingPermission = existingGqlPermissions.find((entry) => entry.typeName === typeName);
|
|
@@ -9286,97 +9501,6 @@ function normalizeComparableGqlPermission(permission) {
|
|
|
9286
9501
|
actions: (policy.actions ?? []).toSorted((left, right) => left - right)
|
|
9287
9502
|
})) };
|
|
9288
9503
|
}
|
|
9289
|
-
function protoGqlPermission(permission) {
|
|
9290
|
-
return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
|
|
9291
|
-
}
|
|
9292
|
-
function protoGqlPolicy(policy) {
|
|
9293
|
-
const actions = [];
|
|
9294
|
-
for (const action of policy.actions) switch (action) {
|
|
9295
|
-
case "all":
|
|
9296
|
-
actions.push(TailorDBGQLPermission_Action.ALL);
|
|
9297
|
-
break;
|
|
9298
|
-
case "create":
|
|
9299
|
-
actions.push(TailorDBGQLPermission_Action.CREATE);
|
|
9300
|
-
break;
|
|
9301
|
-
case "read":
|
|
9302
|
-
actions.push(TailorDBGQLPermission_Action.READ);
|
|
9303
|
-
break;
|
|
9304
|
-
case "update":
|
|
9305
|
-
actions.push(TailorDBGQLPermission_Action.UPDATE);
|
|
9306
|
-
break;
|
|
9307
|
-
case "delete":
|
|
9308
|
-
actions.push(TailorDBGQLPermission_Action.DELETE);
|
|
9309
|
-
break;
|
|
9310
|
-
case "aggregate":
|
|
9311
|
-
actions.push(TailorDBGQLPermission_Action.AGGREGATE);
|
|
9312
|
-
break;
|
|
9313
|
-
case "bulkUpsert":
|
|
9314
|
-
actions.push(TailorDBGQLPermission_Action.BULK_UPSERT);
|
|
9315
|
-
break;
|
|
9316
|
-
default: throw new Error(`Unknown action: ${action}`);
|
|
9317
|
-
}
|
|
9318
|
-
let permit;
|
|
9319
|
-
switch (policy.permit) {
|
|
9320
|
-
case "allow":
|
|
9321
|
-
permit = TailorDBGQLPermission_Permit.ALLOW;
|
|
9322
|
-
break;
|
|
9323
|
-
case "deny":
|
|
9324
|
-
permit = TailorDBGQLPermission_Permit.DENY;
|
|
9325
|
-
break;
|
|
9326
|
-
default: throw new Error(`Unknown permission: ${policy.permit}`);
|
|
9327
|
-
}
|
|
9328
|
-
return {
|
|
9329
|
-
conditions: policy.conditions.map((cond) => protoGqlCondition(cond)),
|
|
9330
|
-
actions,
|
|
9331
|
-
permit,
|
|
9332
|
-
description: policy.description
|
|
9333
|
-
};
|
|
9334
|
-
}
|
|
9335
|
-
function protoGqlCondition(condition) {
|
|
9336
|
-
const [left, operator, right] = condition;
|
|
9337
|
-
const l = protoGqlOperand(left);
|
|
9338
|
-
const r = protoGqlOperand(right);
|
|
9339
|
-
let op;
|
|
9340
|
-
switch (operator) {
|
|
9341
|
-
case "eq":
|
|
9342
|
-
op = TailorDBGQLPermission_Operator.EQ;
|
|
9343
|
-
break;
|
|
9344
|
-
case "ne":
|
|
9345
|
-
op = TailorDBGQLPermission_Operator.NE;
|
|
9346
|
-
break;
|
|
9347
|
-
case "in":
|
|
9348
|
-
op = TailorDBGQLPermission_Operator.IN;
|
|
9349
|
-
break;
|
|
9350
|
-
case "nin":
|
|
9351
|
-
op = TailorDBGQLPermission_Operator.NIN;
|
|
9352
|
-
break;
|
|
9353
|
-
case "hasAny":
|
|
9354
|
-
op = TailorDBGQLPermission_Operator.HAS_ANY;
|
|
9355
|
-
break;
|
|
9356
|
-
case "nhasAny":
|
|
9357
|
-
op = TailorDBGQLPermission_Operator.NHAS_ANY;
|
|
9358
|
-
break;
|
|
9359
|
-
default: throw new Error(`Unknown operator: ${operator}`);
|
|
9360
|
-
}
|
|
9361
|
-
return {
|
|
9362
|
-
left: l,
|
|
9363
|
-
operator: op,
|
|
9364
|
-
right: r
|
|
9365
|
-
};
|
|
9366
|
-
}
|
|
9367
|
-
function protoGqlOperand(operand) {
|
|
9368
|
-
if (isSnapshotFieldRefOperand(operand)) {
|
|
9369
|
-
if ("user" in operand) return { kind: {
|
|
9370
|
-
case: "userField",
|
|
9371
|
-
value: operand.user
|
|
9372
|
-
} };
|
|
9373
|
-
throw new Error(`Unsupported field-ref operand in GQL permission: ${JSON.stringify(operand)} — GQL permissions only support { user } field references`);
|
|
9374
|
-
}
|
|
9375
|
-
return { kind: {
|
|
9376
|
-
case: "value",
|
|
9377
|
-
value: fromJson(ValueSchema, operand)
|
|
9378
|
-
} };
|
|
9379
|
-
}
|
|
9380
9504
|
/**
|
|
9381
9505
|
* Check if there are schema differences between migration snapshots and local definitions
|
|
9382
9506
|
* @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Snapshot-shaped local types by namespace
|
|
@@ -9454,31 +9578,78 @@ async function applyWorkflow(client, result, phase = "create-update") {
|
|
|
9454
9578
|
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, appId, result.unchangedWorkflowJobNames);
|
|
9455
9579
|
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
9456
9580
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
|
|
9581
|
+
const shape = buildWorkflowValidationShape(create.workspaceId, create.workflow);
|
|
9457
9582
|
await client.createWorkflow({
|
|
9458
|
-
workspaceId:
|
|
9459
|
-
workflowName:
|
|
9460
|
-
mainJobFunctionName:
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9583
|
+
workspaceId: shape.workspaceId,
|
|
9584
|
+
workflowName: shape.workflowName,
|
|
9585
|
+
mainJobFunctionName: shape.mainJobFunctionName,
|
|
9586
|
+
retryPolicy: shape.retryPolicy,
|
|
9587
|
+
concurrencyPolicy: shape.concurrencyPolicy,
|
|
9588
|
+
jobFunctions: filteredVersions
|
|
9464
9589
|
});
|
|
9465
9590
|
await client.setMetadata(create.metaRequest);
|
|
9466
9591
|
}), ...changeSet.updates.map(async (update) => {
|
|
9467
9592
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, update.usedJobNames);
|
|
9593
|
+
const shape = buildWorkflowValidationShape(update.workspaceId, update.workflow);
|
|
9468
9594
|
await client.updateWorkflow({
|
|
9469
|
-
workspaceId:
|
|
9470
|
-
workflowName:
|
|
9471
|
-
mainJobFunctionName:
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9595
|
+
workspaceId: shape.workspaceId,
|
|
9596
|
+
workflowName: shape.workflowName,
|
|
9597
|
+
mainJobFunctionName: shape.mainJobFunctionName,
|
|
9598
|
+
retryPolicy: shape.retryPolicy,
|
|
9599
|
+
concurrencyPolicy: shape.concurrencyPolicy,
|
|
9600
|
+
jobFunctions: filteredVersions
|
|
9475
9601
|
});
|
|
9476
9602
|
await client.setMetadata(update.metaRequest);
|
|
9477
9603
|
})]);
|
|
9478
|
-
} else
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9604
|
+
} else {
|
|
9605
|
+
await deleteAllSettled(changeSet.deletes.map((del) => ({
|
|
9606
|
+
resourceType: "workflow",
|
|
9607
|
+
resourceName: del.name,
|
|
9608
|
+
run: () => client.deleteWorkflow({
|
|
9609
|
+
workspaceId: del.workspaceId,
|
|
9610
|
+
workflowId: del.workflowId
|
|
9611
|
+
})
|
|
9612
|
+
})));
|
|
9613
|
+
await deleteAllSettled((result.jobFunctionDeletes ?? collectDeletableJobFunctions(changeSet.deletes)).map((del) => ({
|
|
9614
|
+
resourceType: "workflow job function",
|
|
9615
|
+
resourceName: del.jobFunctionName,
|
|
9616
|
+
run: () => client.deleteWorkflowJobFunction({
|
|
9617
|
+
workspaceId: del.workspaceId,
|
|
9618
|
+
jobFunctionName: del.jobFunctionName
|
|
9619
|
+
})
|
|
9620
|
+
})));
|
|
9621
|
+
}
|
|
9622
|
+
}
|
|
9623
|
+
async function deleteAllSettled(operations) {
|
|
9624
|
+
const results = await Promise.allSettled(operations.map((operation) => operation.run()));
|
|
9625
|
+
const errors = [];
|
|
9626
|
+
results.forEach((result, index) => {
|
|
9627
|
+
if (result.status === "fulfilled") return;
|
|
9628
|
+
const operation = assertDefined(operations[index], "operation missing at index");
|
|
9629
|
+
const error = result.reason;
|
|
9630
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return;
|
|
9631
|
+
if (error instanceof ConnectError && error.code === Code.FailedPrecondition) {
|
|
9632
|
+
logger.warn(`Skipped deleting ${operation.resourceType} "${operation.resourceName}" because it is still referenced.`);
|
|
9633
|
+
return;
|
|
9634
|
+
}
|
|
9635
|
+
errors.push(error);
|
|
9636
|
+
});
|
|
9637
|
+
const firstError = errors[0];
|
|
9638
|
+
if (firstError) throw firstError;
|
|
9639
|
+
}
|
|
9640
|
+
function collectDeletableJobFunctions(deletes) {
|
|
9641
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9642
|
+
const jobFunctions = [];
|
|
9643
|
+
for (const del of deletes) for (const jobFunctionName of del.deletableJobNames) {
|
|
9644
|
+
const key = `${del.workspaceId}\0${jobFunctionName}`;
|
|
9645
|
+
if (seen.has(key)) continue;
|
|
9646
|
+
seen.add(key);
|
|
9647
|
+
jobFunctions.push({
|
|
9648
|
+
workspaceId: del.workspaceId,
|
|
9649
|
+
jobFunctionName
|
|
9650
|
+
});
|
|
9651
|
+
}
|
|
9652
|
+
return jobFunctions;
|
|
9482
9653
|
}
|
|
9483
9654
|
/**
|
|
9484
9655
|
* Filter job function versions to only include those used by a workflow
|
|
@@ -9495,7 +9666,7 @@ function filterJobFunctionVersions(allVersions, usedJobNames) {
|
|
|
9495
9666
|
* Register job functions used by any workflow.
|
|
9496
9667
|
* Only registers jobs that are actually used (based on usedJobNames in changeSet).
|
|
9497
9668
|
* Uses create for new jobs and update for existing jobs.
|
|
9498
|
-
* Sets metadata on used JobFunctions
|
|
9669
|
+
* Sets metadata on used JobFunctions.
|
|
9499
9670
|
* @param client - Operator client instance
|
|
9500
9671
|
* @param changeSet - Workflow change set
|
|
9501
9672
|
* @param appName - Application name
|
|
@@ -9543,14 +9714,6 @@ async function registerJobFunctions(client, changeSet, appName, appId, unchanged
|
|
|
9543
9714
|
}));
|
|
9544
9715
|
for (const { jobName, version } of results) if (version) jobFunctionVersions[jobName] = version;
|
|
9545
9716
|
}
|
|
9546
|
-
const unusedJobFunctions = existingJobFunctions.filter((jobName) => !allUsedJobNames.has(jobName));
|
|
9547
|
-
await Promise.all(unusedJobFunctions.map(async (jobName) => {
|
|
9548
|
-
const { metadata } = await client.getMetadata({ trn: resourceTrn(workspaceId, "workflow_job_function", jobName) });
|
|
9549
|
-
if (isOwnedByApp(metadata?.labels, appName, appId)) await client.setMetadata({
|
|
9550
|
-
trn: resourceTrn(workspaceId, "workflow_job_function", jobName),
|
|
9551
|
-
labels: { [sdkNameLabelKey]: "" }
|
|
9552
|
-
});
|
|
9553
|
-
}));
|
|
9554
9717
|
return jobFunctionVersions;
|
|
9555
9718
|
}
|
|
9556
9719
|
function parseDurationToProto(duration) {
|
|
@@ -9574,6 +9737,21 @@ function toConcurrencyPolicy(policy) {
|
|
|
9574
9737
|
return { maxConcurrentExecutions: policy.maxConcurrentExecutions };
|
|
9575
9738
|
}
|
|
9576
9739
|
/**
|
|
9740
|
+
* Build the plan-time validation init shape for a workflow.
|
|
9741
|
+
* @param workspaceId - Workspace ID
|
|
9742
|
+
* @param workflow - Parsed workflow object
|
|
9743
|
+
* @returns Init shape suitable for validating against CreateWorkflowRequestSchema and UpdateWorkflowRequestSchema
|
|
9744
|
+
*/
|
|
9745
|
+
function buildWorkflowValidationShape(workspaceId, workflow) {
|
|
9746
|
+
return {
|
|
9747
|
+
workspaceId,
|
|
9748
|
+
workflowName: workflow.name,
|
|
9749
|
+
mainJobFunctionName: workflow.mainJob.name,
|
|
9750
|
+
...workflow.retryPolicy && { retryPolicy: toRetryPolicy(workflow.retryPolicy) },
|
|
9751
|
+
...workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(workflow.concurrencyPolicy) }
|
|
9752
|
+
};
|
|
9753
|
+
}
|
|
9754
|
+
/**
|
|
9577
9755
|
* Plan workflow changes and job functions based on current and desired state.
|
|
9578
9756
|
* @param client - Operator client instance
|
|
9579
9757
|
* @param workspaceId - Workspace ID
|
|
@@ -9590,6 +9768,7 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
9590
9768
|
const unmanaged = [];
|
|
9591
9769
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
9592
9770
|
const unchangedWorkflowJobNames = /* @__PURE__ */ new Set();
|
|
9771
|
+
const retainedWorkflowJobNames = /* @__PURE__ */ new Set();
|
|
9593
9772
|
const existingWorkflows = await fetchExistingResourcesWithLabels({
|
|
9594
9773
|
client,
|
|
9595
9774
|
workspaceId,
|
|
@@ -9613,6 +9792,7 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
9613
9792
|
});
|
|
9614
9793
|
const usedJobNames = mainJobDeps[workflow.mainJob.name];
|
|
9615
9794
|
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}", ... })`);
|
|
9795
|
+
usedJobNames.forEach((jobName) => retainedWorkflowJobNames.add(jobName));
|
|
9616
9796
|
if (existing) {
|
|
9617
9797
|
if (trackDesiredResourceOwnership({
|
|
9618
9798
|
labels: existing.allLabels,
|
|
@@ -9642,20 +9822,37 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
9642
9822
|
metaRequest
|
|
9643
9823
|
});
|
|
9644
9824
|
}
|
|
9825
|
+
const deleteWorkflows = [];
|
|
9645
9826
|
Object.values(existingWorkflows).forEach((existing) => {
|
|
9646
9827
|
if (!existing) return;
|
|
9647
|
-
|
|
9828
|
+
const owned = trackRemainingResourceOwner({
|
|
9648
9829
|
labels: existing.allLabels,
|
|
9649
9830
|
ownerLabel: existing.label,
|
|
9650
9831
|
appName,
|
|
9651
9832
|
appId,
|
|
9652
9833
|
resourceOwners
|
|
9653
|
-
})
|
|
9834
|
+
});
|
|
9835
|
+
const usedJobNames = getExistingWorkflowJobNames(existing.resource);
|
|
9836
|
+
if (owned) deleteWorkflows.push({
|
|
9654
9837
|
name: existing.resource.name,
|
|
9655
9838
|
workspaceId,
|
|
9656
9839
|
workflowId: existing.resource.id,
|
|
9657
|
-
usedJobNames
|
|
9840
|
+
usedJobNames,
|
|
9841
|
+
deletableJobNames: []
|
|
9658
9842
|
});
|
|
9843
|
+
else usedJobNames.forEach((jobName) => retainedWorkflowJobNames.add(jobName));
|
|
9844
|
+
});
|
|
9845
|
+
const jobFunctionDeletes = await planWorkflowJobFunctionDeletes({
|
|
9846
|
+
client,
|
|
9847
|
+
workspaceId,
|
|
9848
|
+
appName,
|
|
9849
|
+
appId,
|
|
9850
|
+
retainedWorkflowJobNames
|
|
9851
|
+
});
|
|
9852
|
+
const deletableJobNames = new Set(jobFunctionDeletes.map((del) => del.jobFunctionName));
|
|
9853
|
+
for (const del of deleteWorkflows) changeSet.deletes.push({
|
|
9854
|
+
...del,
|
|
9855
|
+
deletableJobNames: del.usedJobNames.filter((jobName) => !retainedWorkflowJobNames.has(jobName) && deletableJobNames.has(jobName))
|
|
9659
9856
|
});
|
|
9660
9857
|
return {
|
|
9661
9858
|
changeSet,
|
|
@@ -9664,9 +9861,29 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
9664
9861
|
resourceOwners,
|
|
9665
9862
|
appName,
|
|
9666
9863
|
appId,
|
|
9667
|
-
unchangedWorkflowJobNames
|
|
9864
|
+
unchangedWorkflowJobNames,
|
|
9865
|
+
jobFunctionDeletes
|
|
9668
9866
|
};
|
|
9669
9867
|
}
|
|
9868
|
+
async function planWorkflowJobFunctionDeletes(params) {
|
|
9869
|
+
const { client, workspaceId, appName, appId, retainedWorkflowJobNames } = params;
|
|
9870
|
+
const existingJobFunctions = await fetchAll(async (pageToken, maxPageSize) => {
|
|
9871
|
+
const response = await client.listWorkflowJobFunctions({
|
|
9872
|
+
workspaceId,
|
|
9873
|
+
pageToken,
|
|
9874
|
+
pageSize: maxPageSize
|
|
9875
|
+
});
|
|
9876
|
+
return [response.jobFunctions.map((jobFunction) => jobFunction.name), response.nextPageToken];
|
|
9877
|
+
});
|
|
9878
|
+
const candidates = [...new Set(existingJobFunctions)].filter((jobName) => !retainedWorkflowJobNames.has(jobName));
|
|
9879
|
+
return (await Promise.all(candidates.map(async (jobFunctionName) => {
|
|
9880
|
+
const { metadata } = await client.getMetadata({ trn: resourceTrn(workspaceId, "workflow_job_function", jobFunctionName) });
|
|
9881
|
+
return isOwnedByApp(metadata?.labels, appName, appId) ? {
|
|
9882
|
+
workspaceId,
|
|
9883
|
+
jobFunctionName
|
|
9884
|
+
} : void 0;
|
|
9885
|
+
}))).filter((item) => item !== void 0);
|
|
9886
|
+
}
|
|
9670
9887
|
/**
|
|
9671
9888
|
* Format workflow changes for grouped dry-run display.
|
|
9672
9889
|
* @param changeSet - Workflow changes
|
|
@@ -9734,6 +9951,191 @@ function normalizeRetryPolicyForCompare(policy) {
|
|
|
9734
9951
|
};
|
|
9735
9952
|
}
|
|
9736
9953
|
|
|
9954
|
+
//#endregion
|
|
9955
|
+
//#region src/cli/commands/deploy/validate-plan.ts
|
|
9956
|
+
function validateItems(params) {
|
|
9957
|
+
const { validator, schema, kind, action, items, requestKey, violations } = params;
|
|
9958
|
+
for (const item of items) {
|
|
9959
|
+
const init = item[requestKey];
|
|
9960
|
+
const msg = create(schema, init);
|
|
9961
|
+
const result = validator.validate(schema, msg);
|
|
9962
|
+
if (result.kind === "invalid") for (const v of result.violations) violations.push({
|
|
9963
|
+
kind,
|
|
9964
|
+
name: item.name,
|
|
9965
|
+
action,
|
|
9966
|
+
fieldPath: v.field.length > 0 ? pathToString(v.field) : "(message)",
|
|
9967
|
+
message: v.message
|
|
9968
|
+
});
|
|
9969
|
+
else if (result.kind === "error") logger.warn(`Could not validate ${kind} "${item.name}" (${action}): ${result.error.message}`);
|
|
9970
|
+
}
|
|
9971
|
+
}
|
|
9972
|
+
/**
|
|
9973
|
+
* Validate all plan-time create/update requests against buf.validate constraints embedded in the
|
|
9974
|
+
* generated proto descriptors.
|
|
9975
|
+
*
|
|
9976
|
+
* Collections not validated: idp client, tailorDB gqlPermission, functionRegistry — no
|
|
9977
|
+
* buf.validate annotations.
|
|
9978
|
+
* Application cors is excluded: static-website URL placeholders are resolved at apply time
|
|
9979
|
+
* and a bare cors array carries no constraint that would false-positive when omitted.
|
|
9980
|
+
* Workflow jobFunctions map excluded: versions are registered at apply time (registerJobFunctions)
|
|
9981
|
+
* and the map field carries no min_items constraint. Job names are validated separately via
|
|
9982
|
+
* CreateWorkflowJobFunctionRequestSchema using usedJobNames from the workflow change set.
|
|
9983
|
+
* auth idpConfig.config (provider oneof) is absent at plan time for BuiltInIdP but carries no
|
|
9984
|
+
* required constraint — the request is validated as-is from the changeset.
|
|
9985
|
+
*
|
|
9986
|
+
* @param input - Plan results from the plan phase
|
|
9987
|
+
*/
|
|
9988
|
+
async function validatePlan(input) {
|
|
9989
|
+
const { tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager } = input;
|
|
9990
|
+
const validator = createValidator();
|
|
9991
|
+
const violations = [];
|
|
9992
|
+
function creates(schema, kind, items) {
|
|
9993
|
+
validateItems({
|
|
9994
|
+
validator,
|
|
9995
|
+
schema,
|
|
9996
|
+
kind,
|
|
9997
|
+
action: "create",
|
|
9998
|
+
items,
|
|
9999
|
+
requestKey: "request",
|
|
10000
|
+
violations
|
|
10001
|
+
});
|
|
10002
|
+
}
|
|
10003
|
+
function updates(schema, kind, items) {
|
|
10004
|
+
validateItems({
|
|
10005
|
+
validator,
|
|
10006
|
+
schema,
|
|
10007
|
+
kind,
|
|
10008
|
+
action: "update",
|
|
10009
|
+
items,
|
|
10010
|
+
requestKey: "request",
|
|
10011
|
+
violations
|
|
10012
|
+
});
|
|
10013
|
+
}
|
|
10014
|
+
function replaces(schema, kind, items) {
|
|
10015
|
+
validateItems({
|
|
10016
|
+
validator,
|
|
10017
|
+
schema,
|
|
10018
|
+
kind,
|
|
10019
|
+
action: "replace",
|
|
10020
|
+
items,
|
|
10021
|
+
requestKey: "createRequest",
|
|
10022
|
+
violations
|
|
10023
|
+
});
|
|
10024
|
+
}
|
|
10025
|
+
creates(CreateTailorDBServiceRequestSchema, "TailorDB service", tailorDB.changeSet.service.creates);
|
|
10026
|
+
creates(CreateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.creates);
|
|
10027
|
+
updates(UpdateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.updates);
|
|
10028
|
+
creates(CreateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.creates);
|
|
10029
|
+
updates(UpdateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.updates);
|
|
10030
|
+
creates(AddCustomDomainRequestSchema, "StaticWebsite custom domain", staticWebsite.customDomainChangeSet.creates);
|
|
10031
|
+
creates(CreateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.creates);
|
|
10032
|
+
updates(UpdateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.updates);
|
|
10033
|
+
const idpClientVaultItems = [...idp.changeSet.client.creates.map((c) => ({
|
|
10034
|
+
clientName: c.request.client?.name ?? "",
|
|
10035
|
+
namespaceName: c.request.namespaceName ?? "",
|
|
10036
|
+
workspaceId: c.request.workspaceId ?? ""
|
|
10037
|
+
})), ...idp.changeSet.client.updates.map((u) => ({
|
|
10038
|
+
clientName: u.name,
|
|
10039
|
+
namespaceName: u.namespaceName,
|
|
10040
|
+
workspaceId: u.workspaceId
|
|
10041
|
+
}))];
|
|
10042
|
+
creates(CreateSecretManagerVaultRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
|
|
10043
|
+
name: item.clientName,
|
|
10044
|
+
request: {
|
|
10045
|
+
workspaceId: item.workspaceId,
|
|
10046
|
+
secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName)
|
|
10047
|
+
}
|
|
10048
|
+
})));
|
|
10049
|
+
creates(CreateSecretManagerSecretRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
|
|
10050
|
+
name: item.clientName,
|
|
10051
|
+
request: {
|
|
10052
|
+
workspaceId: item.workspaceId,
|
|
10053
|
+
secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName),
|
|
10054
|
+
secretmanagerSecretName: idpClientSecretName(item.namespaceName, item.clientName)
|
|
10055
|
+
}
|
|
10056
|
+
})));
|
|
10057
|
+
creates(CreateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.creates);
|
|
10058
|
+
updates(UpdateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.updates);
|
|
10059
|
+
creates(CreateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.creates);
|
|
10060
|
+
updates(UpdateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.updates);
|
|
10061
|
+
creates(CreateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.creates);
|
|
10062
|
+
updates(UpdateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.updates);
|
|
10063
|
+
creates(CreateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.creates);
|
|
10064
|
+
updates(UpdateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.updates);
|
|
10065
|
+
creates(CreateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.creates);
|
|
10066
|
+
updates(UpdateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.updates);
|
|
10067
|
+
creates(CreateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.creates);
|
|
10068
|
+
updates(UpdateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.updates);
|
|
10069
|
+
creates(CreateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.creates);
|
|
10070
|
+
updates(UpdateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.updates);
|
|
10071
|
+
creates(CreateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.creates);
|
|
10072
|
+
updates(UpdateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.updates);
|
|
10073
|
+
creates(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.creates);
|
|
10074
|
+
updates(UpdateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.updates);
|
|
10075
|
+
replaces(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.replaces);
|
|
10076
|
+
creates(CreatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.creates);
|
|
10077
|
+
updates(UpdatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.updates);
|
|
10078
|
+
creates(CreatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.creates);
|
|
10079
|
+
updates(UpdatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.updates);
|
|
10080
|
+
creates(CreateExecutorExecutorRequestSchema, "Executor", executor.changeSet.creates);
|
|
10081
|
+
updates(UpdateExecutorExecutorRequestSchema, "Executor", executor.changeSet.updates);
|
|
10082
|
+
creates(CreateWorkflowRequestSchema, "Workflow", workflow.changeSet.creates.map((item) => ({
|
|
10083
|
+
name: item.name,
|
|
10084
|
+
request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
|
|
10085
|
+
})));
|
|
10086
|
+
updates(UpdateWorkflowRequestSchema, "Workflow", workflow.changeSet.updates.map((item) => ({
|
|
10087
|
+
name: item.name,
|
|
10088
|
+
request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
|
|
10089
|
+
})));
|
|
10090
|
+
const workflowJobNameWorkspaceId = workflow.changeSet.creates[0]?.workspaceId ?? workflow.changeSet.updates[0]?.workspaceId ?? "";
|
|
10091
|
+
if (workflowJobNameWorkspaceId) {
|
|
10092
|
+
const allJobNames = /* @__PURE__ */ new Set();
|
|
10093
|
+
for (const item of [...workflow.changeSet.creates, ...workflow.changeSet.updates]) for (const jobName of item.usedJobNames) allJobNames.add(jobName);
|
|
10094
|
+
for (const jobName of workflow.unchangedWorkflowJobNames) allJobNames.add(jobName);
|
|
10095
|
+
creates(CreateWorkflowJobFunctionRequestSchema, "Workflow job function", [...allJobNames].map((jobName) => ({
|
|
10096
|
+
name: jobName,
|
|
10097
|
+
request: {
|
|
10098
|
+
workspaceId: workflowJobNameWorkspaceId,
|
|
10099
|
+
jobFunctionName: jobName,
|
|
10100
|
+
scriptRef: jobName
|
|
10101
|
+
}
|
|
10102
|
+
})));
|
|
10103
|
+
}
|
|
10104
|
+
creates(CreateSecretManagerVaultRequestSchema, "Secret Manager vault", secretManager.vaultChangeSet.creates.map((item) => ({
|
|
10105
|
+
name: item.name,
|
|
10106
|
+
request: vaultCreateRequest(item)
|
|
10107
|
+
})));
|
|
10108
|
+
creates(CreateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.creates.map((item) => ({
|
|
10109
|
+
name: item.name,
|
|
10110
|
+
request: secretCreateRequest(item)
|
|
10111
|
+
})));
|
|
10112
|
+
updates(UpdateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.updates.map((item) => ({
|
|
10113
|
+
name: item.name,
|
|
10114
|
+
request: secretUpdateRequest(item)
|
|
10115
|
+
})));
|
|
10116
|
+
creates(CreateApplicationRequestSchema, "Application", app.creates.map((item) => ({
|
|
10117
|
+
name: item.name,
|
|
10118
|
+
request: {
|
|
10119
|
+
...item.request,
|
|
10120
|
+
cors: void 0
|
|
10121
|
+
}
|
|
10122
|
+
})));
|
|
10123
|
+
updates(UpdateApplicationRequestSchema, "Application", [...app.updates, ...app.unchanged].map((item) => ({
|
|
10124
|
+
name: item.name,
|
|
10125
|
+
request: {
|
|
10126
|
+
...item.request,
|
|
10127
|
+
cors: void 0
|
|
10128
|
+
}
|
|
10129
|
+
})));
|
|
10130
|
+
creates(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.creates);
|
|
10131
|
+
replaces(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.replaces);
|
|
10132
|
+
if (violations.length === 0) return;
|
|
10133
|
+
const resourceNames = new Set(violations.map((v) => `${v.kind}:${v.name}`));
|
|
10134
|
+
logger.error(`Pre-flight validation found ${violations.length} violation(s) across ${resourceNames.size} resource(s):`);
|
|
10135
|
+
for (const v of violations) logger.log(` ${styles.resourceType(v.kind)} ${styles.resourceName(v.name)} (${v.action}) — ${styles.bold(v.fieldPath)}: ${v.message}`);
|
|
10136
|
+
throw new Error(`${violations.length} validation error(s) found in ${resourceNames.size} resource(s)`);
|
|
10137
|
+
}
|
|
10138
|
+
|
|
9737
10139
|
//#endregion
|
|
9738
10140
|
//#region src/cli/commands/deploy/deploy.ts
|
|
9739
10141
|
/**
|
|
@@ -9751,7 +10153,10 @@ function collectIdpUserTriggerTargets(application) {
|
|
|
9751
10153
|
for (const executor of Object.values(application.executorService?.executors ?? {})) {
|
|
9752
10154
|
if (executor.trigger.kind !== "idpUser") continue;
|
|
9753
10155
|
if (executor.trigger.idp != null) targets.add(executor.trigger.idp);
|
|
9754
|
-
else if (idps.length === 1)
|
|
10156
|
+
else if (idps.length === 1) {
|
|
10157
|
+
const [idp] = idps;
|
|
10158
|
+
if (idp) targets.add(idp.name);
|
|
10159
|
+
}
|
|
9755
10160
|
}
|
|
9756
10161
|
return targets;
|
|
9757
10162
|
}
|
|
@@ -9834,7 +10239,7 @@ function printPlanResults(results) {
|
|
|
9834
10239
|
...formatChangeSetEntries(results.auth.changeSet.oauth2Client, ["oauth2Client"], namespaceOf),
|
|
9835
10240
|
...formatChangeSetEntries(results.auth.changeSet.scim, ["scimConfig"], namespaceOf),
|
|
9836
10241
|
...formatChangeSetEntries(results.auth.changeSet.scimResource, ["scimResource"], namespaceOf),
|
|
9837
|
-
...
|
|
10242
|
+
...formatChangeSetEntries(results.auth.changeSet.connection, ["connection"], namespaceOf)
|
|
9838
10243
|
];
|
|
9839
10244
|
const { otherChanges: otherFunctionRegistryChanges } = splitFunctionRegistryChanges(results.functionRegistry.changeSet);
|
|
9840
10245
|
printGroupedDisplaySection(results.functionRegistry.changeSet.title, formatChangeSetEntries(otherFunctionRegistryChanges));
|
|
@@ -9976,10 +10381,7 @@ async function deploy(options) {
|
|
|
9976
10381
|
};
|
|
9977
10382
|
});
|
|
9978
10383
|
if (buildOnly) return { bundledScripts };
|
|
9979
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
9980
|
-
useProfile: true,
|
|
9981
|
-
profile: options?.profile
|
|
9982
|
-
}));
|
|
10384
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
9983
10385
|
const workspaceId = await loadWorkspaceId({
|
|
9984
10386
|
workspaceId: options?.workspaceId,
|
|
9985
10387
|
profile: options?.profile
|
|
@@ -10124,6 +10526,19 @@ async function deploy(options) {
|
|
|
10124
10526
|
workflow,
|
|
10125
10527
|
secretManager
|
|
10126
10528
|
});
|
|
10529
|
+
if (options?.noValidate) logger.warn("Client-side validation skipped (--no-validate).");
|
|
10530
|
+
else await validatePlan({
|
|
10531
|
+
functionRegistry,
|
|
10532
|
+
tailorDB,
|
|
10533
|
+
staticWebsite,
|
|
10534
|
+
idp,
|
|
10535
|
+
auth,
|
|
10536
|
+
pipeline,
|
|
10537
|
+
app,
|
|
10538
|
+
executor,
|
|
10539
|
+
workflow,
|
|
10540
|
+
secretManager
|
|
10541
|
+
});
|
|
10127
10542
|
if (dryRun) {
|
|
10128
10543
|
logger.info("Dry run enabled. No changes applied.");
|
|
10129
10544
|
return;
|
|
@@ -10486,10 +10901,7 @@ async function resolveExecutor(client, workspaceId, name) {
|
|
|
10486
10901
|
}
|
|
10487
10902
|
async function getExecutor(options) {
|
|
10488
10903
|
const name = "name" in options ? options.name : options.executor.name;
|
|
10489
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10490
|
-
useProfile: true,
|
|
10491
|
-
profile: options.profile
|
|
10492
|
-
}));
|
|
10904
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
10493
10905
|
const workspaceId = await loadWorkspaceId({
|
|
10494
10906
|
workspaceId: options.workspaceId,
|
|
10495
10907
|
profile: options.profile
|
|
@@ -10738,10 +11150,7 @@ function parseStatus(status) {
|
|
|
10738
11150
|
}
|
|
10739
11151
|
async function listWorkflowExecutions(options) {
|
|
10740
11152
|
const workflowName = options && "workflowName" in options ? options.workflowName : options && "workflow" in options ? options.workflow?.name : void 0;
|
|
10741
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10742
|
-
useProfile: true,
|
|
10743
|
-
profile: options?.profile
|
|
10744
|
-
}));
|
|
11153
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
10745
11154
|
const workspaceId = await loadWorkspaceId({
|
|
10746
11155
|
workspaceId: options?.workspaceId,
|
|
10747
11156
|
profile: options?.profile
|
|
@@ -10778,10 +11187,7 @@ async function listWorkflowExecutions(options) {
|
|
|
10778
11187
|
* @returns Workflow execution with optional logs
|
|
10779
11188
|
*/
|
|
10780
11189
|
async function getWorkflowExecution(options) {
|
|
10781
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10782
|
-
useProfile: true,
|
|
10783
|
-
profile: options.profile
|
|
10784
|
-
}));
|
|
11190
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
10785
11191
|
const workspaceId = await loadWorkspaceId({
|
|
10786
11192
|
workspaceId: options.workspaceId,
|
|
10787
11193
|
profile: options.profile
|
|
@@ -10966,10 +11372,7 @@ async function resolveWorkflow(client, workspaceId, name) {
|
|
|
10966
11372
|
}
|
|
10967
11373
|
async function getWorkflow(options) {
|
|
10968
11374
|
const name = "name" in options ? options.name : options.workflow.name;
|
|
10969
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10970
|
-
useProfile: true,
|
|
10971
|
-
profile: options.profile
|
|
10972
|
-
}));
|
|
11375
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
10973
11376
|
const workspaceId = await loadWorkspaceId({
|
|
10974
11377
|
workspaceId: options.workspaceId,
|
|
10975
11378
|
profile: options.profile
|
|
@@ -11113,10 +11516,7 @@ async function startWorkflowCore(options) {
|
|
|
11113
11516
|
}
|
|
11114
11517
|
}
|
|
11115
11518
|
async function startWorkflowByName(options) {
|
|
11116
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11117
|
-
useProfile: true,
|
|
11118
|
-
profile: options.profile
|
|
11119
|
-
}));
|
|
11519
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11120
11520
|
const workspaceId = await loadWorkspaceId({
|
|
11121
11521
|
workspaceId: options.workspaceId,
|
|
11122
11522
|
profile: options.profile
|
|
@@ -11142,10 +11542,7 @@ async function startWorkflowByName(options) {
|
|
|
11142
11542
|
async function startWorkflow(options) {
|
|
11143
11543
|
if ("name" in options) return await startWorkflowByName(options);
|
|
11144
11544
|
return await startWorkflowCore({
|
|
11145
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
11146
|
-
useProfile: true,
|
|
11147
|
-
profile: options.profile
|
|
11148
|
-
})),
|
|
11545
|
+
client: await initOperatorClient(await loadAccessToken({ profile: options.profile })),
|
|
11149
11546
|
workspaceId: await loadWorkspaceId({
|
|
11150
11547
|
workspaceId: options.workspaceId,
|
|
11151
11548
|
profile: options.profile
|
|
@@ -11208,10 +11605,7 @@ function formatTime(date) {
|
|
|
11208
11605
|
}
|
|
11209
11606
|
async function listExecutorJobs(options) {
|
|
11210
11607
|
const executorName = "executorName" in options ? options.executorName : options.executor.name;
|
|
11211
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11212
|
-
useProfile: true,
|
|
11213
|
-
profile: options.profile
|
|
11214
|
-
}));
|
|
11608
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11215
11609
|
const workspaceId = await loadWorkspaceId({
|
|
11216
11610
|
workspaceId: options.workspaceId,
|
|
11217
11611
|
profile: options.profile
|
|
@@ -11249,10 +11643,7 @@ async function listExecutorJobs(options) {
|
|
|
11249
11643
|
}
|
|
11250
11644
|
async function getExecutorJob(options) {
|
|
11251
11645
|
const executorName = "executorName" in options ? options.executorName : options.executor.name;
|
|
11252
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11253
|
-
useProfile: true,
|
|
11254
|
-
profile: options.profile
|
|
11255
|
-
}));
|
|
11646
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11256
11647
|
const workspaceId = await loadWorkspaceId({
|
|
11257
11648
|
workspaceId: options.workspaceId,
|
|
11258
11649
|
profile: options.profile
|
|
@@ -11289,10 +11680,7 @@ async function getExecutorJob(options) {
|
|
|
11289
11680
|
}
|
|
11290
11681
|
async function watchExecutorJob(options) {
|
|
11291
11682
|
const executorName = "executorName" in options ? options.executorName : options.executor.name;
|
|
11292
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11293
|
-
useProfile: true,
|
|
11294
|
-
profile: options.profile
|
|
11295
|
-
}));
|
|
11683
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11296
11684
|
const workspaceId = await loadWorkspaceId({
|
|
11297
11685
|
workspaceId: options.workspaceId,
|
|
11298
11686
|
profile: options.profile
|
|
@@ -11592,10 +11980,7 @@ const jobsCommand = defineAppCommand({
|
|
|
11592
11980
|
* @returns List of executors
|
|
11593
11981
|
*/
|
|
11594
11982
|
async function listExecutors(options) {
|
|
11595
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11596
|
-
useProfile: true,
|
|
11597
|
-
profile: options?.profile
|
|
11598
|
-
}));
|
|
11983
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
11599
11984
|
const workspaceId = await loadWorkspaceId({
|
|
11600
11985
|
workspaceId: options?.workspaceId,
|
|
11601
11986
|
profile: options?.profile
|
|
@@ -11668,10 +12053,7 @@ const headerArg = z.string().superRefine((val, ctx) => {
|
|
|
11668
12053
|
};
|
|
11669
12054
|
}).refine((h) => h.key.length > 0, { message: "Header name cannot be empty" });
|
|
11670
12055
|
async function triggerExecutorByName(options) {
|
|
11671
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11672
|
-
useProfile: true,
|
|
11673
|
-
profile: options.profile
|
|
11674
|
-
}));
|
|
12056
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11675
12057
|
const workspaceId = await loadWorkspaceId({
|
|
11676
12058
|
workspaceId: options.workspaceId,
|
|
11677
12059
|
profile: options.profile
|
|
@@ -11767,10 +12149,7 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
11767
12149
|
}).strict(),
|
|
11768
12150
|
run: async (args) => {
|
|
11769
12151
|
await assertWritable({ profile: args.profile });
|
|
11770
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11771
|
-
useProfile: true,
|
|
11772
|
-
profile: args.profile
|
|
11773
|
-
}));
|
|
12152
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: args.profile }));
|
|
11774
12153
|
const workspaceId = await loadWorkspaceId({
|
|
11775
12154
|
workspaceId: args["workspace-id"],
|
|
11776
12155
|
profile: args.profile
|
|
@@ -11858,10 +12237,7 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
11858
12237
|
* @returns List of webhook executors with URLs
|
|
11859
12238
|
*/
|
|
11860
12239
|
async function listWebhookExecutors(options) {
|
|
11861
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11862
|
-
useProfile: true,
|
|
11863
|
-
profile: options?.profile
|
|
11864
|
-
}));
|
|
12240
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
11865
12241
|
const workspaceId = await loadWorkspaceId({
|
|
11866
12242
|
workspaceId: options?.workspaceId,
|
|
11867
12243
|
profile: options?.profile
|
|
@@ -11936,12 +12312,9 @@ const getFunctionRegistryOptionsSchema = z.object({
|
|
|
11936
12312
|
});
|
|
11937
12313
|
async function loadOptions$12(options) {
|
|
11938
12314
|
const result = getFunctionRegistryOptionsSchema.safeParse(options);
|
|
11939
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
12315
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
11940
12316
|
return {
|
|
11941
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
11942
|
-
useProfile: true,
|
|
11943
|
-
profile: result.data.profile
|
|
11944
|
-
})),
|
|
12317
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
11945
12318
|
workspaceId: await loadWorkspaceId({
|
|
11946
12319
|
workspaceId: result.data.workspaceId,
|
|
11947
12320
|
profile: result.data.profile
|
|
@@ -12004,12 +12377,9 @@ const listFunctionRegistriesOptionsSchema = z.object({
|
|
|
12004
12377
|
});
|
|
12005
12378
|
async function loadOptions$11(options) {
|
|
12006
12379
|
const result = listFunctionRegistriesOptionsSchema.safeParse(options);
|
|
12007
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
12380
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
12008
12381
|
return {
|
|
12009
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
12010
|
-
useProfile: true,
|
|
12011
|
-
profile: result.data.profile
|
|
12012
|
-
})),
|
|
12382
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
12013
12383
|
workspaceId: await loadWorkspaceId({
|
|
12014
12384
|
workspaceId: result.data.workspaceId,
|
|
12015
12385
|
profile: result.data.profile
|
|
@@ -12504,13 +12874,13 @@ function createGenerationManager(params) {
|
|
|
12504
12874
|
};
|
|
12505
12875
|
}
|
|
12506
12876
|
async function processTailorDBNamespace(gen, namespace, typeInfo) {
|
|
12507
|
-
const results = generatorResults[gen.id];
|
|
12877
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12508
12878
|
results.tailordbResults[namespace] = {};
|
|
12509
12879
|
if (!gen.processType) return;
|
|
12510
12880
|
const processType = gen.processType;
|
|
12511
12881
|
await Promise.allSettled(Object.entries(typeInfo.types).map(async ([typeName, type]) => {
|
|
12512
12882
|
try {
|
|
12513
|
-
results.tailordbResults[namespace][typeName] = await processType({
|
|
12883
|
+
assertDefined(results.tailordbResults[namespace], `tailordb results not initialized for namespace ${namespace}`)[typeName] = await processType({
|
|
12514
12884
|
type,
|
|
12515
12885
|
namespace,
|
|
12516
12886
|
source: typeInfo.sourceInfo[typeName],
|
|
@@ -12533,13 +12903,13 @@ function createGenerationManager(params) {
|
|
|
12533
12903
|
else results.tailordbNamespaceResults[namespace] = results.tailordbResults[namespace];
|
|
12534
12904
|
}
|
|
12535
12905
|
async function processResolverNamespace(gen, namespace, resolvers) {
|
|
12536
|
-
const results = generatorResults[gen.id];
|
|
12906
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12537
12907
|
results.resolverResults[namespace] = {};
|
|
12538
12908
|
if (!gen.processResolver) return;
|
|
12539
12909
|
const processResolver = gen.processResolver;
|
|
12540
12910
|
await Promise.allSettled(Object.entries(resolvers).map(async ([resolverName, resolver]) => {
|
|
12541
12911
|
try {
|
|
12542
|
-
results.resolverResults[namespace][resolverName] = await processResolver({
|
|
12912
|
+
assertDefined(results.resolverResults[namespace], `resolver results not initialized for namespace ${namespace}`)[resolverName] = await processResolver({
|
|
12543
12913
|
resolver,
|
|
12544
12914
|
namespace
|
|
12545
12915
|
});
|
|
@@ -12560,7 +12930,7 @@ function createGenerationManager(params) {
|
|
|
12560
12930
|
else results.resolverNamespaceResults[namespace] = results.resolverResults[namespace];
|
|
12561
12931
|
}
|
|
12562
12932
|
async function processExecutors(gen) {
|
|
12563
|
-
const results = generatorResults[gen.id];
|
|
12933
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12564
12934
|
if (!gen.processExecutor) return;
|
|
12565
12935
|
const processExecutor = gen.processExecutor;
|
|
12566
12936
|
await Promise.allSettled(Object.entries(services.executor).map(async ([executorId, executor]) => {
|
|
@@ -12573,7 +12943,7 @@ function createGenerationManager(params) {
|
|
|
12573
12943
|
}));
|
|
12574
12944
|
}
|
|
12575
12945
|
async function aggregate(gen) {
|
|
12576
|
-
const results = generatorResults[gen.id];
|
|
12946
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12577
12947
|
const tailordbResults = [];
|
|
12578
12948
|
const resolverResults = [];
|
|
12579
12949
|
for (const [namespace, types] of Object.entries(results.tailordbNamespaceResults)) tailordbResults.push({
|
|
@@ -12631,7 +13001,7 @@ function createGenerationManager(params) {
|
|
|
12631
13001
|
let result;
|
|
12632
13002
|
switch (hookName) {
|
|
12633
13003
|
case "onTailorDBReady":
|
|
12634
|
-
result = await plugin.onTailorDBReady({
|
|
13004
|
+
result = await assertDefined(plugin.onTailorDBReady, "plugin.onTailorDBReady hook missing")({
|
|
12635
13005
|
tailordb,
|
|
12636
13006
|
auth,
|
|
12637
13007
|
baseDir: pluginBaseDir,
|
|
@@ -12640,7 +13010,7 @@ function createGenerationManager(params) {
|
|
|
12640
13010
|
});
|
|
12641
13011
|
break;
|
|
12642
13012
|
case "onResolverReady":
|
|
12643
|
-
result = await plugin.onResolverReady({
|
|
13013
|
+
result = await assertDefined(plugin.onResolverReady, "plugin.onResolverReady hook missing")({
|
|
12644
13014
|
tailordb,
|
|
12645
13015
|
resolvers: buildResolverData(),
|
|
12646
13016
|
auth,
|
|
@@ -12650,7 +13020,7 @@ function createGenerationManager(params) {
|
|
|
12650
13020
|
});
|
|
12651
13021
|
break;
|
|
12652
13022
|
case "onExecutorReady":
|
|
12653
|
-
result = await plugin.onExecutorReady({
|
|
13023
|
+
result = await assertDefined(plugin.onExecutorReady, "plugin.onExecutorReady hook missing")({
|
|
12654
13024
|
tailordb,
|
|
12655
13025
|
resolvers: buildResolverData(),
|
|
12656
13026
|
executors: { ...services.executor },
|
|
@@ -12764,7 +13134,7 @@ function createGenerationManager(params) {
|
|
|
12764
13134
|
...process.env,
|
|
12765
13135
|
TAILOR_WATCH_GENERATION: (parseInt(process.env.TAILOR_WATCH_GENERATION || "0", 10) + 1).toString()
|
|
12766
13136
|
};
|
|
12767
|
-
const child = spawn(process.argv[0], [process.argv[1], ...args], {
|
|
13137
|
+
const child = spawn(assertDefined(process.argv[0], "argv[0] missing"), [assertDefined(process.argv[1], "argv[1] missing"), ...args], {
|
|
12768
13138
|
stdio: "inherit",
|
|
12769
13139
|
env,
|
|
12770
13140
|
detached: false
|
|
@@ -12828,7 +13198,10 @@ function createGenerationManager(params) {
|
|
|
12828
13198
|
executorService: app.executorService ?? (pluginExecutorFiles.length > 0 ? createExecutorService({ config: { files: [] } }) : void 0)
|
|
12829
13199
|
};
|
|
12830
13200
|
});
|
|
12831
|
-
if (app.authService)
|
|
13201
|
+
if (app.authService) {
|
|
13202
|
+
const authService = app.authService;
|
|
13203
|
+
await withSpan("generate.resolveAuthNamespaces", async () => authService.resolveNamespaces());
|
|
13204
|
+
}
|
|
12832
13205
|
if (app.tailorDBServices.length > 0 || pluginExecutorFiles.length > 0) logger.newline();
|
|
12833
13206
|
const readyAfterTailorDB = getReadyGenerators("tailordb");
|
|
12834
13207
|
const hasOnTailorDBReady = generationPlugins.some((p) => p.onTailorDBReady != null);
|
|
@@ -12844,9 +13217,10 @@ function createGenerationManager(params) {
|
|
|
12844
13217
|
await withSpan(`generate.loadResolvers.${namespace}`, async () => {
|
|
12845
13218
|
try {
|
|
12846
13219
|
await resolverService.loadResolvers();
|
|
12847
|
-
|
|
13220
|
+
const namespaceResolvers = {};
|
|
13221
|
+
services.resolver[namespace] = namespaceResolvers;
|
|
12848
13222
|
Object.entries(resolverService.resolvers).forEach(([_, resolver]) => {
|
|
12849
|
-
|
|
13223
|
+
namespaceResolvers[resolver.name] = resolver;
|
|
12850
13224
|
});
|
|
12851
13225
|
} catch (error) {
|
|
12852
13226
|
logger.error(`Error loading resolvers for Resolver service ${styles.bold(namespace)}`);
|
|
@@ -12892,11 +13266,11 @@ function createGenerationManager(params) {
|
|
|
12892
13266
|
const app = application;
|
|
12893
13267
|
for (const db of app.tailorDBServices) {
|
|
12894
13268
|
const dbNamespace = db.namespace;
|
|
12895
|
-
await watcher
|
|
13269
|
+
await watcher.addWatchGroup(`TailorDB/${dbNamespace}`, db.config.files);
|
|
12896
13270
|
}
|
|
12897
13271
|
for (const resolverService of app.resolverServices) {
|
|
12898
13272
|
const resolverNamespace = resolverService.namespace;
|
|
12899
|
-
await watcher
|
|
13273
|
+
await watcher.addWatchGroup(`Resolver/${resolverNamespace}`, resolverService["config"].files);
|
|
12900
13274
|
}
|
|
12901
13275
|
await new Promise(() => {});
|
|
12902
13276
|
}
|
|
@@ -12960,10 +13334,7 @@ function machineUserInfo(user) {
|
|
|
12960
13334
|
* @returns List of machine users
|
|
12961
13335
|
*/
|
|
12962
13336
|
async function listMachineUsers(options) {
|
|
12963
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
12964
|
-
useProfile: true,
|
|
12965
|
-
profile: options?.profile
|
|
12966
|
-
}));
|
|
13337
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
12967
13338
|
const workspaceId = await loadWorkspaceId({
|
|
12968
13339
|
workspaceId: options?.workspaceId,
|
|
12969
13340
|
profile: options?.profile
|
|
@@ -13016,10 +13387,7 @@ const listCommand$7 = defineAppCommand({
|
|
|
13016
13387
|
* @returns Machine user token info
|
|
13017
13388
|
*/
|
|
13018
13389
|
async function getMachineUserToken(options) {
|
|
13019
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13020
|
-
useProfile: true,
|
|
13021
|
-
profile: options.profile
|
|
13022
|
-
}));
|
|
13390
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
13023
13391
|
const workspaceId = await loadWorkspaceId({
|
|
13024
13392
|
workspaceId: options.workspaceId,
|
|
13025
13393
|
profile: options.profile
|
|
@@ -13120,10 +13488,7 @@ function toOAuth2ClientCredentials(client) {
|
|
|
13120
13488
|
* @returns OAuth2 client credentials
|
|
13121
13489
|
*/
|
|
13122
13490
|
async function getOAuth2Client(options) {
|
|
13123
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13124
|
-
useProfile: true,
|
|
13125
|
-
profile: options.profile
|
|
13126
|
-
}));
|
|
13491
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
13127
13492
|
const workspaceId = await loadWorkspaceId({
|
|
13128
13493
|
workspaceId: options.workspaceId,
|
|
13129
13494
|
profile: options.profile
|
|
@@ -13140,7 +13505,7 @@ async function getOAuth2Client(options) {
|
|
|
13140
13505
|
namespaceName: application.authNamespace,
|
|
13141
13506
|
name: options.name
|
|
13142
13507
|
});
|
|
13143
|
-
return toOAuth2ClientCredentials(oauth2Client);
|
|
13508
|
+
return toOAuth2ClientCredentials(assertDefined(oauth2Client, "oauth2Client missing in response"));
|
|
13144
13509
|
} catch (error) {
|
|
13145
13510
|
if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`OAuth2 client '${options.name}' not found.`, { cause: error });
|
|
13146
13511
|
throw error;
|
|
@@ -13175,10 +13540,7 @@ const getCommand$3 = defineAppCommand({
|
|
|
13175
13540
|
* @returns List of OAuth2 clients
|
|
13176
13541
|
*/
|
|
13177
13542
|
async function listOAuth2Clients(options) {
|
|
13178
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13179
|
-
useProfile: true,
|
|
13180
|
-
profile: options?.profile
|
|
13181
|
-
}));
|
|
13543
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13182
13544
|
const workspaceId = await loadWorkspaceId({
|
|
13183
13545
|
workspaceId: options?.workspaceId,
|
|
13184
13546
|
profile: options?.profile
|
|
@@ -13262,7 +13624,7 @@ const createFolderOptionsSchema = z.object({
|
|
|
13262
13624
|
*/
|
|
13263
13625
|
async function createFolder(options) {
|
|
13264
13626
|
const result = createFolderOptionsSchema.safeParse(options);
|
|
13265
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13627
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13266
13628
|
const response = await (await initOperatorClient(await loadAccessToken())).createOrganizationFolder({
|
|
13267
13629
|
organizationId: result.data.organizationId,
|
|
13268
13630
|
parentFolderId: result.data.parentFolderId ?? "",
|
|
@@ -13307,7 +13669,7 @@ const deleteFolderOptionsSchema = z.object({
|
|
|
13307
13669
|
*/
|
|
13308
13670
|
async function deleteFolder(options) {
|
|
13309
13671
|
const result = deleteFolderOptionsSchema.safeParse(options);
|
|
13310
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13672
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13311
13673
|
await (await initOperatorClient(await loadAccessToken())).deleteOrganizationFolder({
|
|
13312
13674
|
organizationId: result.data.organizationId,
|
|
13313
13675
|
folderId: result.data.folderId
|
|
@@ -13360,7 +13722,7 @@ const getFolderOptionsSchema = z.object({
|
|
|
13360
13722
|
*/
|
|
13361
13723
|
async function getFolder(options) {
|
|
13362
13724
|
const result = getFolderOptionsSchema.safeParse(options);
|
|
13363
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13725
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13364
13726
|
const response = await (await initOperatorClient(await loadAccessToken())).getOrganizationFolder({
|
|
13365
13727
|
organizationId: result.data.organizationId,
|
|
13366
13728
|
folderId: result.data.folderId
|
|
@@ -13404,7 +13766,7 @@ const listFoldersOptionsSchema = z.object({
|
|
|
13404
13766
|
*/
|
|
13405
13767
|
async function listFolders(options) {
|
|
13406
13768
|
const result = listFoldersOptionsSchema.safeParse(options);
|
|
13407
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13769
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13408
13770
|
const { organizationId, parentFolderId, order, limit } = result.data;
|
|
13409
13771
|
const client = await initOperatorClient(await loadAccessToken());
|
|
13410
13772
|
const pageDirection = toPageDirection(order);
|
|
@@ -13452,7 +13814,7 @@ const updateFolderOptionsSchema = z.object({
|
|
|
13452
13814
|
*/
|
|
13453
13815
|
async function updateFolder(options) {
|
|
13454
13816
|
const result = updateFolderOptionsSchema.safeParse(options);
|
|
13455
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13817
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13456
13818
|
const response = await (await initOperatorClient(await loadAccessToken())).updateOrganizationFolder({
|
|
13457
13819
|
organizationId: result.data.organizationId,
|
|
13458
13820
|
folderId: result.data.folderId,
|
|
@@ -13494,7 +13856,7 @@ const getOrganizationOptionsSchema = z.object({ organizationId: z.uuid({ message
|
|
|
13494
13856
|
*/
|
|
13495
13857
|
async function getOrganization(options) {
|
|
13496
13858
|
const result = getOrganizationOptionsSchema.safeParse(options);
|
|
13497
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13859
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13498
13860
|
const response = await (await initOperatorClient(await loadAccessToken())).getOrganization({ organizationId: result.data.organizationId });
|
|
13499
13861
|
if (!response.organization) throw new Error(`Organization "${result.data.organizationId}" not found.`);
|
|
13500
13862
|
return organizationInfo(response.organization);
|
|
@@ -13588,12 +13950,12 @@ async function buildFolderTreeJson(client, organizationId, parentFolderId, curre
|
|
|
13588
13950
|
}
|
|
13589
13951
|
function renderTree(nodes, prefix) {
|
|
13590
13952
|
let output = "";
|
|
13591
|
-
for (
|
|
13953
|
+
for (const [i, node] of nodes.entries()) {
|
|
13592
13954
|
const isLast = i === nodes.length - 1;
|
|
13593
13955
|
const connector = isLast ? "└── " : "├── ";
|
|
13594
13956
|
const childPrefix = isLast ? " " : "│ ";
|
|
13595
|
-
output += `${prefix}${connector}${
|
|
13596
|
-
if (
|
|
13957
|
+
output += `${prefix}${connector}${node.name}\n`;
|
|
13958
|
+
if (node.children.length > 0) output += renderTree(node.children, prefix + childPrefix);
|
|
13597
13959
|
}
|
|
13598
13960
|
return output;
|
|
13599
13961
|
}
|
|
@@ -13680,7 +14042,7 @@ const updateOrganizationOptionsSchema = z.object({
|
|
|
13680
14042
|
*/
|
|
13681
14043
|
async function updateOrganization(options) {
|
|
13682
14044
|
const result = updateOrganizationOptionsSchema.safeParse(options);
|
|
13683
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
14045
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13684
14046
|
const response = await (await initOperatorClient(await loadAccessToken())).updateOrganization({
|
|
13685
14047
|
organizationId: result.data.organizationId,
|
|
13686
14048
|
organizationName: result.data.name
|
|
@@ -13712,10 +14074,7 @@ const updateCommand$1 = defineAppCommand({
|
|
|
13712
14074
|
//#endregion
|
|
13713
14075
|
//#region src/cli/commands/remove.ts
|
|
13714
14076
|
async function loadOptions$10(options) {
|
|
13715
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13716
|
-
useProfile: true,
|
|
13717
|
-
profile: options?.profile
|
|
13718
|
-
}));
|
|
14077
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13719
14078
|
const workspaceId = await loadWorkspaceId({
|
|
13720
14079
|
workspaceId: options?.workspaceId,
|
|
13721
14080
|
profile: options?.profile
|
|
@@ -13767,7 +14126,7 @@ async function execRemove(client, workspaceId, application, config, confirm) {
|
|
|
13767
14126
|
auth.changeSet.authHook.print();
|
|
13768
14127
|
auth.changeSet.scim.print();
|
|
13769
14128
|
auth.changeSet.scimResource.print();
|
|
13770
|
-
auth.changeSet.connection
|
|
14129
|
+
auth.changeSet.connection.print();
|
|
13771
14130
|
secretManager.vaultChangeSet.print();
|
|
13772
14131
|
secretManager.secretChangeSet.print();
|
|
13773
14132
|
if (tailorDB.changeSet.service.deletes.length === 0 && staticWebsite.changeSet.deletes.length === 0 && idp.changeSet.service.deletes.length === 0 && auth.changeSet.service.deletes.length === 0 && pipeline.changeSet.service.deletes.length === 0 && app.deletes.length === 0 && executor.changeSet.deletes.length === 0 && workflow.changeSet.deletes.length === 0 && functionRegistry.changeSet.deletes.length === 0 && secretManager.vaultChangeSet.deletes.length === 0 && secretManager.secretChangeSet.deletes.length === 0) return;
|
|
@@ -13838,6 +14197,82 @@ function logBetaWarning(featureName) {
|
|
|
13838
14197
|
logger.newline();
|
|
13839
14198
|
}
|
|
13840
14199
|
|
|
14200
|
+
//#endregion
|
|
14201
|
+
//#region src/cli/commands/workspace/transform.ts
|
|
14202
|
+
const workspaceInfo = (workspace, folderName) => {
|
|
14203
|
+
const info = {
|
|
14204
|
+
id: workspace.id,
|
|
14205
|
+
name: workspace.name,
|
|
14206
|
+
region: workspace.region,
|
|
14207
|
+
createdAt: formatTimestamp(workspace.createTime),
|
|
14208
|
+
updatedAt: formatTimestamp(workspace.updateTime)
|
|
14209
|
+
};
|
|
14210
|
+
return folderName ? {
|
|
14211
|
+
...info,
|
|
14212
|
+
folderName
|
|
14213
|
+
} : info;
|
|
14214
|
+
};
|
|
14215
|
+
const workspaceDetails = (workspace, folderName) => {
|
|
14216
|
+
return {
|
|
14217
|
+
...workspaceInfo(workspace, folderName),
|
|
14218
|
+
deleteProtection: workspace.deleteProtection,
|
|
14219
|
+
organizationId: workspace.organizationId,
|
|
14220
|
+
folderId: workspace.folderId
|
|
14221
|
+
};
|
|
14222
|
+
};
|
|
14223
|
+
async function resolveWorkspaceFolderName(client, workspace) {
|
|
14224
|
+
if (!workspace.organizationId || !workspace.folderId) return void 0;
|
|
14225
|
+
try {
|
|
14226
|
+
return (await client.getOrganizationFolder({
|
|
14227
|
+
organizationId: workspace.organizationId,
|
|
14228
|
+
folderId: workspace.folderId
|
|
14229
|
+
})).folder?.name || void 0;
|
|
14230
|
+
} catch (error) {
|
|
14231
|
+
if (error instanceof ConnectError && (error.code === Code.NotFound || error.code === Code.PermissionDenied)) return;
|
|
14232
|
+
logger.warn(`Failed to resolve workspace folder name: ${error}`);
|
|
14233
|
+
return;
|
|
14234
|
+
}
|
|
14235
|
+
}
|
|
14236
|
+
function createWorkspaceFolderNameResolver(client) {
|
|
14237
|
+
const cache = /* @__PURE__ */ new Map();
|
|
14238
|
+
return (workspace) => {
|
|
14239
|
+
if (!workspace.organizationId || !workspace.folderId) return Promise.resolve(void 0);
|
|
14240
|
+
const cacheKey = `${workspace.organizationId}/${workspace.folderId}`;
|
|
14241
|
+
const cached = cache.get(cacheKey);
|
|
14242
|
+
if (cached) return cached;
|
|
14243
|
+
const promise = resolveWorkspaceFolderName(client, workspace);
|
|
14244
|
+
cache.set(cacheKey, promise);
|
|
14245
|
+
return promise;
|
|
14246
|
+
};
|
|
14247
|
+
}
|
|
14248
|
+
async function workspaceInfoWithFolderName(client, workspace) {
|
|
14249
|
+
return workspaceInfo(workspace, await resolveWorkspaceFolderName(client, workspace));
|
|
14250
|
+
}
|
|
14251
|
+
async function workspaceDetailsWithFolderName(client, workspace) {
|
|
14252
|
+
return workspaceDetails(workspace, await resolveWorkspaceFolderName(client, workspace));
|
|
14253
|
+
}
|
|
14254
|
+
async function workspaceInfosWithFolderNames(client, workspaces) {
|
|
14255
|
+
const resolveFolderName = createWorkspaceFolderNameResolver(client);
|
|
14256
|
+
const limit = pLimit(5);
|
|
14257
|
+
return Promise.all(workspaces.map((workspace) => limit(async () => workspaceInfo(workspace, await resolveFolderName(workspace)))));
|
|
14258
|
+
}
|
|
14259
|
+
function workspaceDisplayName(workspace) {
|
|
14260
|
+
return workspace.folderName ? `${workspace.folderName}/${workspace.name}` : workspace.name;
|
|
14261
|
+
}
|
|
14262
|
+
function createWorkspaceNameTransformer(nameKey, folderNameKey) {
|
|
14263
|
+
return (value, item) => {
|
|
14264
|
+
const workspace = item;
|
|
14265
|
+
const name = workspace[nameKey];
|
|
14266
|
+
const folderName = workspace[folderNameKey];
|
|
14267
|
+
if (typeof name === "string" && typeof folderName === "string") return workspaceDisplayName({
|
|
14268
|
+
name,
|
|
14269
|
+
folderName
|
|
14270
|
+
});
|
|
14271
|
+
return String(value ?? "");
|
|
14272
|
+
};
|
|
14273
|
+
}
|
|
14274
|
+
const workspaceNameTransformer = createWorkspaceNameTransformer("name", "folderName");
|
|
14275
|
+
|
|
13841
14276
|
//#endregion
|
|
13842
14277
|
//#region src/cli/commands/show.ts
|
|
13843
14278
|
function applicationInfo(app) {
|
|
@@ -13859,10 +14294,7 @@ function applicationInfo(app) {
|
|
|
13859
14294
|
* @returns Application information
|
|
13860
14295
|
*/
|
|
13861
14296
|
async function show(options) {
|
|
13862
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13863
|
-
useProfile: true,
|
|
13864
|
-
profile: options?.profile
|
|
13865
|
-
}));
|
|
14297
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13866
14298
|
const workspaceId = await loadWorkspaceId({
|
|
13867
14299
|
workspaceId: options?.workspaceId,
|
|
13868
14300
|
profile: options?.profile
|
|
@@ -13872,15 +14304,19 @@ async function show(options) {
|
|
|
13872
14304
|
workspaceId,
|
|
13873
14305
|
applicationName: config.name
|
|
13874
14306
|
})]);
|
|
13875
|
-
const { name, ...appInfo } = applicationInfo(resp.application);
|
|
14307
|
+
const { name, ...appInfo } = applicationInfo(assertDefined(resp.application, `application "${config.name}" not found in workspace`));
|
|
14308
|
+
const workspace = workspaceResp.workspace;
|
|
14309
|
+
const workspaceFolderName = workspace ? await resolveWorkspaceFolderName(client, workspace) : "";
|
|
13876
14310
|
return {
|
|
13877
14311
|
name,
|
|
13878
14312
|
workspaceId,
|
|
13879
|
-
workspaceName:
|
|
13880
|
-
|
|
14313
|
+
workspaceName: workspace?.name ?? "",
|
|
14314
|
+
...workspaceFolderName ? { workspaceFolderName } : {},
|
|
14315
|
+
workspaceRegion: workspace?.region ?? "",
|
|
13881
14316
|
...appInfo
|
|
13882
14317
|
};
|
|
13883
14318
|
}
|
|
14319
|
+
const showWorkspaceNameTransformer = createWorkspaceNameTransformer("workspaceName", "workspaceFolderName");
|
|
13884
14320
|
const showCommand = defineAppCommand({
|
|
13885
14321
|
name: "show",
|
|
13886
14322
|
description: "Show information about the deployed application.",
|
|
@@ -13891,7 +14327,10 @@ const showCommand = defineAppCommand({
|
|
|
13891
14327
|
profile: args.profile,
|
|
13892
14328
|
configPath: args.config
|
|
13893
14329
|
});
|
|
13894
|
-
logger.out(appInfo
|
|
14330
|
+
logger.out(appInfo, { display: {
|
|
14331
|
+
workspaceName: showWorkspaceNameTransformer,
|
|
14332
|
+
workspaceFolderName: null
|
|
14333
|
+
} });
|
|
13895
14334
|
}
|
|
13896
14335
|
});
|
|
13897
14336
|
|
|
@@ -13980,7 +14419,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
13980
14419
|
const { before, after } = change;
|
|
13981
14420
|
if (before && after && !before.required && after.required) {
|
|
13982
14421
|
if (!optionalToRequired.has(change.typeName)) optionalToRequired.set(change.typeName, /* @__PURE__ */ new Set());
|
|
13983
|
-
optionalToRequired.get(change.typeName).add(change.fieldName);
|
|
14422
|
+
assertDefined(optionalToRequired.get(change.typeName), "optionalToRequired entry missing").add(change.fieldName);
|
|
13984
14423
|
}
|
|
13985
14424
|
if (before && after && before.type === "enum" && after.type === "enum" && before.allowedValues && after.allowedValues) {
|
|
13986
14425
|
const beforeValues = before.allowedValues.map((v) => v.value);
|
|
@@ -13989,7 +14428,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
13989
14428
|
const afterSet = new Set(afterValues);
|
|
13990
14429
|
if (beforeValues.some((v) => !afterSet.has(v)) || afterValues.some((v) => !beforeSet.has(v))) {
|
|
13991
14430
|
if (!enumValueChanges.has(change.typeName)) enumValueChanges.set(change.typeName, /* @__PURE__ */ new Map());
|
|
13992
|
-
enumValueChanges.get(change.typeName).set(change.fieldName, {
|
|
14431
|
+
assertDefined(enumValueChanges.get(change.typeName), "enumValueChanges entry missing").set(change.fieldName, {
|
|
13993
14432
|
beforeValues,
|
|
13994
14433
|
afterValues
|
|
13995
14434
|
});
|
|
@@ -13999,7 +14438,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
13999
14438
|
const { after } = change;
|
|
14000
14439
|
if (after && after.required) {
|
|
14001
14440
|
if (!addedRequiredFields.has(change.typeName)) addedRequiredFields.set(change.typeName, /* @__PURE__ */ new Map());
|
|
14002
|
-
addedRequiredFields.get(change.typeName).set(change.fieldName, after);
|
|
14441
|
+
assertDefined(addedRequiredFields.get(change.typeName), "addedRequiredFields entry missing").set(change.fieldName, after);
|
|
14003
14442
|
}
|
|
14004
14443
|
}
|
|
14005
14444
|
return {
|
|
@@ -14481,7 +14920,7 @@ async function generate(options) {
|
|
|
14481
14920
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
14482
14921
|
let pluginManager;
|
|
14483
14922
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
14484
|
-
const { defineApplication } = await import("./application-
|
|
14923
|
+
const { defineApplication } = await import("./application-DSXntqnV.mjs");
|
|
14485
14924
|
const application = defineApplication({
|
|
14486
14925
|
config,
|
|
14487
14926
|
pluginManager
|
|
@@ -14652,7 +15091,7 @@ function extractAllNamespaces(config) {
|
|
|
14652
15091
|
function extractOwnedNamespaces(config) {
|
|
14653
15092
|
const namespaces = /* @__PURE__ */ new Set();
|
|
14654
15093
|
if (config.db) for (const [namespaceName, nsConfig] of Object.entries(config.db)) {
|
|
14655
|
-
if ("external" in nsConfig
|
|
15094
|
+
if ("external" in nsConfig) continue;
|
|
14656
15095
|
namespaces.add(namespaceName);
|
|
14657
15096
|
}
|
|
14658
15097
|
return Array.from(namespaces);
|
|
@@ -14729,18 +15168,15 @@ async function truncate(options) {
|
|
|
14729
15168
|
yes: true
|
|
14730
15169
|
});
|
|
14731
15170
|
}
|
|
14732
|
-
async function $truncate(options) {
|
|
14733
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14734
|
-
useProfile: true,
|
|
14735
|
-
profile: options?.profile
|
|
14736
|
-
}));
|
|
15171
|
+
async function $truncate(options = {}) {
|
|
15172
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
14737
15173
|
const workspaceId = await loadWorkspaceId({
|
|
14738
|
-
workspaceId: options
|
|
14739
|
-
profile: options
|
|
15174
|
+
workspaceId: options.workspaceId,
|
|
15175
|
+
profile: options.profile
|
|
14740
15176
|
});
|
|
14741
|
-
const hasTypes = options
|
|
14742
|
-
const hasNamespace = !!options
|
|
14743
|
-
const hasAll = !!options
|
|
15177
|
+
const hasTypes = options.types && options.types.length > 0;
|
|
15178
|
+
const hasNamespace = !!options.namespace;
|
|
15179
|
+
const hasAll = !!options.all;
|
|
14744
15180
|
const optionCount = [
|
|
14745
15181
|
hasAll,
|
|
14746
15182
|
hasNamespace,
|
|
@@ -14748,14 +15184,14 @@ async function $truncate(options) {
|
|
|
14748
15184
|
].filter(Boolean).length;
|
|
14749
15185
|
if (optionCount === 0) throw new Error("Please specify one of: --all, --namespace <name>, or type names");
|
|
14750
15186
|
if (optionCount > 1) throw new Error("Options --all, --namespace, and type names are mutually exclusive. Please specify only one.");
|
|
14751
|
-
const { config } = await loadConfig(options
|
|
15187
|
+
const { config } = await loadConfig(options.configPath);
|
|
14752
15188
|
const namespaces = extractOwnedNamespaces(config);
|
|
14753
15189
|
if (hasAll) {
|
|
14754
15190
|
if (namespaces.length === 0) {
|
|
14755
15191
|
logger.warn("No namespaces found in config file.");
|
|
14756
15192
|
return;
|
|
14757
15193
|
}
|
|
14758
|
-
if (!options
|
|
15194
|
+
if (!options.yes) {
|
|
14759
15195
|
const namespaceList = namespaces.join(", ");
|
|
14760
15196
|
if (!await prompt.confirm({
|
|
14761
15197
|
message: `This will truncate ALL tables in the following owned namespaces (external namespaces are excluded): ${namespaceList}. Continue?`,
|
|
@@ -14769,11 +15205,11 @@ async function $truncate(options) {
|
|
|
14769
15205
|
logger.success("Truncated all tables in all owned namespaces");
|
|
14770
15206
|
return;
|
|
14771
15207
|
}
|
|
14772
|
-
if (hasNamespace
|
|
14773
|
-
const namespace = options.namespace;
|
|
15208
|
+
if (hasNamespace) {
|
|
15209
|
+
const namespace = assertDefined(options.namespace, "namespace option missing");
|
|
14774
15210
|
if (!namespaces.includes(namespace)) {
|
|
14775
15211
|
const dbConfig = config.db?.[namespace];
|
|
14776
|
-
if (dbConfig && "external" in dbConfig
|
|
15212
|
+
if (dbConfig && "external" in dbConfig) throw new Error(`Namespace "${namespace}" is declared as external in this app's config and cannot be truncated from here. Run truncate from the app that owns it.`);
|
|
14777
15213
|
throw new Error(`Namespace "${namespace}" not found in config. Available owned namespaces (external namespaces are excluded): ${namespaces.join(", ")}`);
|
|
14778
15214
|
}
|
|
14779
15215
|
if (!options.yes) {
|
|
@@ -14788,8 +15224,8 @@ async function $truncate(options) {
|
|
|
14788
15224
|
await truncateNamespace(workspaceId, namespace, client);
|
|
14789
15225
|
return;
|
|
14790
15226
|
}
|
|
14791
|
-
if (hasTypes
|
|
14792
|
-
const typeNames = options.types;
|
|
15227
|
+
if (hasTypes) {
|
|
15228
|
+
const typeNames = assertDefined(options.types, "types option missing");
|
|
14793
15229
|
const typeNamespaceMap = await resolveTypeNamespaces({
|
|
14794
15230
|
workspaceId,
|
|
14795
15231
|
namespaces,
|
|
@@ -14861,10 +15297,7 @@ const truncateCommand = defineAppCommand({
|
|
|
14861
15297
|
* @returns List of workflows
|
|
14862
15298
|
*/
|
|
14863
15299
|
async function listWorkflows(options) {
|
|
14864
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14865
|
-
useProfile: true,
|
|
14866
|
-
profile: options?.profile
|
|
14867
|
-
}));
|
|
15300
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
14868
15301
|
const workspaceId = await loadWorkspaceId({
|
|
14869
15302
|
workspaceId: options?.workspaceId,
|
|
14870
15303
|
profile: options?.profile
|
|
@@ -14911,10 +15344,7 @@ const listCommand$3 = defineAppCommand({
|
|
|
14911
15344
|
* @returns Resume result with wait helper
|
|
14912
15345
|
*/
|
|
14913
15346
|
async function resumeWorkflow(options) {
|
|
14914
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14915
|
-
useProfile: true,
|
|
14916
|
-
profile: options.profile
|
|
14917
|
-
}));
|
|
15347
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
14918
15348
|
const workspaceId = await loadWorkspaceId({
|
|
14919
15349
|
workspaceId: options.workspaceId,
|
|
14920
15350
|
profile: options.profile
|
|
@@ -15022,12 +15452,9 @@ const healthOptionsSchema = z.object({
|
|
|
15022
15452
|
});
|
|
15023
15453
|
async function loadOptions$9(options) {
|
|
15024
15454
|
const result = healthOptionsSchema.safeParse(options);
|
|
15025
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15455
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15026
15456
|
return {
|
|
15027
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15028
|
-
useProfile: true,
|
|
15029
|
-
profile: result.data.profile
|
|
15030
|
-
})),
|
|
15457
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15031
15458
|
workspaceId: await loadWorkspaceId({
|
|
15032
15459
|
workspaceId: result.data.workspaceId,
|
|
15033
15460
|
profile: result.data.profile
|
|
@@ -15082,12 +15509,9 @@ const listAppsOptionsSchema = z.object({
|
|
|
15082
15509
|
});
|
|
15083
15510
|
async function loadOptions$8(options) {
|
|
15084
15511
|
const result = listAppsOptionsSchema.safeParse(options);
|
|
15085
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15512
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15086
15513
|
return {
|
|
15087
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15088
|
-
useProfile: true,
|
|
15089
|
-
profile: result.data.profile
|
|
15090
|
-
})),
|
|
15514
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15091
15515
|
workspaceId: await loadWorkspaceId({
|
|
15092
15516
|
workspaceId: result.data.workspaceId,
|
|
15093
15517
|
profile: result.data.profile
|
|
@@ -15137,26 +15561,6 @@ const listCommand$2 = defineAppCommand({
|
|
|
15137
15561
|
}
|
|
15138
15562
|
});
|
|
15139
15563
|
|
|
15140
|
-
//#endregion
|
|
15141
|
-
//#region src/cli/commands/workspace/transform.ts
|
|
15142
|
-
const workspaceInfo = (workspace) => {
|
|
15143
|
-
return {
|
|
15144
|
-
id: workspace.id,
|
|
15145
|
-
name: workspace.name,
|
|
15146
|
-
region: workspace.region,
|
|
15147
|
-
createdAt: formatTimestamp(workspace.createTime),
|
|
15148
|
-
updatedAt: formatTimestamp(workspace.updateTime)
|
|
15149
|
-
};
|
|
15150
|
-
};
|
|
15151
|
-
const workspaceDetails = (workspace) => {
|
|
15152
|
-
return {
|
|
15153
|
-
...workspaceInfo(workspace),
|
|
15154
|
-
deleteProtection: workspace.deleteProtection,
|
|
15155
|
-
organizationId: workspace.organizationId,
|
|
15156
|
-
folderId: workspace.folderId
|
|
15157
|
-
};
|
|
15158
|
-
};
|
|
15159
|
-
|
|
15160
15564
|
//#endregion
|
|
15161
15565
|
//#region src/cli/commands/workspace/create.ts
|
|
15162
15566
|
/**
|
|
@@ -15182,17 +15586,17 @@ const validateRegion = async (region, client) => {
|
|
|
15182
15586
|
*/
|
|
15183
15587
|
async function createWorkspace(options) {
|
|
15184
15588
|
const result = createWorkspaceOptionsSchema.safeParse(options);
|
|
15185
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15589
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15186
15590
|
const validated = result.data;
|
|
15187
15591
|
const client = await initOperatorClient(await loadAccessToken());
|
|
15188
15592
|
await validateRegion(validated.region, client);
|
|
15189
|
-
return
|
|
15593
|
+
return workspaceInfoWithFolderName(client, assertDefined((await client.createWorkspace({
|
|
15190
15594
|
workspaceName: validated.name,
|
|
15191
15595
|
workspaceRegion: validated.region,
|
|
15192
15596
|
deleteProtection: validated.deleteProtection ?? false,
|
|
15193
15597
|
organizationId: validated.organizationId,
|
|
15194
15598
|
folderId: validated.folderId
|
|
15195
|
-
})).workspace);
|
|
15599
|
+
})).workspace, "createWorkspace response missing workspace"));
|
|
15196
15600
|
}
|
|
15197
15601
|
const createCommand = defineAppCommand({
|
|
15198
15602
|
name: "create",
|
|
@@ -15258,7 +15662,7 @@ const createCommand = defineAppCommand({
|
|
|
15258
15662
|
};
|
|
15259
15663
|
if (!args.json) logger.success(`Profile "${profileName}" created successfully.`);
|
|
15260
15664
|
}
|
|
15261
|
-
if (!args.json) logger.success(`Workspace "${
|
|
15665
|
+
if (!args.json) logger.success(`Workspace "${workspaceDisplayName(workspace)}" created successfully.`);
|
|
15262
15666
|
if (args.json && profileInfo) {
|
|
15263
15667
|
logger.out({
|
|
15264
15668
|
...workspace,
|
|
@@ -15266,7 +15670,10 @@ const createCommand = defineAppCommand({
|
|
|
15266
15670
|
});
|
|
15267
15671
|
return;
|
|
15268
15672
|
}
|
|
15269
|
-
logger.out(workspace
|
|
15673
|
+
logger.out(workspace, { display: {
|
|
15674
|
+
name: workspaceNameTransformer,
|
|
15675
|
+
folderName: null
|
|
15676
|
+
} });
|
|
15270
15677
|
if (profileInfo) {
|
|
15271
15678
|
logger.out("Profile:");
|
|
15272
15679
|
logger.out(profileInfo);
|
|
@@ -15279,7 +15686,7 @@ const createCommand = defineAppCommand({
|
|
|
15279
15686
|
const deleteWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
|
|
15280
15687
|
async function loadOptions$7(options) {
|
|
15281
15688
|
const result = deleteWorkspaceOptionsSchema.safeParse(options);
|
|
15282
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15689
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15283
15690
|
return {
|
|
15284
15691
|
client: await initOperatorClient(await loadAccessToken()),
|
|
15285
15692
|
workspaceId: result.data.workspaceId
|
|
@@ -15313,8 +15720,15 @@ const deleteCommand = defineAppCommand({
|
|
|
15313
15720
|
} catch {
|
|
15314
15721
|
throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
15315
15722
|
}
|
|
15723
|
+
const workspaceResource = workspace.workspace;
|
|
15724
|
+
const workspaceName = workspaceResource?.name ?? workspaceId;
|
|
15725
|
+
const displayName = workspaceDisplayName({
|
|
15726
|
+
name: workspaceName,
|
|
15727
|
+
folderName: workspaceResource ? await resolveWorkspaceFolderName(client, workspaceResource) : ""
|
|
15728
|
+
});
|
|
15316
15729
|
if (!args.yes) {
|
|
15317
|
-
|
|
15730
|
+
const confirmation = await prompt.text({ message: `Enter the workspace name to confirm deletion (${displayName}):` });
|
|
15731
|
+
if (confirmation !== workspaceName && confirmation !== displayName) {
|
|
15318
15732
|
logger.info("Workspace deletion cancelled.");
|
|
15319
15733
|
return;
|
|
15320
15734
|
}
|
|
@@ -15326,8 +15740,8 @@ const deleteCommand = defineAppCommand({
|
|
|
15326
15740
|
for (const [profileName] of profilesToDelete) delete pfConfig.profiles[profileName];
|
|
15327
15741
|
writePlatformConfig(pfConfig);
|
|
15328
15742
|
}
|
|
15329
|
-
if (profilesToDelete.length > 0) logger.success(`Workspace "${
|
|
15330
|
-
else logger.success(`Workspace "${
|
|
15743
|
+
if (profilesToDelete.length > 0) logger.success(`Workspace "${displayName}" and ${profilesToDelete.length} associated profile(s) deleted successfully.`);
|
|
15744
|
+
else logger.success(`Workspace "${displayName}" deleted successfully.`);
|
|
15331
15745
|
}
|
|
15332
15746
|
});
|
|
15333
15747
|
|
|
@@ -15339,12 +15753,9 @@ const getWorkspaceOptionsSchema = z.object({
|
|
|
15339
15753
|
});
|
|
15340
15754
|
async function loadOptions$6(options) {
|
|
15341
15755
|
const result = getWorkspaceOptionsSchema.safeParse(options);
|
|
15342
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15756
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15343
15757
|
return {
|
|
15344
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15345
|
-
useProfile: true,
|
|
15346
|
-
profile: result.data.profile
|
|
15347
|
-
})),
|
|
15758
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15348
15759
|
workspaceId: await loadWorkspaceId({
|
|
15349
15760
|
workspaceId: result.data.workspaceId,
|
|
15350
15761
|
profile: result.data.profile
|
|
@@ -15360,7 +15771,7 @@ async function getWorkspace(options) {
|
|
|
15360
15771
|
const { client, workspaceId } = await loadOptions$6(options);
|
|
15361
15772
|
const response = await client.getWorkspace({ workspaceId });
|
|
15362
15773
|
if (!response.workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
15363
|
-
return
|
|
15774
|
+
return workspaceDetailsWithFolderName(client, response.workspace);
|
|
15364
15775
|
}
|
|
15365
15776
|
const getCommand = defineAppCommand({
|
|
15366
15777
|
name: "get",
|
|
@@ -15376,7 +15787,10 @@ const getCommand = defineAppCommand({
|
|
|
15376
15787
|
createdAt: humanizeRelativeTime(workspace.createdAt),
|
|
15377
15788
|
updatedAt: humanizeRelativeTime(workspace.updatedAt)
|
|
15378
15789
|
};
|
|
15379
|
-
logger.out(formattedWorkspace
|
|
15790
|
+
logger.out(formattedWorkspace, { display: {
|
|
15791
|
+
name: workspaceNameTransformer,
|
|
15792
|
+
folderName: null
|
|
15793
|
+
} });
|
|
15380
15794
|
}
|
|
15381
15795
|
});
|
|
15382
15796
|
|
|
@@ -15390,14 +15804,14 @@ const getCommand = defineAppCommand({
|
|
|
15390
15804
|
async function listWorkspaces(options) {
|
|
15391
15805
|
const client = await initOperatorClient(await loadAccessToken());
|
|
15392
15806
|
const pageDirection = toPageDirection(options?.order);
|
|
15393
|
-
return (await fetchPaged(async (pageToken, pageSize) => {
|
|
15807
|
+
return workspaceInfosWithFolderNames(client, await fetchPaged(async (pageToken, pageSize) => {
|
|
15394
15808
|
const { workspaces, nextPageToken } = await client.listWorkspaces({
|
|
15395
15809
|
pageToken,
|
|
15396
15810
|
pageSize,
|
|
15397
15811
|
pageDirection
|
|
15398
15812
|
});
|
|
15399
15813
|
return [workspaces, nextPageToken];
|
|
15400
|
-
}, { limit: options?.limit }))
|
|
15814
|
+
}, { limit: options?.limit }));
|
|
15401
15815
|
}
|
|
15402
15816
|
const listCommand$1 = defineAppCommand({
|
|
15403
15817
|
name: "list",
|
|
@@ -15408,7 +15822,11 @@ const listCommand$1 = defineAppCommand({
|
|
|
15408
15822
|
order: args.order,
|
|
15409
15823
|
limit: args.limit
|
|
15410
15824
|
});
|
|
15411
|
-
logger.out(workspaces, { display: {
|
|
15825
|
+
logger.out(workspaces, { display: {
|
|
15826
|
+
name: workspaceNameTransformer,
|
|
15827
|
+
folderName: null,
|
|
15828
|
+
updatedAt: null
|
|
15829
|
+
} });
|
|
15412
15830
|
}
|
|
15413
15831
|
});
|
|
15414
15832
|
|
|
@@ -15417,7 +15835,7 @@ const listCommand$1 = defineAppCommand({
|
|
|
15417
15835
|
const restoreWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
|
|
15418
15836
|
async function loadOptions$5(options) {
|
|
15419
15837
|
const result = restoreWorkspaceOptionsSchema.safeParse(options);
|
|
15420
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15838
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15421
15839
|
return {
|
|
15422
15840
|
client: await initOperatorClient(await loadAccessToken()),
|
|
15423
15841
|
workspaceId: result.data.workspaceId
|
|
@@ -15497,12 +15915,9 @@ const inviteUserOptionsSchema = z.object({
|
|
|
15497
15915
|
});
|
|
15498
15916
|
async function loadOptions$4(options) {
|
|
15499
15917
|
const result = inviteUserOptionsSchema.safeParse(options);
|
|
15500
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15918
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15501
15919
|
return {
|
|
15502
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15503
|
-
useProfile: true,
|
|
15504
|
-
profile: result.data.profile
|
|
15505
|
-
})),
|
|
15920
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15506
15921
|
workspaceId: await loadWorkspaceId({
|
|
15507
15922
|
workspaceId: result.data.workspaceId,
|
|
15508
15923
|
profile: result.data.profile
|
|
@@ -15557,12 +15972,9 @@ const listUsersOptionsSchema = z.object({
|
|
|
15557
15972
|
});
|
|
15558
15973
|
async function loadOptions$3(options) {
|
|
15559
15974
|
const result = listUsersOptionsSchema.safeParse(options);
|
|
15560
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15975
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15561
15976
|
return {
|
|
15562
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15563
|
-
useProfile: true,
|
|
15564
|
-
profile: result.data.profile
|
|
15565
|
-
})),
|
|
15977
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15566
15978
|
workspaceId: await loadWorkspaceId({
|
|
15567
15979
|
workspaceId: result.data.workspaceId,
|
|
15568
15980
|
profile: result.data.profile
|
|
@@ -15616,12 +16028,9 @@ const removeUserOptionsSchema = z.object({
|
|
|
15616
16028
|
});
|
|
15617
16029
|
async function loadOptions$2(options) {
|
|
15618
16030
|
const result = removeUserOptionsSchema.safeParse(options);
|
|
15619
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16031
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15620
16032
|
return {
|
|
15621
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15622
|
-
useProfile: true,
|
|
15623
|
-
profile: result.data.profile
|
|
15624
|
-
})),
|
|
16033
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15625
16034
|
workspaceId: await loadWorkspaceId({
|
|
15626
16035
|
workspaceId: result.data.workspaceId,
|
|
15627
16036
|
profile: result.data.profile
|
|
@@ -15676,12 +16085,9 @@ const updateUserOptionsSchema = z.object({
|
|
|
15676
16085
|
});
|
|
15677
16086
|
async function loadOptions$1(options) {
|
|
15678
16087
|
const result = updateUserOptionsSchema.safeParse(options);
|
|
15679
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16088
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15680
16089
|
return {
|
|
15681
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15682
|
-
useProfile: true,
|
|
15683
|
-
profile: result.data.profile
|
|
15684
|
-
})),
|
|
16090
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15685
16091
|
workspaceId: await loadWorkspaceId({
|
|
15686
16092
|
workspaceId: result.data.workspaceId,
|
|
15687
16093
|
profile: result.data.profile
|
|
@@ -15902,7 +16308,7 @@ function isSqlInputComplete(input) {
|
|
|
15902
16308
|
let dollarQuoteTag = null;
|
|
15903
16309
|
let lastSignificantTokenWasSemicolon = false;
|
|
15904
16310
|
for (let i = 0; i < input.length; i += 1) {
|
|
15905
|
-
const char = input[i];
|
|
16311
|
+
const char = assertDefined(input[i], `character at index ${i} missing`);
|
|
15906
16312
|
const next = input[i + 1];
|
|
15907
16313
|
if (inLineComment) {
|
|
15908
16314
|
if (char === "\n") inLineComment = false;
|
|
@@ -16105,7 +16511,7 @@ const queryBaseOptionsSchema = z.object({
|
|
|
16105
16511
|
const queryOptionsSchema = queryBaseOptionsSchema.extend({ query: z.string() });
|
|
16106
16512
|
async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces) {
|
|
16107
16513
|
if (namespaces.length === 0) throw new Error("No namespaces found in configuration.");
|
|
16108
|
-
if (namespaces.length === 1) return namespaces[0];
|
|
16514
|
+
if (namespaces.length === 1) return assertDefined(namespaces[0], "namespace missing");
|
|
16109
16515
|
const typeNames = extractTypeNamesFromSql(query);
|
|
16110
16516
|
if (typeNames.length === 0) throw new Error(`Could not infer namespace from query. Detected namespaces: ${namespaces.join(", ")}.`);
|
|
16111
16517
|
const typeNamespaceMap = await resolveTypeNamespaces({
|
|
@@ -16117,16 +16523,13 @@ async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces)
|
|
|
16117
16523
|
const notFoundTypes = typeNames.filter((typeName) => !typeNamespaceMap.has(typeName));
|
|
16118
16524
|
if (notFoundTypes.length > 0) throw new Error(`Could not find namespace for types in query: ${notFoundTypes.join(", ")}.`);
|
|
16119
16525
|
const namespacesFromTypes = new Set(typeNamespaceMap.values());
|
|
16120
|
-
if (namespacesFromTypes.size === 1) return [...namespacesFromTypes][0];
|
|
16526
|
+
if (namespacesFromTypes.size === 1) return assertDefined([...namespacesFromTypes][0], "namespace from types missing");
|
|
16121
16527
|
throw new Error(`Query references types from multiple namespaces: ${[...namespacesFromTypes].join(", ")}.`);
|
|
16122
16528
|
}
|
|
16123
16529
|
async function loadOptions(options) {
|
|
16124
16530
|
const result = queryBaseOptionsSchema.safeParse(options);
|
|
16125
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16126
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
16127
|
-
useProfile: true,
|
|
16128
|
-
profile: result.data.profile
|
|
16129
|
-
}));
|
|
16531
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
|
|
16532
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: result.data.profile }));
|
|
16130
16533
|
const workspaceId = await loadWorkspaceId({
|
|
16131
16534
|
workspaceId: result.data.workspaceId,
|
|
16132
16535
|
profile: result.data.profile
|
|
@@ -16259,7 +16662,7 @@ async function resolveEditedQueryInput(engine) {
|
|
|
16259
16662
|
*/
|
|
16260
16663
|
async function query(options) {
|
|
16261
16664
|
const result = queryOptionsSchema.safeParse(options);
|
|
16262
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16665
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
|
|
16263
16666
|
return await (await prepareQueryExecutor(result.data))(result.data.query);
|
|
16264
16667
|
}
|
|
16265
16668
|
async function prepareQueryExecutor(options) {
|
|
@@ -16341,7 +16744,7 @@ async function runRepl(options) {
|
|
|
16341
16744
|
const execute = await prepareQueryExecutor(options);
|
|
16342
16745
|
const historyPath = getReplHistoryPath(options.engine, options.profile, options.workspaceId);
|
|
16343
16746
|
const validate = createReplValidator(options.engine);
|
|
16344
|
-
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-
|
|
16747
|
+
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-CJG3sz7A.mjs");
|
|
16345
16748
|
const highlight = options.engine === "sql" ? highlightSqlLine : highlightGraphqlLine;
|
|
16346
16749
|
const prompt = createPrompt({
|
|
16347
16750
|
prefix: "",
|
|
@@ -16602,8 +17005,9 @@ function printSingleSqlResult(execResult, options = {}) {
|
|
|
16602
17005
|
function splitSqlStatements(query) {
|
|
16603
17006
|
const statements = parse(query, { locationTracking: true });
|
|
16604
17007
|
return statements.map((s, i) => {
|
|
16605
|
-
const start = s._location.start;
|
|
16606
|
-
const
|
|
17008
|
+
const start = assertDefined(s._location, "SQL statement location missing").start;
|
|
17009
|
+
const nextStmt = statements[i + 1];
|
|
17010
|
+
const end = nextStmt !== void 0 ? assertDefined(nextStmt._location, "SQL statement location missing").start : query.length;
|
|
16607
17011
|
return query.substring(start, end);
|
|
16608
17012
|
});
|
|
16609
17013
|
}
|
|
@@ -16623,7 +17027,7 @@ function printSqlResult(result, options = {}) {
|
|
|
16623
17027
|
for (let i = 0; i < result.result.length; i++) {
|
|
16624
17028
|
if (i > 0) logger.log("");
|
|
16625
17029
|
logger.info(queries[i] ?? `Statement ${i + 1}`);
|
|
16626
|
-
printSingleSqlResult(result.result[i], options);
|
|
17030
|
+
printSingleSqlResult(assertDefined(result.result[i], `SQL result at index ${i} missing`), options);
|
|
16627
17031
|
}
|
|
16628
17032
|
return;
|
|
16629
17033
|
}
|
|
@@ -16674,5 +17078,5 @@ function isDeno() {
|
|
|
16674
17078
|
}
|
|
16675
17079
|
|
|
16676
17080
|
//#endregion
|
|
16677
|
-
export { listCommand$5 as $,
|
|
16678
|
-
//# sourceMappingURL=runtime-
|
|
17081
|
+
export { listCommand$5 as $, INITIAL_SCHEMA_NUMBER as $t, truncate as A, configArg as An, startCommand as At, logBetaWarning as B, getExecutor as Bt, listCommand$2 as C, generateUserTypes as Cn, triggerExecutor as Ct, resumeWorkflow as D, assertWritable as Dn, jobsCommand as Dt, resumeCommand as E, apiCall as En, getExecutorJob as Et, writeDbTypesFile as F, paginationArgs as Fn, getWorkflowExecution as Ft, organizationTree as G, MIGRATION_LABEL_KEY as Gt, removeCommand$1 as H, executeScript as Ht, getConfiguredEditorCommand as I, toPageDirection as In, listWorkflowExecutions as It, listOrganizations as J, compareSnapshotWithRemote as Jt, treeCommand as K, handleOptionalToRequiredError as Kt, openInConfiguredEditor as L, workspaceArgs as Ln, functionExecutionStatusToString as Lt, generate as M, deploymentArgs as Mn, getCommand$5 as Mt, generateCommand as N, isVerbose as Nn, getWorkflow as Nt, listCommand$3 as O, defineAppCommand as On, listExecutorJobs as Ot, generateMigrationScript as P, pagedLogArgs as Pn, executionsCommand as Pt, updateFolder as Q, DIFF_FILE_NAME as Qt, show as R, formatKeyValueTable as Rt, listApps as S, PluginManager as Sn, triggerCommand as St, healthCommand as T, apiCommand as Tn, listExecutors as Tt, updateCommand$1 as U, waitForExecution$1 as Ut, remove as V, deploy as Vt, updateOrganization as W, bundleMigrationScript as Wt, getOrganization as X, protoGqlPermission as Xt, getCommand$1 as Y, generateAllTypeManifestsFromSnapshot as Yt, updateCommand$2 as Z, DB_TYPES_FILE_NAME as Zt, getWorkspace as _, formatMigrationDiff as _n, listFunctionRegistries as _t, updateUser as a, createSnapshotFromLocalTypes as an, createCommand$1 as at, createCommand as b, resourceTrn as bn, listWebhookExecutors as bt, listCommand as c, getMigrationFilePath as cn, listOAuth2Clients as ct, inviteUser as d, isValidMigrationNumber as dn, getMachineUserToken as dt, MIGRATE_FILE_NAME as en, listFolders as et, restoreCommand as f, loadDiff as fn, tokenCommand as ft, getCommand as g, formatDiffSummary as gn, listCommand$8 as gt, listWorkspaces as h, parseMigrationNumberArg as hn, generate$1 as ht, updateCommand as i, compareSnapshots as in, deleteFolder as it, truncateCommand as j, confirmationArgs as jn, startWorkflow as jt, listWorkflows as k, commonArgs as kn, watchExecutorJob as kt, listUsers as l, getMigrationFiles as ln, getCommand$3 as lt, listCommand$1 as m, formatMigrationNumber as mn, listMachineUsers as mt, query as n, assertValidMigrationFiles as nn, getFolder as nt, removeCommand as o, getLatestMigrationNumber as on, createFolder as ot, restoreWorkspace as p, reconstructSnapshotFromMigrations as pn, listCommand$7 as pt, listCommand$4 as q, parseMigrationLabelNumber as qt, queryCommand as r, compareLocalTypesWithSnapshot as rn, deleteCommand$1 as rt, removeUser as s, getMigrationDirPath as sn, listCommand$6 as st, isNativeTypeScriptRuntime as t, SCHEMA_FILE_NAME as tn, getCommand$2 as tt, inviteCommand as u, getNextMigrationNumber as un, getOAuth2Client as ut, deleteCommand as v, hasChanges as vn, getCommand$4 as vt, getAppHealth as w, prompt as wn, listCommand$9 as wt, createWorkspace as x, sdkNameLabelKey as xn, webhookCommand as xt, deleteWorkspace as y, getNamespacesWithMigrations as yn, getFunctionRegistry as yt, showCommand as z, getCommand$6 as zt };
|
|
17082
|
+
//# sourceMappingURL=runtime-C6o4hiYq.mjs.map
|