@tailor-platform/sdk 1.60.3 → 1.63.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 +51 -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 +819 -239
- 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-C0_FZWdE.mjs → runtime-CW3jcQCc.mjs} +979 -584
- package/dist/runtime-CW3jcQCc.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/setup.md +18 -12
- package/docs/cli/tailordb.md +54 -0
- package/docs/cli-reference.md +4 -3
- package/docs/github-actions.md +337 -0
- package/docs/services/tailordb-migration.md +17 -1
- package/package.json +4 -3
- 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-C0_FZWdE.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) {
|
|
@@ -4671,13 +4677,80 @@ async function ensureConfigId(configPath) {
|
|
|
4671
4677
|
injected: true
|
|
4672
4678
|
};
|
|
4673
4679
|
}
|
|
4680
|
+
/**
|
|
4681
|
+
* Read the resolved `defineConfig({...})` `id` from a config file without
|
|
4682
|
+
* mutating it. Returns null when the file has no inline `defineConfig()` call
|
|
4683
|
+
* (wrapper/re-export config), and `{ id: null }` when the call exists but has
|
|
4684
|
+
* no usable `id` property.
|
|
4685
|
+
* @param configPath - Absolute path to the config file
|
|
4686
|
+
* @returns The existing id (or null when absent), or null for wrapper configs
|
|
4687
|
+
*/
|
|
4688
|
+
async function readConfigId(configPath) {
|
|
4689
|
+
const { program } = parseSync(configPath, await fs$1.promises.readFile(configPath, "utf-8"));
|
|
4690
|
+
const calls = [];
|
|
4691
|
+
findDefineConfigCalls(program, calls);
|
|
4692
|
+
if (calls.length === 0) return null;
|
|
4693
|
+
if (calls.length > 1) throw new Error(`Multiple defineConfig() calls found in ${configPath}. Only one is supported.`);
|
|
4694
|
+
const { configObj } = assertDefined(calls[0], "defineConfig call site missing");
|
|
4695
|
+
if (!configObj) throw new Error(`defineConfig() argument must be an inline object literal in ${configPath} so the SDK can manage the 'id' field.`);
|
|
4696
|
+
const idProp = findIdProperty(configObj);
|
|
4697
|
+
if (!idProp || idProp.value.type !== "Literal") return { id: null };
|
|
4698
|
+
const value = idProp.value.value;
|
|
4699
|
+
return { id: typeof value === "string" && value !== "" ? value : null };
|
|
4700
|
+
}
|
|
4701
|
+
/**
|
|
4702
|
+
* Read-only CI check: the config must already carry a valid app id.
|
|
4703
|
+
* Wrapper/re-export configs (no inline defineConfig call) are exempt,
|
|
4704
|
+
* mirroring the local behavior where {@link ensureConfigId} no-ops.
|
|
4705
|
+
* @param configPath - Absolute path to the config file
|
|
4706
|
+
*/
|
|
4707
|
+
async function assertConfigIdInCI(configPath) {
|
|
4708
|
+
const result = await readConfigId(configPath);
|
|
4709
|
+
if (result === null) return;
|
|
4710
|
+
if (!result.id) throw new Error("tailor.config.ts is missing an 'id'. CI does not auto-generate one (each run would be treated as a separate app and break resource ownership). Run 'tailor-sdk setup github' or 'tailor-sdk apply' locally and commit the injected id.");
|
|
4711
|
+
if (!uuidRegex.test(result.id)) throw new Error(`'id' in ${configPath} must be a UUID. To use this config for a separate app, delete it.`);
|
|
4712
|
+
}
|
|
4713
|
+
/**
|
|
4714
|
+
* Ensure the config has an app id for a deploy run.
|
|
4715
|
+
*
|
|
4716
|
+
* Locally, the id is auto-injected when missing (via {@link ensureConfigId}).
|
|
4717
|
+
* In CI, the id is never auto-injected — a missing id is a hard error, because
|
|
4718
|
+
* generating one per run would create a fresh app each time and break resource
|
|
4719
|
+
* ownership. CI dry-runs (plan) perform the same check read-only, so a
|
|
4720
|
+
* forgotten id fails at PR time instead of at deploy. Ephemeral pipelines that
|
|
4721
|
+
* intentionally deploy a fresh app per run (such as e2e harnesses) can opt
|
|
4722
|
+
* back into injection with `TAILOR_PLATFORM_SDK_ALLOW_CI_ID_INJECTION=true`.
|
|
4723
|
+
* Local dry-run and build-only flows skip both injection and the check (no
|
|
4724
|
+
* on-disk side effects are expected, and build-only never talks to the
|
|
4725
|
+
* platform).
|
|
4726
|
+
* @param obj - Inputs
|
|
4727
|
+
* @param obj.configPath - Absolute path to the config file
|
|
4728
|
+
* @param obj.dryRun - Whether this is a dry-run
|
|
4729
|
+
* @param obj.buildOnly - Whether this is a build-only run
|
|
4730
|
+
*/
|
|
4731
|
+
async function ensureConfigIdForDeploy(obj) {
|
|
4732
|
+
const { configPath, dryRun, buildOnly } = obj;
|
|
4733
|
+
if (buildOnly) return;
|
|
4734
|
+
const allowCIInjection = parseBoolean(process.env.TAILOR_PLATFORM_SDK_ALLOW_CI_ID_INJECTION) === true;
|
|
4735
|
+
const strictCI = isCI && !allowCIInjection;
|
|
4736
|
+
if (dryRun) {
|
|
4737
|
+
if (strictCI) await assertConfigIdInCI(configPath);
|
|
4738
|
+
return;
|
|
4739
|
+
}
|
|
4740
|
+
if (strictCI) {
|
|
4741
|
+
await assertConfigIdInCI(configPath);
|
|
4742
|
+
return;
|
|
4743
|
+
}
|
|
4744
|
+
await ensureConfigId(configPath);
|
|
4745
|
+
}
|
|
4674
4746
|
const idComment = "// SDK-managed app id — do not edit, except when copying this config to a separate app.";
|
|
4675
4747
|
function insertIdProperty(source, configObj, id) {
|
|
4676
4748
|
const idLiteral = `id: ${JSON.stringify(id)}`;
|
|
4677
4749
|
if (configObj.properties.length > 0) {
|
|
4678
|
-
const firstProp = configObj.properties[0];
|
|
4750
|
+
const firstProp = assertDefined(configObj.properties[0], "first property missing");
|
|
4679
4751
|
const lineStart = source.lastIndexOf("\n", firstProp.start - 1) + 1;
|
|
4680
4752
|
const indent = source.slice(lineStart, firstProp.start);
|
|
4753
|
+
if (!/^[\t ]*$/.test(indent)) return source.slice(0, firstProp.start) + `${idLiteral}, ` + source.slice(firstProp.start);
|
|
4681
4754
|
const insertion = `${idComment}\n${indent}${idLiteral},\n${indent}`;
|
|
4682
4755
|
return source.slice(0, firstProp.start) + insertion + source.slice(firstProp.start);
|
|
4683
4756
|
}
|
|
@@ -4927,7 +5000,7 @@ async function applyExecutor(client, result, phase = "create-update") {
|
|
|
4927
5000
|
await client.updateExecutorExecutor(update.request);
|
|
4928
5001
|
await client.setMetadata(update.metaRequest);
|
|
4929
5002
|
})]);
|
|
4930
|
-
else
|
|
5003
|
+
else await Promise.all(changeSet.deletes.map((del) => client.deleteExecutorExecutor(del.request)));
|
|
4931
5004
|
}
|
|
4932
5005
|
/**
|
|
4933
5006
|
* Plan executor-related changes based on current and desired state.
|
|
@@ -5042,7 +5115,7 @@ function formatExecutorChangeEntries(changeSet, executors, functionRegistryExecu
|
|
|
5042
5115
|
});
|
|
5043
5116
|
}
|
|
5044
5117
|
function normalizeComparableExecutor(executor) {
|
|
5045
|
-
const normalized = normalizeProtoConfig(executor)
|
|
5118
|
+
const normalized = normalizeProtoConfig(executor);
|
|
5046
5119
|
const webhookHeaders = normalized.targetConfig?.config?.case === "webhook" ? (normalized.targetConfig.config.value.headers ?? []).toSorted((left, right) => (left.key ?? "").localeCompare(right.key ?? "")) : void 0;
|
|
5047
5120
|
const triggerConfig = normalized.triggerConfig?.config?.case === "incomingWebhook" ? {
|
|
5048
5121
|
...normalized.triggerConfig,
|
|
@@ -5095,7 +5168,7 @@ function areExecutorsEqual(existing, desired) {
|
|
|
5095
5168
|
return areNormalizedEqual(normalizeComparableExecutor(existing), normalizeComparableExecutor(desired));
|
|
5096
5169
|
}
|
|
5097
5170
|
function resolveTailorDBNamespace(application, typeName) {
|
|
5098
|
-
for (const service of application.tailorDBServices) if (service.types
|
|
5171
|
+
for (const service of application.tailorDBServices) if (Object.hasOwn(service.types, typeName)) return service.namespace;
|
|
5099
5172
|
throw new Error(`TailorDB type "${typeName}" not found in any namespace. Available namespaces: ${application.tailorDBServices.map((s) => s.namespace).join(", ")}`);
|
|
5100
5173
|
}
|
|
5101
5174
|
function resolveResolverNamespace(application, resolverName) {
|
|
@@ -5116,7 +5189,7 @@ function resolveIdpNamespace(application, executorName, idpName) {
|
|
|
5116
5189
|
const available = application.idpServices.map((idp) => idp.name).join(", ");
|
|
5117
5190
|
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
5191
|
}
|
|
5119
|
-
return application.idpServices[0].name;
|
|
5192
|
+
return assertDefined(application.idpServices[0], "idp service missing").name;
|
|
5120
5193
|
}
|
|
5121
5194
|
function resolveAuthNamespace(application) {
|
|
5122
5195
|
if (!application.authService) throw new Error("No Auth service configured");
|
|
@@ -5345,7 +5418,7 @@ async function applyPipeline(client, result, phase = "create-update") {
|
|
|
5345
5418
|
})]);
|
|
5346
5419
|
await Promise.all([...changeSet.resolver.creates.map((create) => client.createPipelineResolver(create.request)), ...changeSet.resolver.updates.map((update) => client.updatePipelineResolver(update.request))]);
|
|
5347
5420
|
} else if (phase === "delete-resources") await Promise.all(changeSet.resolver.deletes.map((del) => client.deletePipelineResolver(del.request)));
|
|
5348
|
-
else
|
|
5421
|
+
else await Promise.all(changeSet.service.deletes.map((del) => client.deletePipelineService(del.request)));
|
|
5349
5422
|
}
|
|
5350
5423
|
/**
|
|
5351
5424
|
* Plan resolver pipeline changes based on current and desired state.
|
|
@@ -5544,7 +5617,7 @@ function formatResolverChangeEntries(changeSet, resolverFunctionChanges) {
|
|
|
5544
5617
|
}, { getNamespace: (item) => item.request.namespaceName });
|
|
5545
5618
|
}
|
|
5546
5619
|
function normalizeComparableResolver(resolver) {
|
|
5547
|
-
const normalized = normalizeProtoConfig(resolver)
|
|
5620
|
+
const normalized = normalizeProtoConfig(resolver);
|
|
5548
5621
|
return {
|
|
5549
5622
|
name: normalized.name,
|
|
5550
5623
|
description: normalized.description ?? "",
|
|
@@ -5609,7 +5682,7 @@ function processResolver(namespace, resolver, executorUsedResolvers, env, authNa
|
|
|
5609
5682
|
}];
|
|
5610
5683
|
const typeBaseName = inflection.camelize(resolver.name);
|
|
5611
5684
|
const inputs = resolver.input ? protoFields(resolver.input, `${typeBaseName}Input`, true) : [];
|
|
5612
|
-
const response = protoFields({ "": resolver.output }, `${typeBaseName}Output`, false)[0];
|
|
5685
|
+
const response = assertDefined(protoFields({ "": resolver.output }, `${typeBaseName}Output`, false)[0], "resolver output field missing");
|
|
5613
5686
|
const resolverDescription = resolver.description || `${resolver.name} resolver`;
|
|
5614
5687
|
const outputDescription = resolver.output.metadata.description;
|
|
5615
5688
|
const combinedDescription = outputDescription ? `${resolverDescription}\n\nReturns:\n${outputDescription}` : resolverDescription;
|
|
@@ -5628,7 +5701,6 @@ function processResolver(namespace, resolver, executorUsedResolvers, env, authNa
|
|
|
5628
5701
|
};
|
|
5629
5702
|
}
|
|
5630
5703
|
function protoFields(fields, baseName, isInput) {
|
|
5631
|
-
if (!fields) return [];
|
|
5632
5704
|
return Object.entries(fields).map(([fieldName, field]) => {
|
|
5633
5705
|
let type;
|
|
5634
5706
|
const required = isInput && field.metadata.hooks?.create !== void 0 ? false : field.metadata.required ?? true;
|
|
@@ -5664,6 +5736,43 @@ function protoFields(fields, baseName, isInput) {
|
|
|
5664
5736
|
//#endregion
|
|
5665
5737
|
//#region src/cli/commands/deploy/secret-manager.ts
|
|
5666
5738
|
/**
|
|
5739
|
+
* Build the CreateSecretManagerVault request for a planned vault create.
|
|
5740
|
+
* @param create - Planned vault create
|
|
5741
|
+
* @returns Request init shape
|
|
5742
|
+
*/
|
|
5743
|
+
function vaultCreateRequest(create) {
|
|
5744
|
+
return {
|
|
5745
|
+
workspaceId: create.workspaceId,
|
|
5746
|
+
secretmanagerVaultName: create.name
|
|
5747
|
+
};
|
|
5748
|
+
}
|
|
5749
|
+
/**
|
|
5750
|
+
* Build the CreateSecretManagerSecret request for a planned secret create.
|
|
5751
|
+
* @param create - Planned secret create
|
|
5752
|
+
* @returns Request init shape
|
|
5753
|
+
*/
|
|
5754
|
+
function secretCreateRequest(create) {
|
|
5755
|
+
return {
|
|
5756
|
+
workspaceId: create.workspaceId,
|
|
5757
|
+
secretmanagerVaultName: create.vaultName,
|
|
5758
|
+
secretmanagerSecretName: create.secretName,
|
|
5759
|
+
secretmanagerSecretValue: create.value
|
|
5760
|
+
};
|
|
5761
|
+
}
|
|
5762
|
+
/**
|
|
5763
|
+
* Build the UpdateSecretManagerSecret request for a planned secret update.
|
|
5764
|
+
* @param update - Planned secret update
|
|
5765
|
+
* @returns Request init shape
|
|
5766
|
+
*/
|
|
5767
|
+
function secretUpdateRequest(update) {
|
|
5768
|
+
return {
|
|
5769
|
+
workspaceId: update.workspaceId,
|
|
5770
|
+
secretmanagerVaultName: update.vaultName,
|
|
5771
|
+
secretmanagerSecretName: update.secretName,
|
|
5772
|
+
secretmanagerSecretValue: update.value
|
|
5773
|
+
};
|
|
5774
|
+
}
|
|
5775
|
+
/**
|
|
5667
5776
|
* Plan secret manager changes based on current and desired state.
|
|
5668
5777
|
* @param context - Planning context
|
|
5669
5778
|
* @returns Planned changes for vaults and secrets
|
|
@@ -5830,10 +5939,7 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5830
5939
|
const { vaultChangeSet, secretChangeSet } = result;
|
|
5831
5940
|
if (phase === "create-update") {
|
|
5832
5941
|
await Promise.all(vaultChangeSet.creates.map(async (create) => {
|
|
5833
|
-
await client.createSecretManagerVault(
|
|
5834
|
-
workspaceId: create.workspaceId,
|
|
5835
|
-
secretmanagerVaultName: create.name
|
|
5836
|
-
});
|
|
5942
|
+
await client.createSecretManagerVault(vaultCreateRequest(create));
|
|
5837
5943
|
if (application) {
|
|
5838
5944
|
const metaRequest = await buildMetaRequest({
|
|
5839
5945
|
trn: resourceTrn(create.workspaceId, "vault", create.name),
|
|
@@ -5851,27 +5957,17 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5851
5957
|
});
|
|
5852
5958
|
await client.setMetadata(metaRequest);
|
|
5853
5959
|
}));
|
|
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
|
-
})));
|
|
5960
|
+
await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret(secretCreateRequest(create))));
|
|
5961
|
+
await Promise.all(secretChangeSet.updates.map((update) => client.updateSecretManagerSecret(secretUpdateRequest(update))));
|
|
5866
5962
|
if (application) {
|
|
5867
5963
|
const state = loadSecretsState();
|
|
5868
5964
|
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);
|
|
5965
|
+
if (!Object.hasOwn(state.vaults, vault.vaultName)) state.vaults[vault.vaultName] = {};
|
|
5966
|
+
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
5967
|
}
|
|
5872
5968
|
saveSecretsState(state);
|
|
5873
5969
|
}
|
|
5874
|
-
} else
|
|
5970
|
+
} else {
|
|
5875
5971
|
await Promise.all(secretChangeSet.deletes.map((del) => client.deleteSecretManagerSecret({
|
|
5876
5972
|
workspaceId: del.workspaceId,
|
|
5877
5973
|
secretmanagerVaultName: del.vaultName,
|
|
@@ -5883,9 +5979,9 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5883
5979
|
})));
|
|
5884
5980
|
if (secretChangeSet.deletes.length > 0 || vaultChangeSet.deletes.length > 0) {
|
|
5885
5981
|
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];
|
|
5982
|
+
for (const del of secretChangeSet.deletes) if (Object.hasOwn(state.vaults, del.vaultName)) {
|
|
5983
|
+
delete assertDefined(state.vaults[del.vaultName], "vault state entry missing")[del.secretName];
|
|
5984
|
+
if (Object.keys(assertDefined(state.vaults[del.vaultName], "vault state entry missing")).length === 0) delete state.vaults[del.vaultName];
|
|
5889
5985
|
}
|
|
5890
5986
|
for (const del of vaultChangeSet.deletes) delete state.vaults[del.name];
|
|
5891
5987
|
saveSecretsState(state);
|
|
@@ -5916,7 +6012,7 @@ async function applyStaticWebsite(client, result, phase = "create-update") {
|
|
|
5916
6012
|
await client.addCustomDomain(add.request);
|
|
5917
6013
|
await client.setMetadata(add.metaRequest);
|
|
5918
6014
|
}), ...customDomainChangeSet.deletes.map((del) => client.removeCustomDomain(del.request))]);
|
|
5919
|
-
} else
|
|
6015
|
+
} else await Promise.all(changeSet.deletes.map((del) => client.deleteStaticWebsite(del.request)));
|
|
5920
6016
|
}
|
|
5921
6017
|
function customDomainTrn(workspaceId, websiteName, domain) {
|
|
5922
6018
|
return `trn:v1:workspace:${workspaceId}:staticwebsite:${websiteName}:custom_domain:${domain}`;
|
|
@@ -6296,6 +6392,24 @@ function formatDiffSummary(diff) {
|
|
|
6296
6392
|
function formatMigrationNumber(num) {
|
|
6297
6393
|
return num.toString().padStart(4, "0");
|
|
6298
6394
|
}
|
|
6395
|
+
/**
|
|
6396
|
+
* Parse a migration number CLI argument.
|
|
6397
|
+
*
|
|
6398
|
+
* Accepts the canonical 4-digit form ("0001") or a bare integer without
|
|
6399
|
+
* leading zeros ("0"–"9999"). Commands that disallow the baseline reject
|
|
6400
|
+
* 0 themselves with a context-specific message.
|
|
6401
|
+
* @param numberStr - Raw CLI argument
|
|
6402
|
+
* @returns Parsed migration number
|
|
6403
|
+
*/
|
|
6404
|
+
function parseMigrationNumberArg(numberStr) {
|
|
6405
|
+
if (/^\d{4}$/.test(numberStr)) return parseInt(numberStr, 10);
|
|
6406
|
+
if (/^(0|[1-9]\d*)$/.test(numberStr)) {
|
|
6407
|
+
const parsed = parseInt(numberStr, 10);
|
|
6408
|
+
if (parsed > 9999) throw new Error(`Migration number ${numberStr} is out of range. Expected 0-9999.`);
|
|
6409
|
+
return parsed;
|
|
6410
|
+
}
|
|
6411
|
+
throw new Error(`Invalid migration number format: ${numberStr}. Expected 4-digit format (e.g., 0001) or integer 0-9999 (e.g., 1).`);
|
|
6412
|
+
}
|
|
6299
6413
|
|
|
6300
6414
|
//#endregion
|
|
6301
6415
|
//#region src/cli/commands/tailordb/migrate/snapshot-types.ts
|
|
@@ -6675,96 +6789,112 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6675
6789
|
case "type_removed":
|
|
6676
6790
|
delete types[change.typeName];
|
|
6677
6791
|
break;
|
|
6678
|
-
case "type_modified":
|
|
6679
|
-
|
|
6792
|
+
case "type_modified": {
|
|
6793
|
+
const existing = types[change.typeName];
|
|
6794
|
+
if (existing && change.after) {
|
|
6680
6795
|
const after = change.after;
|
|
6681
6796
|
types[change.typeName] = {
|
|
6682
|
-
...
|
|
6797
|
+
...existing,
|
|
6683
6798
|
...after.indexes !== void 0 && { indexes: after.indexes },
|
|
6684
6799
|
...after.files !== void 0 && { files: after.files }
|
|
6685
6800
|
};
|
|
6686
6801
|
}
|
|
6687
6802
|
break;
|
|
6803
|
+
}
|
|
6688
6804
|
case "field_added":
|
|
6689
|
-
case "field_modified":
|
|
6690
|
-
|
|
6691
|
-
|
|
6805
|
+
case "field_modified": {
|
|
6806
|
+
const existing = types[change.typeName];
|
|
6807
|
+
if (existing && change.fieldName) types[change.typeName] = {
|
|
6808
|
+
...existing,
|
|
6692
6809
|
fields: {
|
|
6693
|
-
...
|
|
6810
|
+
...existing.fields,
|
|
6694
6811
|
[change.fieldName]: change.after
|
|
6695
6812
|
}
|
|
6696
6813
|
};
|
|
6697
6814
|
break;
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6815
|
+
}
|
|
6816
|
+
case "field_removed": {
|
|
6817
|
+
const existing = types[change.typeName];
|
|
6818
|
+
if (existing && change.fieldName) {
|
|
6819
|
+
const { [change.fieldName]: _, ...remainingFields } = existing.fields;
|
|
6701
6820
|
types[change.typeName] = {
|
|
6702
|
-
...
|
|
6821
|
+
...existing,
|
|
6703
6822
|
fields: remainingFields
|
|
6704
6823
|
};
|
|
6705
6824
|
}
|
|
6706
6825
|
break;
|
|
6826
|
+
}
|
|
6707
6827
|
case "index_added":
|
|
6708
|
-
case "index_modified":
|
|
6709
|
-
|
|
6710
|
-
|
|
6828
|
+
case "index_modified": {
|
|
6829
|
+
const existing = types[change.typeName];
|
|
6830
|
+
if (existing && change.indexName) types[change.typeName] = {
|
|
6831
|
+
...existing,
|
|
6711
6832
|
indexes: {
|
|
6712
|
-
...
|
|
6833
|
+
...existing.indexes,
|
|
6713
6834
|
[change.indexName]: change.after
|
|
6714
6835
|
}
|
|
6715
6836
|
};
|
|
6716
6837
|
break;
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6838
|
+
}
|
|
6839
|
+
case "index_removed": {
|
|
6840
|
+
const existing = types[change.typeName];
|
|
6841
|
+
if (existing && change.indexName && existing.indexes) {
|
|
6842
|
+
const { [change.indexName]: _, ...remainingIndexes } = existing.indexes;
|
|
6720
6843
|
types[change.typeName] = {
|
|
6721
|
-
...
|
|
6844
|
+
...existing,
|
|
6722
6845
|
indexes: Object.keys(remainingIndexes).length > 0 ? remainingIndexes : void 0
|
|
6723
6846
|
};
|
|
6724
6847
|
}
|
|
6725
6848
|
break;
|
|
6849
|
+
}
|
|
6726
6850
|
case "file_added":
|
|
6727
|
-
case "file_modified":
|
|
6728
|
-
|
|
6729
|
-
|
|
6851
|
+
case "file_modified": {
|
|
6852
|
+
const existing = types[change.typeName];
|
|
6853
|
+
if (existing && change.fieldName) types[change.typeName] = {
|
|
6854
|
+
...existing,
|
|
6730
6855
|
files: {
|
|
6731
|
-
...
|
|
6856
|
+
...existing.files,
|
|
6732
6857
|
[change.fieldName]: change.after
|
|
6733
6858
|
}
|
|
6734
6859
|
};
|
|
6735
6860
|
break;
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6861
|
+
}
|
|
6862
|
+
case "file_removed": {
|
|
6863
|
+
const existing = types[change.typeName];
|
|
6864
|
+
if (existing && change.fieldName && existing.files) {
|
|
6865
|
+
const { [change.fieldName]: _, ...remainingFiles } = existing.files;
|
|
6739
6866
|
types[change.typeName] = {
|
|
6740
|
-
...
|
|
6867
|
+
...existing,
|
|
6741
6868
|
files: Object.keys(remainingFiles).length > 0 ? remainingFiles : void 0
|
|
6742
6869
|
};
|
|
6743
6870
|
}
|
|
6744
6871
|
break;
|
|
6872
|
+
}
|
|
6745
6873
|
case "relationship_added":
|
|
6746
|
-
case "relationship_modified":
|
|
6747
|
-
|
|
6874
|
+
case "relationship_modified": {
|
|
6875
|
+
const existing = types[change.typeName];
|
|
6876
|
+
if (existing && change.relationshipName) {
|
|
6748
6877
|
const rel = change.after;
|
|
6749
|
-
if ((change.relationshipType ?? (
|
|
6750
|
-
...
|
|
6878
|
+
if ((change.relationshipType ?? (existing.forwardRelationships?.[change.relationshipName] ? "forward" : existing.backwardRelationships?.[change.relationshipName] ? "backward" : "forward")) === "forward") types[change.typeName] = {
|
|
6879
|
+
...existing,
|
|
6751
6880
|
forwardRelationships: {
|
|
6752
|
-
...
|
|
6881
|
+
...existing.forwardRelationships,
|
|
6753
6882
|
[change.relationshipName]: rel
|
|
6754
6883
|
}
|
|
6755
6884
|
};
|
|
6756
6885
|
else types[change.typeName] = {
|
|
6757
|
-
...
|
|
6886
|
+
...existing,
|
|
6758
6887
|
backwardRelationships: {
|
|
6759
|
-
...
|
|
6888
|
+
...existing.backwardRelationships,
|
|
6760
6889
|
[change.relationshipName]: rel
|
|
6761
6890
|
}
|
|
6762
6891
|
};
|
|
6763
6892
|
}
|
|
6764
6893
|
break;
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6894
|
+
}
|
|
6895
|
+
case "relationship_removed": {
|
|
6896
|
+
const type = types[change.typeName];
|
|
6897
|
+
if (type && change.relationshipName) {
|
|
6768
6898
|
const targetType = change.relationshipType ?? (type.forwardRelationships?.[change.relationshipName] ? "forward" : type.backwardRelationships?.[change.relationshipName] ? "backward" : null);
|
|
6769
6899
|
if (targetType === "forward" && type.forwardRelationships?.[change.relationshipName]) {
|
|
6770
6900
|
const { [change.relationshipName]: _, ...remaining } = type.forwardRelationships;
|
|
@@ -6781,11 +6911,13 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6781
6911
|
}
|
|
6782
6912
|
}
|
|
6783
6913
|
break;
|
|
6784
|
-
|
|
6785
|
-
|
|
6914
|
+
}
|
|
6915
|
+
case "permission_modified": {
|
|
6916
|
+
const existing = types[change.typeName];
|
|
6917
|
+
if (existing && change.after) {
|
|
6786
6918
|
const after = change.after;
|
|
6787
6919
|
types[change.typeName] = {
|
|
6788
|
-
...
|
|
6920
|
+
...existing,
|
|
6789
6921
|
permissions: {
|
|
6790
6922
|
record: after.recordPermission,
|
|
6791
6923
|
gql: after.gqlPermission
|
|
@@ -6793,6 +6925,7 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6793
6925
|
};
|
|
6794
6926
|
}
|
|
6795
6927
|
break;
|
|
6928
|
+
}
|
|
6796
6929
|
}
|
|
6797
6930
|
return {
|
|
6798
6931
|
...snapshot,
|
|
@@ -6869,8 +7002,10 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
6869
7002
|
const newValidate = newField.validate ?? [];
|
|
6870
7003
|
if (oldValidate.length !== newValidate.length) return true;
|
|
6871
7004
|
for (let i = 0; i < oldValidate.length; i++) {
|
|
6872
|
-
|
|
6873
|
-
|
|
7005
|
+
const oldV = assertDefined(oldValidate[i], `oldValidate missing index ${i}`);
|
|
7006
|
+
const newV = assertDefined(newValidate[i], `newValidate missing index ${i}`);
|
|
7007
|
+
if (oldV.script.expr !== newV.script.expr) return true;
|
|
7008
|
+
if (oldV.errorMessage !== newV.errorMessage) return true;
|
|
6874
7009
|
}
|
|
6875
7010
|
const oldSerial = oldField.serial;
|
|
6876
7011
|
const newSerial = newField.serial;
|
|
@@ -6887,8 +7022,10 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
6887
7022
|
const newFieldNames = Object.keys(newFields);
|
|
6888
7023
|
if (oldFieldNames.length !== newFieldNames.length) return true;
|
|
6889
7024
|
for (const fieldName of oldFieldNames) {
|
|
6890
|
-
|
|
6891
|
-
|
|
7025
|
+
const oldF = oldFields[fieldName];
|
|
7026
|
+
const newF = newFields[fieldName];
|
|
7027
|
+
if (!newF) return true;
|
|
7028
|
+
if (areFieldsDifferent(assertDefined(oldF, `field "${fieldName}" missing from oldFields`), newF)) return true;
|
|
6892
7029
|
}
|
|
6893
7030
|
return false;
|
|
6894
7031
|
}
|
|
@@ -6973,22 +7110,28 @@ function addChange(ctx, change, oldField, newField) {
|
|
|
6973
7110
|
function compareTypeFields(ctx, typeName, prevType, currType) {
|
|
6974
7111
|
const prevFieldNames = new Set(Object.keys(prevType.fields));
|
|
6975
7112
|
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
|
-
|
|
7113
|
+
for (const fieldName of currFieldNames) if (!prevFieldNames.has(fieldName)) {
|
|
7114
|
+
const currField = assertDefined(currType.fields[fieldName], `field "${fieldName}" missing from currType`);
|
|
7115
|
+
addChange(ctx, {
|
|
7116
|
+
kind: "field_added",
|
|
7117
|
+
typeName,
|
|
7118
|
+
fieldName,
|
|
7119
|
+
after: currField
|
|
7120
|
+
}, void 0, currField);
|
|
7121
|
+
}
|
|
7122
|
+
for (const fieldName of prevFieldNames) if (!currFieldNames.has(fieldName)) {
|
|
7123
|
+
const prevField = assertDefined(prevType.fields[fieldName], `field "${fieldName}" missing from prevType`);
|
|
7124
|
+
addChange(ctx, {
|
|
7125
|
+
kind: "field_removed",
|
|
7126
|
+
typeName,
|
|
7127
|
+
fieldName,
|
|
7128
|
+
before: prevField
|
|
7129
|
+
}, prevField, void 0);
|
|
7130
|
+
}
|
|
6988
7131
|
for (const fieldName of currFieldNames) {
|
|
6989
7132
|
if (!prevFieldNames.has(fieldName)) continue;
|
|
6990
|
-
const prevField = prevType.fields[fieldName];
|
|
6991
|
-
const currField = currType.fields[fieldName];
|
|
7133
|
+
const prevField = assertDefined(prevType.fields[fieldName], `field "${fieldName}" missing from prevType`);
|
|
7134
|
+
const currField = assertDefined(currType.fields[fieldName], `field "${fieldName}" missing from currType`);
|
|
6992
7135
|
if (areFieldsDifferent(prevField, currField)) addChange(ctx, {
|
|
6993
7136
|
kind: "field_modified",
|
|
6994
7137
|
typeName,
|
|
@@ -7009,21 +7152,20 @@ function compareTypeFields(ctx, typeName, prevType, currType) {
|
|
|
7009
7152
|
function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
|
|
7010
7153
|
const oldKeys = new Set(Object.keys(oldIndexes || {}));
|
|
7011
7154
|
const newKeys = new Set(Object.keys(newIndexes || {}));
|
|
7012
|
-
for (const indexName of
|
|
7155
|
+
for (const [indexName, indexConfig] of Object.entries(newIndexes ?? {})) if (!oldKeys.has(indexName)) ctx.changes.push({
|
|
7013
7156
|
kind: "index_added",
|
|
7014
7157
|
typeName,
|
|
7015
7158
|
indexName,
|
|
7016
|
-
after:
|
|
7159
|
+
after: indexConfig
|
|
7017
7160
|
});
|
|
7018
|
-
for (const indexName of
|
|
7161
|
+
for (const [indexName, indexConfig] of Object.entries(oldIndexes ?? {})) if (!newKeys.has(indexName)) ctx.changes.push({
|
|
7019
7162
|
kind: "index_removed",
|
|
7020
7163
|
typeName,
|
|
7021
7164
|
indexName,
|
|
7022
|
-
before:
|
|
7165
|
+
before: indexConfig
|
|
7023
7166
|
});
|
|
7024
|
-
for (const indexName of
|
|
7025
|
-
const oldIndex = oldIndexes[indexName];
|
|
7026
|
-
const newIndex = newIndexes[indexName];
|
|
7167
|
+
for (const [indexName, newIndex] of Object.entries(newIndexes ?? {})) if (oldKeys.has(indexName)) {
|
|
7168
|
+
const oldIndex = assertDefined(assertDefined(oldIndexes, "oldIndexes is undefined when oldKeys has entry")[indexName], `index "${indexName}" missing from oldIndexes`);
|
|
7027
7169
|
const oldFieldsStr = JSON.stringify(oldIndex.fields.toSorted());
|
|
7028
7170
|
const newFieldsStr = JSON.stringify(newIndex.fields.toSorted());
|
|
7029
7171
|
if (oldFieldsStr !== newFieldsStr || oldIndex.unique !== newIndex.unique) {
|
|
@@ -7052,26 +7194,27 @@ function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
|
|
|
7052
7194
|
function compareFiles(ctx, typeName, oldFiles, newFiles) {
|
|
7053
7195
|
const oldKeys = new Set(Object.keys(oldFiles || {}));
|
|
7054
7196
|
const newKeys = new Set(Object.keys(newFiles || {}));
|
|
7055
|
-
for (const fileName of
|
|
7197
|
+
for (const [fileName, fileDesc] of Object.entries(newFiles ?? {})) if (!oldKeys.has(fileName)) ctx.changes.push({
|
|
7056
7198
|
kind: "file_added",
|
|
7057
7199
|
typeName,
|
|
7058
7200
|
fieldName: fileName,
|
|
7059
|
-
after:
|
|
7201
|
+
after: fileDesc
|
|
7060
7202
|
});
|
|
7061
|
-
for (const fileName of
|
|
7203
|
+
for (const [fileName, fileDesc] of Object.entries(oldFiles ?? {})) if (!newKeys.has(fileName)) ctx.changes.push({
|
|
7062
7204
|
kind: "file_removed",
|
|
7063
7205
|
typeName,
|
|
7064
7206
|
fieldName: fileName,
|
|
7065
|
-
before:
|
|
7207
|
+
before: fileDesc
|
|
7066
7208
|
});
|
|
7067
|
-
for (const fileName of
|
|
7068
|
-
|
|
7209
|
+
for (const [fileName, newDesc] of Object.entries(newFiles ?? {})) if (oldKeys.has(fileName)) {
|
|
7210
|
+
const oldDesc = assertDefined(assertDefined(oldFiles, "oldFiles is undefined when oldKeys has entry")[fileName], `file "${fileName}" missing from oldFiles`);
|
|
7211
|
+
if (oldDesc !== newDesc) ctx.changes.push({
|
|
7069
7212
|
kind: "file_modified",
|
|
7070
7213
|
typeName,
|
|
7071
7214
|
fieldName: fileName,
|
|
7072
7215
|
reason: "description changed",
|
|
7073
|
-
before:
|
|
7074
|
-
after:
|
|
7216
|
+
before: oldDesc,
|
|
7217
|
+
after: newDesc
|
|
7075
7218
|
});
|
|
7076
7219
|
}
|
|
7077
7220
|
}
|
|
@@ -7087,23 +7230,22 @@ function compareFiles(ctx, typeName, oldFiles, newFiles) {
|
|
|
7087
7230
|
function compareRelationships(ctx, typeName, relationshipType, oldRelationships, newRelationships) {
|
|
7088
7231
|
const oldKeys = new Set(Object.keys(oldRelationships || {}));
|
|
7089
7232
|
const newKeys = new Set(Object.keys(newRelationships || {}));
|
|
7090
|
-
for (const relName of
|
|
7233
|
+
for (const [relName, rel] of Object.entries(newRelationships ?? {})) if (!oldKeys.has(relName)) ctx.changes.push({
|
|
7091
7234
|
kind: "relationship_added",
|
|
7092
7235
|
typeName,
|
|
7093
7236
|
relationshipName: relName,
|
|
7094
7237
|
relationshipType,
|
|
7095
|
-
after:
|
|
7238
|
+
after: rel
|
|
7096
7239
|
});
|
|
7097
|
-
for (const relName of
|
|
7240
|
+
for (const [relName, rel] of Object.entries(oldRelationships ?? {})) if (!newKeys.has(relName)) ctx.changes.push({
|
|
7098
7241
|
kind: "relationship_removed",
|
|
7099
7242
|
typeName,
|
|
7100
7243
|
relationshipName: relName,
|
|
7101
7244
|
relationshipType,
|
|
7102
|
-
before:
|
|
7245
|
+
before: rel
|
|
7103
7246
|
});
|
|
7104
|
-
for (const relName of
|
|
7105
|
-
const oldRel = oldRelationships[relName];
|
|
7106
|
-
const newRel = newRelationships[relName];
|
|
7247
|
+
for (const [relName, newRel] of Object.entries(newRelationships ?? {})) if (oldKeys.has(relName)) {
|
|
7248
|
+
const oldRel = assertDefined(assertDefined(oldRelationships, "oldRelationships is undefined when oldKeys has entry")[relName], `relationship "${relName}" missing from oldRelationships`);
|
|
7107
7249
|
const reasons = [];
|
|
7108
7250
|
if (oldRel.targetType !== newRel.targetType) reasons.push("targetType changed");
|
|
7109
7251
|
if (oldRel.targetField !== newRel.targetField) reasons.push("targetField changed");
|
|
@@ -7168,16 +7310,16 @@ function compareSnapshots(previous, current) {
|
|
|
7168
7310
|
};
|
|
7169
7311
|
const previousTypeNames = new Set(Object.keys(previous.types));
|
|
7170
7312
|
const currentTypeNames = new Set(Object.keys(current.types));
|
|
7171
|
-
for (const typeName of
|
|
7313
|
+
for (const [typeName, type] of Object.entries(current.types)) if (!previousTypeNames.has(typeName)) ctx.changes.push({
|
|
7172
7314
|
kind: "type_added",
|
|
7173
7315
|
typeName,
|
|
7174
|
-
after:
|
|
7316
|
+
after: type
|
|
7175
7317
|
});
|
|
7176
|
-
for (const typeName of
|
|
7318
|
+
for (const [typeName, type] of Object.entries(previous.types)) if (!currentTypeNames.has(typeName)) {
|
|
7177
7319
|
ctx.changes.push({
|
|
7178
7320
|
kind: "type_removed",
|
|
7179
7321
|
typeName,
|
|
7180
|
-
before:
|
|
7322
|
+
before: type
|
|
7181
7323
|
});
|
|
7182
7324
|
ctx.warnings.push({
|
|
7183
7325
|
typeName,
|
|
@@ -7186,8 +7328,8 @@ function compareSnapshots(previous, current) {
|
|
|
7186
7328
|
}
|
|
7187
7329
|
for (const typeName of currentTypeNames) {
|
|
7188
7330
|
if (!previousTypeNames.has(typeName)) continue;
|
|
7189
|
-
const prevType = previous.types[typeName];
|
|
7190
|
-
const currType = current.types[typeName];
|
|
7331
|
+
const prevType = assertDefined(previous.types[typeName], `type "${typeName}" missing from previous snapshot`);
|
|
7332
|
+
const currType = assertDefined(current.types[typeName], `type "${typeName}" missing from current snapshot`);
|
|
7191
7333
|
compareTypeFields(ctx, typeName, prevType, currType);
|
|
7192
7334
|
compareIndexes(ctx, typeName, prevType.indexes, currType.indexes);
|
|
7193
7335
|
compareFiles(ctx, typeName, prevType.files, currType.files);
|
|
@@ -7245,7 +7387,7 @@ function validateMigrationFiles(migrationsDir) {
|
|
|
7245
7387
|
const schemaFiles = [];
|
|
7246
7388
|
const diffFiles = [];
|
|
7247
7389
|
for (const file of migrationFiles) if (file.type === "schema") schemaFiles.push(file.number);
|
|
7248
|
-
else
|
|
7390
|
+
else diffFiles.push(file.number);
|
|
7249
7391
|
if (!schemaFiles.includes(0)) errors.push({
|
|
7250
7392
|
type: "missing_schema",
|
|
7251
7393
|
message: `Initial schema snapshot (${formatMigrationNumber(0)}/schema.json) is missing`,
|
|
@@ -7414,8 +7556,8 @@ function compareRemoteWithSnapshot(remoteTypes, snapshot) {
|
|
|
7414
7556
|
});
|
|
7415
7557
|
for (const typeName of snapshotTypeNames) {
|
|
7416
7558
|
if (!remoteTypeNames.has(typeName)) continue;
|
|
7417
|
-
const remoteType = remoteTypeMap.get(typeName);
|
|
7418
|
-
const snapshotType = snapshot.types[typeName];
|
|
7559
|
+
const remoteType = assertDefined(remoteTypeMap.get(typeName), `type "${typeName}" missing from remoteTypeMap`);
|
|
7560
|
+
const snapshotType = assertDefined(snapshot.types[typeName], `type "${typeName}" missing from snapshot`);
|
|
7419
7561
|
const remoteFields = convertRemoteFieldsToSnapshot(remoteType);
|
|
7420
7562
|
const snapshotFields = snapshotType.fields;
|
|
7421
7563
|
const remoteFieldNames = new Set(Object.keys(remoteFields).filter((f) => !SYSTEM_FIELDS.has(f)));
|
|
@@ -7434,7 +7576,7 @@ function compareRemoteWithSnapshot(remoteTypes, snapshot) {
|
|
|
7434
7576
|
});
|
|
7435
7577
|
for (const fieldName of snapshotFieldNames) {
|
|
7436
7578
|
if (!remoteFieldNames.has(fieldName)) continue;
|
|
7437
|
-
const drift = compareFields(typeName, fieldName, remoteFields[fieldName], snapshotFields[fieldName]);
|
|
7579
|
+
const drift = compareFields(typeName, fieldName, assertDefined(remoteFields[fieldName], `field "${fieldName}" missing from remoteFields`), assertDefined(snapshotFields[fieldName], `field "${fieldName}" missing from snapshotFields`));
|
|
7438
7580
|
if (drift) drifts.push(drift);
|
|
7439
7581
|
}
|
|
7440
7582
|
}
|
|
@@ -7752,6 +7894,145 @@ function convertOperandToProto(operand) {
|
|
|
7752
7894
|
value: fromJson(ValueSchema, operand)
|
|
7753
7895
|
} };
|
|
7754
7896
|
}
|
|
7897
|
+
/**
|
|
7898
|
+
* Generate all TailorDB type manifests from a schema snapshot
|
|
7899
|
+
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
7900
|
+
* @param {GenerateAllManifestsOptions} options - Generation options
|
|
7901
|
+
* @returns {Map<string, MessageInitShape<typeof TailorDBTypeSchema>>} Map of type name to manifest
|
|
7902
|
+
*/
|
|
7903
|
+
function generateAllTypeManifestsFromSnapshot(snapshot, options = {}) {
|
|
7904
|
+
const manifests = /* @__PURE__ */ new Map();
|
|
7905
|
+
const { executorUsedTypes, ...baseOptions } = options;
|
|
7906
|
+
for (const [typeName, snapshotType] of Object.entries(snapshot.types)) {
|
|
7907
|
+
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.`);
|
|
7908
|
+
let publishRecordEvents;
|
|
7909
|
+
if (snapshotType.settings?.publishEvents !== void 0) publishRecordEvents = snapshotType.settings.publishEvents;
|
|
7910
|
+
else if (executorUsedTypes?.has(typeName)) publishRecordEvents = true;
|
|
7911
|
+
else publishRecordEvents = baseOptions.publishRecordEvents ?? false;
|
|
7912
|
+
const typeOptions = {
|
|
7913
|
+
...baseOptions,
|
|
7914
|
+
publishRecordEvents
|
|
7915
|
+
};
|
|
7916
|
+
manifests.set(typeName, generateTailorDBTypeManifestFromSnapshot(snapshotType, typeOptions));
|
|
7917
|
+
}
|
|
7918
|
+
return manifests;
|
|
7919
|
+
}
|
|
7920
|
+
/**
|
|
7921
|
+
* Compare snapshot types with existing remote type names
|
|
7922
|
+
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
7923
|
+
* @param {ReadonlySet<string>} existingTypeNames - Set of existing type names in remote
|
|
7924
|
+
* @returns {SnapshotTypeComparison} Comparison result
|
|
7925
|
+
*/
|
|
7926
|
+
function compareSnapshotWithRemote(snapshot, existingTypeNames) {
|
|
7927
|
+
const snapshotTypeNames = new Set(Object.keys(snapshot.types));
|
|
7928
|
+
const creates = [];
|
|
7929
|
+
const updates = [];
|
|
7930
|
+
const deletes = [];
|
|
7931
|
+
for (const typeName of snapshotTypeNames) if (existingTypeNames.has(typeName)) updates.push(typeName);
|
|
7932
|
+
else creates.push(typeName);
|
|
7933
|
+
for (const typeName of existingTypeNames) if (!snapshotTypeNames.has(typeName)) deletes.push(typeName);
|
|
7934
|
+
return {
|
|
7935
|
+
creates,
|
|
7936
|
+
updates,
|
|
7937
|
+
deletes
|
|
7938
|
+
};
|
|
7939
|
+
}
|
|
7940
|
+
/**
|
|
7941
|
+
* Convert snapshot GQL permission policies to the proto request shape.
|
|
7942
|
+
* @param permission - Snapshot GQL permission policies
|
|
7943
|
+
* @returns Proto GQL permission
|
|
7944
|
+
*/
|
|
7945
|
+
function protoGqlPermission(permission) {
|
|
7946
|
+
return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
|
|
7947
|
+
}
|
|
7948
|
+
function protoGqlPolicy(policy) {
|
|
7949
|
+
const actions = [];
|
|
7950
|
+
for (const action of policy.actions) switch (action) {
|
|
7951
|
+
case "all":
|
|
7952
|
+
actions.push(TailorDBGQLPermission_Action.ALL);
|
|
7953
|
+
break;
|
|
7954
|
+
case "create":
|
|
7955
|
+
actions.push(TailorDBGQLPermission_Action.CREATE);
|
|
7956
|
+
break;
|
|
7957
|
+
case "read":
|
|
7958
|
+
actions.push(TailorDBGQLPermission_Action.READ);
|
|
7959
|
+
break;
|
|
7960
|
+
case "update":
|
|
7961
|
+
actions.push(TailorDBGQLPermission_Action.UPDATE);
|
|
7962
|
+
break;
|
|
7963
|
+
case "delete":
|
|
7964
|
+
actions.push(TailorDBGQLPermission_Action.DELETE);
|
|
7965
|
+
break;
|
|
7966
|
+
case "aggregate":
|
|
7967
|
+
actions.push(TailorDBGQLPermission_Action.AGGREGATE);
|
|
7968
|
+
break;
|
|
7969
|
+
case "bulkUpsert":
|
|
7970
|
+
actions.push(TailorDBGQLPermission_Action.BULK_UPSERT);
|
|
7971
|
+
break;
|
|
7972
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
7973
|
+
}
|
|
7974
|
+
let permit;
|
|
7975
|
+
switch (policy.permit) {
|
|
7976
|
+
case "allow":
|
|
7977
|
+
permit = TailorDBGQLPermission_Permit.ALLOW;
|
|
7978
|
+
break;
|
|
7979
|
+
case "deny":
|
|
7980
|
+
permit = TailorDBGQLPermission_Permit.DENY;
|
|
7981
|
+
break;
|
|
7982
|
+
default: throw new Error(`Unknown permission: ${policy.permit}`);
|
|
7983
|
+
}
|
|
7984
|
+
return {
|
|
7985
|
+
conditions: policy.conditions.map((cond) => protoGqlCondition(cond)),
|
|
7986
|
+
actions,
|
|
7987
|
+
permit,
|
|
7988
|
+
description: policy.description
|
|
7989
|
+
};
|
|
7990
|
+
}
|
|
7991
|
+
function protoGqlCondition(condition) {
|
|
7992
|
+
const [left, operator, right] = condition;
|
|
7993
|
+
const l = protoGqlOperand(left);
|
|
7994
|
+
const r = protoGqlOperand(right);
|
|
7995
|
+
let op;
|
|
7996
|
+
switch (operator) {
|
|
7997
|
+
case "eq":
|
|
7998
|
+
op = TailorDBGQLPermission_Operator.EQ;
|
|
7999
|
+
break;
|
|
8000
|
+
case "ne":
|
|
8001
|
+
op = TailorDBGQLPermission_Operator.NE;
|
|
8002
|
+
break;
|
|
8003
|
+
case "in":
|
|
8004
|
+
op = TailorDBGQLPermission_Operator.IN;
|
|
8005
|
+
break;
|
|
8006
|
+
case "nin":
|
|
8007
|
+
op = TailorDBGQLPermission_Operator.NIN;
|
|
8008
|
+
break;
|
|
8009
|
+
case "hasAny":
|
|
8010
|
+
op = TailorDBGQLPermission_Operator.HAS_ANY;
|
|
8011
|
+
break;
|
|
8012
|
+
case "nhasAny":
|
|
8013
|
+
op = TailorDBGQLPermission_Operator.NHAS_ANY;
|
|
8014
|
+
break;
|
|
8015
|
+
default: throw new Error(`Unknown operator: ${operator}`);
|
|
8016
|
+
}
|
|
8017
|
+
return {
|
|
8018
|
+
left: l,
|
|
8019
|
+
operator: op,
|
|
8020
|
+
right: r
|
|
8021
|
+
};
|
|
8022
|
+
}
|
|
8023
|
+
function protoGqlOperand(operand) {
|
|
8024
|
+
if (isSnapshotFieldRefOperand(operand)) {
|
|
8025
|
+
if ("user" in operand) return { kind: {
|
|
8026
|
+
case: "userField",
|
|
8027
|
+
value: operand.user
|
|
8028
|
+
} };
|
|
8029
|
+
throw new Error(`Unsupported field-ref operand in GQL permission: ${JSON.stringify(operand)} — GQL permissions only support { user } field references`);
|
|
8030
|
+
}
|
|
8031
|
+
return { kind: {
|
|
8032
|
+
case: "value",
|
|
8033
|
+
value: fromJson(ValueSchema, operand)
|
|
8034
|
+
} };
|
|
8035
|
+
}
|
|
7755
8036
|
|
|
7756
8037
|
//#endregion
|
|
7757
8038
|
//#region src/cli/commands/tailordb/migrate/pre-migration-schema.ts
|
|
@@ -7850,6 +8131,45 @@ function applyPreMigrationFieldAdjustments(fields, typeChanges) {
|
|
|
7850
8131
|
}
|
|
7851
8132
|
}
|
|
7852
8133
|
|
|
8134
|
+
//#endregion
|
|
8135
|
+
//#region src/cli/commands/tailordb/migrate/types.ts
|
|
8136
|
+
/**
|
|
8137
|
+
* Types for TailorDB migration execution
|
|
8138
|
+
*/
|
|
8139
|
+
/**
|
|
8140
|
+
* Prefix added to migration numbers in labels (required because migration names start with numbers)
|
|
8141
|
+
*/
|
|
8142
|
+
const MIGRATION_LABEL_PREFIX = "m";
|
|
8143
|
+
/**
|
|
8144
|
+
* Label key for storing migration state in TailorDB Service metadata
|
|
8145
|
+
*/
|
|
8146
|
+
const MIGRATION_LABEL_KEY = "sdk-migration";
|
|
8147
|
+
/**
|
|
8148
|
+
* Parse migration number from label value
|
|
8149
|
+
* @param {string} label - Label value (e.g., "m0001")
|
|
8150
|
+
* @returns {number | null} Parsed number or null if invalid
|
|
8151
|
+
*/
|
|
8152
|
+
function parseMigrationLabelNumber(label) {
|
|
8153
|
+
if (!label.startsWith("m")) return null;
|
|
8154
|
+
const numStr = label.slice(1);
|
|
8155
|
+
if (!/^\d+$/.test(numStr)) return null;
|
|
8156
|
+
const num = parseInt(numStr, 10);
|
|
8157
|
+
return num > 9999 ? null : num;
|
|
8158
|
+
}
|
|
8159
|
+
/**
|
|
8160
|
+
* Handle optional-to-required field change error with helpful message
|
|
8161
|
+
* @param {unknown} error - Error to handle
|
|
8162
|
+
* @param {string[]} messages - Additional messages to display
|
|
8163
|
+
*/
|
|
8164
|
+
function handleOptionalToRequiredError(error, messages) {
|
|
8165
|
+
if (error instanceof ConnectError && error.code === Code.FailedPrecondition && error.message.includes("cannot be updated from non-required to required when records exist")) {
|
|
8166
|
+
logger.error("Schema change failed: Cannot change field from optional to required when records exist.");
|
|
8167
|
+
logger.newline();
|
|
8168
|
+
for (const message of messages) logger.info(message);
|
|
8169
|
+
}
|
|
8170
|
+
throw error;
|
|
8171
|
+
}
|
|
8172
|
+
|
|
7853
8173
|
//#endregion
|
|
7854
8174
|
//#region src/cli/commands/tailordb/migrate/bundler.ts
|
|
7855
8175
|
/**
|
|
@@ -7929,28 +8249,6 @@ async function bundleMigrationScript(sourceFile, namespace, migrationNumber, env
|
|
|
7929
8249
|
};
|
|
7930
8250
|
}
|
|
7931
8251
|
|
|
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
8252
|
//#endregion
|
|
7955
8253
|
//#region src/cli/shared/script-executor.ts
|
|
7956
8254
|
/**
|
|
@@ -8155,7 +8453,7 @@ var Spinner = class {
|
|
|
8155
8453
|
#renderFrame() {
|
|
8156
8454
|
this.#stream.write(SYNC_BEGIN);
|
|
8157
8455
|
this.#clearDrawn();
|
|
8158
|
-
const frame = styles.info(FRAMES[this.#frame] ?? FRAMES[0]);
|
|
8456
|
+
const frame = styles.info(FRAMES[this.#frame] ?? assertDefined(FRAMES[0], "spinner frames empty"));
|
|
8159
8457
|
this.#frame = (this.#frame + 1) % FRAMES.length;
|
|
8160
8458
|
const line = `${" ".repeat(this.#indent)}${frame} ${this.text}`;
|
|
8161
8459
|
this.#stream.write(line);
|
|
@@ -8401,10 +8699,10 @@ async function getRemoteMigrationNumber(client, workspaceId, namespace) {
|
|
|
8401
8699
|
try {
|
|
8402
8700
|
const trn = resourceTrn(workspaceId, "tailordb", namespace);
|
|
8403
8701
|
const { metadata } = await client.getMetadata({ trn });
|
|
8404
|
-
const label = metadata?.labels
|
|
8702
|
+
const label = metadata?.labels["sdk-migration"];
|
|
8405
8703
|
if (!label) return null;
|
|
8406
8704
|
const match = label.match(/^m(\d+)$/);
|
|
8407
|
-
return match ? parseInt(match[1], 10) : null;
|
|
8705
|
+
return match ? parseInt(assertDefined(match[1], "migration label capture group missing"), 10) : null;
|
|
8408
8706
|
} catch {
|
|
8409
8707
|
return null;
|
|
8410
8708
|
}
|
|
@@ -8619,25 +8917,12 @@ async function applyTailorDB(client, result, phase = "create-update") {
|
|
|
8619
8917
|
} else if (phase === "delete-resources") {
|
|
8620
8918
|
await Promise.all(changeSet.gqlPermission.deletes.map((del) => client.deleteTailorDBGQLPermission(del.request)));
|
|
8621
8919
|
await Promise.all(changeSet.type.deletes.map((del) => client.deleteTailorDBType(del.request)));
|
|
8622
|
-
} else
|
|
8920
|
+
} else await Promise.all(changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)));
|
|
8623
8921
|
}
|
|
8624
8922
|
/**
|
|
8625
|
-
*
|
|
8626
|
-
* @param {
|
|
8627
|
-
* @
|
|
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;
|
|
8636
|
-
}
|
|
8637
|
-
/**
|
|
8638
|
-
* Get the set of type names affected by a migration
|
|
8639
|
-
* @param {PendingMigration} migration - Pending migration
|
|
8640
|
-
* @returns {Set<string>} Set of affected type names
|
|
8923
|
+
* Get the set of type names affected by a migration
|
|
8924
|
+
* @param {PendingMigration} migration - Pending migration
|
|
8925
|
+
* @returns {Set<string>} Set of affected type names
|
|
8641
8926
|
*/
|
|
8642
8927
|
function getAffectedTypeNames(migration) {
|
|
8643
8928
|
const typeNames = /* @__PURE__ */ new Set();
|
|
@@ -8746,7 +9031,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
8746
9031
|
const clonedRequest = structuredClone(create.request);
|
|
8747
9032
|
clonedRequest.tailordbType = snapshotType;
|
|
8748
9033
|
const typeChanges = typeName ? preMigrationChanges.get(typeName) : void 0;
|
|
8749
|
-
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType
|
|
9034
|
+
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
|
|
8750
9035
|
return client.createTailorDBType(clonedRequest);
|
|
8751
9036
|
}),
|
|
8752
9037
|
...changeSet.type.creates.filter((create) => {
|
|
@@ -8777,7 +9062,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
8777
9062
|
const clonedRequest = structuredClone(update.request);
|
|
8778
9063
|
clonedRequest.tailordbType = snapshotType;
|
|
8779
9064
|
const typeChanges = typeName ? preMigrationChanges.get(typeName) : void 0;
|
|
8780
|
-
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType
|
|
9065
|
+
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
|
|
8781
9066
|
return client.updateTailorDBType(clonedRequest);
|
|
8782
9067
|
})
|
|
8783
9068
|
]);
|
|
@@ -9075,17 +9360,14 @@ async function planTypes(client, workspaceId, tailordbs, executorUsedTypes, dele
|
|
|
9075
9360
|
};
|
|
9076
9361
|
for (const tailordb of tailordbs) {
|
|
9077
9362
|
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
|
-
}
|
|
9363
|
+
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
9364
|
}
|
|
9083
9365
|
for (const tailordb of tailordbs) {
|
|
9084
9366
|
const existingTypes = await fetchTypes(tailordb.namespace);
|
|
9085
9367
|
const existingTypesMap = new Map(existingTypes.map((type) => [type.name, type]));
|
|
9086
9368
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
9087
|
-
for (const typeName of Object.
|
|
9088
|
-
const tailordbType = generateTailorDBTypeManifestFromSnapshot(
|
|
9369
|
+
for (const [typeName, tailordbTypeSnapshot] of Object.entries(types)) {
|
|
9370
|
+
const tailordbType = generateTailorDBTypeManifestFromSnapshot(tailordbTypeSnapshot, {
|
|
9089
9371
|
publishRecordEvents: executorUsedTypes.has(typeName),
|
|
9090
9372
|
namespaceGqlOperations: tailordb.config.gqlOperations
|
|
9091
9373
|
});
|
|
@@ -9230,8 +9512,8 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
9230
9512
|
existingNameSet.add(gqlPermission.typeName);
|
|
9231
9513
|
});
|
|
9232
9514
|
const types = tailordb.types;
|
|
9233
|
-
for (const typeName of Object.
|
|
9234
|
-
const gqlPermission =
|
|
9515
|
+
for (const [typeName, typeEntry] of Object.entries(types)) {
|
|
9516
|
+
const gqlPermission = typeEntry.permissions?.gql;
|
|
9235
9517
|
if (!gqlPermission) continue;
|
|
9236
9518
|
const desiredPermission = protoGqlPermission(gqlPermission);
|
|
9237
9519
|
const existingPermission = existingGqlPermissions.find((entry) => entry.typeName === typeName);
|
|
@@ -9286,97 +9568,6 @@ function normalizeComparableGqlPermission(permission) {
|
|
|
9286
9568
|
actions: (policy.actions ?? []).toSorted((left, right) => left - right)
|
|
9287
9569
|
})) };
|
|
9288
9570
|
}
|
|
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
9571
|
/**
|
|
9381
9572
|
* Check if there are schema differences between migration snapshots and local definitions
|
|
9382
9573
|
* @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Snapshot-shaped local types by namespace
|
|
@@ -9454,28 +9645,30 @@ async function applyWorkflow(client, result, phase = "create-update") {
|
|
|
9454
9645
|
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, appId, result.unchangedWorkflowJobNames);
|
|
9455
9646
|
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
9456
9647
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
|
|
9648
|
+
const shape = buildWorkflowValidationShape(create.workspaceId, create.workflow);
|
|
9457
9649
|
await client.createWorkflow({
|
|
9458
|
-
workspaceId:
|
|
9459
|
-
workflowName:
|
|
9460
|
-
mainJobFunctionName:
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9650
|
+
workspaceId: shape.workspaceId,
|
|
9651
|
+
workflowName: shape.workflowName,
|
|
9652
|
+
mainJobFunctionName: shape.mainJobFunctionName,
|
|
9653
|
+
retryPolicy: shape.retryPolicy,
|
|
9654
|
+
concurrencyPolicy: shape.concurrencyPolicy,
|
|
9655
|
+
jobFunctions: filteredVersions
|
|
9464
9656
|
});
|
|
9465
9657
|
await client.setMetadata(create.metaRequest);
|
|
9466
9658
|
}), ...changeSet.updates.map(async (update) => {
|
|
9467
9659
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, update.usedJobNames);
|
|
9660
|
+
const shape = buildWorkflowValidationShape(update.workspaceId, update.workflow);
|
|
9468
9661
|
await client.updateWorkflow({
|
|
9469
|
-
workspaceId:
|
|
9470
|
-
workflowName:
|
|
9471
|
-
mainJobFunctionName:
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9662
|
+
workspaceId: shape.workspaceId,
|
|
9663
|
+
workflowName: shape.workflowName,
|
|
9664
|
+
mainJobFunctionName: shape.mainJobFunctionName,
|
|
9665
|
+
retryPolicy: shape.retryPolicy,
|
|
9666
|
+
concurrencyPolicy: shape.concurrencyPolicy,
|
|
9667
|
+
jobFunctions: filteredVersions
|
|
9475
9668
|
});
|
|
9476
9669
|
await client.setMetadata(update.metaRequest);
|
|
9477
9670
|
})]);
|
|
9478
|
-
} else
|
|
9671
|
+
} else {
|
|
9479
9672
|
await deleteAllSettled(changeSet.deletes.map((del) => ({
|
|
9480
9673
|
resourceType: "workflow",
|
|
9481
9674
|
resourceName: del.name,
|
|
@@ -9499,12 +9692,8 @@ async function deleteAllSettled(operations) {
|
|
|
9499
9692
|
const errors = [];
|
|
9500
9693
|
results.forEach((result, index) => {
|
|
9501
9694
|
if (result.status === "fulfilled") return;
|
|
9502
|
-
const operation = operations[index];
|
|
9695
|
+
const operation = assertDefined(operations[index], "operation missing at index");
|
|
9503
9696
|
const error = result.reason;
|
|
9504
|
-
if (!operation) {
|
|
9505
|
-
errors.push(error);
|
|
9506
|
-
return;
|
|
9507
|
-
}
|
|
9508
9697
|
if (error instanceof ConnectError && error.code === Code.NotFound) return;
|
|
9509
9698
|
if (error instanceof ConnectError && error.code === Code.FailedPrecondition) {
|
|
9510
9699
|
logger.warn(`Skipped deleting ${operation.resourceType} "${operation.resourceName}" because it is still referenced.`);
|
|
@@ -9615,6 +9804,21 @@ function toConcurrencyPolicy(policy) {
|
|
|
9615
9804
|
return { maxConcurrentExecutions: policy.maxConcurrentExecutions };
|
|
9616
9805
|
}
|
|
9617
9806
|
/**
|
|
9807
|
+
* Build the plan-time validation init shape for a workflow.
|
|
9808
|
+
* @param workspaceId - Workspace ID
|
|
9809
|
+
* @param workflow - Parsed workflow object
|
|
9810
|
+
* @returns Init shape suitable for validating against CreateWorkflowRequestSchema and UpdateWorkflowRequestSchema
|
|
9811
|
+
*/
|
|
9812
|
+
function buildWorkflowValidationShape(workspaceId, workflow) {
|
|
9813
|
+
return {
|
|
9814
|
+
workspaceId,
|
|
9815
|
+
workflowName: workflow.name,
|
|
9816
|
+
mainJobFunctionName: workflow.mainJob.name,
|
|
9817
|
+
...workflow.retryPolicy && { retryPolicy: toRetryPolicy(workflow.retryPolicy) },
|
|
9818
|
+
...workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(workflow.concurrencyPolicy) }
|
|
9819
|
+
};
|
|
9820
|
+
}
|
|
9821
|
+
/**
|
|
9618
9822
|
* Plan workflow changes and job functions based on current and desired state.
|
|
9619
9823
|
* @param client - Operator client instance
|
|
9620
9824
|
* @param workspaceId - Workspace ID
|
|
@@ -9814,6 +10018,191 @@ function normalizeRetryPolicyForCompare(policy) {
|
|
|
9814
10018
|
};
|
|
9815
10019
|
}
|
|
9816
10020
|
|
|
10021
|
+
//#endregion
|
|
10022
|
+
//#region src/cli/commands/deploy/validate-plan.ts
|
|
10023
|
+
function validateItems(params) {
|
|
10024
|
+
const { validator, schema, kind, action, items, requestKey, violations } = params;
|
|
10025
|
+
for (const item of items) {
|
|
10026
|
+
const init = item[requestKey];
|
|
10027
|
+
const msg = create(schema, init);
|
|
10028
|
+
const result = validator.validate(schema, msg);
|
|
10029
|
+
if (result.kind === "invalid") for (const v of result.violations) violations.push({
|
|
10030
|
+
kind,
|
|
10031
|
+
name: item.name,
|
|
10032
|
+
action,
|
|
10033
|
+
fieldPath: v.field.length > 0 ? pathToString(v.field) : "(message)",
|
|
10034
|
+
message: v.message
|
|
10035
|
+
});
|
|
10036
|
+
else if (result.kind === "error") logger.warn(`Could not validate ${kind} "${item.name}" (${action}): ${result.error.message}`);
|
|
10037
|
+
}
|
|
10038
|
+
}
|
|
10039
|
+
/**
|
|
10040
|
+
* Validate all plan-time create/update requests against buf.validate constraints embedded in the
|
|
10041
|
+
* generated proto descriptors.
|
|
10042
|
+
*
|
|
10043
|
+
* Collections not validated: idp client, tailorDB gqlPermission, functionRegistry — no
|
|
10044
|
+
* buf.validate annotations.
|
|
10045
|
+
* Application cors is excluded: static-website URL placeholders are resolved at apply time
|
|
10046
|
+
* and a bare cors array carries no constraint that would false-positive when omitted.
|
|
10047
|
+
* Workflow jobFunctions map excluded: versions are registered at apply time (registerJobFunctions)
|
|
10048
|
+
* and the map field carries no min_items constraint. Job names are validated separately via
|
|
10049
|
+
* CreateWorkflowJobFunctionRequestSchema using usedJobNames from the workflow change set.
|
|
10050
|
+
* auth idpConfig.config (provider oneof) is absent at plan time for BuiltInIdP but carries no
|
|
10051
|
+
* required constraint — the request is validated as-is from the changeset.
|
|
10052
|
+
*
|
|
10053
|
+
* @param input - Plan results from the plan phase
|
|
10054
|
+
*/
|
|
10055
|
+
async function validatePlan(input) {
|
|
10056
|
+
const { tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager } = input;
|
|
10057
|
+
const validator = createValidator();
|
|
10058
|
+
const violations = [];
|
|
10059
|
+
function creates(schema, kind, items) {
|
|
10060
|
+
validateItems({
|
|
10061
|
+
validator,
|
|
10062
|
+
schema,
|
|
10063
|
+
kind,
|
|
10064
|
+
action: "create",
|
|
10065
|
+
items,
|
|
10066
|
+
requestKey: "request",
|
|
10067
|
+
violations
|
|
10068
|
+
});
|
|
10069
|
+
}
|
|
10070
|
+
function updates(schema, kind, items) {
|
|
10071
|
+
validateItems({
|
|
10072
|
+
validator,
|
|
10073
|
+
schema,
|
|
10074
|
+
kind,
|
|
10075
|
+
action: "update",
|
|
10076
|
+
items,
|
|
10077
|
+
requestKey: "request",
|
|
10078
|
+
violations
|
|
10079
|
+
});
|
|
10080
|
+
}
|
|
10081
|
+
function replaces(schema, kind, items) {
|
|
10082
|
+
validateItems({
|
|
10083
|
+
validator,
|
|
10084
|
+
schema,
|
|
10085
|
+
kind,
|
|
10086
|
+
action: "replace",
|
|
10087
|
+
items,
|
|
10088
|
+
requestKey: "createRequest",
|
|
10089
|
+
violations
|
|
10090
|
+
});
|
|
10091
|
+
}
|
|
10092
|
+
creates(CreateTailorDBServiceRequestSchema, "TailorDB service", tailorDB.changeSet.service.creates);
|
|
10093
|
+
creates(CreateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.creates);
|
|
10094
|
+
updates(UpdateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.updates);
|
|
10095
|
+
creates(CreateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.creates);
|
|
10096
|
+
updates(UpdateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.updates);
|
|
10097
|
+
creates(AddCustomDomainRequestSchema, "StaticWebsite custom domain", staticWebsite.customDomainChangeSet.creates);
|
|
10098
|
+
creates(CreateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.creates);
|
|
10099
|
+
updates(UpdateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.updates);
|
|
10100
|
+
const idpClientVaultItems = [...idp.changeSet.client.creates.map((c) => ({
|
|
10101
|
+
clientName: c.request.client?.name ?? "",
|
|
10102
|
+
namespaceName: c.request.namespaceName ?? "",
|
|
10103
|
+
workspaceId: c.request.workspaceId ?? ""
|
|
10104
|
+
})), ...idp.changeSet.client.updates.map((u) => ({
|
|
10105
|
+
clientName: u.name,
|
|
10106
|
+
namespaceName: u.namespaceName,
|
|
10107
|
+
workspaceId: u.workspaceId
|
|
10108
|
+
}))];
|
|
10109
|
+
creates(CreateSecretManagerVaultRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
|
|
10110
|
+
name: item.clientName,
|
|
10111
|
+
request: {
|
|
10112
|
+
workspaceId: item.workspaceId,
|
|
10113
|
+
secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName)
|
|
10114
|
+
}
|
|
10115
|
+
})));
|
|
10116
|
+
creates(CreateSecretManagerSecretRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
|
|
10117
|
+
name: item.clientName,
|
|
10118
|
+
request: {
|
|
10119
|
+
workspaceId: item.workspaceId,
|
|
10120
|
+
secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName),
|
|
10121
|
+
secretmanagerSecretName: idpClientSecretName(item.namespaceName, item.clientName)
|
|
10122
|
+
}
|
|
10123
|
+
})));
|
|
10124
|
+
creates(CreateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.creates);
|
|
10125
|
+
updates(UpdateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.updates);
|
|
10126
|
+
creates(CreateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.creates);
|
|
10127
|
+
updates(UpdateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.updates);
|
|
10128
|
+
creates(CreateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.creates);
|
|
10129
|
+
updates(UpdateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.updates);
|
|
10130
|
+
creates(CreateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.creates);
|
|
10131
|
+
updates(UpdateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.updates);
|
|
10132
|
+
creates(CreateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.creates);
|
|
10133
|
+
updates(UpdateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.updates);
|
|
10134
|
+
creates(CreateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.creates);
|
|
10135
|
+
updates(UpdateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.updates);
|
|
10136
|
+
creates(CreateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.creates);
|
|
10137
|
+
updates(UpdateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.updates);
|
|
10138
|
+
creates(CreateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.creates);
|
|
10139
|
+
updates(UpdateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.updates);
|
|
10140
|
+
creates(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.creates);
|
|
10141
|
+
updates(UpdateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.updates);
|
|
10142
|
+
replaces(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.replaces);
|
|
10143
|
+
creates(CreatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.creates);
|
|
10144
|
+
updates(UpdatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.updates);
|
|
10145
|
+
creates(CreatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.creates);
|
|
10146
|
+
updates(UpdatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.updates);
|
|
10147
|
+
creates(CreateExecutorExecutorRequestSchema, "Executor", executor.changeSet.creates);
|
|
10148
|
+
updates(UpdateExecutorExecutorRequestSchema, "Executor", executor.changeSet.updates);
|
|
10149
|
+
creates(CreateWorkflowRequestSchema, "Workflow", workflow.changeSet.creates.map((item) => ({
|
|
10150
|
+
name: item.name,
|
|
10151
|
+
request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
|
|
10152
|
+
})));
|
|
10153
|
+
updates(UpdateWorkflowRequestSchema, "Workflow", workflow.changeSet.updates.map((item) => ({
|
|
10154
|
+
name: item.name,
|
|
10155
|
+
request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
|
|
10156
|
+
})));
|
|
10157
|
+
const workflowJobNameWorkspaceId = workflow.changeSet.creates[0]?.workspaceId ?? workflow.changeSet.updates[0]?.workspaceId ?? "";
|
|
10158
|
+
if (workflowJobNameWorkspaceId) {
|
|
10159
|
+
const allJobNames = /* @__PURE__ */ new Set();
|
|
10160
|
+
for (const item of [...workflow.changeSet.creates, ...workflow.changeSet.updates]) for (const jobName of item.usedJobNames) allJobNames.add(jobName);
|
|
10161
|
+
for (const jobName of workflow.unchangedWorkflowJobNames) allJobNames.add(jobName);
|
|
10162
|
+
creates(CreateWorkflowJobFunctionRequestSchema, "Workflow job function", [...allJobNames].map((jobName) => ({
|
|
10163
|
+
name: jobName,
|
|
10164
|
+
request: {
|
|
10165
|
+
workspaceId: workflowJobNameWorkspaceId,
|
|
10166
|
+
jobFunctionName: jobName,
|
|
10167
|
+
scriptRef: jobName
|
|
10168
|
+
}
|
|
10169
|
+
})));
|
|
10170
|
+
}
|
|
10171
|
+
creates(CreateSecretManagerVaultRequestSchema, "Secret Manager vault", secretManager.vaultChangeSet.creates.map((item) => ({
|
|
10172
|
+
name: item.name,
|
|
10173
|
+
request: vaultCreateRequest(item)
|
|
10174
|
+
})));
|
|
10175
|
+
creates(CreateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.creates.map((item) => ({
|
|
10176
|
+
name: item.name,
|
|
10177
|
+
request: secretCreateRequest(item)
|
|
10178
|
+
})));
|
|
10179
|
+
updates(UpdateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.updates.map((item) => ({
|
|
10180
|
+
name: item.name,
|
|
10181
|
+
request: secretUpdateRequest(item)
|
|
10182
|
+
})));
|
|
10183
|
+
creates(CreateApplicationRequestSchema, "Application", app.creates.map((item) => ({
|
|
10184
|
+
name: item.name,
|
|
10185
|
+
request: {
|
|
10186
|
+
...item.request,
|
|
10187
|
+
cors: void 0
|
|
10188
|
+
}
|
|
10189
|
+
})));
|
|
10190
|
+
updates(UpdateApplicationRequestSchema, "Application", [...app.updates, ...app.unchanged].map((item) => ({
|
|
10191
|
+
name: item.name,
|
|
10192
|
+
request: {
|
|
10193
|
+
...item.request,
|
|
10194
|
+
cors: void 0
|
|
10195
|
+
}
|
|
10196
|
+
})));
|
|
10197
|
+
creates(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.creates);
|
|
10198
|
+
replaces(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.replaces);
|
|
10199
|
+
if (violations.length === 0) return;
|
|
10200
|
+
const resourceNames = new Set(violations.map((v) => `${v.kind}:${v.name}`));
|
|
10201
|
+
logger.error(`Pre-flight validation found ${violations.length} violation(s) across ${resourceNames.size} resource(s):`);
|
|
10202
|
+
for (const v of violations) logger.log(` ${styles.resourceType(v.kind)} ${styles.resourceName(v.name)} (${v.action}) — ${styles.bold(v.fieldPath)}: ${v.message}`);
|
|
10203
|
+
throw new Error(`${violations.length} validation error(s) found in ${resourceNames.size} resource(s)`);
|
|
10204
|
+
}
|
|
10205
|
+
|
|
9817
10206
|
//#endregion
|
|
9818
10207
|
//#region src/cli/commands/deploy/deploy.ts
|
|
9819
10208
|
/**
|
|
@@ -9831,7 +10220,10 @@ function collectIdpUserTriggerTargets(application) {
|
|
|
9831
10220
|
for (const executor of Object.values(application.executorService?.executors ?? {})) {
|
|
9832
10221
|
if (executor.trigger.kind !== "idpUser") continue;
|
|
9833
10222
|
if (executor.trigger.idp != null) targets.add(executor.trigger.idp);
|
|
9834
|
-
else if (idps.length === 1)
|
|
10223
|
+
else if (idps.length === 1) {
|
|
10224
|
+
const [idp] = idps;
|
|
10225
|
+
if (idp) targets.add(idp.name);
|
|
10226
|
+
}
|
|
9835
10227
|
}
|
|
9836
10228
|
return targets;
|
|
9837
10229
|
}
|
|
@@ -9914,7 +10306,7 @@ function printPlanResults(results) {
|
|
|
9914
10306
|
...formatChangeSetEntries(results.auth.changeSet.oauth2Client, ["oauth2Client"], namespaceOf),
|
|
9915
10307
|
...formatChangeSetEntries(results.auth.changeSet.scim, ["scimConfig"], namespaceOf),
|
|
9916
10308
|
...formatChangeSetEntries(results.auth.changeSet.scimResource, ["scimResource"], namespaceOf),
|
|
9917
|
-
...
|
|
10309
|
+
...formatChangeSetEntries(results.auth.changeSet.connection, ["connection"], namespaceOf)
|
|
9918
10310
|
];
|
|
9919
10311
|
const { otherChanges: otherFunctionRegistryChanges } = splitFunctionRegistryChanges(results.functionRegistry.changeSet);
|
|
9920
10312
|
printGroupedDisplaySection(results.functionRegistry.changeSet.title, formatChangeSetEntries(otherFunctionRegistryChanges));
|
|
@@ -9997,9 +10389,13 @@ async function deploy(options) {
|
|
|
9997
10389
|
const buildOnly = options?.buildOnly ?? parseBoolean(process.env.TAILOR_PLATFORM_SDK_BUILD_ONLY) === true;
|
|
9998
10390
|
const { config, plugins } = await withSpan("build.loadConfig", async () => {
|
|
9999
10391
|
const foundPath = loadConfigPath(options?.configPath);
|
|
10000
|
-
if (foundPath
|
|
10392
|
+
if (foundPath) {
|
|
10001
10393
|
const resolvedPath = path.resolve(process.cwd(), foundPath);
|
|
10002
|
-
if (fs$1.existsSync(resolvedPath)) await
|
|
10394
|
+
if (fs$1.existsSync(resolvedPath)) await ensureConfigIdForDeploy({
|
|
10395
|
+
configPath: resolvedPath,
|
|
10396
|
+
dryRun,
|
|
10397
|
+
buildOnly
|
|
10398
|
+
});
|
|
10003
10399
|
}
|
|
10004
10400
|
return loadConfig(options?.configPath);
|
|
10005
10401
|
});
|
|
@@ -10056,10 +10452,7 @@ async function deploy(options) {
|
|
|
10056
10452
|
};
|
|
10057
10453
|
});
|
|
10058
10454
|
if (buildOnly) return { bundledScripts };
|
|
10059
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10060
|
-
useProfile: true,
|
|
10061
|
-
profile: options?.profile
|
|
10062
|
-
}));
|
|
10455
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
10063
10456
|
const workspaceId = await loadWorkspaceId({
|
|
10064
10457
|
workspaceId: options?.workspaceId,
|
|
10065
10458
|
profile: options?.profile
|
|
@@ -10204,6 +10597,19 @@ async function deploy(options) {
|
|
|
10204
10597
|
workflow,
|
|
10205
10598
|
secretManager
|
|
10206
10599
|
});
|
|
10600
|
+
if (options?.noValidate) logger.warn("Client-side validation skipped (--no-validate).");
|
|
10601
|
+
else await validatePlan({
|
|
10602
|
+
functionRegistry,
|
|
10603
|
+
tailorDB,
|
|
10604
|
+
staticWebsite,
|
|
10605
|
+
idp,
|
|
10606
|
+
auth,
|
|
10607
|
+
pipeline,
|
|
10608
|
+
app,
|
|
10609
|
+
executor,
|
|
10610
|
+
workflow,
|
|
10611
|
+
secretManager
|
|
10612
|
+
});
|
|
10207
10613
|
if (dryRun) {
|
|
10208
10614
|
logger.info("Dry run enabled. No changes applied.");
|
|
10209
10615
|
return;
|
|
@@ -10566,10 +10972,7 @@ async function resolveExecutor(client, workspaceId, name) {
|
|
|
10566
10972
|
}
|
|
10567
10973
|
async function getExecutor(options) {
|
|
10568
10974
|
const name = "name" in options ? options.name : options.executor.name;
|
|
10569
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10570
|
-
useProfile: true,
|
|
10571
|
-
profile: options.profile
|
|
10572
|
-
}));
|
|
10975
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
10573
10976
|
const workspaceId = await loadWorkspaceId({
|
|
10574
10977
|
workspaceId: options.workspaceId,
|
|
10575
10978
|
profile: options.profile
|
|
@@ -10818,10 +11221,7 @@ function parseStatus(status) {
|
|
|
10818
11221
|
}
|
|
10819
11222
|
async function listWorkflowExecutions(options) {
|
|
10820
11223
|
const workflowName = options && "workflowName" in options ? options.workflowName : options && "workflow" in options ? options.workflow?.name : void 0;
|
|
10821
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10822
|
-
useProfile: true,
|
|
10823
|
-
profile: options?.profile
|
|
10824
|
-
}));
|
|
11224
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
10825
11225
|
const workspaceId = await loadWorkspaceId({
|
|
10826
11226
|
workspaceId: options?.workspaceId,
|
|
10827
11227
|
profile: options?.profile
|
|
@@ -10858,10 +11258,7 @@ async function listWorkflowExecutions(options) {
|
|
|
10858
11258
|
* @returns Workflow execution with optional logs
|
|
10859
11259
|
*/
|
|
10860
11260
|
async function getWorkflowExecution(options) {
|
|
10861
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10862
|
-
useProfile: true,
|
|
10863
|
-
profile: options.profile
|
|
10864
|
-
}));
|
|
11261
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
10865
11262
|
const workspaceId = await loadWorkspaceId({
|
|
10866
11263
|
workspaceId: options.workspaceId,
|
|
10867
11264
|
profile: options.profile
|
|
@@ -11046,10 +11443,7 @@ async function resolveWorkflow(client, workspaceId, name) {
|
|
|
11046
11443
|
}
|
|
11047
11444
|
async function getWorkflow(options) {
|
|
11048
11445
|
const name = "name" in options ? options.name : options.workflow.name;
|
|
11049
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11050
|
-
useProfile: true,
|
|
11051
|
-
profile: options.profile
|
|
11052
|
-
}));
|
|
11446
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11053
11447
|
const workspaceId = await loadWorkspaceId({
|
|
11054
11448
|
workspaceId: options.workspaceId,
|
|
11055
11449
|
profile: options.profile
|
|
@@ -11193,10 +11587,7 @@ async function startWorkflowCore(options) {
|
|
|
11193
11587
|
}
|
|
11194
11588
|
}
|
|
11195
11589
|
async function startWorkflowByName(options) {
|
|
11196
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11197
|
-
useProfile: true,
|
|
11198
|
-
profile: options.profile
|
|
11199
|
-
}));
|
|
11590
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11200
11591
|
const workspaceId = await loadWorkspaceId({
|
|
11201
11592
|
workspaceId: options.workspaceId,
|
|
11202
11593
|
profile: options.profile
|
|
@@ -11222,10 +11613,7 @@ async function startWorkflowByName(options) {
|
|
|
11222
11613
|
async function startWorkflow(options) {
|
|
11223
11614
|
if ("name" in options) return await startWorkflowByName(options);
|
|
11224
11615
|
return await startWorkflowCore({
|
|
11225
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
11226
|
-
useProfile: true,
|
|
11227
|
-
profile: options.profile
|
|
11228
|
-
})),
|
|
11616
|
+
client: await initOperatorClient(await loadAccessToken({ profile: options.profile })),
|
|
11229
11617
|
workspaceId: await loadWorkspaceId({
|
|
11230
11618
|
workspaceId: options.workspaceId,
|
|
11231
11619
|
profile: options.profile
|
|
@@ -11288,10 +11676,7 @@ function formatTime(date) {
|
|
|
11288
11676
|
}
|
|
11289
11677
|
async function listExecutorJobs(options) {
|
|
11290
11678
|
const executorName = "executorName" in options ? options.executorName : options.executor.name;
|
|
11291
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11292
|
-
useProfile: true,
|
|
11293
|
-
profile: options.profile
|
|
11294
|
-
}));
|
|
11679
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11295
11680
|
const workspaceId = await loadWorkspaceId({
|
|
11296
11681
|
workspaceId: options.workspaceId,
|
|
11297
11682
|
profile: options.profile
|
|
@@ -11329,10 +11714,7 @@ async function listExecutorJobs(options) {
|
|
|
11329
11714
|
}
|
|
11330
11715
|
async function getExecutorJob(options) {
|
|
11331
11716
|
const executorName = "executorName" in options ? options.executorName : options.executor.name;
|
|
11332
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11333
|
-
useProfile: true,
|
|
11334
|
-
profile: options.profile
|
|
11335
|
-
}));
|
|
11717
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11336
11718
|
const workspaceId = await loadWorkspaceId({
|
|
11337
11719
|
workspaceId: options.workspaceId,
|
|
11338
11720
|
profile: options.profile
|
|
@@ -11369,10 +11751,7 @@ async function getExecutorJob(options) {
|
|
|
11369
11751
|
}
|
|
11370
11752
|
async function watchExecutorJob(options) {
|
|
11371
11753
|
const executorName = "executorName" in options ? options.executorName : options.executor.name;
|
|
11372
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11373
|
-
useProfile: true,
|
|
11374
|
-
profile: options.profile
|
|
11375
|
-
}));
|
|
11754
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11376
11755
|
const workspaceId = await loadWorkspaceId({
|
|
11377
11756
|
workspaceId: options.workspaceId,
|
|
11378
11757
|
profile: options.profile
|
|
@@ -11672,10 +12051,7 @@ const jobsCommand = defineAppCommand({
|
|
|
11672
12051
|
* @returns List of executors
|
|
11673
12052
|
*/
|
|
11674
12053
|
async function listExecutors(options) {
|
|
11675
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11676
|
-
useProfile: true,
|
|
11677
|
-
profile: options?.profile
|
|
11678
|
-
}));
|
|
12054
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
11679
12055
|
const workspaceId = await loadWorkspaceId({
|
|
11680
12056
|
workspaceId: options?.workspaceId,
|
|
11681
12057
|
profile: options?.profile
|
|
@@ -11748,10 +12124,7 @@ const headerArg = z.string().superRefine((val, ctx) => {
|
|
|
11748
12124
|
};
|
|
11749
12125
|
}).refine((h) => h.key.length > 0, { message: "Header name cannot be empty" });
|
|
11750
12126
|
async function triggerExecutorByName(options) {
|
|
11751
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11752
|
-
useProfile: true,
|
|
11753
|
-
profile: options.profile
|
|
11754
|
-
}));
|
|
12127
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11755
12128
|
const workspaceId = await loadWorkspaceId({
|
|
11756
12129
|
workspaceId: options.workspaceId,
|
|
11757
12130
|
profile: options.profile
|
|
@@ -11847,10 +12220,7 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
11847
12220
|
}).strict(),
|
|
11848
12221
|
run: async (args) => {
|
|
11849
12222
|
await assertWritable({ profile: args.profile });
|
|
11850
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11851
|
-
useProfile: true,
|
|
11852
|
-
profile: args.profile
|
|
11853
|
-
}));
|
|
12223
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: args.profile }));
|
|
11854
12224
|
const workspaceId = await loadWorkspaceId({
|
|
11855
12225
|
workspaceId: args["workspace-id"],
|
|
11856
12226
|
profile: args.profile
|
|
@@ -11938,10 +12308,7 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
11938
12308
|
* @returns List of webhook executors with URLs
|
|
11939
12309
|
*/
|
|
11940
12310
|
async function listWebhookExecutors(options) {
|
|
11941
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11942
|
-
useProfile: true,
|
|
11943
|
-
profile: options?.profile
|
|
11944
|
-
}));
|
|
12311
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
11945
12312
|
const workspaceId = await loadWorkspaceId({
|
|
11946
12313
|
workspaceId: options?.workspaceId,
|
|
11947
12314
|
profile: options?.profile
|
|
@@ -12016,12 +12383,9 @@ const getFunctionRegistryOptionsSchema = z.object({
|
|
|
12016
12383
|
});
|
|
12017
12384
|
async function loadOptions$12(options) {
|
|
12018
12385
|
const result = getFunctionRegistryOptionsSchema.safeParse(options);
|
|
12019
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
12386
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
12020
12387
|
return {
|
|
12021
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
12022
|
-
useProfile: true,
|
|
12023
|
-
profile: result.data.profile
|
|
12024
|
-
})),
|
|
12388
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
12025
12389
|
workspaceId: await loadWorkspaceId({
|
|
12026
12390
|
workspaceId: result.data.workspaceId,
|
|
12027
12391
|
profile: result.data.profile
|
|
@@ -12084,12 +12448,9 @@ const listFunctionRegistriesOptionsSchema = z.object({
|
|
|
12084
12448
|
});
|
|
12085
12449
|
async function loadOptions$11(options) {
|
|
12086
12450
|
const result = listFunctionRegistriesOptionsSchema.safeParse(options);
|
|
12087
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
12451
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
12088
12452
|
return {
|
|
12089
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
12090
|
-
useProfile: true,
|
|
12091
|
-
profile: result.data.profile
|
|
12092
|
-
})),
|
|
12453
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
12093
12454
|
workspaceId: await loadWorkspaceId({
|
|
12094
12455
|
workspaceId: result.data.workspaceId,
|
|
12095
12456
|
profile: result.data.profile
|
|
@@ -12584,13 +12945,13 @@ function createGenerationManager(params) {
|
|
|
12584
12945
|
};
|
|
12585
12946
|
}
|
|
12586
12947
|
async function processTailorDBNamespace(gen, namespace, typeInfo) {
|
|
12587
|
-
const results = generatorResults[gen.id];
|
|
12948
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12588
12949
|
results.tailordbResults[namespace] = {};
|
|
12589
12950
|
if (!gen.processType) return;
|
|
12590
12951
|
const processType = gen.processType;
|
|
12591
12952
|
await Promise.allSettled(Object.entries(typeInfo.types).map(async ([typeName, type]) => {
|
|
12592
12953
|
try {
|
|
12593
|
-
results.tailordbResults[namespace][typeName] = await processType({
|
|
12954
|
+
assertDefined(results.tailordbResults[namespace], `tailordb results not initialized for namespace ${namespace}`)[typeName] = await processType({
|
|
12594
12955
|
type,
|
|
12595
12956
|
namespace,
|
|
12596
12957
|
source: typeInfo.sourceInfo[typeName],
|
|
@@ -12613,13 +12974,13 @@ function createGenerationManager(params) {
|
|
|
12613
12974
|
else results.tailordbNamespaceResults[namespace] = results.tailordbResults[namespace];
|
|
12614
12975
|
}
|
|
12615
12976
|
async function processResolverNamespace(gen, namespace, resolvers) {
|
|
12616
|
-
const results = generatorResults[gen.id];
|
|
12977
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12617
12978
|
results.resolverResults[namespace] = {};
|
|
12618
12979
|
if (!gen.processResolver) return;
|
|
12619
12980
|
const processResolver = gen.processResolver;
|
|
12620
12981
|
await Promise.allSettled(Object.entries(resolvers).map(async ([resolverName, resolver]) => {
|
|
12621
12982
|
try {
|
|
12622
|
-
results.resolverResults[namespace][resolverName] = await processResolver({
|
|
12983
|
+
assertDefined(results.resolverResults[namespace], `resolver results not initialized for namespace ${namespace}`)[resolverName] = await processResolver({
|
|
12623
12984
|
resolver,
|
|
12624
12985
|
namespace
|
|
12625
12986
|
});
|
|
@@ -12640,7 +13001,7 @@ function createGenerationManager(params) {
|
|
|
12640
13001
|
else results.resolverNamespaceResults[namespace] = results.resolverResults[namespace];
|
|
12641
13002
|
}
|
|
12642
13003
|
async function processExecutors(gen) {
|
|
12643
|
-
const results = generatorResults[gen.id];
|
|
13004
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12644
13005
|
if (!gen.processExecutor) return;
|
|
12645
13006
|
const processExecutor = gen.processExecutor;
|
|
12646
13007
|
await Promise.allSettled(Object.entries(services.executor).map(async ([executorId, executor]) => {
|
|
@@ -12653,7 +13014,7 @@ function createGenerationManager(params) {
|
|
|
12653
13014
|
}));
|
|
12654
13015
|
}
|
|
12655
13016
|
async function aggregate(gen) {
|
|
12656
|
-
const results = generatorResults[gen.id];
|
|
13017
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12657
13018
|
const tailordbResults = [];
|
|
12658
13019
|
const resolverResults = [];
|
|
12659
13020
|
for (const [namespace, types] of Object.entries(results.tailordbNamespaceResults)) tailordbResults.push({
|
|
@@ -12711,7 +13072,7 @@ function createGenerationManager(params) {
|
|
|
12711
13072
|
let result;
|
|
12712
13073
|
switch (hookName) {
|
|
12713
13074
|
case "onTailorDBReady":
|
|
12714
|
-
result = await plugin.onTailorDBReady({
|
|
13075
|
+
result = await assertDefined(plugin.onTailorDBReady, "plugin.onTailorDBReady hook missing")({
|
|
12715
13076
|
tailordb,
|
|
12716
13077
|
auth,
|
|
12717
13078
|
baseDir: pluginBaseDir,
|
|
@@ -12720,7 +13081,7 @@ function createGenerationManager(params) {
|
|
|
12720
13081
|
});
|
|
12721
13082
|
break;
|
|
12722
13083
|
case "onResolverReady":
|
|
12723
|
-
result = await plugin.onResolverReady({
|
|
13084
|
+
result = await assertDefined(plugin.onResolverReady, "plugin.onResolverReady hook missing")({
|
|
12724
13085
|
tailordb,
|
|
12725
13086
|
resolvers: buildResolverData(),
|
|
12726
13087
|
auth,
|
|
@@ -12730,7 +13091,7 @@ function createGenerationManager(params) {
|
|
|
12730
13091
|
});
|
|
12731
13092
|
break;
|
|
12732
13093
|
case "onExecutorReady":
|
|
12733
|
-
result = await plugin.onExecutorReady({
|
|
13094
|
+
result = await assertDefined(plugin.onExecutorReady, "plugin.onExecutorReady hook missing")({
|
|
12734
13095
|
tailordb,
|
|
12735
13096
|
resolvers: buildResolverData(),
|
|
12736
13097
|
executors: { ...services.executor },
|
|
@@ -12844,7 +13205,7 @@ function createGenerationManager(params) {
|
|
|
12844
13205
|
...process.env,
|
|
12845
13206
|
TAILOR_WATCH_GENERATION: (parseInt(process.env.TAILOR_WATCH_GENERATION || "0", 10) + 1).toString()
|
|
12846
13207
|
};
|
|
12847
|
-
const child = spawn(process.argv[0], [process.argv[1], ...args], {
|
|
13208
|
+
const child = spawn(assertDefined(process.argv[0], "argv[0] missing"), [assertDefined(process.argv[1], "argv[1] missing"), ...args], {
|
|
12848
13209
|
stdio: "inherit",
|
|
12849
13210
|
env,
|
|
12850
13211
|
detached: false
|
|
@@ -12908,7 +13269,10 @@ function createGenerationManager(params) {
|
|
|
12908
13269
|
executorService: app.executorService ?? (pluginExecutorFiles.length > 0 ? createExecutorService({ config: { files: [] } }) : void 0)
|
|
12909
13270
|
};
|
|
12910
13271
|
});
|
|
12911
|
-
if (app.authService)
|
|
13272
|
+
if (app.authService) {
|
|
13273
|
+
const authService = app.authService;
|
|
13274
|
+
await withSpan("generate.resolveAuthNamespaces", async () => authService.resolveNamespaces());
|
|
13275
|
+
}
|
|
12912
13276
|
if (app.tailorDBServices.length > 0 || pluginExecutorFiles.length > 0) logger.newline();
|
|
12913
13277
|
const readyAfterTailorDB = getReadyGenerators("tailordb");
|
|
12914
13278
|
const hasOnTailorDBReady = generationPlugins.some((p) => p.onTailorDBReady != null);
|
|
@@ -12924,9 +13288,10 @@ function createGenerationManager(params) {
|
|
|
12924
13288
|
await withSpan(`generate.loadResolvers.${namespace}`, async () => {
|
|
12925
13289
|
try {
|
|
12926
13290
|
await resolverService.loadResolvers();
|
|
12927
|
-
|
|
13291
|
+
const namespaceResolvers = {};
|
|
13292
|
+
services.resolver[namespace] = namespaceResolvers;
|
|
12928
13293
|
Object.entries(resolverService.resolvers).forEach(([_, resolver]) => {
|
|
12929
|
-
|
|
13294
|
+
namespaceResolvers[resolver.name] = resolver;
|
|
12930
13295
|
});
|
|
12931
13296
|
} catch (error) {
|
|
12932
13297
|
logger.error(`Error loading resolvers for Resolver service ${styles.bold(namespace)}`);
|
|
@@ -12972,11 +13337,11 @@ function createGenerationManager(params) {
|
|
|
12972
13337
|
const app = application;
|
|
12973
13338
|
for (const db of app.tailorDBServices) {
|
|
12974
13339
|
const dbNamespace = db.namespace;
|
|
12975
|
-
await watcher
|
|
13340
|
+
await watcher.addWatchGroup(`TailorDB/${dbNamespace}`, db.config.files);
|
|
12976
13341
|
}
|
|
12977
13342
|
for (const resolverService of app.resolverServices) {
|
|
12978
13343
|
const resolverNamespace = resolverService.namespace;
|
|
12979
|
-
await watcher
|
|
13344
|
+
await watcher.addWatchGroup(`Resolver/${resolverNamespace}`, resolverService["config"].files);
|
|
12980
13345
|
}
|
|
12981
13346
|
await new Promise(() => {});
|
|
12982
13347
|
}
|
|
@@ -13040,10 +13405,7 @@ function machineUserInfo(user) {
|
|
|
13040
13405
|
* @returns List of machine users
|
|
13041
13406
|
*/
|
|
13042
13407
|
async function listMachineUsers(options) {
|
|
13043
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13044
|
-
useProfile: true,
|
|
13045
|
-
profile: options?.profile
|
|
13046
|
-
}));
|
|
13408
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13047
13409
|
const workspaceId = await loadWorkspaceId({
|
|
13048
13410
|
workspaceId: options?.workspaceId,
|
|
13049
13411
|
profile: options?.profile
|
|
@@ -13096,10 +13458,7 @@ const listCommand$7 = defineAppCommand({
|
|
|
13096
13458
|
* @returns Machine user token info
|
|
13097
13459
|
*/
|
|
13098
13460
|
async function getMachineUserToken(options) {
|
|
13099
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13100
|
-
useProfile: true,
|
|
13101
|
-
profile: options.profile
|
|
13102
|
-
}));
|
|
13461
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
13103
13462
|
const workspaceId = await loadWorkspaceId({
|
|
13104
13463
|
workspaceId: options.workspaceId,
|
|
13105
13464
|
profile: options.profile
|
|
@@ -13200,10 +13559,7 @@ function toOAuth2ClientCredentials(client) {
|
|
|
13200
13559
|
* @returns OAuth2 client credentials
|
|
13201
13560
|
*/
|
|
13202
13561
|
async function getOAuth2Client(options) {
|
|
13203
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13204
|
-
useProfile: true,
|
|
13205
|
-
profile: options.profile
|
|
13206
|
-
}));
|
|
13562
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
13207
13563
|
const workspaceId = await loadWorkspaceId({
|
|
13208
13564
|
workspaceId: options.workspaceId,
|
|
13209
13565
|
profile: options.profile
|
|
@@ -13220,7 +13576,7 @@ async function getOAuth2Client(options) {
|
|
|
13220
13576
|
namespaceName: application.authNamespace,
|
|
13221
13577
|
name: options.name
|
|
13222
13578
|
});
|
|
13223
|
-
return toOAuth2ClientCredentials(oauth2Client);
|
|
13579
|
+
return toOAuth2ClientCredentials(assertDefined(oauth2Client, "oauth2Client missing in response"));
|
|
13224
13580
|
} catch (error) {
|
|
13225
13581
|
if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`OAuth2 client '${options.name}' not found.`, { cause: error });
|
|
13226
13582
|
throw error;
|
|
@@ -13255,10 +13611,7 @@ const getCommand$3 = defineAppCommand({
|
|
|
13255
13611
|
* @returns List of OAuth2 clients
|
|
13256
13612
|
*/
|
|
13257
13613
|
async function listOAuth2Clients(options) {
|
|
13258
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13259
|
-
useProfile: true,
|
|
13260
|
-
profile: options?.profile
|
|
13261
|
-
}));
|
|
13614
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13262
13615
|
const workspaceId = await loadWorkspaceId({
|
|
13263
13616
|
workspaceId: options?.workspaceId,
|
|
13264
13617
|
profile: options?.profile
|
|
@@ -13342,7 +13695,7 @@ const createFolderOptionsSchema = z.object({
|
|
|
13342
13695
|
*/
|
|
13343
13696
|
async function createFolder(options) {
|
|
13344
13697
|
const result = createFolderOptionsSchema.safeParse(options);
|
|
13345
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13698
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13346
13699
|
const response = await (await initOperatorClient(await loadAccessToken())).createOrganizationFolder({
|
|
13347
13700
|
organizationId: result.data.organizationId,
|
|
13348
13701
|
parentFolderId: result.data.parentFolderId ?? "",
|
|
@@ -13387,7 +13740,7 @@ const deleteFolderOptionsSchema = z.object({
|
|
|
13387
13740
|
*/
|
|
13388
13741
|
async function deleteFolder(options) {
|
|
13389
13742
|
const result = deleteFolderOptionsSchema.safeParse(options);
|
|
13390
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13743
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13391
13744
|
await (await initOperatorClient(await loadAccessToken())).deleteOrganizationFolder({
|
|
13392
13745
|
organizationId: result.data.organizationId,
|
|
13393
13746
|
folderId: result.data.folderId
|
|
@@ -13440,7 +13793,7 @@ const getFolderOptionsSchema = z.object({
|
|
|
13440
13793
|
*/
|
|
13441
13794
|
async function getFolder(options) {
|
|
13442
13795
|
const result = getFolderOptionsSchema.safeParse(options);
|
|
13443
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13796
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13444
13797
|
const response = await (await initOperatorClient(await loadAccessToken())).getOrganizationFolder({
|
|
13445
13798
|
organizationId: result.data.organizationId,
|
|
13446
13799
|
folderId: result.data.folderId
|
|
@@ -13484,7 +13837,7 @@ const listFoldersOptionsSchema = z.object({
|
|
|
13484
13837
|
*/
|
|
13485
13838
|
async function listFolders(options) {
|
|
13486
13839
|
const result = listFoldersOptionsSchema.safeParse(options);
|
|
13487
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13840
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13488
13841
|
const { organizationId, parentFolderId, order, limit } = result.data;
|
|
13489
13842
|
const client = await initOperatorClient(await loadAccessToken());
|
|
13490
13843
|
const pageDirection = toPageDirection(order);
|
|
@@ -13532,7 +13885,7 @@ const updateFolderOptionsSchema = z.object({
|
|
|
13532
13885
|
*/
|
|
13533
13886
|
async function updateFolder(options) {
|
|
13534
13887
|
const result = updateFolderOptionsSchema.safeParse(options);
|
|
13535
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13888
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13536
13889
|
const response = await (await initOperatorClient(await loadAccessToken())).updateOrganizationFolder({
|
|
13537
13890
|
organizationId: result.data.organizationId,
|
|
13538
13891
|
folderId: result.data.folderId,
|
|
@@ -13574,7 +13927,7 @@ const getOrganizationOptionsSchema = z.object({ organizationId: z.uuid({ message
|
|
|
13574
13927
|
*/
|
|
13575
13928
|
async function getOrganization(options) {
|
|
13576
13929
|
const result = getOrganizationOptionsSchema.safeParse(options);
|
|
13577
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13930
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13578
13931
|
const response = await (await initOperatorClient(await loadAccessToken())).getOrganization({ organizationId: result.data.organizationId });
|
|
13579
13932
|
if (!response.organization) throw new Error(`Organization "${result.data.organizationId}" not found.`);
|
|
13580
13933
|
return organizationInfo(response.organization);
|
|
@@ -13668,12 +14021,12 @@ async function buildFolderTreeJson(client, organizationId, parentFolderId, curre
|
|
|
13668
14021
|
}
|
|
13669
14022
|
function renderTree(nodes, prefix) {
|
|
13670
14023
|
let output = "";
|
|
13671
|
-
for (
|
|
14024
|
+
for (const [i, node] of nodes.entries()) {
|
|
13672
14025
|
const isLast = i === nodes.length - 1;
|
|
13673
14026
|
const connector = isLast ? "└── " : "├── ";
|
|
13674
14027
|
const childPrefix = isLast ? " " : "│ ";
|
|
13675
|
-
output += `${prefix}${connector}${
|
|
13676
|
-
if (
|
|
14028
|
+
output += `${prefix}${connector}${node.name}\n`;
|
|
14029
|
+
if (node.children.length > 0) output += renderTree(node.children, prefix + childPrefix);
|
|
13677
14030
|
}
|
|
13678
14031
|
return output;
|
|
13679
14032
|
}
|
|
@@ -13760,7 +14113,7 @@ const updateOrganizationOptionsSchema = z.object({
|
|
|
13760
14113
|
*/
|
|
13761
14114
|
async function updateOrganization(options) {
|
|
13762
14115
|
const result = updateOrganizationOptionsSchema.safeParse(options);
|
|
13763
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
14116
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13764
14117
|
const response = await (await initOperatorClient(await loadAccessToken())).updateOrganization({
|
|
13765
14118
|
organizationId: result.data.organizationId,
|
|
13766
14119
|
organizationName: result.data.name
|
|
@@ -13792,10 +14145,7 @@ const updateCommand$1 = defineAppCommand({
|
|
|
13792
14145
|
//#endregion
|
|
13793
14146
|
//#region src/cli/commands/remove.ts
|
|
13794
14147
|
async function loadOptions$10(options) {
|
|
13795
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13796
|
-
useProfile: true,
|
|
13797
|
-
profile: options?.profile
|
|
13798
|
-
}));
|
|
14148
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13799
14149
|
const workspaceId = await loadWorkspaceId({
|
|
13800
14150
|
workspaceId: options?.workspaceId,
|
|
13801
14151
|
profile: options?.profile
|
|
@@ -13847,7 +14197,7 @@ async function execRemove(client, workspaceId, application, config, confirm) {
|
|
|
13847
14197
|
auth.changeSet.authHook.print();
|
|
13848
14198
|
auth.changeSet.scim.print();
|
|
13849
14199
|
auth.changeSet.scimResource.print();
|
|
13850
|
-
auth.changeSet.connection
|
|
14200
|
+
auth.changeSet.connection.print();
|
|
13851
14201
|
secretManager.vaultChangeSet.print();
|
|
13852
14202
|
secretManager.secretChangeSet.print();
|
|
13853
14203
|
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;
|
|
@@ -13918,6 +14268,82 @@ function logBetaWarning(featureName) {
|
|
|
13918
14268
|
logger.newline();
|
|
13919
14269
|
}
|
|
13920
14270
|
|
|
14271
|
+
//#endregion
|
|
14272
|
+
//#region src/cli/commands/workspace/transform.ts
|
|
14273
|
+
const workspaceInfo = (workspace, folderName) => {
|
|
14274
|
+
const info = {
|
|
14275
|
+
id: workspace.id,
|
|
14276
|
+
name: workspace.name,
|
|
14277
|
+
region: workspace.region,
|
|
14278
|
+
createdAt: formatTimestamp(workspace.createTime),
|
|
14279
|
+
updatedAt: formatTimestamp(workspace.updateTime)
|
|
14280
|
+
};
|
|
14281
|
+
return folderName ? {
|
|
14282
|
+
...info,
|
|
14283
|
+
folderName
|
|
14284
|
+
} : info;
|
|
14285
|
+
};
|
|
14286
|
+
const workspaceDetails = (workspace, folderName) => {
|
|
14287
|
+
return {
|
|
14288
|
+
...workspaceInfo(workspace, folderName),
|
|
14289
|
+
deleteProtection: workspace.deleteProtection,
|
|
14290
|
+
organizationId: workspace.organizationId,
|
|
14291
|
+
folderId: workspace.folderId
|
|
14292
|
+
};
|
|
14293
|
+
};
|
|
14294
|
+
async function resolveWorkspaceFolderName(client, workspace) {
|
|
14295
|
+
if (!workspace.organizationId || !workspace.folderId) return void 0;
|
|
14296
|
+
try {
|
|
14297
|
+
return (await client.getOrganizationFolder({
|
|
14298
|
+
organizationId: workspace.organizationId,
|
|
14299
|
+
folderId: workspace.folderId
|
|
14300
|
+
})).folder?.name || void 0;
|
|
14301
|
+
} catch (error) {
|
|
14302
|
+
if (error instanceof ConnectError && (error.code === Code.NotFound || error.code === Code.PermissionDenied)) return;
|
|
14303
|
+
logger.warn(`Failed to resolve workspace folder name: ${error}`);
|
|
14304
|
+
return;
|
|
14305
|
+
}
|
|
14306
|
+
}
|
|
14307
|
+
function createWorkspaceFolderNameResolver(client) {
|
|
14308
|
+
const cache = /* @__PURE__ */ new Map();
|
|
14309
|
+
return (workspace) => {
|
|
14310
|
+
if (!workspace.organizationId || !workspace.folderId) return Promise.resolve(void 0);
|
|
14311
|
+
const cacheKey = `${workspace.organizationId}/${workspace.folderId}`;
|
|
14312
|
+
const cached = cache.get(cacheKey);
|
|
14313
|
+
if (cached) return cached;
|
|
14314
|
+
const promise = resolveWorkspaceFolderName(client, workspace);
|
|
14315
|
+
cache.set(cacheKey, promise);
|
|
14316
|
+
return promise;
|
|
14317
|
+
};
|
|
14318
|
+
}
|
|
14319
|
+
async function workspaceInfoWithFolderName(client, workspace) {
|
|
14320
|
+
return workspaceInfo(workspace, await resolveWorkspaceFolderName(client, workspace));
|
|
14321
|
+
}
|
|
14322
|
+
async function workspaceDetailsWithFolderName(client, workspace) {
|
|
14323
|
+
return workspaceDetails(workspace, await resolveWorkspaceFolderName(client, workspace));
|
|
14324
|
+
}
|
|
14325
|
+
async function workspaceInfosWithFolderNames(client, workspaces) {
|
|
14326
|
+
const resolveFolderName = createWorkspaceFolderNameResolver(client);
|
|
14327
|
+
const limit = pLimit(5);
|
|
14328
|
+
return Promise.all(workspaces.map((workspace) => limit(async () => workspaceInfo(workspace, await resolveFolderName(workspace)))));
|
|
14329
|
+
}
|
|
14330
|
+
function workspaceDisplayName(workspace) {
|
|
14331
|
+
return workspace.folderName ? `${workspace.folderName}/${workspace.name}` : workspace.name;
|
|
14332
|
+
}
|
|
14333
|
+
function createWorkspaceNameTransformer(nameKey, folderNameKey) {
|
|
14334
|
+
return (value, item) => {
|
|
14335
|
+
const workspace = item;
|
|
14336
|
+
const name = workspace[nameKey];
|
|
14337
|
+
const folderName = workspace[folderNameKey];
|
|
14338
|
+
if (typeof name === "string" && typeof folderName === "string") return workspaceDisplayName({
|
|
14339
|
+
name,
|
|
14340
|
+
folderName
|
|
14341
|
+
});
|
|
14342
|
+
return String(value ?? "");
|
|
14343
|
+
};
|
|
14344
|
+
}
|
|
14345
|
+
const workspaceNameTransformer = createWorkspaceNameTransformer("name", "folderName");
|
|
14346
|
+
|
|
13921
14347
|
//#endregion
|
|
13922
14348
|
//#region src/cli/commands/show.ts
|
|
13923
14349
|
function applicationInfo(app) {
|
|
@@ -13939,10 +14365,7 @@ function applicationInfo(app) {
|
|
|
13939
14365
|
* @returns Application information
|
|
13940
14366
|
*/
|
|
13941
14367
|
async function show(options) {
|
|
13942
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13943
|
-
useProfile: true,
|
|
13944
|
-
profile: options?.profile
|
|
13945
|
-
}));
|
|
14368
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13946
14369
|
const workspaceId = await loadWorkspaceId({
|
|
13947
14370
|
workspaceId: options?.workspaceId,
|
|
13948
14371
|
profile: options?.profile
|
|
@@ -13952,15 +14375,19 @@ async function show(options) {
|
|
|
13952
14375
|
workspaceId,
|
|
13953
14376
|
applicationName: config.name
|
|
13954
14377
|
})]);
|
|
13955
|
-
const { name, ...appInfo } = applicationInfo(resp.application);
|
|
14378
|
+
const { name, ...appInfo } = applicationInfo(assertDefined(resp.application, `application "${config.name}" not found in workspace`));
|
|
14379
|
+
const workspace = workspaceResp.workspace;
|
|
14380
|
+
const workspaceFolderName = workspace ? await resolveWorkspaceFolderName(client, workspace) : "";
|
|
13956
14381
|
return {
|
|
13957
14382
|
name,
|
|
13958
14383
|
workspaceId,
|
|
13959
|
-
workspaceName:
|
|
13960
|
-
|
|
14384
|
+
workspaceName: workspace?.name ?? "",
|
|
14385
|
+
...workspaceFolderName ? { workspaceFolderName } : {},
|
|
14386
|
+
workspaceRegion: workspace?.region ?? "",
|
|
13961
14387
|
...appInfo
|
|
13962
14388
|
};
|
|
13963
14389
|
}
|
|
14390
|
+
const showWorkspaceNameTransformer = createWorkspaceNameTransformer("workspaceName", "workspaceFolderName");
|
|
13964
14391
|
const showCommand = defineAppCommand({
|
|
13965
14392
|
name: "show",
|
|
13966
14393
|
description: "Show information about the deployed application.",
|
|
@@ -13971,7 +14398,10 @@ const showCommand = defineAppCommand({
|
|
|
13971
14398
|
profile: args.profile,
|
|
13972
14399
|
configPath: args.config
|
|
13973
14400
|
});
|
|
13974
|
-
logger.out(appInfo
|
|
14401
|
+
logger.out(appInfo, { display: {
|
|
14402
|
+
workspaceName: showWorkspaceNameTransformer,
|
|
14403
|
+
workspaceFolderName: null
|
|
14404
|
+
} });
|
|
13975
14405
|
}
|
|
13976
14406
|
});
|
|
13977
14407
|
|
|
@@ -14060,7 +14490,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
14060
14490
|
const { before, after } = change;
|
|
14061
14491
|
if (before && after && !before.required && after.required) {
|
|
14062
14492
|
if (!optionalToRequired.has(change.typeName)) optionalToRequired.set(change.typeName, /* @__PURE__ */ new Set());
|
|
14063
|
-
optionalToRequired.get(change.typeName).add(change.fieldName);
|
|
14493
|
+
assertDefined(optionalToRequired.get(change.typeName), "optionalToRequired entry missing").add(change.fieldName);
|
|
14064
14494
|
}
|
|
14065
14495
|
if (before && after && before.type === "enum" && after.type === "enum" && before.allowedValues && after.allowedValues) {
|
|
14066
14496
|
const beforeValues = before.allowedValues.map((v) => v.value);
|
|
@@ -14069,7 +14499,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
14069
14499
|
const afterSet = new Set(afterValues);
|
|
14070
14500
|
if (beforeValues.some((v) => !afterSet.has(v)) || afterValues.some((v) => !beforeSet.has(v))) {
|
|
14071
14501
|
if (!enumValueChanges.has(change.typeName)) enumValueChanges.set(change.typeName, /* @__PURE__ */ new Map());
|
|
14072
|
-
enumValueChanges.get(change.typeName).set(change.fieldName, {
|
|
14502
|
+
assertDefined(enumValueChanges.get(change.typeName), "enumValueChanges entry missing").set(change.fieldName, {
|
|
14073
14503
|
beforeValues,
|
|
14074
14504
|
afterValues
|
|
14075
14505
|
});
|
|
@@ -14079,7 +14509,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
14079
14509
|
const { after } = change;
|
|
14080
14510
|
if (after && after.required) {
|
|
14081
14511
|
if (!addedRequiredFields.has(change.typeName)) addedRequiredFields.set(change.typeName, /* @__PURE__ */ new Map());
|
|
14082
|
-
addedRequiredFields.get(change.typeName).set(change.fieldName, after);
|
|
14512
|
+
assertDefined(addedRequiredFields.get(change.typeName), "addedRequiredFields entry missing").set(change.fieldName, after);
|
|
14083
14513
|
}
|
|
14084
14514
|
}
|
|
14085
14515
|
return {
|
|
@@ -14561,7 +14991,7 @@ async function generate(options) {
|
|
|
14561
14991
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
14562
14992
|
let pluginManager;
|
|
14563
14993
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
14564
|
-
const { defineApplication } = await import("./application-
|
|
14994
|
+
const { defineApplication } = await import("./application-DSXntqnV.mjs");
|
|
14565
14995
|
const application = defineApplication({
|
|
14566
14996
|
config,
|
|
14567
14997
|
pluginManager
|
|
@@ -14732,7 +15162,7 @@ function extractAllNamespaces(config) {
|
|
|
14732
15162
|
function extractOwnedNamespaces(config) {
|
|
14733
15163
|
const namespaces = /* @__PURE__ */ new Set();
|
|
14734
15164
|
if (config.db) for (const [namespaceName, nsConfig] of Object.entries(config.db)) {
|
|
14735
|
-
if ("external" in nsConfig
|
|
15165
|
+
if ("external" in nsConfig) continue;
|
|
14736
15166
|
namespaces.add(namespaceName);
|
|
14737
15167
|
}
|
|
14738
15168
|
return Array.from(namespaces);
|
|
@@ -14809,18 +15239,15 @@ async function truncate(options) {
|
|
|
14809
15239
|
yes: true
|
|
14810
15240
|
});
|
|
14811
15241
|
}
|
|
14812
|
-
async function $truncate(options) {
|
|
14813
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14814
|
-
useProfile: true,
|
|
14815
|
-
profile: options?.profile
|
|
14816
|
-
}));
|
|
15242
|
+
async function $truncate(options = {}) {
|
|
15243
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
14817
15244
|
const workspaceId = await loadWorkspaceId({
|
|
14818
|
-
workspaceId: options
|
|
14819
|
-
profile: options
|
|
15245
|
+
workspaceId: options.workspaceId,
|
|
15246
|
+
profile: options.profile
|
|
14820
15247
|
});
|
|
14821
|
-
const hasTypes = options
|
|
14822
|
-
const hasNamespace = !!options
|
|
14823
|
-
const hasAll = !!options
|
|
15248
|
+
const hasTypes = options.types && options.types.length > 0;
|
|
15249
|
+
const hasNamespace = !!options.namespace;
|
|
15250
|
+
const hasAll = !!options.all;
|
|
14824
15251
|
const optionCount = [
|
|
14825
15252
|
hasAll,
|
|
14826
15253
|
hasNamespace,
|
|
@@ -14828,14 +15255,14 @@ async function $truncate(options) {
|
|
|
14828
15255
|
].filter(Boolean).length;
|
|
14829
15256
|
if (optionCount === 0) throw new Error("Please specify one of: --all, --namespace <name>, or type names");
|
|
14830
15257
|
if (optionCount > 1) throw new Error("Options --all, --namespace, and type names are mutually exclusive. Please specify only one.");
|
|
14831
|
-
const { config } = await loadConfig(options
|
|
15258
|
+
const { config } = await loadConfig(options.configPath);
|
|
14832
15259
|
const namespaces = extractOwnedNamespaces(config);
|
|
14833
15260
|
if (hasAll) {
|
|
14834
15261
|
if (namespaces.length === 0) {
|
|
14835
15262
|
logger.warn("No namespaces found in config file.");
|
|
14836
15263
|
return;
|
|
14837
15264
|
}
|
|
14838
|
-
if (!options
|
|
15265
|
+
if (!options.yes) {
|
|
14839
15266
|
const namespaceList = namespaces.join(", ");
|
|
14840
15267
|
if (!await prompt.confirm({
|
|
14841
15268
|
message: `This will truncate ALL tables in the following owned namespaces (external namespaces are excluded): ${namespaceList}. Continue?`,
|
|
@@ -14849,11 +15276,11 @@ async function $truncate(options) {
|
|
|
14849
15276
|
logger.success("Truncated all tables in all owned namespaces");
|
|
14850
15277
|
return;
|
|
14851
15278
|
}
|
|
14852
|
-
if (hasNamespace
|
|
14853
|
-
const namespace = options.namespace;
|
|
15279
|
+
if (hasNamespace) {
|
|
15280
|
+
const namespace = assertDefined(options.namespace, "namespace option missing");
|
|
14854
15281
|
if (!namespaces.includes(namespace)) {
|
|
14855
15282
|
const dbConfig = config.db?.[namespace];
|
|
14856
|
-
if (dbConfig && "external" in dbConfig
|
|
15283
|
+
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.`);
|
|
14857
15284
|
throw new Error(`Namespace "${namespace}" not found in config. Available owned namespaces (external namespaces are excluded): ${namespaces.join(", ")}`);
|
|
14858
15285
|
}
|
|
14859
15286
|
if (!options.yes) {
|
|
@@ -14868,8 +15295,8 @@ async function $truncate(options) {
|
|
|
14868
15295
|
await truncateNamespace(workspaceId, namespace, client);
|
|
14869
15296
|
return;
|
|
14870
15297
|
}
|
|
14871
|
-
if (hasTypes
|
|
14872
|
-
const typeNames = options.types;
|
|
15298
|
+
if (hasTypes) {
|
|
15299
|
+
const typeNames = assertDefined(options.types, "types option missing");
|
|
14873
15300
|
const typeNamespaceMap = await resolveTypeNamespaces({
|
|
14874
15301
|
workspaceId,
|
|
14875
15302
|
namespaces,
|
|
@@ -14941,10 +15368,7 @@ const truncateCommand = defineAppCommand({
|
|
|
14941
15368
|
* @returns List of workflows
|
|
14942
15369
|
*/
|
|
14943
15370
|
async function listWorkflows(options) {
|
|
14944
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14945
|
-
useProfile: true,
|
|
14946
|
-
profile: options?.profile
|
|
14947
|
-
}));
|
|
15371
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
14948
15372
|
const workspaceId = await loadWorkspaceId({
|
|
14949
15373
|
workspaceId: options?.workspaceId,
|
|
14950
15374
|
profile: options?.profile
|
|
@@ -14991,10 +15415,7 @@ const listCommand$3 = defineAppCommand({
|
|
|
14991
15415
|
* @returns Resume result with wait helper
|
|
14992
15416
|
*/
|
|
14993
15417
|
async function resumeWorkflow(options) {
|
|
14994
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14995
|
-
useProfile: true,
|
|
14996
|
-
profile: options.profile
|
|
14997
|
-
}));
|
|
15418
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
14998
15419
|
const workspaceId = await loadWorkspaceId({
|
|
14999
15420
|
workspaceId: options.workspaceId,
|
|
15000
15421
|
profile: options.profile
|
|
@@ -15102,12 +15523,9 @@ const healthOptionsSchema = z.object({
|
|
|
15102
15523
|
});
|
|
15103
15524
|
async function loadOptions$9(options) {
|
|
15104
15525
|
const result = healthOptionsSchema.safeParse(options);
|
|
15105
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15526
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15106
15527
|
return {
|
|
15107
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15108
|
-
useProfile: true,
|
|
15109
|
-
profile: result.data.profile
|
|
15110
|
-
})),
|
|
15528
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15111
15529
|
workspaceId: await loadWorkspaceId({
|
|
15112
15530
|
workspaceId: result.data.workspaceId,
|
|
15113
15531
|
profile: result.data.profile
|
|
@@ -15162,12 +15580,9 @@ const listAppsOptionsSchema = z.object({
|
|
|
15162
15580
|
});
|
|
15163
15581
|
async function loadOptions$8(options) {
|
|
15164
15582
|
const result = listAppsOptionsSchema.safeParse(options);
|
|
15165
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15583
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15166
15584
|
return {
|
|
15167
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15168
|
-
useProfile: true,
|
|
15169
|
-
profile: result.data.profile
|
|
15170
|
-
})),
|
|
15585
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15171
15586
|
workspaceId: await loadWorkspaceId({
|
|
15172
15587
|
workspaceId: result.data.workspaceId,
|
|
15173
15588
|
profile: result.data.profile
|
|
@@ -15217,26 +15632,6 @@ const listCommand$2 = defineAppCommand({
|
|
|
15217
15632
|
}
|
|
15218
15633
|
});
|
|
15219
15634
|
|
|
15220
|
-
//#endregion
|
|
15221
|
-
//#region src/cli/commands/workspace/transform.ts
|
|
15222
|
-
const workspaceInfo = (workspace) => {
|
|
15223
|
-
return {
|
|
15224
|
-
id: workspace.id,
|
|
15225
|
-
name: workspace.name,
|
|
15226
|
-
region: workspace.region,
|
|
15227
|
-
createdAt: formatTimestamp(workspace.createTime),
|
|
15228
|
-
updatedAt: formatTimestamp(workspace.updateTime)
|
|
15229
|
-
};
|
|
15230
|
-
};
|
|
15231
|
-
const workspaceDetails = (workspace) => {
|
|
15232
|
-
return {
|
|
15233
|
-
...workspaceInfo(workspace),
|
|
15234
|
-
deleteProtection: workspace.deleteProtection,
|
|
15235
|
-
organizationId: workspace.organizationId,
|
|
15236
|
-
folderId: workspace.folderId
|
|
15237
|
-
};
|
|
15238
|
-
};
|
|
15239
|
-
|
|
15240
15635
|
//#endregion
|
|
15241
15636
|
//#region src/cli/commands/workspace/create.ts
|
|
15242
15637
|
/**
|
|
@@ -15262,17 +15657,17 @@ const validateRegion = async (region, client) => {
|
|
|
15262
15657
|
*/
|
|
15263
15658
|
async function createWorkspace(options) {
|
|
15264
15659
|
const result = createWorkspaceOptionsSchema.safeParse(options);
|
|
15265
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15660
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15266
15661
|
const validated = result.data;
|
|
15267
15662
|
const client = await initOperatorClient(await loadAccessToken());
|
|
15268
15663
|
await validateRegion(validated.region, client);
|
|
15269
|
-
return
|
|
15664
|
+
return workspaceInfoWithFolderName(client, assertDefined((await client.createWorkspace({
|
|
15270
15665
|
workspaceName: validated.name,
|
|
15271
15666
|
workspaceRegion: validated.region,
|
|
15272
15667
|
deleteProtection: validated.deleteProtection ?? false,
|
|
15273
15668
|
organizationId: validated.organizationId,
|
|
15274
15669
|
folderId: validated.folderId
|
|
15275
|
-
})).workspace);
|
|
15670
|
+
})).workspace, "createWorkspace response missing workspace"));
|
|
15276
15671
|
}
|
|
15277
15672
|
const createCommand = defineAppCommand({
|
|
15278
15673
|
name: "create",
|
|
@@ -15338,7 +15733,7 @@ const createCommand = defineAppCommand({
|
|
|
15338
15733
|
};
|
|
15339
15734
|
if (!args.json) logger.success(`Profile "${profileName}" created successfully.`);
|
|
15340
15735
|
}
|
|
15341
|
-
if (!args.json) logger.success(`Workspace "${
|
|
15736
|
+
if (!args.json) logger.success(`Workspace "${workspaceDisplayName(workspace)}" created successfully.`);
|
|
15342
15737
|
if (args.json && profileInfo) {
|
|
15343
15738
|
logger.out({
|
|
15344
15739
|
...workspace,
|
|
@@ -15346,7 +15741,10 @@ const createCommand = defineAppCommand({
|
|
|
15346
15741
|
});
|
|
15347
15742
|
return;
|
|
15348
15743
|
}
|
|
15349
|
-
logger.out(workspace
|
|
15744
|
+
logger.out(workspace, { display: {
|
|
15745
|
+
name: workspaceNameTransformer,
|
|
15746
|
+
folderName: null
|
|
15747
|
+
} });
|
|
15350
15748
|
if (profileInfo) {
|
|
15351
15749
|
logger.out("Profile:");
|
|
15352
15750
|
logger.out(profileInfo);
|
|
@@ -15359,7 +15757,7 @@ const createCommand = defineAppCommand({
|
|
|
15359
15757
|
const deleteWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
|
|
15360
15758
|
async function loadOptions$7(options) {
|
|
15361
15759
|
const result = deleteWorkspaceOptionsSchema.safeParse(options);
|
|
15362
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15760
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15363
15761
|
return {
|
|
15364
15762
|
client: await initOperatorClient(await loadAccessToken()),
|
|
15365
15763
|
workspaceId: result.data.workspaceId
|
|
@@ -15393,8 +15791,15 @@ const deleteCommand = defineAppCommand({
|
|
|
15393
15791
|
} catch {
|
|
15394
15792
|
throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
15395
15793
|
}
|
|
15794
|
+
const workspaceResource = workspace.workspace;
|
|
15795
|
+
const workspaceName = workspaceResource?.name ?? workspaceId;
|
|
15796
|
+
const displayName = workspaceDisplayName({
|
|
15797
|
+
name: workspaceName,
|
|
15798
|
+
folderName: workspaceResource ? await resolveWorkspaceFolderName(client, workspaceResource) : ""
|
|
15799
|
+
});
|
|
15396
15800
|
if (!args.yes) {
|
|
15397
|
-
|
|
15801
|
+
const confirmation = await prompt.text({ message: `Enter the workspace name to confirm deletion (${displayName}):` });
|
|
15802
|
+
if (confirmation !== workspaceName && confirmation !== displayName) {
|
|
15398
15803
|
logger.info("Workspace deletion cancelled.");
|
|
15399
15804
|
return;
|
|
15400
15805
|
}
|
|
@@ -15406,8 +15811,8 @@ const deleteCommand = defineAppCommand({
|
|
|
15406
15811
|
for (const [profileName] of profilesToDelete) delete pfConfig.profiles[profileName];
|
|
15407
15812
|
writePlatformConfig(pfConfig);
|
|
15408
15813
|
}
|
|
15409
|
-
if (profilesToDelete.length > 0) logger.success(`Workspace "${
|
|
15410
|
-
else logger.success(`Workspace "${
|
|
15814
|
+
if (profilesToDelete.length > 0) logger.success(`Workspace "${displayName}" and ${profilesToDelete.length} associated profile(s) deleted successfully.`);
|
|
15815
|
+
else logger.success(`Workspace "${displayName}" deleted successfully.`);
|
|
15411
15816
|
}
|
|
15412
15817
|
});
|
|
15413
15818
|
|
|
@@ -15419,12 +15824,9 @@ const getWorkspaceOptionsSchema = z.object({
|
|
|
15419
15824
|
});
|
|
15420
15825
|
async function loadOptions$6(options) {
|
|
15421
15826
|
const result = getWorkspaceOptionsSchema.safeParse(options);
|
|
15422
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15827
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15423
15828
|
return {
|
|
15424
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15425
|
-
useProfile: true,
|
|
15426
|
-
profile: result.data.profile
|
|
15427
|
-
})),
|
|
15829
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15428
15830
|
workspaceId: await loadWorkspaceId({
|
|
15429
15831
|
workspaceId: result.data.workspaceId,
|
|
15430
15832
|
profile: result.data.profile
|
|
@@ -15440,7 +15842,7 @@ async function getWorkspace(options) {
|
|
|
15440
15842
|
const { client, workspaceId } = await loadOptions$6(options);
|
|
15441
15843
|
const response = await client.getWorkspace({ workspaceId });
|
|
15442
15844
|
if (!response.workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
15443
|
-
return
|
|
15845
|
+
return workspaceDetailsWithFolderName(client, response.workspace);
|
|
15444
15846
|
}
|
|
15445
15847
|
const getCommand = defineAppCommand({
|
|
15446
15848
|
name: "get",
|
|
@@ -15456,7 +15858,10 @@ const getCommand = defineAppCommand({
|
|
|
15456
15858
|
createdAt: humanizeRelativeTime(workspace.createdAt),
|
|
15457
15859
|
updatedAt: humanizeRelativeTime(workspace.updatedAt)
|
|
15458
15860
|
};
|
|
15459
|
-
logger.out(formattedWorkspace
|
|
15861
|
+
logger.out(formattedWorkspace, { display: {
|
|
15862
|
+
name: workspaceNameTransformer,
|
|
15863
|
+
folderName: null
|
|
15864
|
+
} });
|
|
15460
15865
|
}
|
|
15461
15866
|
});
|
|
15462
15867
|
|
|
@@ -15470,14 +15875,14 @@ const getCommand = defineAppCommand({
|
|
|
15470
15875
|
async function listWorkspaces(options) {
|
|
15471
15876
|
const client = await initOperatorClient(await loadAccessToken());
|
|
15472
15877
|
const pageDirection = toPageDirection(options?.order);
|
|
15473
|
-
return (await fetchPaged(async (pageToken, pageSize) => {
|
|
15878
|
+
return workspaceInfosWithFolderNames(client, await fetchPaged(async (pageToken, pageSize) => {
|
|
15474
15879
|
const { workspaces, nextPageToken } = await client.listWorkspaces({
|
|
15475
15880
|
pageToken,
|
|
15476
15881
|
pageSize,
|
|
15477
15882
|
pageDirection
|
|
15478
15883
|
});
|
|
15479
15884
|
return [workspaces, nextPageToken];
|
|
15480
|
-
}, { limit: options?.limit }))
|
|
15885
|
+
}, { limit: options?.limit }));
|
|
15481
15886
|
}
|
|
15482
15887
|
const listCommand$1 = defineAppCommand({
|
|
15483
15888
|
name: "list",
|
|
@@ -15488,7 +15893,11 @@ const listCommand$1 = defineAppCommand({
|
|
|
15488
15893
|
order: args.order,
|
|
15489
15894
|
limit: args.limit
|
|
15490
15895
|
});
|
|
15491
|
-
logger.out(workspaces, { display: {
|
|
15896
|
+
logger.out(workspaces, { display: {
|
|
15897
|
+
name: workspaceNameTransformer,
|
|
15898
|
+
folderName: null,
|
|
15899
|
+
updatedAt: null
|
|
15900
|
+
} });
|
|
15492
15901
|
}
|
|
15493
15902
|
});
|
|
15494
15903
|
|
|
@@ -15497,7 +15906,7 @@ const listCommand$1 = defineAppCommand({
|
|
|
15497
15906
|
const restoreWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
|
|
15498
15907
|
async function loadOptions$5(options) {
|
|
15499
15908
|
const result = restoreWorkspaceOptionsSchema.safeParse(options);
|
|
15500
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15909
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15501
15910
|
return {
|
|
15502
15911
|
client: await initOperatorClient(await loadAccessToken()),
|
|
15503
15912
|
workspaceId: result.data.workspaceId
|
|
@@ -15577,12 +15986,9 @@ const inviteUserOptionsSchema = z.object({
|
|
|
15577
15986
|
});
|
|
15578
15987
|
async function loadOptions$4(options) {
|
|
15579
15988
|
const result = inviteUserOptionsSchema.safeParse(options);
|
|
15580
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15989
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15581
15990
|
return {
|
|
15582
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15583
|
-
useProfile: true,
|
|
15584
|
-
profile: result.data.profile
|
|
15585
|
-
})),
|
|
15991
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15586
15992
|
workspaceId: await loadWorkspaceId({
|
|
15587
15993
|
workspaceId: result.data.workspaceId,
|
|
15588
15994
|
profile: result.data.profile
|
|
@@ -15637,12 +16043,9 @@ const listUsersOptionsSchema = z.object({
|
|
|
15637
16043
|
});
|
|
15638
16044
|
async function loadOptions$3(options) {
|
|
15639
16045
|
const result = listUsersOptionsSchema.safeParse(options);
|
|
15640
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16046
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15641
16047
|
return {
|
|
15642
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15643
|
-
useProfile: true,
|
|
15644
|
-
profile: result.data.profile
|
|
15645
|
-
})),
|
|
16048
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15646
16049
|
workspaceId: await loadWorkspaceId({
|
|
15647
16050
|
workspaceId: result.data.workspaceId,
|
|
15648
16051
|
profile: result.data.profile
|
|
@@ -15696,12 +16099,9 @@ const removeUserOptionsSchema = z.object({
|
|
|
15696
16099
|
});
|
|
15697
16100
|
async function loadOptions$2(options) {
|
|
15698
16101
|
const result = removeUserOptionsSchema.safeParse(options);
|
|
15699
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16102
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15700
16103
|
return {
|
|
15701
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15702
|
-
useProfile: true,
|
|
15703
|
-
profile: result.data.profile
|
|
15704
|
-
})),
|
|
16104
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15705
16105
|
workspaceId: await loadWorkspaceId({
|
|
15706
16106
|
workspaceId: result.data.workspaceId,
|
|
15707
16107
|
profile: result.data.profile
|
|
@@ -15756,12 +16156,9 @@ const updateUserOptionsSchema = z.object({
|
|
|
15756
16156
|
});
|
|
15757
16157
|
async function loadOptions$1(options) {
|
|
15758
16158
|
const result = updateUserOptionsSchema.safeParse(options);
|
|
15759
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16159
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15760
16160
|
return {
|
|
15761
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15762
|
-
useProfile: true,
|
|
15763
|
-
profile: result.data.profile
|
|
15764
|
-
})),
|
|
16161
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15765
16162
|
workspaceId: await loadWorkspaceId({
|
|
15766
16163
|
workspaceId: result.data.workspaceId,
|
|
15767
16164
|
profile: result.data.profile
|
|
@@ -15982,7 +16379,7 @@ function isSqlInputComplete(input) {
|
|
|
15982
16379
|
let dollarQuoteTag = null;
|
|
15983
16380
|
let lastSignificantTokenWasSemicolon = false;
|
|
15984
16381
|
for (let i = 0; i < input.length; i += 1) {
|
|
15985
|
-
const char = input[i];
|
|
16382
|
+
const char = assertDefined(input[i], `character at index ${i} missing`);
|
|
15986
16383
|
const next = input[i + 1];
|
|
15987
16384
|
if (inLineComment) {
|
|
15988
16385
|
if (char === "\n") inLineComment = false;
|
|
@@ -16185,7 +16582,7 @@ const queryBaseOptionsSchema = z.object({
|
|
|
16185
16582
|
const queryOptionsSchema = queryBaseOptionsSchema.extend({ query: z.string() });
|
|
16186
16583
|
async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces) {
|
|
16187
16584
|
if (namespaces.length === 0) throw new Error("No namespaces found in configuration.");
|
|
16188
|
-
if (namespaces.length === 1) return namespaces[0];
|
|
16585
|
+
if (namespaces.length === 1) return assertDefined(namespaces[0], "namespace missing");
|
|
16189
16586
|
const typeNames = extractTypeNamesFromSql(query);
|
|
16190
16587
|
if (typeNames.length === 0) throw new Error(`Could not infer namespace from query. Detected namespaces: ${namespaces.join(", ")}.`);
|
|
16191
16588
|
const typeNamespaceMap = await resolveTypeNamespaces({
|
|
@@ -16197,16 +16594,13 @@ async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces)
|
|
|
16197
16594
|
const notFoundTypes = typeNames.filter((typeName) => !typeNamespaceMap.has(typeName));
|
|
16198
16595
|
if (notFoundTypes.length > 0) throw new Error(`Could not find namespace for types in query: ${notFoundTypes.join(", ")}.`);
|
|
16199
16596
|
const namespacesFromTypes = new Set(typeNamespaceMap.values());
|
|
16200
|
-
if (namespacesFromTypes.size === 1) return [...namespacesFromTypes][0];
|
|
16597
|
+
if (namespacesFromTypes.size === 1) return assertDefined([...namespacesFromTypes][0], "namespace from types missing");
|
|
16201
16598
|
throw new Error(`Query references types from multiple namespaces: ${[...namespacesFromTypes].join(", ")}.`);
|
|
16202
16599
|
}
|
|
16203
16600
|
async function loadOptions(options) {
|
|
16204
16601
|
const result = queryBaseOptionsSchema.safeParse(options);
|
|
16205
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16206
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
16207
|
-
useProfile: true,
|
|
16208
|
-
profile: result.data.profile
|
|
16209
|
-
}));
|
|
16602
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
|
|
16603
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: result.data.profile }));
|
|
16210
16604
|
const workspaceId = await loadWorkspaceId({
|
|
16211
16605
|
workspaceId: result.data.workspaceId,
|
|
16212
16606
|
profile: result.data.profile
|
|
@@ -16339,7 +16733,7 @@ async function resolveEditedQueryInput(engine) {
|
|
|
16339
16733
|
*/
|
|
16340
16734
|
async function query(options) {
|
|
16341
16735
|
const result = queryOptionsSchema.safeParse(options);
|
|
16342
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16736
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
|
|
16343
16737
|
return await (await prepareQueryExecutor(result.data))(result.data.query);
|
|
16344
16738
|
}
|
|
16345
16739
|
async function prepareQueryExecutor(options) {
|
|
@@ -16421,7 +16815,7 @@ async function runRepl(options) {
|
|
|
16421
16815
|
const execute = await prepareQueryExecutor(options);
|
|
16422
16816
|
const historyPath = getReplHistoryPath(options.engine, options.profile, options.workspaceId);
|
|
16423
16817
|
const validate = createReplValidator(options.engine);
|
|
16424
|
-
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-
|
|
16818
|
+
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-CJG3sz7A.mjs");
|
|
16425
16819
|
const highlight = options.engine === "sql" ? highlightSqlLine : highlightGraphqlLine;
|
|
16426
16820
|
const prompt = createPrompt({
|
|
16427
16821
|
prefix: "",
|
|
@@ -16682,8 +17076,9 @@ function printSingleSqlResult(execResult, options = {}) {
|
|
|
16682
17076
|
function splitSqlStatements(query) {
|
|
16683
17077
|
const statements = parse(query, { locationTracking: true });
|
|
16684
17078
|
return statements.map((s, i) => {
|
|
16685
|
-
const start = s._location.start;
|
|
16686
|
-
const
|
|
17079
|
+
const start = assertDefined(s._location, "SQL statement location missing").start;
|
|
17080
|
+
const nextStmt = statements[i + 1];
|
|
17081
|
+
const end = nextStmt !== void 0 ? assertDefined(nextStmt._location, "SQL statement location missing").start : query.length;
|
|
16687
17082
|
return query.substring(start, end);
|
|
16688
17083
|
});
|
|
16689
17084
|
}
|
|
@@ -16703,7 +17098,7 @@ function printSqlResult(result, options = {}) {
|
|
|
16703
17098
|
for (let i = 0; i < result.result.length; i++) {
|
|
16704
17099
|
if (i > 0) logger.log("");
|
|
16705
17100
|
logger.info(queries[i] ?? `Statement ${i + 1}`);
|
|
16706
|
-
printSingleSqlResult(result.result[i], options);
|
|
17101
|
+
printSingleSqlResult(assertDefined(result.result[i], `SQL result at index ${i} missing`), options);
|
|
16707
17102
|
}
|
|
16708
17103
|
return;
|
|
16709
17104
|
}
|
|
@@ -16754,5 +17149,5 @@ function isDeno() {
|
|
|
16754
17149
|
}
|
|
16755
17150
|
|
|
16756
17151
|
//#endregion
|
|
16757
|
-
export { listCommand$5 as $,
|
|
16758
|
-
//# sourceMappingURL=runtime-
|
|
17152
|
+
export { listCommand$5 as $, INITIAL_SCHEMA_NUMBER as $t, truncate as A, commonArgs as An, startCommand as At, logBetaWarning as B, getExecutor as Bt, listCommand$2 as C, PluginManager as Cn, triggerExecutor as Ct, resumeWorkflow as D, apiCall as Dn, jobsCommand as Dt, resumeCommand as E, apiCommand as En, getExecutorJob as Et, writeDbTypesFile as F, pagedLogArgs as Fn, getWorkflowExecution as Ft, organizationTree as G, MIGRATION_LABEL_KEY as Gt, removeCommand$1 as H, executeScript as Ht, getConfiguredEditorCommand as I, paginationArgs as In, listWorkflowExecutions as It, listOrganizations as J, compareSnapshotWithRemote as Jt, treeCommand as K, handleOptionalToRequiredError as Kt, openInConfiguredEditor as L, toPageDirection as Ln, functionExecutionStatusToString as Lt, generate as M, confirmationArgs as Mn, getCommand$5 as Mt, generateCommand as N, deploymentArgs as Nn, getWorkflow as Nt, listCommand$3 as O, assertWritable as On, listExecutorJobs as Ot, generateMigrationScript as P, isVerbose as Pn, executionsCommand as Pt, updateFolder as Q, DIFF_FILE_NAME as Qt, show as R, workspaceArgs as Rn, formatKeyValueTable as Rt, listApps as S, sdkNameLabelKey as Sn, triggerCommand as St, healthCommand as T, prompt 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, ensureConfigId 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, configArg as jn, startWorkflow as jt, listWorkflows as k, defineAppCommand 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, generateUserTypes as wn, listCommand$9 as wt, createWorkspace as x, resourceTrn as xn, webhookCommand as xt, deleteWorkspace as y, getNamespacesWithMigrations as yn, getFunctionRegistry as yt, showCommand as z, getCommand$6 as zt };
|
|
17153
|
+
//# sourceMappingURL=runtime-CW3jcQCc.mjs.map
|