@tailor-platform/sdk 1.60.3 → 1.63.0

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