@mesh-tech/mesh-cli 0.40.10 → 0.40.11

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 (53) hide show
  1. package/dist/bin/{mesh.auth-preflight-RCZH7V34.js → mesh.auth-preflight-BGI5LPLN.js} +1 -1
  2. package/dist/bin/{mesh.chunk-TFOKVJ34.js → mesh.chunk-3WJGDNHA.js} +71 -27
  3. package/dist/bin/mesh.chunk-3WJGDNHA.js.map +6 -0
  4. package/dist/bin/{mesh.chunk-SEIVILJR.js → mesh.chunk-4XX62O6Z.js} +1 -1
  5. package/dist/bin/{mesh.chunk-SOX2CJMU.js → mesh.chunk-DYWR76EO.js} +1 -1
  6. package/dist/bin/{mesh.chunk-N55Y3YII.js → mesh.chunk-EHLBX24J.js} +1 -1
  7. package/dist/bin/{mesh.chunk-M23VKWSF.js → mesh.chunk-GLG5JBI7.js} +23 -24
  8. package/dist/bin/mesh.chunk-GLG5JBI7.js.map +6 -0
  9. package/dist/bin/{mesh.chunk-TG4FBJK3.js → mesh.chunk-O5CP4NPZ.js} +2 -2
  10. package/dist/bin/{mesh.chunk-NT2NPR7J.js → mesh.chunk-O677AU5E.js} +1 -1
  11. package/dist/bin/{mesh.chunk-CA4LI762.js → mesh.chunk-WT27GBE4.js} +1 -1
  12. package/dist/bin/{mesh.chunk-CN6PMHQ5.js → mesh.chunk-YKW256CK.js} +3 -3
  13. package/dist/bin/{mesh.create-app-QRAZVRA3.js → mesh.create-app-GQIGCZNI.js} +3 -3
  14. package/dist/bin/{mesh.dev-token-server-DIECW5KC.js → mesh.dev-token-server-IJUVRBWI.js} +2 -2
  15. package/dist/bin/mesh.js +9 -9
  16. package/dist/bin/{mesh.login-J3QPALUS.js → mesh.login-N5LPLRRX.js} +2 -2
  17. package/dist/bin/{mesh.platform-setup-SNIAJTWJ.js → mesh.platform-setup-PCDLE2EI.js} +1 -1
  18. package/dist/bin/{mesh.program-T57YYRF5.js → mesh.program-WSFVQU7P.js} +9 -9
  19. package/dist/bin/{mesh.registry-UTIC3OY2.js → mesh.registry-5U4L6256.js} +4 -4
  20. package/dist/bin/{mesh.registry-identity-Y4Y5WFQ3.js → mesh.registry-identity-6UPUHKO2.js} +3 -3
  21. package/dist/bin/{mesh.review-command-LYTUNZ5G.js → mesh.review-command-MLBWVHF7.js} +3 -3
  22. package/dist/bin/{mesh.start-OWIKVKN6.js → mesh.start-24YIFB4O.js} +2 -2
  23. package/dist/bin/{mesh.wizard-QL5SQ47K.js → mesh.wizard-6HMOBC5L.js} +7 -7
  24. package/dist/build-info.json +2 -2
  25. package/dist/src/commands/local/index.js +5 -7
  26. package/dist/src/commands/local/seed-zitadel.d.ts +18 -0
  27. package/dist/src/commands/local/seed-zitadel.js +53 -19
  28. package/dist/src/commands/temporal.js.map +1 -1
  29. package/fragments/base/index.ts.hbs +5 -2
  30. package/package.json +3 -3
  31. package/stack/docker-compose.hub.yml +6 -1
  32. package/templates/api-auth/index.ts.hbs +2 -1
  33. package/templates/api-role-gating/index.ts.hbs +2 -1
  34. package/dist/bin/mesh.chunk-M23VKWSF.js.map +0 -6
  35. package/dist/bin/mesh.chunk-TFOKVJ34.js.map +0 -6
  36. /package/dist/bin/{mesh.auth-preflight-RCZH7V34.js.map → mesh.auth-preflight-BGI5LPLN.js.map} +0 -0
  37. /package/dist/bin/{mesh.chunk-SEIVILJR.js.map → mesh.chunk-4XX62O6Z.js.map} +0 -0
  38. /package/dist/bin/{mesh.chunk-SOX2CJMU.js.map → mesh.chunk-DYWR76EO.js.map} +0 -0
  39. /package/dist/bin/{mesh.chunk-N55Y3YII.js.map → mesh.chunk-EHLBX24J.js.map} +0 -0
  40. /package/dist/bin/{mesh.chunk-TG4FBJK3.js.map → mesh.chunk-O5CP4NPZ.js.map} +0 -0
  41. /package/dist/bin/{mesh.chunk-NT2NPR7J.js.map → mesh.chunk-O677AU5E.js.map} +0 -0
  42. /package/dist/bin/{mesh.chunk-CA4LI762.js.map → mesh.chunk-WT27GBE4.js.map} +0 -0
  43. /package/dist/bin/{mesh.chunk-CN6PMHQ5.js.map → mesh.chunk-YKW256CK.js.map} +0 -0
  44. /package/dist/bin/{mesh.create-app-QRAZVRA3.js.map → mesh.create-app-GQIGCZNI.js.map} +0 -0
  45. /package/dist/bin/{mesh.dev-token-server-DIECW5KC.js.map → mesh.dev-token-server-IJUVRBWI.js.map} +0 -0
  46. /package/dist/bin/{mesh.login-J3QPALUS.js.map → mesh.login-N5LPLRRX.js.map} +0 -0
  47. /package/dist/bin/{mesh.platform-setup-SNIAJTWJ.js.map → mesh.platform-setup-PCDLE2EI.js.map} +0 -0
  48. /package/dist/bin/{mesh.program-T57YYRF5.js.map → mesh.program-WSFVQU7P.js.map} +0 -0
  49. /package/dist/bin/{mesh.registry-UTIC3OY2.js.map → mesh.registry-5U4L6256.js.map} +0 -0
  50. /package/dist/bin/{mesh.registry-identity-Y4Y5WFQ3.js.map → mesh.registry-identity-6UPUHKO2.js.map} +0 -0
  51. /package/dist/bin/{mesh.review-command-LYTUNZ5G.js.map → mesh.review-command-MLBWVHF7.js.map} +0 -0
  52. /package/dist/bin/{mesh.start-OWIKVKN6.js.map → mesh.start-24YIFB4O.js.map} +0 -0
  53. /package/dist/bin/{mesh.wizard-QL5SQ47K.js.map → mesh.wizard-6HMOBC5L.js.map} +0 -0
@@ -2,20 +2,20 @@ import {
2
2
  CLI_DESCRIPTION,
3
3
  CLI_NAME,
4
4
  createProgram
5
- } from "./mesh.chunk-M23VKWSF.js";
6
- import "./mesh.chunk-N55Y3YII.js";
7
- import "./mesh.chunk-NT2NPR7J.js";
8
- import "./mesh.chunk-TG4FBJK3.js";
9
- import "./mesh.chunk-CA4LI762.js";
10
- import "./mesh.chunk-CN6PMHQ5.js";
5
+ } from "./mesh.chunk-GLG5JBI7.js";
6
+ import "./mesh.chunk-EHLBX24J.js";
7
+ import "./mesh.chunk-O677AU5E.js";
8
+ import "./mesh.chunk-O5CP4NPZ.js";
9
+ import "./mesh.chunk-WT27GBE4.js";
10
+ import "./mesh.chunk-YKW256CK.js";
11
11
  import "./mesh.chunk-F4654EPX.js";
12
- import "./mesh.chunk-SOX2CJMU.js";
13
- import "./mesh.chunk-TFOKVJ34.js";
12
+ import "./mesh.chunk-DYWR76EO.js";
13
+ import "./mesh.chunk-3WJGDNHA.js";
14
14
  import "./mesh.chunk-2QIVBQX5.js";
15
15
  import "./mesh.chunk-MCBMHWXP.js";
16
16
  import "./mesh.chunk-WFFDF346.js";
17
17
  import "./mesh.chunk-IQOBTL42.js";
18
- import "./mesh.chunk-SEIVILJR.js";
18
+ import "./mesh.chunk-4XX62O6Z.js";
19
19
  import "./mesh.chunk-OW5EMVG5.js";
20
20
  export {
21
21
  CLI_DESCRIPTION,
@@ -17,14 +17,14 @@ import {
17
17
  runRegistryStatus,
18
18
  shouldRemintAfter,
19
19
  shouldRepairUserNpmrc
20
- } from "./mesh.chunk-CN6PMHQ5.js";
21
- import "./mesh.chunk-SOX2CJMU.js";
22
- import "./mesh.chunk-TFOKVJ34.js";
20
+ } from "./mesh.chunk-YKW256CK.js";
21
+ import "./mesh.chunk-DYWR76EO.js";
22
+ import "./mesh.chunk-3WJGDNHA.js";
23
23
  import "./mesh.chunk-2QIVBQX5.js";
24
24
  import "./mesh.chunk-MCBMHWXP.js";
25
25
  import "./mesh.chunk-WFFDF346.js";
26
26
  import "./mesh.chunk-IQOBTL42.js";
27
- import "./mesh.chunk-SEIVILJR.js";
27
+ import "./mesh.chunk-4XX62O6Z.js";
28
28
  export {
29
29
  CONTEXT_IGNORED_NOTICE,
30
30
  NOT_AUTHORIZED_RERUN,
@@ -15,13 +15,13 @@ import {
15
15
  registrySessionCandidates,
16
16
  registryTokenRoles,
17
17
  resolveRegistryIdentity
18
- } from "./mesh.chunk-SOX2CJMU.js";
19
- import "./mesh.chunk-TFOKVJ34.js";
18
+ } from "./mesh.chunk-DYWR76EO.js";
19
+ import "./mesh.chunk-3WJGDNHA.js";
20
20
  import "./mesh.chunk-2QIVBQX5.js";
21
21
  import "./mesh.chunk-MCBMHWXP.js";
22
22
  import "./mesh.chunk-WFFDF346.js";
23
23
  import "./mesh.chunk-IQOBTL42.js";
24
- import "./mesh.chunk-SEIVILJR.js";
24
+ import "./mesh.chunk-4XX62O6Z.js";
25
25
  export {
26
26
  REGISTRY_ALIAS,
27
27
  REGISTRY_CREDENTIAL_KEY,
@@ -10,15 +10,15 @@ import {
10
10
  discoverStackExternalServices,
11
11
  ensureAwsCredentialsForStack,
12
12
  resolveExternalServiceScope
13
- } from "./mesh.chunk-N55Y3YII.js";
14
- import "./mesh.chunk-TFOKVJ34.js";
13
+ } from "./mesh.chunk-EHLBX24J.js";
14
+ import "./mesh.chunk-3WJGDNHA.js";
15
15
  import "./mesh.chunk-2QIVBQX5.js";
16
16
  import "./mesh.chunk-MCBMHWXP.js";
17
17
  import {
18
18
  logInfo
19
19
  } from "./mesh.chunk-WFFDF346.js";
20
20
  import "./mesh.chunk-IQOBTL42.js";
21
- import "./mesh.chunk-SEIVILJR.js";
21
+ import "./mesh.chunk-4XX62O6Z.js";
22
22
 
23
23
  // packages/mesh-cli/src/commands/mcp/review-command.ts
24
24
  import { SSMClient } from "@aws-sdk/client-ssm";
@@ -4,7 +4,7 @@ import {
4
4
  reportAssembly,
5
5
  resolveCliRuntime,
6
6
  runAssemble
7
- } from "./mesh.chunk-NT2NPR7J.js";
7
+ } from "./mesh.chunk-O677AU5E.js";
8
8
  import {
9
9
  logError,
10
10
  logInfo,
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  homeNpmrcPath,
15
15
  parseNpmrcRegistryAuth
16
- } from "./mesh.chunk-SEIVILJR.js";
16
+ } from "./mesh.chunk-4XX62O6Z.js";
17
17
 
18
18
  // packages/mesh-cli/src/docs/start.ts
19
19
  import { execFileSync as execFileSync2 } from "node:child_process";
@@ -2,24 +2,24 @@ import {
2
2
  bootstrapAppsRepo,
3
3
  isInsidePlatformMonorepo,
4
4
  shouldBootstrapAppsRepo
5
- } from "./mesh.chunk-TG4FBJK3.js";
5
+ } from "./mesh.chunk-O5CP4NPZ.js";
6
6
  import {
7
7
  PLATFORM_SETUP_DEFAULTS,
8
8
  ensureStateBucket,
9
9
  renderPlatformNextSteps,
10
10
  resolvePlatformSetup,
11
11
  scaffoldPlatformRepo
12
- } from "./mesh.chunk-CA4LI762.js";
12
+ } from "./mesh.chunk-WT27GBE4.js";
13
13
  import {
14
14
  RegistryNotAuthorizedError
15
- } from "./mesh.chunk-CN6PMHQ5.js";
15
+ } from "./mesh.chunk-YKW256CK.js";
16
16
  import {
17
17
  resolveTargetRoot,
18
18
  syncSkills
19
19
  } from "./mesh.chunk-F4654EPX.js";
20
20
  import {
21
21
  readRegistrySession
22
- } from "./mesh.chunk-SOX2CJMU.js";
22
+ } from "./mesh.chunk-DYWR76EO.js";
23
23
  import {
24
24
  detectLocalTenant,
25
25
  discoverConfigForContext,
@@ -31,7 +31,7 @@ import {
31
31
  runLoginFlow,
32
32
  tokenStillValid,
33
33
  writeMeshJson
34
- } from "./mesh.chunk-TFOKVJ34.js";
34
+ } from "./mesh.chunk-3WJGDNHA.js";
35
35
  import "./mesh.chunk-2QIVBQX5.js";
36
36
  import "./mesh.chunk-MCBMHWXP.js";
37
37
  import {
@@ -44,7 +44,7 @@ import {
44
44
  } from "./mesh.chunk-IQOBTL42.js";
45
45
  import {
46
46
  probeRegistryToken
47
- } from "./mesh.chunk-SEIVILJR.js";
47
+ } from "./mesh.chunk-4XX62O6Z.js";
48
48
 
49
49
  // packages/mesh-cli/src/commands/init/wizard.ts
50
50
  import * as fs from "fs";
@@ -157,7 +157,7 @@ var registryStep = {
157
157
  try {
158
158
  logInfo(REGISTRY_WHY);
159
159
  const login = ctx.seams?.runRegistryLogin ?? (async (opts) => {
160
- const { runRegistryLogin } = await import("./mesh.registry-UTIC3OY2.js");
160
+ const { runRegistryLogin } = await import("./mesh.registry-5U4L6256.js");
161
161
  await runRegistryLogin(void 0, opts);
162
162
  });
163
163
  await login({ device: ctx.device, profile: ctx.profile });
@@ -1,4 +1,4 @@
1
1
  {
2
- "commit": "772a007d6",
3
- "builtAt": "2026-10-25T03:35:13.360Z"
2
+ "commit": "3c7a4caed",
3
+ "builtAt": "2026-10-25T07:07:10.710Z"
4
4
  }
@@ -9,7 +9,7 @@ import { probeRegistryToken, REGISTRY_LOGIN_FIX } from "../../utils/auth-preflig
9
9
  import { ensureHubAuthImage, ensureHubImages, buildHubImagesFromSource, readHubCompiledAuthz, hasRegistryAuth, localHubVersion, planWithHubRefresh, } from "./hub-local.js";
10
10
  import { reconcileRegistryFromZitadel } from "./auth-provision.js";
11
11
  import { LOCAL_AWS_CONFIG, localAwsEnv, seedLocalPlatform, verifyFabric } from "./seed.js";
12
- import { LOGIN_CONTEXT, readHubAuth, seedMockIdps, seedZitadel, TEST_USERS } from "./seed-zitadel.js";
12
+ import { hubAuthComposeEnv, LOGIN_CONTEXT, readHubAuth, seedMockIdps, seedZitadel, TEST_USERS, } from "./seed-zitadel.js";
13
13
  import { idpEndpoints, mockIdpComposeEnv, MOCK_OIDC_PORT, MOCK_SAML_PORT } from "./mock-idps.js";
14
14
  import { publishHubAuthzCatalog } from "./seed-hub-catalog.js";
15
15
  import { removeAllAliasContainers } from "./publish-docs.js";
@@ -263,12 +263,10 @@ export function registerLocalCommands(program) {
263
263
  logWarn(`--no-seed with MESH_HUB_PORT=${hubPort()}: this port's redirect URI is registered during seeding — if Hub sign-in fails with "redirect_uri is missing in the client configuration", re-run without --no-seed.`);
264
264
  }
265
265
  ensureHubAuthImage();
266
- const hubEnv = { MESH_HUB_VERSION: hubVersion };
267
- if (hubAuth) {
268
- hubEnv.MESH_HUB_OAUTH2_CLIENT_ID = hubAuth.clientId;
269
- hubEnv.MESH_HUB_OAUTH2_CLIENT_SECRET = hubAuth.clientSecret;
270
- hubEnv.MESH_HUB_OAUTH2_COOKIE_SECRET = hubAuth.cookieSecret;
271
- }
266
+ const hubEnv = {
267
+ MESH_HUB_VERSION: hubVersion,
268
+ ...(hubAuth ? hubAuthComposeEnv(hubAuth) : {}),
269
+ };
272
270
  await composeStreamed(["up", "-d"], {
273
271
  hub: true,
274
272
  idps: opts.withIdps,
@@ -39,6 +39,7 @@ export declare function ensureZitadelProject(pat: string, name: string, opts?: {
39
39
  orgId?: string;
40
40
  describe?: string;
41
41
  logExisting?: boolean;
42
+ projectRoleAssertion?: boolean;
42
43
  }): Promise<string>;
43
44
  export declare function searchZitadelApp(pat: string, projectId: string, name: string, orgId?: string): Promise<any | undefined>;
44
45
  export interface HubAuthConfig {
@@ -48,7 +49,10 @@ export interface HubAuthConfig {
48
49
  projectId: string;
49
50
  }
50
51
  export declare function hubAuthPath(): string;
52
+ export declare function hubSignInScope(projectId: string): string;
53
+ export declare function hubAuthComposeEnv(auth: HubAuthConfig): Record<string, string>;
51
54
  export declare function readHubAuth(): HubAuthConfig | null;
55
+ export declare const ensureHubProject: (pat: string) => Promise<string>;
52
56
  interface HubOidcApp {
53
57
  id: string;
54
58
  oidcConfig?: {
@@ -65,6 +69,20 @@ interface HubOidcApp {
65
69
  };
66
70
  }
67
71
  export declare function reconcileHubRedirectUris(pat: string, projectId: string, app: HubOidcApp): Promise<void>;
72
+ export declare function buildHubAppPayload(): {
73
+ name: string;
74
+ redirectUris: string[];
75
+ postLogoutRedirectUris: string[];
76
+ responseTypes: string[];
77
+ grantTypes: string[];
78
+ appType: string;
79
+ authMethodType: string;
80
+ accessTokenType: string;
81
+ accessTokenRoleAssertion: boolean;
82
+ idTokenRoleAssertion: boolean;
83
+ idTokenUserinfoAssertion: boolean;
84
+ devMode: boolean;
85
+ };
68
86
  export declare function seedHubAuth(pat: string): Promise<HubAuthConfig>;
69
87
  export declare const OPS_HUB_SECRET_ID = "mesh/local/dev/zitadel/ops-hub";
70
88
  export interface ZitadelSeedResult {
@@ -94,13 +94,26 @@ export async function api(pat, method, apiPath, body, orgId) {
94
94
  export const isAlreadyExists = (err) => err?.status === 409 || err?.zitadelCode === 6 || /already exists/i.test(err?.message ?? "");
95
95
  export async function ensureZitadelProject(pat, name, opts = {}) {
96
96
  const search = await api(pat, "POST", "/management/v1/projects/_search", { queries: [{ nameQuery: { name, method: "TEXT_QUERY_METHOD_EQUALS" } }] }, opts.orgId);
97
- const existing = search?.result?.[0]?.id;
98
- if (existing) {
97
+ const existing = search?.result?.[0];
98
+ if (existing?.id) {
99
99
  if (opts.logExisting)
100
100
  logInfo(`Zitadel project '${name}' already exists`);
101
- return existing;
101
+ const wanted = opts.projectRoleAssertion;
102
+ if (wanted !== undefined && (existing.projectRoleAssertion ?? false) !== wanted) {
103
+ await api(pat, "PUT", `/management/v1/projects/${existing.id}`, {
104
+ name: existing.name ?? name,
105
+ projectRoleAssertion: wanted,
106
+ projectRoleCheck: existing.projectRoleCheck ?? false,
107
+ hasProjectCheck: existing.hasProjectCheck ?? false,
108
+ ...(existing.privateLabelingSetting
109
+ ? { privateLabelingSetting: existing.privateLabelingSetting }
110
+ : {}),
111
+ }, opts.orgId);
112
+ logSuccess(`Zitadel project '${name}': role assertion turned ${wanted ? "on" : "off"}`);
113
+ }
114
+ return existing.id;
102
115
  }
103
- const created = await api(pat, "POST", "/management/v1/projects", { name, projectRoleAssertion: true }, opts.orgId);
116
+ const created = await api(pat, "POST", "/management/v1/projects", { name, projectRoleAssertion: opts.projectRoleAssertion ?? true }, opts.orgId);
104
117
  logSuccess(`Created Zitadel project '${name}'${opts.describe ? ` (${opts.describe})` : ""}`);
105
118
  return created.id;
106
119
  }
@@ -151,6 +164,21 @@ async function ensureTestUsers(pat) {
151
164
  export function hubAuthPath() {
152
165
  return path.join(meshCacheDir("mesh-local"), "hub-auth.json");
153
166
  }
167
+ export function hubSignInScope(projectId) {
168
+ return [
169
+ "openid email profile",
170
+ "urn:zitadel:iam:org:projects:roles",
171
+ `urn:zitadel:iam:org:project:id:${projectId}:aud`,
172
+ ].join(" ");
173
+ }
174
+ export function hubAuthComposeEnv(auth) {
175
+ return {
176
+ MESH_HUB_OAUTH2_CLIENT_ID: auth.clientId,
177
+ MESH_HUB_OAUTH2_CLIENT_SECRET: auth.clientSecret,
178
+ MESH_HUB_OAUTH2_COOKIE_SECRET: auth.cookieSecret,
179
+ ...(auth.projectId ? { MESH_HUB_OAUTH2_SCOPE: hubSignInScope(auth.projectId) } : {}),
180
+ };
181
+ }
154
182
  export function readHubAuth() {
155
183
  try {
156
184
  const parsed = JSON.parse(fs.readFileSync(hubAuthPath(), "utf-8"));
@@ -162,7 +190,10 @@ export function readHubAuth() {
162
190
  return null;
163
191
  }
164
192
  }
165
- const ensureHubProject = (pat) => ensureZitadelProject(pat, HUB_PROJECT_NAME, { describe: "Hub platform app" });
193
+ export const ensureHubProject = (pat) => ensureZitadelProject(pat, HUB_PROJECT_NAME, {
194
+ describe: "Hub platform app",
195
+ projectRoleAssertion: false,
196
+ });
166
197
  function hubRoleDisplayName(roleKey) {
167
198
  const tenant = hubRoleKeyTenant(roleKey);
168
199
  return tenant === null ? roleKey : `${restrictedRoleBase(roleKey) ?? roleKey} (${tenant})`;
@@ -218,19 +249,8 @@ export async function reconcileHubRedirectUris(pat, projectId, app) {
218
249
  });
219
250
  logSuccess(`Registered Hub redirect URI http://localhost:${hubPort()}/oauth2/callback (MESH_HUB_PORT)`);
220
251
  }
221
- async function ensureHubApp(pat, projectId) {
222
- const existing = await searchZitadelApp(pat, projectId, HUB_APP_NAME);
223
- if (existing) {
224
- await reconcileHubRedirectUris(pat, projectId, existing);
225
- const clientId = existing?.oidcConfig?.clientId;
226
- const persisted = readHubAuth();
227
- if (persisted && persisted.clientId === clientId)
228
- return { clientId };
229
- const regenerated = await api(pat, "POST", `/management/v1/projects/${projectId}/apps/${existing.id}/oidc_config/_generate_client_secret`, {});
230
- logSuccess(`Regenerated Hub UI client secret (local copy was missing)`);
231
- return { clientId, clientSecret: regenerated.clientSecret };
232
- }
233
- const created = await api(pat, "POST", `/management/v1/projects/${projectId}/apps/oidc`, {
252
+ export function buildHubAppPayload() {
253
+ return {
234
254
  name: HUB_APP_NAME,
235
255
  redirectUris: [...new Set([hubRedirectUri(), HUB_DEFAULT_REDIRECT_URI])],
236
256
  postLogoutRedirectUris: [
@@ -250,7 +270,21 @@ async function ensureHubApp(pat, projectId) {
250
270
  idTokenRoleAssertion: true,
251
271
  idTokenUserinfoAssertion: true,
252
272
  devMode: true,
253
- });
273
+ };
274
+ }
275
+ async function ensureHubApp(pat, projectId) {
276
+ const existing = await searchZitadelApp(pat, projectId, HUB_APP_NAME);
277
+ if (existing) {
278
+ await reconcileHubRedirectUris(pat, projectId, existing);
279
+ const clientId = existing?.oidcConfig?.clientId;
280
+ const persisted = readHubAuth();
281
+ if (persisted && persisted.clientId === clientId)
282
+ return { clientId };
283
+ const regenerated = await api(pat, "POST", `/management/v1/projects/${projectId}/apps/${existing.id}/oidc_config/_generate_client_secret`, {});
284
+ logSuccess(`Regenerated Hub UI client secret (local copy was missing)`);
285
+ return { clientId, clientSecret: regenerated.clientSecret };
286
+ }
287
+ const created = await api(pat, "POST", `/management/v1/projects/${projectId}/apps/oidc`, buildHubAppPayload());
254
288
  logSuccess(`Created Zitadel application '${HUB_APP_NAME}' (Hub UI web client, code flow)`);
255
289
  return { clientId: created.clientId, clientSecret: created.clientSecret };
256
290
  }