@tailor-platform/sdk 0.8.5 → 0.9.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.
@@ -21,6 +21,7 @@ import * as os from "node:os";
21
21
  import { parseTOML, parseYAML, stringifyYAML } from "confbox";
22
22
  import { xdgConfig } from "xdg-basedir";
23
23
  import { fromJson } from "@bufbuild/protobuf";
24
+ import chalk from "chalk";
24
25
  import { spawn } from "node:child_process";
25
26
  import { glob } from "node:fs/promises";
26
27
  import chokidar from "chokidar";
@@ -190,6 +191,7 @@ var ExecutorService = class {
190
191
  this.config = config;
191
192
  }
192
193
  async loadExecutors() {
194
+ if (Object.keys(this.executors).length > 0) return this.executors;
193
195
  if (!this.config.files || this.config.files.length === 0) return;
194
196
  const executorFiles = loadFilesWithIgnores(this.config);
195
197
  console.log("");
@@ -275,6 +277,7 @@ var ResolverService = class {
275
277
  this.config = config;
276
278
  }
277
279
  async loadResolvers() {
280
+ if (Object.keys(this.resolvers).length > 0) return;
278
281
  if (!this.config.files || this.config.files.length === 0) return;
279
282
  const resolverFiles = loadFilesWithIgnores(this.config);
280
283
  console.log("");
@@ -867,10 +870,11 @@ var EnumProcessor = class {
867
870
  /**
868
871
  * Generate enum constant definitions from collected metadata.
869
872
  */
870
- static async generateEnumConstants(types) {
871
- const allEnums = /* @__PURE__ */ new Map();
872
- for (const typeMetadata of Object.values(types)) if (typeMetadata.enums) for (const enumDef of typeMetadata.enums) allEnums.set(enumDef.name, enumDef);
873
- const enumDefs = Array.from(allEnums.values()).map((e) => {
873
+ static generateUnifiedEnumConstants(allEnums) {
874
+ if (allEnums.length === 0) return "";
875
+ const enumMap = /* @__PURE__ */ new Map();
876
+ for (const enumDef of allEnums) enumMap.set(enumDef.name, enumDef);
877
+ const enumDefs = Array.from(enumMap.values()).map((e) => {
874
878
  const members = e.values.map((v) => {
875
879
  return ` "${v.value.replace(/[-\s]/g, "_")}": "${v.value}"`;
876
880
  }).join(",\n");
@@ -920,17 +924,27 @@ var EnumConstantsGenerator = class {
920
924
  processResolver() {}
921
925
  processExecutor() {}
922
926
  async processTailorDBNamespace(args) {
923
- return await EnumProcessor.generateEnumConstants(args.types);
927
+ const allEnums = [];
928
+ for (const enumConstantMetadata of Object.values(args.types)) allEnums.push(...enumConstantMetadata.enums);
929
+ return {
930
+ namespace: args.namespace,
931
+ enums: allEnums
932
+ };
924
933
  }
925
934
  processIdProvider() {}
926
935
  processAuth() {}
927
936
  processStaticWebsite() {}
928
937
  aggregate(args) {
929
938
  const files = [];
930
- for (const input of args.inputs) for (const nsResult of input.tailordb) if (nsResult.types) files.push({
931
- path: this.options.distPath,
932
- content: nsResult.types
933
- });
939
+ const allEnums = [];
940
+ for (const input of args.inputs) for (const nsResult of input.tailordb) if (nsResult.types && nsResult.types.enums.length > 0) allEnums.push(...nsResult.types.enums);
941
+ if (allEnums.length > 0) {
942
+ const content = EnumProcessor.generateUnifiedEnumConstants(allEnums);
943
+ files.push({
944
+ path: this.options.distPath,
945
+ content
946
+ });
947
+ }
934
948
  return { files };
935
949
  }
936
950
  };
@@ -1083,7 +1097,7 @@ var FileUtilsGenerator = class {
1083
1097
  /**
1084
1098
  * Processor that converts a ParsedTailorDBType into Kysely type metadata.
1085
1099
  */
1086
- var TypeProcessor = class TypeProcessor {
1100
+ var TypeProcessor = class {
1087
1101
  /**
1088
1102
  * Convert a ParsedTailorDBType into KyselyTypeMetadata.
1089
1103
  */
@@ -1221,49 +1235,52 @@ var TypeProcessor = class TypeProcessor {
1221
1235
  usedUtilityTypes: aggregatedUtilityTypes
1222
1236
  };
1223
1237
  }
1224
- static async processTypes(types, namespace) {
1225
- const aggregatedUtilityTypes = Object.values(types).reduce((acc, type) => ({
1226
- Timestamp: acc.Timestamp || type.usedUtilityTypes.Timestamp,
1227
- Serial: acc.Serial || type.usedUtilityTypes.Serial
1238
+ /**
1239
+ * Generate unified types file from multiple namespaces.
1240
+ */
1241
+ static generateUnifiedTypes(namespaceData) {
1242
+ if (namespaceData.length === 0) return "";
1243
+ const globalUsedUtilityTypes = namespaceData.reduce((acc, ns) => ({
1244
+ Timestamp: acc.Timestamp || ns.usedUtilityTypes.Timestamp,
1245
+ Serial: acc.Serial || ns.usedUtilityTypes.Serial
1228
1246
  }), {
1229
1247
  Timestamp: false,
1230
1248
  Serial: false
1231
1249
  });
1232
1250
  const utilityTypeDeclarations = [];
1233
- if (aggregatedUtilityTypes.Timestamp) utilityTypeDeclarations.push(`type Timestamp = ColumnType<Date, Date | string, Date | string>;`);
1251
+ if (globalUsedUtilityTypes.Timestamp) utilityTypeDeclarations.push(`type Timestamp = ColumnType<Date, Date | string, Date | string>;`);
1234
1252
  utilityTypeDeclarations.push(ml`
1235
1253
  type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
1236
1254
  ? ColumnType<S, I | undefined, U>
1237
1255
  : ColumnType<T, T | undefined, T>;
1238
1256
  `);
1239
- if (aggregatedUtilityTypes.Serial) utilityTypeDeclarations.push(`type Serial<T = string | number> = ColumnType<T, never, never>;`);
1240
- return [
1241
- ml`
1242
- import { type ColumnType, Kysely } from "kysely";
1243
- import { TailordbDialect } from "@tailor-platform/function-kysely-tailordb";
1257
+ if (globalUsedUtilityTypes.Serial) utilityTypeDeclarations.push(`type Serial<T = string | number> = ColumnType<T, never, never>;`);
1258
+ const importsSection = ml`
1259
+ import { type ColumnType, Kysely } from "kysely";
1260
+ import { TailordbDialect } from "@tailor-platform/function-kysely-tailordb";
1244
1261
 
1245
- ${utilityTypeDeclarations.join("\n")}
1246
- `,
1247
- TypeProcessor.generateNamespaceInterface(Object.values(types), namespace),
1248
- ml`
1249
- export function getDB<const N extends keyof Namespace>(namespace: N): Kysely<Namespace[N]> {
1250
- const client = new tailordb.Client({ namespace });
1251
- return new Kysely<Namespace[N]>({ dialect: new TailordbDialect(client) });
1252
- }
1262
+ ${utilityTypeDeclarations.join("\n")}
1263
+ `;
1264
+ const namespaceInterface = `export interface Namespace {\n${namespaceData.map(({ namespace, types }) => {
1265
+ const typeDefsWithIndent = types.map((type) => {
1266
+ return type.typeDef.split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
1267
+ }).join("\n\n");
1268
+ return ` "${namespace}": {\n${typeDefsWithIndent}\n }`;
1269
+ }).join(",\n")}\n}`;
1270
+ const getDBFunction = ml`
1271
+ export function getDB<const N extends keyof Namespace>(namespace: N): Kysely<Namespace[N]> {
1272
+ const client = new tailordb.Client({ namespace });
1273
+ return new Kysely<Namespace[N]>({ dialect: new TailordbDialect(client) });
1274
+ }
1253
1275
 
1254
- export type DB<N extends keyof Namespace = keyof Namespace> = ReturnType<typeof getDB<N>>;
1255
- `
1276
+ export type DB<N extends keyof Namespace = keyof Namespace> = ReturnType<typeof getDB<N>>;
1277
+ `;
1278
+ return [
1279
+ importsSection,
1280
+ namespaceInterface,
1281
+ getDBFunction
1256
1282
  ].join("\n\n") + "\n";
1257
1283
  }
1258
- /**
1259
- * Generate the Namespace interface.
1260
- */
1261
- static generateNamespaceInterface(types, namespace) {
1262
- const typeDefsWithIndent = types.map((type) => {
1263
- return type.typeDef.split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
1264
- }).join("\n\n");
1265
- return `export interface Namespace {\n "${namespace}": {\n${typeDefsWithIndent}\n }\n}`;
1266
- }
1267
1284
  };
1268
1285
 
1269
1286
  //#endregion
@@ -1284,14 +1301,31 @@ var KyselyGenerator = class {
1284
1301
  processResolver() {}
1285
1302
  processExecutor() {}
1286
1303
  async processTailorDBNamespace(args) {
1287
- return await TypeProcessor.processTypes(args.types, args.namespace);
1304
+ const typesList = Object.values(args.types);
1305
+ const usedUtilityTypes = typesList.reduce((acc, type) => ({
1306
+ Timestamp: acc.Timestamp || type.usedUtilityTypes.Timestamp,
1307
+ Serial: acc.Serial || type.usedUtilityTypes.Serial
1308
+ }), {
1309
+ Timestamp: false,
1310
+ Serial: false
1311
+ });
1312
+ return {
1313
+ namespace: args.namespace,
1314
+ types: typesList,
1315
+ usedUtilityTypes
1316
+ };
1288
1317
  }
1289
1318
  aggregate(args) {
1290
1319
  const files = [];
1291
- for (const input of args.inputs) for (const nsResult of input.tailordb) if (nsResult.types) files.push({
1292
- path: this.options.distPath,
1293
- content: nsResult.types
1294
- });
1320
+ const allNamespaceData = [];
1321
+ for (const input of args.inputs) for (const nsResult of input.tailordb) if (nsResult.types && nsResult.types.types.length > 0) allNamespaceData.push(nsResult.types);
1322
+ if (allNamespaceData.length > 0) {
1323
+ const content = TypeProcessor.generateUnifiedTypes(allNamespaceData);
1324
+ files.push({
1325
+ path: this.options.distPath,
1326
+ content
1327
+ });
1328
+ }
1295
1329
  return { files };
1296
1330
  }
1297
1331
  };
@@ -2223,6 +2257,15 @@ const file_tailor_v1_service = /* @__PURE__ */ fileDesc("Chd0YWlsb3IvdjEvc2Vydml
2223
2257
  */
2224
2258
  const OperatorService = /* @__PURE__ */ serviceDesc(file_tailor_v1_service, 0);
2225
2259
 
2260
+ //#endregion
2261
+ //#region src/cli/package-json.ts
2262
+ let packageJson = null;
2263
+ async function readPackageJson() {
2264
+ if (packageJson) return packageJson;
2265
+ packageJson = await readPackageJSON(import.meta.url);
2266
+ return packageJson;
2267
+ }
2268
+
2226
2269
  //#endregion
2227
2270
  //#region src/cli/client.ts
2228
2271
  const baseUrl = process.env.PLATFORM_URL ?? "https://api.tailor.tech";
@@ -2247,7 +2290,7 @@ async function userAgentInterceptor() {
2247
2290
  };
2248
2291
  }
2249
2292
  async function userAgent() {
2250
- return `tailor-sdk/${(await readPackageJSON(import.meta.url)).version ?? "unknown"}`;
2293
+ return `tailor-sdk/${(await readPackageJson()).version ?? "unknown"}`;
2251
2294
  }
2252
2295
  async function bearerTokenInterceptor(accessToken) {
2253
2296
  return (next) => async (req) => {
@@ -2509,6 +2552,24 @@ function loadConfigPath(configPath) {
2509
2552
  return "tailor.config.ts";
2510
2553
  }
2511
2554
 
2555
+ //#endregion
2556
+ //#region src/cli/apply/services/label.ts
2557
+ function trnPrefix(workspaceId) {
2558
+ return `trn:v1:workspace:${workspaceId}`;
2559
+ }
2560
+ const sdkNameLabelKey = "sdk-name";
2561
+ async function buildMetaRequest(trn$7, appName) {
2562
+ const packageJson$1 = await readPackageJson();
2563
+ const sdkVersion = packageJson$1.version ? `v${packageJson$1.version.replace(/\./g, "-")}` : "unknown";
2564
+ return {
2565
+ trn: trn$7,
2566
+ labels: {
2567
+ [sdkNameLabelKey]: appName,
2568
+ "sdk-version": sdkVersion
2569
+ }
2570
+ };
2571
+ }
2572
+
2512
2573
  //#endregion
2513
2574
  //#region src/cli/apply/services/index.ts
2514
2575
  var ChangeSet = class {
@@ -2538,14 +2599,21 @@ var ChangeSet = class {
2538
2599
  async function applyApplication(client, changeSet, phase = "create-update") {
2539
2600
  if (phase === "create-update") await Promise.all([...changeSet.creates.map(async (create) => {
2540
2601
  create.request.cors = await resolveStaticWebsiteUrls(client, create.request.workspaceId, create.request.cors, "CORS");
2541
- return client.createApplication(create.request);
2602
+ await client.createApplication(create.request);
2603
+ await client.setMetadata(create.metaRequest);
2542
2604
  }), ...changeSet.updates.map(async (update) => {
2543
2605
  update.request.cors = await resolveStaticWebsiteUrls(client, update.request.workspaceId, update.request.cors, "CORS");
2544
- return client.updateApplication(update.request);
2606
+ await client.updateApplication(update.request);
2607
+ await client.setMetadata(update.metaRequest);
2545
2608
  })]);
2546
- else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteApplication(del.request)));
2609
+ else if (phase === "delete") await Promise.all(changeSet.deletes.map(async (del) => {
2610
+ await client.deleteApplication(del.request);
2611
+ }));
2547
2612
  }
2548
- async function planApplication(client, workspaceId, application) {
2613
+ function trn$6(workspaceId, name) {
2614
+ return `trn:v1:workspace:${workspaceId}:application:${name}`;
2615
+ }
2616
+ async function planApplication({ client, workspaceId, application }) {
2549
2617
  const changeSet = new ChangeSet("Applications");
2550
2618
  const existingApplications = await fetchAll(async (pageToken) => {
2551
2619
  try {
@@ -2559,55 +2627,41 @@ async function planApplication(client, workspaceId, application) {
2559
2627
  throw error;
2560
2628
  }
2561
2629
  });
2562
- const existingNameSet = /* @__PURE__ */ new Set();
2563
- existingApplications.forEach((application$1) => {
2564
- existingNameSet.add(application$1.name);
2630
+ let authNamespace;
2631
+ let authIdpConfigName;
2632
+ if (application.authService && application.authService.config) {
2633
+ authNamespace = application.authService.config.name;
2634
+ const idProvider = application.authService.config.idProvider;
2635
+ if (idProvider) authIdpConfigName = idProvider.name;
2636
+ }
2637
+ const metaRequest = await buildMetaRequest(trn$6(workspaceId, application.name), application.name);
2638
+ if (existingApplications.some((app) => app.name === application.name)) changeSet.updates.push({
2639
+ name: application.name,
2640
+ request: {
2641
+ workspaceId,
2642
+ applicationName: application.name,
2643
+ authNamespace,
2644
+ authIdpConfigName,
2645
+ cors: application.config.cors,
2646
+ subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
2647
+ allowedIpAddresses: application.config.allowedIPAddresses,
2648
+ disableIntrospection: application.config.disableIntrospection
2649
+ },
2650
+ metaRequest
2565
2651
  });
2566
- for (const app of application.applications) {
2567
- let authNamespace;
2568
- let authIdpConfigName;
2569
- if (app.authService && app.authService.config) {
2570
- authNamespace = app.authService.config.name;
2571
- const idProvider = app.authService.config.idProvider;
2572
- if (idProvider) authIdpConfigName = idProvider.name;
2573
- }
2574
- if (existingNameSet.has(app.name)) {
2575
- changeSet.updates.push({
2576
- name: app.name,
2577
- request: {
2578
- workspaceId,
2579
- applicationName: app.name,
2580
- authNamespace,
2581
- authIdpConfigName,
2582
- cors: app.config.cors,
2583
- subgraphs: app.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
2584
- allowedIpAddresses: app.config.allowedIPAddresses,
2585
- disableIntrospection: app.config.disableIntrospection
2586
- }
2587
- });
2588
- existingNameSet.delete(app.name);
2589
- } else changeSet.creates.push({
2590
- name: app.name,
2591
- request: {
2592
- workspaceId,
2593
- applicationName: app.name,
2594
- authNamespace,
2595
- authIdpConfigName,
2596
- cors: app.config.cors,
2597
- subgraphs: app.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
2598
- allowedIpAddresses: app.config.allowedIPAddresses,
2599
- disableIntrospection: app.config.disableIntrospection
2600
- }
2601
- });
2602
- }
2603
- existingNameSet.forEach((name) => {
2604
- changeSet.deletes.push({
2605
- name,
2606
- request: {
2607
- workspaceId,
2608
- applicationName: name
2609
- }
2610
- });
2652
+ else changeSet.creates.push({
2653
+ name: application.name,
2654
+ request: {
2655
+ workspaceId,
2656
+ applicationName: application.name,
2657
+ authNamespace,
2658
+ authIdpConfigName,
2659
+ cors: application.config.cors,
2660
+ subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
2661
+ allowedIpAddresses: application.config.allowedIPAddresses,
2662
+ disableIntrospection: application.config.disableIntrospection
2663
+ },
2664
+ metaRequest
2611
2665
  });
2612
2666
  changeSet.print();
2613
2667
  return changeSet;
@@ -2643,9 +2697,16 @@ function idpClientVaultName(namespaceName, clientName) {
2643
2697
  function idpClientSecretName(namespaceName, clientName) {
2644
2698
  return `client-secret-${namespaceName}-${clientName}`;
2645
2699
  }
2646
- async function applyIdP(client, changeSet, phase = "create-update") {
2700
+ async function applyIdP(client, result, phase = "create-update") {
2701
+ const { changeSet } = result;
2647
2702
  if (phase === "create-update") {
2648
- await Promise.all([...changeSet.service.creates.map((create) => client.createIdPService(create.request)), ...changeSet.service.updates.map((update) => client.updateIdPService(update.request))]);
2703
+ await Promise.all([...changeSet.service.creates.map(async (create) => {
2704
+ await client.createIdPService(create.request);
2705
+ await client.setMetadata(create.metaRequest);
2706
+ }), ...changeSet.service.updates.map(async (update) => {
2707
+ await client.updateIdPService(update.request);
2708
+ await client.setMetadata(update.metaRequest);
2709
+ })]);
2649
2710
  await Promise.all([...changeSet.client.creates.map(async (create) => {
2650
2711
  const resp = await client.createIdPClient(create.request);
2651
2712
  const vaultName = idpClientVaultName(create.request.namespaceName, create.request.client?.name || "");
@@ -2684,7 +2745,7 @@ async function applyIdP(client, changeSet, phase = "create-update") {
2684
2745
  });
2685
2746
  })]);
2686
2747
  } else if (phase === "delete") {
2687
- await Promise.all(changeSet.client.deletes.filter((del) => del.tag === "client-deleted").map(async (del) => {
2748
+ await Promise.all(changeSet.client.deletes.map(async (del) => {
2688
2749
  await client.deleteIdPClient(del.request);
2689
2750
  const vaultName = `idp-${del.request.namespaceName}-${del.request.name}`;
2690
2751
  await client.deleteSecretManagerVault({
@@ -2695,22 +2756,32 @@ async function applyIdP(client, changeSet, phase = "create-update") {
2695
2756
  await Promise.all(changeSet.service.deletes.map((del) => client.deleteIdPService(del.request)));
2696
2757
  }
2697
2758
  }
2698
- async function planIdP(client, workspaceId, application) {
2699
- const idps = [];
2700
- for (const app of application.applications) idps.push(...app.idpServices);
2701
- const serviceChangeSet = await planServices$3(client, workspaceId, idps);
2759
+ async function planIdP({ client, workspaceId, application }) {
2760
+ const idps = application.idpServices;
2761
+ const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$3(client, workspaceId, application.name, idps);
2702
2762
  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
2703
2763
  const clientChangeSet = await planClients(client, workspaceId, idps, deletedServices);
2704
2764
  serviceChangeSet.print();
2705
2765
  clientChangeSet.print();
2706
2766
  return {
2707
- service: serviceChangeSet,
2708
- client: clientChangeSet
2767
+ changeSet: {
2768
+ service: serviceChangeSet,
2769
+ client: clientChangeSet
2770
+ },
2771
+ conflicts,
2772
+ unmanaged,
2773
+ resourceOwners
2709
2774
  };
2710
2775
  }
2711
- async function planServices$3(client, workspaceId, idps) {
2776
+ function trn$5(workspaceId, name) {
2777
+ return `trn:v1:workspace:${workspaceId}:idp:${name}`;
2778
+ }
2779
+ async function planServices$3(client, workspaceId, appName, idps) {
2712
2780
  const changeSet = new ChangeSet("IdP services");
2713
- const existingServices = await fetchAll(async (pageToken) => {
2781
+ const conflicts = [];
2782
+ const unmanaged = [];
2783
+ const resourceOwners = /* @__PURE__ */ new Set();
2784
+ const withoutLabel = await fetchAll(async (pageToken) => {
2714
2785
  try {
2715
2786
  const { idpServices, nextPageToken } = await client.listIdPServices({
2716
2787
  workspaceId,
@@ -2722,13 +2793,19 @@ async function planServices$3(client, workspaceId, idps) {
2722
2793
  throw error;
2723
2794
  }
2724
2795
  });
2725
- const existingNameSet = /* @__PURE__ */ new Set();
2726
- existingServices.forEach((service) => {
2727
- const name = service.namespace?.name;
2728
- if (name) existingNameSet.add(name);
2729
- });
2796
+ const existingServices = {};
2797
+ await Promise.all(withoutLabel.map(async (resource) => {
2798
+ if (!resource.namespace?.name) return;
2799
+ const { metadata } = await client.getMetadata({ trn: trn$5(workspaceId, resource.namespace.name) });
2800
+ existingServices[resource.namespace.name] = {
2801
+ resource,
2802
+ label: metadata?.labels[sdkNameLabelKey]
2803
+ };
2804
+ }));
2730
2805
  for (const idp of idps) {
2731
2806
  const namespaceName = idp.name;
2807
+ const existing = existingServices[namespaceName];
2808
+ const metaRequest = await buildMetaRequest(trn$5(workspaceId, namespaceName), appName);
2732
2809
  let authorization;
2733
2810
  switch (idp.authorization) {
2734
2811
  case "insecure":
@@ -2741,27 +2818,40 @@ async function planServices$3(client, workspaceId, idps) {
2741
2818
  authorization = idp.authorization.cel;
2742
2819
  break;
2743
2820
  }
2744
- if (existingNameSet.has(namespaceName)) {
2821
+ if (existing) {
2822
+ if (!existing.label) unmanaged.push({
2823
+ resourceType: "IdP service",
2824
+ resourceName: idp.name
2825
+ });
2826
+ else if (existing.label !== appName) conflicts.push({
2827
+ resourceType: "IdP service",
2828
+ resourceName: idp.name,
2829
+ currentOwner: existing.label
2830
+ });
2745
2831
  changeSet.updates.push({
2746
2832
  name: namespaceName,
2747
2833
  request: {
2748
2834
  workspaceId,
2749
2835
  namespaceName,
2750
2836
  authorization
2751
- }
2837
+ },
2838
+ metaRequest
2752
2839
  });
2753
- existingNameSet.delete(namespaceName);
2840
+ delete existingServices[namespaceName];
2754
2841
  } else changeSet.creates.push({
2755
2842
  name: namespaceName,
2756
2843
  request: {
2757
2844
  workspaceId,
2758
2845
  namespaceName,
2759
2846
  authorization
2760
- }
2847
+ },
2848
+ metaRequest
2761
2849
  });
2762
2850
  }
2763
- existingNameSet.forEach((namespaceName) => {
2764
- changeSet.deletes.push({
2851
+ Object.entries(existingServices).forEach(([namespaceName]) => {
2852
+ const label = existingServices[namespaceName]?.label;
2853
+ if (label && label !== appName) resourceOwners.add(label);
2854
+ if (label === appName) changeSet.deletes.push({
2765
2855
  name: namespaceName,
2766
2856
  request: {
2767
2857
  workspaceId,
@@ -2769,7 +2859,12 @@ async function planServices$3(client, workspaceId, idps) {
2769
2859
  }
2770
2860
  });
2771
2861
  });
2772
- return changeSet;
2862
+ return {
2863
+ changeSet,
2864
+ conflicts,
2865
+ unmanaged,
2866
+ resourceOwners
2867
+ };
2773
2868
  }
2774
2869
  async function planClients(client, workspaceId, idps, deletedServices) {
2775
2870
  const changeSet = new ChangeSet("IdP clients");
@@ -2813,7 +2908,6 @@ async function planClients(client, workspaceId, idps, deletedServices) {
2813
2908
  });
2814
2909
  existingNameMap.forEach((name) => {
2815
2910
  changeSet.deletes.push({
2816
- tag: "client-deleted",
2817
2911
  name,
2818
2912
  request: {
2819
2913
  workspaceId,
@@ -2825,8 +2919,12 @@ async function planClients(client, workspaceId, idps, deletedServices) {
2825
2919
  }
2826
2920
  for (const namespaceName of deletedServices) (await fetchClients(namespaceName)).forEach((client$1) => {
2827
2921
  changeSet.deletes.push({
2828
- tag: "service-deleted",
2829
- name: client$1.name
2922
+ name: client$1.name,
2923
+ request: {
2924
+ workspaceId,
2925
+ namespaceName,
2926
+ name: client$1.name
2927
+ }
2830
2928
  });
2831
2929
  });
2832
2930
  return changeSet;
@@ -2834,9 +2932,13 @@ async function planClients(client, workspaceId, idps, deletedServices) {
2834
2932
 
2835
2933
  //#endregion
2836
2934
  //#region src/cli/apply/services/auth.ts
2837
- async function applyAuth(client, changeSet, phase = "create-update") {
2935
+ async function applyAuth(client, result, phase = "create-update") {
2936
+ const { changeSet } = result;
2838
2937
  if (phase === "create-update") {
2839
- await Promise.all(changeSet.service.creates.map((create) => client.createAuthService(create.request)));
2938
+ await Promise.all([...changeSet.service.creates.map(async (create) => {
2939
+ await client.createAuthService(create.request);
2940
+ await client.setMetadata(create.metaRequest);
2941
+ }), ...changeSet.service.updates.map((update) => client.setMetadata(update.metaRequest))]);
2840
2942
  await Promise.all([...changeSet.idpConfig.creates.map(async (create) => {
2841
2943
  if (create.idpConfig.kind === "BuiltInIdP") create.request.idpConfig.config = await protoBuiltinIdPConfig(client, create.request.workspaceId, create.idpConfig);
2842
2944
  return client.createAuthIDPConfig(create.request);
@@ -2857,23 +2959,23 @@ async function applyAuth(client, changeSet, phase = "create-update") {
2857
2959
  await Promise.all([...changeSet.scim.creates.map((create) => client.createAuthSCIMConfig(create.request)), ...changeSet.scim.updates.map((update) => client.updateAuthSCIMConfig(update.request))]);
2858
2960
  await Promise.all([...changeSet.scimResource.creates.map((create) => client.createAuthSCIMResource(create.request)), ...changeSet.scimResource.updates.map((update) => client.updateAuthSCIMResource(update.request))]);
2859
2961
  } else if (phase === "delete") {
2860
- await Promise.all(changeSet.scimResource.deletes.filter((del) => del.tag === "scim-resource-deleted").map((del) => client.deleteAuthSCIMResource(del.request)));
2861
- await Promise.all(changeSet.scim.deletes.filter((del) => del.tag === "scim-config-deleted").map((del) => client.deleteAuthSCIMConfig(del.request)));
2862
- await Promise.all(changeSet.oauth2Client.deletes.filter((del) => del.tag === "oauth2-client-deleted").map((del) => client.deleteAuthOAuth2Client(del.request)));
2863
- await Promise.all(changeSet.machineUser.deletes.filter((del) => del.tag === "machine-user-deleted").map((del) => client.deleteAuthMachineUser(del.request)));
2864
- await Promise.all(changeSet.tenantConfig.deletes.filter((del) => del.tag === "tenant-config-deleted").map((del) => client.deleteTenantConfig(del.request)));
2865
- await Promise.all(changeSet.userProfileConfig.deletes.filter((del) => del.tag === "user-profile-config-deleted").map((del) => client.deleteUserProfileConfig(del.request)));
2866
- await Promise.all(changeSet.idpConfig.deletes.filter((del) => del.tag === "idp-config-deleted").map((del) => client.deleteAuthIDPConfig(del.request)));
2962
+ await Promise.all(changeSet.scimResource.deletes.map((del) => client.deleteAuthSCIMResource(del.request)));
2963
+ await Promise.all(changeSet.scim.deletes.map((del) => client.deleteAuthSCIMConfig(del.request)));
2964
+ await Promise.all(changeSet.oauth2Client.deletes.map((del) => client.deleteAuthOAuth2Client(del.request)));
2965
+ await Promise.all(changeSet.machineUser.deletes.map((del) => client.deleteAuthMachineUser(del.request)));
2966
+ await Promise.all(changeSet.tenantConfig.deletes.map((del) => client.deleteTenantConfig(del.request)));
2967
+ await Promise.all(changeSet.userProfileConfig.deletes.map((del) => client.deleteUserProfileConfig(del.request)));
2968
+ await Promise.all(changeSet.idpConfig.deletes.map((del) => client.deleteAuthIDPConfig(del.request)));
2867
2969
  await Promise.all(changeSet.service.deletes.map((del) => client.deleteAuthService(del.request)));
2868
2970
  }
2869
2971
  }
2870
- async function planAuth(client, workspaceId, application) {
2972
+ async function planAuth({ client, workspaceId, application }) {
2871
2973
  const auths = [];
2872
- for (const app of application.applications) if (app.authService) {
2873
- await app.authService.resolveNamespaces();
2874
- auths.push(app.authService);
2974
+ if (application.authService) {
2975
+ await application.authService.resolveNamespaces();
2976
+ auths.push(application.authService);
2875
2977
  }
2876
- const serviceChangeSet = await planServices$2(client, workspaceId, auths);
2978
+ const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$2(client, workspaceId, application.name, auths);
2877
2979
  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
2878
2980
  const idpConfigChangeSet = await planIdPConfigs(client, workspaceId, auths, deletedServices);
2879
2981
  const userProfileConfigChangeSet = await planUserProfileConfigs(client, workspaceId, auths, deletedServices);
@@ -2891,19 +2993,30 @@ async function planAuth(client, workspaceId, application) {
2891
2993
  scimChangeSet.print();
2892
2994
  scimResourceChangeSet.print();
2893
2995
  return {
2894
- service: serviceChangeSet,
2895
- idpConfig: idpConfigChangeSet,
2896
- userProfileConfig: userProfileConfigChangeSet,
2897
- tenantConfig: tenantConfigChangeSet,
2898
- machineUser: machineUserChangeSet,
2899
- oauth2Client: oauth2ClientChangeSet,
2900
- scim: scimChangeSet,
2901
- scimResource: scimResourceChangeSet
2996
+ changeSet: {
2997
+ service: serviceChangeSet,
2998
+ idpConfig: idpConfigChangeSet,
2999
+ userProfileConfig: userProfileConfigChangeSet,
3000
+ tenantConfig: tenantConfigChangeSet,
3001
+ machineUser: machineUserChangeSet,
3002
+ oauth2Client: oauth2ClientChangeSet,
3003
+ scim: scimChangeSet,
3004
+ scimResource: scimResourceChangeSet
3005
+ },
3006
+ conflicts,
3007
+ unmanaged,
3008
+ resourceOwners
2902
3009
  };
2903
3010
  }
2904
- async function planServices$2(client, workspaceId, auths) {
3011
+ function trn$4(workspaceId, name) {
3012
+ return `trn:v1:workspace:${workspaceId}:auth:${name}`;
3013
+ }
3014
+ async function planServices$2(client, workspaceId, appName, auths) {
2905
3015
  const changeSet = new ChangeSet("Auth services");
2906
- const existingServices = await fetchAll(async (pageToken) => {
3016
+ const conflicts = [];
3017
+ const unmanaged = [];
3018
+ const resourceOwners = /* @__PURE__ */ new Set();
3019
+ const withoutLabel = await fetchAll(async (pageToken) => {
2907
3020
  try {
2908
3021
  const { authServices, nextPageToken } = await client.listAuthServices({
2909
3022
  workspaceId,
@@ -2915,23 +3028,46 @@ async function planServices$2(client, workspaceId, auths) {
2915
3028
  throw error;
2916
3029
  }
2917
3030
  });
2918
- const existingNameSet = /* @__PURE__ */ new Set();
2919
- existingServices.forEach((service) => {
2920
- const name = service.namespace?.name;
2921
- if (name) existingNameSet.add(name);
2922
- });
2923
- for (const { config } of auths) if (existingNameSet.has(config.name)) {
2924
- changeSet.updates.push({ name: config.name });
2925
- existingNameSet.delete(config.name);
2926
- } else changeSet.creates.push({
2927
- name: config.name,
2928
- request: {
2929
- workspaceId,
2930
- namespaceName: config.name
2931
- }
2932
- });
2933
- existingNameSet.forEach((namespaceName) => {
2934
- changeSet.deletes.push({
3031
+ const existingServices = {};
3032
+ await Promise.all(withoutLabel.map(async (resource) => {
3033
+ if (!resource.namespace?.name) return;
3034
+ const { metadata } = await client.getMetadata({ trn: trn$4(workspaceId, resource.namespace.name) });
3035
+ existingServices[resource.namespace.name] = {
3036
+ resource,
3037
+ label: metadata?.labels[sdkNameLabelKey]
3038
+ };
3039
+ }));
3040
+ for (const { config } of auths) {
3041
+ const existing = existingServices[config.name];
3042
+ const metaRequest = await buildMetaRequest(trn$4(workspaceId, config.name), appName);
3043
+ if (existing) {
3044
+ if (!existing.label) unmanaged.push({
3045
+ resourceType: "Auth service",
3046
+ resourceName: config.name
3047
+ });
3048
+ else if (existing.label !== appName) conflicts.push({
3049
+ resourceType: "Auth service",
3050
+ resourceName: config.name,
3051
+ currentOwner: existing.label
3052
+ });
3053
+ changeSet.updates.push({
3054
+ name: config.name,
3055
+ metaRequest
3056
+ });
3057
+ delete existingServices[config.name];
3058
+ } else changeSet.creates.push({
3059
+ name: config.name,
3060
+ request: {
3061
+ workspaceId,
3062
+ namespaceName: config.name
3063
+ },
3064
+ metaRequest
3065
+ });
3066
+ }
3067
+ Object.entries(existingServices).forEach(([namespaceName]) => {
3068
+ const label = existingServices[namespaceName]?.label;
3069
+ if (label && label !== appName) resourceOwners.add(label);
3070
+ if (label === appName) changeSet.deletes.push({
2935
3071
  name: namespaceName,
2936
3072
  request: {
2937
3073
  workspaceId,
@@ -2939,7 +3075,12 @@ async function planServices$2(client, workspaceId, auths) {
2939
3075
  }
2940
3076
  });
2941
3077
  });
2942
- return changeSet;
3078
+ return {
3079
+ changeSet,
3080
+ conflicts,
3081
+ unmanaged,
3082
+ resourceOwners
3083
+ };
2943
3084
  }
2944
3085
  async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
2945
3086
  const changeSet = new ChangeSet("Auth idpConfigs");
@@ -2987,7 +3128,6 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
2987
3128
  });
2988
3129
  existingNameSet.forEach((name) => {
2989
3130
  changeSet.deletes.push({
2990
- tag: "idp-config-deleted",
2991
3131
  name,
2992
3132
  request: {
2993
3133
  workspaceId,
@@ -2999,8 +3139,12 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
2999
3139
  }
3000
3140
  for (const namespaceName of deletedServices) (await fetchIdPConfigs(namespaceName)).forEach((idpConfig) => {
3001
3141
  changeSet.deletes.push({
3002
- tag: "service-deleted",
3003
- name: idpConfig.name
3142
+ name: idpConfig.name,
3143
+ request: {
3144
+ workspaceId,
3145
+ namespaceName,
3146
+ name: idpConfig.name
3147
+ }
3004
3148
  });
3005
3149
  });
3006
3150
  return changeSet;
@@ -3126,7 +3270,6 @@ async function planUserProfileConfigs(client, workspaceId, auths, deletedService
3126
3270
  }
3127
3271
  });
3128
3272
  else changeSet.deletes.push({
3129
- tag: "user-profile-config-deleted",
3130
3273
  name,
3131
3274
  request: {
3132
3275
  workspaceId,
@@ -3145,8 +3288,11 @@ async function planUserProfileConfigs(client, workspaceId, auths, deletedService
3145
3288
  throw error;
3146
3289
  }
3147
3290
  changeSet.deletes.push({
3148
- tag: "service-deleted",
3149
- name: `${namespaceName}-user-profile-config`
3291
+ name: `${namespaceName}-user-profile-config`,
3292
+ request: {
3293
+ workspaceId,
3294
+ namespaceName
3295
+ }
3150
3296
  });
3151
3297
  }
3152
3298
  return changeSet;
@@ -3201,7 +3347,6 @@ async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
3201
3347
  }
3202
3348
  });
3203
3349
  else changeSet.deletes.push({
3204
- tag: "tenant-config-deleted",
3205
3350
  name,
3206
3351
  request: {
3207
3352
  workspaceId,
@@ -3220,8 +3365,11 @@ async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
3220
3365
  throw error;
3221
3366
  }
3222
3367
  changeSet.deletes.push({
3223
- tag: "service-deleted",
3224
- name: `${namespaceName}-tenant-config`
3368
+ name: `${namespaceName}-tenant-config`,
3369
+ request: {
3370
+ workspaceId,
3371
+ namespaceName
3372
+ }
3225
3373
  });
3226
3374
  }
3227
3375
  return changeSet;
@@ -3290,7 +3438,6 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
3290
3438
  }
3291
3439
  existingNameSet.forEach((name) => {
3292
3440
  changeSet.deletes.push({
3293
- tag: "machine-user-deleted",
3294
3441
  name,
3295
3442
  request: {
3296
3443
  workspaceId,
@@ -3302,8 +3449,12 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
3302
3449
  }
3303
3450
  for (const namespaceName of deletedServices) (await fetchMachineUsers(namespaceName)).forEach((machineUser) => {
3304
3451
  changeSet.deletes.push({
3305
- tag: "service-deleted",
3306
- name: machineUser.name
3452
+ name: machineUser.name,
3453
+ request: {
3454
+ workspaceId,
3455
+ authNamespace: namespaceName,
3456
+ name: machineUser.name
3457
+ }
3307
3458
  });
3308
3459
  });
3309
3460
  return changeSet;
@@ -3360,7 +3511,6 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
3360
3511
  }
3361
3512
  existingNameSet.forEach((name) => {
3362
3513
  changeSet.deletes.push({
3363
- tag: "oauth2-client-deleted",
3364
3514
  name,
3365
3515
  request: {
3366
3516
  workspaceId,
@@ -3372,8 +3522,12 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
3372
3522
  }
3373
3523
  for (const namespaceName of deletedServices) (await fetchOAuth2Clients(namespaceName)).forEach((oauth2Client) => {
3374
3524
  changeSet.deletes.push({
3375
- tag: "service-deleted",
3376
- name: oauth2Client.name
3525
+ name: oauth2Client.name,
3526
+ request: {
3527
+ workspaceId,
3528
+ namespaceName,
3529
+ name: oauth2Client.name
3530
+ }
3377
3531
  });
3378
3532
  });
3379
3533
  return changeSet;
@@ -3429,7 +3583,6 @@ async function planSCIMConfigs(client, workspaceId, auths, deletedServices) {
3429
3583
  }
3430
3584
  });
3431
3585
  else changeSet.deletes.push({
3432
- tag: "scim-config-deleted",
3433
3586
  name,
3434
3587
  request: {
3435
3588
  workspaceId,
@@ -3448,8 +3601,11 @@ async function planSCIMConfigs(client, workspaceId, auths, deletedServices) {
3448
3601
  throw error;
3449
3602
  }
3450
3603
  changeSet.deletes.push({
3451
- tag: "service-deleted",
3452
- name: `${namespaceName}-scim-config`
3604
+ name: `${namespaceName}-scim-config`,
3605
+ request: {
3606
+ workspaceId,
3607
+ namespaceName
3608
+ }
3453
3609
  });
3454
3610
  }
3455
3611
  return changeSet;
@@ -3517,7 +3673,6 @@ async function planSCIMResources(client, workspaceId, auths, deletedServices) {
3517
3673
  });
3518
3674
  existingNameSet.forEach((name) => {
3519
3675
  changeSet.deletes.push({
3520
- tag: "scim-resource-deleted",
3521
3676
  name,
3522
3677
  request: {
3523
3678
  workspaceId,
@@ -3529,8 +3684,12 @@ async function planSCIMResources(client, workspaceId, auths, deletedServices) {
3529
3684
  }
3530
3685
  for (const namespaceName of deletedServices) (await fetchSCIMResources(namespaceName)).forEach((scimResource) => {
3531
3686
  changeSet.deletes.push({
3532
- tag: "service-deleted",
3533
- name: scimResource.name
3687
+ name: scimResource.name,
3688
+ request: {
3689
+ workspaceId,
3690
+ namespaceName,
3691
+ name: scimResource.name
3692
+ }
3534
3693
  });
3535
3694
  });
3536
3695
  return changeSet;
@@ -3609,15 +3768,72 @@ function protoSCIMAttribute(attr) {
3609
3768
  };
3610
3769
  }
3611
3770
 
3771
+ //#endregion
3772
+ //#region src/cli/apply/services/confirm.ts
3773
+ async function confirmOwnerConflict(conflicts, appName, yes) {
3774
+ if (conflicts.length === 0) return;
3775
+ const currentOwners = [...new Set(conflicts.map((c) => c.currentOwner))];
3776
+ consola.warn("Application name mismatch detected:");
3777
+ console.log(` ${chalk.yellow("Current application(s)")}: ${currentOwners.map((o) => chalk.bold(`"${o}"`)).join(", ")}`);
3778
+ console.log(` ${chalk.green("New application")}: ${chalk.bold(`"${appName}"`)}`);
3779
+ console.log("");
3780
+ console.log(` ${chalk.cyan("Resources")}:`);
3781
+ for (const c of conflicts) console.log(` • ${chalk.bold(c.resourceType)} ${chalk.cyan(`"${c.resourceName}"`)}`);
3782
+ if (yes) {
3783
+ consola.success("Updating resources (--yes flag specified)...");
3784
+ return;
3785
+ }
3786
+ const promptMessage = currentOwners.length === 1 ? `Update these resources to be managed by "${appName}"?\n${chalk.gray("(Common when renaming your application)")}` : `Update these resources to be managed by "${appName}"?`;
3787
+ if (!await consola.prompt(promptMessage, {
3788
+ type: "confirm",
3789
+ initial: false
3790
+ })) throw new Error(ml`
3791
+ Apply cancelled. Resources remain managed by their current applications.
3792
+ To override, run again and confirm, or use --yes flag.
3793
+ `);
3794
+ }
3795
+ async function confirmUnmanagedResources(resources, appName, yes) {
3796
+ if (resources.length === 0) return;
3797
+ consola.warn("Unmanaged resources detected:");
3798
+ console.log(` ${chalk.cyan("Resources")}:`);
3799
+ for (const r of resources) console.log(` • ${chalk.bold(r.resourceType)} ${chalk.cyan(`"${r.resourceName}"`)}`);
3800
+ console.log("");
3801
+ console.log(" These resources are not managed by any application.");
3802
+ if (yes) {
3803
+ consola.success(`Adding to "${appName}" (--yes flag specified)...`);
3804
+ return;
3805
+ }
3806
+ if (!await consola.prompt(`Add these resources to "${appName}"?`, {
3807
+ type: "confirm",
3808
+ initial: false
3809
+ })) throw new Error(ml`
3810
+ Apply cancelled. Resources remain unmanaged.
3811
+ To override, run again and confirm, or use --yes flag.
3812
+ `);
3813
+ }
3814
+
3612
3815
  //#endregion
3613
3816
  //#region src/cli/apply/services/executor.ts
3614
- async function applyExecutor(client, changeSet, phase = "create-update") {
3615
- if (phase === "create-update") await Promise.all([...changeSet.creates.map((create) => client.createExecutorExecutor(create.request)), ...changeSet.updates.map((update) => client.updateExecutorExecutor(update.request))]);
3817
+ async function applyExecutor(client, result, phase = "create-update") {
3818
+ const { changeSet } = result;
3819
+ if (phase === "create-update") await Promise.all([...changeSet.creates.map(async (create) => {
3820
+ await client.createExecutorExecutor(create.request);
3821
+ await client.setMetadata(create.metaRequest);
3822
+ }), ...changeSet.updates.map(async (update) => {
3823
+ await client.updateExecutorExecutor(update.request);
3824
+ await client.setMetadata(update.metaRequest);
3825
+ })]);
3616
3826
  else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteExecutorExecutor(del.request)));
3617
3827
  }
3618
- async function planExecutor(client, workspaceId, application) {
3828
+ function trn$3(workspaceId, name) {
3829
+ return `trn:v1:workspace:${workspaceId}:executor:${name}`;
3830
+ }
3831
+ async function planExecutor({ client, workspaceId, application }) {
3619
3832
  const changeSet = new ChangeSet("Executors");
3620
- const existingExecutors = await fetchAll(async (pageToken) => {
3833
+ const conflicts = [];
3834
+ const unmanaged = [];
3835
+ const resourceOwners = /* @__PURE__ */ new Set();
3836
+ const withoutLabel = await fetchAll(async (pageToken) => {
3621
3837
  try {
3622
3838
  const { executors: executors$1, nextPageToken } = await client.listExecutorExecutors({
3623
3839
  workspaceId,
@@ -3629,29 +3845,50 @@ async function planExecutor(client, workspaceId, application) {
3629
3845
  throw error;
3630
3846
  }
3631
3847
  });
3632
- const existingNameSet = /* @__PURE__ */ new Set();
3633
- existingExecutors.forEach((executor) => {
3634
- existingNameSet.add(executor.name);
3635
- });
3848
+ const existingExecutors = {};
3849
+ await Promise.all(withoutLabel.map(async (resource) => {
3850
+ const { metadata } = await client.getMetadata({ trn: trn$3(workspaceId, resource.name) });
3851
+ existingExecutors[resource.name] = {
3852
+ resource,
3853
+ label: metadata?.labels[sdkNameLabelKey]
3854
+ };
3855
+ }));
3636
3856
  const executors = await application.executorService?.loadExecutors() ?? {};
3637
- for (const executor of Object.values(executors)) if (existingNameSet.has(executor.name)) {
3638
- changeSet.updates.push({
3857
+ for (const executor of Object.values(executors)) {
3858
+ const existing = existingExecutors[executor.name];
3859
+ const metaRequest = await buildMetaRequest(trn$3(workspaceId, executor.name), application.name);
3860
+ if (existing) {
3861
+ if (!existing.label) unmanaged.push({
3862
+ resourceType: "Executor",
3863
+ resourceName: executor.name
3864
+ });
3865
+ else if (existing.label !== application.name) conflicts.push({
3866
+ resourceType: "Executor",
3867
+ resourceName: executor.name,
3868
+ currentOwner: existing.label
3869
+ });
3870
+ changeSet.updates.push({
3871
+ name: executor.name,
3872
+ request: {
3873
+ workspaceId,
3874
+ executor: protoExecutor(executor)
3875
+ },
3876
+ metaRequest
3877
+ });
3878
+ delete existingExecutors[executor.name];
3879
+ } else changeSet.creates.push({
3639
3880
  name: executor.name,
3640
3881
  request: {
3641
3882
  workspaceId,
3642
3883
  executor: protoExecutor(executor)
3643
- }
3884
+ },
3885
+ metaRequest
3644
3886
  });
3645
- existingNameSet.delete(executor.name);
3646
- } else changeSet.creates.push({
3647
- name: executor.name,
3648
- request: {
3649
- workspaceId,
3650
- executor: protoExecutor(executor)
3651
- }
3652
- });
3653
- existingNameSet.forEach((name) => {
3654
- changeSet.deletes.push({
3887
+ }
3888
+ Object.entries(existingExecutors).forEach(([name]) => {
3889
+ const label = existingExecutors[name]?.label;
3890
+ if (label && label !== application.name) resourceOwners.add(label);
3891
+ if (label === application.name) changeSet.deletes.push({
3655
3892
  name,
3656
3893
  request: {
3657
3894
  workspaceId,
@@ -3660,7 +3897,12 @@ async function planExecutor(client, workspaceId, application) {
3660
3897
  });
3661
3898
  });
3662
3899
  changeSet.print();
3663
- return changeSet;
3900
+ return {
3901
+ changeSet,
3902
+ conflicts,
3903
+ unmanaged,
3904
+ resourceOwners
3905
+ };
3664
3906
  }
3665
3907
  function protoExecutor(executor) {
3666
3908
  const trigger = executor.trigger;
@@ -3830,35 +4072,53 @@ const SCALAR_TYPE_MAP = {
3830
4072
  name: "Time"
3831
4073
  }
3832
4074
  };
3833
- async function applyPipeline(client, changeSet, phase = "create-update") {
4075
+ async function applyPipeline(client, result, phase = "create-update") {
4076
+ const { changeSet } = result;
3834
4077
  if (phase === "create-update") {
3835
- await Promise.all([...changeSet.service.creates.map((create) => client.createPipelineService(create.request)), ...changeSet.service.updates.map((update) => client.updatePipelineService(update.request))]);
4078
+ await Promise.all([...changeSet.service.creates.map(async (create) => {
4079
+ await client.createPipelineService(create.request);
4080
+ await client.setMetadata(create.metaRequest);
4081
+ }), ...changeSet.service.updates.map(async (update) => {
4082
+ await client.updatePipelineService(update.request);
4083
+ await client.setMetadata(update.metaRequest);
4084
+ })]);
3836
4085
  await Promise.all([...changeSet.resolver.creates.map((create) => client.createPipelineResolver(create.request)), ...changeSet.resolver.updates.map((update) => client.updatePipelineResolver(update.request))]);
3837
4086
  } else if (phase === "delete") {
3838
- await Promise.all(changeSet.resolver.deletes.filter((del) => del.tag === "resolver-deleted").map((del) => client.deletePipelineResolver(del.request)));
4087
+ await Promise.all(changeSet.resolver.deletes.map((del) => client.deletePipelineResolver(del.request)));
3839
4088
  await Promise.all(changeSet.service.deletes.map((del) => client.deletePipelineService(del.request)));
3840
4089
  }
3841
4090
  }
3842
- async function planPipeline(client, workspaceId, application) {
4091
+ async function planPipeline({ client, workspaceId, application }) {
3843
4092
  const pipelines = [];
3844
- for (const app of application.applications) for (const pipeline of app.resolverServices) {
4093
+ for (const pipeline of application.resolverServices) {
3845
4094
  await pipeline.loadResolvers();
3846
4095
  pipelines.push(pipeline);
3847
4096
  }
3848
4097
  const executors = Object.values(await application.executorService?.loadExecutors() ?? {});
3849
- const serviceChangeSet = await planServices$1(client, workspaceId, pipelines);
4098
+ const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$1(client, workspaceId, application.name, pipelines);
3850
4099
  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
3851
4100
  const resolverChangeSet = await planResolvers(client, workspaceId, pipelines, executors, deletedServices);
3852
4101
  serviceChangeSet.print();
3853
4102
  resolverChangeSet.print();
3854
4103
  return {
3855
- service: serviceChangeSet,
3856
- resolver: resolverChangeSet
4104
+ changeSet: {
4105
+ service: serviceChangeSet,
4106
+ resolver: resolverChangeSet
4107
+ },
4108
+ conflicts,
4109
+ unmanaged,
4110
+ resourceOwners
3857
4111
  };
3858
4112
  }
3859
- async function planServices$1(client, workspaceId, pipelines) {
4113
+ function trn$2(workspaceId, name) {
4114
+ return `trn:v1:workspace:${workspaceId}:pipeline:${name}`;
4115
+ }
4116
+ async function planServices$1(client, workspaceId, appName, pipelines) {
3860
4117
  const changeSet = new ChangeSet("Pipeline services");
3861
- const existingServices = await fetchAll(async (pageToken) => {
4118
+ const conflicts = [];
4119
+ const unmanaged = [];
4120
+ const resourceOwners = /* @__PURE__ */ new Set();
4121
+ const withoutLabel = await fetchAll(async (pageToken) => {
3862
4122
  try {
3863
4123
  const { pipelineServices, nextPageToken } = await client.listPipelineServices({
3864
4124
  workspaceId,
@@ -3870,29 +4130,50 @@ async function planServices$1(client, workspaceId, pipelines) {
3870
4130
  throw error;
3871
4131
  }
3872
4132
  });
3873
- const existingNameSet = /* @__PURE__ */ new Set();
3874
- existingServices.forEach((service) => {
3875
- const name = service.namespace?.name;
3876
- if (name) existingNameSet.add(name);
3877
- });
3878
- for (const pipeline of pipelines) if (existingNameSet.has(pipeline.namespace)) {
3879
- changeSet.updates.push({
4133
+ const existingServices = {};
4134
+ await Promise.all(withoutLabel.map(async (resource) => {
4135
+ if (!resource.namespace?.name) return;
4136
+ const { metadata } = await client.getMetadata({ trn: trn$2(workspaceId, resource.namespace.name) });
4137
+ existingServices[resource.namespace.name] = {
4138
+ resource,
4139
+ label: metadata?.labels[sdkNameLabelKey]
4140
+ };
4141
+ }));
4142
+ for (const pipeline of pipelines) {
4143
+ const existing = existingServices[pipeline.namespace];
4144
+ const metaRequest = await buildMetaRequest(trn$2(workspaceId, pipeline.namespace), appName);
4145
+ if (existing) {
4146
+ if (!existing.label) unmanaged.push({
4147
+ resourceType: "Pipeline service",
4148
+ resourceName: pipeline.namespace
4149
+ });
4150
+ else if (existing.label !== appName) conflicts.push({
4151
+ resourceType: "Pipeline service",
4152
+ resourceName: pipeline.namespace,
4153
+ currentOwner: existing.label
4154
+ });
4155
+ changeSet.updates.push({
4156
+ name: pipeline.namespace,
4157
+ request: {
4158
+ workspaceId,
4159
+ namespaceName: pipeline.namespace
4160
+ },
4161
+ metaRequest
4162
+ });
4163
+ delete existingServices[pipeline.namespace];
4164
+ } else changeSet.creates.push({
3880
4165
  name: pipeline.namespace,
3881
4166
  request: {
3882
4167
  workspaceId,
3883
4168
  namespaceName: pipeline.namespace
3884
- }
4169
+ },
4170
+ metaRequest
3885
4171
  });
3886
- existingNameSet.delete(pipeline.namespace);
3887
- } else changeSet.creates.push({
3888
- name: pipeline.namespace,
3889
- request: {
3890
- workspaceId,
3891
- namespaceName: pipeline.namespace
3892
- }
3893
- });
3894
- existingNameSet.forEach((namespaceName) => {
3895
- changeSet.deletes.push({
4172
+ }
4173
+ Object.entries(existingServices).forEach(([namespaceName]) => {
4174
+ const label = existingServices[namespaceName]?.label;
4175
+ if (label && label !== appName) resourceOwners.add(label);
4176
+ if (label === appName) changeSet.deletes.push({
3896
4177
  name: namespaceName,
3897
4178
  request: {
3898
4179
  workspaceId,
@@ -3900,7 +4181,12 @@ async function planServices$1(client, workspaceId, pipelines) {
3900
4181
  }
3901
4182
  });
3902
4183
  });
3903
- return changeSet;
4184
+ return {
4185
+ changeSet,
4186
+ conflicts,
4187
+ unmanaged,
4188
+ resourceOwners
4189
+ };
3904
4190
  }
3905
4191
  async function planResolvers(client, workspaceId, pipelines, executors, deletedServices) {
3906
4192
  const changeSet = new ChangeSet("Pipeline resolvers");
@@ -3947,7 +4233,6 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
3947
4233
  });
3948
4234
  existingNameSet.forEach((name) => {
3949
4235
  changeSet.deletes.push({
3950
- tag: "resolver-deleted",
3951
4236
  name,
3952
4237
  request: {
3953
4238
  workspaceId,
@@ -3959,8 +4244,12 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
3959
4244
  }
3960
4245
  for (const namespaceName of deletedServices) (await fetchResolvers(namespaceName)).forEach((resolver) => {
3961
4246
  changeSet.deletes.push({
3962
- tag: "service-deleted",
3963
- name: resolver.name
4247
+ name: resolver.name,
4248
+ request: {
4249
+ workspaceId,
4250
+ namespaceName,
4251
+ resolverName: resolver.name
4252
+ }
3964
4253
  });
3965
4254
  });
3966
4255
  return changeSet;
@@ -4034,13 +4323,26 @@ function protoFields(fields, baseName, isInput) {
4034
4323
 
4035
4324
  //#endregion
4036
4325
  //#region src/cli/apply/services/staticwebsite.ts
4037
- async function applyStaticWebsite(client, changeSet, phase = "create-update") {
4038
- if (phase === "create-update") await Promise.all([...changeSet.creates.map((create) => client.createStaticWebsite(create.request)), ...changeSet.updates.map((update) => client.updateStaticWebsite(update.request))]);
4326
+ async function applyStaticWebsite(client, result, phase = "create-update") {
4327
+ const { changeSet } = result;
4328
+ if (phase === "create-update") await Promise.all([...changeSet.creates.map(async (create) => {
4329
+ await client.createStaticWebsite(create.request);
4330
+ await client.setMetadata(create.metaRequest);
4331
+ }), ...changeSet.updates.map(async (update) => {
4332
+ await client.updateStaticWebsite(update.request);
4333
+ await client.setMetadata(update.metaRequest);
4334
+ })]);
4039
4335
  else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteStaticWebsite(del.request)));
4040
4336
  }
4041
- async function planStaticWebsite(client, workspaceId, application) {
4337
+ function trn$1(workspaceId, name) {
4338
+ return `trn:v1:workspace:${workspaceId}:staticwebsite:${name}`;
4339
+ }
4340
+ async function planStaticWebsite({ client, workspaceId, application }) {
4042
4341
  const changeSet = new ChangeSet("StaticWebsites");
4043
- const existingWebsites = await fetchAll(async (pageToken) => {
4342
+ const conflicts = [];
4343
+ const unmanaged = [];
4344
+ const resourceOwners = /* @__PURE__ */ new Set();
4345
+ const withoutLabel = await fetchAll(async (pageToken) => {
4044
4346
  try {
4045
4347
  const { staticwebsites, nextPageToken } = await client.listStaticWebsites({
4046
4348
  workspaceId,
@@ -4052,14 +4354,29 @@ async function planStaticWebsite(client, workspaceId, application) {
4052
4354
  throw error;
4053
4355
  }
4054
4356
  });
4055
- const existingNameSet = /* @__PURE__ */ new Set();
4056
- existingWebsites.forEach((website) => {
4057
- existingNameSet.add(website.name);
4058
- });
4357
+ const existingWebsites = {};
4358
+ await Promise.all(withoutLabel.map(async (resource) => {
4359
+ const { metadata } = await client.getMetadata({ trn: trn$1(workspaceId, resource.name) });
4360
+ existingWebsites[resource.name] = {
4361
+ resource,
4362
+ label: metadata?.labels[sdkNameLabelKey]
4363
+ };
4364
+ }));
4059
4365
  for (const websiteService of application.staticWebsiteServices) {
4060
4366
  const config = websiteService;
4061
4367
  const name = websiteService.name;
4062
- if (existingNameSet.has(name)) {
4368
+ const existing = existingWebsites[name];
4369
+ const metaRequest = await buildMetaRequest(trn$1(workspaceId, name), application.name);
4370
+ if (existing) {
4371
+ if (!existing.label) unmanaged.push({
4372
+ resourceType: "StaticWebsite",
4373
+ resourceName: name
4374
+ });
4375
+ else if (existing.label !== application.name) conflicts.push({
4376
+ resourceType: "StaticWebsite",
4377
+ resourceName: name,
4378
+ currentOwner: existing.label
4379
+ });
4063
4380
  changeSet.updates.push({
4064
4381
  name,
4065
4382
  request: {
@@ -4069,9 +4386,10 @@ async function planStaticWebsite(client, workspaceId, application) {
4069
4386
  description: config.description || "",
4070
4387
  allowedIpAddresses: config.allowedIpAddresses || []
4071
4388
  }
4072
- }
4389
+ },
4390
+ metaRequest
4073
4391
  });
4074
- existingNameSet.delete(name);
4392
+ delete existingWebsites[name];
4075
4393
  } else changeSet.creates.push({
4076
4394
  name,
4077
4395
  request: {
@@ -4081,11 +4399,14 @@ async function planStaticWebsite(client, workspaceId, application) {
4081
4399
  description: config.description || "",
4082
4400
  allowedIpAddresses: config.allowedIpAddresses || []
4083
4401
  }
4084
- }
4402
+ },
4403
+ metaRequest
4085
4404
  });
4086
4405
  }
4087
- existingNameSet.forEach((name) => {
4088
- changeSet.deletes.push({
4406
+ Object.entries(existingWebsites).forEach(([name]) => {
4407
+ const label = existingWebsites[name]?.label;
4408
+ if (label && label !== application.name) resourceOwners.add(label);
4409
+ if (label === application.name) changeSet.deletes.push({
4089
4410
  name,
4090
4411
  request: {
4091
4412
  workspaceId,
@@ -4094,30 +4415,39 @@ async function planStaticWebsite(client, workspaceId, application) {
4094
4415
  });
4095
4416
  });
4096
4417
  changeSet.print();
4097
- return changeSet;
4418
+ return {
4419
+ changeSet,
4420
+ conflicts,
4421
+ unmanaged,
4422
+ resourceOwners
4423
+ };
4098
4424
  }
4099
4425
 
4100
4426
  //#endregion
4101
4427
  //#region src/cli/apply/services/tailordb.ts
4102
- async function applyTailorDB(client, changeSet, phase = "create-update") {
4428
+ async function applyTailorDB(client, result, phase = "create-update") {
4429
+ const { changeSet } = result;
4103
4430
  if (phase === "create-update") {
4104
- await Promise.all(changeSet.service.creates.map((create) => client.createTailorDBService(create.request)));
4431
+ await Promise.all([...changeSet.service.creates.map(async (create) => {
4432
+ await client.createTailorDBService(create.request);
4433
+ await client.setMetadata(create.metaRequest);
4434
+ }), ...changeSet.service.updates.map((update) => client.setMetadata(update.metaRequest))]);
4105
4435
  await Promise.all([...changeSet.type.creates.map((create) => client.createTailorDBType(create.request)), ...changeSet.type.updates.map((update) => client.updateTailorDBType(update.request))]);
4106
4436
  await Promise.all([...changeSet.gqlPermission.creates.map((create) => client.createTailorDBGQLPermission(create.request)), ...changeSet.gqlPermission.updates.map((update) => client.updateTailorDBGQLPermission(update.request))]);
4107
4437
  } else if (phase === "delete") {
4108
- await Promise.all(changeSet.gqlPermission.deletes.filter((del) => del.tag === "gql-permission-deleted").map((del) => client.deleteTailorDBGQLPermission(del.request)));
4109
- await Promise.all(changeSet.type.deletes.filter((del) => del.tag === "type-deleted").map((del) => client.deleteTailorDBType(del.request)));
4438
+ await Promise.all(changeSet.gqlPermission.deletes.map((del) => client.deleteTailorDBGQLPermission(del.request)));
4439
+ await Promise.all(changeSet.type.deletes.map((del) => client.deleteTailorDBType(del.request)));
4110
4440
  await Promise.all(changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)));
4111
4441
  }
4112
4442
  }
4113
- async function planTailorDB(client, workspaceId, application) {
4443
+ async function planTailorDB({ client, workspaceId, application }) {
4114
4444
  const tailordbs = [];
4115
- for (const app of application.applications) for (const tailordb of app.tailorDBServices) {
4445
+ for (const tailordb of application.tailorDBServices) {
4116
4446
  await tailordb.loadTypes();
4117
4447
  tailordbs.push(tailordb);
4118
4448
  }
4119
4449
  const executors = Object.values(await application.executorService?.loadExecutors() ?? {});
4120
- const serviceChangeSet = await planServices(client, workspaceId, tailordbs);
4450
+ const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices(client, workspaceId, application.name, tailordbs);
4121
4451
  const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
4122
4452
  const typeChangeSet = await planTypes(client, workspaceId, tailordbs, executors, deletedServices);
4123
4453
  const gqlPermissionChangeSet = await planGqlPermissions(client, workspaceId, tailordbs, deletedServices);
@@ -4125,14 +4455,25 @@ async function planTailorDB(client, workspaceId, application) {
4125
4455
  typeChangeSet.print();
4126
4456
  gqlPermissionChangeSet.print();
4127
4457
  return {
4128
- service: serviceChangeSet,
4129
- type: typeChangeSet,
4130
- gqlPermission: gqlPermissionChangeSet
4458
+ changeSet: {
4459
+ service: serviceChangeSet,
4460
+ type: typeChangeSet,
4461
+ gqlPermission: gqlPermissionChangeSet
4462
+ },
4463
+ conflicts,
4464
+ unmanaged,
4465
+ resourceOwners
4131
4466
  };
4132
4467
  }
4133
- async function planServices(client, workspaceId, tailordbs) {
4468
+ function trn(workspaceId, name) {
4469
+ return `${trnPrefix(workspaceId)}:tailordb:${name}`;
4470
+ }
4471
+ async function planServices(client, workspaceId, appName, tailordbs) {
4134
4472
  const changeSet = new ChangeSet("TailorDB services");
4135
- const existingServices = await fetchAll(async (pageToken) => {
4473
+ const conflicts = [];
4474
+ const unmanaged = [];
4475
+ const resourceOwners = /* @__PURE__ */ new Set();
4476
+ const withoutLabel = await fetchAll(async (pageToken) => {
4136
4477
  try {
4137
4478
  const { tailordbServices, nextPageToken } = await client.listTailorDBServices({
4138
4479
  workspaceId,
@@ -4144,24 +4485,47 @@ async function planServices(client, workspaceId, tailordbs) {
4144
4485
  throw error;
4145
4486
  }
4146
4487
  });
4147
- const existingNameSet = /* @__PURE__ */ new Set();
4148
- existingServices.forEach((service) => {
4149
- const name = service.namespace?.name;
4150
- if (name) existingNameSet.add(name);
4151
- });
4152
- for (const tailordb of tailordbs) if (existingNameSet.has(tailordb.namespace)) {
4153
- changeSet.updates.push({ name: tailordb.namespace });
4154
- existingNameSet.delete(tailordb.namespace);
4155
- } else changeSet.creates.push({
4156
- name: tailordb.namespace,
4157
- request: {
4158
- workspaceId,
4159
- namespaceName: tailordb.namespace,
4160
- defaultTimezone: "UTC"
4161
- }
4162
- });
4163
- existingNameSet.forEach((namespaceName) => {
4164
- changeSet.deletes.push({
4488
+ const existingServices = {};
4489
+ await Promise.all(withoutLabel.map(async (resource) => {
4490
+ if (!resource.namespace?.name) return;
4491
+ const { metadata } = await client.getMetadata({ trn: trn(workspaceId, resource.namespace.name) });
4492
+ existingServices[resource.namespace.name] = {
4493
+ resource,
4494
+ label: metadata?.labels[sdkNameLabelKey]
4495
+ };
4496
+ }));
4497
+ for (const tailordb of tailordbs) {
4498
+ const existing = existingServices[tailordb.namespace];
4499
+ const metaRequest = await buildMetaRequest(trn(workspaceId, tailordb.namespace), appName);
4500
+ if (existing) {
4501
+ if (!existing.label) unmanaged.push({
4502
+ resourceType: "TailorDB service",
4503
+ resourceName: tailordb.namespace
4504
+ });
4505
+ else if (existing.label !== appName) conflicts.push({
4506
+ resourceType: "TailorDB service",
4507
+ resourceName: tailordb.namespace,
4508
+ currentOwner: existing.label
4509
+ });
4510
+ changeSet.updates.push({
4511
+ name: tailordb.namespace,
4512
+ metaRequest
4513
+ });
4514
+ delete existingServices[tailordb.namespace];
4515
+ } else changeSet.creates.push({
4516
+ name: tailordb.namespace,
4517
+ request: {
4518
+ workspaceId,
4519
+ namespaceName: tailordb.namespace,
4520
+ defaultTimezone: "UTC"
4521
+ },
4522
+ metaRequest
4523
+ });
4524
+ }
4525
+ Object.entries(existingServices).forEach(([namespaceName]) => {
4526
+ const label = existingServices[namespaceName]?.label;
4527
+ if (label && label !== appName) resourceOwners.add(label);
4528
+ if (label === appName) changeSet.deletes.push({
4165
4529
  name: namespaceName,
4166
4530
  request: {
4167
4531
  workspaceId,
@@ -4169,7 +4533,12 @@ async function planServices(client, workspaceId, tailordbs) {
4169
4533
  }
4170
4534
  });
4171
4535
  });
4172
- return changeSet;
4536
+ return {
4537
+ changeSet,
4538
+ conflicts,
4539
+ unmanaged,
4540
+ resourceOwners
4541
+ };
4173
4542
  }
4174
4543
  async function planTypes(client, workspaceId, tailordbs, executors, deletedServices) {
4175
4544
  const changeSet = new ChangeSet("TailorDB types");
@@ -4218,7 +4587,6 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
4218
4587
  }
4219
4588
  existingNameSet.forEach((name) => {
4220
4589
  changeSet.deletes.push({
4221
- tag: "type-deleted",
4222
4590
  name,
4223
4591
  request: {
4224
4592
  workspaceId,
@@ -4230,8 +4598,12 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
4230
4598
  }
4231
4599
  for (const namespaceName of deletedServices) (await fetchTypes(namespaceName)).forEach((typ) => {
4232
4600
  changeSet.deletes.push({
4233
- tag: "service-deleted",
4234
- name: typ.name
4601
+ name: typ.name,
4602
+ request: {
4603
+ workspaceId,
4604
+ namespaceName,
4605
+ tailordbTypeName: typ.name
4606
+ }
4235
4607
  });
4236
4608
  });
4237
4609
  return changeSet;
@@ -4489,7 +4861,6 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
4489
4861
  }
4490
4862
  existingNameSet.forEach((name) => {
4491
4863
  changeSet.deletes.push({
4492
- tag: "gql-permission-deleted",
4493
4864
  name,
4494
4865
  request: {
4495
4866
  workspaceId,
@@ -4501,8 +4872,12 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
4501
4872
  }
4502
4873
  for (const namespaceName of deletedServices) (await fetchGqlPermissions(namespaceName)).forEach((gqlPermission) => {
4503
4874
  changeSet.deletes.push({
4504
- tag: "service-deleted",
4505
- name: gqlPermission.typeName
4875
+ name: gqlPermission.typeName,
4876
+ request: {
4877
+ workspaceId,
4878
+ namespaceName,
4879
+ typeName: gqlPermission.typeName
4880
+ }
4506
4881
  });
4507
4882
  });
4508
4883
  return changeSet;
@@ -4597,6 +4972,7 @@ async function apply(options) {
4597
4972
  const configPath = loadConfigPath(options?.configPath);
4598
4973
  const { config } = await loadConfig(configPath);
4599
4974
  const dryRun = options?.dryRun ?? false;
4975
+ const yes = options?.yes ?? false;
4600
4976
  const buildOnly = options?.buildOnly ?? false;
4601
4977
  await generateUserTypes(config, configPath);
4602
4978
  const application = defineApplication(config);
@@ -4612,13 +4988,56 @@ async function apply(options) {
4612
4988
  workspaceId: options?.workspaceId,
4613
4989
  profile: options?.profile
4614
4990
  });
4615
- const tailorDB = await planTailorDB(client, workspaceId, application);
4616
- const staticWebsite = await planStaticWebsite(client, workspaceId, application);
4617
- const idp = await planIdP(client, workspaceId, application);
4618
- const auth = await planAuth(client, workspaceId, application);
4619
- const pipeline = await planPipeline(client, workspaceId, application);
4620
- const app = await planApplication(client, workspaceId, application);
4621
- const executor = await planExecutor(client, workspaceId, application);
4991
+ for (const tailordb of application.tailorDBServices) await tailordb.loadTypes();
4992
+ for (const pipeline$1 of application.resolverServices) await pipeline$1.loadResolvers();
4993
+ if (application.executorService) await application.executorService.loadExecutors();
4994
+ console.log("");
4995
+ const ctx = {
4996
+ client,
4997
+ workspaceId,
4998
+ application
4999
+ };
5000
+ const tailorDB = await planTailorDB(ctx);
5001
+ const staticWebsite = await planStaticWebsite(ctx);
5002
+ const idp = await planIdP(ctx);
5003
+ const auth = await planAuth(ctx);
5004
+ const pipeline = await planPipeline(ctx);
5005
+ const app = await planApplication(ctx);
5006
+ const executor = await planExecutor(ctx);
5007
+ const allConflicts = [
5008
+ ...tailorDB.conflicts,
5009
+ ...staticWebsite.conflicts,
5010
+ ...idp.conflicts,
5011
+ ...auth.conflicts,
5012
+ ...pipeline.conflicts,
5013
+ ...executor.conflicts
5014
+ ];
5015
+ const allUnmanaged = [
5016
+ ...tailorDB.unmanaged,
5017
+ ...staticWebsite.unmanaged,
5018
+ ...idp.unmanaged,
5019
+ ...auth.unmanaged,
5020
+ ...pipeline.unmanaged,
5021
+ ...executor.unmanaged
5022
+ ];
5023
+ await confirmOwnerConflict(allConflicts, application.name, yes);
5024
+ await confirmUnmanagedResources(allUnmanaged, application.name, yes);
5025
+ const resourceOwners = new Set([
5026
+ ...tailorDB.resourceOwners,
5027
+ ...staticWebsite.resourceOwners,
5028
+ ...idp.resourceOwners,
5029
+ ...auth.resourceOwners,
5030
+ ...pipeline.resourceOwners,
5031
+ ...executor.resourceOwners
5032
+ ]);
5033
+ const emptyApps = [...new Set(allConflicts.map((c) => c.currentOwner))].filter((owner) => !resourceOwners.has(owner));
5034
+ for (const emptyApp of emptyApps) app.deletes.push({
5035
+ name: emptyApp,
5036
+ request: {
5037
+ workspaceId,
5038
+ applicationName: emptyApp
5039
+ }
5040
+ });
4622
5041
  if (dryRun) {
4623
5042
  console.log("Dry run enabled. No changes applied.");
4624
5043
  return;
@@ -4693,6 +5112,11 @@ const applyCommand = defineCommand({
4693
5112
  type: "boolean",
4694
5113
  description: "Run the command without making any changes",
4695
5114
  alias: "d"
5115
+ },
5116
+ yes: {
5117
+ type: "boolean",
5118
+ description: "Skip all confirmation prompts",
5119
+ alias: "y"
4696
5120
  }
4697
5121
  },
4698
5122
  run: withCommonArgs(async (args) => {
@@ -4700,7 +5124,8 @@ const applyCommand = defineCommand({
4700
5124
  workspaceId: args["workspace-id"],
4701
5125
  profile: args.profile,
4702
5126
  configPath: args.config,
4703
- dryRun: args.dryRun
5127
+ dryRun: args.dryRun,
5128
+ yes: args.yes
4704
5129
  });
4705
5130
  })
4706
5131
  });
@@ -5824,4 +6249,4 @@ const tokenCommand = defineCommand({
5824
6249
  });
5825
6250
 
5826
6251
  //#endregion
5827
- export { PATScope, apply, applyCommand, commonArgs, createCommand, deleteCommand, fetchAll, fetchLatestToken, formatArgs, generate, generateCommand, generateUserTypes, initOperatorClient, listCommand, listCommand$1, loadAccessToken, loadConfig, loadConfigPath, loadWorkspaceId, machineUserList, machineUserToken, parseFormat, printWithFormat, readPlatformConfig, show, showCommand, tokenCommand, userAgent, withCommonArgs, workspaceCreate, workspaceDelete, workspaceList, writePlatformConfig };
6252
+ export { PATScope, apply, applyCommand, commonArgs, createCommand, deleteCommand, fetchAll, fetchLatestToken, formatArgs, generate, generateCommand, generateUserTypes, initOperatorClient, listCommand, listCommand$1, loadAccessToken, loadConfig, loadConfigPath, loadWorkspaceId, machineUserList, machineUserToken, parseFormat, printWithFormat, readPackageJson, readPlatformConfig, show, showCommand, tokenCommand, userAgent, withCommonArgs, workspaceCreate, workspaceDelete, workspaceList, writePlatformConfig };