@tailor-platform/sdk 1.60.3 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/{application-pusdxz35.mjs → application-BezXGbrU.mjs} +73 -509
- package/dist/application-BezXGbrU.mjs.map +1 -0
- package/dist/application-DSXntqnV.mjs +4 -0
- package/dist/assert-CKfwrmCV.mjs +10 -0
- package/dist/assert-CKfwrmCV.mjs.map +1 -0
- package/dist/cli/index.mjs +376 -136
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +3 -1
- package/dist/cli/lib.mjs +13 -6
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/{client-B-jRdlC_.mjs → client-C68VWo4g.mjs} +1 -1
- package/dist/{client-W5P4NYYX.mjs → client-CobIRHl-.mjs} +207 -2
- package/dist/{client-W5P4NYYX.mjs.map → client-CobIRHl-.mjs.map} +1 -1
- package/dist/configure/index.mjs +2 -2
- package/dist/{crashreport-D3DvAzdg.mjs → crashreport-BhD0y14F.mjs} +2 -2
- package/dist/{crashreport-D3DvAzdg.mjs.map → crashreport-BhD0y14F.mjs.map} +1 -1
- package/dist/{crashreport-lnVTnbB5.mjs → crashreport-D1wKBJ8N.mjs} +1 -1
- package/dist/{mock-Dpu__UeJ.mjs → mock-DMgIygjE.mjs} +3 -2
- package/dist/mock-DMgIygjE.mjs.map +1 -0
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/index.mjs +1 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/registry-D0uB0OrK.mjs.map +1 -1
- package/dist/{repl-editor-Y9QJDL0K.mjs → repl-editor-CJG3sz7A.mjs} +11 -9
- package/dist/repl-editor-CJG3sz7A.mjs.map +1 -0
- package/dist/{runtime-C0_FZWdE.mjs → runtime-C6o4hiYq.mjs} +903 -579
- package/dist/runtime-C6o4hiYq.mjs.map +1 -0
- package/dist/{schema-DYKNTu-n.mjs → schema-1msIhXwA.mjs} +12 -7
- package/dist/schema-1msIhXwA.mjs.map +1 -0
- package/dist/{seed-C0fE2sJB.mjs → seed-BH2FbrPV.mjs} +4 -3
- package/dist/seed-BH2FbrPV.mjs.map +1 -0
- package/dist/service-BHQIerYh.mjs +4 -0
- package/dist/{service-aPT0fx3y.mjs → service-DMohAx8a2.mjs} +3 -3
- package/dist/service-DMohAx8a2.mjs.map +1 -0
- package/dist/service-wI3Hvrgx.mjs +460 -0
- package/dist/service-wI3Hvrgx.mjs.map +1 -0
- package/dist/{types-Ccwchyj5.mjs → types-2Be3wSMc.mjs} +1 -1
- package/dist/{types-BwGth3a1.mjs → types-CmzfQP_m.mjs} +3 -3
- package/dist/types-CmzfQP_m.mjs.map +1 -0
- package/dist/utils/test/index.mjs +1 -1
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/index.mjs +7 -4
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/setup.mjs +1 -1
- package/docs/cli/application.md +11 -10
- package/docs/cli/tailordb.md +54 -0
- package/docs/cli-reference.md +1 -0
- package/docs/services/tailordb-migration.md +17 -1
- package/package.json +2 -1
- package/dist/application-D4tRNn90.mjs +0 -4
- package/dist/application-pusdxz35.mjs.map +0 -1
- package/dist/mock-Dpu__UeJ.mjs.map +0 -1
- package/dist/repl-editor-Y9QJDL0K.mjs.map +0 -1
- package/dist/runtime-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) {
|
|
@@ -4675,7 +4681,7 @@ const idComment = "// SDK-managed app id — do not edit, except when copying th
|
|
|
4675
4681
|
function insertIdProperty(source, configObj, id) {
|
|
4676
4682
|
const idLiteral = `id: ${JSON.stringify(id)}`;
|
|
4677
4683
|
if (configObj.properties.length > 0) {
|
|
4678
|
-
const firstProp = configObj.properties[0];
|
|
4684
|
+
const firstProp = assertDefined(configObj.properties[0], "first property missing");
|
|
4679
4685
|
const lineStart = source.lastIndexOf("\n", firstProp.start - 1) + 1;
|
|
4680
4686
|
const indent = source.slice(lineStart, firstProp.start);
|
|
4681
4687
|
const insertion = `${idComment}\n${indent}${idLiteral},\n${indent}`;
|
|
@@ -4927,7 +4933,7 @@ async function applyExecutor(client, result, phase = "create-update") {
|
|
|
4927
4933
|
await client.updateExecutorExecutor(update.request);
|
|
4928
4934
|
await client.setMetadata(update.metaRequest);
|
|
4929
4935
|
})]);
|
|
4930
|
-
else
|
|
4936
|
+
else await Promise.all(changeSet.deletes.map((del) => client.deleteExecutorExecutor(del.request)));
|
|
4931
4937
|
}
|
|
4932
4938
|
/**
|
|
4933
4939
|
* Plan executor-related changes based on current and desired state.
|
|
@@ -5042,7 +5048,7 @@ function formatExecutorChangeEntries(changeSet, executors, functionRegistryExecu
|
|
|
5042
5048
|
});
|
|
5043
5049
|
}
|
|
5044
5050
|
function normalizeComparableExecutor(executor) {
|
|
5045
|
-
const normalized = normalizeProtoConfig(executor)
|
|
5051
|
+
const normalized = normalizeProtoConfig(executor);
|
|
5046
5052
|
const webhookHeaders = normalized.targetConfig?.config?.case === "webhook" ? (normalized.targetConfig.config.value.headers ?? []).toSorted((left, right) => (left.key ?? "").localeCompare(right.key ?? "")) : void 0;
|
|
5047
5053
|
const triggerConfig = normalized.triggerConfig?.config?.case === "incomingWebhook" ? {
|
|
5048
5054
|
...normalized.triggerConfig,
|
|
@@ -5095,7 +5101,7 @@ function areExecutorsEqual(existing, desired) {
|
|
|
5095
5101
|
return areNormalizedEqual(normalizeComparableExecutor(existing), normalizeComparableExecutor(desired));
|
|
5096
5102
|
}
|
|
5097
5103
|
function resolveTailorDBNamespace(application, typeName) {
|
|
5098
|
-
for (const service of application.tailorDBServices) if (service.types
|
|
5104
|
+
for (const service of application.tailorDBServices) if (Object.hasOwn(service.types, typeName)) return service.namespace;
|
|
5099
5105
|
throw new Error(`TailorDB type "${typeName}" not found in any namespace. Available namespaces: ${application.tailorDBServices.map((s) => s.namespace).join(", ")}`);
|
|
5100
5106
|
}
|
|
5101
5107
|
function resolveResolverNamespace(application, resolverName) {
|
|
@@ -5116,7 +5122,7 @@ function resolveIdpNamespace(application, executorName, idpName) {
|
|
|
5116
5122
|
const available = application.idpServices.map((idp) => idp.name).join(", ");
|
|
5117
5123
|
throw new Error(`Executor "${executorName}" uses an idpUser trigger but the project defines multiple IdPs (${available}). Specify which IdP to subscribe to via the trigger's "idp" option.`);
|
|
5118
5124
|
}
|
|
5119
|
-
return application.idpServices[0].name;
|
|
5125
|
+
return assertDefined(application.idpServices[0], "idp service missing").name;
|
|
5120
5126
|
}
|
|
5121
5127
|
function resolveAuthNamespace(application) {
|
|
5122
5128
|
if (!application.authService) throw new Error("No Auth service configured");
|
|
@@ -5345,7 +5351,7 @@ async function applyPipeline(client, result, phase = "create-update") {
|
|
|
5345
5351
|
})]);
|
|
5346
5352
|
await Promise.all([...changeSet.resolver.creates.map((create) => client.createPipelineResolver(create.request)), ...changeSet.resolver.updates.map((update) => client.updatePipelineResolver(update.request))]);
|
|
5347
5353
|
} else if (phase === "delete-resources") await Promise.all(changeSet.resolver.deletes.map((del) => client.deletePipelineResolver(del.request)));
|
|
5348
|
-
else
|
|
5354
|
+
else await Promise.all(changeSet.service.deletes.map((del) => client.deletePipelineService(del.request)));
|
|
5349
5355
|
}
|
|
5350
5356
|
/**
|
|
5351
5357
|
* Plan resolver pipeline changes based on current and desired state.
|
|
@@ -5544,7 +5550,7 @@ function formatResolverChangeEntries(changeSet, resolverFunctionChanges) {
|
|
|
5544
5550
|
}, { getNamespace: (item) => item.request.namespaceName });
|
|
5545
5551
|
}
|
|
5546
5552
|
function normalizeComparableResolver(resolver) {
|
|
5547
|
-
const normalized = normalizeProtoConfig(resolver)
|
|
5553
|
+
const normalized = normalizeProtoConfig(resolver);
|
|
5548
5554
|
return {
|
|
5549
5555
|
name: normalized.name,
|
|
5550
5556
|
description: normalized.description ?? "",
|
|
@@ -5609,7 +5615,7 @@ function processResolver(namespace, resolver, executorUsedResolvers, env, authNa
|
|
|
5609
5615
|
}];
|
|
5610
5616
|
const typeBaseName = inflection.camelize(resolver.name);
|
|
5611
5617
|
const inputs = resolver.input ? protoFields(resolver.input, `${typeBaseName}Input`, true) : [];
|
|
5612
|
-
const response = protoFields({ "": resolver.output }, `${typeBaseName}Output`, false)[0];
|
|
5618
|
+
const response = assertDefined(protoFields({ "": resolver.output }, `${typeBaseName}Output`, false)[0], "resolver output field missing");
|
|
5613
5619
|
const resolverDescription = resolver.description || `${resolver.name} resolver`;
|
|
5614
5620
|
const outputDescription = resolver.output.metadata.description;
|
|
5615
5621
|
const combinedDescription = outputDescription ? `${resolverDescription}\n\nReturns:\n${outputDescription}` : resolverDescription;
|
|
@@ -5628,7 +5634,6 @@ function processResolver(namespace, resolver, executorUsedResolvers, env, authNa
|
|
|
5628
5634
|
};
|
|
5629
5635
|
}
|
|
5630
5636
|
function protoFields(fields, baseName, isInput) {
|
|
5631
|
-
if (!fields) return [];
|
|
5632
5637
|
return Object.entries(fields).map(([fieldName, field]) => {
|
|
5633
5638
|
let type;
|
|
5634
5639
|
const required = isInput && field.metadata.hooks?.create !== void 0 ? false : field.metadata.required ?? true;
|
|
@@ -5664,6 +5669,43 @@ function protoFields(fields, baseName, isInput) {
|
|
|
5664
5669
|
//#endregion
|
|
5665
5670
|
//#region src/cli/commands/deploy/secret-manager.ts
|
|
5666
5671
|
/**
|
|
5672
|
+
* Build the CreateSecretManagerVault request for a planned vault create.
|
|
5673
|
+
* @param create - Planned vault create
|
|
5674
|
+
* @returns Request init shape
|
|
5675
|
+
*/
|
|
5676
|
+
function vaultCreateRequest(create) {
|
|
5677
|
+
return {
|
|
5678
|
+
workspaceId: create.workspaceId,
|
|
5679
|
+
secretmanagerVaultName: create.name
|
|
5680
|
+
};
|
|
5681
|
+
}
|
|
5682
|
+
/**
|
|
5683
|
+
* Build the CreateSecretManagerSecret request for a planned secret create.
|
|
5684
|
+
* @param create - Planned secret create
|
|
5685
|
+
* @returns Request init shape
|
|
5686
|
+
*/
|
|
5687
|
+
function secretCreateRequest(create) {
|
|
5688
|
+
return {
|
|
5689
|
+
workspaceId: create.workspaceId,
|
|
5690
|
+
secretmanagerVaultName: create.vaultName,
|
|
5691
|
+
secretmanagerSecretName: create.secretName,
|
|
5692
|
+
secretmanagerSecretValue: create.value
|
|
5693
|
+
};
|
|
5694
|
+
}
|
|
5695
|
+
/**
|
|
5696
|
+
* Build the UpdateSecretManagerSecret request for a planned secret update.
|
|
5697
|
+
* @param update - Planned secret update
|
|
5698
|
+
* @returns Request init shape
|
|
5699
|
+
*/
|
|
5700
|
+
function secretUpdateRequest(update) {
|
|
5701
|
+
return {
|
|
5702
|
+
workspaceId: update.workspaceId,
|
|
5703
|
+
secretmanagerVaultName: update.vaultName,
|
|
5704
|
+
secretmanagerSecretName: update.secretName,
|
|
5705
|
+
secretmanagerSecretValue: update.value
|
|
5706
|
+
};
|
|
5707
|
+
}
|
|
5708
|
+
/**
|
|
5667
5709
|
* Plan secret manager changes based on current and desired state.
|
|
5668
5710
|
* @param context - Planning context
|
|
5669
5711
|
* @returns Planned changes for vaults and secrets
|
|
@@ -5830,10 +5872,7 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5830
5872
|
const { vaultChangeSet, secretChangeSet } = result;
|
|
5831
5873
|
if (phase === "create-update") {
|
|
5832
5874
|
await Promise.all(vaultChangeSet.creates.map(async (create) => {
|
|
5833
|
-
await client.createSecretManagerVault(
|
|
5834
|
-
workspaceId: create.workspaceId,
|
|
5835
|
-
secretmanagerVaultName: create.name
|
|
5836
|
-
});
|
|
5875
|
+
await client.createSecretManagerVault(vaultCreateRequest(create));
|
|
5837
5876
|
if (application) {
|
|
5838
5877
|
const metaRequest = await buildMetaRequest({
|
|
5839
5878
|
trn: resourceTrn(create.workspaceId, "vault", create.name),
|
|
@@ -5851,27 +5890,17 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5851
5890
|
});
|
|
5852
5891
|
await client.setMetadata(metaRequest);
|
|
5853
5892
|
}));
|
|
5854
|
-
await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret(
|
|
5855
|
-
|
|
5856
|
-
secretmanagerVaultName: create.vaultName,
|
|
5857
|
-
secretmanagerSecretName: create.secretName,
|
|
5858
|
-
secretmanagerSecretValue: create.value
|
|
5859
|
-
})));
|
|
5860
|
-
await Promise.all(secretChangeSet.updates.map((update) => client.updateSecretManagerSecret({
|
|
5861
|
-
workspaceId: update.workspaceId,
|
|
5862
|
-
secretmanagerVaultName: update.vaultName,
|
|
5863
|
-
secretmanagerSecretName: update.secretName,
|
|
5864
|
-
secretmanagerSecretValue: update.value
|
|
5865
|
-
})));
|
|
5893
|
+
await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret(secretCreateRequest(create))));
|
|
5894
|
+
await Promise.all(secretChangeSet.updates.map((update) => client.updateSecretManagerSecret(secretUpdateRequest(update))));
|
|
5866
5895
|
if (application) {
|
|
5867
5896
|
const state = loadSecretsState();
|
|
5868
5897
|
for (const vault of application.secrets) {
|
|
5869
|
-
if (!state.vaults
|
|
5870
|
-
for (const secret of vault.secrets) if (secret.value != null) state.vaults[vault.vaultName][secret.name] = hashValue(secret.value);
|
|
5898
|
+
if (!Object.hasOwn(state.vaults, vault.vaultName)) state.vaults[vault.vaultName] = {};
|
|
5899
|
+
for (const secret of vault.secrets) if (secret.value != null) assertDefined(state.vaults[vault.vaultName], "vault state entry missing")[secret.name] = hashValue(secret.value);
|
|
5871
5900
|
}
|
|
5872
5901
|
saveSecretsState(state);
|
|
5873
5902
|
}
|
|
5874
|
-
} else
|
|
5903
|
+
} else {
|
|
5875
5904
|
await Promise.all(secretChangeSet.deletes.map((del) => client.deleteSecretManagerSecret({
|
|
5876
5905
|
workspaceId: del.workspaceId,
|
|
5877
5906
|
secretmanagerVaultName: del.vaultName,
|
|
@@ -5883,9 +5912,9 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
5883
5912
|
})));
|
|
5884
5913
|
if (secretChangeSet.deletes.length > 0 || vaultChangeSet.deletes.length > 0) {
|
|
5885
5914
|
const state = loadSecretsState();
|
|
5886
|
-
for (const del of secretChangeSet.deletes) if (state.vaults
|
|
5887
|
-
delete state.vaults[del.vaultName][del.secretName];
|
|
5888
|
-
if (Object.keys(state.vaults[del.vaultName]).length === 0) delete state.vaults[del.vaultName];
|
|
5915
|
+
for (const del of secretChangeSet.deletes) if (Object.hasOwn(state.vaults, del.vaultName)) {
|
|
5916
|
+
delete assertDefined(state.vaults[del.vaultName], "vault state entry missing")[del.secretName];
|
|
5917
|
+
if (Object.keys(assertDefined(state.vaults[del.vaultName], "vault state entry missing")).length === 0) delete state.vaults[del.vaultName];
|
|
5889
5918
|
}
|
|
5890
5919
|
for (const del of vaultChangeSet.deletes) delete state.vaults[del.name];
|
|
5891
5920
|
saveSecretsState(state);
|
|
@@ -5916,7 +5945,7 @@ async function applyStaticWebsite(client, result, phase = "create-update") {
|
|
|
5916
5945
|
await client.addCustomDomain(add.request);
|
|
5917
5946
|
await client.setMetadata(add.metaRequest);
|
|
5918
5947
|
}), ...customDomainChangeSet.deletes.map((del) => client.removeCustomDomain(del.request))]);
|
|
5919
|
-
} else
|
|
5948
|
+
} else await Promise.all(changeSet.deletes.map((del) => client.deleteStaticWebsite(del.request)));
|
|
5920
5949
|
}
|
|
5921
5950
|
function customDomainTrn(workspaceId, websiteName, domain) {
|
|
5922
5951
|
return `trn:v1:workspace:${workspaceId}:staticwebsite:${websiteName}:custom_domain:${domain}`;
|
|
@@ -6296,6 +6325,24 @@ function formatDiffSummary(diff) {
|
|
|
6296
6325
|
function formatMigrationNumber(num) {
|
|
6297
6326
|
return num.toString().padStart(4, "0");
|
|
6298
6327
|
}
|
|
6328
|
+
/**
|
|
6329
|
+
* Parse a migration number CLI argument.
|
|
6330
|
+
*
|
|
6331
|
+
* Accepts the canonical 4-digit form ("0001") or a bare integer without
|
|
6332
|
+
* leading zeros ("0"–"9999"). Commands that disallow the baseline reject
|
|
6333
|
+
* 0 themselves with a context-specific message.
|
|
6334
|
+
* @param numberStr - Raw CLI argument
|
|
6335
|
+
* @returns Parsed migration number
|
|
6336
|
+
*/
|
|
6337
|
+
function parseMigrationNumberArg(numberStr) {
|
|
6338
|
+
if (/^\d{4}$/.test(numberStr)) return parseInt(numberStr, 10);
|
|
6339
|
+
if (/^(0|[1-9]\d*)$/.test(numberStr)) {
|
|
6340
|
+
const parsed = parseInt(numberStr, 10);
|
|
6341
|
+
if (parsed > 9999) throw new Error(`Migration number ${numberStr} is out of range. Expected 0-9999.`);
|
|
6342
|
+
return parsed;
|
|
6343
|
+
}
|
|
6344
|
+
throw new Error(`Invalid migration number format: ${numberStr}. Expected 4-digit format (e.g., 0001) or integer 0-9999 (e.g., 1).`);
|
|
6345
|
+
}
|
|
6299
6346
|
|
|
6300
6347
|
//#endregion
|
|
6301
6348
|
//#region src/cli/commands/tailordb/migrate/snapshot-types.ts
|
|
@@ -6675,96 +6722,112 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6675
6722
|
case "type_removed":
|
|
6676
6723
|
delete types[change.typeName];
|
|
6677
6724
|
break;
|
|
6678
|
-
case "type_modified":
|
|
6679
|
-
|
|
6725
|
+
case "type_modified": {
|
|
6726
|
+
const existing = types[change.typeName];
|
|
6727
|
+
if (existing && change.after) {
|
|
6680
6728
|
const after = change.after;
|
|
6681
6729
|
types[change.typeName] = {
|
|
6682
|
-
...
|
|
6730
|
+
...existing,
|
|
6683
6731
|
...after.indexes !== void 0 && { indexes: after.indexes },
|
|
6684
6732
|
...after.files !== void 0 && { files: after.files }
|
|
6685
6733
|
};
|
|
6686
6734
|
}
|
|
6687
6735
|
break;
|
|
6736
|
+
}
|
|
6688
6737
|
case "field_added":
|
|
6689
|
-
case "field_modified":
|
|
6690
|
-
|
|
6691
|
-
|
|
6738
|
+
case "field_modified": {
|
|
6739
|
+
const existing = types[change.typeName];
|
|
6740
|
+
if (existing && change.fieldName) types[change.typeName] = {
|
|
6741
|
+
...existing,
|
|
6692
6742
|
fields: {
|
|
6693
|
-
...
|
|
6743
|
+
...existing.fields,
|
|
6694
6744
|
[change.fieldName]: change.after
|
|
6695
6745
|
}
|
|
6696
6746
|
};
|
|
6697
6747
|
break;
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6748
|
+
}
|
|
6749
|
+
case "field_removed": {
|
|
6750
|
+
const existing = types[change.typeName];
|
|
6751
|
+
if (existing && change.fieldName) {
|
|
6752
|
+
const { [change.fieldName]: _, ...remainingFields } = existing.fields;
|
|
6701
6753
|
types[change.typeName] = {
|
|
6702
|
-
...
|
|
6754
|
+
...existing,
|
|
6703
6755
|
fields: remainingFields
|
|
6704
6756
|
};
|
|
6705
6757
|
}
|
|
6706
6758
|
break;
|
|
6759
|
+
}
|
|
6707
6760
|
case "index_added":
|
|
6708
|
-
case "index_modified":
|
|
6709
|
-
|
|
6710
|
-
|
|
6761
|
+
case "index_modified": {
|
|
6762
|
+
const existing = types[change.typeName];
|
|
6763
|
+
if (existing && change.indexName) types[change.typeName] = {
|
|
6764
|
+
...existing,
|
|
6711
6765
|
indexes: {
|
|
6712
|
-
...
|
|
6766
|
+
...existing.indexes,
|
|
6713
6767
|
[change.indexName]: change.after
|
|
6714
6768
|
}
|
|
6715
6769
|
};
|
|
6716
6770
|
break;
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6771
|
+
}
|
|
6772
|
+
case "index_removed": {
|
|
6773
|
+
const existing = types[change.typeName];
|
|
6774
|
+
if (existing && change.indexName && existing.indexes) {
|
|
6775
|
+
const { [change.indexName]: _, ...remainingIndexes } = existing.indexes;
|
|
6720
6776
|
types[change.typeName] = {
|
|
6721
|
-
...
|
|
6777
|
+
...existing,
|
|
6722
6778
|
indexes: Object.keys(remainingIndexes).length > 0 ? remainingIndexes : void 0
|
|
6723
6779
|
};
|
|
6724
6780
|
}
|
|
6725
6781
|
break;
|
|
6782
|
+
}
|
|
6726
6783
|
case "file_added":
|
|
6727
|
-
case "file_modified":
|
|
6728
|
-
|
|
6729
|
-
|
|
6784
|
+
case "file_modified": {
|
|
6785
|
+
const existing = types[change.typeName];
|
|
6786
|
+
if (existing && change.fieldName) types[change.typeName] = {
|
|
6787
|
+
...existing,
|
|
6730
6788
|
files: {
|
|
6731
|
-
...
|
|
6789
|
+
...existing.files,
|
|
6732
6790
|
[change.fieldName]: change.after
|
|
6733
6791
|
}
|
|
6734
6792
|
};
|
|
6735
6793
|
break;
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6794
|
+
}
|
|
6795
|
+
case "file_removed": {
|
|
6796
|
+
const existing = types[change.typeName];
|
|
6797
|
+
if (existing && change.fieldName && existing.files) {
|
|
6798
|
+
const { [change.fieldName]: _, ...remainingFiles } = existing.files;
|
|
6739
6799
|
types[change.typeName] = {
|
|
6740
|
-
...
|
|
6800
|
+
...existing,
|
|
6741
6801
|
files: Object.keys(remainingFiles).length > 0 ? remainingFiles : void 0
|
|
6742
6802
|
};
|
|
6743
6803
|
}
|
|
6744
6804
|
break;
|
|
6805
|
+
}
|
|
6745
6806
|
case "relationship_added":
|
|
6746
|
-
case "relationship_modified":
|
|
6747
|
-
|
|
6807
|
+
case "relationship_modified": {
|
|
6808
|
+
const existing = types[change.typeName];
|
|
6809
|
+
if (existing && change.relationshipName) {
|
|
6748
6810
|
const rel = change.after;
|
|
6749
|
-
if ((change.relationshipType ?? (
|
|
6750
|
-
...
|
|
6811
|
+
if ((change.relationshipType ?? (existing.forwardRelationships?.[change.relationshipName] ? "forward" : existing.backwardRelationships?.[change.relationshipName] ? "backward" : "forward")) === "forward") types[change.typeName] = {
|
|
6812
|
+
...existing,
|
|
6751
6813
|
forwardRelationships: {
|
|
6752
|
-
...
|
|
6814
|
+
...existing.forwardRelationships,
|
|
6753
6815
|
[change.relationshipName]: rel
|
|
6754
6816
|
}
|
|
6755
6817
|
};
|
|
6756
6818
|
else types[change.typeName] = {
|
|
6757
|
-
...
|
|
6819
|
+
...existing,
|
|
6758
6820
|
backwardRelationships: {
|
|
6759
|
-
...
|
|
6821
|
+
...existing.backwardRelationships,
|
|
6760
6822
|
[change.relationshipName]: rel
|
|
6761
6823
|
}
|
|
6762
6824
|
};
|
|
6763
6825
|
}
|
|
6764
6826
|
break;
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6827
|
+
}
|
|
6828
|
+
case "relationship_removed": {
|
|
6829
|
+
const type = types[change.typeName];
|
|
6830
|
+
if (type && change.relationshipName) {
|
|
6768
6831
|
const targetType = change.relationshipType ?? (type.forwardRelationships?.[change.relationshipName] ? "forward" : type.backwardRelationships?.[change.relationshipName] ? "backward" : null);
|
|
6769
6832
|
if (targetType === "forward" && type.forwardRelationships?.[change.relationshipName]) {
|
|
6770
6833
|
const { [change.relationshipName]: _, ...remaining } = type.forwardRelationships;
|
|
@@ -6781,11 +6844,13 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6781
6844
|
}
|
|
6782
6845
|
}
|
|
6783
6846
|
break;
|
|
6784
|
-
|
|
6785
|
-
|
|
6847
|
+
}
|
|
6848
|
+
case "permission_modified": {
|
|
6849
|
+
const existing = types[change.typeName];
|
|
6850
|
+
if (existing && change.after) {
|
|
6786
6851
|
const after = change.after;
|
|
6787
6852
|
types[change.typeName] = {
|
|
6788
|
-
...
|
|
6853
|
+
...existing,
|
|
6789
6854
|
permissions: {
|
|
6790
6855
|
record: after.recordPermission,
|
|
6791
6856
|
gql: after.gqlPermission
|
|
@@ -6793,6 +6858,7 @@ function applyDiffToSnapshot(snapshot, diff) {
|
|
|
6793
6858
|
};
|
|
6794
6859
|
}
|
|
6795
6860
|
break;
|
|
6861
|
+
}
|
|
6796
6862
|
}
|
|
6797
6863
|
return {
|
|
6798
6864
|
...snapshot,
|
|
@@ -6869,8 +6935,10 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
6869
6935
|
const newValidate = newField.validate ?? [];
|
|
6870
6936
|
if (oldValidate.length !== newValidate.length) return true;
|
|
6871
6937
|
for (let i = 0; i < oldValidate.length; i++) {
|
|
6872
|
-
|
|
6873
|
-
|
|
6938
|
+
const oldV = assertDefined(oldValidate[i], `oldValidate missing index ${i}`);
|
|
6939
|
+
const newV = assertDefined(newValidate[i], `newValidate missing index ${i}`);
|
|
6940
|
+
if (oldV.script.expr !== newV.script.expr) return true;
|
|
6941
|
+
if (oldV.errorMessage !== newV.errorMessage) return true;
|
|
6874
6942
|
}
|
|
6875
6943
|
const oldSerial = oldField.serial;
|
|
6876
6944
|
const newSerial = newField.serial;
|
|
@@ -6887,8 +6955,10 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
6887
6955
|
const newFieldNames = Object.keys(newFields);
|
|
6888
6956
|
if (oldFieldNames.length !== newFieldNames.length) return true;
|
|
6889
6957
|
for (const fieldName of oldFieldNames) {
|
|
6890
|
-
|
|
6891
|
-
|
|
6958
|
+
const oldF = oldFields[fieldName];
|
|
6959
|
+
const newF = newFields[fieldName];
|
|
6960
|
+
if (!newF) return true;
|
|
6961
|
+
if (areFieldsDifferent(assertDefined(oldF, `field "${fieldName}" missing from oldFields`), newF)) return true;
|
|
6892
6962
|
}
|
|
6893
6963
|
return false;
|
|
6894
6964
|
}
|
|
@@ -6973,22 +7043,28 @@ function addChange(ctx, change, oldField, newField) {
|
|
|
6973
7043
|
function compareTypeFields(ctx, typeName, prevType, currType) {
|
|
6974
7044
|
const prevFieldNames = new Set(Object.keys(prevType.fields));
|
|
6975
7045
|
const currFieldNames = new Set(Object.keys(currType.fields));
|
|
6976
|
-
for (const fieldName of currFieldNames) if (!prevFieldNames.has(fieldName))
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
7046
|
+
for (const fieldName of currFieldNames) if (!prevFieldNames.has(fieldName)) {
|
|
7047
|
+
const currField = assertDefined(currType.fields[fieldName], `field "${fieldName}" missing from currType`);
|
|
7048
|
+
addChange(ctx, {
|
|
7049
|
+
kind: "field_added",
|
|
7050
|
+
typeName,
|
|
7051
|
+
fieldName,
|
|
7052
|
+
after: currField
|
|
7053
|
+
}, void 0, currField);
|
|
7054
|
+
}
|
|
7055
|
+
for (const fieldName of prevFieldNames) if (!currFieldNames.has(fieldName)) {
|
|
7056
|
+
const prevField = assertDefined(prevType.fields[fieldName], `field "${fieldName}" missing from prevType`);
|
|
7057
|
+
addChange(ctx, {
|
|
7058
|
+
kind: "field_removed",
|
|
7059
|
+
typeName,
|
|
7060
|
+
fieldName,
|
|
7061
|
+
before: prevField
|
|
7062
|
+
}, prevField, void 0);
|
|
7063
|
+
}
|
|
6988
7064
|
for (const fieldName of currFieldNames) {
|
|
6989
7065
|
if (!prevFieldNames.has(fieldName)) continue;
|
|
6990
|
-
const prevField = prevType.fields[fieldName];
|
|
6991
|
-
const currField = currType.fields[fieldName];
|
|
7066
|
+
const prevField = assertDefined(prevType.fields[fieldName], `field "${fieldName}" missing from prevType`);
|
|
7067
|
+
const currField = assertDefined(currType.fields[fieldName], `field "${fieldName}" missing from currType`);
|
|
6992
7068
|
if (areFieldsDifferent(prevField, currField)) addChange(ctx, {
|
|
6993
7069
|
kind: "field_modified",
|
|
6994
7070
|
typeName,
|
|
@@ -7009,21 +7085,20 @@ function compareTypeFields(ctx, typeName, prevType, currType) {
|
|
|
7009
7085
|
function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
|
|
7010
7086
|
const oldKeys = new Set(Object.keys(oldIndexes || {}));
|
|
7011
7087
|
const newKeys = new Set(Object.keys(newIndexes || {}));
|
|
7012
|
-
for (const indexName of
|
|
7088
|
+
for (const [indexName, indexConfig] of Object.entries(newIndexes ?? {})) if (!oldKeys.has(indexName)) ctx.changes.push({
|
|
7013
7089
|
kind: "index_added",
|
|
7014
7090
|
typeName,
|
|
7015
7091
|
indexName,
|
|
7016
|
-
after:
|
|
7092
|
+
after: indexConfig
|
|
7017
7093
|
});
|
|
7018
|
-
for (const indexName of
|
|
7094
|
+
for (const [indexName, indexConfig] of Object.entries(oldIndexes ?? {})) if (!newKeys.has(indexName)) ctx.changes.push({
|
|
7019
7095
|
kind: "index_removed",
|
|
7020
7096
|
typeName,
|
|
7021
7097
|
indexName,
|
|
7022
|
-
before:
|
|
7098
|
+
before: indexConfig
|
|
7023
7099
|
});
|
|
7024
|
-
for (const indexName of
|
|
7025
|
-
const oldIndex = oldIndexes[indexName];
|
|
7026
|
-
const newIndex = newIndexes[indexName];
|
|
7100
|
+
for (const [indexName, newIndex] of Object.entries(newIndexes ?? {})) if (oldKeys.has(indexName)) {
|
|
7101
|
+
const oldIndex = assertDefined(assertDefined(oldIndexes, "oldIndexes is undefined when oldKeys has entry")[indexName], `index "${indexName}" missing from oldIndexes`);
|
|
7027
7102
|
const oldFieldsStr = JSON.stringify(oldIndex.fields.toSorted());
|
|
7028
7103
|
const newFieldsStr = JSON.stringify(newIndex.fields.toSorted());
|
|
7029
7104
|
if (oldFieldsStr !== newFieldsStr || oldIndex.unique !== newIndex.unique) {
|
|
@@ -7052,26 +7127,27 @@ function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
|
|
|
7052
7127
|
function compareFiles(ctx, typeName, oldFiles, newFiles) {
|
|
7053
7128
|
const oldKeys = new Set(Object.keys(oldFiles || {}));
|
|
7054
7129
|
const newKeys = new Set(Object.keys(newFiles || {}));
|
|
7055
|
-
for (const fileName of
|
|
7130
|
+
for (const [fileName, fileDesc] of Object.entries(newFiles ?? {})) if (!oldKeys.has(fileName)) ctx.changes.push({
|
|
7056
7131
|
kind: "file_added",
|
|
7057
7132
|
typeName,
|
|
7058
7133
|
fieldName: fileName,
|
|
7059
|
-
after:
|
|
7134
|
+
after: fileDesc
|
|
7060
7135
|
});
|
|
7061
|
-
for (const fileName of
|
|
7136
|
+
for (const [fileName, fileDesc] of Object.entries(oldFiles ?? {})) if (!newKeys.has(fileName)) ctx.changes.push({
|
|
7062
7137
|
kind: "file_removed",
|
|
7063
7138
|
typeName,
|
|
7064
7139
|
fieldName: fileName,
|
|
7065
|
-
before:
|
|
7140
|
+
before: fileDesc
|
|
7066
7141
|
});
|
|
7067
|
-
for (const fileName of
|
|
7068
|
-
|
|
7142
|
+
for (const [fileName, newDesc] of Object.entries(newFiles ?? {})) if (oldKeys.has(fileName)) {
|
|
7143
|
+
const oldDesc = assertDefined(assertDefined(oldFiles, "oldFiles is undefined when oldKeys has entry")[fileName], `file "${fileName}" missing from oldFiles`);
|
|
7144
|
+
if (oldDesc !== newDesc) ctx.changes.push({
|
|
7069
7145
|
kind: "file_modified",
|
|
7070
7146
|
typeName,
|
|
7071
7147
|
fieldName: fileName,
|
|
7072
7148
|
reason: "description changed",
|
|
7073
|
-
before:
|
|
7074
|
-
after:
|
|
7149
|
+
before: oldDesc,
|
|
7150
|
+
after: newDesc
|
|
7075
7151
|
});
|
|
7076
7152
|
}
|
|
7077
7153
|
}
|
|
@@ -7087,23 +7163,22 @@ function compareFiles(ctx, typeName, oldFiles, newFiles) {
|
|
|
7087
7163
|
function compareRelationships(ctx, typeName, relationshipType, oldRelationships, newRelationships) {
|
|
7088
7164
|
const oldKeys = new Set(Object.keys(oldRelationships || {}));
|
|
7089
7165
|
const newKeys = new Set(Object.keys(newRelationships || {}));
|
|
7090
|
-
for (const relName of
|
|
7166
|
+
for (const [relName, rel] of Object.entries(newRelationships ?? {})) if (!oldKeys.has(relName)) ctx.changes.push({
|
|
7091
7167
|
kind: "relationship_added",
|
|
7092
7168
|
typeName,
|
|
7093
7169
|
relationshipName: relName,
|
|
7094
7170
|
relationshipType,
|
|
7095
|
-
after:
|
|
7171
|
+
after: rel
|
|
7096
7172
|
});
|
|
7097
|
-
for (const relName of
|
|
7173
|
+
for (const [relName, rel] of Object.entries(oldRelationships ?? {})) if (!newKeys.has(relName)) ctx.changes.push({
|
|
7098
7174
|
kind: "relationship_removed",
|
|
7099
7175
|
typeName,
|
|
7100
7176
|
relationshipName: relName,
|
|
7101
7177
|
relationshipType,
|
|
7102
|
-
before:
|
|
7178
|
+
before: rel
|
|
7103
7179
|
});
|
|
7104
|
-
for (const relName of
|
|
7105
|
-
const oldRel = oldRelationships[relName];
|
|
7106
|
-
const newRel = newRelationships[relName];
|
|
7180
|
+
for (const [relName, newRel] of Object.entries(newRelationships ?? {})) if (oldKeys.has(relName)) {
|
|
7181
|
+
const oldRel = assertDefined(assertDefined(oldRelationships, "oldRelationships is undefined when oldKeys has entry")[relName], `relationship "${relName}" missing from oldRelationships`);
|
|
7107
7182
|
const reasons = [];
|
|
7108
7183
|
if (oldRel.targetType !== newRel.targetType) reasons.push("targetType changed");
|
|
7109
7184
|
if (oldRel.targetField !== newRel.targetField) reasons.push("targetField changed");
|
|
@@ -7168,16 +7243,16 @@ function compareSnapshots(previous, current) {
|
|
|
7168
7243
|
};
|
|
7169
7244
|
const previousTypeNames = new Set(Object.keys(previous.types));
|
|
7170
7245
|
const currentTypeNames = new Set(Object.keys(current.types));
|
|
7171
|
-
for (const typeName of
|
|
7246
|
+
for (const [typeName, type] of Object.entries(current.types)) if (!previousTypeNames.has(typeName)) ctx.changes.push({
|
|
7172
7247
|
kind: "type_added",
|
|
7173
7248
|
typeName,
|
|
7174
|
-
after:
|
|
7249
|
+
after: type
|
|
7175
7250
|
});
|
|
7176
|
-
for (const typeName of
|
|
7251
|
+
for (const [typeName, type] of Object.entries(previous.types)) if (!currentTypeNames.has(typeName)) {
|
|
7177
7252
|
ctx.changes.push({
|
|
7178
7253
|
kind: "type_removed",
|
|
7179
7254
|
typeName,
|
|
7180
|
-
before:
|
|
7255
|
+
before: type
|
|
7181
7256
|
});
|
|
7182
7257
|
ctx.warnings.push({
|
|
7183
7258
|
typeName,
|
|
@@ -7186,8 +7261,8 @@ function compareSnapshots(previous, current) {
|
|
|
7186
7261
|
}
|
|
7187
7262
|
for (const typeName of currentTypeNames) {
|
|
7188
7263
|
if (!previousTypeNames.has(typeName)) continue;
|
|
7189
|
-
const prevType = previous.types[typeName];
|
|
7190
|
-
const currType = current.types[typeName];
|
|
7264
|
+
const prevType = assertDefined(previous.types[typeName], `type "${typeName}" missing from previous snapshot`);
|
|
7265
|
+
const currType = assertDefined(current.types[typeName], `type "${typeName}" missing from current snapshot`);
|
|
7191
7266
|
compareTypeFields(ctx, typeName, prevType, currType);
|
|
7192
7267
|
compareIndexes(ctx, typeName, prevType.indexes, currType.indexes);
|
|
7193
7268
|
compareFiles(ctx, typeName, prevType.files, currType.files);
|
|
@@ -7245,7 +7320,7 @@ function validateMigrationFiles(migrationsDir) {
|
|
|
7245
7320
|
const schemaFiles = [];
|
|
7246
7321
|
const diffFiles = [];
|
|
7247
7322
|
for (const file of migrationFiles) if (file.type === "schema") schemaFiles.push(file.number);
|
|
7248
|
-
else
|
|
7323
|
+
else diffFiles.push(file.number);
|
|
7249
7324
|
if (!schemaFiles.includes(0)) errors.push({
|
|
7250
7325
|
type: "missing_schema",
|
|
7251
7326
|
message: `Initial schema snapshot (${formatMigrationNumber(0)}/schema.json) is missing`,
|
|
@@ -7414,8 +7489,8 @@ function compareRemoteWithSnapshot(remoteTypes, snapshot) {
|
|
|
7414
7489
|
});
|
|
7415
7490
|
for (const typeName of snapshotTypeNames) {
|
|
7416
7491
|
if (!remoteTypeNames.has(typeName)) continue;
|
|
7417
|
-
const remoteType = remoteTypeMap.get(typeName);
|
|
7418
|
-
const snapshotType = snapshot.types[typeName];
|
|
7492
|
+
const remoteType = assertDefined(remoteTypeMap.get(typeName), `type "${typeName}" missing from remoteTypeMap`);
|
|
7493
|
+
const snapshotType = assertDefined(snapshot.types[typeName], `type "${typeName}" missing from snapshot`);
|
|
7419
7494
|
const remoteFields = convertRemoteFieldsToSnapshot(remoteType);
|
|
7420
7495
|
const snapshotFields = snapshotType.fields;
|
|
7421
7496
|
const remoteFieldNames = new Set(Object.keys(remoteFields).filter((f) => !SYSTEM_FIELDS.has(f)));
|
|
@@ -7434,7 +7509,7 @@ function compareRemoteWithSnapshot(remoteTypes, snapshot) {
|
|
|
7434
7509
|
});
|
|
7435
7510
|
for (const fieldName of snapshotFieldNames) {
|
|
7436
7511
|
if (!remoteFieldNames.has(fieldName)) continue;
|
|
7437
|
-
const drift = compareFields(typeName, fieldName, remoteFields[fieldName], snapshotFields[fieldName]);
|
|
7512
|
+
const drift = compareFields(typeName, fieldName, assertDefined(remoteFields[fieldName], `field "${fieldName}" missing from remoteFields`), assertDefined(snapshotFields[fieldName], `field "${fieldName}" missing from snapshotFields`));
|
|
7438
7513
|
if (drift) drifts.push(drift);
|
|
7439
7514
|
}
|
|
7440
7515
|
}
|
|
@@ -7752,6 +7827,145 @@ function convertOperandToProto(operand) {
|
|
|
7752
7827
|
value: fromJson(ValueSchema, operand)
|
|
7753
7828
|
} };
|
|
7754
7829
|
}
|
|
7830
|
+
/**
|
|
7831
|
+
* Generate all TailorDB type manifests from a schema snapshot
|
|
7832
|
+
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
7833
|
+
* @param {GenerateAllManifestsOptions} options - Generation options
|
|
7834
|
+
* @returns {Map<string, MessageInitShape<typeof TailorDBTypeSchema>>} Map of type name to manifest
|
|
7835
|
+
*/
|
|
7836
|
+
function generateAllTypeManifestsFromSnapshot(snapshot, options = {}) {
|
|
7837
|
+
const manifests = /* @__PURE__ */ new Map();
|
|
7838
|
+
const { executorUsedTypes, ...baseOptions } = options;
|
|
7839
|
+
for (const [typeName, snapshotType] of Object.entries(snapshot.types)) {
|
|
7840
|
+
if (executorUsedTypes?.has(typeName) && snapshotType.settings?.publishEvents === false) throw new Error(`Type "${typeName}" has publishEvents set to false, but it is used by an executor with a record trigger. Either remove the publishEvents: false setting or remove the executor trigger for this type.`);
|
|
7841
|
+
let publishRecordEvents;
|
|
7842
|
+
if (snapshotType.settings?.publishEvents !== void 0) publishRecordEvents = snapshotType.settings.publishEvents;
|
|
7843
|
+
else if (executorUsedTypes?.has(typeName)) publishRecordEvents = true;
|
|
7844
|
+
else publishRecordEvents = baseOptions.publishRecordEvents ?? false;
|
|
7845
|
+
const typeOptions = {
|
|
7846
|
+
...baseOptions,
|
|
7847
|
+
publishRecordEvents
|
|
7848
|
+
};
|
|
7849
|
+
manifests.set(typeName, generateTailorDBTypeManifestFromSnapshot(snapshotType, typeOptions));
|
|
7850
|
+
}
|
|
7851
|
+
return manifests;
|
|
7852
|
+
}
|
|
7853
|
+
/**
|
|
7854
|
+
* Compare snapshot types with existing remote type names
|
|
7855
|
+
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
7856
|
+
* @param {ReadonlySet<string>} existingTypeNames - Set of existing type names in remote
|
|
7857
|
+
* @returns {SnapshotTypeComparison} Comparison result
|
|
7858
|
+
*/
|
|
7859
|
+
function compareSnapshotWithRemote(snapshot, existingTypeNames) {
|
|
7860
|
+
const snapshotTypeNames = new Set(Object.keys(snapshot.types));
|
|
7861
|
+
const creates = [];
|
|
7862
|
+
const updates = [];
|
|
7863
|
+
const deletes = [];
|
|
7864
|
+
for (const typeName of snapshotTypeNames) if (existingTypeNames.has(typeName)) updates.push(typeName);
|
|
7865
|
+
else creates.push(typeName);
|
|
7866
|
+
for (const typeName of existingTypeNames) if (!snapshotTypeNames.has(typeName)) deletes.push(typeName);
|
|
7867
|
+
return {
|
|
7868
|
+
creates,
|
|
7869
|
+
updates,
|
|
7870
|
+
deletes
|
|
7871
|
+
};
|
|
7872
|
+
}
|
|
7873
|
+
/**
|
|
7874
|
+
* Convert snapshot GQL permission policies to the proto request shape.
|
|
7875
|
+
* @param permission - Snapshot GQL permission policies
|
|
7876
|
+
* @returns Proto GQL permission
|
|
7877
|
+
*/
|
|
7878
|
+
function protoGqlPermission(permission) {
|
|
7879
|
+
return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
|
|
7880
|
+
}
|
|
7881
|
+
function protoGqlPolicy(policy) {
|
|
7882
|
+
const actions = [];
|
|
7883
|
+
for (const action of policy.actions) switch (action) {
|
|
7884
|
+
case "all":
|
|
7885
|
+
actions.push(TailorDBGQLPermission_Action.ALL);
|
|
7886
|
+
break;
|
|
7887
|
+
case "create":
|
|
7888
|
+
actions.push(TailorDBGQLPermission_Action.CREATE);
|
|
7889
|
+
break;
|
|
7890
|
+
case "read":
|
|
7891
|
+
actions.push(TailorDBGQLPermission_Action.READ);
|
|
7892
|
+
break;
|
|
7893
|
+
case "update":
|
|
7894
|
+
actions.push(TailorDBGQLPermission_Action.UPDATE);
|
|
7895
|
+
break;
|
|
7896
|
+
case "delete":
|
|
7897
|
+
actions.push(TailorDBGQLPermission_Action.DELETE);
|
|
7898
|
+
break;
|
|
7899
|
+
case "aggregate":
|
|
7900
|
+
actions.push(TailorDBGQLPermission_Action.AGGREGATE);
|
|
7901
|
+
break;
|
|
7902
|
+
case "bulkUpsert":
|
|
7903
|
+
actions.push(TailorDBGQLPermission_Action.BULK_UPSERT);
|
|
7904
|
+
break;
|
|
7905
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
7906
|
+
}
|
|
7907
|
+
let permit;
|
|
7908
|
+
switch (policy.permit) {
|
|
7909
|
+
case "allow":
|
|
7910
|
+
permit = TailorDBGQLPermission_Permit.ALLOW;
|
|
7911
|
+
break;
|
|
7912
|
+
case "deny":
|
|
7913
|
+
permit = TailorDBGQLPermission_Permit.DENY;
|
|
7914
|
+
break;
|
|
7915
|
+
default: throw new Error(`Unknown permission: ${policy.permit}`);
|
|
7916
|
+
}
|
|
7917
|
+
return {
|
|
7918
|
+
conditions: policy.conditions.map((cond) => protoGqlCondition(cond)),
|
|
7919
|
+
actions,
|
|
7920
|
+
permit,
|
|
7921
|
+
description: policy.description
|
|
7922
|
+
};
|
|
7923
|
+
}
|
|
7924
|
+
function protoGqlCondition(condition) {
|
|
7925
|
+
const [left, operator, right] = condition;
|
|
7926
|
+
const l = protoGqlOperand(left);
|
|
7927
|
+
const r = protoGqlOperand(right);
|
|
7928
|
+
let op;
|
|
7929
|
+
switch (operator) {
|
|
7930
|
+
case "eq":
|
|
7931
|
+
op = TailorDBGQLPermission_Operator.EQ;
|
|
7932
|
+
break;
|
|
7933
|
+
case "ne":
|
|
7934
|
+
op = TailorDBGQLPermission_Operator.NE;
|
|
7935
|
+
break;
|
|
7936
|
+
case "in":
|
|
7937
|
+
op = TailorDBGQLPermission_Operator.IN;
|
|
7938
|
+
break;
|
|
7939
|
+
case "nin":
|
|
7940
|
+
op = TailorDBGQLPermission_Operator.NIN;
|
|
7941
|
+
break;
|
|
7942
|
+
case "hasAny":
|
|
7943
|
+
op = TailorDBGQLPermission_Operator.HAS_ANY;
|
|
7944
|
+
break;
|
|
7945
|
+
case "nhasAny":
|
|
7946
|
+
op = TailorDBGQLPermission_Operator.NHAS_ANY;
|
|
7947
|
+
break;
|
|
7948
|
+
default: throw new Error(`Unknown operator: ${operator}`);
|
|
7949
|
+
}
|
|
7950
|
+
return {
|
|
7951
|
+
left: l,
|
|
7952
|
+
operator: op,
|
|
7953
|
+
right: r
|
|
7954
|
+
};
|
|
7955
|
+
}
|
|
7956
|
+
function protoGqlOperand(operand) {
|
|
7957
|
+
if (isSnapshotFieldRefOperand(operand)) {
|
|
7958
|
+
if ("user" in operand) return { kind: {
|
|
7959
|
+
case: "userField",
|
|
7960
|
+
value: operand.user
|
|
7961
|
+
} };
|
|
7962
|
+
throw new Error(`Unsupported field-ref operand in GQL permission: ${JSON.stringify(operand)} — GQL permissions only support { user } field references`);
|
|
7963
|
+
}
|
|
7964
|
+
return { kind: {
|
|
7965
|
+
case: "value",
|
|
7966
|
+
value: fromJson(ValueSchema, operand)
|
|
7967
|
+
} };
|
|
7968
|
+
}
|
|
7755
7969
|
|
|
7756
7970
|
//#endregion
|
|
7757
7971
|
//#region src/cli/commands/tailordb/migrate/pre-migration-schema.ts
|
|
@@ -7850,6 +8064,45 @@ function applyPreMigrationFieldAdjustments(fields, typeChanges) {
|
|
|
7850
8064
|
}
|
|
7851
8065
|
}
|
|
7852
8066
|
|
|
8067
|
+
//#endregion
|
|
8068
|
+
//#region src/cli/commands/tailordb/migrate/types.ts
|
|
8069
|
+
/**
|
|
8070
|
+
* Types for TailorDB migration execution
|
|
8071
|
+
*/
|
|
8072
|
+
/**
|
|
8073
|
+
* Prefix added to migration numbers in labels (required because migration names start with numbers)
|
|
8074
|
+
*/
|
|
8075
|
+
const MIGRATION_LABEL_PREFIX = "m";
|
|
8076
|
+
/**
|
|
8077
|
+
* Label key for storing migration state in TailorDB Service metadata
|
|
8078
|
+
*/
|
|
8079
|
+
const MIGRATION_LABEL_KEY = "sdk-migration";
|
|
8080
|
+
/**
|
|
8081
|
+
* Parse migration number from label value
|
|
8082
|
+
* @param {string} label - Label value (e.g., "m0001")
|
|
8083
|
+
* @returns {number | null} Parsed number or null if invalid
|
|
8084
|
+
*/
|
|
8085
|
+
function parseMigrationLabelNumber(label) {
|
|
8086
|
+
if (!label.startsWith("m")) return null;
|
|
8087
|
+
const numStr = label.slice(1);
|
|
8088
|
+
if (!/^\d+$/.test(numStr)) return null;
|
|
8089
|
+
const num = parseInt(numStr, 10);
|
|
8090
|
+
return num > 9999 ? null : num;
|
|
8091
|
+
}
|
|
8092
|
+
/**
|
|
8093
|
+
* Handle optional-to-required field change error with helpful message
|
|
8094
|
+
* @param {unknown} error - Error to handle
|
|
8095
|
+
* @param {string[]} messages - Additional messages to display
|
|
8096
|
+
*/
|
|
8097
|
+
function handleOptionalToRequiredError(error, messages) {
|
|
8098
|
+
if (error instanceof ConnectError && error.code === Code.FailedPrecondition && error.message.includes("cannot be updated from non-required to required when records exist")) {
|
|
8099
|
+
logger.error("Schema change failed: Cannot change field from optional to required when records exist.");
|
|
8100
|
+
logger.newline();
|
|
8101
|
+
for (const message of messages) logger.info(message);
|
|
8102
|
+
}
|
|
8103
|
+
throw error;
|
|
8104
|
+
}
|
|
8105
|
+
|
|
7853
8106
|
//#endregion
|
|
7854
8107
|
//#region src/cli/commands/tailordb/migrate/bundler.ts
|
|
7855
8108
|
/**
|
|
@@ -7929,28 +8182,6 @@ async function bundleMigrationScript(sourceFile, namespace, migrationNumber, env
|
|
|
7929
8182
|
};
|
|
7930
8183
|
}
|
|
7931
8184
|
|
|
7932
|
-
//#endregion
|
|
7933
|
-
//#region src/cli/commands/tailordb/migrate/types.ts
|
|
7934
|
-
/**
|
|
7935
|
-
* Prefix added to migration numbers in labels (required because migration names start with numbers)
|
|
7936
|
-
*/
|
|
7937
|
-
const MIGRATION_LABEL_PREFIX = "m";
|
|
7938
|
-
/**
|
|
7939
|
-
* Label key for storing migration state in TailorDB Service metadata
|
|
7940
|
-
*/
|
|
7941
|
-
const MIGRATION_LABEL_KEY = "sdk-migration";
|
|
7942
|
-
/**
|
|
7943
|
-
* Parse migration number from label value
|
|
7944
|
-
* @param {string} label - Label value (e.g., "m0001")
|
|
7945
|
-
* @returns {number | null} Parsed number or null if invalid
|
|
7946
|
-
*/
|
|
7947
|
-
function parseMigrationLabelNumber(label) {
|
|
7948
|
-
if (!label.startsWith("m")) return null;
|
|
7949
|
-
const numStr = label.slice(1);
|
|
7950
|
-
const num = parseInt(numStr, 10);
|
|
7951
|
-
return isNaN(num) ? null : num;
|
|
7952
|
-
}
|
|
7953
|
-
|
|
7954
8185
|
//#endregion
|
|
7955
8186
|
//#region src/cli/shared/script-executor.ts
|
|
7956
8187
|
/**
|
|
@@ -8155,7 +8386,7 @@ var Spinner = class {
|
|
|
8155
8386
|
#renderFrame() {
|
|
8156
8387
|
this.#stream.write(SYNC_BEGIN);
|
|
8157
8388
|
this.#clearDrawn();
|
|
8158
|
-
const frame = styles.info(FRAMES[this.#frame] ?? FRAMES[0]);
|
|
8389
|
+
const frame = styles.info(FRAMES[this.#frame] ?? assertDefined(FRAMES[0], "spinner frames empty"));
|
|
8159
8390
|
this.#frame = (this.#frame + 1) % FRAMES.length;
|
|
8160
8391
|
const line = `${" ".repeat(this.#indent)}${frame} ${this.text}`;
|
|
8161
8392
|
this.#stream.write(line);
|
|
@@ -8401,10 +8632,10 @@ async function getRemoteMigrationNumber(client, workspaceId, namespace) {
|
|
|
8401
8632
|
try {
|
|
8402
8633
|
const trn = resourceTrn(workspaceId, "tailordb", namespace);
|
|
8403
8634
|
const { metadata } = await client.getMetadata({ trn });
|
|
8404
|
-
const label = metadata?.labels
|
|
8635
|
+
const label = metadata?.labels["sdk-migration"];
|
|
8405
8636
|
if (!label) return null;
|
|
8406
8637
|
const match = label.match(/^m(\d+)$/);
|
|
8407
|
-
return match ? parseInt(match[1], 10) : null;
|
|
8638
|
+
return match ? parseInt(assertDefined(match[1], "migration label capture group missing"), 10) : null;
|
|
8408
8639
|
} catch {
|
|
8409
8640
|
return null;
|
|
8410
8641
|
}
|
|
@@ -8619,20 +8850,7 @@ async function applyTailorDB(client, result, phase = "create-update") {
|
|
|
8619
8850
|
} else if (phase === "delete-resources") {
|
|
8620
8851
|
await Promise.all(changeSet.gqlPermission.deletes.map((del) => client.deleteTailorDBGQLPermission(del.request)));
|
|
8621
8852
|
await Promise.all(changeSet.type.deletes.map((del) => client.deleteTailorDBType(del.request)));
|
|
8622
|
-
} else
|
|
8623
|
-
}
|
|
8624
|
-
/**
|
|
8625
|
-
* Handle optional-to-required field change error with helpful message
|
|
8626
|
-
* @param {unknown} error - Error to handle
|
|
8627
|
-
* @param {string[]} messages - Additional messages to display
|
|
8628
|
-
*/
|
|
8629
|
-
function handleOptionalToRequiredError(error, messages) {
|
|
8630
|
-
if (error instanceof ConnectError && error.code === Code.FailedPrecondition && error.message.includes("cannot be updated from non-required to required when records exist")) {
|
|
8631
|
-
logger.error("Schema change failed: Cannot change field from optional to required when records exist.");
|
|
8632
|
-
logger.newline();
|
|
8633
|
-
for (const message of messages) logger.info(message);
|
|
8634
|
-
}
|
|
8635
|
-
throw error;
|
|
8853
|
+
} else await Promise.all(changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)));
|
|
8636
8854
|
}
|
|
8637
8855
|
/**
|
|
8638
8856
|
* Get the set of type names affected by a migration
|
|
@@ -8746,7 +8964,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
8746
8964
|
const clonedRequest = structuredClone(create.request);
|
|
8747
8965
|
clonedRequest.tailordbType = snapshotType;
|
|
8748
8966
|
const typeChanges = typeName ? preMigrationChanges.get(typeName) : void 0;
|
|
8749
|
-
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType
|
|
8967
|
+
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
|
|
8750
8968
|
return client.createTailorDBType(clonedRequest);
|
|
8751
8969
|
}),
|
|
8752
8970
|
...changeSet.type.creates.filter((create) => {
|
|
@@ -8777,7 +8995,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
8777
8995
|
const clonedRequest = structuredClone(update.request);
|
|
8778
8996
|
clonedRequest.tailordbType = snapshotType;
|
|
8779
8997
|
const typeChanges = typeName ? preMigrationChanges.get(typeName) : void 0;
|
|
8780
|
-
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType
|
|
8998
|
+
if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
|
|
8781
8999
|
return client.updateTailorDBType(clonedRequest);
|
|
8782
9000
|
})
|
|
8783
9001
|
]);
|
|
@@ -9075,17 +9293,14 @@ async function planTypes(client, workspaceId, tailordbs, executorUsedTypes, dele
|
|
|
9075
9293
|
};
|
|
9076
9294
|
for (const tailordb of tailordbs) {
|
|
9077
9295
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
9078
|
-
for (const typeName of Object.
|
|
9079
|
-
const type = types[typeName];
|
|
9080
|
-
if (executorUsedTypes.has(typeName) && type.settings?.publishEvents === false) throw new Error(`Type "${typeName}" has publishEvents set to false, but it is used by an executor with a record trigger. Either remove the publishEvents: false setting or remove the executor trigger for this type.`);
|
|
9081
|
-
}
|
|
9296
|
+
for (const [typeName, type] of Object.entries(types)) if (executorUsedTypes.has(typeName) && type.settings?.publishEvents === false) throw new Error(`Type "${typeName}" has publishEvents set to false, but it is used by an executor with a record trigger. Either remove the publishEvents: false setting or remove the executor trigger for this type.`);
|
|
9082
9297
|
}
|
|
9083
9298
|
for (const tailordb of tailordbs) {
|
|
9084
9299
|
const existingTypes = await fetchTypes(tailordb.namespace);
|
|
9085
9300
|
const existingTypesMap = new Map(existingTypes.map((type) => [type.name, type]));
|
|
9086
9301
|
const types = filteredTypesByNamespace?.get(tailordb.namespace) ?? tailordb.types;
|
|
9087
|
-
for (const typeName of Object.
|
|
9088
|
-
const tailordbType = generateTailorDBTypeManifestFromSnapshot(
|
|
9302
|
+
for (const [typeName, tailordbTypeSnapshot] of Object.entries(types)) {
|
|
9303
|
+
const tailordbType = generateTailorDBTypeManifestFromSnapshot(tailordbTypeSnapshot, {
|
|
9089
9304
|
publishRecordEvents: executorUsedTypes.has(typeName),
|
|
9090
9305
|
namespaceGqlOperations: tailordb.config.gqlOperations
|
|
9091
9306
|
});
|
|
@@ -9230,8 +9445,8 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
9230
9445
|
existingNameSet.add(gqlPermission.typeName);
|
|
9231
9446
|
});
|
|
9232
9447
|
const types = tailordb.types;
|
|
9233
|
-
for (const typeName of Object.
|
|
9234
|
-
const gqlPermission =
|
|
9448
|
+
for (const [typeName, typeEntry] of Object.entries(types)) {
|
|
9449
|
+
const gqlPermission = typeEntry.permissions?.gql;
|
|
9235
9450
|
if (!gqlPermission) continue;
|
|
9236
9451
|
const desiredPermission = protoGqlPermission(gqlPermission);
|
|
9237
9452
|
const existingPermission = existingGqlPermissions.find((entry) => entry.typeName === typeName);
|
|
@@ -9286,97 +9501,6 @@ function normalizeComparableGqlPermission(permission) {
|
|
|
9286
9501
|
actions: (policy.actions ?? []).toSorted((left, right) => left - right)
|
|
9287
9502
|
})) };
|
|
9288
9503
|
}
|
|
9289
|
-
function protoGqlPermission(permission) {
|
|
9290
|
-
return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
|
|
9291
|
-
}
|
|
9292
|
-
function protoGqlPolicy(policy) {
|
|
9293
|
-
const actions = [];
|
|
9294
|
-
for (const action of policy.actions) switch (action) {
|
|
9295
|
-
case "all":
|
|
9296
|
-
actions.push(TailorDBGQLPermission_Action.ALL);
|
|
9297
|
-
break;
|
|
9298
|
-
case "create":
|
|
9299
|
-
actions.push(TailorDBGQLPermission_Action.CREATE);
|
|
9300
|
-
break;
|
|
9301
|
-
case "read":
|
|
9302
|
-
actions.push(TailorDBGQLPermission_Action.READ);
|
|
9303
|
-
break;
|
|
9304
|
-
case "update":
|
|
9305
|
-
actions.push(TailorDBGQLPermission_Action.UPDATE);
|
|
9306
|
-
break;
|
|
9307
|
-
case "delete":
|
|
9308
|
-
actions.push(TailorDBGQLPermission_Action.DELETE);
|
|
9309
|
-
break;
|
|
9310
|
-
case "aggregate":
|
|
9311
|
-
actions.push(TailorDBGQLPermission_Action.AGGREGATE);
|
|
9312
|
-
break;
|
|
9313
|
-
case "bulkUpsert":
|
|
9314
|
-
actions.push(TailorDBGQLPermission_Action.BULK_UPSERT);
|
|
9315
|
-
break;
|
|
9316
|
-
default: throw new Error(`Unknown action: ${action}`);
|
|
9317
|
-
}
|
|
9318
|
-
let permit;
|
|
9319
|
-
switch (policy.permit) {
|
|
9320
|
-
case "allow":
|
|
9321
|
-
permit = TailorDBGQLPermission_Permit.ALLOW;
|
|
9322
|
-
break;
|
|
9323
|
-
case "deny":
|
|
9324
|
-
permit = TailorDBGQLPermission_Permit.DENY;
|
|
9325
|
-
break;
|
|
9326
|
-
default: throw new Error(`Unknown permission: ${policy.permit}`);
|
|
9327
|
-
}
|
|
9328
|
-
return {
|
|
9329
|
-
conditions: policy.conditions.map((cond) => protoGqlCondition(cond)),
|
|
9330
|
-
actions,
|
|
9331
|
-
permit,
|
|
9332
|
-
description: policy.description
|
|
9333
|
-
};
|
|
9334
|
-
}
|
|
9335
|
-
function protoGqlCondition(condition) {
|
|
9336
|
-
const [left, operator, right] = condition;
|
|
9337
|
-
const l = protoGqlOperand(left);
|
|
9338
|
-
const r = protoGqlOperand(right);
|
|
9339
|
-
let op;
|
|
9340
|
-
switch (operator) {
|
|
9341
|
-
case "eq":
|
|
9342
|
-
op = TailorDBGQLPermission_Operator.EQ;
|
|
9343
|
-
break;
|
|
9344
|
-
case "ne":
|
|
9345
|
-
op = TailorDBGQLPermission_Operator.NE;
|
|
9346
|
-
break;
|
|
9347
|
-
case "in":
|
|
9348
|
-
op = TailorDBGQLPermission_Operator.IN;
|
|
9349
|
-
break;
|
|
9350
|
-
case "nin":
|
|
9351
|
-
op = TailorDBGQLPermission_Operator.NIN;
|
|
9352
|
-
break;
|
|
9353
|
-
case "hasAny":
|
|
9354
|
-
op = TailorDBGQLPermission_Operator.HAS_ANY;
|
|
9355
|
-
break;
|
|
9356
|
-
case "nhasAny":
|
|
9357
|
-
op = TailorDBGQLPermission_Operator.NHAS_ANY;
|
|
9358
|
-
break;
|
|
9359
|
-
default: throw new Error(`Unknown operator: ${operator}`);
|
|
9360
|
-
}
|
|
9361
|
-
return {
|
|
9362
|
-
left: l,
|
|
9363
|
-
operator: op,
|
|
9364
|
-
right: r
|
|
9365
|
-
};
|
|
9366
|
-
}
|
|
9367
|
-
function protoGqlOperand(operand) {
|
|
9368
|
-
if (isSnapshotFieldRefOperand(operand)) {
|
|
9369
|
-
if ("user" in operand) return { kind: {
|
|
9370
|
-
case: "userField",
|
|
9371
|
-
value: operand.user
|
|
9372
|
-
} };
|
|
9373
|
-
throw new Error(`Unsupported field-ref operand in GQL permission: ${JSON.stringify(operand)} — GQL permissions only support { user } field references`);
|
|
9374
|
-
}
|
|
9375
|
-
return { kind: {
|
|
9376
|
-
case: "value",
|
|
9377
|
-
value: fromJson(ValueSchema, operand)
|
|
9378
|
-
} };
|
|
9379
|
-
}
|
|
9380
9504
|
/**
|
|
9381
9505
|
* Check if there are schema differences between migration snapshots and local definitions
|
|
9382
9506
|
* @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Snapshot-shaped local types by namespace
|
|
@@ -9454,28 +9578,30 @@ async function applyWorkflow(client, result, phase = "create-update") {
|
|
|
9454
9578
|
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, appId, result.unchangedWorkflowJobNames);
|
|
9455
9579
|
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
9456
9580
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
|
|
9581
|
+
const shape = buildWorkflowValidationShape(create.workspaceId, create.workflow);
|
|
9457
9582
|
await client.createWorkflow({
|
|
9458
|
-
workspaceId:
|
|
9459
|
-
workflowName:
|
|
9460
|
-
mainJobFunctionName:
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9583
|
+
workspaceId: shape.workspaceId,
|
|
9584
|
+
workflowName: shape.workflowName,
|
|
9585
|
+
mainJobFunctionName: shape.mainJobFunctionName,
|
|
9586
|
+
retryPolicy: shape.retryPolicy,
|
|
9587
|
+
concurrencyPolicy: shape.concurrencyPolicy,
|
|
9588
|
+
jobFunctions: filteredVersions
|
|
9464
9589
|
});
|
|
9465
9590
|
await client.setMetadata(create.metaRequest);
|
|
9466
9591
|
}), ...changeSet.updates.map(async (update) => {
|
|
9467
9592
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, update.usedJobNames);
|
|
9593
|
+
const shape = buildWorkflowValidationShape(update.workspaceId, update.workflow);
|
|
9468
9594
|
await client.updateWorkflow({
|
|
9469
|
-
workspaceId:
|
|
9470
|
-
workflowName:
|
|
9471
|
-
mainJobFunctionName:
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9595
|
+
workspaceId: shape.workspaceId,
|
|
9596
|
+
workflowName: shape.workflowName,
|
|
9597
|
+
mainJobFunctionName: shape.mainJobFunctionName,
|
|
9598
|
+
retryPolicy: shape.retryPolicy,
|
|
9599
|
+
concurrencyPolicy: shape.concurrencyPolicy,
|
|
9600
|
+
jobFunctions: filteredVersions
|
|
9475
9601
|
});
|
|
9476
9602
|
await client.setMetadata(update.metaRequest);
|
|
9477
9603
|
})]);
|
|
9478
|
-
} else
|
|
9604
|
+
} else {
|
|
9479
9605
|
await deleteAllSettled(changeSet.deletes.map((del) => ({
|
|
9480
9606
|
resourceType: "workflow",
|
|
9481
9607
|
resourceName: del.name,
|
|
@@ -9499,12 +9625,8 @@ async function deleteAllSettled(operations) {
|
|
|
9499
9625
|
const errors = [];
|
|
9500
9626
|
results.forEach((result, index) => {
|
|
9501
9627
|
if (result.status === "fulfilled") return;
|
|
9502
|
-
const operation = operations[index];
|
|
9628
|
+
const operation = assertDefined(operations[index], "operation missing at index");
|
|
9503
9629
|
const error = result.reason;
|
|
9504
|
-
if (!operation) {
|
|
9505
|
-
errors.push(error);
|
|
9506
|
-
return;
|
|
9507
|
-
}
|
|
9508
9630
|
if (error instanceof ConnectError && error.code === Code.NotFound) return;
|
|
9509
9631
|
if (error instanceof ConnectError && error.code === Code.FailedPrecondition) {
|
|
9510
9632
|
logger.warn(`Skipped deleting ${operation.resourceType} "${operation.resourceName}" because it is still referenced.`);
|
|
@@ -9615,6 +9737,21 @@ function toConcurrencyPolicy(policy) {
|
|
|
9615
9737
|
return { maxConcurrentExecutions: policy.maxConcurrentExecutions };
|
|
9616
9738
|
}
|
|
9617
9739
|
/**
|
|
9740
|
+
* Build the plan-time validation init shape for a workflow.
|
|
9741
|
+
* @param workspaceId - Workspace ID
|
|
9742
|
+
* @param workflow - Parsed workflow object
|
|
9743
|
+
* @returns Init shape suitable for validating against CreateWorkflowRequestSchema and UpdateWorkflowRequestSchema
|
|
9744
|
+
*/
|
|
9745
|
+
function buildWorkflowValidationShape(workspaceId, workflow) {
|
|
9746
|
+
return {
|
|
9747
|
+
workspaceId,
|
|
9748
|
+
workflowName: workflow.name,
|
|
9749
|
+
mainJobFunctionName: workflow.mainJob.name,
|
|
9750
|
+
...workflow.retryPolicy && { retryPolicy: toRetryPolicy(workflow.retryPolicy) },
|
|
9751
|
+
...workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(workflow.concurrencyPolicy) }
|
|
9752
|
+
};
|
|
9753
|
+
}
|
|
9754
|
+
/**
|
|
9618
9755
|
* Plan workflow changes and job functions based on current and desired state.
|
|
9619
9756
|
* @param client - Operator client instance
|
|
9620
9757
|
* @param workspaceId - Workspace ID
|
|
@@ -9814,6 +9951,191 @@ function normalizeRetryPolicyForCompare(policy) {
|
|
|
9814
9951
|
};
|
|
9815
9952
|
}
|
|
9816
9953
|
|
|
9954
|
+
//#endregion
|
|
9955
|
+
//#region src/cli/commands/deploy/validate-plan.ts
|
|
9956
|
+
function validateItems(params) {
|
|
9957
|
+
const { validator, schema, kind, action, items, requestKey, violations } = params;
|
|
9958
|
+
for (const item of items) {
|
|
9959
|
+
const init = item[requestKey];
|
|
9960
|
+
const msg = create(schema, init);
|
|
9961
|
+
const result = validator.validate(schema, msg);
|
|
9962
|
+
if (result.kind === "invalid") for (const v of result.violations) violations.push({
|
|
9963
|
+
kind,
|
|
9964
|
+
name: item.name,
|
|
9965
|
+
action,
|
|
9966
|
+
fieldPath: v.field.length > 0 ? pathToString(v.field) : "(message)",
|
|
9967
|
+
message: v.message
|
|
9968
|
+
});
|
|
9969
|
+
else if (result.kind === "error") logger.warn(`Could not validate ${kind} "${item.name}" (${action}): ${result.error.message}`);
|
|
9970
|
+
}
|
|
9971
|
+
}
|
|
9972
|
+
/**
|
|
9973
|
+
* Validate all plan-time create/update requests against buf.validate constraints embedded in the
|
|
9974
|
+
* generated proto descriptors.
|
|
9975
|
+
*
|
|
9976
|
+
* Collections not validated: idp client, tailorDB gqlPermission, functionRegistry — no
|
|
9977
|
+
* buf.validate annotations.
|
|
9978
|
+
* Application cors is excluded: static-website URL placeholders are resolved at apply time
|
|
9979
|
+
* and a bare cors array carries no constraint that would false-positive when omitted.
|
|
9980
|
+
* Workflow jobFunctions map excluded: versions are registered at apply time (registerJobFunctions)
|
|
9981
|
+
* and the map field carries no min_items constraint. Job names are validated separately via
|
|
9982
|
+
* CreateWorkflowJobFunctionRequestSchema using usedJobNames from the workflow change set.
|
|
9983
|
+
* auth idpConfig.config (provider oneof) is absent at plan time for BuiltInIdP but carries no
|
|
9984
|
+
* required constraint — the request is validated as-is from the changeset.
|
|
9985
|
+
*
|
|
9986
|
+
* @param input - Plan results from the plan phase
|
|
9987
|
+
*/
|
|
9988
|
+
async function validatePlan(input) {
|
|
9989
|
+
const { tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager } = input;
|
|
9990
|
+
const validator = createValidator();
|
|
9991
|
+
const violations = [];
|
|
9992
|
+
function creates(schema, kind, items) {
|
|
9993
|
+
validateItems({
|
|
9994
|
+
validator,
|
|
9995
|
+
schema,
|
|
9996
|
+
kind,
|
|
9997
|
+
action: "create",
|
|
9998
|
+
items,
|
|
9999
|
+
requestKey: "request",
|
|
10000
|
+
violations
|
|
10001
|
+
});
|
|
10002
|
+
}
|
|
10003
|
+
function updates(schema, kind, items) {
|
|
10004
|
+
validateItems({
|
|
10005
|
+
validator,
|
|
10006
|
+
schema,
|
|
10007
|
+
kind,
|
|
10008
|
+
action: "update",
|
|
10009
|
+
items,
|
|
10010
|
+
requestKey: "request",
|
|
10011
|
+
violations
|
|
10012
|
+
});
|
|
10013
|
+
}
|
|
10014
|
+
function replaces(schema, kind, items) {
|
|
10015
|
+
validateItems({
|
|
10016
|
+
validator,
|
|
10017
|
+
schema,
|
|
10018
|
+
kind,
|
|
10019
|
+
action: "replace",
|
|
10020
|
+
items,
|
|
10021
|
+
requestKey: "createRequest",
|
|
10022
|
+
violations
|
|
10023
|
+
});
|
|
10024
|
+
}
|
|
10025
|
+
creates(CreateTailorDBServiceRequestSchema, "TailorDB service", tailorDB.changeSet.service.creates);
|
|
10026
|
+
creates(CreateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.creates);
|
|
10027
|
+
updates(UpdateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.updates);
|
|
10028
|
+
creates(CreateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.creates);
|
|
10029
|
+
updates(UpdateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.updates);
|
|
10030
|
+
creates(AddCustomDomainRequestSchema, "StaticWebsite custom domain", staticWebsite.customDomainChangeSet.creates);
|
|
10031
|
+
creates(CreateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.creates);
|
|
10032
|
+
updates(UpdateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.updates);
|
|
10033
|
+
const idpClientVaultItems = [...idp.changeSet.client.creates.map((c) => ({
|
|
10034
|
+
clientName: c.request.client?.name ?? "",
|
|
10035
|
+
namespaceName: c.request.namespaceName ?? "",
|
|
10036
|
+
workspaceId: c.request.workspaceId ?? ""
|
|
10037
|
+
})), ...idp.changeSet.client.updates.map((u) => ({
|
|
10038
|
+
clientName: u.name,
|
|
10039
|
+
namespaceName: u.namespaceName,
|
|
10040
|
+
workspaceId: u.workspaceId
|
|
10041
|
+
}))];
|
|
10042
|
+
creates(CreateSecretManagerVaultRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
|
|
10043
|
+
name: item.clientName,
|
|
10044
|
+
request: {
|
|
10045
|
+
workspaceId: item.workspaceId,
|
|
10046
|
+
secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName)
|
|
10047
|
+
}
|
|
10048
|
+
})));
|
|
10049
|
+
creates(CreateSecretManagerSecretRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
|
|
10050
|
+
name: item.clientName,
|
|
10051
|
+
request: {
|
|
10052
|
+
workspaceId: item.workspaceId,
|
|
10053
|
+
secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName),
|
|
10054
|
+
secretmanagerSecretName: idpClientSecretName(item.namespaceName, item.clientName)
|
|
10055
|
+
}
|
|
10056
|
+
})));
|
|
10057
|
+
creates(CreateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.creates);
|
|
10058
|
+
updates(UpdateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.updates);
|
|
10059
|
+
creates(CreateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.creates);
|
|
10060
|
+
updates(UpdateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.updates);
|
|
10061
|
+
creates(CreateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.creates);
|
|
10062
|
+
updates(UpdateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.updates);
|
|
10063
|
+
creates(CreateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.creates);
|
|
10064
|
+
updates(UpdateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.updates);
|
|
10065
|
+
creates(CreateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.creates);
|
|
10066
|
+
updates(UpdateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.updates);
|
|
10067
|
+
creates(CreateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.creates);
|
|
10068
|
+
updates(UpdateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.updates);
|
|
10069
|
+
creates(CreateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.creates);
|
|
10070
|
+
updates(UpdateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.updates);
|
|
10071
|
+
creates(CreateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.creates);
|
|
10072
|
+
updates(UpdateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.updates);
|
|
10073
|
+
creates(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.creates);
|
|
10074
|
+
updates(UpdateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.updates);
|
|
10075
|
+
replaces(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.replaces);
|
|
10076
|
+
creates(CreatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.creates);
|
|
10077
|
+
updates(UpdatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.updates);
|
|
10078
|
+
creates(CreatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.creates);
|
|
10079
|
+
updates(UpdatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.updates);
|
|
10080
|
+
creates(CreateExecutorExecutorRequestSchema, "Executor", executor.changeSet.creates);
|
|
10081
|
+
updates(UpdateExecutorExecutorRequestSchema, "Executor", executor.changeSet.updates);
|
|
10082
|
+
creates(CreateWorkflowRequestSchema, "Workflow", workflow.changeSet.creates.map((item) => ({
|
|
10083
|
+
name: item.name,
|
|
10084
|
+
request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
|
|
10085
|
+
})));
|
|
10086
|
+
updates(UpdateWorkflowRequestSchema, "Workflow", workflow.changeSet.updates.map((item) => ({
|
|
10087
|
+
name: item.name,
|
|
10088
|
+
request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
|
|
10089
|
+
})));
|
|
10090
|
+
const workflowJobNameWorkspaceId = workflow.changeSet.creates[0]?.workspaceId ?? workflow.changeSet.updates[0]?.workspaceId ?? "";
|
|
10091
|
+
if (workflowJobNameWorkspaceId) {
|
|
10092
|
+
const allJobNames = /* @__PURE__ */ new Set();
|
|
10093
|
+
for (const item of [...workflow.changeSet.creates, ...workflow.changeSet.updates]) for (const jobName of item.usedJobNames) allJobNames.add(jobName);
|
|
10094
|
+
for (const jobName of workflow.unchangedWorkflowJobNames) allJobNames.add(jobName);
|
|
10095
|
+
creates(CreateWorkflowJobFunctionRequestSchema, "Workflow job function", [...allJobNames].map((jobName) => ({
|
|
10096
|
+
name: jobName,
|
|
10097
|
+
request: {
|
|
10098
|
+
workspaceId: workflowJobNameWorkspaceId,
|
|
10099
|
+
jobFunctionName: jobName,
|
|
10100
|
+
scriptRef: jobName
|
|
10101
|
+
}
|
|
10102
|
+
})));
|
|
10103
|
+
}
|
|
10104
|
+
creates(CreateSecretManagerVaultRequestSchema, "Secret Manager vault", secretManager.vaultChangeSet.creates.map((item) => ({
|
|
10105
|
+
name: item.name,
|
|
10106
|
+
request: vaultCreateRequest(item)
|
|
10107
|
+
})));
|
|
10108
|
+
creates(CreateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.creates.map((item) => ({
|
|
10109
|
+
name: item.name,
|
|
10110
|
+
request: secretCreateRequest(item)
|
|
10111
|
+
})));
|
|
10112
|
+
updates(UpdateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.updates.map((item) => ({
|
|
10113
|
+
name: item.name,
|
|
10114
|
+
request: secretUpdateRequest(item)
|
|
10115
|
+
})));
|
|
10116
|
+
creates(CreateApplicationRequestSchema, "Application", app.creates.map((item) => ({
|
|
10117
|
+
name: item.name,
|
|
10118
|
+
request: {
|
|
10119
|
+
...item.request,
|
|
10120
|
+
cors: void 0
|
|
10121
|
+
}
|
|
10122
|
+
})));
|
|
10123
|
+
updates(UpdateApplicationRequestSchema, "Application", [...app.updates, ...app.unchanged].map((item) => ({
|
|
10124
|
+
name: item.name,
|
|
10125
|
+
request: {
|
|
10126
|
+
...item.request,
|
|
10127
|
+
cors: void 0
|
|
10128
|
+
}
|
|
10129
|
+
})));
|
|
10130
|
+
creates(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.creates);
|
|
10131
|
+
replaces(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.replaces);
|
|
10132
|
+
if (violations.length === 0) return;
|
|
10133
|
+
const resourceNames = new Set(violations.map((v) => `${v.kind}:${v.name}`));
|
|
10134
|
+
logger.error(`Pre-flight validation found ${violations.length} violation(s) across ${resourceNames.size} resource(s):`);
|
|
10135
|
+
for (const v of violations) logger.log(` ${styles.resourceType(v.kind)} ${styles.resourceName(v.name)} (${v.action}) — ${styles.bold(v.fieldPath)}: ${v.message}`);
|
|
10136
|
+
throw new Error(`${violations.length} validation error(s) found in ${resourceNames.size} resource(s)`);
|
|
10137
|
+
}
|
|
10138
|
+
|
|
9817
10139
|
//#endregion
|
|
9818
10140
|
//#region src/cli/commands/deploy/deploy.ts
|
|
9819
10141
|
/**
|
|
@@ -9831,7 +10153,10 @@ function collectIdpUserTriggerTargets(application) {
|
|
|
9831
10153
|
for (const executor of Object.values(application.executorService?.executors ?? {})) {
|
|
9832
10154
|
if (executor.trigger.kind !== "idpUser") continue;
|
|
9833
10155
|
if (executor.trigger.idp != null) targets.add(executor.trigger.idp);
|
|
9834
|
-
else if (idps.length === 1)
|
|
10156
|
+
else if (idps.length === 1) {
|
|
10157
|
+
const [idp] = idps;
|
|
10158
|
+
if (idp) targets.add(idp.name);
|
|
10159
|
+
}
|
|
9835
10160
|
}
|
|
9836
10161
|
return targets;
|
|
9837
10162
|
}
|
|
@@ -9914,7 +10239,7 @@ function printPlanResults(results) {
|
|
|
9914
10239
|
...formatChangeSetEntries(results.auth.changeSet.oauth2Client, ["oauth2Client"], namespaceOf),
|
|
9915
10240
|
...formatChangeSetEntries(results.auth.changeSet.scim, ["scimConfig"], namespaceOf),
|
|
9916
10241
|
...formatChangeSetEntries(results.auth.changeSet.scimResource, ["scimResource"], namespaceOf),
|
|
9917
|
-
...
|
|
10242
|
+
...formatChangeSetEntries(results.auth.changeSet.connection, ["connection"], namespaceOf)
|
|
9918
10243
|
];
|
|
9919
10244
|
const { otherChanges: otherFunctionRegistryChanges } = splitFunctionRegistryChanges(results.functionRegistry.changeSet);
|
|
9920
10245
|
printGroupedDisplaySection(results.functionRegistry.changeSet.title, formatChangeSetEntries(otherFunctionRegistryChanges));
|
|
@@ -10056,10 +10381,7 @@ async function deploy(options) {
|
|
|
10056
10381
|
};
|
|
10057
10382
|
});
|
|
10058
10383
|
if (buildOnly) return { bundledScripts };
|
|
10059
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10060
|
-
useProfile: true,
|
|
10061
|
-
profile: options?.profile
|
|
10062
|
-
}));
|
|
10384
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
10063
10385
|
const workspaceId = await loadWorkspaceId({
|
|
10064
10386
|
workspaceId: options?.workspaceId,
|
|
10065
10387
|
profile: options?.profile
|
|
@@ -10204,6 +10526,19 @@ async function deploy(options) {
|
|
|
10204
10526
|
workflow,
|
|
10205
10527
|
secretManager
|
|
10206
10528
|
});
|
|
10529
|
+
if (options?.noValidate) logger.warn("Client-side validation skipped (--no-validate).");
|
|
10530
|
+
else await validatePlan({
|
|
10531
|
+
functionRegistry,
|
|
10532
|
+
tailorDB,
|
|
10533
|
+
staticWebsite,
|
|
10534
|
+
idp,
|
|
10535
|
+
auth,
|
|
10536
|
+
pipeline,
|
|
10537
|
+
app,
|
|
10538
|
+
executor,
|
|
10539
|
+
workflow,
|
|
10540
|
+
secretManager
|
|
10541
|
+
});
|
|
10207
10542
|
if (dryRun) {
|
|
10208
10543
|
logger.info("Dry run enabled. No changes applied.");
|
|
10209
10544
|
return;
|
|
@@ -10566,10 +10901,7 @@ async function resolveExecutor(client, workspaceId, name) {
|
|
|
10566
10901
|
}
|
|
10567
10902
|
async function getExecutor(options) {
|
|
10568
10903
|
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
|
-
}));
|
|
10904
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
10573
10905
|
const workspaceId = await loadWorkspaceId({
|
|
10574
10906
|
workspaceId: options.workspaceId,
|
|
10575
10907
|
profile: options.profile
|
|
@@ -10818,10 +11150,7 @@ function parseStatus(status) {
|
|
|
10818
11150
|
}
|
|
10819
11151
|
async function listWorkflowExecutions(options) {
|
|
10820
11152
|
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
|
-
}));
|
|
11153
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
10825
11154
|
const workspaceId = await loadWorkspaceId({
|
|
10826
11155
|
workspaceId: options?.workspaceId,
|
|
10827
11156
|
profile: options?.profile
|
|
@@ -10858,10 +11187,7 @@ async function listWorkflowExecutions(options) {
|
|
|
10858
11187
|
* @returns Workflow execution with optional logs
|
|
10859
11188
|
*/
|
|
10860
11189
|
async function getWorkflowExecution(options) {
|
|
10861
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
10862
|
-
useProfile: true,
|
|
10863
|
-
profile: options.profile
|
|
10864
|
-
}));
|
|
11190
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
10865
11191
|
const workspaceId = await loadWorkspaceId({
|
|
10866
11192
|
workspaceId: options.workspaceId,
|
|
10867
11193
|
profile: options.profile
|
|
@@ -11046,10 +11372,7 @@ async function resolveWorkflow(client, workspaceId, name) {
|
|
|
11046
11372
|
}
|
|
11047
11373
|
async function getWorkflow(options) {
|
|
11048
11374
|
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
|
-
}));
|
|
11375
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11053
11376
|
const workspaceId = await loadWorkspaceId({
|
|
11054
11377
|
workspaceId: options.workspaceId,
|
|
11055
11378
|
profile: options.profile
|
|
@@ -11193,10 +11516,7 @@ async function startWorkflowCore(options) {
|
|
|
11193
11516
|
}
|
|
11194
11517
|
}
|
|
11195
11518
|
async function startWorkflowByName(options) {
|
|
11196
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11197
|
-
useProfile: true,
|
|
11198
|
-
profile: options.profile
|
|
11199
|
-
}));
|
|
11519
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11200
11520
|
const workspaceId = await loadWorkspaceId({
|
|
11201
11521
|
workspaceId: options.workspaceId,
|
|
11202
11522
|
profile: options.profile
|
|
@@ -11222,10 +11542,7 @@ async function startWorkflowByName(options) {
|
|
|
11222
11542
|
async function startWorkflow(options) {
|
|
11223
11543
|
if ("name" in options) return await startWorkflowByName(options);
|
|
11224
11544
|
return await startWorkflowCore({
|
|
11225
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
11226
|
-
useProfile: true,
|
|
11227
|
-
profile: options.profile
|
|
11228
|
-
})),
|
|
11545
|
+
client: await initOperatorClient(await loadAccessToken({ profile: options.profile })),
|
|
11229
11546
|
workspaceId: await loadWorkspaceId({
|
|
11230
11547
|
workspaceId: options.workspaceId,
|
|
11231
11548
|
profile: options.profile
|
|
@@ -11288,10 +11605,7 @@ function formatTime(date) {
|
|
|
11288
11605
|
}
|
|
11289
11606
|
async function listExecutorJobs(options) {
|
|
11290
11607
|
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
|
-
}));
|
|
11608
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11295
11609
|
const workspaceId = await loadWorkspaceId({
|
|
11296
11610
|
workspaceId: options.workspaceId,
|
|
11297
11611
|
profile: options.profile
|
|
@@ -11329,10 +11643,7 @@ async function listExecutorJobs(options) {
|
|
|
11329
11643
|
}
|
|
11330
11644
|
async function getExecutorJob(options) {
|
|
11331
11645
|
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
|
-
}));
|
|
11646
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11336
11647
|
const workspaceId = await loadWorkspaceId({
|
|
11337
11648
|
workspaceId: options.workspaceId,
|
|
11338
11649
|
profile: options.profile
|
|
@@ -11369,10 +11680,7 @@ async function getExecutorJob(options) {
|
|
|
11369
11680
|
}
|
|
11370
11681
|
async function watchExecutorJob(options) {
|
|
11371
11682
|
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
|
-
}));
|
|
11683
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11376
11684
|
const workspaceId = await loadWorkspaceId({
|
|
11377
11685
|
workspaceId: options.workspaceId,
|
|
11378
11686
|
profile: options.profile
|
|
@@ -11672,10 +11980,7 @@ const jobsCommand = defineAppCommand({
|
|
|
11672
11980
|
* @returns List of executors
|
|
11673
11981
|
*/
|
|
11674
11982
|
async function listExecutors(options) {
|
|
11675
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11676
|
-
useProfile: true,
|
|
11677
|
-
profile: options?.profile
|
|
11678
|
-
}));
|
|
11983
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
11679
11984
|
const workspaceId = await loadWorkspaceId({
|
|
11680
11985
|
workspaceId: options?.workspaceId,
|
|
11681
11986
|
profile: options?.profile
|
|
@@ -11748,10 +12053,7 @@ const headerArg = z.string().superRefine((val, ctx) => {
|
|
|
11748
12053
|
};
|
|
11749
12054
|
}).refine((h) => h.key.length > 0, { message: "Header name cannot be empty" });
|
|
11750
12055
|
async function triggerExecutorByName(options) {
|
|
11751
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11752
|
-
useProfile: true,
|
|
11753
|
-
profile: options.profile
|
|
11754
|
-
}));
|
|
12056
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
11755
12057
|
const workspaceId = await loadWorkspaceId({
|
|
11756
12058
|
workspaceId: options.workspaceId,
|
|
11757
12059
|
profile: options.profile
|
|
@@ -11847,10 +12149,7 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
11847
12149
|
}).strict(),
|
|
11848
12150
|
run: async (args) => {
|
|
11849
12151
|
await assertWritable({ profile: args.profile });
|
|
11850
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11851
|
-
useProfile: true,
|
|
11852
|
-
profile: args.profile
|
|
11853
|
-
}));
|
|
12152
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: args.profile }));
|
|
11854
12153
|
const workspaceId = await loadWorkspaceId({
|
|
11855
12154
|
workspaceId: args["workspace-id"],
|
|
11856
12155
|
profile: args.profile
|
|
@@ -11938,10 +12237,7 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
11938
12237
|
* @returns List of webhook executors with URLs
|
|
11939
12238
|
*/
|
|
11940
12239
|
async function listWebhookExecutors(options) {
|
|
11941
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11942
|
-
useProfile: true,
|
|
11943
|
-
profile: options?.profile
|
|
11944
|
-
}));
|
|
12240
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
11945
12241
|
const workspaceId = await loadWorkspaceId({
|
|
11946
12242
|
workspaceId: options?.workspaceId,
|
|
11947
12243
|
profile: options?.profile
|
|
@@ -12016,12 +12312,9 @@ const getFunctionRegistryOptionsSchema = z.object({
|
|
|
12016
12312
|
});
|
|
12017
12313
|
async function loadOptions$12(options) {
|
|
12018
12314
|
const result = getFunctionRegistryOptionsSchema.safeParse(options);
|
|
12019
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
12315
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
12020
12316
|
return {
|
|
12021
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
12022
|
-
useProfile: true,
|
|
12023
|
-
profile: result.data.profile
|
|
12024
|
-
})),
|
|
12317
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
12025
12318
|
workspaceId: await loadWorkspaceId({
|
|
12026
12319
|
workspaceId: result.data.workspaceId,
|
|
12027
12320
|
profile: result.data.profile
|
|
@@ -12084,12 +12377,9 @@ const listFunctionRegistriesOptionsSchema = z.object({
|
|
|
12084
12377
|
});
|
|
12085
12378
|
async function loadOptions$11(options) {
|
|
12086
12379
|
const result = listFunctionRegistriesOptionsSchema.safeParse(options);
|
|
12087
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
12380
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
12088
12381
|
return {
|
|
12089
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
12090
|
-
useProfile: true,
|
|
12091
|
-
profile: result.data.profile
|
|
12092
|
-
})),
|
|
12382
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
12093
12383
|
workspaceId: await loadWorkspaceId({
|
|
12094
12384
|
workspaceId: result.data.workspaceId,
|
|
12095
12385
|
profile: result.data.profile
|
|
@@ -12584,13 +12874,13 @@ function createGenerationManager(params) {
|
|
|
12584
12874
|
};
|
|
12585
12875
|
}
|
|
12586
12876
|
async function processTailorDBNamespace(gen, namespace, typeInfo) {
|
|
12587
|
-
const results = generatorResults[gen.id];
|
|
12877
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12588
12878
|
results.tailordbResults[namespace] = {};
|
|
12589
12879
|
if (!gen.processType) return;
|
|
12590
12880
|
const processType = gen.processType;
|
|
12591
12881
|
await Promise.allSettled(Object.entries(typeInfo.types).map(async ([typeName, type]) => {
|
|
12592
12882
|
try {
|
|
12593
|
-
results.tailordbResults[namespace][typeName] = await processType({
|
|
12883
|
+
assertDefined(results.tailordbResults[namespace], `tailordb results not initialized for namespace ${namespace}`)[typeName] = await processType({
|
|
12594
12884
|
type,
|
|
12595
12885
|
namespace,
|
|
12596
12886
|
source: typeInfo.sourceInfo[typeName],
|
|
@@ -12613,13 +12903,13 @@ function createGenerationManager(params) {
|
|
|
12613
12903
|
else results.tailordbNamespaceResults[namespace] = results.tailordbResults[namespace];
|
|
12614
12904
|
}
|
|
12615
12905
|
async function processResolverNamespace(gen, namespace, resolvers) {
|
|
12616
|
-
const results = generatorResults[gen.id];
|
|
12906
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12617
12907
|
results.resolverResults[namespace] = {};
|
|
12618
12908
|
if (!gen.processResolver) return;
|
|
12619
12909
|
const processResolver = gen.processResolver;
|
|
12620
12910
|
await Promise.allSettled(Object.entries(resolvers).map(async ([resolverName, resolver]) => {
|
|
12621
12911
|
try {
|
|
12622
|
-
results.resolverResults[namespace][resolverName] = await processResolver({
|
|
12912
|
+
assertDefined(results.resolverResults[namespace], `resolver results not initialized for namespace ${namespace}`)[resolverName] = await processResolver({
|
|
12623
12913
|
resolver,
|
|
12624
12914
|
namespace
|
|
12625
12915
|
});
|
|
@@ -12640,7 +12930,7 @@ function createGenerationManager(params) {
|
|
|
12640
12930
|
else results.resolverNamespaceResults[namespace] = results.resolverResults[namespace];
|
|
12641
12931
|
}
|
|
12642
12932
|
async function processExecutors(gen) {
|
|
12643
|
-
const results = generatorResults[gen.id];
|
|
12933
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12644
12934
|
if (!gen.processExecutor) return;
|
|
12645
12935
|
const processExecutor = gen.processExecutor;
|
|
12646
12936
|
await Promise.allSettled(Object.entries(services.executor).map(async ([executorId, executor]) => {
|
|
@@ -12653,7 +12943,7 @@ function createGenerationManager(params) {
|
|
|
12653
12943
|
}));
|
|
12654
12944
|
}
|
|
12655
12945
|
async function aggregate(gen) {
|
|
12656
|
-
const results = generatorResults[gen.id];
|
|
12946
|
+
const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
|
|
12657
12947
|
const tailordbResults = [];
|
|
12658
12948
|
const resolverResults = [];
|
|
12659
12949
|
for (const [namespace, types] of Object.entries(results.tailordbNamespaceResults)) tailordbResults.push({
|
|
@@ -12711,7 +13001,7 @@ function createGenerationManager(params) {
|
|
|
12711
13001
|
let result;
|
|
12712
13002
|
switch (hookName) {
|
|
12713
13003
|
case "onTailorDBReady":
|
|
12714
|
-
result = await plugin.onTailorDBReady({
|
|
13004
|
+
result = await assertDefined(plugin.onTailorDBReady, "plugin.onTailorDBReady hook missing")({
|
|
12715
13005
|
tailordb,
|
|
12716
13006
|
auth,
|
|
12717
13007
|
baseDir: pluginBaseDir,
|
|
@@ -12720,7 +13010,7 @@ function createGenerationManager(params) {
|
|
|
12720
13010
|
});
|
|
12721
13011
|
break;
|
|
12722
13012
|
case "onResolverReady":
|
|
12723
|
-
result = await plugin.onResolverReady({
|
|
13013
|
+
result = await assertDefined(plugin.onResolverReady, "plugin.onResolverReady hook missing")({
|
|
12724
13014
|
tailordb,
|
|
12725
13015
|
resolvers: buildResolverData(),
|
|
12726
13016
|
auth,
|
|
@@ -12730,7 +13020,7 @@ function createGenerationManager(params) {
|
|
|
12730
13020
|
});
|
|
12731
13021
|
break;
|
|
12732
13022
|
case "onExecutorReady":
|
|
12733
|
-
result = await plugin.onExecutorReady({
|
|
13023
|
+
result = await assertDefined(plugin.onExecutorReady, "plugin.onExecutorReady hook missing")({
|
|
12734
13024
|
tailordb,
|
|
12735
13025
|
resolvers: buildResolverData(),
|
|
12736
13026
|
executors: { ...services.executor },
|
|
@@ -12844,7 +13134,7 @@ function createGenerationManager(params) {
|
|
|
12844
13134
|
...process.env,
|
|
12845
13135
|
TAILOR_WATCH_GENERATION: (parseInt(process.env.TAILOR_WATCH_GENERATION || "0", 10) + 1).toString()
|
|
12846
13136
|
};
|
|
12847
|
-
const child = spawn(process.argv[0], [process.argv[1], ...args], {
|
|
13137
|
+
const child = spawn(assertDefined(process.argv[0], "argv[0] missing"), [assertDefined(process.argv[1], "argv[1] missing"), ...args], {
|
|
12848
13138
|
stdio: "inherit",
|
|
12849
13139
|
env,
|
|
12850
13140
|
detached: false
|
|
@@ -12908,7 +13198,10 @@ function createGenerationManager(params) {
|
|
|
12908
13198
|
executorService: app.executorService ?? (pluginExecutorFiles.length > 0 ? createExecutorService({ config: { files: [] } }) : void 0)
|
|
12909
13199
|
};
|
|
12910
13200
|
});
|
|
12911
|
-
if (app.authService)
|
|
13201
|
+
if (app.authService) {
|
|
13202
|
+
const authService = app.authService;
|
|
13203
|
+
await withSpan("generate.resolveAuthNamespaces", async () => authService.resolveNamespaces());
|
|
13204
|
+
}
|
|
12912
13205
|
if (app.tailorDBServices.length > 0 || pluginExecutorFiles.length > 0) logger.newline();
|
|
12913
13206
|
const readyAfterTailorDB = getReadyGenerators("tailordb");
|
|
12914
13207
|
const hasOnTailorDBReady = generationPlugins.some((p) => p.onTailorDBReady != null);
|
|
@@ -12924,9 +13217,10 @@ function createGenerationManager(params) {
|
|
|
12924
13217
|
await withSpan(`generate.loadResolvers.${namespace}`, async () => {
|
|
12925
13218
|
try {
|
|
12926
13219
|
await resolverService.loadResolvers();
|
|
12927
|
-
|
|
13220
|
+
const namespaceResolvers = {};
|
|
13221
|
+
services.resolver[namespace] = namespaceResolvers;
|
|
12928
13222
|
Object.entries(resolverService.resolvers).forEach(([_, resolver]) => {
|
|
12929
|
-
|
|
13223
|
+
namespaceResolvers[resolver.name] = resolver;
|
|
12930
13224
|
});
|
|
12931
13225
|
} catch (error) {
|
|
12932
13226
|
logger.error(`Error loading resolvers for Resolver service ${styles.bold(namespace)}`);
|
|
@@ -12972,11 +13266,11 @@ function createGenerationManager(params) {
|
|
|
12972
13266
|
const app = application;
|
|
12973
13267
|
for (const db of app.tailorDBServices) {
|
|
12974
13268
|
const dbNamespace = db.namespace;
|
|
12975
|
-
await watcher
|
|
13269
|
+
await watcher.addWatchGroup(`TailorDB/${dbNamespace}`, db.config.files);
|
|
12976
13270
|
}
|
|
12977
13271
|
for (const resolverService of app.resolverServices) {
|
|
12978
13272
|
const resolverNamespace = resolverService.namespace;
|
|
12979
|
-
await watcher
|
|
13273
|
+
await watcher.addWatchGroup(`Resolver/${resolverNamespace}`, resolverService["config"].files);
|
|
12980
13274
|
}
|
|
12981
13275
|
await new Promise(() => {});
|
|
12982
13276
|
}
|
|
@@ -13040,10 +13334,7 @@ function machineUserInfo(user) {
|
|
|
13040
13334
|
* @returns List of machine users
|
|
13041
13335
|
*/
|
|
13042
13336
|
async function listMachineUsers(options) {
|
|
13043
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13044
|
-
useProfile: true,
|
|
13045
|
-
profile: options?.profile
|
|
13046
|
-
}));
|
|
13337
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13047
13338
|
const workspaceId = await loadWorkspaceId({
|
|
13048
13339
|
workspaceId: options?.workspaceId,
|
|
13049
13340
|
profile: options?.profile
|
|
@@ -13096,10 +13387,7 @@ const listCommand$7 = defineAppCommand({
|
|
|
13096
13387
|
* @returns Machine user token info
|
|
13097
13388
|
*/
|
|
13098
13389
|
async function getMachineUserToken(options) {
|
|
13099
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13100
|
-
useProfile: true,
|
|
13101
|
-
profile: options.profile
|
|
13102
|
-
}));
|
|
13390
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
13103
13391
|
const workspaceId = await loadWorkspaceId({
|
|
13104
13392
|
workspaceId: options.workspaceId,
|
|
13105
13393
|
profile: options.profile
|
|
@@ -13200,10 +13488,7 @@ function toOAuth2ClientCredentials(client) {
|
|
|
13200
13488
|
* @returns OAuth2 client credentials
|
|
13201
13489
|
*/
|
|
13202
13490
|
async function getOAuth2Client(options) {
|
|
13203
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13204
|
-
useProfile: true,
|
|
13205
|
-
profile: options.profile
|
|
13206
|
-
}));
|
|
13491
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
13207
13492
|
const workspaceId = await loadWorkspaceId({
|
|
13208
13493
|
workspaceId: options.workspaceId,
|
|
13209
13494
|
profile: options.profile
|
|
@@ -13220,7 +13505,7 @@ async function getOAuth2Client(options) {
|
|
|
13220
13505
|
namespaceName: application.authNamespace,
|
|
13221
13506
|
name: options.name
|
|
13222
13507
|
});
|
|
13223
|
-
return toOAuth2ClientCredentials(oauth2Client);
|
|
13508
|
+
return toOAuth2ClientCredentials(assertDefined(oauth2Client, "oauth2Client missing in response"));
|
|
13224
13509
|
} catch (error) {
|
|
13225
13510
|
if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`OAuth2 client '${options.name}' not found.`, { cause: error });
|
|
13226
13511
|
throw error;
|
|
@@ -13255,10 +13540,7 @@ const getCommand$3 = defineAppCommand({
|
|
|
13255
13540
|
* @returns List of OAuth2 clients
|
|
13256
13541
|
*/
|
|
13257
13542
|
async function listOAuth2Clients(options) {
|
|
13258
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13259
|
-
useProfile: true,
|
|
13260
|
-
profile: options?.profile
|
|
13261
|
-
}));
|
|
13543
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13262
13544
|
const workspaceId = await loadWorkspaceId({
|
|
13263
13545
|
workspaceId: options?.workspaceId,
|
|
13264
13546
|
profile: options?.profile
|
|
@@ -13342,7 +13624,7 @@ const createFolderOptionsSchema = z.object({
|
|
|
13342
13624
|
*/
|
|
13343
13625
|
async function createFolder(options) {
|
|
13344
13626
|
const result = createFolderOptionsSchema.safeParse(options);
|
|
13345
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13627
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13346
13628
|
const response = await (await initOperatorClient(await loadAccessToken())).createOrganizationFolder({
|
|
13347
13629
|
organizationId: result.data.organizationId,
|
|
13348
13630
|
parentFolderId: result.data.parentFolderId ?? "",
|
|
@@ -13387,7 +13669,7 @@ const deleteFolderOptionsSchema = z.object({
|
|
|
13387
13669
|
*/
|
|
13388
13670
|
async function deleteFolder(options) {
|
|
13389
13671
|
const result = deleteFolderOptionsSchema.safeParse(options);
|
|
13390
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13672
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13391
13673
|
await (await initOperatorClient(await loadAccessToken())).deleteOrganizationFolder({
|
|
13392
13674
|
organizationId: result.data.organizationId,
|
|
13393
13675
|
folderId: result.data.folderId
|
|
@@ -13440,7 +13722,7 @@ const getFolderOptionsSchema = z.object({
|
|
|
13440
13722
|
*/
|
|
13441
13723
|
async function getFolder(options) {
|
|
13442
13724
|
const result = getFolderOptionsSchema.safeParse(options);
|
|
13443
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13725
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13444
13726
|
const response = await (await initOperatorClient(await loadAccessToken())).getOrganizationFolder({
|
|
13445
13727
|
organizationId: result.data.organizationId,
|
|
13446
13728
|
folderId: result.data.folderId
|
|
@@ -13484,7 +13766,7 @@ const listFoldersOptionsSchema = z.object({
|
|
|
13484
13766
|
*/
|
|
13485
13767
|
async function listFolders(options) {
|
|
13486
13768
|
const result = listFoldersOptionsSchema.safeParse(options);
|
|
13487
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13769
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13488
13770
|
const { organizationId, parentFolderId, order, limit } = result.data;
|
|
13489
13771
|
const client = await initOperatorClient(await loadAccessToken());
|
|
13490
13772
|
const pageDirection = toPageDirection(order);
|
|
@@ -13532,7 +13814,7 @@ const updateFolderOptionsSchema = z.object({
|
|
|
13532
13814
|
*/
|
|
13533
13815
|
async function updateFolder(options) {
|
|
13534
13816
|
const result = updateFolderOptionsSchema.safeParse(options);
|
|
13535
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13817
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13536
13818
|
const response = await (await initOperatorClient(await loadAccessToken())).updateOrganizationFolder({
|
|
13537
13819
|
organizationId: result.data.organizationId,
|
|
13538
13820
|
folderId: result.data.folderId,
|
|
@@ -13574,7 +13856,7 @@ const getOrganizationOptionsSchema = z.object({ organizationId: z.uuid({ message
|
|
|
13574
13856
|
*/
|
|
13575
13857
|
async function getOrganization(options) {
|
|
13576
13858
|
const result = getOrganizationOptionsSchema.safeParse(options);
|
|
13577
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
13859
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13578
13860
|
const response = await (await initOperatorClient(await loadAccessToken())).getOrganization({ organizationId: result.data.organizationId });
|
|
13579
13861
|
if (!response.organization) throw new Error(`Organization "${result.data.organizationId}" not found.`);
|
|
13580
13862
|
return organizationInfo(response.organization);
|
|
@@ -13668,12 +13950,12 @@ async function buildFolderTreeJson(client, organizationId, parentFolderId, curre
|
|
|
13668
13950
|
}
|
|
13669
13951
|
function renderTree(nodes, prefix) {
|
|
13670
13952
|
let output = "";
|
|
13671
|
-
for (
|
|
13953
|
+
for (const [i, node] of nodes.entries()) {
|
|
13672
13954
|
const isLast = i === nodes.length - 1;
|
|
13673
13955
|
const connector = isLast ? "└── " : "├── ";
|
|
13674
13956
|
const childPrefix = isLast ? " " : "│ ";
|
|
13675
|
-
output += `${prefix}${connector}${
|
|
13676
|
-
if (
|
|
13957
|
+
output += `${prefix}${connector}${node.name}\n`;
|
|
13958
|
+
if (node.children.length > 0) output += renderTree(node.children, prefix + childPrefix);
|
|
13677
13959
|
}
|
|
13678
13960
|
return output;
|
|
13679
13961
|
}
|
|
@@ -13760,7 +14042,7 @@ const updateOrganizationOptionsSchema = z.object({
|
|
|
13760
14042
|
*/
|
|
13761
14043
|
async function updateOrganization(options) {
|
|
13762
14044
|
const result = updateOrganizationOptionsSchema.safeParse(options);
|
|
13763
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
14045
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
13764
14046
|
const response = await (await initOperatorClient(await loadAccessToken())).updateOrganization({
|
|
13765
14047
|
organizationId: result.data.organizationId,
|
|
13766
14048
|
organizationName: result.data.name
|
|
@@ -13792,10 +14074,7 @@ const updateCommand$1 = defineAppCommand({
|
|
|
13792
14074
|
//#endregion
|
|
13793
14075
|
//#region src/cli/commands/remove.ts
|
|
13794
14076
|
async function loadOptions$10(options) {
|
|
13795
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13796
|
-
useProfile: true,
|
|
13797
|
-
profile: options?.profile
|
|
13798
|
-
}));
|
|
14077
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13799
14078
|
const workspaceId = await loadWorkspaceId({
|
|
13800
14079
|
workspaceId: options?.workspaceId,
|
|
13801
14080
|
profile: options?.profile
|
|
@@ -13847,7 +14126,7 @@ async function execRemove(client, workspaceId, application, config, confirm) {
|
|
|
13847
14126
|
auth.changeSet.authHook.print();
|
|
13848
14127
|
auth.changeSet.scim.print();
|
|
13849
14128
|
auth.changeSet.scimResource.print();
|
|
13850
|
-
auth.changeSet.connection
|
|
14129
|
+
auth.changeSet.connection.print();
|
|
13851
14130
|
secretManager.vaultChangeSet.print();
|
|
13852
14131
|
secretManager.secretChangeSet.print();
|
|
13853
14132
|
if (tailorDB.changeSet.service.deletes.length === 0 && staticWebsite.changeSet.deletes.length === 0 && idp.changeSet.service.deletes.length === 0 && auth.changeSet.service.deletes.length === 0 && pipeline.changeSet.service.deletes.length === 0 && app.deletes.length === 0 && executor.changeSet.deletes.length === 0 && workflow.changeSet.deletes.length === 0 && functionRegistry.changeSet.deletes.length === 0 && secretManager.vaultChangeSet.deletes.length === 0 && secretManager.secretChangeSet.deletes.length === 0) return;
|
|
@@ -13918,6 +14197,82 @@ function logBetaWarning(featureName) {
|
|
|
13918
14197
|
logger.newline();
|
|
13919
14198
|
}
|
|
13920
14199
|
|
|
14200
|
+
//#endregion
|
|
14201
|
+
//#region src/cli/commands/workspace/transform.ts
|
|
14202
|
+
const workspaceInfo = (workspace, folderName) => {
|
|
14203
|
+
const info = {
|
|
14204
|
+
id: workspace.id,
|
|
14205
|
+
name: workspace.name,
|
|
14206
|
+
region: workspace.region,
|
|
14207
|
+
createdAt: formatTimestamp(workspace.createTime),
|
|
14208
|
+
updatedAt: formatTimestamp(workspace.updateTime)
|
|
14209
|
+
};
|
|
14210
|
+
return folderName ? {
|
|
14211
|
+
...info,
|
|
14212
|
+
folderName
|
|
14213
|
+
} : info;
|
|
14214
|
+
};
|
|
14215
|
+
const workspaceDetails = (workspace, folderName) => {
|
|
14216
|
+
return {
|
|
14217
|
+
...workspaceInfo(workspace, folderName),
|
|
14218
|
+
deleteProtection: workspace.deleteProtection,
|
|
14219
|
+
organizationId: workspace.organizationId,
|
|
14220
|
+
folderId: workspace.folderId
|
|
14221
|
+
};
|
|
14222
|
+
};
|
|
14223
|
+
async function resolveWorkspaceFolderName(client, workspace) {
|
|
14224
|
+
if (!workspace.organizationId || !workspace.folderId) return void 0;
|
|
14225
|
+
try {
|
|
14226
|
+
return (await client.getOrganizationFolder({
|
|
14227
|
+
organizationId: workspace.organizationId,
|
|
14228
|
+
folderId: workspace.folderId
|
|
14229
|
+
})).folder?.name || void 0;
|
|
14230
|
+
} catch (error) {
|
|
14231
|
+
if (error instanceof ConnectError && (error.code === Code.NotFound || error.code === Code.PermissionDenied)) return;
|
|
14232
|
+
logger.warn(`Failed to resolve workspace folder name: ${error}`);
|
|
14233
|
+
return;
|
|
14234
|
+
}
|
|
14235
|
+
}
|
|
14236
|
+
function createWorkspaceFolderNameResolver(client) {
|
|
14237
|
+
const cache = /* @__PURE__ */ new Map();
|
|
14238
|
+
return (workspace) => {
|
|
14239
|
+
if (!workspace.organizationId || !workspace.folderId) return Promise.resolve(void 0);
|
|
14240
|
+
const cacheKey = `${workspace.organizationId}/${workspace.folderId}`;
|
|
14241
|
+
const cached = cache.get(cacheKey);
|
|
14242
|
+
if (cached) return cached;
|
|
14243
|
+
const promise = resolveWorkspaceFolderName(client, workspace);
|
|
14244
|
+
cache.set(cacheKey, promise);
|
|
14245
|
+
return promise;
|
|
14246
|
+
};
|
|
14247
|
+
}
|
|
14248
|
+
async function workspaceInfoWithFolderName(client, workspace) {
|
|
14249
|
+
return workspaceInfo(workspace, await resolveWorkspaceFolderName(client, workspace));
|
|
14250
|
+
}
|
|
14251
|
+
async function workspaceDetailsWithFolderName(client, workspace) {
|
|
14252
|
+
return workspaceDetails(workspace, await resolveWorkspaceFolderName(client, workspace));
|
|
14253
|
+
}
|
|
14254
|
+
async function workspaceInfosWithFolderNames(client, workspaces) {
|
|
14255
|
+
const resolveFolderName = createWorkspaceFolderNameResolver(client);
|
|
14256
|
+
const limit = pLimit(5);
|
|
14257
|
+
return Promise.all(workspaces.map((workspace) => limit(async () => workspaceInfo(workspace, await resolveFolderName(workspace)))));
|
|
14258
|
+
}
|
|
14259
|
+
function workspaceDisplayName(workspace) {
|
|
14260
|
+
return workspace.folderName ? `${workspace.folderName}/${workspace.name}` : workspace.name;
|
|
14261
|
+
}
|
|
14262
|
+
function createWorkspaceNameTransformer(nameKey, folderNameKey) {
|
|
14263
|
+
return (value, item) => {
|
|
14264
|
+
const workspace = item;
|
|
14265
|
+
const name = workspace[nameKey];
|
|
14266
|
+
const folderName = workspace[folderNameKey];
|
|
14267
|
+
if (typeof name === "string" && typeof folderName === "string") return workspaceDisplayName({
|
|
14268
|
+
name,
|
|
14269
|
+
folderName
|
|
14270
|
+
});
|
|
14271
|
+
return String(value ?? "");
|
|
14272
|
+
};
|
|
14273
|
+
}
|
|
14274
|
+
const workspaceNameTransformer = createWorkspaceNameTransformer("name", "folderName");
|
|
14275
|
+
|
|
13921
14276
|
//#endregion
|
|
13922
14277
|
//#region src/cli/commands/show.ts
|
|
13923
14278
|
function applicationInfo(app) {
|
|
@@ -13939,10 +14294,7 @@ function applicationInfo(app) {
|
|
|
13939
14294
|
* @returns Application information
|
|
13940
14295
|
*/
|
|
13941
14296
|
async function show(options) {
|
|
13942
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
13943
|
-
useProfile: true,
|
|
13944
|
-
profile: options?.profile
|
|
13945
|
-
}));
|
|
14297
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
13946
14298
|
const workspaceId = await loadWorkspaceId({
|
|
13947
14299
|
workspaceId: options?.workspaceId,
|
|
13948
14300
|
profile: options?.profile
|
|
@@ -13952,15 +14304,19 @@ async function show(options) {
|
|
|
13952
14304
|
workspaceId,
|
|
13953
14305
|
applicationName: config.name
|
|
13954
14306
|
})]);
|
|
13955
|
-
const { name, ...appInfo } = applicationInfo(resp.application);
|
|
14307
|
+
const { name, ...appInfo } = applicationInfo(assertDefined(resp.application, `application "${config.name}" not found in workspace`));
|
|
14308
|
+
const workspace = workspaceResp.workspace;
|
|
14309
|
+
const workspaceFolderName = workspace ? await resolveWorkspaceFolderName(client, workspace) : "";
|
|
13956
14310
|
return {
|
|
13957
14311
|
name,
|
|
13958
14312
|
workspaceId,
|
|
13959
|
-
workspaceName:
|
|
13960
|
-
|
|
14313
|
+
workspaceName: workspace?.name ?? "",
|
|
14314
|
+
...workspaceFolderName ? { workspaceFolderName } : {},
|
|
14315
|
+
workspaceRegion: workspace?.region ?? "",
|
|
13961
14316
|
...appInfo
|
|
13962
14317
|
};
|
|
13963
14318
|
}
|
|
14319
|
+
const showWorkspaceNameTransformer = createWorkspaceNameTransformer("workspaceName", "workspaceFolderName");
|
|
13964
14320
|
const showCommand = defineAppCommand({
|
|
13965
14321
|
name: "show",
|
|
13966
14322
|
description: "Show information about the deployed application.",
|
|
@@ -13971,7 +14327,10 @@ const showCommand = defineAppCommand({
|
|
|
13971
14327
|
profile: args.profile,
|
|
13972
14328
|
configPath: args.config
|
|
13973
14329
|
});
|
|
13974
|
-
logger.out(appInfo
|
|
14330
|
+
logger.out(appInfo, { display: {
|
|
14331
|
+
workspaceName: showWorkspaceNameTransformer,
|
|
14332
|
+
workspaceFolderName: null
|
|
14333
|
+
} });
|
|
13975
14334
|
}
|
|
13976
14335
|
});
|
|
13977
14336
|
|
|
@@ -14060,7 +14419,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
14060
14419
|
const { before, after } = change;
|
|
14061
14420
|
if (before && after && !before.required && after.required) {
|
|
14062
14421
|
if (!optionalToRequired.has(change.typeName)) optionalToRequired.set(change.typeName, /* @__PURE__ */ new Set());
|
|
14063
|
-
optionalToRequired.get(change.typeName).add(change.fieldName);
|
|
14422
|
+
assertDefined(optionalToRequired.get(change.typeName), "optionalToRequired entry missing").add(change.fieldName);
|
|
14064
14423
|
}
|
|
14065
14424
|
if (before && after && before.type === "enum" && after.type === "enum" && before.allowedValues && after.allowedValues) {
|
|
14066
14425
|
const beforeValues = before.allowedValues.map((v) => v.value);
|
|
@@ -14069,7 +14428,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
14069
14428
|
const afterSet = new Set(afterValues);
|
|
14070
14429
|
if (beforeValues.some((v) => !afterSet.has(v)) || afterValues.some((v) => !beforeSet.has(v))) {
|
|
14071
14430
|
if (!enumValueChanges.has(change.typeName)) enumValueChanges.set(change.typeName, /* @__PURE__ */ new Map());
|
|
14072
|
-
enumValueChanges.get(change.typeName).set(change.fieldName, {
|
|
14431
|
+
assertDefined(enumValueChanges.get(change.typeName), "enumValueChanges entry missing").set(change.fieldName, {
|
|
14073
14432
|
beforeValues,
|
|
14074
14433
|
afterValues
|
|
14075
14434
|
});
|
|
@@ -14079,7 +14438,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
14079
14438
|
const { after } = change;
|
|
14080
14439
|
if (after && after.required) {
|
|
14081
14440
|
if (!addedRequiredFields.has(change.typeName)) addedRequiredFields.set(change.typeName, /* @__PURE__ */ new Map());
|
|
14082
|
-
addedRequiredFields.get(change.typeName).set(change.fieldName, after);
|
|
14441
|
+
assertDefined(addedRequiredFields.get(change.typeName), "addedRequiredFields entry missing").set(change.fieldName, after);
|
|
14083
14442
|
}
|
|
14084
14443
|
}
|
|
14085
14444
|
return {
|
|
@@ -14561,7 +14920,7 @@ async function generate(options) {
|
|
|
14561
14920
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
14562
14921
|
let pluginManager;
|
|
14563
14922
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
14564
|
-
const { defineApplication } = await import("./application-
|
|
14923
|
+
const { defineApplication } = await import("./application-DSXntqnV.mjs");
|
|
14565
14924
|
const application = defineApplication({
|
|
14566
14925
|
config,
|
|
14567
14926
|
pluginManager
|
|
@@ -14732,7 +15091,7 @@ function extractAllNamespaces(config) {
|
|
|
14732
15091
|
function extractOwnedNamespaces(config) {
|
|
14733
15092
|
const namespaces = /* @__PURE__ */ new Set();
|
|
14734
15093
|
if (config.db) for (const [namespaceName, nsConfig] of Object.entries(config.db)) {
|
|
14735
|
-
if ("external" in nsConfig
|
|
15094
|
+
if ("external" in nsConfig) continue;
|
|
14736
15095
|
namespaces.add(namespaceName);
|
|
14737
15096
|
}
|
|
14738
15097
|
return Array.from(namespaces);
|
|
@@ -14809,18 +15168,15 @@ async function truncate(options) {
|
|
|
14809
15168
|
yes: true
|
|
14810
15169
|
});
|
|
14811
15170
|
}
|
|
14812
|
-
async function $truncate(options) {
|
|
14813
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14814
|
-
useProfile: true,
|
|
14815
|
-
profile: options?.profile
|
|
14816
|
-
}));
|
|
15171
|
+
async function $truncate(options = {}) {
|
|
15172
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
14817
15173
|
const workspaceId = await loadWorkspaceId({
|
|
14818
|
-
workspaceId: options
|
|
14819
|
-
profile: options
|
|
15174
|
+
workspaceId: options.workspaceId,
|
|
15175
|
+
profile: options.profile
|
|
14820
15176
|
});
|
|
14821
|
-
const hasTypes = options
|
|
14822
|
-
const hasNamespace = !!options
|
|
14823
|
-
const hasAll = !!options
|
|
15177
|
+
const hasTypes = options.types && options.types.length > 0;
|
|
15178
|
+
const hasNamespace = !!options.namespace;
|
|
15179
|
+
const hasAll = !!options.all;
|
|
14824
15180
|
const optionCount = [
|
|
14825
15181
|
hasAll,
|
|
14826
15182
|
hasNamespace,
|
|
@@ -14828,14 +15184,14 @@ async function $truncate(options) {
|
|
|
14828
15184
|
].filter(Boolean).length;
|
|
14829
15185
|
if (optionCount === 0) throw new Error("Please specify one of: --all, --namespace <name>, or type names");
|
|
14830
15186
|
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
|
|
15187
|
+
const { config } = await loadConfig(options.configPath);
|
|
14832
15188
|
const namespaces = extractOwnedNamespaces(config);
|
|
14833
15189
|
if (hasAll) {
|
|
14834
15190
|
if (namespaces.length === 0) {
|
|
14835
15191
|
logger.warn("No namespaces found in config file.");
|
|
14836
15192
|
return;
|
|
14837
15193
|
}
|
|
14838
|
-
if (!options
|
|
15194
|
+
if (!options.yes) {
|
|
14839
15195
|
const namespaceList = namespaces.join(", ");
|
|
14840
15196
|
if (!await prompt.confirm({
|
|
14841
15197
|
message: `This will truncate ALL tables in the following owned namespaces (external namespaces are excluded): ${namespaceList}. Continue?`,
|
|
@@ -14849,11 +15205,11 @@ async function $truncate(options) {
|
|
|
14849
15205
|
logger.success("Truncated all tables in all owned namespaces");
|
|
14850
15206
|
return;
|
|
14851
15207
|
}
|
|
14852
|
-
if (hasNamespace
|
|
14853
|
-
const namespace = options.namespace;
|
|
15208
|
+
if (hasNamespace) {
|
|
15209
|
+
const namespace = assertDefined(options.namespace, "namespace option missing");
|
|
14854
15210
|
if (!namespaces.includes(namespace)) {
|
|
14855
15211
|
const dbConfig = config.db?.[namespace];
|
|
14856
|
-
if (dbConfig && "external" in dbConfig
|
|
15212
|
+
if (dbConfig && "external" in dbConfig) throw new Error(`Namespace "${namespace}" is declared as external in this app's config and cannot be truncated from here. Run truncate from the app that owns it.`);
|
|
14857
15213
|
throw new Error(`Namespace "${namespace}" not found in config. Available owned namespaces (external namespaces are excluded): ${namespaces.join(", ")}`);
|
|
14858
15214
|
}
|
|
14859
15215
|
if (!options.yes) {
|
|
@@ -14868,8 +15224,8 @@ async function $truncate(options) {
|
|
|
14868
15224
|
await truncateNamespace(workspaceId, namespace, client);
|
|
14869
15225
|
return;
|
|
14870
15226
|
}
|
|
14871
|
-
if (hasTypes
|
|
14872
|
-
const typeNames = options.types;
|
|
15227
|
+
if (hasTypes) {
|
|
15228
|
+
const typeNames = assertDefined(options.types, "types option missing");
|
|
14873
15229
|
const typeNamespaceMap = await resolveTypeNamespaces({
|
|
14874
15230
|
workspaceId,
|
|
14875
15231
|
namespaces,
|
|
@@ -14941,10 +15297,7 @@ const truncateCommand = defineAppCommand({
|
|
|
14941
15297
|
* @returns List of workflows
|
|
14942
15298
|
*/
|
|
14943
15299
|
async function listWorkflows(options) {
|
|
14944
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14945
|
-
useProfile: true,
|
|
14946
|
-
profile: options?.profile
|
|
14947
|
-
}));
|
|
15300
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
|
|
14948
15301
|
const workspaceId = await loadWorkspaceId({
|
|
14949
15302
|
workspaceId: options?.workspaceId,
|
|
14950
15303
|
profile: options?.profile
|
|
@@ -14991,10 +15344,7 @@ const listCommand$3 = defineAppCommand({
|
|
|
14991
15344
|
* @returns Resume result with wait helper
|
|
14992
15345
|
*/
|
|
14993
15346
|
async function resumeWorkflow(options) {
|
|
14994
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
14995
|
-
useProfile: true,
|
|
14996
|
-
profile: options.profile
|
|
14997
|
-
}));
|
|
15347
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
|
|
14998
15348
|
const workspaceId = await loadWorkspaceId({
|
|
14999
15349
|
workspaceId: options.workspaceId,
|
|
15000
15350
|
profile: options.profile
|
|
@@ -15102,12 +15452,9 @@ const healthOptionsSchema = z.object({
|
|
|
15102
15452
|
});
|
|
15103
15453
|
async function loadOptions$9(options) {
|
|
15104
15454
|
const result = healthOptionsSchema.safeParse(options);
|
|
15105
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15455
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15106
15456
|
return {
|
|
15107
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15108
|
-
useProfile: true,
|
|
15109
|
-
profile: result.data.profile
|
|
15110
|
-
})),
|
|
15457
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15111
15458
|
workspaceId: await loadWorkspaceId({
|
|
15112
15459
|
workspaceId: result.data.workspaceId,
|
|
15113
15460
|
profile: result.data.profile
|
|
@@ -15162,12 +15509,9 @@ const listAppsOptionsSchema = z.object({
|
|
|
15162
15509
|
});
|
|
15163
15510
|
async function loadOptions$8(options) {
|
|
15164
15511
|
const result = listAppsOptionsSchema.safeParse(options);
|
|
15165
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15512
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15166
15513
|
return {
|
|
15167
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15168
|
-
useProfile: true,
|
|
15169
|
-
profile: result.data.profile
|
|
15170
|
-
})),
|
|
15514
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15171
15515
|
workspaceId: await loadWorkspaceId({
|
|
15172
15516
|
workspaceId: result.data.workspaceId,
|
|
15173
15517
|
profile: result.data.profile
|
|
@@ -15217,26 +15561,6 @@ const listCommand$2 = defineAppCommand({
|
|
|
15217
15561
|
}
|
|
15218
15562
|
});
|
|
15219
15563
|
|
|
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
15564
|
//#endregion
|
|
15241
15565
|
//#region src/cli/commands/workspace/create.ts
|
|
15242
15566
|
/**
|
|
@@ -15262,17 +15586,17 @@ const validateRegion = async (region, client) => {
|
|
|
15262
15586
|
*/
|
|
15263
15587
|
async function createWorkspace(options) {
|
|
15264
15588
|
const result = createWorkspaceOptionsSchema.safeParse(options);
|
|
15265
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15589
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15266
15590
|
const validated = result.data;
|
|
15267
15591
|
const client = await initOperatorClient(await loadAccessToken());
|
|
15268
15592
|
await validateRegion(validated.region, client);
|
|
15269
|
-
return
|
|
15593
|
+
return workspaceInfoWithFolderName(client, assertDefined((await client.createWorkspace({
|
|
15270
15594
|
workspaceName: validated.name,
|
|
15271
15595
|
workspaceRegion: validated.region,
|
|
15272
15596
|
deleteProtection: validated.deleteProtection ?? false,
|
|
15273
15597
|
organizationId: validated.organizationId,
|
|
15274
15598
|
folderId: validated.folderId
|
|
15275
|
-
})).workspace);
|
|
15599
|
+
})).workspace, "createWorkspace response missing workspace"));
|
|
15276
15600
|
}
|
|
15277
15601
|
const createCommand = defineAppCommand({
|
|
15278
15602
|
name: "create",
|
|
@@ -15338,7 +15662,7 @@ const createCommand = defineAppCommand({
|
|
|
15338
15662
|
};
|
|
15339
15663
|
if (!args.json) logger.success(`Profile "${profileName}" created successfully.`);
|
|
15340
15664
|
}
|
|
15341
|
-
if (!args.json) logger.success(`Workspace "${
|
|
15665
|
+
if (!args.json) logger.success(`Workspace "${workspaceDisplayName(workspace)}" created successfully.`);
|
|
15342
15666
|
if (args.json && profileInfo) {
|
|
15343
15667
|
logger.out({
|
|
15344
15668
|
...workspace,
|
|
@@ -15346,7 +15670,10 @@ const createCommand = defineAppCommand({
|
|
|
15346
15670
|
});
|
|
15347
15671
|
return;
|
|
15348
15672
|
}
|
|
15349
|
-
logger.out(workspace
|
|
15673
|
+
logger.out(workspace, { display: {
|
|
15674
|
+
name: workspaceNameTransformer,
|
|
15675
|
+
folderName: null
|
|
15676
|
+
} });
|
|
15350
15677
|
if (profileInfo) {
|
|
15351
15678
|
logger.out("Profile:");
|
|
15352
15679
|
logger.out(profileInfo);
|
|
@@ -15359,7 +15686,7 @@ const createCommand = defineAppCommand({
|
|
|
15359
15686
|
const deleteWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
|
|
15360
15687
|
async function loadOptions$7(options) {
|
|
15361
15688
|
const result = deleteWorkspaceOptionsSchema.safeParse(options);
|
|
15362
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15689
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15363
15690
|
return {
|
|
15364
15691
|
client: await initOperatorClient(await loadAccessToken()),
|
|
15365
15692
|
workspaceId: result.data.workspaceId
|
|
@@ -15393,8 +15720,15 @@ const deleteCommand = defineAppCommand({
|
|
|
15393
15720
|
} catch {
|
|
15394
15721
|
throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
15395
15722
|
}
|
|
15723
|
+
const workspaceResource = workspace.workspace;
|
|
15724
|
+
const workspaceName = workspaceResource?.name ?? workspaceId;
|
|
15725
|
+
const displayName = workspaceDisplayName({
|
|
15726
|
+
name: workspaceName,
|
|
15727
|
+
folderName: workspaceResource ? await resolveWorkspaceFolderName(client, workspaceResource) : ""
|
|
15728
|
+
});
|
|
15396
15729
|
if (!args.yes) {
|
|
15397
|
-
|
|
15730
|
+
const confirmation = await prompt.text({ message: `Enter the workspace name to confirm deletion (${displayName}):` });
|
|
15731
|
+
if (confirmation !== workspaceName && confirmation !== displayName) {
|
|
15398
15732
|
logger.info("Workspace deletion cancelled.");
|
|
15399
15733
|
return;
|
|
15400
15734
|
}
|
|
@@ -15406,8 +15740,8 @@ const deleteCommand = defineAppCommand({
|
|
|
15406
15740
|
for (const [profileName] of profilesToDelete) delete pfConfig.profiles[profileName];
|
|
15407
15741
|
writePlatformConfig(pfConfig);
|
|
15408
15742
|
}
|
|
15409
|
-
if (profilesToDelete.length > 0) logger.success(`Workspace "${
|
|
15410
|
-
else logger.success(`Workspace "${
|
|
15743
|
+
if (profilesToDelete.length > 0) logger.success(`Workspace "${displayName}" and ${profilesToDelete.length} associated profile(s) deleted successfully.`);
|
|
15744
|
+
else logger.success(`Workspace "${displayName}" deleted successfully.`);
|
|
15411
15745
|
}
|
|
15412
15746
|
});
|
|
15413
15747
|
|
|
@@ -15419,12 +15753,9 @@ const getWorkspaceOptionsSchema = z.object({
|
|
|
15419
15753
|
});
|
|
15420
15754
|
async function loadOptions$6(options) {
|
|
15421
15755
|
const result = getWorkspaceOptionsSchema.safeParse(options);
|
|
15422
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15756
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15423
15757
|
return {
|
|
15424
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15425
|
-
useProfile: true,
|
|
15426
|
-
profile: result.data.profile
|
|
15427
|
-
})),
|
|
15758
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15428
15759
|
workspaceId: await loadWorkspaceId({
|
|
15429
15760
|
workspaceId: result.data.workspaceId,
|
|
15430
15761
|
profile: result.data.profile
|
|
@@ -15440,7 +15771,7 @@ async function getWorkspace(options) {
|
|
|
15440
15771
|
const { client, workspaceId } = await loadOptions$6(options);
|
|
15441
15772
|
const response = await client.getWorkspace({ workspaceId });
|
|
15442
15773
|
if (!response.workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
15443
|
-
return
|
|
15774
|
+
return workspaceDetailsWithFolderName(client, response.workspace);
|
|
15444
15775
|
}
|
|
15445
15776
|
const getCommand = defineAppCommand({
|
|
15446
15777
|
name: "get",
|
|
@@ -15456,7 +15787,10 @@ const getCommand = defineAppCommand({
|
|
|
15456
15787
|
createdAt: humanizeRelativeTime(workspace.createdAt),
|
|
15457
15788
|
updatedAt: humanizeRelativeTime(workspace.updatedAt)
|
|
15458
15789
|
};
|
|
15459
|
-
logger.out(formattedWorkspace
|
|
15790
|
+
logger.out(formattedWorkspace, { display: {
|
|
15791
|
+
name: workspaceNameTransformer,
|
|
15792
|
+
folderName: null
|
|
15793
|
+
} });
|
|
15460
15794
|
}
|
|
15461
15795
|
});
|
|
15462
15796
|
|
|
@@ -15470,14 +15804,14 @@ const getCommand = defineAppCommand({
|
|
|
15470
15804
|
async function listWorkspaces(options) {
|
|
15471
15805
|
const client = await initOperatorClient(await loadAccessToken());
|
|
15472
15806
|
const pageDirection = toPageDirection(options?.order);
|
|
15473
|
-
return (await fetchPaged(async (pageToken, pageSize) => {
|
|
15807
|
+
return workspaceInfosWithFolderNames(client, await fetchPaged(async (pageToken, pageSize) => {
|
|
15474
15808
|
const { workspaces, nextPageToken } = await client.listWorkspaces({
|
|
15475
15809
|
pageToken,
|
|
15476
15810
|
pageSize,
|
|
15477
15811
|
pageDirection
|
|
15478
15812
|
});
|
|
15479
15813
|
return [workspaces, nextPageToken];
|
|
15480
|
-
}, { limit: options?.limit }))
|
|
15814
|
+
}, { limit: options?.limit }));
|
|
15481
15815
|
}
|
|
15482
15816
|
const listCommand$1 = defineAppCommand({
|
|
15483
15817
|
name: "list",
|
|
@@ -15488,7 +15822,11 @@ const listCommand$1 = defineAppCommand({
|
|
|
15488
15822
|
order: args.order,
|
|
15489
15823
|
limit: args.limit
|
|
15490
15824
|
});
|
|
15491
|
-
logger.out(workspaces, { display: {
|
|
15825
|
+
logger.out(workspaces, { display: {
|
|
15826
|
+
name: workspaceNameTransformer,
|
|
15827
|
+
folderName: null,
|
|
15828
|
+
updatedAt: null
|
|
15829
|
+
} });
|
|
15492
15830
|
}
|
|
15493
15831
|
});
|
|
15494
15832
|
|
|
@@ -15497,7 +15835,7 @@ const listCommand$1 = defineAppCommand({
|
|
|
15497
15835
|
const restoreWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
|
|
15498
15836
|
async function loadOptions$5(options) {
|
|
15499
15837
|
const result = restoreWorkspaceOptionsSchema.safeParse(options);
|
|
15500
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15838
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15501
15839
|
return {
|
|
15502
15840
|
client: await initOperatorClient(await loadAccessToken()),
|
|
15503
15841
|
workspaceId: result.data.workspaceId
|
|
@@ -15577,12 +15915,9 @@ const inviteUserOptionsSchema = z.object({
|
|
|
15577
15915
|
});
|
|
15578
15916
|
async function loadOptions$4(options) {
|
|
15579
15917
|
const result = inviteUserOptionsSchema.safeParse(options);
|
|
15580
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15918
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15581
15919
|
return {
|
|
15582
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15583
|
-
useProfile: true,
|
|
15584
|
-
profile: result.data.profile
|
|
15585
|
-
})),
|
|
15920
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15586
15921
|
workspaceId: await loadWorkspaceId({
|
|
15587
15922
|
workspaceId: result.data.workspaceId,
|
|
15588
15923
|
profile: result.data.profile
|
|
@@ -15637,12 +15972,9 @@ const listUsersOptionsSchema = z.object({
|
|
|
15637
15972
|
});
|
|
15638
15973
|
async function loadOptions$3(options) {
|
|
15639
15974
|
const result = listUsersOptionsSchema.safeParse(options);
|
|
15640
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
15975
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15641
15976
|
return {
|
|
15642
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15643
|
-
useProfile: true,
|
|
15644
|
-
profile: result.data.profile
|
|
15645
|
-
})),
|
|
15977
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15646
15978
|
workspaceId: await loadWorkspaceId({
|
|
15647
15979
|
workspaceId: result.data.workspaceId,
|
|
15648
15980
|
profile: result.data.profile
|
|
@@ -15696,12 +16028,9 @@ const removeUserOptionsSchema = z.object({
|
|
|
15696
16028
|
});
|
|
15697
16029
|
async function loadOptions$2(options) {
|
|
15698
16030
|
const result = removeUserOptionsSchema.safeParse(options);
|
|
15699
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16031
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15700
16032
|
return {
|
|
15701
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15702
|
-
useProfile: true,
|
|
15703
|
-
profile: result.data.profile
|
|
15704
|
-
})),
|
|
16033
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15705
16034
|
workspaceId: await loadWorkspaceId({
|
|
15706
16035
|
workspaceId: result.data.workspaceId,
|
|
15707
16036
|
profile: result.data.profile
|
|
@@ -15756,12 +16085,9 @@ const updateUserOptionsSchema = z.object({
|
|
|
15756
16085
|
});
|
|
15757
16086
|
async function loadOptions$1(options) {
|
|
15758
16087
|
const result = updateUserOptionsSchema.safeParse(options);
|
|
15759
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16088
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
15760
16089
|
return {
|
|
15761
|
-
client: await initOperatorClient(await loadAccessToken({
|
|
15762
|
-
useProfile: true,
|
|
15763
|
-
profile: result.data.profile
|
|
15764
|
-
})),
|
|
16090
|
+
client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
|
|
15765
16091
|
workspaceId: await loadWorkspaceId({
|
|
15766
16092
|
workspaceId: result.data.workspaceId,
|
|
15767
16093
|
profile: result.data.profile
|
|
@@ -15982,7 +16308,7 @@ function isSqlInputComplete(input) {
|
|
|
15982
16308
|
let dollarQuoteTag = null;
|
|
15983
16309
|
let lastSignificantTokenWasSemicolon = false;
|
|
15984
16310
|
for (let i = 0; i < input.length; i += 1) {
|
|
15985
|
-
const char = input[i];
|
|
16311
|
+
const char = assertDefined(input[i], `character at index ${i} missing`);
|
|
15986
16312
|
const next = input[i + 1];
|
|
15987
16313
|
if (inLineComment) {
|
|
15988
16314
|
if (char === "\n") inLineComment = false;
|
|
@@ -16185,7 +16511,7 @@ const queryBaseOptionsSchema = z.object({
|
|
|
16185
16511
|
const queryOptionsSchema = queryBaseOptionsSchema.extend({ query: z.string() });
|
|
16186
16512
|
async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces) {
|
|
16187
16513
|
if (namespaces.length === 0) throw new Error("No namespaces found in configuration.");
|
|
16188
|
-
if (namespaces.length === 1) return namespaces[0];
|
|
16514
|
+
if (namespaces.length === 1) return assertDefined(namespaces[0], "namespace missing");
|
|
16189
16515
|
const typeNames = extractTypeNamesFromSql(query);
|
|
16190
16516
|
if (typeNames.length === 0) throw new Error(`Could not infer namespace from query. Detected namespaces: ${namespaces.join(", ")}.`);
|
|
16191
16517
|
const typeNamespaceMap = await resolveTypeNamespaces({
|
|
@@ -16197,16 +16523,13 @@ async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces)
|
|
|
16197
16523
|
const notFoundTypes = typeNames.filter((typeName) => !typeNamespaceMap.has(typeName));
|
|
16198
16524
|
if (notFoundTypes.length > 0) throw new Error(`Could not find namespace for types in query: ${notFoundTypes.join(", ")}.`);
|
|
16199
16525
|
const namespacesFromTypes = new Set(typeNamespaceMap.values());
|
|
16200
|
-
if (namespacesFromTypes.size === 1) return [...namespacesFromTypes][0];
|
|
16526
|
+
if (namespacesFromTypes.size === 1) return assertDefined([...namespacesFromTypes][0], "namespace from types missing");
|
|
16201
16527
|
throw new Error(`Query references types from multiple namespaces: ${[...namespacesFromTypes].join(", ")}.`);
|
|
16202
16528
|
}
|
|
16203
16529
|
async function loadOptions(options) {
|
|
16204
16530
|
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
|
-
}));
|
|
16531
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
|
|
16532
|
+
const client = await initOperatorClient(await loadAccessToken({ profile: result.data.profile }));
|
|
16210
16533
|
const workspaceId = await loadWorkspaceId({
|
|
16211
16534
|
workspaceId: result.data.workspaceId,
|
|
16212
16535
|
profile: result.data.profile
|
|
@@ -16339,7 +16662,7 @@ async function resolveEditedQueryInput(engine) {
|
|
|
16339
16662
|
*/
|
|
16340
16663
|
async function query(options) {
|
|
16341
16664
|
const result = queryOptionsSchema.safeParse(options);
|
|
16342
|
-
if (!result.success) throw new Error(result.error.issues[0].message);
|
|
16665
|
+
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
|
|
16343
16666
|
return await (await prepareQueryExecutor(result.data))(result.data.query);
|
|
16344
16667
|
}
|
|
16345
16668
|
async function prepareQueryExecutor(options) {
|
|
@@ -16421,7 +16744,7 @@ async function runRepl(options) {
|
|
|
16421
16744
|
const execute = await prepareQueryExecutor(options);
|
|
16422
16745
|
const historyPath = getReplHistoryPath(options.engine, options.profile, options.workspaceId);
|
|
16423
16746
|
const validate = createReplValidator(options.engine);
|
|
16424
|
-
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-
|
|
16747
|
+
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-CJG3sz7A.mjs");
|
|
16425
16748
|
const highlight = options.engine === "sql" ? highlightSqlLine : highlightGraphqlLine;
|
|
16426
16749
|
const prompt = createPrompt({
|
|
16427
16750
|
prefix: "",
|
|
@@ -16682,8 +17005,9 @@ function printSingleSqlResult(execResult, options = {}) {
|
|
|
16682
17005
|
function splitSqlStatements(query) {
|
|
16683
17006
|
const statements = parse(query, { locationTracking: true });
|
|
16684
17007
|
return statements.map((s, i) => {
|
|
16685
|
-
const start = s._location.start;
|
|
16686
|
-
const
|
|
17008
|
+
const start = assertDefined(s._location, "SQL statement location missing").start;
|
|
17009
|
+
const nextStmt = statements[i + 1];
|
|
17010
|
+
const end = nextStmt !== void 0 ? assertDefined(nextStmt._location, "SQL statement location missing").start : query.length;
|
|
16687
17011
|
return query.substring(start, end);
|
|
16688
17012
|
});
|
|
16689
17013
|
}
|
|
@@ -16703,7 +17027,7 @@ function printSqlResult(result, options = {}) {
|
|
|
16703
17027
|
for (let i = 0; i < result.result.length; i++) {
|
|
16704
17028
|
if (i > 0) logger.log("");
|
|
16705
17029
|
logger.info(queries[i] ?? `Statement ${i + 1}`);
|
|
16706
|
-
printSingleSqlResult(result.result[i], options);
|
|
17030
|
+
printSingleSqlResult(assertDefined(result.result[i], `SQL result at index ${i} missing`), options);
|
|
16707
17031
|
}
|
|
16708
17032
|
return;
|
|
16709
17033
|
}
|
|
@@ -16754,5 +17078,5 @@ function isDeno() {
|
|
|
16754
17078
|
}
|
|
16755
17079
|
|
|
16756
17080
|
//#endregion
|
|
16757
|
-
export { listCommand$5 as $,
|
|
16758
|
-
//# sourceMappingURL=runtime-
|
|
17081
|
+
export { listCommand$5 as $, INITIAL_SCHEMA_NUMBER as $t, truncate as A, configArg as An, startCommand as At, logBetaWarning as B, getExecutor as Bt, listCommand$2 as C, generateUserTypes as Cn, triggerExecutor as Ct, resumeWorkflow as D, assertWritable as Dn, jobsCommand as Dt, resumeCommand as E, apiCall as En, getExecutorJob as Et, writeDbTypesFile as F, paginationArgs as Fn, getWorkflowExecution as Ft, organizationTree as G, MIGRATION_LABEL_KEY as Gt, removeCommand$1 as H, executeScript as Ht, getConfiguredEditorCommand as I, toPageDirection as In, listWorkflowExecutions as It, listOrganizations as J, compareSnapshotWithRemote as Jt, treeCommand as K, handleOptionalToRequiredError as Kt, openInConfiguredEditor as L, workspaceArgs as Ln, functionExecutionStatusToString as Lt, generate as M, deploymentArgs as Mn, getCommand$5 as Mt, generateCommand as N, isVerbose as Nn, getWorkflow as Nt, listCommand$3 as O, defineAppCommand as On, listExecutorJobs as Ot, generateMigrationScript as P, pagedLogArgs as Pn, executionsCommand as Pt, updateFolder as Q, DIFF_FILE_NAME as Qt, show as R, formatKeyValueTable as Rt, listApps as S, PluginManager as Sn, triggerCommand as St, healthCommand as T, apiCommand as Tn, listExecutors as Tt, updateCommand$1 as U, waitForExecution$1 as Ut, remove as V, deploy as Vt, updateOrganization as W, bundleMigrationScript as Wt, getOrganization as X, protoGqlPermission as Xt, getCommand$1 as Y, generateAllTypeManifestsFromSnapshot as Yt, updateCommand$2 as Z, DB_TYPES_FILE_NAME as Zt, getWorkspace as _, formatMigrationDiff as _n, listFunctionRegistries as _t, updateUser as a, createSnapshotFromLocalTypes as an, createCommand$1 as at, createCommand as b, resourceTrn as bn, listWebhookExecutors as bt, listCommand as c, getMigrationFilePath as cn, listOAuth2Clients as ct, inviteUser as d, isValidMigrationNumber as dn, getMachineUserToken as dt, MIGRATE_FILE_NAME as en, listFolders as et, restoreCommand as f, loadDiff as fn, tokenCommand as ft, getCommand as g, formatDiffSummary as gn, listCommand$8 as gt, listWorkspaces as h, parseMigrationNumberArg as hn, generate$1 as ht, updateCommand as i, compareSnapshots as in, deleteFolder as it, truncateCommand as j, confirmationArgs as jn, startWorkflow as jt, listWorkflows as k, commonArgs as kn, watchExecutorJob as kt, listUsers as l, getMigrationFiles as ln, getCommand$3 as lt, listCommand$1 as m, formatMigrationNumber as mn, listMachineUsers as mt, query as n, assertValidMigrationFiles as nn, getFolder as nt, removeCommand as o, getLatestMigrationNumber as on, createFolder as ot, restoreWorkspace as p, reconstructSnapshotFromMigrations as pn, listCommand$7 as pt, listCommand$4 as q, parseMigrationLabelNumber as qt, queryCommand as r, compareLocalTypesWithSnapshot as rn, deleteCommand$1 as rt, removeUser as s, getMigrationDirPath as sn, listCommand$6 as st, isNativeTypeScriptRuntime as t, SCHEMA_FILE_NAME as tn, getCommand$2 as tt, inviteCommand as u, getNextMigrationNumber as un, getOAuth2Client as ut, deleteCommand as v, hasChanges as vn, getCommand$4 as vt, getAppHealth as w, prompt as wn, listCommand$9 as wt, createWorkspace as x, sdkNameLabelKey as xn, webhookCommand as xt, deleteWorkspace as y, getNamespacesWithMigrations as yn, getFunctionRegistry as yt, showCommand as z, getCommand$6 as zt };
|
|
17082
|
+
//# sourceMappingURL=runtime-C6o4hiYq.mjs.map
|