@zitadel/cli 0.1.0-alpha.15 → 0.1.0-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/SKILLS.md +25 -7
- package/dist/commands/apply.mjs +13 -6
- package/dist/commands/apply.mjs.map +1 -1
- package/dist/commands/doctor.mjs +5 -6
- package/dist/commands/doctor.mjs.map +1 -1
- package/dist/commands/eject.mjs +17 -5
- package/dist/commands/eject.mjs.map +1 -1
- package/dist/commands/logs.mjs +2 -2
- package/dist/commands/plan.mjs +8 -4
- package/dist/commands/plan.mjs.map +1 -1
- package/dist/commands/reset.mjs +2 -2
- package/dist/commands/schemas/list.mjs +9 -5
- package/dist/commands/schemas/list.mjs.map +1 -1
- package/dist/commands/setup.mjs +153 -117
- package/dist/commands/setup.mjs.map +1 -1
- package/dist/commands/start.mjs +3 -4
- package/dist/commands/start.mjs.map +1 -1
- package/dist/commands/status.mjs +40 -9
- package/dist/commands/status.mjs.map +1 -1
- package/dist/commands/stop.mjs +2 -2
- package/dist/{docker-D7BSD5C9.mjs → docker-pGcTrDIY.mjs} +2 -2
- package/dist/{docker-D7BSD5C9.mjs.map → docker-pGcTrDIY.mjs.map} +1 -1
- package/dist/journey-guidance-CYVpQszz.mjs +29 -0
- package/dist/journey-guidance-CYVpQszz.mjs.map +1 -0
- package/dist/{oclif-Bm-FkF6z.mjs → oclif-BRdjVNne.mjs} +37 -36
- package/dist/oclif-BRdjVNne.mjs.map +1 -0
- package/dist/{orca-CpXj_XsA.mjs → orca-Dip6DPJ2.mjs} +209 -163
- package/dist/orca-Dip6DPJ2.mjs.map +1 -0
- package/dist/{ports-CxBKS1ga.mjs → ports-V8JfiNgT.mjs} +25 -20
- package/dist/ports-V8JfiNgT.mjs.map +1 -0
- package/dist/{project-Dk7V0xka.mjs → project-BGgv7Bba.mjs} +2 -2
- package/dist/{project-Dk7V0xka.mjs.map → project-BGgv7Bba.mjs.map} +1 -1
- package/dist/{sync-CYuHVQT5.mjs → sync-Cd3z7Q1R.mjs} +226 -31
- package/dist/sync-Cd3z7Q1R.mjs.map +1 -0
- package/oclif.manifest.json +12 -1
- package/package.json +6 -6
- package/dist/docker-guidance-mcTT3_0E.mjs +0 -21
- package/dist/docker-guidance-mcTT3_0E.mjs.map +0 -1
- package/dist/oclif-Bm-FkF6z.mjs.map +0 -1
- package/dist/orca-CpXj_XsA.mjs.map +0 -1
- package/dist/ports-CxBKS1ga.mjs.map +0 -1
- package/dist/sync-CYuHVQT5.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as BaseCommand } from "../../oclif-
|
|
2
|
-
import { o as readZitadelSecret } from "../../project-
|
|
1
|
+
import { t as BaseCommand } from "../../oclif-BRdjVNne.mjs";
|
|
2
|
+
import { o as readZitadelSecret } from "../../project-BGgv7Bba.mjs";
|
|
3
3
|
import { t as environmentSchema } from "../../environment-BQF7LeCz.mjs";
|
|
4
4
|
import { cancel, isCancel, select, spinner } from "@clack/prompts";
|
|
5
5
|
import { Flags } from "@oclif/core";
|
|
@@ -45,6 +45,10 @@ var SchemasList = class SchemasList extends BaseCommand {
|
|
|
45
45
|
project_id: secret.project_id,
|
|
46
46
|
object_type: objectType
|
|
47
47
|
});
|
|
48
|
+
const revisionRows = revisions.map((r) => ({
|
|
49
|
+
id: r.id,
|
|
50
|
+
created_at: r.createdAt
|
|
51
|
+
}));
|
|
48
52
|
if (revisions.length === 0) {
|
|
49
53
|
const message = `No revisions found for objectType "${objectType}".`;
|
|
50
54
|
consola$1.warn(message);
|
|
@@ -62,7 +66,7 @@ var SchemasList = class SchemasList extends BaseCommand {
|
|
|
62
66
|
status: "ok",
|
|
63
67
|
data: {
|
|
64
68
|
object_type: objectType,
|
|
65
|
-
revisions,
|
|
69
|
+
revisions: revisionRows,
|
|
66
70
|
count: revisions.length
|
|
67
71
|
},
|
|
68
72
|
pretty: renderTable(objectType, revisions)
|
|
@@ -80,7 +84,7 @@ var SchemasList = class SchemasList extends BaseCommand {
|
|
|
80
84
|
status: "ok",
|
|
81
85
|
data: {
|
|
82
86
|
object_type: objectType,
|
|
83
|
-
revisions,
|
|
87
|
+
revisions: revisionRows,
|
|
84
88
|
count: revisions.length
|
|
85
89
|
},
|
|
86
90
|
pretty: ""
|
|
@@ -95,7 +99,7 @@ var SchemasList = class SchemasList extends BaseCommand {
|
|
|
95
99
|
status: "ok",
|
|
96
100
|
data: {
|
|
97
101
|
object_type: objectType,
|
|
98
|
-
revisions,
|
|
102
|
+
revisions: revisionRows,
|
|
99
103
|
selected: {
|
|
100
104
|
id: picked,
|
|
101
105
|
body
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.mjs","names":[],"sources":["../../../src/commands/schemas/list.ts"],"sourcesContent":["import { cancel, isCancel, select, spinner } from \"@clack/prompts\";\nimport { Flags } from \"@oclif/core\";\nimport { consola } from \"consola\";\n\nimport { createZitadelClient, type ZitadelClient } from \"@zitadel/api/client\";\nimport type { ListSchemas200Item } from \"@zitadel/api/generated/model\";\n\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport { environmentSchema } from \"../../lib/environment\";\nimport { readZitadelSecret } from \"../../lib/project\";\n\n/**\n * The `schemas list` topic command — inspect the revision history of a\n * user-schema, filtered by `objectType`.\n *\n * Non-interactive: prints one row per revision (newest first) as a JSON payload\n * or a plain-text table. Interactive: renders a `@clack/prompts` `select` menu\n * of the same rows; on selection, fetches the full schema body via\n * `getSchemaById` and pretty-prints it to stdout.\n */\nexport default class SchemasList extends BaseCommand {\n static override description = \"List revisions of a user-schema by objectType.\";\n static override flags = {\n \"object-type\": Flags.string({\n char: \"t\",\n required: true,\n description: \"Filter revisions by objectType (e.g. human-user).\",\n }),\n environment: Flags.string({\n char: \"e\",\n description: \"Target environment (default: development).\",\n options: [...environmentSchema.options],\n }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(SchemasList);\n await this.toMeta(flags);\n const { cwd, source, nonInteractive } = this.meta;\n\n const secret = await readZitadelSecret(cwd);\n consola.info(`Project ${secret.project_id}`);\n consola.info(`Server ${source}`);\n const client = createZitadelClient({\n baseUrl: source,\n token: secret.project_secret,\n });\n\n const objectType = flags[\"object-type\"];\n const revisions = await client.listSchemas({\n project_id: secret.project_id,\n object_type: objectType,\n });\n\n if (revisions.length === 0) {\n const message = `No revisions found for objectType \"${objectType}\".`;\n consola.warn(message);\n return this.emit({\n status: \"ok\",\n data: { object_type: objectType, revisions: [], count: 0 },\n pretty: message,\n });\n }\n\n // Server orders newest-first; the interactive picker inherits that order.\n if (nonInteractive) {\n return this.emit({\n status: \"ok\",\n data: {\n object_type: objectType,\n revisions,\n count: revisions.length,\n },\n pretty: renderTable(objectType, revisions),\n });\n }\n\n const picked = await select({\n message: `Revisions of objectType \"${objectType}\" (newest first)`,\n options: revisions.map((r, idx) => ({\n value: r.id,\n label: `${r.createdAt} ${r.id}${idx === 0 ? \" (latest)\" : \"\"}`,\n })),\n });\n if (isCancel(picked)) {\n cancel(\"No revision selected.\");\n return this.emit({\n status: \"ok\",\n data: { object_type: objectType, revisions, count: revisions.length },\n pretty: \"\",\n });\n }\n\n const s = spinner();\n s.start(`Loading ${String(picked)}…`);\n const body = await fetchSchemaRevision(client, String(picked), secret.project_id);\n s.stop(`Loaded ${String(picked)}`);\n\n const pretty = JSON.stringify(body, null, 2);\n\n return this.emit({\n status: \"ok\",\n data: {\n object_type: objectType,\n revisions,\n selected: { id: picked, body },\n count: revisions.length,\n },\n pretty,\n });\n }\n}\n\n/**\n * Fetch one schema revision body. The id is URL-encoded before it lands in\n * the path: server-allocated ids are opaque today (`sch_…`), but ids can be\n * full URLs when a schema carried an `$id` (the server-seeded defaults do),\n * and an unencoded URL would break the `/schemas/:id` path. Mirrors the\n * encoding the sync engine's schema syncer applies.\n */\nexport async function fetchSchemaRevision(\n client: ZitadelClient,\n id: string,\n projectId: string,\n): Promise<unknown> {\n return client.getSchemaById(encodeURIComponent(id), { project_id: projectId });\n}\n\nfunction renderTable(objectType: string, revisions: ReadonlyArray<ListSchemas200Item>): string {\n const header = `Revisions of objectType \"${objectType}\" (${revisions.length}, newest first)`;\n const idCol = Math.max(\"id\".length, ...revisions.map((r) => r.id.length));\n const createdCol = Math.max(\"createdAt\".length, ...revisions.map((r) => r.createdAt.length));\n const rows = revisions.map(\n (r) => `${r.createdAt.padEnd(createdCol)} ${r.id.padEnd(idCol)}`,\n );\n return [\n header,\n `${\"createdAt\".padEnd(createdCol)} ${\"id\".padEnd(idCol)}`,\n `${\"-\".repeat(createdCol)} ${\"-\".repeat(idCol)}`,\n ...rows,\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAoBA,IAAqB,cAArB,MAAqB,oBAAoB,YAAY;CACnD,OAAgB,cAAc;CAC9B,OAAgB,QAAQ;EACtB,eAAe,MAAM,OAAO;GAC1B,MAAM;GACN,UAAU;GACV,aAAa;GACd,CAAC;EACF,aAAa,MAAM,OAAO;GACxB,MAAM;GACN,aAAa;GACb,SAAS,CAAC,GAAG,kBAAkB,QAAQ;GACxC,CAAC;EACH;CAED,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,YAAY;AAC/C,QAAM,KAAK,OAAO,MAAM;EACxB,MAAM,EAAE,KAAK,QAAQ,mBAAmB,KAAK;EAE7C,MAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,YAAQ,KAAK,aAAa,OAAO,aAAa;AAC9C,YAAQ,KAAK,aAAa,SAAS;EACnC,MAAM,SAAS,oBAAoB;GACjC,SAAS;GACT,OAAO,OAAO;GACf,CAAC;EAEF,MAAM,aAAa,MAAM;EACzB,MAAM,YAAY,MAAM,OAAO,YAAY;GACzC,YAAY,OAAO;GACnB,aAAa;GACd,CAAC;
|
|
1
|
+
{"version":3,"file":"list.mjs","names":[],"sources":["../../../src/commands/schemas/list.ts"],"sourcesContent":["import { cancel, isCancel, select, spinner } from \"@clack/prompts\";\nimport { Flags } from \"@oclif/core\";\nimport { consola } from \"consola\";\n\nimport { createZitadelClient, type ZitadelClient } from \"@zitadel/api/client\";\nimport type { ListSchemas200Item } from \"@zitadel/api/generated/model\";\n\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport { environmentSchema } from \"../../lib/environment\";\nimport { readZitadelSecret } from \"../../lib/project\";\n\n/**\n * The `schemas list` topic command — inspect the revision history of a\n * user-schema, filtered by `objectType`.\n *\n * Non-interactive: prints one row per revision (newest first) as a JSON payload\n * or a plain-text table. Interactive: renders a `@clack/prompts` `select` menu\n * of the same rows; on selection, fetches the full schema body via\n * `getSchemaById` and pretty-prints it to stdout.\n */\nexport default class SchemasList extends BaseCommand {\n static override description = \"List revisions of a user-schema by objectType.\";\n static override flags = {\n \"object-type\": Flags.string({\n char: \"t\",\n required: true,\n description: \"Filter revisions by objectType (e.g. human-user).\",\n }),\n environment: Flags.string({\n char: \"e\",\n description: \"Target environment (default: development).\",\n options: [...environmentSchema.options],\n }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(SchemasList);\n await this.toMeta(flags);\n const { cwd, source, nonInteractive } = this.meta;\n\n const secret = await readZitadelSecret(cwd);\n consola.info(`Project ${secret.project_id}`);\n consola.info(`Server ${source}`);\n const client = createZitadelClient({\n baseUrl: source,\n token: secret.project_secret,\n });\n\n const objectType = flags[\"object-type\"];\n const revisions = await client.listSchemas({\n project_id: secret.project_id,\n object_type: objectType,\n });\n\n // Envelope rows are snake_case like every other command's data; the\n // orval model's `createdAt` is not spread verbatim.\n const revisionRows = revisions.map((r) => ({ id: r.id, created_at: r.createdAt }));\n\n if (revisions.length === 0) {\n const message = `No revisions found for objectType \"${objectType}\".`;\n consola.warn(message);\n return this.emit({\n status: \"ok\",\n data: { object_type: objectType, revisions: [], count: 0 },\n pretty: message,\n });\n }\n\n // Server orders newest-first; the interactive picker inherits that order.\n if (nonInteractive) {\n return this.emit({\n status: \"ok\",\n data: {\n object_type: objectType,\n revisions: revisionRows,\n count: revisions.length,\n },\n pretty: renderTable(objectType, revisions),\n });\n }\n\n const picked = await select({\n message: `Revisions of objectType \"${objectType}\" (newest first)`,\n options: revisions.map((r, idx) => ({\n value: r.id,\n label: `${r.createdAt} ${r.id}${idx === 0 ? \" (latest)\" : \"\"}`,\n })),\n });\n if (isCancel(picked)) {\n cancel(\"No revision selected.\");\n return this.emit({\n status: \"ok\",\n data: { object_type: objectType, revisions: revisionRows, count: revisions.length },\n pretty: \"\",\n });\n }\n\n const s = spinner();\n s.start(`Loading ${String(picked)}…`);\n const body = await fetchSchemaRevision(client, String(picked), secret.project_id);\n s.stop(`Loaded ${String(picked)}`);\n\n const pretty = JSON.stringify(body, null, 2);\n\n return this.emit({\n status: \"ok\",\n data: {\n object_type: objectType,\n revisions: revisionRows,\n selected: { id: picked, body },\n count: revisions.length,\n },\n pretty,\n });\n }\n}\n\n/**\n * Fetch one schema revision body. The id is URL-encoded before it lands in\n * the path: server-allocated ids are opaque today (`sch_…`), but ids can be\n * full URLs when a schema carried an `$id` (the server-seeded defaults do),\n * and an unencoded URL would break the `/schemas/:id` path. Mirrors the\n * encoding the sync engine's schema syncer applies.\n */\nexport async function fetchSchemaRevision(\n client: ZitadelClient,\n id: string,\n projectId: string,\n): Promise<unknown> {\n return client.getSchemaById(encodeURIComponent(id), { project_id: projectId });\n}\n\nfunction renderTable(objectType: string, revisions: ReadonlyArray<ListSchemas200Item>): string {\n const header = `Revisions of objectType \"${objectType}\" (${revisions.length}, newest first)`;\n const idCol = Math.max(\"id\".length, ...revisions.map((r) => r.id.length));\n const createdCol = Math.max(\"createdAt\".length, ...revisions.map((r) => r.createdAt.length));\n const rows = revisions.map(\n (r) => `${r.createdAt.padEnd(createdCol)} ${r.id.padEnd(idCol)}`,\n );\n return [\n header,\n `${\"createdAt\".padEnd(createdCol)} ${\"id\".padEnd(idCol)}`,\n `${\"-\".repeat(createdCol)} ${\"-\".repeat(idCol)}`,\n ...rows,\n ].join(\"\\n\");\n}\n"],"mappings":"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"}
|
package/dist/commands/setup.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import {
|
|
3
|
-
import { n as hasZitadelSecret, t as hasZitadelConfig } from "../project-
|
|
4
|
-
import {
|
|
1
|
+
import { D as ZitadelError, E as stableStringify, O as toZitadelError, n as DEFAULT_SERVER, t as BaseCommand, u as detectHealthyLocalServer, x as publicCliCommand } from "../oclif-BRdjVNne.mjs";
|
|
2
|
+
import { n as inspectScaffoldTarget, o as issuerFromPort, r as RENDERER_IDS, t as createOrca } from "../orca-Dip6DPJ2.mjs";
|
|
3
|
+
import { n as hasZitadelSecret, t as hasZitadelConfig } from "../project-BGgv7Bba.mjs";
|
|
4
|
+
import { c as writeBackResource, d as FLOWS_DIR, l as updateState, o as hashForState } from "../sync-Cd3z7Q1R.mjs";
|
|
5
5
|
import { t as SCHEMAS_DIR } from "../user-schema-DDz5-lX5.mjs";
|
|
6
|
-
import { t as
|
|
6
|
+
import { n as verifyLoginAction, t as customizeAndPublishActions } from "../journey-guidance-CYVpQszz.mjs";
|
|
7
7
|
import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
8
8
|
import { basename, dirname, join } from "node:path";
|
|
9
9
|
import { cancel, confirm, intro, isCancel, outro, select, spinner, text } from "@clack/prompts";
|
|
10
10
|
import { Flags } from "@oclif/core";
|
|
11
11
|
import { createZitadelClient } from "@zitadel/api/client";
|
|
12
|
+
import { DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, DEFAULT_SETUP_PRESET, SETUP_PRESETS, flowsReadmeContent, getDefaultHumanUserSchema, getDefaultLoginFlow, schemasReadmeContent } from "@zitadel/config/defaults";
|
|
12
13
|
import { consola as consola$1 } from "consola";
|
|
13
14
|
import { spawn } from "node:child_process";
|
|
14
|
-
import { DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, flowsReadmeContent, getDefaultHumanUserSchema, getDefaultLoginFlow, schemasReadmeContent } from "@zitadel/config/defaults";
|
|
15
15
|
import { normalizeFlowBody, normalizeSchemaBody } from "@zitadel/config/normalize";
|
|
16
16
|
import pc from "picocolors";
|
|
17
17
|
//#region src/lib/setup-resources.ts
|
|
@@ -30,7 +30,8 @@ async function materializeSetupResources(opts) {
|
|
|
30
30
|
await mkdir(join(opts.cwd, FLOWS_DIR), { recursive: true });
|
|
31
31
|
await mkdir(join(opts.cwd, SCHEMAS_DIR), { recursive: true });
|
|
32
32
|
const filesWritten = [];
|
|
33
|
-
const
|
|
33
|
+
const preset = opts.preset ?? DEFAULT_SETUP_PRESET;
|
|
34
|
+
const { $id: _templateId, ...schemaBody } = getDefaultHumanUserSchema({ preset });
|
|
34
35
|
if (await writeResourceFile(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH, schemaBody, opts.force)) filesWritten.push(join(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH));
|
|
35
36
|
const schemaId = requiredString((await opts.client.createSchema(schemaBody, { project_id: opts.projectId })).id, "created schema id");
|
|
36
37
|
let schemaHash = hashForState({ normalize: normalizeSchemaBody }, schemaBody);
|
|
@@ -44,7 +45,10 @@ async function materializeSetupResources(opts) {
|
|
|
44
45
|
id: schemaId,
|
|
45
46
|
hash: schemaHash
|
|
46
47
|
});
|
|
47
|
-
const flowBody = getDefaultLoginFlow({
|
|
48
|
+
const flowBody = getDefaultLoginFlow({
|
|
49
|
+
userSchemaUrl: schemaId,
|
|
50
|
+
preset
|
|
51
|
+
});
|
|
48
52
|
if (await writeResourceFile(opts.cwd, DEFAULT_FLOW_CONFIG_PATH, flowBody, opts.force)) filesWritten.push(join(opts.cwd, DEFAULT_FLOW_CONFIG_PATH));
|
|
49
53
|
const flow = await opts.client.createFlowDefinition({
|
|
50
54
|
project_id: opts.projectId,
|
|
@@ -238,17 +242,18 @@ async function installDependenciesForSetup(input) {
|
|
|
238
242
|
}
|
|
239
243
|
function outcome(input) {
|
|
240
244
|
const planCommand = publicCliCommand("plan", input.cliVersion);
|
|
241
|
-
const
|
|
242
|
-
const
|
|
243
|
-
`
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
`Preview and publish config changes: ${planCommand} then ${applyCommand}`
|
|
245
|
+
const statusCommand = publicCliCommand("status", input.cliVersion);
|
|
246
|
+
const verifyActions = [
|
|
247
|
+
...input.includeInstallCommand ? [`Install dependencies: ${input.install.command}`] : [],
|
|
248
|
+
`Start your project: ${input.devCommand} (then open ${input.issuer}/login)`,
|
|
249
|
+
verifyLoginAction()
|
|
247
250
|
];
|
|
251
|
+
const breadcrumb = `Once login works: ${statusCommand} shows your next steps; customizing is covered in your README's Zitadel section.`;
|
|
248
252
|
return {
|
|
249
253
|
install: input.install,
|
|
250
254
|
devCommand: input.devCommand,
|
|
251
|
-
|
|
255
|
+
boxActions: [...verifyActions, breadcrumb],
|
|
256
|
+
nextActions: [...verifyActions, ...customizeAndPublishActions(input.cliVersion)],
|
|
252
257
|
nextCommands: input.includeInstallCommand ? [
|
|
253
258
|
input.install.command,
|
|
254
259
|
input.devCommand,
|
|
@@ -332,64 +337,27 @@ var FrameworkConfirmPrompt = class {
|
|
|
332
337
|
}
|
|
333
338
|
};
|
|
334
339
|
//#endregion
|
|
335
|
-
//#region src/lib/prober/http.ts
|
|
336
|
-
/**
|
|
337
|
-
* Fetch `url` with a per-call timeout and pass the resulting `Response` to
|
|
338
|
-
* `predicate`. Returns the predicate's value, or `null` on any failure: a
|
|
339
|
-
* network error, an `AbortError` from the timeout, a thrown predicate, or the
|
|
340
|
-
* predicate returning `null`.
|
|
341
|
-
*
|
|
342
|
-
* Never throws. The predicate decides what counts as a match — it gets the
|
|
343
|
-
* raw `Response` and may read `.json()` / `.headers` / `.status` as needed.
|
|
344
|
-
*
|
|
345
|
-
* `timeoutMs` defaults to 500ms. The implementation uses
|
|
346
|
-
* `AbortSignal.timeout`, so the underlying fetch is cancelled when the
|
|
347
|
-
* timeout fires (no orphaned sockets).
|
|
348
|
-
*/
|
|
349
|
-
async function probeUrl(url, predicate, opts) {
|
|
350
|
-
const timeoutMs = opts?.timeoutMs ?? 500;
|
|
351
|
-
try {
|
|
352
|
-
return await predicate(await fetch(url, { signal: AbortSignal.timeout(timeoutMs) }));
|
|
353
|
-
} catch {
|
|
354
|
-
return null;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Probe many URLs in parallel and return the non-null matches, preserving
|
|
359
|
-
* the input order. Each URL is bounded by `timeoutMs` independently — one
|
|
360
|
-
* slow target can't hold up the others.
|
|
361
|
-
*/
|
|
362
|
-
async function probeUrls(urls, predicate, opts) {
|
|
363
|
-
const list = [...urls];
|
|
364
|
-
return (await Promise.all(list.map(async (url) => {
|
|
365
|
-
const value = await probeUrl(url, predicate, opts);
|
|
366
|
-
return value === null ? null : {
|
|
367
|
-
url,
|
|
368
|
-
value
|
|
369
|
-
};
|
|
370
|
-
}))).filter((match) => match !== null);
|
|
371
|
-
}
|
|
372
|
-
//#endregion
|
|
373
340
|
//#region src/commands/setup/prompts/server.ts
|
|
374
341
|
/** Sentinel returned by the choice select when the user picks "Custom URL". */
|
|
375
342
|
const CUSTOM = "__custom__";
|
|
376
|
-
/** Per-probe timeout for the localhost OIDC scan — generous enough for a TLS handshake on a busy laptop. */
|
|
377
|
-
const OIDC_PROBE_TIMEOUT_MS = 300;
|
|
378
343
|
/**
|
|
379
|
-
* "Which server should `zitadel.json` point to?" — Zitadel Cloud,
|
|
380
|
-
*
|
|
344
|
+
* "Which server should `zitadel.json` point to?" — Zitadel Cloud, the managed
|
|
345
|
+
* local server we detected, or a custom URL.
|
|
381
346
|
*
|
|
382
|
-
* Before asking, it
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
347
|
+
* Before asking, it looks for a healthy local Zitadel server the same way the
|
|
348
|
+
* rest of the CLI does (`detectHealthyLocalServer`: the runtime metadata that
|
|
349
|
+
* `zitadel start` wrote to `.zitadel/local/runtime.json`, falling back to a
|
|
350
|
+
* `/healthz` probe on the default localhost port). A detected server becomes
|
|
351
|
+
* an extra option in the choice list *and* the preselected answer — a user
|
|
352
|
+
* who just ran `zitadel start` almost certainly wants it, and `start`'s own
|
|
353
|
+
* next-step hint says `setup --server local`. Picking it writes the URL
|
|
354
|
+
* directly to `answers.server`; picking "Custom URL" still asks for a
|
|
387
355
|
* validated URL exactly as before.
|
|
388
356
|
*/
|
|
389
357
|
var ServerPrompt = class {
|
|
390
358
|
async ask(answers, ctx) {
|
|
391
359
|
if (ctx.serverFlag) return answers;
|
|
392
|
-
const
|
|
360
|
+
const detected = await detectLocalServer(ctx.cwd);
|
|
393
361
|
const choice = await select({
|
|
394
362
|
message: "Which server should zitadel.json point to?",
|
|
395
363
|
options: [
|
|
@@ -398,17 +366,17 @@ var ServerPrompt = class {
|
|
|
398
366
|
label: "Zitadel Cloud (api.zitadel.cloud)",
|
|
399
367
|
hint: "recommended for real projects"
|
|
400
368
|
},
|
|
401
|
-
...
|
|
402
|
-
value:
|
|
403
|
-
label: server
|
|
404
|
-
hint: "detected —
|
|
405
|
-
}
|
|
369
|
+
...detected ? [{
|
|
370
|
+
value: detected,
|
|
371
|
+
label: `Local Zitadel server (${detected})`,
|
|
372
|
+
hint: "detected — started with zitadel start"
|
|
373
|
+
}] : [],
|
|
406
374
|
{
|
|
407
375
|
value: CUSTOM,
|
|
408
376
|
label: "Custom URL (self-hosted)"
|
|
409
377
|
}
|
|
410
378
|
],
|
|
411
|
-
initialValue: answers.server ?? "https://api.zitadel.cloud"
|
|
379
|
+
initialValue: detected ?? answers.server ?? "https://api.zitadel.cloud"
|
|
412
380
|
});
|
|
413
381
|
bail(choice);
|
|
414
382
|
if (choice !== CUSTOM) return {
|
|
@@ -435,39 +403,48 @@ var ServerPrompt = class {
|
|
|
435
403
|
}
|
|
436
404
|
};
|
|
437
405
|
/**
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
* Zitadel-shaped detail here is the OIDC predicate, which is the standard
|
|
442
|
-
* "any OIDC server" contract (no `zitadel`-keyword check), so Keycloak/dex/
|
|
443
|
-
* etc. also surface and the user picks the right one.
|
|
406
|
+
* Wraps {@link detectHealthyLocalServer} in a spinner: the unhealthy paths
|
|
407
|
+
* block on up to two 1.5s `/healthz` probes, long enough that the wizard
|
|
408
|
+
* should say what it is doing.
|
|
444
409
|
*/
|
|
445
|
-
async function
|
|
410
|
+
async function detectLocalServer(cwd) {
|
|
446
411
|
const s = spinner();
|
|
447
|
-
s.start("
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
s.stop("No local servers detected.");
|
|
452
|
-
return [];
|
|
453
|
-
}
|
|
454
|
-
const origins = (await probeUrls(ports.map((port) => `http://localhost:${port}/.well-known/openid-configuration`), async (response) => {
|
|
455
|
-
if (!response.ok) return null;
|
|
456
|
-
try {
|
|
457
|
-
const body = await response.json();
|
|
458
|
-
return typeof body.issuer === "string" ? body.issuer : null;
|
|
459
|
-
} catch {
|
|
460
|
-
return null;
|
|
461
|
-
}
|
|
462
|
-
}, { timeoutMs: OIDC_PROBE_TIMEOUT_MS })).map((match) => new URL(match.url).origin);
|
|
463
|
-
s.stop(origins.length === 0 ? "No local OIDC servers found." : `Found ${origins.length} local OIDC server${origins.length === 1 ? "" : "s"}.`);
|
|
464
|
-
return origins;
|
|
465
|
-
} catch (error) {
|
|
466
|
-
s.stop("Discovery skipped.");
|
|
467
|
-
throw error;
|
|
468
|
-
}
|
|
412
|
+
s.start("Checking for a local Zitadel server");
|
|
413
|
+
const detected = await detectHealthyLocalServer(cwd);
|
|
414
|
+
s.stop(detected ? `Found local Zitadel server at ${detected}.` : "No local Zitadel server detected.");
|
|
415
|
+
return detected;
|
|
469
416
|
}
|
|
470
417
|
//#endregion
|
|
418
|
+
//#region src/commands/setup/prompts/sign-in-preset.ts
|
|
419
|
+
/**
|
|
420
|
+
* "How should users sign in?" — picks the schema+flow preset the scaffold
|
|
421
|
+
* starts from (#448: app-type/preset selection before any `.zitadel/` file
|
|
422
|
+
* is written). `--preset` is authoritative; non-interactive runs keep the
|
|
423
|
+
* password-first default seeded by the command.
|
|
424
|
+
*/
|
|
425
|
+
var SignInPresetPrompt = class {
|
|
426
|
+
async ask(answers, ctx) {
|
|
427
|
+
if (ctx.presetFromFlag) return answers;
|
|
428
|
+
const labels = {
|
|
429
|
+
"password-first": "Password first — email + password, passkey optional during registration",
|
|
430
|
+
"passkey-first": "Passkey first — one-tap passkey up front, email + password fallback"
|
|
431
|
+
};
|
|
432
|
+
const value = await select({
|
|
433
|
+
message: "How should users sign in?",
|
|
434
|
+
initialValue: answers.preset,
|
|
435
|
+
options: SETUP_PRESETS.map((preset) => ({
|
|
436
|
+
value: preset,
|
|
437
|
+
label: labels[preset]
|
|
438
|
+
}))
|
|
439
|
+
});
|
|
440
|
+
bail(value);
|
|
441
|
+
return {
|
|
442
|
+
...answers,
|
|
443
|
+
preset: value
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
//#endregion
|
|
471
448
|
//#region src/commands/setup/prompts/pick-framework.ts
|
|
472
449
|
/**
|
|
473
450
|
* "Choose a framework to scaffold" — the only prompt outside the main wizard.
|
|
@@ -506,7 +483,8 @@ var PickFrameworkPrompt = class {
|
|
|
506
483
|
const SETUP_PROMPTS = [
|
|
507
484
|
new FrameworkConfirmPrompt(),
|
|
508
485
|
new ServerPrompt(),
|
|
509
|
-
new DevPortPrompt()
|
|
486
|
+
new DevPortPrompt(),
|
|
487
|
+
new SignInPresetPrompt()
|
|
510
488
|
];
|
|
511
489
|
//#endregion
|
|
512
490
|
//#region src/commands/setup/summary.ts
|
|
@@ -633,14 +611,18 @@ var Setup = class Setup extends BaseCommand {
|
|
|
633
611
|
options: [...RENDERER_IDS]
|
|
634
612
|
}),
|
|
635
613
|
"dev-port": Flags.integer({ description: "Dev-server port; also the issuer origin registered with Zitadel. Defaults to the detected port. Use distinct ports to run several scaffolded apps side by side." }),
|
|
636
|
-
"skip-install": Flags.boolean({ description: "Do not install dependencies after setup updates package.json." })
|
|
614
|
+
"skip-install": Flags.boolean({ description: "Do not install dependencies after setup updates package.json." }),
|
|
615
|
+
preset: Flags.string({
|
|
616
|
+
description: "Sign-in preset for the scaffolded schema and login flow (default: password-first).",
|
|
617
|
+
options: [...SETUP_PRESETS]
|
|
618
|
+
})
|
|
637
619
|
};
|
|
638
620
|
async run() {
|
|
639
621
|
const { flags } = await this.parse(Setup);
|
|
640
622
|
try {
|
|
641
623
|
await this.toMeta(flags);
|
|
642
624
|
} catch (error) {
|
|
643
|
-
throw localSetupHint(error, flags
|
|
625
|
+
throw localSetupHint(error, retryOptionsFromFlags(flags), this.config.version);
|
|
644
626
|
}
|
|
645
627
|
const { cwd, nonInteractive, dryRun, force } = this.meta;
|
|
646
628
|
if (await hasZitadelConfig(cwd)) return this.emit({
|
|
@@ -671,6 +653,7 @@ var Setup = class Setup extends BaseCommand {
|
|
|
671
653
|
scaffolded_skeleton: scaffoldedFramework,
|
|
672
654
|
skip_install: Boolean(flags["skip-install"]),
|
|
673
655
|
dev_port_explicit: flags["dev-port"] !== void 0,
|
|
656
|
+
preset: flags.preset ?? DEFAULT_SETUP_PRESET,
|
|
674
657
|
step: "framework_resolved"
|
|
675
658
|
});
|
|
676
659
|
if (flags["dev-port"] !== void 0) {
|
|
@@ -684,18 +667,22 @@ var Setup = class Setup extends BaseCommand {
|
|
|
684
667
|
}
|
|
685
668
|
let answers = {
|
|
686
669
|
server: this.meta.source,
|
|
687
|
-
devPort: framework.devPort
|
|
670
|
+
devPort: framework.devPort,
|
|
671
|
+
preset: flags.preset ?? DEFAULT_SETUP_PRESET
|
|
688
672
|
};
|
|
689
673
|
if (!nonInteractive && !dryRun) {
|
|
690
674
|
intro("Zitadel setup");
|
|
691
675
|
const promptCtx = {
|
|
692
676
|
framework,
|
|
677
|
+
cwd,
|
|
693
678
|
serverFlag: this.meta.serverFlag,
|
|
694
|
-
devPortFromFlag: flags["dev-port"] !== void 0
|
|
679
|
+
devPortFromFlag: flags["dev-port"] !== void 0,
|
|
680
|
+
presetFromFlag: flags.preset !== void 0
|
|
695
681
|
};
|
|
696
682
|
for (const prompt of SETUP_PROMPTS) answers = await prompt.ask(answers, promptCtx);
|
|
697
683
|
outro("Configuration captured");
|
|
698
684
|
}
|
|
685
|
+
this.recordTelemetry({ preset: answers.preset });
|
|
699
686
|
const issuer = issuerFromPort(answers.devPort);
|
|
700
687
|
framework = {
|
|
701
688
|
...framework,
|
|
@@ -704,7 +691,13 @@ var Setup = class Setup extends BaseCommand {
|
|
|
704
691
|
};
|
|
705
692
|
consola$1.start(`Creating project on ${answers.server}${dryRun ? " (dry run)" : ""}`);
|
|
706
693
|
const unauthClient = createZitadelClient({ baseUrl: answers.server });
|
|
707
|
-
const
|
|
694
|
+
const projectName = defaultProjectName(cwd, framework.id);
|
|
695
|
+
const project = dryRun ? dryRunProject(issuer) : await createProjectWithLocalHint(unauthClient, answers.server, this.meta.cliVersion, projectName, issuer, {
|
|
696
|
+
...retryOptionsFromFlags(flags),
|
|
697
|
+
framework: framework.id,
|
|
698
|
+
preset: answers.preset,
|
|
699
|
+
devPort: answers.devPort
|
|
700
|
+
});
|
|
708
701
|
consola$1.success(`Created project ${project.id}`);
|
|
709
702
|
this.recordTelemetry({ step: "project_created" });
|
|
710
703
|
const ctx = {
|
|
@@ -714,7 +707,8 @@ var Setup = class Setup extends BaseCommand {
|
|
|
714
707
|
issuer,
|
|
715
708
|
server: answers.server,
|
|
716
709
|
cliVersion: this.meta.cliVersion,
|
|
717
|
-
scaffoldedFramework
|
|
710
|
+
scaffoldedFramework,
|
|
711
|
+
preset: answers.preset
|
|
718
712
|
};
|
|
719
713
|
consola$1.start(`Patching project files${dryRun ? " (dry run)" : ""}`);
|
|
720
714
|
const result = await orca.patcherFor(framework.id).patch(ctx, {
|
|
@@ -736,7 +730,8 @@ var Setup = class Setup extends BaseCommand {
|
|
|
736
730
|
token: project.projectSecret
|
|
737
731
|
}),
|
|
738
732
|
projectId: project.id,
|
|
739
|
-
force
|
|
733
|
+
force,
|
|
734
|
+
preset: answers.preset
|
|
740
735
|
});
|
|
741
736
|
} catch (error) {
|
|
742
737
|
await rm(join(cwd, "zitadel.json"), { force: true });
|
|
@@ -788,7 +783,7 @@ var Setup = class Setup extends BaseCommand {
|
|
|
788
783
|
message: [
|
|
789
784
|
renderSummary(sections),
|
|
790
785
|
"",
|
|
791
|
-
installOutcome.
|
|
786
|
+
installOutcome.boxActions.join("\n")
|
|
792
787
|
].join("\n"),
|
|
793
788
|
style: {
|
|
794
789
|
padding: 1,
|
|
@@ -847,17 +842,49 @@ function dryRunProject(issuer) {
|
|
|
847
842
|
createdAt: "2026-04-21T14:03:11.000Z"
|
|
848
843
|
};
|
|
849
844
|
}
|
|
850
|
-
|
|
845
|
+
/**
|
|
846
|
+
* Reconstructs the flag list of the current invocation for retry guidance,
|
|
847
|
+
* ending in `--server local`. Flags whose resolved value equals the default
|
|
848
|
+
* are omitted — the retry reproduces the same outcome without them.
|
|
849
|
+
*/
|
|
850
|
+
function setupRetryFlags(opts) {
|
|
851
|
+
const parts = [];
|
|
852
|
+
if (opts.framework) parts.push(`--framework ${opts.framework}`);
|
|
853
|
+
if (opts.preset && opts.preset !== DEFAULT_SETUP_PRESET) parts.push(`--preset ${opts.preset}`);
|
|
854
|
+
if (opts.renderer && opts.renderer !== "react") parts.push(`--renderer ${opts.renderer}`);
|
|
855
|
+
if (opts.devPort !== void 0) parts.push(`--dev-port ${opts.devPort}`);
|
|
856
|
+
if (opts.nonInteractive) parts.push("--non-interactive");
|
|
857
|
+
parts.push("--server local");
|
|
858
|
+
return parts.join(" ");
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Retry options straight from parsed flags, for failures before the wizard
|
|
862
|
+
* resolves answers. `--non-interactive` is echoed only when explicitly passed
|
|
863
|
+
* — TTY/JSON-inferred non-interactivity re-infers itself on the retry.
|
|
864
|
+
*/
|
|
865
|
+
function retryOptionsFromFlags(flags) {
|
|
866
|
+
return {
|
|
867
|
+
framework: flags.framework,
|
|
868
|
+
preset: flags.preset,
|
|
869
|
+
renderer: flags.renderer,
|
|
870
|
+
devPort: flags["dev-port"],
|
|
871
|
+
nonInteractive: Boolean(flags["non-interactive"])
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
async function createProjectWithLocalHint(client, server, cliVersion, projectName, issuer, retry) {
|
|
851
875
|
try {
|
|
852
|
-
|
|
876
|
+
const payload = {
|
|
877
|
+
name: projectName,
|
|
853
878
|
previewOrigins: [issuer],
|
|
854
879
|
seedDefaults: false
|
|
855
|
-
}
|
|
880
|
+
};
|
|
881
|
+
return await client.createProject(payload);
|
|
856
882
|
} catch (error) {
|
|
857
883
|
const normalized = toZitadelError(error);
|
|
884
|
+
const retryFlags = setupRetryFlags(retry);
|
|
858
885
|
throw new ZitadelError(normalized.code, normalized.message, {
|
|
859
|
-
hint: `${normalized.hint ? `${normalized.hint} ` : ""}If you meant to use a local Zitadel server, start it first and retry setup with
|
|
860
|
-
nextCommands: [publicCliCommand("start", cliVersion), publicCliCommand(`setup
|
|
886
|
+
hint: `${normalized.hint ? `${normalized.hint} ` : ""}If you meant to use a local Zitadel server, start it first and retry setup with ${retryFlags}.`,
|
|
887
|
+
nextCommands: [publicCliCommand("start", cliVersion), publicCliCommand(`setup ${retryFlags}`, cliVersion)],
|
|
861
888
|
details: {
|
|
862
889
|
server,
|
|
863
890
|
original: normalized.details
|
|
@@ -865,10 +892,14 @@ async function createProjectWithLocalHint(client, server, cliVersion, issuer, fr
|
|
|
865
892
|
});
|
|
866
893
|
}
|
|
867
894
|
}
|
|
868
|
-
function
|
|
895
|
+
function defaultProjectName(cwd, framework) {
|
|
896
|
+
const fromDirectory = basename(cwd).trim();
|
|
897
|
+
return fromDirectory.length > 0 ? fromDirectory : `zitadel-${framework}-app`;
|
|
898
|
+
}
|
|
899
|
+
function localSetupHint(error, retry, cliVersion) {
|
|
869
900
|
const normalized = toZitadelError(error);
|
|
870
901
|
if (normalized.code !== "E_LOCAL_SERVER_NOT_RUNNING") return error;
|
|
871
|
-
const setupCommand =
|
|
902
|
+
const setupCommand = `setup ${setupRetryFlags(retry)}`;
|
|
872
903
|
return new ZitadelError(normalized.code, normalized.message, {
|
|
873
904
|
hint: `${normalized.hint ? `${normalized.hint} ` : ""}Start local Zitadel first, then rerun setup. After setup succeeds, follow its next_commands to start the app and verify registration, logout, and login in the browser.`,
|
|
874
905
|
nextCommands: [publicCliCommand("start", cliVersion), publicCliCommand(setupCommand, cliVersion)],
|
|
@@ -907,7 +938,7 @@ function pickWrittenFile(written, suffix) {
|
|
|
907
938
|
* something happened.
|
|
908
939
|
*/
|
|
909
940
|
function describeWrittenFile(relPath, dryRun) {
|
|
910
|
-
if (relPath === ".zitadel" || relPath === ".zitadel/flows" || relPath === ".zitadel/schemas") return null;
|
|
941
|
+
if (relPath === ".zitadel" || relPath === ".zitadel/flows" || relPath === ".zitadel/schemas" || relPath === ".zitadel/meta") return null;
|
|
911
942
|
const verb = dryRun ? "Would write" : "Wrote";
|
|
912
943
|
const sentence = SENTENCE_BY_PATH[relPath];
|
|
913
944
|
if (sentence) return `${verb} ${sentence.subject} (${path(relPath)})`;
|
|
@@ -930,7 +961,12 @@ const SENTENCE_BY_PATH = {
|
|
|
930
961
|
".zitadel/flows/README.md": { subject: "the flows folder README" },
|
|
931
962
|
".zitadel/schemas/default-human-user.json": { subject: "the editable default human user schema" },
|
|
932
963
|
".zitadel/schemas/README.md": { subject: "the schemas folder README" },
|
|
933
|
-
"
|
|
964
|
+
".zitadel/meta/flow-definition.json": { subject: "the flow dialect spec (editor $schema)" },
|
|
965
|
+
".zitadel/meta/user-schema.json": { subject: "the user-schema dialect spec" },
|
|
966
|
+
".zitadel/meta/user-property.json": { subject: "the user-property dialect spec" },
|
|
967
|
+
"AGENTS.md": { subject: "the agent guidance (golden journey + config dialect)" },
|
|
968
|
+
"README.md": { subject: "the README's Zitadel section" },
|
|
969
|
+
"app/page.tsx": { subject: "the home page redirect" },
|
|
934
970
|
"app/login/page.tsx": { subject: "the login page" },
|
|
935
971
|
"app/register/page.tsx": { subject: "the registration page" },
|
|
936
972
|
"app/profile/page.tsx": { subject: "the profile page" },
|
|
@@ -959,7 +995,7 @@ function buildSummary(opts) {
|
|
|
959
995
|
secondary: path(fileNameOf(packageJsonHit))
|
|
960
996
|
});
|
|
961
997
|
for (const [label, suffix] of [
|
|
962
|
-
["Home
|
|
998
|
+
["Home redirect", "app/page.tsx"],
|
|
963
999
|
["Login page", "app/login/page.tsx"],
|
|
964
1000
|
["Register page", "app/register/page.tsx"],
|
|
965
1001
|
["Profile page", "app/profile/page.tsx"],
|