@tailor-platform/sdk 1.60.2 → 1.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -0
  3. package/dist/{application-pusdxz35.mjs → application-BezXGbrU.mjs} +73 -509
  4. package/dist/application-BezXGbrU.mjs.map +1 -0
  5. package/dist/application-DSXntqnV.mjs +4 -0
  6. package/dist/assert-CKfwrmCV.mjs +10 -0
  7. package/dist/assert-CKfwrmCV.mjs.map +1 -0
  8. package/dist/cli/index.mjs +376 -136
  9. package/dist/cli/index.mjs.map +1 -1
  10. package/dist/cli/lib.d.mts +3 -1
  11. package/dist/cli/lib.mjs +13 -6
  12. package/dist/cli/lib.mjs.map +1 -1
  13. package/dist/{client-B-jRdlC_.mjs → client-C68VWo4g.mjs} +1 -1
  14. package/dist/{client-W5P4NYYX.mjs → client-CobIRHl-.mjs} +207 -2
  15. package/dist/{client-W5P4NYYX.mjs.map → client-CobIRHl-.mjs.map} +1 -1
  16. package/dist/configure/index.mjs +2 -2
  17. package/dist/{crashreport-D3DvAzdg.mjs → crashreport-BhD0y14F.mjs} +2 -2
  18. package/dist/{crashreport-D3DvAzdg.mjs.map → crashreport-BhD0y14F.mjs.map} +1 -1
  19. package/dist/{crashreport-lnVTnbB5.mjs → crashreport-D1wKBJ8N.mjs} +1 -1
  20. package/dist/{mock-Dpu__UeJ.mjs → mock-DMgIygjE.mjs} +3 -2
  21. package/dist/mock-DMgIygjE.mjs.map +1 -0
  22. package/dist/plugin/builtin/seed/index.mjs +1 -1
  23. package/dist/plugin/index.mjs +1 -1
  24. package/dist/plugin/index.mjs.map +1 -1
  25. package/dist/registry-D0uB0OrK.mjs.map +1 -1
  26. package/dist/{repl-editor-Y9QJDL0K.mjs → repl-editor-CJG3sz7A.mjs} +11 -9
  27. package/dist/repl-editor-CJG3sz7A.mjs.map +1 -0
  28. package/dist/{runtime-CZpsV8vj.mjs → runtime-C6o4hiYq.mjs} +994 -590
  29. package/dist/runtime-C6o4hiYq.mjs.map +1 -0
  30. package/dist/{schema-DYKNTu-n.mjs → schema-1msIhXwA.mjs} +12 -7
  31. package/dist/schema-1msIhXwA.mjs.map +1 -0
  32. package/dist/{seed-C0fE2sJB.mjs → seed-BH2FbrPV.mjs} +4 -3
  33. package/dist/seed-BH2FbrPV.mjs.map +1 -0
  34. package/dist/service-BHQIerYh.mjs +4 -0
  35. package/dist/{service-aPT0fx3y.mjs → service-DMohAx8a2.mjs} +3 -3
  36. package/dist/service-DMohAx8a2.mjs.map +1 -0
  37. package/dist/service-wI3Hvrgx.mjs +460 -0
  38. package/dist/service-wI3Hvrgx.mjs.map +1 -0
  39. package/dist/{types-Ccwchyj5.mjs → types-2Be3wSMc.mjs} +1 -1
  40. package/dist/{types-BwGth3a1.mjs → types-CmzfQP_m.mjs} +3 -3
  41. package/dist/types-CmzfQP_m.mjs.map +1 -0
  42. package/dist/utils/test/index.mjs +1 -1
  43. package/dist/utils/test/index.mjs.map +1 -1
  44. package/dist/vitest/index.mjs +7 -4
  45. package/dist/vitest/index.mjs.map +1 -1
  46. package/dist/vitest/setup.mjs +1 -1
  47. package/docs/cli/application.md +11 -10
  48. package/docs/cli/tailordb.md +54 -0
  49. package/docs/cli-reference.md +1 -0
  50. package/docs/configuration.md +2 -0
  51. package/docs/multi-environment.md +74 -0
  52. package/docs/services/staticwebsite.md +2 -0
  53. package/docs/services/tailordb-migration.md +17 -1
  54. package/package.json +2 -1
  55. package/dist/application-D4tRNn90.mjs +0 -4
  56. package/dist/application-pusdxz35.mjs.map +0 -1
  57. package/dist/mock-Dpu__UeJ.mjs.map +0 -1
  58. package/dist/repl-editor-Y9QJDL0K.mjs.map +0 -1
  59. package/dist/runtime-CZpsV8vj.mjs.map +0 -1
  60. package/dist/schema-DYKNTu-n.mjs.map +0 -1
  61. package/dist/seed-C0fE2sJB.mjs.map +0 -1
  62. package/dist/service-aPT0fx3y.mjs.map +0 -1
  63. package/dist/types-BwGth3a1.mjs.map +0 -1
@@ -1,8 +1,10 @@
1
1
 
2
- import { t as db } from "./schema-DYKNTu-n.mjs";
3
- import { $ as Subgraph_ServiceType, A as IdPLang, B as AuthIDPConfig_AuthType, C as TailorDBGQLPermission_Operator, D as TailorDBType_PermitAction, E as TailorDBType_Permission_Permit, F as ExecutorJobStatus, G as AuthSCIMAttribute_Type, H as AuthOAuth2Client_ClientType, I as ExecutorTargetType, K as AuthSCIMAttribute_Uniqueness, L as ExecutorTriggerType, M as IdPPermissionPermit, N as FunctionExecution_Status, Q as ApplicationSchemaUpdateAttemptStatus, R as AuthConnection_Type, S as TailorDBGQLPermission_Action, T as TailorDBType_Permission_Operator, U as AuthOAuth2Client_GrantType, V as AuthInvokerSchema, W as AuthSCIMAttribute_Mutability, X as UserProfileProviderConfig_UserProfileProviderType, Y as TenantProviderConfig_TenantProviderType, Z as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, _ as userAgent, a as fetchAll, b as WorkflowExecution_Status, et as ConditionSchema, f as initOperatorClient, h as resolveStaticWebsiteUrls, j as IdPPermissionOperator, k as PipelineResolver_OperationType, m as platformBaseUrl, nt as FilterSchema, o as fetchMachineUserToken, q as AuthSCIMConfig_AuthorizationType, rt as PageDirection, s as fetchPaged, tt as Condition_Operator, v as OperatorService, w as TailorDBGQLPermission_Permit, x as WorkflowJobExecution_Status, y as WorkspacePlatformUserRole, z as AuthHookPoint } from "./client-W5P4NYYX.mjs";
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 { A as loadConfigPath, C as getDistDir, E as loadConfig, F as writePlatformConfig, M as readPlatformConfig, S as createBundleCache, T as hashFile, _ as loadFilesWithIgnores, c as createExecutorService, d as buildExecutorArgsExpr, f as buildResolverOperationHookExpr, g as stringifyFunction, h as TailorDBTypeSchema, j as loadWorkspaceId, k as loadAccessToken, m as assertUniqueTailorDBTypeNamesWithExternal, n as generatePluginFilesIfNeeded, p as assertUniqueLocalTailorDBTypeNames, r as loadApplication, s as HTTP_METHODS, t as defineApplication, v as platformBundleDefinePlugin } from "./application-pusdxz35.mjs";
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
- return parseInt(match[1], 10) > 0;
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 (metadata.files && Object.keys(metadata.files).length > 0) result = result.files(metadata.files);
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?.record) result = result.permission(metadata.permissions.record);
1602
- if (metadata.permissions?.gql) result = result.gqlPermission(metadata.permissions.gql);
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 && original.plugins.length > 0) for (const plugin of original.plugins) result = result.plugin({ [plugin.pluginId]: plugin.config });
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 if (phase === "delete") await Promise.all(changeSet.deletes.map(async (del) => {
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 && application.authService.config) {
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) authIdpConfigName = idpConfigs[0].name;
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) if (auth.connections) for (const [name, config] of Object.entries(auth.connections)) desiredConnections[name] = config;
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" || !config.value) return void 0;
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 if (phase === "delete-resources" || phase === "delete") {
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 if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteFunctionRegistry({
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 if (phase === "delete-services") await Promise.all(changeSet.service.deletes.map((del) => client.deleteIdPService(del.request)));
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 (let i = 0; i < idps.length; i++) {
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 (let i = 0; i < deletedServices.length; i++) {
3364
- const namespaceName = deletedServices[i];
3365
- deletedClientsByService[i].forEach((client) => {
3366
- changeSet.deletes.push({
3367
- name: client.name,
3368
- request: {
3369
- workspaceId,
3370
- namespaceName,
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
- if (changeSet.connection) await applyAuthConnections(client, { changeSet: changeSet.connection }, "create-update");
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
- create.request.oauth2Client.redirectUris = await resolveStaticWebsiteUrls(client, create.request.workspaceId, create.request.oauth2Client.redirectUris, "OAuth2 redirect URIs");
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
- update.request.oauth2Client.redirectUris = await resolveStaticWebsiteUrls(client, update.request.workspaceId, update.request.oauth2Client.redirectUris, "OAuth2 redirect URIs");
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
- replace.createRequest.oauth2Client.redirectUris = await resolveStaticWebsiteUrls(client, replace.createRequest.workspaceId, replace.createRequest.oauth2Client.redirectUris, "OAuth2 redirect URIs");
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
- if (changeSet.connection) await applyAuthConnections(client, { changeSet: changeSet.connection }, "delete-resources");
3526
- } else if (phase === "delete-services") await Promise.all(changeSet.service.deletes.map((del) => client.deleteAuthService(del.request)));
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 if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteExecutorExecutor(del.request)));
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[typeName]) return service.namespace;
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 if (phase === "delete-services") await Promise.all(changeSet.service.deletes.map((del) => client.deletePipelineService(del.request)));
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
- workspaceId: create.workspaceId,
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[vault.vaultName]) state.vaults[vault.vaultName] = {};
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 if (phase === "delete") {
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[del.vaultName]) {
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 if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteStaticWebsite(del.request)));
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
- if (types[change.typeName] && change.after) {
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
- ...types[change.typeName],
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
- if (types[change.typeName] && change.fieldName) types[change.typeName] = {
6691
- ...types[change.typeName],
6738
+ case "field_modified": {
6739
+ const existing = types[change.typeName];
6740
+ if (existing && change.fieldName) types[change.typeName] = {
6741
+ ...existing,
6692
6742
  fields: {
6693
- ...types[change.typeName].fields,
6743
+ ...existing.fields,
6694
6744
  [change.fieldName]: change.after
6695
6745
  }
6696
6746
  };
6697
6747
  break;
6698
- case "field_removed":
6699
- if (types[change.typeName] && change.fieldName) {
6700
- const { [change.fieldName]: _, ...remainingFields } = types[change.typeName].fields;
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
- ...types[change.typeName],
6754
+ ...existing,
6703
6755
  fields: remainingFields
6704
6756
  };
6705
6757
  }
6706
6758
  break;
6759
+ }
6707
6760
  case "index_added":
6708
- case "index_modified":
6709
- if (types[change.typeName] && change.indexName) types[change.typeName] = {
6710
- ...types[change.typeName],
6761
+ case "index_modified": {
6762
+ const existing = types[change.typeName];
6763
+ if (existing && change.indexName) types[change.typeName] = {
6764
+ ...existing,
6711
6765
  indexes: {
6712
- ...types[change.typeName].indexes,
6766
+ ...existing.indexes,
6713
6767
  [change.indexName]: change.after
6714
6768
  }
6715
6769
  };
6716
6770
  break;
6717
- case "index_removed":
6718
- if (types[change.typeName] && change.indexName && types[change.typeName].indexes) {
6719
- const { [change.indexName]: _, ...remainingIndexes } = types[change.typeName].indexes;
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
- ...types[change.typeName],
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
- if (types[change.typeName] && change.fieldName) types[change.typeName] = {
6729
- ...types[change.typeName],
6784
+ case "file_modified": {
6785
+ const existing = types[change.typeName];
6786
+ if (existing && change.fieldName) types[change.typeName] = {
6787
+ ...existing,
6730
6788
  files: {
6731
- ...types[change.typeName].files,
6789
+ ...existing.files,
6732
6790
  [change.fieldName]: change.after
6733
6791
  }
6734
6792
  };
6735
6793
  break;
6736
- case "file_removed":
6737
- if (types[change.typeName] && change.fieldName && types[change.typeName].files) {
6738
- const { [change.fieldName]: _, ...remainingFiles } = types[change.typeName].files;
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
- ...types[change.typeName],
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
- if (types[change.typeName] && change.relationshipName) {
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 ?? (types[change.typeName].forwardRelationships?.[change.relationshipName] ? "forward" : types[change.typeName].backwardRelationships?.[change.relationshipName] ? "backward" : "forward")) === "forward") types[change.typeName] = {
6750
- ...types[change.typeName],
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
- ...types[change.typeName].forwardRelationships,
6814
+ ...existing.forwardRelationships,
6753
6815
  [change.relationshipName]: rel
6754
6816
  }
6755
6817
  };
6756
6818
  else types[change.typeName] = {
6757
- ...types[change.typeName],
6819
+ ...existing,
6758
6820
  backwardRelationships: {
6759
- ...types[change.typeName].backwardRelationships,
6821
+ ...existing.backwardRelationships,
6760
6822
  [change.relationshipName]: rel
6761
6823
  }
6762
6824
  };
6763
6825
  }
6764
6826
  break;
6765
- case "relationship_removed":
6766
- if (types[change.typeName] && change.relationshipName) {
6767
- const type = types[change.typeName];
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
- case "permission_modified":
6785
- if (types[change.typeName] && change.after) {
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
- ...types[change.typeName],
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
- if (oldValidate[i].script.expr !== newValidate[i].script.expr) return true;
6873
- if (oldValidate[i].errorMessage !== newValidate[i].errorMessage) return true;
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
- if (!newFields[fieldName]) return true;
6891
- if (areFieldsDifferent(oldFields[fieldName], newFields[fieldName])) return true;
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)) addChange(ctx, {
6977
- kind: "field_added",
6978
- typeName,
6979
- fieldName,
6980
- after: currType.fields[fieldName]
6981
- }, void 0, currType.fields[fieldName]);
6982
- for (const fieldName of prevFieldNames) if (!currFieldNames.has(fieldName)) addChange(ctx, {
6983
- kind: "field_removed",
6984
- typeName,
6985
- fieldName,
6986
- before: prevType.fields[fieldName]
6987
- }, prevType.fields[fieldName], void 0);
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 newKeys) if (!oldKeys.has(indexName)) ctx.changes.push({
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: newIndexes[indexName]
7092
+ after: indexConfig
7017
7093
  });
7018
- for (const indexName of oldKeys) if (!newKeys.has(indexName)) ctx.changes.push({
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: oldIndexes[indexName]
7098
+ before: indexConfig
7023
7099
  });
7024
- for (const indexName of newKeys) if (oldKeys.has(indexName)) {
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 newKeys) if (!oldKeys.has(fileName)) ctx.changes.push({
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: newFiles[fileName]
7134
+ after: fileDesc
7060
7135
  });
7061
- for (const fileName of oldKeys) if (!newKeys.has(fileName)) ctx.changes.push({
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: oldFiles[fileName]
7140
+ before: fileDesc
7066
7141
  });
7067
- for (const fileName of newKeys) if (oldKeys.has(fileName)) {
7068
- if (oldFiles[fileName] !== newFiles[fileName]) ctx.changes.push({
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: oldFiles[fileName],
7074
- after: newFiles[fileName]
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 newKeys) if (!oldKeys.has(relName)) ctx.changes.push({
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: newRelationships[relName]
7171
+ after: rel
7096
7172
  });
7097
- for (const relName of oldKeys) if (!newKeys.has(relName)) ctx.changes.push({
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: oldRelationships[relName]
7178
+ before: rel
7103
7179
  });
7104
- for (const relName of newKeys) if (oldKeys.has(relName)) {
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 currentTypeNames) if (!previousTypeNames.has(typeName)) ctx.changes.push({
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: current.types[typeName]
7249
+ after: type
7175
7250
  });
7176
- for (const typeName of previousTypeNames) if (!currentTypeNames.has(typeName)) {
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: previous.types[typeName]
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 if (file.type === "diff") diffFiles.push(file.number);
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?.["sdk-migration"];
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 if (phase === "delete-services") await Promise.all(changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)));
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?.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
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?.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
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.keys(types)) {
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.keys(types)) {
9088
- const tailordbType = generateTailorDBTypeManifestFromSnapshot(types[typeName], {
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.keys(types)) {
9234
- const gqlPermission = types[typeName].permissions?.gql;
9448
+ for (const [typeName, typeEntry] of Object.entries(types)) {
9449
+ const gqlPermission = typeEntry.permissions?.gql;
9235
9450
  if (!gqlPermission) continue;
9236
9451
  const desiredPermission = protoGqlPermission(gqlPermission);
9237
9452
  const existingPermission = existingGqlPermissions.find((entry) => entry.typeName === typeName);
@@ -9286,97 +9501,6 @@ function normalizeComparableGqlPermission(permission) {
9286
9501
  actions: (policy.actions ?? []).toSorted((left, right) => left - right)
9287
9502
  })) };
9288
9503
  }
9289
- function protoGqlPermission(permission) {
9290
- return { policies: permission.map((policy) => protoGqlPolicy(policy)) };
9291
- }
9292
- function protoGqlPolicy(policy) {
9293
- const actions = [];
9294
- for (const action of policy.actions) switch (action) {
9295
- case "all":
9296
- actions.push(TailorDBGQLPermission_Action.ALL);
9297
- break;
9298
- case "create":
9299
- actions.push(TailorDBGQLPermission_Action.CREATE);
9300
- break;
9301
- case "read":
9302
- actions.push(TailorDBGQLPermission_Action.READ);
9303
- break;
9304
- case "update":
9305
- actions.push(TailorDBGQLPermission_Action.UPDATE);
9306
- break;
9307
- case "delete":
9308
- actions.push(TailorDBGQLPermission_Action.DELETE);
9309
- break;
9310
- case "aggregate":
9311
- actions.push(TailorDBGQLPermission_Action.AGGREGATE);
9312
- break;
9313
- case "bulkUpsert":
9314
- actions.push(TailorDBGQLPermission_Action.BULK_UPSERT);
9315
- break;
9316
- default: throw new Error(`Unknown action: ${action}`);
9317
- }
9318
- let permit;
9319
- switch (policy.permit) {
9320
- case "allow":
9321
- permit = TailorDBGQLPermission_Permit.ALLOW;
9322
- break;
9323
- case "deny":
9324
- permit = TailorDBGQLPermission_Permit.DENY;
9325
- break;
9326
- default: throw new Error(`Unknown permission: ${policy.permit}`);
9327
- }
9328
- return {
9329
- conditions: policy.conditions.map((cond) => protoGqlCondition(cond)),
9330
- actions,
9331
- permit,
9332
- description: policy.description
9333
- };
9334
- }
9335
- function protoGqlCondition(condition) {
9336
- const [left, operator, right] = condition;
9337
- const l = protoGqlOperand(left);
9338
- const r = protoGqlOperand(right);
9339
- let op;
9340
- switch (operator) {
9341
- case "eq":
9342
- op = TailorDBGQLPermission_Operator.EQ;
9343
- break;
9344
- case "ne":
9345
- op = TailorDBGQLPermission_Operator.NE;
9346
- break;
9347
- case "in":
9348
- op = TailorDBGQLPermission_Operator.IN;
9349
- break;
9350
- case "nin":
9351
- op = TailorDBGQLPermission_Operator.NIN;
9352
- break;
9353
- case "hasAny":
9354
- op = TailorDBGQLPermission_Operator.HAS_ANY;
9355
- break;
9356
- case "nhasAny":
9357
- op = TailorDBGQLPermission_Operator.NHAS_ANY;
9358
- break;
9359
- default: throw new Error(`Unknown operator: ${operator}`);
9360
- }
9361
- return {
9362
- left: l,
9363
- operator: op,
9364
- right: r
9365
- };
9366
- }
9367
- function protoGqlOperand(operand) {
9368
- if (isSnapshotFieldRefOperand(operand)) {
9369
- if ("user" in operand) return { kind: {
9370
- case: "userField",
9371
- value: operand.user
9372
- } };
9373
- throw new Error(`Unsupported field-ref operand in GQL permission: ${JSON.stringify(operand)} — GQL permissions only support { user } field references`);
9374
- }
9375
- return { kind: {
9376
- case: "value",
9377
- value: fromJson(ValueSchema, operand)
9378
- } };
9379
- }
9380
9504
  /**
9381
9505
  * Check if there are schema differences between migration snapshots and local definitions
9382
9506
  * @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Snapshot-shaped local types by namespace
@@ -9454,31 +9578,78 @@ async function applyWorkflow(client, result, phase = "create-update") {
9454
9578
  const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, appId, result.unchangedWorkflowJobNames);
9455
9579
  await Promise.all([...changeSet.creates.map(async (create) => {
9456
9580
  const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
9581
+ const shape = buildWorkflowValidationShape(create.workspaceId, create.workflow);
9457
9582
  await client.createWorkflow({
9458
- workspaceId: create.workspaceId,
9459
- workflowName: create.workflow.name,
9460
- mainJobFunctionName: create.workflow.mainJob.name,
9461
- jobFunctions: filteredVersions,
9462
- ...create.workflow.retryPolicy && { retryPolicy: toRetryPolicy(create.workflow.retryPolicy) },
9463
- ...create.workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(create.workflow.concurrencyPolicy) }
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: update.workspaceId,
9470
- workflowName: update.workflow.name,
9471
- mainJobFunctionName: update.workflow.mainJob.name,
9472
- jobFunctions: filteredVersions,
9473
- ...update.workflow.retryPolicy && { retryPolicy: toRetryPolicy(update.workflow.retryPolicy) },
9474
- ...update.workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(update.workflow.concurrencyPolicy) }
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 if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteWorkflow({
9479
- workspaceId: del.workspaceId,
9480
- workflowId: del.workflowId
9481
- })));
9604
+ } else {
9605
+ await deleteAllSettled(changeSet.deletes.map((del) => ({
9606
+ resourceType: "workflow",
9607
+ resourceName: del.name,
9608
+ run: () => client.deleteWorkflow({
9609
+ workspaceId: del.workspaceId,
9610
+ workflowId: del.workflowId
9611
+ })
9612
+ })));
9613
+ await deleteAllSettled((result.jobFunctionDeletes ?? collectDeletableJobFunctions(changeSet.deletes)).map((del) => ({
9614
+ resourceType: "workflow job function",
9615
+ resourceName: del.jobFunctionName,
9616
+ run: () => client.deleteWorkflowJobFunction({
9617
+ workspaceId: del.workspaceId,
9618
+ jobFunctionName: del.jobFunctionName
9619
+ })
9620
+ })));
9621
+ }
9622
+ }
9623
+ async function deleteAllSettled(operations) {
9624
+ const results = await Promise.allSettled(operations.map((operation) => operation.run()));
9625
+ const errors = [];
9626
+ results.forEach((result, index) => {
9627
+ if (result.status === "fulfilled") return;
9628
+ const operation = assertDefined(operations[index], "operation missing at index");
9629
+ const error = result.reason;
9630
+ if (error instanceof ConnectError && error.code === Code.NotFound) return;
9631
+ if (error instanceof ConnectError && error.code === Code.FailedPrecondition) {
9632
+ logger.warn(`Skipped deleting ${operation.resourceType} "${operation.resourceName}" because it is still referenced.`);
9633
+ return;
9634
+ }
9635
+ errors.push(error);
9636
+ });
9637
+ const firstError = errors[0];
9638
+ if (firstError) throw firstError;
9639
+ }
9640
+ function collectDeletableJobFunctions(deletes) {
9641
+ const seen = /* @__PURE__ */ new Set();
9642
+ const jobFunctions = [];
9643
+ for (const del of deletes) for (const jobFunctionName of del.deletableJobNames) {
9644
+ const key = `${del.workspaceId}\0${jobFunctionName}`;
9645
+ if (seen.has(key)) continue;
9646
+ seen.add(key);
9647
+ jobFunctions.push({
9648
+ workspaceId: del.workspaceId,
9649
+ jobFunctionName
9650
+ });
9651
+ }
9652
+ return jobFunctions;
9482
9653
  }
9483
9654
  /**
9484
9655
  * Filter job function versions to only include those used by a workflow
@@ -9495,7 +9666,7 @@ function filterJobFunctionVersions(allVersions, usedJobNames) {
9495
9666
  * Register job functions used by any workflow.
9496
9667
  * Only registers jobs that are actually used (based on usedJobNames in changeSet).
9497
9668
  * Uses create for new jobs and update for existing jobs.
9498
- * Sets metadata on used JobFunctions and removes metadata from unused ones.
9669
+ * Sets metadata on used JobFunctions.
9499
9670
  * @param client - Operator client instance
9500
9671
  * @param changeSet - Workflow change set
9501
9672
  * @param appName - Application name
@@ -9543,14 +9714,6 @@ async function registerJobFunctions(client, changeSet, appName, appId, unchanged
9543
9714
  }));
9544
9715
  for (const { jobName, version } of results) if (version) jobFunctionVersions[jobName] = version;
9545
9716
  }
9546
- const unusedJobFunctions = existingJobFunctions.filter((jobName) => !allUsedJobNames.has(jobName));
9547
- await Promise.all(unusedJobFunctions.map(async (jobName) => {
9548
- const { metadata } = await client.getMetadata({ trn: resourceTrn(workspaceId, "workflow_job_function", jobName) });
9549
- if (isOwnedByApp(metadata?.labels, appName, appId)) await client.setMetadata({
9550
- trn: resourceTrn(workspaceId, "workflow_job_function", jobName),
9551
- labels: { [sdkNameLabelKey]: "" }
9552
- });
9553
- }));
9554
9717
  return jobFunctionVersions;
9555
9718
  }
9556
9719
  function parseDurationToProto(duration) {
@@ -9574,6 +9737,21 @@ function toConcurrencyPolicy(policy) {
9574
9737
  return { maxConcurrentExecutions: policy.maxConcurrentExecutions };
9575
9738
  }
9576
9739
  /**
9740
+ * Build the plan-time validation init shape for a workflow.
9741
+ * @param workspaceId - Workspace ID
9742
+ * @param workflow - Parsed workflow object
9743
+ * @returns Init shape suitable for validating against CreateWorkflowRequestSchema and UpdateWorkflowRequestSchema
9744
+ */
9745
+ function buildWorkflowValidationShape(workspaceId, workflow) {
9746
+ return {
9747
+ workspaceId,
9748
+ workflowName: workflow.name,
9749
+ mainJobFunctionName: workflow.mainJob.name,
9750
+ ...workflow.retryPolicy && { retryPolicy: toRetryPolicy(workflow.retryPolicy) },
9751
+ ...workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(workflow.concurrencyPolicy) }
9752
+ };
9753
+ }
9754
+ /**
9577
9755
  * Plan workflow changes and job functions based on current and desired state.
9578
9756
  * @param client - Operator client instance
9579
9757
  * @param workspaceId - Workspace ID
@@ -9590,6 +9768,7 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
9590
9768
  const unmanaged = [];
9591
9769
  const resourceOwners = /* @__PURE__ */ new Set();
9592
9770
  const unchangedWorkflowJobNames = /* @__PURE__ */ new Set();
9771
+ const retainedWorkflowJobNames = /* @__PURE__ */ new Set();
9593
9772
  const existingWorkflows = await fetchExistingResourcesWithLabels({
9594
9773
  client,
9595
9774
  workspaceId,
@@ -9613,6 +9792,7 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
9613
9792
  });
9614
9793
  const usedJobNames = mainJobDeps[workflow.mainJob.name];
9615
9794
  if (!usedJobNames) throw new Error(`Job "${workflow.mainJob.name}" (mainJob of workflow "${workflow.name}") was not found.\n\nPossible causes:\n - The job is not exported as a named export\n - The file containing the job is not included in workflow.files glob pattern\n\nSolution:\n export const ${workflow.mainJob.name} = createWorkflowJob({ name: "${workflow.mainJob.name}", ... })`);
9795
+ usedJobNames.forEach((jobName) => retainedWorkflowJobNames.add(jobName));
9616
9796
  if (existing) {
9617
9797
  if (trackDesiredResourceOwnership({
9618
9798
  labels: existing.allLabels,
@@ -9642,20 +9822,37 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
9642
9822
  metaRequest
9643
9823
  });
9644
9824
  }
9825
+ const deleteWorkflows = [];
9645
9826
  Object.values(existingWorkflows).forEach((existing) => {
9646
9827
  if (!existing) return;
9647
- if (trackRemainingResourceOwner({
9828
+ const owned = trackRemainingResourceOwner({
9648
9829
  labels: existing.allLabels,
9649
9830
  ownerLabel: existing.label,
9650
9831
  appName,
9651
9832
  appId,
9652
9833
  resourceOwners
9653
- })) changeSet.deletes.push({
9834
+ });
9835
+ const usedJobNames = getExistingWorkflowJobNames(existing.resource);
9836
+ if (owned) deleteWorkflows.push({
9654
9837
  name: existing.resource.name,
9655
9838
  workspaceId,
9656
9839
  workflowId: existing.resource.id,
9657
- usedJobNames: getExistingWorkflowJobNames(existing.resource)
9840
+ usedJobNames,
9841
+ deletableJobNames: []
9658
9842
  });
9843
+ else usedJobNames.forEach((jobName) => retainedWorkflowJobNames.add(jobName));
9844
+ });
9845
+ const jobFunctionDeletes = await planWorkflowJobFunctionDeletes({
9846
+ client,
9847
+ workspaceId,
9848
+ appName,
9849
+ appId,
9850
+ retainedWorkflowJobNames
9851
+ });
9852
+ const deletableJobNames = new Set(jobFunctionDeletes.map((del) => del.jobFunctionName));
9853
+ for (const del of deleteWorkflows) changeSet.deletes.push({
9854
+ ...del,
9855
+ deletableJobNames: del.usedJobNames.filter((jobName) => !retainedWorkflowJobNames.has(jobName) && deletableJobNames.has(jobName))
9659
9856
  });
9660
9857
  return {
9661
9858
  changeSet,
@@ -9664,9 +9861,29 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
9664
9861
  resourceOwners,
9665
9862
  appName,
9666
9863
  appId,
9667
- unchangedWorkflowJobNames
9864
+ unchangedWorkflowJobNames,
9865
+ jobFunctionDeletes
9668
9866
  };
9669
9867
  }
9868
+ async function planWorkflowJobFunctionDeletes(params) {
9869
+ const { client, workspaceId, appName, appId, retainedWorkflowJobNames } = params;
9870
+ const existingJobFunctions = await fetchAll(async (pageToken, maxPageSize) => {
9871
+ const response = await client.listWorkflowJobFunctions({
9872
+ workspaceId,
9873
+ pageToken,
9874
+ pageSize: maxPageSize
9875
+ });
9876
+ return [response.jobFunctions.map((jobFunction) => jobFunction.name), response.nextPageToken];
9877
+ });
9878
+ const candidates = [...new Set(existingJobFunctions)].filter((jobName) => !retainedWorkflowJobNames.has(jobName));
9879
+ return (await Promise.all(candidates.map(async (jobFunctionName) => {
9880
+ const { metadata } = await client.getMetadata({ trn: resourceTrn(workspaceId, "workflow_job_function", jobFunctionName) });
9881
+ return isOwnedByApp(metadata?.labels, appName, appId) ? {
9882
+ workspaceId,
9883
+ jobFunctionName
9884
+ } : void 0;
9885
+ }))).filter((item) => item !== void 0);
9886
+ }
9670
9887
  /**
9671
9888
  * Format workflow changes for grouped dry-run display.
9672
9889
  * @param changeSet - Workflow changes
@@ -9734,6 +9951,191 @@ function normalizeRetryPolicyForCompare(policy) {
9734
9951
  };
9735
9952
  }
9736
9953
 
9954
+ //#endregion
9955
+ //#region src/cli/commands/deploy/validate-plan.ts
9956
+ function validateItems(params) {
9957
+ const { validator, schema, kind, action, items, requestKey, violations } = params;
9958
+ for (const item of items) {
9959
+ const init = item[requestKey];
9960
+ const msg = create(schema, init);
9961
+ const result = validator.validate(schema, msg);
9962
+ if (result.kind === "invalid") for (const v of result.violations) violations.push({
9963
+ kind,
9964
+ name: item.name,
9965
+ action,
9966
+ fieldPath: v.field.length > 0 ? pathToString(v.field) : "(message)",
9967
+ message: v.message
9968
+ });
9969
+ else if (result.kind === "error") logger.warn(`Could not validate ${kind} "${item.name}" (${action}): ${result.error.message}`);
9970
+ }
9971
+ }
9972
+ /**
9973
+ * Validate all plan-time create/update requests against buf.validate constraints embedded in the
9974
+ * generated proto descriptors.
9975
+ *
9976
+ * Collections not validated: idp client, tailorDB gqlPermission, functionRegistry — no
9977
+ * buf.validate annotations.
9978
+ * Application cors is excluded: static-website URL placeholders are resolved at apply time
9979
+ * and a bare cors array carries no constraint that would false-positive when omitted.
9980
+ * Workflow jobFunctions map excluded: versions are registered at apply time (registerJobFunctions)
9981
+ * and the map field carries no min_items constraint. Job names are validated separately via
9982
+ * CreateWorkflowJobFunctionRequestSchema using usedJobNames from the workflow change set.
9983
+ * auth idpConfig.config (provider oneof) is absent at plan time for BuiltInIdP but carries no
9984
+ * required constraint — the request is validated as-is from the changeset.
9985
+ *
9986
+ * @param input - Plan results from the plan phase
9987
+ */
9988
+ async function validatePlan(input) {
9989
+ const { tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager } = input;
9990
+ const validator = createValidator();
9991
+ const violations = [];
9992
+ function creates(schema, kind, items) {
9993
+ validateItems({
9994
+ validator,
9995
+ schema,
9996
+ kind,
9997
+ action: "create",
9998
+ items,
9999
+ requestKey: "request",
10000
+ violations
10001
+ });
10002
+ }
10003
+ function updates(schema, kind, items) {
10004
+ validateItems({
10005
+ validator,
10006
+ schema,
10007
+ kind,
10008
+ action: "update",
10009
+ items,
10010
+ requestKey: "request",
10011
+ violations
10012
+ });
10013
+ }
10014
+ function replaces(schema, kind, items) {
10015
+ validateItems({
10016
+ validator,
10017
+ schema,
10018
+ kind,
10019
+ action: "replace",
10020
+ items,
10021
+ requestKey: "createRequest",
10022
+ violations
10023
+ });
10024
+ }
10025
+ creates(CreateTailorDBServiceRequestSchema, "TailorDB service", tailorDB.changeSet.service.creates);
10026
+ creates(CreateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.creates);
10027
+ updates(UpdateTailorDBTypeRequestSchema, "TailorDB type", tailorDB.changeSet.type.updates);
10028
+ creates(CreateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.creates);
10029
+ updates(UpdateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.updates);
10030
+ creates(AddCustomDomainRequestSchema, "StaticWebsite custom domain", staticWebsite.customDomainChangeSet.creates);
10031
+ creates(CreateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.creates);
10032
+ updates(UpdateIdPServiceRequestSchema, "IdP service", idp.changeSet.service.updates);
10033
+ const idpClientVaultItems = [...idp.changeSet.client.creates.map((c) => ({
10034
+ clientName: c.request.client?.name ?? "",
10035
+ namespaceName: c.request.namespaceName ?? "",
10036
+ workspaceId: c.request.workspaceId ?? ""
10037
+ })), ...idp.changeSet.client.updates.map((u) => ({
10038
+ clientName: u.name,
10039
+ namespaceName: u.namespaceName,
10040
+ workspaceId: u.workspaceId
10041
+ }))];
10042
+ creates(CreateSecretManagerVaultRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
10043
+ name: item.clientName,
10044
+ request: {
10045
+ workspaceId: item.workspaceId,
10046
+ secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName)
10047
+ }
10048
+ })));
10049
+ creates(CreateSecretManagerSecretRequestSchema, "IdP client secret", idpClientVaultItems.map((item) => ({
10050
+ name: item.clientName,
10051
+ request: {
10052
+ workspaceId: item.workspaceId,
10053
+ secretmanagerVaultName: idpClientVaultName(item.namespaceName, item.clientName),
10054
+ secretmanagerSecretName: idpClientSecretName(item.namespaceName, item.clientName)
10055
+ }
10056
+ })));
10057
+ creates(CreateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.creates);
10058
+ updates(UpdateAuthServiceRequestSchema, "Auth service", auth.changeSet.service.updates);
10059
+ creates(CreateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.creates);
10060
+ updates(UpdateAuthIDPConfigRequestSchema, "Auth IDP config", auth.changeSet.idpConfig.updates);
10061
+ creates(CreateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.creates);
10062
+ updates(UpdateUserProfileConfigRequestSchema, "Auth user profile config", auth.changeSet.userProfileConfig.updates);
10063
+ creates(CreateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.creates);
10064
+ updates(UpdateTenantConfigRequestSchema, "Auth tenant config", auth.changeSet.tenantConfig.updates);
10065
+ creates(CreateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.creates);
10066
+ updates(UpdateAuthMachineUserRequestSchema, "Auth machine user", auth.changeSet.machineUser.updates);
10067
+ creates(CreateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.creates);
10068
+ updates(UpdateAuthHookRequestSchema, "Auth hook", auth.changeSet.authHook.updates);
10069
+ creates(CreateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.creates);
10070
+ updates(UpdateAuthSCIMConfigRequestSchema, "Auth SCIM config", auth.changeSet.scim.updates);
10071
+ creates(CreateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.creates);
10072
+ updates(UpdateAuthSCIMResourceRequestSchema, "Auth SCIM resource", auth.changeSet.scimResource.updates);
10073
+ creates(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.creates);
10074
+ updates(UpdateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.updates);
10075
+ replaces(CreateAuthOAuth2ClientRequestSchema, "OAuth2 client", auth.changeSet.oauth2Client.replaces);
10076
+ creates(CreatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.creates);
10077
+ updates(UpdatePipelineServiceRequestSchema, "Pipeline service", pipeline.changeSet.service.updates);
10078
+ creates(CreatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.creates);
10079
+ updates(UpdatePipelineResolverRequestSchema, "Resolver", pipeline.changeSet.resolver.updates);
10080
+ creates(CreateExecutorExecutorRequestSchema, "Executor", executor.changeSet.creates);
10081
+ updates(UpdateExecutorExecutorRequestSchema, "Executor", executor.changeSet.updates);
10082
+ creates(CreateWorkflowRequestSchema, "Workflow", workflow.changeSet.creates.map((item) => ({
10083
+ name: item.name,
10084
+ request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
10085
+ })));
10086
+ updates(UpdateWorkflowRequestSchema, "Workflow", workflow.changeSet.updates.map((item) => ({
10087
+ name: item.name,
10088
+ request: buildWorkflowValidationShape(item.workspaceId, item.workflow)
10089
+ })));
10090
+ const workflowJobNameWorkspaceId = workflow.changeSet.creates[0]?.workspaceId ?? workflow.changeSet.updates[0]?.workspaceId ?? "";
10091
+ if (workflowJobNameWorkspaceId) {
10092
+ const allJobNames = /* @__PURE__ */ new Set();
10093
+ for (const item of [...workflow.changeSet.creates, ...workflow.changeSet.updates]) for (const jobName of item.usedJobNames) allJobNames.add(jobName);
10094
+ for (const jobName of workflow.unchangedWorkflowJobNames) allJobNames.add(jobName);
10095
+ creates(CreateWorkflowJobFunctionRequestSchema, "Workflow job function", [...allJobNames].map((jobName) => ({
10096
+ name: jobName,
10097
+ request: {
10098
+ workspaceId: workflowJobNameWorkspaceId,
10099
+ jobFunctionName: jobName,
10100
+ scriptRef: jobName
10101
+ }
10102
+ })));
10103
+ }
10104
+ creates(CreateSecretManagerVaultRequestSchema, "Secret Manager vault", secretManager.vaultChangeSet.creates.map((item) => ({
10105
+ name: item.name,
10106
+ request: vaultCreateRequest(item)
10107
+ })));
10108
+ creates(CreateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.creates.map((item) => ({
10109
+ name: item.name,
10110
+ request: secretCreateRequest(item)
10111
+ })));
10112
+ updates(UpdateSecretManagerSecretRequestSchema, "Secret Manager secret", secretManager.secretChangeSet.updates.map((item) => ({
10113
+ name: item.name,
10114
+ request: secretUpdateRequest(item)
10115
+ })));
10116
+ creates(CreateApplicationRequestSchema, "Application", app.creates.map((item) => ({
10117
+ name: item.name,
10118
+ request: {
10119
+ ...item.request,
10120
+ cors: void 0
10121
+ }
10122
+ })));
10123
+ updates(UpdateApplicationRequestSchema, "Application", [...app.updates, ...app.unchanged].map((item) => ({
10124
+ name: item.name,
10125
+ request: {
10126
+ ...item.request,
10127
+ cors: void 0
10128
+ }
10129
+ })));
10130
+ creates(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.creates);
10131
+ replaces(CreateAuthConnectionRequestSchema, "Auth connection", auth.changeSet.connection.replaces);
10132
+ if (violations.length === 0) return;
10133
+ const resourceNames = new Set(violations.map((v) => `${v.kind}:${v.name}`));
10134
+ logger.error(`Pre-flight validation found ${violations.length} violation(s) across ${resourceNames.size} resource(s):`);
10135
+ for (const v of violations) logger.log(` ${styles.resourceType(v.kind)} ${styles.resourceName(v.name)} (${v.action}) — ${styles.bold(v.fieldPath)}: ${v.message}`);
10136
+ throw new Error(`${violations.length} validation error(s) found in ${resourceNames.size} resource(s)`);
10137
+ }
10138
+
9737
10139
  //#endregion
9738
10140
  //#region src/cli/commands/deploy/deploy.ts
9739
10141
  /**
@@ -9751,7 +10153,10 @@ function collectIdpUserTriggerTargets(application) {
9751
10153
  for (const executor of Object.values(application.executorService?.executors ?? {})) {
9752
10154
  if (executor.trigger.kind !== "idpUser") continue;
9753
10155
  if (executor.trigger.idp != null) targets.add(executor.trigger.idp);
9754
- else if (idps.length === 1) targets.add(idps[0].name);
10156
+ else if (idps.length === 1) {
10157
+ const [idp] = idps;
10158
+ if (idp) targets.add(idp.name);
10159
+ }
9755
10160
  }
9756
10161
  return targets;
9757
10162
  }
@@ -9834,7 +10239,7 @@ function printPlanResults(results) {
9834
10239
  ...formatChangeSetEntries(results.auth.changeSet.oauth2Client, ["oauth2Client"], namespaceOf),
9835
10240
  ...formatChangeSetEntries(results.auth.changeSet.scim, ["scimConfig"], namespaceOf),
9836
10241
  ...formatChangeSetEntries(results.auth.changeSet.scimResource, ["scimResource"], namespaceOf),
9837
- ...results.auth.changeSet.connection ? formatChangeSetEntries(results.auth.changeSet.connection, ["connection"], namespaceOf) : []
10242
+ ...formatChangeSetEntries(results.auth.changeSet.connection, ["connection"], namespaceOf)
9838
10243
  ];
9839
10244
  const { otherChanges: otherFunctionRegistryChanges } = splitFunctionRegistryChanges(results.functionRegistry.changeSet);
9840
10245
  printGroupedDisplaySection(results.functionRegistry.changeSet.title, formatChangeSetEntries(otherFunctionRegistryChanges));
@@ -9976,10 +10381,7 @@ async function deploy(options) {
9976
10381
  };
9977
10382
  });
9978
10383
  if (buildOnly) return { bundledScripts };
9979
- const client = await initOperatorClient(await loadAccessToken({
9980
- useProfile: true,
9981
- profile: options?.profile
9982
- }));
10384
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
9983
10385
  const workspaceId = await loadWorkspaceId({
9984
10386
  workspaceId: options?.workspaceId,
9985
10387
  profile: options?.profile
@@ -10124,6 +10526,19 @@ async function deploy(options) {
10124
10526
  workflow,
10125
10527
  secretManager
10126
10528
  });
10529
+ if (options?.noValidate) logger.warn("Client-side validation skipped (--no-validate).");
10530
+ else await validatePlan({
10531
+ functionRegistry,
10532
+ tailorDB,
10533
+ staticWebsite,
10534
+ idp,
10535
+ auth,
10536
+ pipeline,
10537
+ app,
10538
+ executor,
10539
+ workflow,
10540
+ secretManager
10541
+ });
10127
10542
  if (dryRun) {
10128
10543
  logger.info("Dry run enabled. No changes applied.");
10129
10544
  return;
@@ -10486,10 +10901,7 @@ async function resolveExecutor(client, workspaceId, name) {
10486
10901
  }
10487
10902
  async function getExecutor(options) {
10488
10903
  const name = "name" in options ? options.name : options.executor.name;
10489
- const client = await initOperatorClient(await loadAccessToken({
10490
- useProfile: true,
10491
- profile: options.profile
10492
- }));
10904
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
10493
10905
  const workspaceId = await loadWorkspaceId({
10494
10906
  workspaceId: options.workspaceId,
10495
10907
  profile: options.profile
@@ -10738,10 +11150,7 @@ function parseStatus(status) {
10738
11150
  }
10739
11151
  async function listWorkflowExecutions(options) {
10740
11152
  const workflowName = options && "workflowName" in options ? options.workflowName : options && "workflow" in options ? options.workflow?.name : void 0;
10741
- const client = await initOperatorClient(await loadAccessToken({
10742
- useProfile: true,
10743
- profile: options?.profile
10744
- }));
11153
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
10745
11154
  const workspaceId = await loadWorkspaceId({
10746
11155
  workspaceId: options?.workspaceId,
10747
11156
  profile: options?.profile
@@ -10778,10 +11187,7 @@ async function listWorkflowExecutions(options) {
10778
11187
  * @returns Workflow execution with optional logs
10779
11188
  */
10780
11189
  async function getWorkflowExecution(options) {
10781
- const client = await initOperatorClient(await loadAccessToken({
10782
- useProfile: true,
10783
- profile: options.profile
10784
- }));
11190
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
10785
11191
  const workspaceId = await loadWorkspaceId({
10786
11192
  workspaceId: options.workspaceId,
10787
11193
  profile: options.profile
@@ -10966,10 +11372,7 @@ async function resolveWorkflow(client, workspaceId, name) {
10966
11372
  }
10967
11373
  async function getWorkflow(options) {
10968
11374
  const name = "name" in options ? options.name : options.workflow.name;
10969
- const client = await initOperatorClient(await loadAccessToken({
10970
- useProfile: true,
10971
- profile: options.profile
10972
- }));
11375
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
10973
11376
  const workspaceId = await loadWorkspaceId({
10974
11377
  workspaceId: options.workspaceId,
10975
11378
  profile: options.profile
@@ -11113,10 +11516,7 @@ async function startWorkflowCore(options) {
11113
11516
  }
11114
11517
  }
11115
11518
  async function startWorkflowByName(options) {
11116
- const client = await initOperatorClient(await loadAccessToken({
11117
- useProfile: true,
11118
- profile: options.profile
11119
- }));
11519
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
11120
11520
  const workspaceId = await loadWorkspaceId({
11121
11521
  workspaceId: options.workspaceId,
11122
11522
  profile: options.profile
@@ -11142,10 +11542,7 @@ async function startWorkflowByName(options) {
11142
11542
  async function startWorkflow(options) {
11143
11543
  if ("name" in options) return await startWorkflowByName(options);
11144
11544
  return await startWorkflowCore({
11145
- client: await initOperatorClient(await loadAccessToken({
11146
- useProfile: true,
11147
- profile: options.profile
11148
- })),
11545
+ client: await initOperatorClient(await loadAccessToken({ profile: options.profile })),
11149
11546
  workspaceId: await loadWorkspaceId({
11150
11547
  workspaceId: options.workspaceId,
11151
11548
  profile: options.profile
@@ -11208,10 +11605,7 @@ function formatTime(date) {
11208
11605
  }
11209
11606
  async function listExecutorJobs(options) {
11210
11607
  const executorName = "executorName" in options ? options.executorName : options.executor.name;
11211
- const client = await initOperatorClient(await loadAccessToken({
11212
- useProfile: true,
11213
- profile: options.profile
11214
- }));
11608
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
11215
11609
  const workspaceId = await loadWorkspaceId({
11216
11610
  workspaceId: options.workspaceId,
11217
11611
  profile: options.profile
@@ -11249,10 +11643,7 @@ async function listExecutorJobs(options) {
11249
11643
  }
11250
11644
  async function getExecutorJob(options) {
11251
11645
  const executorName = "executorName" in options ? options.executorName : options.executor.name;
11252
- const client = await initOperatorClient(await loadAccessToken({
11253
- useProfile: true,
11254
- profile: options.profile
11255
- }));
11646
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
11256
11647
  const workspaceId = await loadWorkspaceId({
11257
11648
  workspaceId: options.workspaceId,
11258
11649
  profile: options.profile
@@ -11289,10 +11680,7 @@ async function getExecutorJob(options) {
11289
11680
  }
11290
11681
  async function watchExecutorJob(options) {
11291
11682
  const executorName = "executorName" in options ? options.executorName : options.executor.name;
11292
- const client = await initOperatorClient(await loadAccessToken({
11293
- useProfile: true,
11294
- profile: options.profile
11295
- }));
11683
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
11296
11684
  const workspaceId = await loadWorkspaceId({
11297
11685
  workspaceId: options.workspaceId,
11298
11686
  profile: options.profile
@@ -11592,10 +11980,7 @@ const jobsCommand = defineAppCommand({
11592
11980
  * @returns List of executors
11593
11981
  */
11594
11982
  async function listExecutors(options) {
11595
- const client = await initOperatorClient(await loadAccessToken({
11596
- useProfile: true,
11597
- profile: options?.profile
11598
- }));
11983
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
11599
11984
  const workspaceId = await loadWorkspaceId({
11600
11985
  workspaceId: options?.workspaceId,
11601
11986
  profile: options?.profile
@@ -11668,10 +12053,7 @@ const headerArg = z.string().superRefine((val, ctx) => {
11668
12053
  };
11669
12054
  }).refine((h) => h.key.length > 0, { message: "Header name cannot be empty" });
11670
12055
  async function triggerExecutorByName(options) {
11671
- const client = await initOperatorClient(await loadAccessToken({
11672
- useProfile: true,
11673
- profile: options.profile
11674
- }));
12056
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
11675
12057
  const workspaceId = await loadWorkspaceId({
11676
12058
  workspaceId: options.workspaceId,
11677
12059
  profile: options.profile
@@ -11767,10 +12149,7 @@ The \`--logs\` option displays logs from the downstream execution when available
11767
12149
  }).strict(),
11768
12150
  run: async (args) => {
11769
12151
  await assertWritable({ profile: args.profile });
11770
- const client = await initOperatorClient(await loadAccessToken({
11771
- useProfile: true,
11772
- profile: args.profile
11773
- }));
12152
+ const client = await initOperatorClient(await loadAccessToken({ profile: args.profile }));
11774
12153
  const workspaceId = await loadWorkspaceId({
11775
12154
  workspaceId: args["workspace-id"],
11776
12155
  profile: args.profile
@@ -11858,10 +12237,7 @@ The \`--logs\` option displays logs from the downstream execution when available
11858
12237
  * @returns List of webhook executors with URLs
11859
12238
  */
11860
12239
  async function listWebhookExecutors(options) {
11861
- const client = await initOperatorClient(await loadAccessToken({
11862
- useProfile: true,
11863
- profile: options?.profile
11864
- }));
12240
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
11865
12241
  const workspaceId = await loadWorkspaceId({
11866
12242
  workspaceId: options?.workspaceId,
11867
12243
  profile: options?.profile
@@ -11936,12 +12312,9 @@ const getFunctionRegistryOptionsSchema = z.object({
11936
12312
  });
11937
12313
  async function loadOptions$12(options) {
11938
12314
  const result = getFunctionRegistryOptionsSchema.safeParse(options);
11939
- if (!result.success) throw new Error(result.error.issues[0].message);
12315
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
11940
12316
  return {
11941
- client: await initOperatorClient(await loadAccessToken({
11942
- useProfile: true,
11943
- profile: result.data.profile
11944
- })),
12317
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
11945
12318
  workspaceId: await loadWorkspaceId({
11946
12319
  workspaceId: result.data.workspaceId,
11947
12320
  profile: result.data.profile
@@ -12004,12 +12377,9 @@ const listFunctionRegistriesOptionsSchema = z.object({
12004
12377
  });
12005
12378
  async function loadOptions$11(options) {
12006
12379
  const result = listFunctionRegistriesOptionsSchema.safeParse(options);
12007
- if (!result.success) throw new Error(result.error.issues[0].message);
12380
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
12008
12381
  return {
12009
- client: await initOperatorClient(await loadAccessToken({
12010
- useProfile: true,
12011
- profile: result.data.profile
12012
- })),
12382
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
12013
12383
  workspaceId: await loadWorkspaceId({
12014
12384
  workspaceId: result.data.workspaceId,
12015
12385
  profile: result.data.profile
@@ -12504,13 +12874,13 @@ function createGenerationManager(params) {
12504
12874
  };
12505
12875
  }
12506
12876
  async function processTailorDBNamespace(gen, namespace, typeInfo) {
12507
- const results = generatorResults[gen.id];
12877
+ const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
12508
12878
  results.tailordbResults[namespace] = {};
12509
12879
  if (!gen.processType) return;
12510
12880
  const processType = gen.processType;
12511
12881
  await Promise.allSettled(Object.entries(typeInfo.types).map(async ([typeName, type]) => {
12512
12882
  try {
12513
- results.tailordbResults[namespace][typeName] = await processType({
12883
+ assertDefined(results.tailordbResults[namespace], `tailordb results not initialized for namespace ${namespace}`)[typeName] = await processType({
12514
12884
  type,
12515
12885
  namespace,
12516
12886
  source: typeInfo.sourceInfo[typeName],
@@ -12533,13 +12903,13 @@ function createGenerationManager(params) {
12533
12903
  else results.tailordbNamespaceResults[namespace] = results.tailordbResults[namespace];
12534
12904
  }
12535
12905
  async function processResolverNamespace(gen, namespace, resolvers) {
12536
- const results = generatorResults[gen.id];
12906
+ const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
12537
12907
  results.resolverResults[namespace] = {};
12538
12908
  if (!gen.processResolver) return;
12539
12909
  const processResolver = gen.processResolver;
12540
12910
  await Promise.allSettled(Object.entries(resolvers).map(async ([resolverName, resolver]) => {
12541
12911
  try {
12542
- results.resolverResults[namespace][resolverName] = await processResolver({
12912
+ assertDefined(results.resolverResults[namespace], `resolver results not initialized for namespace ${namespace}`)[resolverName] = await processResolver({
12543
12913
  resolver,
12544
12914
  namespace
12545
12915
  });
@@ -12560,7 +12930,7 @@ function createGenerationManager(params) {
12560
12930
  else results.resolverNamespaceResults[namespace] = results.resolverResults[namespace];
12561
12931
  }
12562
12932
  async function processExecutors(gen) {
12563
- const results = generatorResults[gen.id];
12933
+ const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
12564
12934
  if (!gen.processExecutor) return;
12565
12935
  const processExecutor = gen.processExecutor;
12566
12936
  await Promise.allSettled(Object.entries(services.executor).map(async ([executorId, executor]) => {
@@ -12573,7 +12943,7 @@ function createGenerationManager(params) {
12573
12943
  }));
12574
12944
  }
12575
12945
  async function aggregate(gen) {
12576
- const results = generatorResults[gen.id];
12946
+ const results = assertDefined(generatorResults[gen.id], `generator result not initialized for ${gen.id}`);
12577
12947
  const tailordbResults = [];
12578
12948
  const resolverResults = [];
12579
12949
  for (const [namespace, types] of Object.entries(results.tailordbNamespaceResults)) tailordbResults.push({
@@ -12631,7 +13001,7 @@ function createGenerationManager(params) {
12631
13001
  let result;
12632
13002
  switch (hookName) {
12633
13003
  case "onTailorDBReady":
12634
- result = await plugin.onTailorDBReady({
13004
+ result = await assertDefined(plugin.onTailorDBReady, "plugin.onTailorDBReady hook missing")({
12635
13005
  tailordb,
12636
13006
  auth,
12637
13007
  baseDir: pluginBaseDir,
@@ -12640,7 +13010,7 @@ function createGenerationManager(params) {
12640
13010
  });
12641
13011
  break;
12642
13012
  case "onResolverReady":
12643
- result = await plugin.onResolverReady({
13013
+ result = await assertDefined(plugin.onResolverReady, "plugin.onResolverReady hook missing")({
12644
13014
  tailordb,
12645
13015
  resolvers: buildResolverData(),
12646
13016
  auth,
@@ -12650,7 +13020,7 @@ function createGenerationManager(params) {
12650
13020
  });
12651
13021
  break;
12652
13022
  case "onExecutorReady":
12653
- result = await plugin.onExecutorReady({
13023
+ result = await assertDefined(plugin.onExecutorReady, "plugin.onExecutorReady hook missing")({
12654
13024
  tailordb,
12655
13025
  resolvers: buildResolverData(),
12656
13026
  executors: { ...services.executor },
@@ -12764,7 +13134,7 @@ function createGenerationManager(params) {
12764
13134
  ...process.env,
12765
13135
  TAILOR_WATCH_GENERATION: (parseInt(process.env.TAILOR_WATCH_GENERATION || "0", 10) + 1).toString()
12766
13136
  };
12767
- const child = spawn(process.argv[0], [process.argv[1], ...args], {
13137
+ const child = spawn(assertDefined(process.argv[0], "argv[0] missing"), [assertDefined(process.argv[1], "argv[1] missing"), ...args], {
12768
13138
  stdio: "inherit",
12769
13139
  env,
12770
13140
  detached: false
@@ -12828,7 +13198,10 @@ function createGenerationManager(params) {
12828
13198
  executorService: app.executorService ?? (pluginExecutorFiles.length > 0 ? createExecutorService({ config: { files: [] } }) : void 0)
12829
13199
  };
12830
13200
  });
12831
- if (app.authService) await withSpan("generate.resolveAuthNamespaces", async () => app.authService.resolveNamespaces());
13201
+ if (app.authService) {
13202
+ const authService = app.authService;
13203
+ await withSpan("generate.resolveAuthNamespaces", async () => authService.resolveNamespaces());
13204
+ }
12832
13205
  if (app.tailorDBServices.length > 0 || pluginExecutorFiles.length > 0) logger.newline();
12833
13206
  const readyAfterTailorDB = getReadyGenerators("tailordb");
12834
13207
  const hasOnTailorDBReady = generationPlugins.some((p) => p.onTailorDBReady != null);
@@ -12844,9 +13217,10 @@ function createGenerationManager(params) {
12844
13217
  await withSpan(`generate.loadResolvers.${namespace}`, async () => {
12845
13218
  try {
12846
13219
  await resolverService.loadResolvers();
12847
- services.resolver[namespace] = {};
13220
+ const namespaceResolvers = {};
13221
+ services.resolver[namespace] = namespaceResolvers;
12848
13222
  Object.entries(resolverService.resolvers).forEach(([_, resolver]) => {
12849
- services.resolver[namespace][resolver.name] = resolver;
13223
+ namespaceResolvers[resolver.name] = resolver;
12850
13224
  });
12851
13225
  } catch (error) {
12852
13226
  logger.error(`Error loading resolvers for Resolver service ${styles.bold(namespace)}`);
@@ -12892,11 +13266,11 @@ function createGenerationManager(params) {
12892
13266
  const app = application;
12893
13267
  for (const db of app.tailorDBServices) {
12894
13268
  const dbNamespace = db.namespace;
12895
- await watcher?.addWatchGroup(`TailorDB/${dbNamespace}`, db.config.files);
13269
+ await watcher.addWatchGroup(`TailorDB/${dbNamespace}`, db.config.files);
12896
13270
  }
12897
13271
  for (const resolverService of app.resolverServices) {
12898
13272
  const resolverNamespace = resolverService.namespace;
12899
- await watcher?.addWatchGroup(`Resolver/${resolverNamespace}`, resolverService["config"].files);
13273
+ await watcher.addWatchGroup(`Resolver/${resolverNamespace}`, resolverService["config"].files);
12900
13274
  }
12901
13275
  await new Promise(() => {});
12902
13276
  }
@@ -12960,10 +13334,7 @@ function machineUserInfo(user) {
12960
13334
  * @returns List of machine users
12961
13335
  */
12962
13336
  async function listMachineUsers(options) {
12963
- const client = await initOperatorClient(await loadAccessToken({
12964
- useProfile: true,
12965
- profile: options?.profile
12966
- }));
13337
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
12967
13338
  const workspaceId = await loadWorkspaceId({
12968
13339
  workspaceId: options?.workspaceId,
12969
13340
  profile: options?.profile
@@ -13016,10 +13387,7 @@ const listCommand$7 = defineAppCommand({
13016
13387
  * @returns Machine user token info
13017
13388
  */
13018
13389
  async function getMachineUserToken(options) {
13019
- const client = await initOperatorClient(await loadAccessToken({
13020
- useProfile: true,
13021
- profile: options.profile
13022
- }));
13390
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
13023
13391
  const workspaceId = await loadWorkspaceId({
13024
13392
  workspaceId: options.workspaceId,
13025
13393
  profile: options.profile
@@ -13120,10 +13488,7 @@ function toOAuth2ClientCredentials(client) {
13120
13488
  * @returns OAuth2 client credentials
13121
13489
  */
13122
13490
  async function getOAuth2Client(options) {
13123
- const client = await initOperatorClient(await loadAccessToken({
13124
- useProfile: true,
13125
- profile: options.profile
13126
- }));
13491
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
13127
13492
  const workspaceId = await loadWorkspaceId({
13128
13493
  workspaceId: options.workspaceId,
13129
13494
  profile: options.profile
@@ -13140,7 +13505,7 @@ async function getOAuth2Client(options) {
13140
13505
  namespaceName: application.authNamespace,
13141
13506
  name: options.name
13142
13507
  });
13143
- return toOAuth2ClientCredentials(oauth2Client);
13508
+ return toOAuth2ClientCredentials(assertDefined(oauth2Client, "oauth2Client missing in response"));
13144
13509
  } catch (error) {
13145
13510
  if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`OAuth2 client '${options.name}' not found.`, { cause: error });
13146
13511
  throw error;
@@ -13175,10 +13540,7 @@ const getCommand$3 = defineAppCommand({
13175
13540
  * @returns List of OAuth2 clients
13176
13541
  */
13177
13542
  async function listOAuth2Clients(options) {
13178
- const client = await initOperatorClient(await loadAccessToken({
13179
- useProfile: true,
13180
- profile: options?.profile
13181
- }));
13543
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
13182
13544
  const workspaceId = await loadWorkspaceId({
13183
13545
  workspaceId: options?.workspaceId,
13184
13546
  profile: options?.profile
@@ -13262,7 +13624,7 @@ const createFolderOptionsSchema = z.object({
13262
13624
  */
13263
13625
  async function createFolder(options) {
13264
13626
  const result = createFolderOptionsSchema.safeParse(options);
13265
- if (!result.success) throw new Error(result.error.issues[0].message);
13627
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
13266
13628
  const response = await (await initOperatorClient(await loadAccessToken())).createOrganizationFolder({
13267
13629
  organizationId: result.data.organizationId,
13268
13630
  parentFolderId: result.data.parentFolderId ?? "",
@@ -13307,7 +13669,7 @@ const deleteFolderOptionsSchema = z.object({
13307
13669
  */
13308
13670
  async function deleteFolder(options) {
13309
13671
  const result = deleteFolderOptionsSchema.safeParse(options);
13310
- if (!result.success) throw new Error(result.error.issues[0].message);
13672
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
13311
13673
  await (await initOperatorClient(await loadAccessToken())).deleteOrganizationFolder({
13312
13674
  organizationId: result.data.organizationId,
13313
13675
  folderId: result.data.folderId
@@ -13360,7 +13722,7 @@ const getFolderOptionsSchema = z.object({
13360
13722
  */
13361
13723
  async function getFolder(options) {
13362
13724
  const result = getFolderOptionsSchema.safeParse(options);
13363
- if (!result.success) throw new Error(result.error.issues[0].message);
13725
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
13364
13726
  const response = await (await initOperatorClient(await loadAccessToken())).getOrganizationFolder({
13365
13727
  organizationId: result.data.organizationId,
13366
13728
  folderId: result.data.folderId
@@ -13404,7 +13766,7 @@ const listFoldersOptionsSchema = z.object({
13404
13766
  */
13405
13767
  async function listFolders(options) {
13406
13768
  const result = listFoldersOptionsSchema.safeParse(options);
13407
- if (!result.success) throw new Error(result.error.issues[0].message);
13769
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
13408
13770
  const { organizationId, parentFolderId, order, limit } = result.data;
13409
13771
  const client = await initOperatorClient(await loadAccessToken());
13410
13772
  const pageDirection = toPageDirection(order);
@@ -13452,7 +13814,7 @@ const updateFolderOptionsSchema = z.object({
13452
13814
  */
13453
13815
  async function updateFolder(options) {
13454
13816
  const result = updateFolderOptionsSchema.safeParse(options);
13455
- if (!result.success) throw new Error(result.error.issues[0].message);
13817
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
13456
13818
  const response = await (await initOperatorClient(await loadAccessToken())).updateOrganizationFolder({
13457
13819
  organizationId: result.data.organizationId,
13458
13820
  folderId: result.data.folderId,
@@ -13494,7 +13856,7 @@ const getOrganizationOptionsSchema = z.object({ organizationId: z.uuid({ message
13494
13856
  */
13495
13857
  async function getOrganization(options) {
13496
13858
  const result = getOrganizationOptionsSchema.safeParse(options);
13497
- if (!result.success) throw new Error(result.error.issues[0].message);
13859
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
13498
13860
  const response = await (await initOperatorClient(await loadAccessToken())).getOrganization({ organizationId: result.data.organizationId });
13499
13861
  if (!response.organization) throw new Error(`Organization "${result.data.organizationId}" not found.`);
13500
13862
  return organizationInfo(response.organization);
@@ -13588,12 +13950,12 @@ async function buildFolderTreeJson(client, organizationId, parentFolderId, curre
13588
13950
  }
13589
13951
  function renderTree(nodes, prefix) {
13590
13952
  let output = "";
13591
- for (let i = 0; i < nodes.length; i++) {
13953
+ for (const [i, node] of nodes.entries()) {
13592
13954
  const isLast = i === nodes.length - 1;
13593
13955
  const connector = isLast ? "└── " : "├── ";
13594
13956
  const childPrefix = isLast ? " " : "│ ";
13595
- output += `${prefix}${connector}${nodes[i].name}\n`;
13596
- if (nodes[i].children.length > 0) output += renderTree(nodes[i].children, prefix + childPrefix);
13957
+ output += `${prefix}${connector}${node.name}\n`;
13958
+ if (node.children.length > 0) output += renderTree(node.children, prefix + childPrefix);
13597
13959
  }
13598
13960
  return output;
13599
13961
  }
@@ -13680,7 +14042,7 @@ const updateOrganizationOptionsSchema = z.object({
13680
14042
  */
13681
14043
  async function updateOrganization(options) {
13682
14044
  const result = updateOrganizationOptionsSchema.safeParse(options);
13683
- if (!result.success) throw new Error(result.error.issues[0].message);
14045
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
13684
14046
  const response = await (await initOperatorClient(await loadAccessToken())).updateOrganization({
13685
14047
  organizationId: result.data.organizationId,
13686
14048
  organizationName: result.data.name
@@ -13712,10 +14074,7 @@ const updateCommand$1 = defineAppCommand({
13712
14074
  //#endregion
13713
14075
  //#region src/cli/commands/remove.ts
13714
14076
  async function loadOptions$10(options) {
13715
- const client = await initOperatorClient(await loadAccessToken({
13716
- useProfile: true,
13717
- profile: options?.profile
13718
- }));
14077
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
13719
14078
  const workspaceId = await loadWorkspaceId({
13720
14079
  workspaceId: options?.workspaceId,
13721
14080
  profile: options?.profile
@@ -13767,7 +14126,7 @@ async function execRemove(client, workspaceId, application, config, confirm) {
13767
14126
  auth.changeSet.authHook.print();
13768
14127
  auth.changeSet.scim.print();
13769
14128
  auth.changeSet.scimResource.print();
13770
- auth.changeSet.connection?.print();
14129
+ auth.changeSet.connection.print();
13771
14130
  secretManager.vaultChangeSet.print();
13772
14131
  secretManager.secretChangeSet.print();
13773
14132
  if (tailorDB.changeSet.service.deletes.length === 0 && staticWebsite.changeSet.deletes.length === 0 && idp.changeSet.service.deletes.length === 0 && auth.changeSet.service.deletes.length === 0 && pipeline.changeSet.service.deletes.length === 0 && app.deletes.length === 0 && executor.changeSet.deletes.length === 0 && workflow.changeSet.deletes.length === 0 && functionRegistry.changeSet.deletes.length === 0 && secretManager.vaultChangeSet.deletes.length === 0 && secretManager.secretChangeSet.deletes.length === 0) return;
@@ -13838,6 +14197,82 @@ function logBetaWarning(featureName) {
13838
14197
  logger.newline();
13839
14198
  }
13840
14199
 
14200
+ //#endregion
14201
+ //#region src/cli/commands/workspace/transform.ts
14202
+ const workspaceInfo = (workspace, folderName) => {
14203
+ const info = {
14204
+ id: workspace.id,
14205
+ name: workspace.name,
14206
+ region: workspace.region,
14207
+ createdAt: formatTimestamp(workspace.createTime),
14208
+ updatedAt: formatTimestamp(workspace.updateTime)
14209
+ };
14210
+ return folderName ? {
14211
+ ...info,
14212
+ folderName
14213
+ } : info;
14214
+ };
14215
+ const workspaceDetails = (workspace, folderName) => {
14216
+ return {
14217
+ ...workspaceInfo(workspace, folderName),
14218
+ deleteProtection: workspace.deleteProtection,
14219
+ organizationId: workspace.organizationId,
14220
+ folderId: workspace.folderId
14221
+ };
14222
+ };
14223
+ async function resolveWorkspaceFolderName(client, workspace) {
14224
+ if (!workspace.organizationId || !workspace.folderId) return void 0;
14225
+ try {
14226
+ return (await client.getOrganizationFolder({
14227
+ organizationId: workspace.organizationId,
14228
+ folderId: workspace.folderId
14229
+ })).folder?.name || void 0;
14230
+ } catch (error) {
14231
+ if (error instanceof ConnectError && (error.code === Code.NotFound || error.code === Code.PermissionDenied)) return;
14232
+ logger.warn(`Failed to resolve workspace folder name: ${error}`);
14233
+ return;
14234
+ }
14235
+ }
14236
+ function createWorkspaceFolderNameResolver(client) {
14237
+ const cache = /* @__PURE__ */ new Map();
14238
+ return (workspace) => {
14239
+ if (!workspace.organizationId || !workspace.folderId) return Promise.resolve(void 0);
14240
+ const cacheKey = `${workspace.organizationId}/${workspace.folderId}`;
14241
+ const cached = cache.get(cacheKey);
14242
+ if (cached) return cached;
14243
+ const promise = resolveWorkspaceFolderName(client, workspace);
14244
+ cache.set(cacheKey, promise);
14245
+ return promise;
14246
+ };
14247
+ }
14248
+ async function workspaceInfoWithFolderName(client, workspace) {
14249
+ return workspaceInfo(workspace, await resolveWorkspaceFolderName(client, workspace));
14250
+ }
14251
+ async function workspaceDetailsWithFolderName(client, workspace) {
14252
+ return workspaceDetails(workspace, await resolveWorkspaceFolderName(client, workspace));
14253
+ }
14254
+ async function workspaceInfosWithFolderNames(client, workspaces) {
14255
+ const resolveFolderName = createWorkspaceFolderNameResolver(client);
14256
+ const limit = pLimit(5);
14257
+ return Promise.all(workspaces.map((workspace) => limit(async () => workspaceInfo(workspace, await resolveFolderName(workspace)))));
14258
+ }
14259
+ function workspaceDisplayName(workspace) {
14260
+ return workspace.folderName ? `${workspace.folderName}/${workspace.name}` : workspace.name;
14261
+ }
14262
+ function createWorkspaceNameTransformer(nameKey, folderNameKey) {
14263
+ return (value, item) => {
14264
+ const workspace = item;
14265
+ const name = workspace[nameKey];
14266
+ const folderName = workspace[folderNameKey];
14267
+ if (typeof name === "string" && typeof folderName === "string") return workspaceDisplayName({
14268
+ name,
14269
+ folderName
14270
+ });
14271
+ return String(value ?? "");
14272
+ };
14273
+ }
14274
+ const workspaceNameTransformer = createWorkspaceNameTransformer("name", "folderName");
14275
+
13841
14276
  //#endregion
13842
14277
  //#region src/cli/commands/show.ts
13843
14278
  function applicationInfo(app) {
@@ -13859,10 +14294,7 @@ function applicationInfo(app) {
13859
14294
  * @returns Application information
13860
14295
  */
13861
14296
  async function show(options) {
13862
- const client = await initOperatorClient(await loadAccessToken({
13863
- useProfile: true,
13864
- profile: options?.profile
13865
- }));
14297
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
13866
14298
  const workspaceId = await loadWorkspaceId({
13867
14299
  workspaceId: options?.workspaceId,
13868
14300
  profile: options?.profile
@@ -13872,15 +14304,19 @@ async function show(options) {
13872
14304
  workspaceId,
13873
14305
  applicationName: config.name
13874
14306
  })]);
13875
- const { name, ...appInfo } = applicationInfo(resp.application);
14307
+ const { name, ...appInfo } = applicationInfo(assertDefined(resp.application, `application "${config.name}" not found in workspace`));
14308
+ const workspace = workspaceResp.workspace;
14309
+ const workspaceFolderName = workspace ? await resolveWorkspaceFolderName(client, workspace) : "";
13876
14310
  return {
13877
14311
  name,
13878
14312
  workspaceId,
13879
- workspaceName: workspaceResp.workspace?.name ?? "",
13880
- workspaceRegion: workspaceResp.workspace?.region ?? "",
14313
+ workspaceName: workspace?.name ?? "",
14314
+ ...workspaceFolderName ? { workspaceFolderName } : {},
14315
+ workspaceRegion: workspace?.region ?? "",
13881
14316
  ...appInfo
13882
14317
  };
13883
14318
  }
14319
+ const showWorkspaceNameTransformer = createWorkspaceNameTransformer("workspaceName", "workspaceFolderName");
13884
14320
  const showCommand = defineAppCommand({
13885
14321
  name: "show",
13886
14322
  description: "Show information about the deployed application.",
@@ -13891,7 +14327,10 @@ const showCommand = defineAppCommand({
13891
14327
  profile: args.profile,
13892
14328
  configPath: args.config
13893
14329
  });
13894
- logger.out(appInfo);
14330
+ logger.out(appInfo, { display: {
14331
+ workspaceName: showWorkspaceNameTransformer,
14332
+ workspaceFolderName: null
14333
+ } });
13895
14334
  }
13896
14335
  });
13897
14336
 
@@ -13980,7 +14419,7 @@ function extractBreakingChangeFields(diff) {
13980
14419
  const { before, after } = change;
13981
14420
  if (before && after && !before.required && after.required) {
13982
14421
  if (!optionalToRequired.has(change.typeName)) optionalToRequired.set(change.typeName, /* @__PURE__ */ new Set());
13983
- optionalToRequired.get(change.typeName).add(change.fieldName);
14422
+ assertDefined(optionalToRequired.get(change.typeName), "optionalToRequired entry missing").add(change.fieldName);
13984
14423
  }
13985
14424
  if (before && after && before.type === "enum" && after.type === "enum" && before.allowedValues && after.allowedValues) {
13986
14425
  const beforeValues = before.allowedValues.map((v) => v.value);
@@ -13989,7 +14428,7 @@ function extractBreakingChangeFields(diff) {
13989
14428
  const afterSet = new Set(afterValues);
13990
14429
  if (beforeValues.some((v) => !afterSet.has(v)) || afterValues.some((v) => !beforeSet.has(v))) {
13991
14430
  if (!enumValueChanges.has(change.typeName)) enumValueChanges.set(change.typeName, /* @__PURE__ */ new Map());
13992
- enumValueChanges.get(change.typeName).set(change.fieldName, {
14431
+ assertDefined(enumValueChanges.get(change.typeName), "enumValueChanges entry missing").set(change.fieldName, {
13993
14432
  beforeValues,
13994
14433
  afterValues
13995
14434
  });
@@ -13999,7 +14438,7 @@ function extractBreakingChangeFields(diff) {
13999
14438
  const { after } = change;
14000
14439
  if (after && after.required) {
14001
14440
  if (!addedRequiredFields.has(change.typeName)) addedRequiredFields.set(change.typeName, /* @__PURE__ */ new Map());
14002
- addedRequiredFields.get(change.typeName).set(change.fieldName, after);
14441
+ assertDefined(addedRequiredFields.get(change.typeName), "addedRequiredFields entry missing").set(change.fieldName, after);
14003
14442
  }
14004
14443
  }
14005
14444
  return {
@@ -14481,7 +14920,7 @@ async function generate(options) {
14481
14920
  if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
14482
14921
  let pluginManager;
14483
14922
  if (plugins.length > 0) pluginManager = new PluginManager(plugins);
14484
- const { defineApplication } = await import("./application-D4tRNn90.mjs");
14923
+ const { defineApplication } = await import("./application-DSXntqnV.mjs");
14485
14924
  const application = defineApplication({
14486
14925
  config,
14487
14926
  pluginManager
@@ -14652,7 +15091,7 @@ function extractAllNamespaces(config) {
14652
15091
  function extractOwnedNamespaces(config) {
14653
15092
  const namespaces = /* @__PURE__ */ new Set();
14654
15093
  if (config.db) for (const [namespaceName, nsConfig] of Object.entries(config.db)) {
14655
- if ("external" in nsConfig && nsConfig.external === true) continue;
15094
+ if ("external" in nsConfig) continue;
14656
15095
  namespaces.add(namespaceName);
14657
15096
  }
14658
15097
  return Array.from(namespaces);
@@ -14729,18 +15168,15 @@ async function truncate(options) {
14729
15168
  yes: true
14730
15169
  });
14731
15170
  }
14732
- async function $truncate(options) {
14733
- const client = await initOperatorClient(await loadAccessToken({
14734
- useProfile: true,
14735
- profile: options?.profile
14736
- }));
15171
+ async function $truncate(options = {}) {
15172
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
14737
15173
  const workspaceId = await loadWorkspaceId({
14738
- workspaceId: options?.workspaceId,
14739
- profile: options?.profile
15174
+ workspaceId: options.workspaceId,
15175
+ profile: options.profile
14740
15176
  });
14741
- const hasTypes = options?.types && options.types.length > 0;
14742
- const hasNamespace = !!options?.namespace;
14743
- const hasAll = !!options?.all;
15177
+ const hasTypes = options.types && options.types.length > 0;
15178
+ const hasNamespace = !!options.namespace;
15179
+ const hasAll = !!options.all;
14744
15180
  const optionCount = [
14745
15181
  hasAll,
14746
15182
  hasNamespace,
@@ -14748,14 +15184,14 @@ async function $truncate(options) {
14748
15184
  ].filter(Boolean).length;
14749
15185
  if (optionCount === 0) throw new Error("Please specify one of: --all, --namespace <name>, or type names");
14750
15186
  if (optionCount > 1) throw new Error("Options --all, --namespace, and type names are mutually exclusive. Please specify only one.");
14751
- const { config } = await loadConfig(options?.configPath);
15187
+ const { config } = await loadConfig(options.configPath);
14752
15188
  const namespaces = extractOwnedNamespaces(config);
14753
15189
  if (hasAll) {
14754
15190
  if (namespaces.length === 0) {
14755
15191
  logger.warn("No namespaces found in config file.");
14756
15192
  return;
14757
15193
  }
14758
- if (!options?.yes) {
15194
+ if (!options.yes) {
14759
15195
  const namespaceList = namespaces.join(", ");
14760
15196
  if (!await prompt.confirm({
14761
15197
  message: `This will truncate ALL tables in the following owned namespaces (external namespaces are excluded): ${namespaceList}. Continue?`,
@@ -14769,11 +15205,11 @@ async function $truncate(options) {
14769
15205
  logger.success("Truncated all tables in all owned namespaces");
14770
15206
  return;
14771
15207
  }
14772
- if (hasNamespace && options?.namespace) {
14773
- const namespace = options.namespace;
15208
+ if (hasNamespace) {
15209
+ const namespace = assertDefined(options.namespace, "namespace option missing");
14774
15210
  if (!namespaces.includes(namespace)) {
14775
15211
  const dbConfig = config.db?.[namespace];
14776
- if (dbConfig && "external" in dbConfig && dbConfig.external === true) 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.`);
15212
+ if (dbConfig && "external" in dbConfig) throw new Error(`Namespace "${namespace}" is declared as external in this app's config and cannot be truncated from here. Run truncate from the app that owns it.`);
14777
15213
  throw new Error(`Namespace "${namespace}" not found in config. Available owned namespaces (external namespaces are excluded): ${namespaces.join(", ")}`);
14778
15214
  }
14779
15215
  if (!options.yes) {
@@ -14788,8 +15224,8 @@ async function $truncate(options) {
14788
15224
  await truncateNamespace(workspaceId, namespace, client);
14789
15225
  return;
14790
15226
  }
14791
- if (hasTypes && options?.types) {
14792
- const typeNames = options.types;
15227
+ if (hasTypes) {
15228
+ const typeNames = assertDefined(options.types, "types option missing");
14793
15229
  const typeNamespaceMap = await resolveTypeNamespaces({
14794
15230
  workspaceId,
14795
15231
  namespaces,
@@ -14861,10 +15297,7 @@ const truncateCommand = defineAppCommand({
14861
15297
  * @returns List of workflows
14862
15298
  */
14863
15299
  async function listWorkflows(options) {
14864
- const client = await initOperatorClient(await loadAccessToken({
14865
- useProfile: true,
14866
- profile: options?.profile
14867
- }));
15300
+ const client = await initOperatorClient(await loadAccessToken({ profile: options?.profile }));
14868
15301
  const workspaceId = await loadWorkspaceId({
14869
15302
  workspaceId: options?.workspaceId,
14870
15303
  profile: options?.profile
@@ -14911,10 +15344,7 @@ const listCommand$3 = defineAppCommand({
14911
15344
  * @returns Resume result with wait helper
14912
15345
  */
14913
15346
  async function resumeWorkflow(options) {
14914
- const client = await initOperatorClient(await loadAccessToken({
14915
- useProfile: true,
14916
- profile: options.profile
14917
- }));
15347
+ const client = await initOperatorClient(await loadAccessToken({ profile: options.profile }));
14918
15348
  const workspaceId = await loadWorkspaceId({
14919
15349
  workspaceId: options.workspaceId,
14920
15350
  profile: options.profile
@@ -15022,12 +15452,9 @@ const healthOptionsSchema = z.object({
15022
15452
  });
15023
15453
  async function loadOptions$9(options) {
15024
15454
  const result = healthOptionsSchema.safeParse(options);
15025
- if (!result.success) throw new Error(result.error.issues[0].message);
15455
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15026
15456
  return {
15027
- client: await initOperatorClient(await loadAccessToken({
15028
- useProfile: true,
15029
- profile: result.data.profile
15030
- })),
15457
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
15031
15458
  workspaceId: await loadWorkspaceId({
15032
15459
  workspaceId: result.data.workspaceId,
15033
15460
  profile: result.data.profile
@@ -15082,12 +15509,9 @@ const listAppsOptionsSchema = z.object({
15082
15509
  });
15083
15510
  async function loadOptions$8(options) {
15084
15511
  const result = listAppsOptionsSchema.safeParse(options);
15085
- if (!result.success) throw new Error(result.error.issues[0].message);
15512
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15086
15513
  return {
15087
- client: await initOperatorClient(await loadAccessToken({
15088
- useProfile: true,
15089
- profile: result.data.profile
15090
- })),
15514
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
15091
15515
  workspaceId: await loadWorkspaceId({
15092
15516
  workspaceId: result.data.workspaceId,
15093
15517
  profile: result.data.profile
@@ -15137,26 +15561,6 @@ const listCommand$2 = defineAppCommand({
15137
15561
  }
15138
15562
  });
15139
15563
 
15140
- //#endregion
15141
- //#region src/cli/commands/workspace/transform.ts
15142
- const workspaceInfo = (workspace) => {
15143
- return {
15144
- id: workspace.id,
15145
- name: workspace.name,
15146
- region: workspace.region,
15147
- createdAt: formatTimestamp(workspace.createTime),
15148
- updatedAt: formatTimestamp(workspace.updateTime)
15149
- };
15150
- };
15151
- const workspaceDetails = (workspace) => {
15152
- return {
15153
- ...workspaceInfo(workspace),
15154
- deleteProtection: workspace.deleteProtection,
15155
- organizationId: workspace.organizationId,
15156
- folderId: workspace.folderId
15157
- };
15158
- };
15159
-
15160
15564
  //#endregion
15161
15565
  //#region src/cli/commands/workspace/create.ts
15162
15566
  /**
@@ -15182,17 +15586,17 @@ const validateRegion = async (region, client) => {
15182
15586
  */
15183
15587
  async function createWorkspace(options) {
15184
15588
  const result = createWorkspaceOptionsSchema.safeParse(options);
15185
- if (!result.success) throw new Error(result.error.issues[0].message);
15589
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15186
15590
  const validated = result.data;
15187
15591
  const client = await initOperatorClient(await loadAccessToken());
15188
15592
  await validateRegion(validated.region, client);
15189
- return workspaceInfo((await client.createWorkspace({
15593
+ return workspaceInfoWithFolderName(client, assertDefined((await client.createWorkspace({
15190
15594
  workspaceName: validated.name,
15191
15595
  workspaceRegion: validated.region,
15192
15596
  deleteProtection: validated.deleteProtection ?? false,
15193
15597
  organizationId: validated.organizationId,
15194
15598
  folderId: validated.folderId
15195
- })).workspace);
15599
+ })).workspace, "createWorkspace response missing workspace"));
15196
15600
  }
15197
15601
  const createCommand = defineAppCommand({
15198
15602
  name: "create",
@@ -15258,7 +15662,7 @@ const createCommand = defineAppCommand({
15258
15662
  };
15259
15663
  if (!args.json) logger.success(`Profile "${profileName}" created successfully.`);
15260
15664
  }
15261
- if (!args.json) logger.success(`Workspace "${args.name}" created successfully.`);
15665
+ if (!args.json) logger.success(`Workspace "${workspaceDisplayName(workspace)}" created successfully.`);
15262
15666
  if (args.json && profileInfo) {
15263
15667
  logger.out({
15264
15668
  ...workspace,
@@ -15266,7 +15670,10 @@ const createCommand = defineAppCommand({
15266
15670
  });
15267
15671
  return;
15268
15672
  }
15269
- logger.out(workspace);
15673
+ logger.out(workspace, { display: {
15674
+ name: workspaceNameTransformer,
15675
+ folderName: null
15676
+ } });
15270
15677
  if (profileInfo) {
15271
15678
  logger.out("Profile:");
15272
15679
  logger.out(profileInfo);
@@ -15279,7 +15686,7 @@ const createCommand = defineAppCommand({
15279
15686
  const deleteWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
15280
15687
  async function loadOptions$7(options) {
15281
15688
  const result = deleteWorkspaceOptionsSchema.safeParse(options);
15282
- if (!result.success) throw new Error(result.error.issues[0].message);
15689
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15283
15690
  return {
15284
15691
  client: await initOperatorClient(await loadAccessToken()),
15285
15692
  workspaceId: result.data.workspaceId
@@ -15313,8 +15720,15 @@ const deleteCommand = defineAppCommand({
15313
15720
  } catch {
15314
15721
  throw new Error(`Workspace "${workspaceId}" not found.`);
15315
15722
  }
15723
+ const workspaceResource = workspace.workspace;
15724
+ const workspaceName = workspaceResource?.name ?? workspaceId;
15725
+ const displayName = workspaceDisplayName({
15726
+ name: workspaceName,
15727
+ folderName: workspaceResource ? await resolveWorkspaceFolderName(client, workspaceResource) : ""
15728
+ });
15316
15729
  if (!args.yes) {
15317
- if (await prompt.text({ message: `Enter the workspace name to confirm deletion (${workspace.workspace?.name}):` }) !== workspace.workspace?.name) {
15730
+ const confirmation = await prompt.text({ message: `Enter the workspace name to confirm deletion (${displayName}):` });
15731
+ if (confirmation !== workspaceName && confirmation !== displayName) {
15318
15732
  logger.info("Workspace deletion cancelled.");
15319
15733
  return;
15320
15734
  }
@@ -15326,8 +15740,8 @@ const deleteCommand = defineAppCommand({
15326
15740
  for (const [profileName] of profilesToDelete) delete pfConfig.profiles[profileName];
15327
15741
  writePlatformConfig(pfConfig);
15328
15742
  }
15329
- if (profilesToDelete.length > 0) logger.success(`Workspace "${args["workspace-id"]}" and ${profilesToDelete.length} associated profile(s) deleted successfully.`);
15330
- else logger.success(`Workspace "${args["workspace-id"]}" deleted successfully.`);
15743
+ if (profilesToDelete.length > 0) logger.success(`Workspace "${displayName}" and ${profilesToDelete.length} associated profile(s) deleted successfully.`);
15744
+ else logger.success(`Workspace "${displayName}" deleted successfully.`);
15331
15745
  }
15332
15746
  });
15333
15747
 
@@ -15339,12 +15753,9 @@ const getWorkspaceOptionsSchema = z.object({
15339
15753
  });
15340
15754
  async function loadOptions$6(options) {
15341
15755
  const result = getWorkspaceOptionsSchema.safeParse(options);
15342
- if (!result.success) throw new Error(result.error.issues[0].message);
15756
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15343
15757
  return {
15344
- client: await initOperatorClient(await loadAccessToken({
15345
- useProfile: true,
15346
- profile: result.data.profile
15347
- })),
15758
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
15348
15759
  workspaceId: await loadWorkspaceId({
15349
15760
  workspaceId: result.data.workspaceId,
15350
15761
  profile: result.data.profile
@@ -15360,7 +15771,7 @@ async function getWorkspace(options) {
15360
15771
  const { client, workspaceId } = await loadOptions$6(options);
15361
15772
  const response = await client.getWorkspace({ workspaceId });
15362
15773
  if (!response.workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
15363
- return workspaceDetails(response.workspace);
15774
+ return workspaceDetailsWithFolderName(client, response.workspace);
15364
15775
  }
15365
15776
  const getCommand = defineAppCommand({
15366
15777
  name: "get",
@@ -15376,7 +15787,10 @@ const getCommand = defineAppCommand({
15376
15787
  createdAt: humanizeRelativeTime(workspace.createdAt),
15377
15788
  updatedAt: humanizeRelativeTime(workspace.updatedAt)
15378
15789
  };
15379
- logger.out(formattedWorkspace);
15790
+ logger.out(formattedWorkspace, { display: {
15791
+ name: workspaceNameTransformer,
15792
+ folderName: null
15793
+ } });
15380
15794
  }
15381
15795
  });
15382
15796
 
@@ -15390,14 +15804,14 @@ const getCommand = defineAppCommand({
15390
15804
  async function listWorkspaces(options) {
15391
15805
  const client = await initOperatorClient(await loadAccessToken());
15392
15806
  const pageDirection = toPageDirection(options?.order);
15393
- return (await fetchPaged(async (pageToken, pageSize) => {
15807
+ return workspaceInfosWithFolderNames(client, await fetchPaged(async (pageToken, pageSize) => {
15394
15808
  const { workspaces, nextPageToken } = await client.listWorkspaces({
15395
15809
  pageToken,
15396
15810
  pageSize,
15397
15811
  pageDirection
15398
15812
  });
15399
15813
  return [workspaces, nextPageToken];
15400
- }, { limit: options?.limit })).map(workspaceInfo);
15814
+ }, { limit: options?.limit }));
15401
15815
  }
15402
15816
  const listCommand$1 = defineAppCommand({
15403
15817
  name: "list",
@@ -15408,7 +15822,11 @@ const listCommand$1 = defineAppCommand({
15408
15822
  order: args.order,
15409
15823
  limit: args.limit
15410
15824
  });
15411
- logger.out(workspaces, { display: { updatedAt: null } });
15825
+ logger.out(workspaces, { display: {
15826
+ name: workspaceNameTransformer,
15827
+ folderName: null,
15828
+ updatedAt: null
15829
+ } });
15412
15830
  }
15413
15831
  });
15414
15832
 
@@ -15417,7 +15835,7 @@ const listCommand$1 = defineAppCommand({
15417
15835
  const restoreWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "workspace-id must be a valid UUID" }) });
15418
15836
  async function loadOptions$5(options) {
15419
15837
  const result = restoreWorkspaceOptionsSchema.safeParse(options);
15420
- if (!result.success) throw new Error(result.error.issues[0].message);
15838
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15421
15839
  return {
15422
15840
  client: await initOperatorClient(await loadAccessToken()),
15423
15841
  workspaceId: result.data.workspaceId
@@ -15497,12 +15915,9 @@ const inviteUserOptionsSchema = z.object({
15497
15915
  });
15498
15916
  async function loadOptions$4(options) {
15499
15917
  const result = inviteUserOptionsSchema.safeParse(options);
15500
- if (!result.success) throw new Error(result.error.issues[0].message);
15918
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15501
15919
  return {
15502
- client: await initOperatorClient(await loadAccessToken({
15503
- useProfile: true,
15504
- profile: result.data.profile
15505
- })),
15920
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
15506
15921
  workspaceId: await loadWorkspaceId({
15507
15922
  workspaceId: result.data.workspaceId,
15508
15923
  profile: result.data.profile
@@ -15557,12 +15972,9 @@ const listUsersOptionsSchema = z.object({
15557
15972
  });
15558
15973
  async function loadOptions$3(options) {
15559
15974
  const result = listUsersOptionsSchema.safeParse(options);
15560
- if (!result.success) throw new Error(result.error.issues[0].message);
15975
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15561
15976
  return {
15562
- client: await initOperatorClient(await loadAccessToken({
15563
- useProfile: true,
15564
- profile: result.data.profile
15565
- })),
15977
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
15566
15978
  workspaceId: await loadWorkspaceId({
15567
15979
  workspaceId: result.data.workspaceId,
15568
15980
  profile: result.data.profile
@@ -15616,12 +16028,9 @@ const removeUserOptionsSchema = z.object({
15616
16028
  });
15617
16029
  async function loadOptions$2(options) {
15618
16030
  const result = removeUserOptionsSchema.safeParse(options);
15619
- if (!result.success) throw new Error(result.error.issues[0].message);
16031
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15620
16032
  return {
15621
- client: await initOperatorClient(await loadAccessToken({
15622
- useProfile: true,
15623
- profile: result.data.profile
15624
- })),
16033
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
15625
16034
  workspaceId: await loadWorkspaceId({
15626
16035
  workspaceId: result.data.workspaceId,
15627
16036
  profile: result.data.profile
@@ -15676,12 +16085,9 @@ const updateUserOptionsSchema = z.object({
15676
16085
  });
15677
16086
  async function loadOptions$1(options) {
15678
16087
  const result = updateUserOptionsSchema.safeParse(options);
15679
- if (!result.success) throw new Error(result.error.issues[0].message);
16088
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
15680
16089
  return {
15681
- client: await initOperatorClient(await loadAccessToken({
15682
- useProfile: true,
15683
- profile: result.data.profile
15684
- })),
16090
+ client: await initOperatorClient(await loadAccessToken({ profile: result.data.profile })),
15685
16091
  workspaceId: await loadWorkspaceId({
15686
16092
  workspaceId: result.data.workspaceId,
15687
16093
  profile: result.data.profile
@@ -15902,7 +16308,7 @@ function isSqlInputComplete(input) {
15902
16308
  let dollarQuoteTag = null;
15903
16309
  let lastSignificantTokenWasSemicolon = false;
15904
16310
  for (let i = 0; i < input.length; i += 1) {
15905
- const char = input[i];
16311
+ const char = assertDefined(input[i], `character at index ${i} missing`);
15906
16312
  const next = input[i + 1];
15907
16313
  if (inLineComment) {
15908
16314
  if (char === "\n") inLineComment = false;
@@ -16105,7 +16511,7 @@ const queryBaseOptionsSchema = z.object({
16105
16511
  const queryOptionsSchema = queryBaseOptionsSchema.extend({ query: z.string() });
16106
16512
  async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces) {
16107
16513
  if (namespaces.length === 0) throw new Error("No namespaces found in configuration.");
16108
- if (namespaces.length === 1) return namespaces[0];
16514
+ if (namespaces.length === 1) return assertDefined(namespaces[0], "namespace missing");
16109
16515
  const typeNames = extractTypeNamesFromSql(query);
16110
16516
  if (typeNames.length === 0) throw new Error(`Could not infer namespace from query. Detected namespaces: ${namespaces.join(", ")}.`);
16111
16517
  const typeNamespaceMap = await resolveTypeNamespaces({
@@ -16117,16 +16523,13 @@ async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces)
16117
16523
  const notFoundTypes = typeNames.filter((typeName) => !typeNamespaceMap.has(typeName));
16118
16524
  if (notFoundTypes.length > 0) throw new Error(`Could not find namespace for types in query: ${notFoundTypes.join(", ")}.`);
16119
16525
  const namespacesFromTypes = new Set(typeNamespaceMap.values());
16120
- if (namespacesFromTypes.size === 1) return [...namespacesFromTypes][0];
16526
+ if (namespacesFromTypes.size === 1) return assertDefined([...namespacesFromTypes][0], "namespace from types missing");
16121
16527
  throw new Error(`Query references types from multiple namespaces: ${[...namespacesFromTypes].join(", ")}.`);
16122
16528
  }
16123
16529
  async function loadOptions(options) {
16124
16530
  const result = queryBaseOptionsSchema.safeParse(options);
16125
- if (!result.success) throw new Error(result.error.issues[0].message);
16126
- const client = await initOperatorClient(await loadAccessToken({
16127
- useProfile: true,
16128
- profile: result.data.profile
16129
- }));
16531
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
16532
+ const client = await initOperatorClient(await loadAccessToken({ profile: result.data.profile }));
16130
16533
  const workspaceId = await loadWorkspaceId({
16131
16534
  workspaceId: result.data.workspaceId,
16132
16535
  profile: result.data.profile
@@ -16259,7 +16662,7 @@ async function resolveEditedQueryInput(engine) {
16259
16662
  */
16260
16663
  async function query(options) {
16261
16664
  const result = queryOptionsSchema.safeParse(options);
16262
- if (!result.success) throw new Error(result.error.issues[0].message);
16665
+ if (!result.success) throw new Error(assertDefined(result.error.issues[0], "validation error missing issues").message);
16263
16666
  return await (await prepareQueryExecutor(result.data))(result.data.query);
16264
16667
  }
16265
16668
  async function prepareQueryExecutor(options) {
@@ -16341,7 +16744,7 @@ async function runRepl(options) {
16341
16744
  const execute = await prepareQueryExecutor(options);
16342
16745
  const historyPath = getReplHistoryPath(options.engine, options.profile, options.workspaceId);
16343
16746
  const validate = createReplValidator(options.engine);
16344
- const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-Y9QJDL0K.mjs");
16747
+ const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-CJG3sz7A.mjs");
16345
16748
  const highlight = options.engine === "sql" ? highlightSqlLine : highlightGraphqlLine;
16346
16749
  const prompt = createPrompt({
16347
16750
  prefix: "",
@@ -16602,8 +17005,9 @@ function printSingleSqlResult(execResult, options = {}) {
16602
17005
  function splitSqlStatements(query) {
16603
17006
  const statements = parse(query, { locationTracking: true });
16604
17007
  return statements.map((s, i) => {
16605
- const start = s._location.start;
16606
- const end = i + 1 < statements.length ? statements[i + 1]._location.start : query.length;
17008
+ const start = assertDefined(s._location, "SQL statement location missing").start;
17009
+ const nextStmt = statements[i + 1];
17010
+ const end = nextStmt !== void 0 ? assertDefined(nextStmt._location, "SQL statement location missing").start : query.length;
16607
17011
  return query.substring(start, end);
16608
17012
  });
16609
17013
  }
@@ -16623,7 +17027,7 @@ function printSqlResult(result, options = {}) {
16623
17027
  for (let i = 0; i < result.result.length; i++) {
16624
17028
  if (i > 0) logger.log("");
16625
17029
  logger.info(queries[i] ?? `Statement ${i + 1}`);
16626
- printSingleSqlResult(result.result[i], options);
17030
+ printSingleSqlResult(assertDefined(result.result[i], `SQL result at index ${i} missing`), options);
16627
17031
  }
16628
17032
  return;
16629
17033
  }
@@ -16674,5 +17078,5 @@ function isDeno() {
16674
17078
  }
16675
17079
 
16676
17080
  //#endregion
16677
- export { listCommand$5 as $, compareSnapshots as $t, truncate as A, toPageDirection as An, startCommand as At, logBetaWarning as B, getExecutor as Bt, listCommand$2 as C, commonArgs as Cn, triggerExecutor as Ct, resumeWorkflow as D, isVerbose as Dn, jobsCommand as Dt, resumeCommand as E, deploymentArgs as En, getExecutorJob as Et, writeDbTypesFile as F, getWorkflowExecution as Ft, organizationTree as G, parseMigrationLabelNumber as Gt, removeCommand$1 as H, executeScript as Ht, getConfiguredEditorCommand as I, listWorkflowExecutions as It, listOrganizations as J, DIFF_FILE_NAME as Jt, treeCommand as K, bundleMigrationScript as Kt, openInConfiguredEditor as L, functionExecutionStatusToString as Lt, generate as M, getCommand$5 as Mt, generateCommand as N, getWorkflow as Nt, listCommand$3 as O, pagedLogArgs as On, listExecutorJobs as Ot, generateMigrationScript as P, executionsCommand as Pt, updateFolder as Q, compareLocalTypesWithSnapshot as Qt, show as R, formatKeyValueTable as Rt, listApps as S, defineAppCommand as Sn, triggerCommand as St, healthCommand as T, confirmationArgs as Tn, listExecutors as Tt, updateCommand$1 as U, waitForExecution$1 as Ut, remove as V, deploy as Vt, updateOrganization as W, MIGRATION_LABEL_KEY as Wt, getOrganization as X, MIGRATE_FILE_NAME as Xt, getCommand$1 as Y, INITIAL_SCHEMA_NUMBER as Yt, updateCommand$2 as Z, SCHEMA_FILE_NAME as Zt, getWorkspace as _, generateUserTypes as _n, listFunctionRegistries as _t, updateUser as a, getNextMigrationNumber as an, createCommand$1 as at, createCommand as b, apiCall as bn, listWebhookExecutors as bt, listCommand as c, reconstructSnapshotFromMigrations as cn, listOAuth2Clients as ct, inviteUser as d, formatMigrationDiff as dn, getMachineUserToken as dt, createSnapshotFromLocalTypes as en, listFolders as et, restoreCommand as f, hasChanges as fn, tokenCommand as ft, getCommand as g, PluginManager as gn, listCommand$8 as gt, listWorkspaces as h, sdkNameLabelKey as hn, generate$1 as ht, updateCommand as i, getMigrationFiles as in, deleteFolder as it, truncateCommand as j, workspaceArgs as jn, startWorkflow as jt, listWorkflows as k, paginationArgs as kn, watchExecutorJob as kt, listUsers as l, formatMigrationNumber as ln, getCommand$3 as lt, listCommand$1 as m, resourceTrn as mn, listMachineUsers as mt, query as n, getMigrationDirPath as nn, getFolder as nt, removeCommand as o, isValidMigrationNumber as on, createFolder as ot, restoreWorkspace as p, getNamespacesWithMigrations as pn, listCommand$7 as pt, listCommand$4 as q, DB_TYPES_FILE_NAME as qt, queryCommand as r, getMigrationFilePath as rn, deleteCommand$1 as rt, removeUser as s, loadDiff as sn, listCommand$6 as st, isNativeTypeScriptRuntime as t, getLatestMigrationNumber as tn, getCommand$2 as tt, inviteCommand as u, formatDiffSummary as un, getOAuth2Client as ut, deleteCommand as v, prompt as vn, getCommand$4 as vt, getAppHealth as w, configArg as wn, listCommand$9 as wt, createWorkspace as x, assertWritable as xn, webhookCommand as xt, deleteWorkspace as y, apiCommand as yn, getFunctionRegistry as yt, showCommand as z, getCommand$6 as zt };
16678
- //# sourceMappingURL=runtime-CZpsV8vj.mjs.map
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